std::vector<PolygonAdjacency> GeneralPolygon::_getConexions(TPPLPoly& A, TPPLPoly& B) { std::vector<sf::Vector2f> pointsA = _getPoints(A); std::vector<sf::Vector2f> edgesA = _getPoints(A); std::vector<sf::Vector2f> pointsB = _getPoints(B); std::vector<sf::Vector2f> edgesB = _getPoints(B); auto dot = [&](const sf::Vector2f& a, const sf::Vector2f& b) -> float { return (a.x*b.x + a.y*b.y); }; auto norm = [&](const sf::Vector2f& a) -> float { return sqrt(a.x*a.x + a.y*a.y); }; auto dist = [&](const sf::Vector2f& a, const sf::Vector2f& b) -> float { float aux1 = a.x-b.x; float aux2 = a.y-b.y; return sqrt(aux1*aux1 + aux2*aux2); }; auto normalized = [&](const sf::Vector2f& a) -> sf::Vector2f { float mag = norm(a); return (a/mag); }; auto areEdgesParallel = [&](const sf::Vector2f& e1, const sf::Vector2f& e2) -> bool { if( abs( dot(normalized(e1),normalized(e2)) ) > 0.9f ) return true; }; auto minDistanceEdges = [&](const std::pair<sf::Vector2f, sf::Vector2f> &S1, const std::pair<sf::Vector2f, sf::Vector2f> &S2) -> float { // http://geomalgorithms.com/a07-_distance.html sf::Vector2f u = S1.second - S1.first; sf::Vector2f v = S2.second - S2.first; sf::Vector2f w = S1.first - S2.first; float a = dot(u,u); // always >= 0 float b = dot(u,v); float c = dot(v,v); // always >= 0 float d = dot(u,w); float e = dot(v,w); float D = a*c - b*b; // always >= 0 float sc, sN, sD = D; // sc = sN / sD, default sD = D >= 0 float tc, tN, tD = D; // tc = tN / tD, default tD = D >= 0 // compute the line parameters of the two closest points if (D < SMALL_NUM) { // the lines are almost parallel sN = 0.0; // force using point P0 on segment S1 sD = 1.0; // to prevent possible division by 0.0 later tN = e; tD = c; } else // get the closest points on the infinite lines { sN = (b*e - c*d); tN = (a*e - b*d); if (sN < 0.0) // sc < 0 => the s=0 edge is visible { sN = 0.0; tN = e; tD = c; } else if (sN > sD) // sc > 1 => the s=1 edge is visible { sN = sD; tN = e + b; tD = c; } } if (tN < 0.0) { // tc < 0 => the t=0 edge is visible tN = 0.0; // recompute sc for this edge if (-d < 0.0) sN = 0.0; else if (-d > a) sN = sD; else { sN = -d; sD = a; } } else if (tN > tD) { // tc > 1 => the t=1 edge is visible tN = tD; // recompute sc for this edge if ((-d + b) < 0.0) sN = 0; else if ((-d + b) > a) sN = sD; else { sN = (-d + b); sD = a; } } // finally do the division to get sc and tc sc = (abs(sN) < SMALL_NUM ? 0.0 : sN / sD); tc = (abs(tN) < SMALL_NUM ? 0.0 : tN / tD); // get the difference of the two closest points sf::Vector2f dP = w + (sc * u) - (tc * v); // = S1(sc) - S2(tc) return norm(dP); // return the closest distance }; auto testCloseEdgePoints = [&](std::pair<sf::Vector2f, sf::Vector2f> &edgePoints1, std::pair<sf::Vector2f, sf::Vector2f> &edgePoints2, float minDist) -> bool { if( ( dist(edgePoints1.first, edgePoints2.first) < minDist ) && ( dist(edgePoints1.second, edgePoints2.second) < minDist ) ) return true; if( ( dist(edgePoints1.second, edgePoints2.first) < minDist ) && ( dist(edgePoints1.first, edgePoints2.second) < minDist ) ) return true; return false; }; std::vector<PolygonAdjacency> conexions; // here the actual work for(unsigned int eA=0; eA < edgesA.size() ; ++eA ) for(unsigned int eB=0; eB < edgesB.size() ; ++eB ) { if( areEdgesParallel(edgesA[eA], edgesB[eB]) ) if( minDistanceEdges(_getEdgePoints(eA, pointsA), _getEdgePoints(eB, pointsB)) < ADJACENT_DISTANCE ) if( testCloseEdgePoints(_getEdgePoints(eA, pointsA), _getEdgePoints(eB, pointsB), ADJACENT_DISTANCE ) ) conexions.push_back( PolygonAdjacency(&A, &B, eA, eB) ); } return conexions; }
void Normals::ComputeNormals(const PolygonalModel& objs, std::vector<Normals::PolygonNormalData>& polygonNormals, NormalList& vertexNormals, PolygonAdjacencyGraph& polygonAdjacency, NormalsGeneration src) { polygonNormals.clear(); vertexNormals.clear(); if (objs.empty()) { return; } std::vector<double> polygonAreas; const size_t approxNumPolygons = objs.front().polygons.size() * objs.size(); polygonAreas.reserve(approxNumPolygons); polygonNormals.reserve(approxNumPolygons); const size_t approxNumVertices = approxNumPolygons * (objs.front().polygons.empty() ? 1 : objs.front().polygons.front().points.size()); std::unordered_map<Point3D, Vector3D, HashAndComparePoint3D, HashAndComparePoint3D> vertexMap; vertexMap.reserve(approxNumVertices); std::unordered_map<LineSegment, PolygonAdjacency, HashAndCompareEdge, HashAndCompareEdge> edgeMap; edgeMap.reserve(2 * approxNumVertices); int polygonIdx = 0; for (auto i = objs.begin(); i != objs.end(); ++i) { for (auto j = i->polygons.begin(); j != i->polygons.end(); ++j) { const std::pair<double, HomogeneousPoint> areaAndCentroid = j->AreaAndCentroid(); Vector3D currPolygonNormal = j->Normal(); if (src == NORMALS_SMART) { FixNormal(*i, j - i->polygons.begin(), areaAndCentroid, currPolygonNormal); } PolygonNormalData d(LineSegment(areaAndCentroid.second, HomogeneousPoint(Point3D(areaAndCentroid.second) + currPolygonNormal))); polygonNormals.push_back(d); polygonAreas.push_back(areaAndCentroid.first); for (auto v = j->points.begin(); v != j->points.end(); ++v) { if ((src != NORMALS_FILE) || j->tmpNormals.empty()) { if (vertexMap.find(Point3D(*v)) == vertexMap.end()) { vertexMap[Point3D(*v)] = currPolygonNormal * areaAndCentroid.first; } else { vertexMap[Point3D(*v)] += currPolygonNormal * areaAndCentroid.first; } } else { vertexMap[Point3D(*v)] = j->tmpNormals[v - j->points.begin()]; } const LineSegment currEdge(*v, (v + 1 != j->points.end()) ? *(v + 1) : j->points.front()); if (edgeMap.find(currEdge) == edgeMap.end()) { edgeMap[currEdge] = PolygonAdjacency(polygonIdx, (i - objs.begin()), (j - i->polygons.begin()), v - j->points.begin()); } else { edgeMap[currEdge].polygonIdxs.push_back(polygonIdx); } } ++polygonIdx; } } polygonAdjacency.clear(); polygonAdjacency.reserve(edgeMap.size()); for (auto e = edgeMap.begin(); e != edgeMap.end(); ++e) { polygonAdjacency.push_back(e->second); } vertexNormals.reserve(vertexMap.size()); for (auto i = vertexMap.begin(); i != vertexMap.end(); ++i) { const Vector3D direction = i->second.Normalized(); vertexNormals.push_back(LineSegment(HomogeneousPoint(i->first), HomogeneousPoint(i->first + direction))); } polygonIdx = 0; for (auto i = objs.begin(); i != objs.end(); ++i) { for (auto j = i->polygons.begin(); j != i->polygons.end(); ++j) { for (auto v = j->points.begin(); v != j->points.end(); ++v) { const Vector3D direction = vertexMap[Point3D(*v)].Normalized(); polygonNormals[polygonIdx].VertexNormals.push_back(LineSegment(*v, HomogeneousPoint(Point3D(*v) + direction))); } ++polygonIdx; } } }