#define NOMINMAX #include "VolumeCalc.h" #define CLIPPER_SCALE 1.0e9 void VolumeCalc::GetLayerBorders(MetaData* metadata, unsigned int layer, PolyTree& pt, bool isSupport) { if (metadata == nullptr || layer > metadata->GetLayerCount()) return; MetaData::Layer* player = metadata->GetCurrentLayer(); if (player == NULL || player->index != layer) { if (metadata->LoadLayerByIndex(layer)) player = metadata->GetCurrentLayer(); else return; } metadata->LockMainDB(); vector m_BordersDB; for (std::map::iterator it = player->data_blocks_map.begin(); it != player->data_blocks_map.end(); it++) { int partid = it->first; MetaData::Part* part = metadata->GetPart(partid); if (!part->print_enable) continue; MetaData::DataBlockList* datas = it->second; if (datas == NULL)continue; for (unsigned int i = 0; i < datas->size(); ++i) { BPBinary::BinDataBlock* pdb = metadata->GetDataBlock((*datas)[i]); if (!pdb)break; MetaData::ParameterSet* ps = metadata->GetParameterSet((*datas)[i]->references->process); if (!ps) { continue; } if (isSupport) { if (ps->set_type == "BorderSupport" || ps->set_type == "SupportBorder") m_BordersDB.push_back(pdb); } else { if (ps->set_type == "Border" || ps->set_type == "BorderUp" || ps->set_type == "BorderDown" || ps->set_type == "InBorder" || ps->set_type == "UpBorder" || ps->set_type == "DownBorder") m_BordersDB.push_back(pdb); } } } PolyTree tmp; for (auto db : m_BordersDB) { for (unsigned int i = 0; i < db->point_indexs.size(); i++) { BPBinary::ChainPoint* point = (BPBinary::ChainPoint*)db->point_indexs[i]; PolyNode* poly = new PolyNode; for (unsigned int k = 0; k < point->points.size(); ++k) { poly->Contour.emplace_back(static_cast(point->points[k]->x * CLIPPER_SCALE), static_cast(point->points[k]->y * CLIPPER_SCALE)); } if (poly->Contour.front() == poly->Contour.back()) { pt.Childs.push_back(poly); pt.AllNodes.push_back(poly); } else { tmp.Childs.push_back(poly); } } } metadata->UnLockMainDB(); #if 0 for (int i = 0; i < tmp.ChildCount(); i++) { char buf[1024]; sprintf_s(buf, "#index:%d, cnt:%d\n", i, tmp.Childs[i]->Contour.size()); OutputDebugStringA(buf); for (int j = 0; j < tmp.Childs[i]->Contour.size(); j++) { memset(buf, '\0', 1024); sprintf_s(buf, "%.10f, %.10f\n", tmp.Childs[i]->Contour[j].X / CLIPPER_SCALE, tmp.Childs[i]->Contour[j].Y / CLIPPER_SCALE); OutputDebugStringA(buf); } OutputDebugStringA("\n\n"); } #endif while (tmp.ChildCount() > 0) { PolyNode* closed = tmp.Childs.front(); tmp.Childs.erase(tmp.Childs.begin()); while (closed->Contour.front() != closed->Contour.back()) { bool poly_found = false; for (int i = 0; i < tmp.ChildCount(); i++) { Path& contour = tmp.Childs[i]->Contour; if (closed->Contour.back() == contour.front()){ closed->Contour.insert(closed->Contour.end(), contour.begin(), contour.end()); PolyNode* poly = tmp.Childs[i]; tmp.Childs.erase(tmp.Childs.begin() + i); delete poly; poly_found = true; break; } else if (closed->Contour.back() == contour.back()) { reverse(contour.begin(), contour.end()); closed->Contour.insert(closed->Contour.end(), contour.begin(), contour.end()); PolyNode* poly = tmp.Childs[i]; tmp.Childs.erase(tmp.Childs.begin() + i); delete poly; poly_found = true; break; } else if (isBetween(contour[0], contour[1], closed->Contour.back())) { if (contour.size() == 2) { if (isBetween(closed->Contour.back(), closed->Contour[closed->Contour.size() - 2], contour[0])) { closed->Contour.push_back(contour[1]); } else { closed->Contour.push_back(contour[0]); } } else { closed->Contour.insert(closed->Contour.end(), contour.begin() + 1, contour.end()); } PolyNode* poly = tmp.Childs[i]; tmp.Childs.erase(tmp.Childs.begin() + i); delete poly; poly_found = true; break; } else if (isBetween(contour.back(), contour[contour.size() - 2], closed->Contour.back())) { if (isBetween(closed->Contour.back(), closed->Contour[closed->Contour.size() - 2], contour.back())/* || isBetween(contour.back(), contour[contour.size() - 2], closed->Contour[closed->Contour.size() - 2])*/) { reverse(contour.begin(), contour.end()); closed->Contour.insert(closed->Contour.end(), contour.begin() + 1, contour.end()); } else { closed->Contour.push_back(contour.back()); } PolyNode* poly = tmp.Childs[i]; tmp.Childs.erase(tmp.Childs.begin() + i); delete poly; poly_found = true; break; } else { for (size_t j = 0; j < 10 && j < contour.size() - 1; j++) { if (isBetween(contour[j], contour[j + 1], closed->Contour.back())) { if (!isBetween(closed->Contour.back(), closed->Contour[closed->Contour.size() - 2], contour[j + 1]) || !isBetween(contour[j], contour[j + 1], closed->Contour[closed->Contour.size() - 2])) { closed->Contour.insert(closed->Contour.end(), contour.begin() + j + 1, contour.end()); } else { reverse(contour.begin(), contour.end()); closed->Contour.insert(closed->Contour.end(), contour.begin() + (contour.size() - j - 1), contour.end()); } PolyNode* poly = tmp.Childs[i]; tmp.Childs.erase(tmp.Childs.begin() + i); delete poly; poly_found = true; break; } } if (poly_found) break; size_t end_idx = contour.size() - 1; for (size_t j = 0; j < 10 && j < contour.size() - 1; j++) { if (isBetween(contour[end_idx - j], contour[end_idx - j - 1], closed->Contour.back())) { if (!isBetween(closed->Contour.back(), closed->Contour[closed->Contour.size() - 2], contour[end_idx - j - 1]) || !isBetween(contour[end_idx - j], contour[end_idx - j - 1], closed->Contour[closed->Contour.size() - 2])) { reverse(contour.begin(), contour.end()); closed->Contour.insert(closed->Contour.end(), contour.begin() + j + 1, contour.end()); } else { closed->Contour.insert(closed->Contour.end(), contour.begin() + (contour.size() - j - 1), contour.end()); } PolyNode* poly = tmp.Childs[i]; tmp.Childs.erase(tmp.Childs.begin() + i); delete poly; poly_found = true; break; } } if (poly_found) break; for (size_t j = 0; j < contour.size() - 1; j++) { if (isBetween(contour[j], contour[j + 1], closed->Contour.back())) { if (!isBetween(closed->Contour.back(), closed->Contour[closed->Contour.size() - 2], contour[j + 1]) || !isBetween(contour[j], contour[j + 1], closed->Contour[closed->Contour.size() - 2])) { closed->Contour.insert(closed->Contour.end(), contour.begin() + j + 1, contour.end()); } else { reverse(contour.begin(), contour.end()); closed->Contour.insert(closed->Contour.end(), contour.begin() + (contour.size() - j - 1), contour.end()); } PolyNode* poly = tmp.Childs[i]; tmp.Childs.erase(tmp.Childs.begin() + i); delete poly; poly_found = true; break; } } if (poly_found) break; } } if (!poly_found) break; } if (closed->Contour.front() == closed->Contour.back()) { pt.AllNodes.push_back(closed); pt.Childs.push_back(closed); } else { bool connected = false; for (size_t j = 0; j < 10 && j < closed->Contour.size() - 1; j++) { if (isBetween(closed->Contour[j], closed->Contour[j + 1], closed->Contour.back())) { closed->Contour.erase(closed->Contour.begin(), closed->Contour.begin() + j); pt.AllNodes.push_back(closed); pt.Childs.push_back(closed); connected = true; break; } } if (!connected) { closed->Contour.push_back(closed->Contour.front()); pt.AllNodes.push_back(closed); pt.Childs.push_back(closed); } } } BuildTree(&pt); Paths tmp_paths; PolyTreeToPaths(pt, tmp_paths); ClipperLib::ClipperOffset co; co.AddPaths(tmp_paths, ClipperLib::jtMiter, ClipperLib::etClosedPolygon); co.MiterLimit = 1.2; co.ArcTolerance = 0.25 * CLIPPER_SCALE; pt.Clear(); co.Execute(pt, 0.03 * CLIPPER_SCALE); } void VolumeCalc::GetBlockSupport(MetaData* metadata, unsigned int layer, PolyTree& pt, double& spotSize) { if (metadata == nullptr || layer > metadata->GetLayerCount()) return; MetaData::Layer* player = metadata->GetCurrentLayer(); if (player == NULL || player->index != layer) { if (metadata->LoadLayerByIndex(layer)) player = metadata->GetCurrentLayer(); else return; } metadata->LockMainDB(); vector m_BordersDB; for (std::map::iterator it = player->data_blocks_map.begin(); it != player->data_blocks_map.end(); it++) { int partid = it->first; MetaData::Part* part = metadata->GetPart(partid); if (!part->print_enable) continue; MetaData::DataBlockList* datas = it->second; if (datas == NULL)continue; for (unsigned int i = 0; i < datas->size(); ++i) { BPBinary::BinDataBlock* pdb = metadata->GetDataBlock((*datas)[i]); if (!pdb)break; MetaData::ParameterSet* ps = metadata->GetParameterSet((*datas)[i]->references->process); if (!ps) { continue; } if (ps->set_type == "BlockSupport" || ps->set_type == "WallSupport") { m_BordersDB.push_back(pdb); if (spotSize == 0.0) { double r = ps->laser_set->laser_diameter; spotSize = r * r * 3.1415926535897932384; } } } } for (auto db : m_BordersDB) { for (unsigned int i = 0; i < db->point_indexs.size(); i++) { BPBinary::ChainPoint* point = (BPBinary::ChainPoint*)db->point_indexs[i]; PolyNode* poly = new PolyNode; for (unsigned int k = 0; k < point->points.size(); ++k) { poly->Contour.emplace_back(static_cast(point->points[k]->x * CLIPPER_SCALE), static_cast(point->points[k]->y * CLIPPER_SCALE)); } pt.Childs.push_back(poly); pt.AllNodes.push_back(poly); } } metadata->UnLockMainDB(); } double VolumeCalc::Len(Path& p) { double len = 0; if (p.size() < 2) return 0; for (size_t i = 0; i < p.size() - 1; i++) { len += sqrt((p[i].X - p[i + 1].X) * (p[i].X - p[i + 1].X) + (p[i].Y - p[i + 1].Y) * (p[i].Y - p[i + 1].Y)); } len += sqrt((p[0].X - p.back().X) * (p[0].X - p.back().X) + (p[0].Y - p.back().Y) * (p[0].Y - p.back().Y)); return len; } void VolumeCalc::BuildTree(PolyTree* node) { if (node->ChildCount() < 2) return; for (int i = 0; i < node->ChildCount(); i++) node->Childs[i]->CalcBounds(); int max_level = 0; for (int i = 0; i < node->ChildCount(); i++) { ClipperLib::PolyNode* p0 = node->Childs[i]; for (int j = 0; j < node->ChildCount(); j++) { if (j == i) continue; ClipperLib::PolyNode* p1 = node->Childs[j]; if (p1->IsInside(p0)) { p1->depth++; if (p1->depth > max_level) max_level = p1->depth; } } } vector childs_copy; childs_copy.insert(childs_copy.begin(), node->Childs.begin(), node->Childs.end()); for (int i = 1; i <= max_level; i += 2) { for (size_t j = 0; j < childs_copy.size(); j++) { if (childs_copy[j]->depth != i) continue; PolyNode* pj = childs_copy[j]; if (Orientation(pj->Contour)) ReversePath(pj->Contour); for (size_t k = 0; k < childs_copy.size(); k++) { if (childs_copy[k]->depth != i - 1) continue; PolyNode* pk = childs_copy[k]; if (!Orientation(pk->Contour)) ReversePath(pk->Contour); if (pj->IsInside(pk)) { if (node->ChildCount() > 0) { vector::iterator it = node->Childs.begin(); for (; it != node->Childs.end(); it++) { if (*it == pj) { node->Childs.erase(it); break; } } } pj->Parent = pk; pk->Childs.push_back(pj); break; } } } } for (PolyNode* poly : node->Childs) { if (poly->ChildCount() == 0 && !Orientation(poly->Contour)) ReversePath(poly->Contour); } double* bounds = node->GetBounds(); for (PolyNode* poly : node->AllNodes) { bounds[0] = std::min(bounds[0], poly->GetBounds()[0]); bounds[1] = std::max(bounds[1], poly->GetBounds()[1]); bounds[2] = std::min(bounds[2], poly->GetBounds()[2]); bounds[3] = std::max(bounds[3], poly->GetBounds()[3]); } } bool VolumeCalc::isBetween(IntPoint a, IntPoint b, IntPoint c) { #if 0 if (a == c || b == c) return true; #endif cInt crossproduct = (c.Y - a.Y) * (b.X - a.X) - (c.X - a.X) * (b.Y - a.Y); // compare versus epsilon for floating point values, or != 0 if using integers double tmp = abs(crossproduct * 1.0e-18); if (tmp > 2.0e-3) return false; cInt dotproduct = (c.X - a.X) * (b.X - a.X) + (c.Y - a.Y) * (b.Y - a.Y); double ddotproduct = dotproduct * 1.0e-18; if (ddotproduct < 0) return false; cInt squaredlengthba = (b.X - a.X) * (b.X - a.X) + (b.Y - a.Y) * (b.Y - a.Y); double dsquaredlengthba = squaredlengthba * 1.0e-18; if (ddotproduct > dsquaredlengthba) return false; return true; } double VolumeCalc::Dist(IntPoint a, IntPoint b) { double tmp = sqrt((a.X / CLIPPER_SCALE - b.X / CLIPPER_SCALE) * (a.X / CLIPPER_SCALE - b.X / CLIPPER_SCALE) + (a.Y / CLIPPER_SCALE - b.Y / CLIPPER_SCALE) * (a.Y / CLIPPER_SCALE - b.Y / CLIPPER_SCALE)); return tmp; } void VolumeCalc::CalcLayerVolume(MetaData* pmd, unsigned int layer) { if (pmd == nullptr || layer > pmd->GetLayerCount()) return; MetaData::Layer* player = pmd->GetCurrentLayer(); if (player == NULL || player->index != layer) { if (pmd->LoadLayerByIndex(layer)) player = pmd->GetCurrentLayer(); else return; } float dotWidth = 0.0f; vector m_HatchingDB; vector m_SupportDB; pmd->LockMainDB(); for (std::map::iterator it = player->data_blocks_map.begin(); it != player->data_blocks_map.end(); it++) { int partid = it->first; MetaData::Part* part = pmd->GetPart(partid); if (!part->print_enable) continue; MetaData::DataBlockList* datas = it->second; if (datas == NULL)continue; for (unsigned int i = 0; i < datas->size(); ++i) { BPBinary::BinDataBlock* pdb = pmd->GetDataBlock((*datas)[i]); if (!pdb)break; MetaData::ParameterSet* ps = pmd->GetParameterSet((*datas)[i]->references->process); if (!ps) { continue; } if (ps->set_type.find("Hatching") != ps->set_type.npos) { if (pdb->type == BIN_VECTOR) { m_HatchingDB.push_back(pdb); } } else if (ps->set_type.find("Support") != ps->set_type.npos) { m_SupportDB.push_back(pdb); } } } int calcCount = 0; vector calcV; for (size_t i = 0; i < m_HatchingDB.size();i++) { for (size_t j = 0; j < m_HatchingDB[i]->point_indexs.size(); ++j) { BPBinary::VectorPoint* pvp = (BPBinary::VectorPoint*)m_HatchingDB[i]->point_indexs[j]; CalcVar cv; cv.difx= pvp->x2 - pvp->x1; cv.dify = pvp->y2 - pvp->y1; cv.a = -(pvp->y2 - pvp->y1); cv.b = pvp->x2 - pvp->x1; cv.c = (pvp->y2 - pvp->y1) * pvp->x1 - (pvp->x2 - pvp->x1) * pvp->y1; calcV.push_back(cv); calcCount++; if (calcCount >= 10)break; } if (calcCount >= 10)break; } pmd->UnLockMainDB(); if (calcV.size() < 10) { dotWidth = 1.0f; } else { CalcVar preV = calcV[0]; float disSum = 0.0f; int count = 0; float maxcalc = -FLT_MAX; float mincalc = FLT_MAX; for (size_t i = 1; i < calcV.size();i++) { CalcVar tempV = calcV[i]; float value = abs((preV.difx*tempV.dify) - (preV.dify*tempV.difx)); if (value < 0.01f) { float calcT = preV.a * preV.a + preV.b * preV.b; if (calcT > 0.0f) { float calcSqr= sqrt(calcT); if (calcSqr != 0.0f) { float dis = abs(preV.c - preV.b * tempV.c / tempV.b) / calcSqr; disSum += dis; count++; if (dis > maxcalc)maxcalc = dis; if (dis < mincalc)mincalc = dis; } else { preV = tempV; continue; } } else { preV = tempV; continue; } } preV = tempV; } if (count >= 3) { disSum -= maxcalc; disSum -= mincalc; dotWidth = disSum / (count - 2); } else { dotWidth = 1.0f; } } pmd->LockMainDB(); for (size_t i = 0; i < m_HatchingDB.size(); i++) { for (size_t j = 0; j < m_HatchingDB[i]->point_indexs.size(); ++j) { BPBinary::VectorPoint* pvp = (BPBinary::VectorPoint*)m_HatchingDB[i]->point_indexs[j]; float dsq = (pvp->x1 - pvp->x2)*(pvp->x1 - pvp->x2) + (pvp->y1 - pvp->y2)*(pvp->y1 - pvp->y2); if (dsq > 0.0f) { float dis = sqrt(dsq); m_Volume = m_Volume + (dis*dotWidth); } } } for (size_t i = 0; i < m_SupportDB.size(); i++) { BPBinary::BinDataBlock* pdb = m_SupportDB[i]; if (pdb->type == BIN_VECTOR) { for (size_t j = 0; j < m_SupportDB[i]->point_indexs.size(); ++j) { BPBinary::VectorPoint* pvp = (BPBinary::VectorPoint*)m_SupportDB[i]->point_indexs[j]; float dsq = (pvp->x1 - pvp->x2)*(pvp->x1 - pvp->x2) + (pvp->y1 - pvp->y2)*(pvp->y1 - pvp->y2); if (dsq > 0.0f) { float dis = sqrt(dsq); m_SupportVolume = m_SupportVolume + (dis*dotWidth); } } } else if(pdb->type == BIN_CHAIN) { for (unsigned int j = 0; j < pdb->point_indexs.size(); ++j) { BPBinary::ChainPoint* point = (BPBinary::ChainPoint*)pdb->point_indexs[j]; if (point->points.empty())continue; float prex = point->points[0]->x; float prey = point->points[0]->y; for (unsigned int k = 1; k < point->points.size(); ++k) { float x = point->points[k]->x; float y = point->points[k]->y; float dsq = (prex - x)*(prex - x) + (prey - y)*(prey - y); if (dsq > 0.0f) { float dis = sqrt(dsq); m_SupportVolume = m_SupportVolume + (dis*dotWidth); } prex = x; prey = y; } } } } pmd->UnLockMainDB(); /*PolyTree pt; GetLayerBorders(pmd, layer, pt, false); for (PolyNode* pn : pt.AllNodes) { double value= Area(pn->Contour) * (*pmd->GetLayerThickness()) / CLIPPER_SCALE / CLIPPER_SCALE; if (!isnan(value)) { m_Volume += value; } } pt.Clear(); GetLayerBorders(pmd, layer, pt, true); for (PolyNode* pn : pt.AllNodes) { double value = Area(pn->Contour) * (*pmd->GetLayerThickness()) / CLIPPER_SCALE / CLIPPER_SCALE; if (!isnan(value)) { m_SupportVolume += value; } } pt.Clear(); double spotSize = 0.0; GetBlockSupport(pmd, layer, pt, spotSize); for (PolyNode* pn : pt.AllNodes) { double value = Len(pn->Contour) * spotSize * (*pmd->GetLayerThickness()) / CLIPPER_SCALE; if (!isnan(value)) { m_SupportVolume += value; } }*/ }