11#ifndef JAU_GAMP_GRAPH_TESS_IMPL_LOOP_HPP_
12#define JAU_GAMP_GRAPH_TESS_IMPL_LOOP_HPP_
30namespace gamp::graph::tess::impl {
32 using namespace jau::math;
33 using namespace jau::math::geom;
34 using namespace gamp::graph;
35 using namespace gamp::graph::tess;
43 typedef std::shared_ptr<Loop> LoopRef;
44 typedef std::vector<LoopRef> LoopRefList;
48 constexpr static bool FixedWindingRule =
true;
51 std::vector<HEdgeRef> m_hedges;
53 GraphOutlineRef m_initialOutline;
55 GraphOutlineRefList m_outlines;
58 struct Private{
explicit Private() =
default; };
60 HEdgePtr createHEdge(
const GraphVertexRef& vert,
int type) {
61 HEdgeRef owner = HEdge::create(vert, type);
62 HEdgePtr ptr = owner.get();
63 m_hedges.push_back(std::move(owner));
68 Loop(Private, GraphOutlineRef polyline,
int edgeType,
bool isComplex)
69 : m_hedges(), m_box(),
70 m_initialOutline(
std::
move(polyline)),
71 m_isComplex(isComplex),
73 m_root(initFromPolyline(m_initialOutline, edgeType))
82 HEdgePtr initFromPolyline(
const GraphOutlineRef& outline,
int edgeType) {
83 m_outlines.push_back(outline);
84 const GraphVertexRefList& vertices = outline->graphPoints();
86 if(vertices.size() < 3) {
87 jau_ERR_PRINT2(
"Graph: Loop.initFromPolyline: GraphOutline's vertices < 3: %zu", vertices.size() );
94 Winding winding = FixedWindingRule ? edgeWinding : outline->outline().getWinding();
96 if( HEdge::BOUNDARY == edgeType &&
Winding::CCW != winding ) {
102 HEdgePtr firstEdge =
nullptr;
103 HEdgePtr lastEdge =
nullptr;
105 if( winding == edgeWinding || HEdge::BOUNDARY == edgeType ) {
107 const size_t maxVertIdx = vertices.size() - 1;
108 for(
size_t index = 0; index <= maxVertIdx; ++index) {
109 GraphVertexRef v1 = vertices[index];
110 m_box.resize(v1->coord());
112 HEdgePtr edge = createHEdge(v1, edgeType);
115 lastEdge->setNext(edge);
116 edge->setPrev(lastEdge);
122 if(index == maxVertIdx ) {
123 edge->setNext(firstEdge);
124 firstEdge->setPrev(edge);
131 for(
size_t index = vertices.size(); index-- > 0;) {
132 GraphVertexRef v1 = vertices[index];
133 m_box.resize(v1->coord());
135 HEdgePtr edge = createHEdge(v1, edgeType);
138 lastEdge->setNext(edge);
139 edge->setPrev(lastEdge);
145 edge->setNext(firstEdge);
146 firstEdge->setPrev(edge);
162 GraphVertexRef locateClosestVertex(
const GraphOutlineRef& polyline) {
163 float minDistance = std::numeric_limits<float>::max();
164 const GraphVertexRefList& initVertices = m_initialOutline->graphPoints();
165 if( initVertices.size() < 2 ) {
168 const GraphVertexRefList& vertices = polyline->graphPoints();
169 HEdgePtr closestE =
nullptr;
170 GraphVertexRef closestV;
172 size_t initSz = initVertices.size();
173 GraphVertexRef v0 = initVertices[0];
174 for(
size_t i=1; i< initSz; ++i){
175 GraphVertexRef v1 = initVertices[i];
176 for(
size_t pos=0; pos<vertices.size(); ++pos) {
177 GraphVertexRef cand = vertices[pos];
178 float distance = v0->coord().dist(cand->coord());
179 if(distance < minDistance){
181 for (
const GraphVertexRef& vert : vertices){
182 if( !( vert == v0 || vert == v1 || vert == cand) ) {
183 inside =
isInCircle2D(v0->coord(), v1->coord(), cand->coord(), vert->coord());
191 minDistance = distance;
192 closestE = v0->findBoundEdge();
204 bool intersectsOutline(
const Vertex& a1,
const Vertex& a2,
const Vertex& b)
const noexcept {
205 for(
const GraphOutlineRef &outline : m_outlines) {
206 const GraphVertexRefList &vertices = outline->graphPoints();
207 size_t sz = vertices.size();
209 const Vertex* v0 = &vertices[0]->vertex();
210 for(
size_t i=1; i< sz; i++){
211 const Vertex& v1 = vertices[i]->vertex();
212 if( *v0 != b && v1 != b ) {
213 if( *v0 != a1 && v1 != a1 &&
217 if( *v0 != a2 && v1 != a2 &&
228 HEdgePtr isValidNeighbor(HEdgePtr candEdge,
bool delaunay)
const noexcept {
229 const GraphVertexRef& rootGPoint = m_root->getGraphPoint();
230 const GraphVertexRef& nextGPoint = m_root->getNext()->getGraphPoint();
231 const Vertex& rootPoint = rootGPoint->vertex();
232 const Vertex& nextPoint = nextGPoint->vertex();
233 const Vertex& candPoint = candEdge->getGraphPoint()->vertex();
235 ( m_isComplex && intersectsOutline(rootPoint, nextPoint, candPoint) ) ) {
241 HEdgePtr e = candEdge->getNext();
242 while (e != candEdge){
243 const GraphVertexRef& egp = e->getGraphPoint();
244 const Vertex& ep = egp->vertex();
245 if(egp != rootGPoint &&
266 TriangleRef createTriangle(Vertex& v1, Vertex& v2, Vertex& v3, HEdgePtr rootT)
const noexcept {
272 boundary.
put(0, rootT->getGraphPoint()->isBoundaryContained());
273 boundary.
put(1, rootT->getNext()->getGraphPoint()->isBoundaryContained());
274 boundary.
put(2, rootT->getNext()->getNext()->getGraphPoint()->isBoundaryContained());
279 static LoopRef createBoundary(
const GraphOutlineRef& polyline,
bool isConvex) {
280 LoopRef res = std::make_shared<Loop>(Private(), polyline, HEdge::BOUNDARY, isConvex);
287 const HEdgePtr& getHEdge() const noexcept {
return m_root; }
289 bool isSimplex() const noexcept {
290 return (m_root->getNext()->getNext()->getNext() == m_root);
294 HEdgePtr next1 = m_root->getNext();
296 Vertex& rootPoint = m_root->getGraphPoint()->vertex();
297 Vertex& nextPoint = next1->getGraphPoint()->vertex();
298 Vertex& candPoint = next1->getNext()->getGraphPoint()->vertex();
299 if( m_isComplex && intersectsOutline(rootPoint, nextPoint, candPoint) ) {
302 return Triangle::create(rootPoint, nextPoint, candPoint, checkVerticesBoundary(m_root));
304 HEdgePtr prev = m_root->getPrev();
305 HEdgePtr next2 = isValidNeighbor(next1->getNext(), delaunay);
307 m_root = m_root->getNext();
310 GraphVertexRef v1 = m_root->getGraphPoint();
311 GraphVertexRef v2 = next1->getGraphPoint();
312 GraphVertexRef v3 = next2->getGraphPoint();
314 HEdgePtr v3Edge = createHEdge(v3, HEdge::INNER);
316 HEdge::connect(v3Edge, m_root);
317 HEdge::connect(next1, v3Edge);
319 HEdgePtr v3EdgeSib = v3Edge->getSibling();
321 v3EdgeSib = createHEdge(v3Edge->getNext()->getGraphPoint(), HEdge::INNER);
322 HEdge::makeSiblings(v3Edge, v3EdgeSib);
324 HEdge::connect(prev, v3EdgeSib);
325 HEdge::connect(v3EdgeSib, next2);
327 TriangleRef t = createTriangle(v1->vertex(), v2->vertex(), v3->vertex(), m_root);
332 void addConstraintCurveHole(
const GraphOutlineRef& polyline) {
335 if( !initFromPolyline(polyline, HEdge::HOLE) ) {
338 GraphVertexRef v3 = locateClosestVertex(polyline);
340 jau_WARN_PRINT(
"Graph: Loop.locateClosestVertex returns null; root valid? %d", (
nullptr!=m_root));
346 HEdgePtr v3Edge = v3->findBoundEdge();
347 HEdgePtr v3EdgeP = v3Edge->getPrev();
348 HEdgePtr crossEdge = createHEdge(m_root->getGraphPoint(), HEdge::INNER);
350 HEdge::connect(m_root->getPrev(), crossEdge);
351 HEdge::connect(crossEdge, v3Edge);
353 HEdgePtr crossEdgeSib = crossEdge->getSibling();
355 crossEdgeSib = createHEdge(crossEdge->getNext()->getGraphPoint(), HEdge::INNER);
356 HEdge::makeSiblings(crossEdge, crossEdgeSib);
359 HEdge::connect(v3EdgeP, crossEdgeSib);
360 HEdge::connect(crossEdgeSib, m_root);
363 bool checkInside(
const Vertex& v)
const noexcept {
364 if(!m_box.contains(v.coord())){
368 HEdgePtr current = m_root;
369 HEdgePtr next = m_root->getNext();
370 const Vec3f& vc = v.coord();
372 const Vec3f& v2c = current->getGraphPoint()->vertex().coord();
373 const Vec3f& v1c = next->getGraphPoint()->vertex().coord();
375 if ( ( (v1c.
y > vc.
y) != (v2c.
y > vc.
y) ) &&
376 ( vc.
x < (v2c.
x - v1c.
x) * (vc.
y - v1c.
y) / (v2c.
y - v1c.
y) + v1c.
x ) ) {
380 next = current->getNext();
381 }
while(current != m_root);
385 size_t computeLoopSize() const noexcept {
391 }
while(e != m_root);
static TriangleRef create(const Vertex &v1, const Vertex &v2, const Vertex &v3, const tribit_t &boundaryVertices) noexcept
jau::bitfield_t< uint8_t, 3 > tribit_t
constexpr const Vec3f & coord() const noexcept
constexpr bool put(size_type bitpos, bool v) noexcept
Writes the bit value v to position bitpos into this storage.
#define jau_WARN_PRINT(...)
Use for unconditional warning messages, prefix '[elapsed_time] Warning @ FILE:LINE FUNC: '.
#define jau_ERR_PRINT2(...)
Use for unconditional error messages, prefix '[elapsed_time] Error @ FILE:LINE FUNC: '.
@ std
Denotes a func::std_target_t.
std::shared_ptr< Triangle > TriangleRef
constexpr bool is2DCCW(const Vec3f &a, const Vec3f &b, const Vec3f &c) noexcept
Check if points are in ccw order.
std::string_view to_string(const math_error_t v) noexcept
Returns std::string_view representation of math_error_t.
constexpr bool testSeg2SegIntersection2D(Vec2f *result, const Vec2f &p, const Vec2f &p2, const Vec2f &q, const Vec2f &q2, const bool do_collinear=false) noexcept
See p + t r = q + u s and its terse C# implementation
constexpr bool isInCircle2D(const Vec3f &a, const Vec3f &b, const Vec3f &c, const Vec3f &d) noexcept
Check if vertices in triangle circumcircle given d vertex, from paper by Guibas and Stolfi (1985).
void print_backtrace(const bool skip_anon_frames, const jau::snsize_t max_frames=-1, const jau::snsize_t skip_frames=2) noexcept
Prints the de-mangled backtrace string separated by newline excluding this function to stderr,...