void Sweep::FillBasinReq(SweepContext& tcx, Node* node) { // if shallow stop filling if (IsShallow(tcx, *node)) { return; } Fill(tcx, *node); if (node->prev == tcx.basin.left_node && node->next == tcx.basin.right_node) { return; } else if (node->prev == tcx.basin.left_node) { Orientation o = Orient2d(*node->point, *node->next->point, *node->next->next->point); if (o == CW) { return; } node = node->next; } else if (node->next == tcx.basin.right_node) { Orientation o = Orient2d(*node->point, *node->prev->point, *node->prev->prev->point); if (o == CCW) { return; } node = node->prev; } else { // Continue with the neighbor node with lowest Y value if (node->prev->point->y < node->next->point->y) { node = node->prev; } else { node = node->next; } } FillBasinReq(tcx, node); }
void Sweep::EdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* triangle, Point& point) { if (IsEdgeSideOfTriangle(*triangle, ep, eq)) { return; } Point* p1 = triangle->PointCCW(point); Orientation o1 = Orient2d(eq, *p1, ep); if (o1 == COLLINEAR) { // ASSIMP_CHANGE (aramis_acg) throw std::runtime_error("EdgeEvent - collinear points not supported"); if( triangle->Contains(&eq, p1)) { triangle->MarkConstrainedEdge(&eq, p1 ); // We are modifying the constraint maybe it would be better to // not change the given constraint and just keep a variable for the new constraint tcx.edge_event.constrained_edge->q = p1; triangle = &triangle->NeighborAcross(point); EdgeEvent( tcx, ep, *p1, triangle, *p1 ); } else { // ASSIMP_CHANGE (aramis_acg) std::runtime_error("EdgeEvent - collinear points not supported"); } return; } Point* p2 = triangle->PointCW(point); Orientation o2 = Orient2d(eq, *p2, ep); if (o2 == COLLINEAR) { // ASSIMP_CHANGE (aramis_acg) throw std::runtime_error("EdgeEvent - collinear points not supported"); if( triangle->Contains(&eq, p2)) { triangle->MarkConstrainedEdge(&eq, p2 ); // We are modifying the constraint maybe it would be better to // not change the given constraint and just keep a variable for the new constraint tcx.edge_event.constrained_edge->q = p2; triangle = &triangle->NeighborAcross(point); EdgeEvent( tcx, ep, *p2, triangle, *p2 ); } else { // ASSIMP_CHANGE (aramis_acg) throw std::runtime_error("EdgeEvent - collinear points not supported"); } return; } if (o1 == o2) { // Need to decide if we are rotating CW or CCW to get to a triangle // that will cross edge if (o1 == CW) { triangle = triangle->NeighborCCW(point); } else{ triangle = triangle->NeighborCW(point); } EdgeEvent(tcx, ep, eq, triangle, point); } else { // This triangle crosses constraint so lets flippin start! FlipEdgeEvent(tcx, ep, eq, triangle, point); } }
void Sweep::FillBasin(SweepContext& tcx, Node& node) { if (Orient2d(*node.point, *node.next->point, *node.next->next->point) == CCW) { tcx.basin.left_node = node.next->next; } else { tcx.basin.left_node = node.next; } // Find the bottom and right node tcx.basin.bottom_node = tcx.basin.left_node; while (tcx.basin.bottom_node->next && tcx.basin.bottom_node->point->y >= tcx.basin.bottom_node->next->point->y) { tcx.basin.bottom_node = tcx.basin.bottom_node->next; } if (tcx.basin.bottom_node == tcx.basin.left_node) { // No valid basin return; } tcx.basin.right_node = tcx.basin.bottom_node; while (tcx.basin.right_node->next && tcx.basin.right_node->point->y < tcx.basin.right_node->next->point->y) { tcx.basin.right_node = tcx.basin.right_node->next; } if (tcx.basin.right_node == tcx.basin.bottom_node) { // No valid basins return; } tcx.basin.width = tcx.basin.right_node->point->x - tcx.basin.left_node->point->x; tcx.basin.left_highest = tcx.basin.left_node->point->y > tcx.basin.right_node->point->y; FillBasinReq(tcx, tcx.basin.bottom_node); }
void Sweep::FillLeftConcaveEdgeEvent(SweepContext& tcx, Edge* edge, Node& node) { Fill(tcx, *node.prev); if (node.prev->point != edge->p) { // Next above or below edge? if (Orient2d(*edge->q, *node.prev->point, *edge->p) == CW) { // Below if (Orient2d(*node.point, *node.prev->point, *node.prev->prev->point) == CW) { // Next is concave FillLeftConcaveEdgeEvent(tcx, edge, node); } else{ // Next is convex } } } }
void Sweep::FillLeftConvexEdgeEvent(SweepContext& tcx, Edge* edge, Node& node) { // Next concave or convex? if (Orient2d(*node.prev->point, *node.prev->prev->point, *node.prev->prev->prev->point) == CW) { // Concave FillLeftConcaveEdgeEvent(tcx, edge, *node.prev); } else{ // Convex // Next above or below edge? if (Orient2d(*edge->q, *node.prev->prev->point, *edge->p) == CW) { // Below FillLeftConvexEdgeEvent(tcx, edge, *node.prev); } else{ // Above } } }
void Sweep::FillLeftAboveEdgeEvent(SweepContext& tcx, Edge* edge, Node* node) { while (node->prev->point->x > edge->p->x) { // Check if next node is below the edge if (Orient2d(*edge->q, *node->prev->point, *edge->p) == CW) { FillLeftBelowEdgeEvent(tcx, edge, *node); } else { node = node->prev; } } }
Point& Sweep::NextFlipPoint(Point& ep, Point& eq, Triangle& ot, Point& op) { Orientation o2d = Orient2d(eq, op, ep); if (o2d == CW) { // Right return *ot.PointCCW(op); } else if (o2d == CCW) { // Left return *ot.PointCW(op); } else{ //throw new RuntimeException("[Unsupported] Opposing point on constrained edge"); assert(0); } }
void Sweep::FillLeftBelowEdgeEvent(SweepContext& tcx, Edge* edge, Node& node) { if (node.point->x > edge->p->x) { if (Orient2d(*node.point, *node.prev->point, *node.prev->prev->point) == CW) { // Concave FillLeftConcaveEdgeEvent(tcx, edge, node); } else { // Convex FillLeftConvexEdgeEvent(tcx, edge, node); // Retry this one FillLeftBelowEdgeEvent(tcx, edge, node); } } }
Point& Sweep::NextFlipPoint(Point& ep, Point& eq, Triangle& ot, Point& op) { Orientation o2d = Orient2d(eq, op, ep); if (o2d == CW) { // Right return *ot.PointCCW(op); } else if (o2d == CCW) { // Left return *ot.PointCW(op); } else{ //throw new RuntimeException("[Unsupported] Opposing point on constrained edge"); // ASSIMP_CHANGE (aramis_acg) throw std::runtime_error("[Unsupported] Opposing point on constrained edge"); } }
void Sweep::FlipEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* t, Point& p) { Triangle& ot = t->NeighborAcross(p); Point& op = *ot.OppositePoint(*t, p); if (&ot == NULL) { // If we want to integrate the fillEdgeEvent do it here // With current implementation we should never get here //throw new RuntimeException( "[BUG:FIXME] FLIP failed due to missing triangle"); assert(0); } if (InScanArea(p, *t->PointCCW(p), *t->PointCW(p), op)) { // Lets rotate shared edge one vertex CW RotateTrianglePair(*t, p, ot, op); tcx.MapTriangleToNodes(*t); tcx.MapTriangleToNodes(ot); if (p == eq && op == ep) { if (eq == *tcx.edge_event.constrained_edge->q && ep == *tcx.edge_event.constrained_edge->p) { t->MarkConstrainedEdge(&ep, &eq); ot.MarkConstrainedEdge(&ep, &eq); Legalize(tcx, *t); Legalize(tcx, ot); } else { // XXX: I think one of the triangles should be legalized here? } } else { Orientation o = Orient2d(eq, op, ep); t = &NextFlipTriangle(tcx, (int)o, *t, ot, p, op); FlipEdgeEvent(tcx, ep, eq, t, p); } } else { Point& newP = NextFlipPoint(ep, eq, ot, op); FlipScanEdgeEvent(tcx, ep, eq, *t, ot, newP); EdgeEvent(tcx, ep, eq, t, p); } }