GrpcPrint/PrintS/job/VolumeCalc.cpp

608 lines
18 KiB
C++

#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<BPBinary::BinDataBlock*> m_BordersDB;
for (std::map<int, MetaData::DataBlockList*>::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<cInt>(point->points[k]->x * CLIPPER_SCALE), static_cast<cInt>(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<BPBinary::BinDataBlock*> m_BordersDB;
for (std::map<int, MetaData::DataBlockList*>::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<cInt>(point->points[k]->x * CLIPPER_SCALE), static_cast<cInt>(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<PolyNode*> 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<PolyNode*>::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<BPBinary::BinDataBlock*> m_HatchingDB;
vector<BPBinary::BinDataBlock*> m_SupportDB;
pmd->LockMainDB();
for (std::map<int, MetaData::DataBlockList*>::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<CalcVar> 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;
}
}*/
}