aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Göthel <[email protected]>2024-02-12 06:17:07 +0100
committerSven Göthel <[email protected]>2024-02-12 06:17:07 +0100
commita77b487a44124a9e55fa9a53d1f9c3ae20b9c3ba (patch)
treebb9271e933b09bfaa92253bc76e8295f56174041
parentbf882af1675f390500cc36c5396f75c394372d52 (diff)
Bug 1501: Graph Delaunay: Use default winding outer-boundary:=CCW and inner-hole:=CW w/o using winding determination (might be incorrect)
This simplifies our code further and it has been validated that our polygon shoelace-algo for area >= 0 ? CCW doesn't produce correct results with all curves. Hence rely on given winding depending on outer-boundary and inner-hole if CDTriangulator2D.FixedWindingRule == true (default and fixed). This also removes the more costly winding shoelace calculus, hence Outline ctor only sets dirtyWinding:=true w/o calculating the winding.
-rw-r--r--src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java11
-rw-r--r--src/jogl/classes/com/jogamp/graph/geom/Outline.java8
-rw-r--r--src/jogl/classes/com/jogamp/math/VectorUtil.java56
-rw-r--r--src/jogl/classes/jogamp/graph/curve/tess/CDTriangulator2D.java33
-rw-r--r--src/jogl/classes/jogamp/graph/curve/tess/Loop.java14
5 files changed, 77 insertions, 45 deletions
diff --git a/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java b/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java
index 805db522b..3e85ff3dc 100644
--- a/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java
+++ b/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java
@@ -61,15 +61,16 @@ import com.jogamp.math.geom.plane.Winding;
* <a name="windingrules">
* Outline shape general {@link Winding} rules
* <ul>
- * <li>Outer boundary shapes are required as {@link Winding#CCW}, if unsure
+ * <li>Outer boundary-shapes are required as {@link Winding#CCW}</li>
+ * <li>Inner hole-shapes should be {@link Winding#CW}</li>
+ * <li>If unsure
* <ul>
- * <li>You may check {@link Winding} via {@link #getWindingOfLastOutline()} or {@link Outline#getWinding()} (optional)</li>
+ * <li>You may check {@link Winding} via {@link #getWindingOfLastOutline()} or {@link Outline#getWinding()} (optional, might be incorrect)</li>
* <li>Use {@link #setWindingOfLastOutline(Winding)} before {@link #closeLastOutline(boolean)} or {@link #closePath()} } to enforce {@link Winding#CCW}, or</li>
* <li>use {@link Outline#setWinding(Winding)} on a specific {@link Outline} to enforce {@link Winding#CCW}.</li>
* <li>If e.g. the {@link Winding} has changed for an {@link Outline} by above operations, its vertices have been reversed.</li>
* </ul></li>
- * <li>Inner shapes or holes are adjusted to be {@link Winding#CW}, no user consideration is required here.</li>
- * <li>Safe path: Simply create all shapes with {@link Winding#CCW} or apply {@link Outline#setWinding(Winding)}.</li>
+ * <li>Safe path: Simply create all outer boundary-shapes with {@link Winding#CCW} and inner hole-shapes with {@link Winding#CW}.</li>
* </ul>
* </p>
* Example to creating an Outline Shape:
@@ -238,7 +239,7 @@ public final class OutlineShape implements Comparable<OutlineShape> {
}
/**
- * Compute the {@link Winding} of the {@link #getLastOutline()} using the {@link #area(ArrayList)} function over all of its vertices.
+ * Compute the {@link Winding} of the {@link #getLastOutline()} using the {@link VectorUtil#area2d(ArrayList)} function over all of its vertices.
* @return {@link Winding#CCW} or {@link Winding#CW}
*/
public final Winding getWindingOfLastOutline() {
diff --git a/src/jogl/classes/com/jogamp/graph/geom/Outline.java b/src/jogl/classes/com/jogamp/graph/geom/Outline.java
index 522919cc6..a9ebd0346 100644
--- a/src/jogl/classes/com/jogamp/graph/geom/Outline.java
+++ b/src/jogl/classes/com/jogamp/graph/geom/Outline.java
@@ -78,8 +78,8 @@ public class Outline implements Comparable<Outline> {
public Outline(final Outline src) {
final int count = src.vertices.size();
vertices = new ArrayList<Vertex>(count);
- winding = src.getWinding();
- dirtyWinding = false;
+ winding = Winding.CCW;
+ dirtyWinding = true;
for(int i=0; i<count; i++) {
vertices.add( src.vertices.get(i).copy() );
}
@@ -138,7 +138,7 @@ public class Outline implements Comparable<Outline> {
}
/**
- * Compute the winding of the {@link #getLastOutline()} using the {@link #area(ArrayList)} function over all of its vertices.
+ * Compute the winding of the {@link #getLastOutline()} using the {@link VectorUtil#area2d(ArrayList)} function over all of its vertices.
* @return {@link Winding#CCW} or {@link Winding#CW}
*/
public final Winding getWinding() {
@@ -149,7 +149,7 @@ public class Outline implements Comparable<Outline> {
if( 3 > count ) {
winding = Winding.CCW;
} else {
- winding = VectorUtil.getWinding( getVertices() );
+ winding = VectorUtil.getWinding2d( getVertices() );
}
dirtyWinding = false;
return winding;
diff --git a/src/jogl/classes/com/jogamp/math/VectorUtil.java b/src/jogl/classes/com/jogamp/math/VectorUtil.java
index 716b63e47..7e66f0b4f 100644
--- a/src/jogl/classes/com/jogamp/math/VectorUtil.java
+++ b/src/jogl/classes/com/jogamp/math/VectorUtil.java
@@ -537,7 +537,7 @@ public final class VectorUtil {
/**
* Check if points are in ccw order
* <p>
- * Consider using {@link #getWinding(ArrayList)} using the {@link #area(ArrayList)} function over all points
+ * Consider using {@link #getWinding2f(ArrayList)} using the {@link #area2f(ArrayList)} function over all points
* on complex shapes for a reliable result!
* </p>
* @param a first vertex
@@ -552,29 +552,29 @@ public final class VectorUtil {
/**
* Compute the winding of the 3 given points
* <p>
- * Consider using {@link #getWinding(ArrayList)} using the {@link #area(ArrayList)} function over all points
+ * Consider using {@link #getWinding2f(ArrayList)} using the {@link #area2f(ArrayList)} function over all points
* on complex shapes for a reliable result!
* </p>
* @param a first vertex
* @param b second vertex
* @param c third vertex
* @return {@link Winding#CCW} or {@link Winding#CW}
- * @see #getWinding(ArrayList)
+ * @see #getWinding2f(ArrayList)
*/
public static Winding getWinding(final Vert2fImmutable a, final Vert2fImmutable b, final Vert2fImmutable c) {
return triAreaVec2d(a,b,c) > InCircleDThreshold ? Winding.CCW : Winding.CW ;
}
/**
- * Computes the area of a list of vertices.
+ * Computes the area of a list of vertices via shoelace formula.
* <p>
* This method is utilized e.g. to reliably compute the {@link Winding} of complex shapes.
* </p>
* @param vertices
* @return positive area if ccw else negative area value
- * @see #getWinding(ArrayList)
+ * @see #getWinding2f(ArrayList)
*/
- public static float area(final ArrayList<? extends Vert2fImmutable> vertices) {
+ public static float area2f(final ArrayList<? extends Vert2fImmutable> vertices) {
final int n = vertices.size();
float area = 0.0f;
for (int p = n - 1, q = 0; q < n; p = q++) {
@@ -586,17 +586,51 @@ public final class VectorUtil {
}
/**
- * Compute the winding using the {@link #area(ArrayList)} function over all vertices for complex shapes.
+ * Compute the winding using the {@link #area2f(ArrayList)} function over all vertices for complex shapes.
* <p>
- * Uses the {@link #area(ArrayList)} function over all points
+ * Uses the {@link #area2f(ArrayList)} function over all points
* on complex shapes for a reliable result!
* </p>
* @param vertices array of Vertices
* @return {@link Winding#CCW} or {@link Winding#CW}
- * @see #area(ArrayList)
+ * @see #area2f(ArrayList)
*/
- public static Winding getWinding(final ArrayList<? extends Vert2fImmutable> vertices) {
- return area(vertices) >= 0 ? Winding.CCW : Winding.CW ;
+ public static Winding getWinding2f(final ArrayList<? extends Vert2fImmutable> vertices) {
+ return area2f(vertices) >= 0 ? Winding.CCW : Winding.CW ;
+ }
+
+ /**
+ * Computes the area of a list of vertices via shoelace formula.
+ * <p>
+ * This method is utilized e.g. to reliably compute the {@link Winding} of complex shapes.
+ * </p>
+ * @param vertices
+ * @return positive area if ccw else negative area value
+ * @see #getWinding2d(ArrayList)
+ */
+ public static double area2d(final ArrayList<? extends Vert2fImmutable> vertices) {
+ final int n = vertices.size();
+ double area = 0.0;
+ for (int p = n - 1, q = 0; q < n; p = q++) {
+ final Vert2fImmutable pCoord = vertices.get(p);
+ final Vert2fImmutable qCoord = vertices.get(q);
+ area += (double)pCoord.x() * (double)qCoord.y() - (double)qCoord.x() * (double)pCoord.y();
+ }
+ return area;
+ }
+
+ /**
+ * Compute the winding using the {@link #area2f(ArrayList)} function over all vertices for complex shapes.
+ * <p>
+ * Uses the {@link #area2f(ArrayList)} function over all points
+ * on complex shapes for a reliable result!
+ * </p>
+ * @param vertices array of Vertices
+ * @return {@link Winding#CCW} or {@link Winding#CW}
+ * @see #area2d(ArrayList)
+ */
+ public static Winding getWinding2d(final ArrayList<? extends Vert2fImmutable> vertices) {
+ return area2d(vertices) >= 0 ? Winding.CCW : Winding.CW ;
}
/**
diff --git a/src/jogl/classes/jogamp/graph/curve/tess/CDTriangulator2D.java b/src/jogl/classes/jogamp/graph/curve/tess/CDTriangulator2D.java
index d27b7a584..1c2f0b323 100644
--- a/src/jogl/classes/jogamp/graph/curve/tess/CDTriangulator2D.java
+++ b/src/jogl/classes/jogamp/graph/curve/tess/CDTriangulator2D.java
@@ -79,31 +79,24 @@ public class CDTriangulator2D implements Triangulator {
}
+ /* pp */ static final boolean FixedWindingRule = true;
+
@Override
public final void addCurve(final List<Triangle> sink, final Outline polyline, final float sharpness) {
Loop loop = getContainerLoop(polyline);
- final Winding winding = polyline.getWinding();
if( null == loop ) {
// HEdge.BOUNDARY -> Winding.CCW
- int edgeType;
- boolean hole;
- if( Winding.CCW != winding ) {
- System.err.println("CDT2.add.xx.BOUNDARY: !CCW but "+winding);
- // polyline.print(System.err);
- if( false ) {
- edgeType = HEdge.HOLE;
- hole = true;
- } else {
- edgeType = HEdge.BOUNDARY;
- hole = false;
- polyline.setWinding(Winding.CCW);
+ final int edgeType = HEdge.BOUNDARY;
+ final boolean hole = false;
+ if( !FixedWindingRule ) {
+ final Winding winding = polyline.getWinding();
+ if( Winding.CCW != winding ) {
+ System.err.println("CDT2.add.xx.BOUNDARY: !CCW but "+winding);
+ // polyline.print(System.err);
+ polyline.setWinding(Winding.CCW); // FIXME: Too late?
}
- } else {
- edgeType = HEdge.BOUNDARY;
- hole = false;
}
- // Too late: polyline.setWinding(winding);
final GraphOutline outline = new GraphOutline(polyline);
final GraphOutline innerPoly = extractBoundaryTriangles(sink, outline, hole, sharpness);
// vertices.addAll(polyline.getVertices());
@@ -140,12 +133,14 @@ public class CDTriangulator2D implements Triangulator {
Thread.dumpStack();
}
} else {
+ final int edgeType = HEdge.HOLE;
+ final boolean hole = true;
// HEdge.HOLE -> Winding.CW, but Winding.CCW is also accepted!
// Winding.CW not required, handled in Loop.initFromPolyline(): polyline.setWinding(winding);
final GraphOutline outline = new GraphOutline(polyline);
- final GraphOutline innerPoly = extractBoundaryTriangles(sink, outline, true, sharpness);
+ final GraphOutline innerPoly = extractBoundaryTriangles(sink, outline, hole, sharpness);
// vertices.addAll(innerPoly.getVertices());
- loop.addConstraintCurve(innerPoly);
+ loop.addConstraintCurve(innerPoly, edgeType);
}
}
diff --git a/src/jogl/classes/jogamp/graph/curve/tess/Loop.java b/src/jogl/classes/jogamp/graph/curve/tess/Loop.java
index d94ab775d..4961ce895 100644
--- a/src/jogl/classes/jogamp/graph/curve/tess/Loop.java
+++ b/src/jogl/classes/jogamp/graph/curve/tess/Loop.java
@@ -122,8 +122,8 @@ public class Loop {
}
return null;
}
- final Winding winding = outline.getOutline().getWinding();
final Winding edgeWinding = HEdge.BOUNDARY == edgeType ? Winding.CCW : Winding.CW;
+ final Winding winding = CDTriangulator2D.FixedWindingRule ? edgeWinding : outline.getOutline().getWinding();
if( HEdge.BOUNDARY == edgeType && Winding.CCW != winding ) {
// XXXX
@@ -135,7 +135,7 @@ public class Loop {
HEdge lastEdge = null;
if( winding == edgeWinding || HEdge.BOUNDARY == edgeType ) {
- // Correct Winding or skipped CW -> CCW (no inversion possible here, too late ??)
+ // Correct Winding or skipped CW -> CCW (no inversion possible here, too late)
final int max = vertices.size() - 1;
for(int index = 0; index <= max; ++index) {
final GraphVertex v1 = vertices.get(index);
@@ -156,7 +156,7 @@ public class Loop {
}
lastEdge = edge;
}
- } else { // if( hasWinding == Winding.CW ) {
+ } else { // if( winding == Winding.CW ) {
// CCW <-> CW
for(int index = vertices.size() - 1; index >= 0; --index) {
final GraphVertex v1 = vertices.get(index);
@@ -182,13 +182,15 @@ public class Loop {
return firstEdge;
}
- public void addConstraintCurve(final GraphOutline polyline) {
+ public void addConstraintCurve(final GraphOutline polyline, final int edgeType) {
// GraphOutline outline = new GraphOutline(polyline);
/**needed to generate vertex references.*/
- if( null == initFromPolyline(polyline, HEdge.HOLE) ) {
+ if( null == initFromPolyline(polyline, edgeType) ) { // 'usually' HEdge.HOLE
return;
}
- addConstraintCurveImpl(polyline);
+ if( HEdge.HOLE == edgeType ) {
+ addConstraintCurveImpl(polyline);
+ }
}
private void addConstraintCurveImpl(final GraphOutline polyline) {
final GraphVertex v3 = locateClosestVertex(polyline);