/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ /** * @file * Utilities and helpers - implementation */ #include "CDTUtils.h" #include "predicates.h" // robust predicates: orient, in-circle #include namespace CDT { //***************************************************************************** // V2d //***************************************************************************** template V2d V2d::make(const T x, const T y) { V2d out = {x, y}; return out; } //***************************************************************************** // Box2d //***************************************************************************** template Box2d envelopBox(const std::vector >& vertices) { return envelopBox( vertices.begin(), vertices.end(), getX_V2d, getY_V2d); } //***************************************************************************** // Edge //***************************************************************************** CDT_INLINE_IF_HEADER_ONLY Edge::Edge(VertInd iV1, VertInd iV2) : m_vertices( iV1 < iV2 ? std::make_pair(iV1, iV2) : std::make_pair(iV2, iV1)) {} CDT_INLINE_IF_HEADER_ONLY bool Edge::operator==(const Edge& other) const { return m_vertices == other.m_vertices; } CDT_INLINE_IF_HEADER_ONLY bool Edge::operator!=(const Edge& other) const { return !(this->operator==(other)); } CDT_INLINE_IF_HEADER_ONLY VertInd Edge::v1() const { return m_vertices.first; } CDT_INLINE_IF_HEADER_ONLY VertInd Edge::v2() const { return m_vertices.second; } CDT_INLINE_IF_HEADER_ONLY const std::pair& Edge::verts() const { return m_vertices; } //***************************************************************************** // Utility functions //***************************************************************************** CDT_INLINE_IF_HEADER_ONLY Index ccw(Index i) { return Index((i + 1) % 3); } CDT_INLINE_IF_HEADER_ONLY Index cw(Index i) { return Index((i + 2) % 3); } CDT_INLINE_IF_HEADER_ONLY bool isOnEdge(const PtTriLocation::Enum location) { return location > PtTriLocation::Outside; } CDT_INLINE_IF_HEADER_ONLY Index edgeNeighbor(const PtTriLocation::Enum location) { assert(location >= PtTriLocation::OnEdge1); return static_cast(location - PtTriLocation::OnEdge1); } template T orient2D(const V2d& p, const V2d& v1, const V2d& v2) { return predicates::adaptive::orient2d(v1.x, v1.y, v2.x, v2.y, p.x, p.y); } template PtLineLocation::Enum locatePointLine( const V2d& p, const V2d& v1, const V2d& v2, const T orientationTolerance) { return classifyOrientation(orient2D(p, v1, v2), orientationTolerance); } template PtLineLocation::Enum classifyOrientation(const T orientation, const T orientationTolerance) { if(orientation < -orientationTolerance) return PtLineLocation::Right; if(orientation > orientationTolerance) return PtLineLocation::Left; return PtLineLocation::OnLine; } template PtTriLocation::Enum locatePointTriangle( const V2d& p, const V2d& v1, const V2d& v2, const V2d& v3) { using namespace predicates::adaptive; PtTriLocation::Enum result = PtTriLocation::Inside; PtLineLocation::Enum edgeCheck = locatePointLine(p, v1, v2); if(edgeCheck == PtLineLocation::Right) return PtTriLocation::Outside; if(edgeCheck == PtLineLocation::OnLine) result = PtTriLocation::OnEdge1; edgeCheck = locatePointLine(p, v2, v3); if(edgeCheck == PtLineLocation::Right) return PtTriLocation::Outside; if(edgeCheck == PtLineLocation::OnLine) result = PtTriLocation::OnEdge2; edgeCheck = locatePointLine(p, v3, v1); if(edgeCheck == PtLineLocation::Right) return PtTriLocation::Outside; if(edgeCheck == PtLineLocation::OnLine) result = PtTriLocation::OnEdge3; return result; } CDT_INLINE_IF_HEADER_ONLY Index opoNbr(const Index vertIndex) { if(vertIndex == Index(0)) return Index(1); if(vertIndex == Index(1)) return Index(2); if(vertIndex == Index(2)) return Index(0); throw std::runtime_error("Invalid vertex index"); } CDT_INLINE_IF_HEADER_ONLY Index opoVrt(const Index neighborIndex) { if(neighborIndex == Index(0)) return Index(2); if(neighborIndex == Index(1)) return Index(0); if(neighborIndex == Index(2)) return Index(1); throw std::runtime_error("Invalid neighbor index"); } CDT_INLINE_IF_HEADER_ONLY Index opposedTriangleInd(const Triangle& tri, const VertInd iVert) { for(Index vi = Index(0); vi < Index(3); ++vi) if(iVert == tri.vertices[vi]) return opoNbr(vi); throw std::runtime_error("Could not find opposed triangle index"); } CDT_INLINE_IF_HEADER_ONLY Index opposedTriangleInd( const Triangle& tri, const VertInd iVedge1, const VertInd iVedge2) { for(Index vi = Index(0); vi < Index(3); ++vi) { const VertInd iVert = tri.vertices[vi]; if(iVert != iVedge1 && iVert != iVedge2) return opoNbr(vi); } throw std::runtime_error("Could not find opposed-to-edge triangle index"); } CDT_INLINE_IF_HEADER_ONLY Index opposedVertexInd(const Triangle& tri, const TriInd iTopo) { for(Index ni = Index(0); ni < Index(3); ++ni) if(iTopo == tri.neighbors[ni]) return opoVrt(ni); throw std::runtime_error("Could not find opposed vertex index"); } CDT_INLINE_IF_HEADER_ONLY Index neighborInd(const Triangle& tri, const TriInd iTnbr) { for(Index ni = Index(0); ni < Index(3); ++ni) if(iTnbr == tri.neighbors[ni]) return ni; throw std::runtime_error("Could not find neighbor triangle index"); } CDT_INLINE_IF_HEADER_ONLY Index vertexInd(const Triangle& tri, const VertInd iV) { for(Index i = Index(0); i < Index(3); ++i) if(iV == tri.vertices[i]) return i; throw std::runtime_error("Could not find vertex index in triangle"); } CDT_INLINE_IF_HEADER_ONLY TriInd opposedTriangle(const Triangle& tri, const VertInd iVert) { return tri.neighbors[opposedTriangleInd(tri, iVert)]; } CDT_INLINE_IF_HEADER_ONLY VertInd opposedVertex(const Triangle& tri, const TriInd iTopo) { return tri.vertices[opposedVertexInd(tri, iTopo)]; } template bool isInCircumcircle( const V2d& p, const V2d& v1, const V2d& v2, const V2d& v3) { using namespace predicates::adaptive; return incircle(v1.x, v1.y, v2.x, v2.y, v3.x, v3.y, p.x, p.y) > T(0); } CDT_INLINE_IF_HEADER_ONLY bool verticesShareEdge(const TriIndVec& aTris, const TriIndVec& bTris) { for(TriIndVec::const_iterator it = aTris.begin(); it != aTris.end(); ++it) if(std::find(bTris.begin(), bTris.end(), *it) != bTris.end()) return true; return false; } template T distanceSquared(const T ax, const T ay, const T bx, const T by) { const T dx = bx - ax; const T dy = by - ay; return dx * dx + dy * dy; } template T distance(const T ax, const T ay, const T bx, const T by) { return std::sqrt(distanceSquared(ax, ay, bx, by)); } template T distance(const V2d& a, const V2d& b) { return distance(a.x, a.y, b.x, b.y); } template T distanceSquared(const V2d& a, const V2d& b) { return distanceSquared(a.x, a.y, b.x, b.y); } } // namespace CDT