#include #include #include #include #include "cutface.h" IMPL_CutFaceFromString IMPL_CutFaceToString TMPL_CutFaceToPoints static void correctFlippedNormal(std::vector *points) { if (points->size() < 3) return; std::vector referenceFacePoints = { QVector3D((float)-1.0, (float)-1.0, (float)0.0), QVector3D((float)1.0, (float)-1.0, (float)0.0), QVector3D((float)1.0, (float)1.0, (float)0.0) }; QVector3D referenceNormal = QVector3D::normal(referenceFacePoints[0], referenceFacePoints[1], referenceFacePoints[2]); QVector3D normal; for (size_t i = 0; i < points->size(); ++i) { size_t j = (i + 1) % points->size(); size_t k = (j + 1) % points->size(); std::vector facePoints = { QVector3D(((*points)[i]).x(), ((*points)[i]).y(), (float)0.0), QVector3D(((*points)[j]).x(), ((*points)[j]).y(), (float)0.0), QVector3D(((*points)[k]).x(), ((*points)[k]).y(), (float)0.0) }; normal += QVector3D::normal(facePoints[0], facePoints[1], facePoints[2]); } normal.normalize(); if (QVector3D::dotProduct(referenceNormal, normal) > 0) return; std::reverse(points->begin() + 1, points->end()); } void normalizeCutFacePoints(std::vector *points) { QVector2D center; if (nullptr == points || points->empty()) return; float xLow = std::numeric_limits::max(); float xHigh = std::numeric_limits::lowest(); float yLow = std::numeric_limits::max(); float yHigh = std::numeric_limits::lowest(); for (const auto &position: *points) { if (position.x() < xLow) xLow = position.x(); else if (position.x() > xHigh) xHigh = position.x(); if (position.y() < yLow) yLow = position.y(); else if (position.y() > yHigh) yHigh = position.y(); } float xMiddle = (xHigh + xLow) * 0.5; float yMiddle = (yHigh + yLow) * 0.5; float xSize = xHigh - xLow; float ySize = yHigh - yLow; float longSize = ySize; if (xSize > longSize) longSize = xSize; if (qFuzzyIsNull(longSize)) longSize = 0.000001; for (auto &position: *points) { position.setX((position.x() - xMiddle) * 2 / longSize); position.setY((position.y() - yMiddle) * 2 / longSize); } correctFlippedNormal(points); } void cutFacePointsFromNodes(std::vector &points, const std::vector> &nodes, bool isRing, std::vector *pointsIds) { if (isRing) { if (nodes.size() < 3) return; for (const auto &it: nodes) { points.push_back(QVector2D(std::get<1>(it), std::get<2>(it))); } if (nullptr != pointsIds) { for (const auto &it: nodes) { pointsIds->push_back(std::get<3>(it)); } } normalizeCutFacePoints(&points); return; } if (nodes.size() < 2) return; std::vector edges; for (size_t i = 1; i < nodes.size(); ++i) { const auto &previous = nodes[i - 1]; const auto ¤t = nodes[i]; edges.push_back((QVector2D(std::get<1>(current), std::get<2>(current)) - QVector2D(std::get<1>(previous), std::get<2>(previous))).normalized()); } std::vector nodeDirections; nodeDirections.push_back(edges[0]); for (size_t i = 1; i < nodes.size() - 1; ++i) { const auto &previousEdge = edges[i - 1]; const auto &nextEdge = edges[i]; nodeDirections.push_back((previousEdge + nextEdge).normalized()); } nodeDirections.push_back(edges[edges.size() - 1]); std::vector> cutPoints; for (size_t i = 0; i < nodes.size(); ++i) { const auto ¤t = nodes[i]; const auto &direction = nodeDirections[i]; const auto &radius = std::get<0>(current); QVector3D origin = QVector3D(std::get<1>(current), std::get<2>(current), 0); QVector3D pointer = QVector3D(direction.x(), direction.y(), 0); QVector3D rotateAxis = QVector3D(0, 0, 1); QVector3D u = QVector3D::crossProduct(pointer, rotateAxis).normalized(); QVector3D upPoint = origin + u * radius; QVector3D downPoint = origin - u * radius; cutPoints.push_back({QVector2D(upPoint.x(), upPoint.y()), QVector2D(downPoint.x(), downPoint.y())}); } for (const auto &it: cutPoints) { points.push_back(it.first); } if (nullptr != pointsIds) { for (const auto &it: nodes) { pointsIds->push_back(std::get<3>(it) + QString("/1")); } } for (auto it = cutPoints.rbegin(); it != cutPoints.rend(); ++it) { points.push_back(it->second); } if (nullptr != pointsIds) { for (auto it = nodes.rbegin(); it != nodes.rend(); ++it) { pointsIds->push_back(std::get<3>(*it) + QString("/2")); } } normalizeCutFacePoints(&points); }