aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Göthel <[email protected]>2024-02-14 20:23:24 +0100
committerSven Göthel <[email protected]>2024-02-14 20:23:24 +0100
commite4b49663f6c6f138a8718847b68d1d78fba8fe73 (patch)
tree3628be91f48347a6b26ebf9d7e0809ddae1d4321
parent52277dc625b515ecc3ff0d26ca05428f3d973427 (diff)
Bug 1501: Refine convex == !complex: Use 'complex' term, have env-property toggle OutlineShape's isComplex() for visibility
We may use complex for other criteria than !convex, i.e. self-intersecting etc.
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/ui/FontView01.java20
-rw-r--r--src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java61
-rw-r--r--src/jogl/classes/com/jogamp/graph/curve/tess/Triangulator.java12
-rw-r--r--src/jogl/classes/com/jogamp/graph/geom/Outline.java55
-rw-r--r--src/jogl/classes/jogamp/graph/curve/tess/CDTriangulator2D.java18
-rw-r--r--src/jogl/classes/jogamp/graph/curve/tess/Loop.java14
6 files changed, 101 insertions, 79 deletions
diff --git a/src/demos/com/jogamp/opengl/demos/graph/ui/FontView01.java b/src/demos/com/jogamp/opengl/demos/graph/ui/FontView01.java
index 8409ac252..770b1b724 100644
--- a/src/demos/com/jogamp/opengl/demos/graph/ui/FontView01.java
+++ b/src/demos/com/jogamp/opengl/demos/graph/ui/FontView01.java
@@ -99,8 +99,8 @@ import com.jogamp.opengl.util.Animator;
public class FontView01 {
private static final float GlyphGridWidth = 3/4f; // FBO AA: 3/4f = 0.75f dropped fine grid lines @ 0.2f thickness; 0.70f OK
private static final float GlyphGridBorderThickness = 0.02f; // thickness 0.2f dropping
- private static final Vec4f GlyphGridBorderColorConvex = new Vec4f(0.2f, 0.2f, 0.7f, 1);
private static final Vec4f GlyphGridBorderColorComplex = new Vec4f(0.2f, 0.2f, 0.2f, 1);
+ private static final Vec4f GlyphGridBorderColorSimple = new Vec4f(0.2f, 0.2f, 0.7f, 1);
// static CommandlineOptions options = new CommandlineOptions(1280, 720, Region.MSAA_RENDERING_BIT, Region.DEFAULT_AA_QUALITY, 4);
// static CommandlineOptions options = new CommandlineOptions(1280, 720, Region.VBAA_RENDERING_BIT);
@@ -437,7 +437,7 @@ public class FontView01 {
final int rows;
final int rowsPerPage;
final int elemCount;
- int convexGlyphCount;
+ int complexGlyphCount;
int maxNameLen;
public GridDim(final Font font, final int columns, final int rowsPerPage, final int xReserved) {
@@ -456,14 +456,14 @@ public class FontView01 {
private int scanContourGlyphs(final Font font) {
final long t0 = Clock.currentNanos();
contourChars.clear();
- convexGlyphCount = 0;
+ complexGlyphCount = 0;
maxNameLen = 1;
final int[] max = { max_glyph_count };
font.forAllGlyphs((final Glyph fg) -> {
if( !fg.isNonContour() && max[0]-- > 0 ) {
contourChars.add( fg.getCodepoint() );
- if( null != fg.getShape() && fg.getShape().isConvex() ) {
- ++convexGlyphCount;
+ if( null != fg.getShape() && fg.getShape().isComplex() ) {
+ ++complexGlyphCount;
}
maxNameLen = Math.max(maxNameLen, fg.getName().length());
}
@@ -475,7 +475,7 @@ public class FontView01 {
return contourChars.size();
}
@Override
- public String toString() { return "GridDim[contours "+glyphCount+", convex "+convexGlyphCount+" ("+((float)convexGlyphCount/(float)glyphCount)*100+"%), "+columns+"x"+rows+"="+(columns*rows)+">="+elemCount+", rows/pg "+rowsPerPage+"]"; }
+ public String toString() { return "GridDim[contours "+glyphCount+", complex "+complexGlyphCount+" ("+((float)complexGlyphCount/(float)glyphCount)*100+"%), "+columns+"x"+rows+"="+(columns*rows)+">="+elemCount+", rows/pg "+rowsPerPage+"]"; }
}
static Group getGlyphShapeHolder(final Shape shape0) {
@@ -505,7 +505,7 @@ public class FontView01 {
for(int idx = 0; idx < gridDim.glyphCount; ++idx) {
final char codepoint = gridDim.contourChars.get(idx);
final Font.Glyph fg = font.getGlyph(codepoint);
- final boolean isConvex = null != fg.getShape() ? fg.getShape().isConvex() : true;
+ final boolean isComplex = null != fg.getShape() ? fg.getShape().isComplex() : false;
final GlyphShape g = new GlyphShape(options.renderModes, fg, 0, 0);
g.setColor(0.1f, 0.1f, 0.1f, 1).setName("GlyphShape");
@@ -519,7 +519,7 @@ public class FontView01 {
final AABBox gbox = fg.getBounds(tmpBox); // g.getBounds(glp);
final boolean addUnderline = showUnderline && gbox.getMinY() < 0f;
final Group c1 = new Group( new BoxLayout( 1f, 1f, addUnderline ? Alignment.None : Alignment.Center) );
- c1.setBorder(GlyphGridBorderThickness).setBorderColor(isConvex ? GlyphGridBorderColorConvex : GlyphGridBorderColorComplex)
+ c1.setBorder(GlyphGridBorderThickness).setBorderColor(isComplex ? GlyphGridBorderColorComplex : GlyphGridBorderColorSimple)
.setInteractive(true).setDragAndResizable(false).setName("GlyphHolder2");
if( addUnderline ) {
final Shape underline = new Rectangle(options.renderModes, 1f, gbox.getMinY(), 0.01f).setInteractive(false).setColor(0f, 0f, 1f, 0.25f);
@@ -574,7 +574,7 @@ public class FontView01 {
static String getGlyphInfo(final Font.Glyph g) {
final OutlineShape os = g.getShape();
- final boolean isConvex = null != os ? os.isConvex() : true;
+ final boolean isComplex = null != os ? os.isComplex() : false;
final int osVertices = null != os ? os.getVertexCount() : 0;
final String name_s = null != g.getName() ? g.getName() : "";
final AABBox bounds = g.getBounds();
@@ -587,6 +587,6 @@ public class FontView01 {
bounds.getWidth(), bounds.getHeight(), box_s,
g.getAdvanceWidth(),
g.getLeftSideBearings(),
- osVertices, isConvex?"Convex":"Non-Convex");
+ osVertices, isComplex?"Complex Shape":"Simple Shape");
}
}
diff --git a/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java b/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java
index 25791e17d..0c42e791c 100644
--- a/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java
+++ b/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java
@@ -46,6 +46,8 @@ import com.jogamp.math.geom.plane.AffineTransform;
import com.jogamp.math.geom.plane.Path2F;
import com.jogamp.math.geom.plane.Winding;
+import jogamp.opengl.Debug;
+
/**
* A Generic shape objects which is defined by a list of Outlines.
* This Shape can be transformed to triangulations.
@@ -119,6 +121,9 @@ import com.jogamp.math.geom.plane.Winding;
* @see Region
*/
public final class OutlineShape implements Comparable<OutlineShape> {
+ private static final boolean FORCE_COMPLEXSHAPE = Debug.debug("graph.curve.triangulation.force.complexshape");
+ private static final boolean FORCE_SIMPLESHAPE = Debug.debug("graph.curve.triangulation.force.simpleshape");
+
/**
* Outline's vertices have undefined state until transformed.
*/
@@ -159,7 +164,7 @@ public final class OutlineShape implements Comparable<OutlineShape> {
private final ArrayList<Triangle> triangles;
private final ArrayList<Vertex> vertices;
private int addedVerticeCount;
- private boolean convexFlag;
+ private boolean complexShape;
private VerticesState outlineState;
@@ -187,7 +192,11 @@ public final class OutlineShape implements Comparable<OutlineShape> {
this.triangles = new ArrayList<Triangle>();
this.vertices = new ArrayList<Vertex>();
this.addedVerticeCount = 0;
- this.convexFlag = true;
+ if( FORCE_COMPLEXSHAPE ) {
+ complexShape = true;
+ } else {
+ complexShape = false;
+ }
this.dirtyBits = 0;
this.sharpness = DEFAULT_SHARPNESS;
}
@@ -221,7 +230,11 @@ public final class OutlineShape implements Comparable<OutlineShape> {
vertices.clear();
triangles.clear();
addedVerticeCount = 0;
- convexFlag = true;
+ if( FORCE_COMPLEXSHAPE ) {
+ complexShape = true;
+ } else {
+ complexShape = false;
+ }
dirtyBits = 0;
}
@@ -262,10 +275,9 @@ public final class OutlineShape implements Comparable<OutlineShape> {
}
/**
- * Returns cached or computed result whether all {@code polyline}s of {@link #getOutline(int)} are of convex shape, see {@link Outline#isConvex()}.
+ * Returns cached or computed result if at least one {@code polyline} of {@link #getOutline(int)} is a complex shape, see {@link Outline#isComplex()}.
* <p>
- * A polyline with less than 3 elements is marked convex for simplicity,
- * since a non-convex complex shape may need to pass intersection testing within triangulation.
+ * A polyline with less than 3 elements is marked a simple shape for simplicity.
* </p>
* <p>
* The result is cached.
@@ -273,32 +285,35 @@ public final class OutlineShape implements Comparable<OutlineShape> {
* @see #setOverrideConvex(boolean)
* @see #clearOverrideConvex()
*/
- public boolean isConvex() {
- if( 0 == ( OVERRIDE_CONVEX & dirtyBits ) ) {
- if( 0 != ( DIRTY_CONVEX & dirtyBits ) ) {
- convexFlag = true;
- final int sz = this.getOutlineCount();
- for(int i=0; i<sz && convexFlag; ++i) {
- convexFlag = getOutline(i).isConvex();
- }
- dirtyBits &= ~DIRTY_CONVEX;
+ public boolean isComplex() {
+ if( !FORCE_COMPLEXSHAPE && !FORCE_SIMPLESHAPE &&
+ 0 == ( OVERRIDE_CONVEX & dirtyBits ) &&
+ 0 != ( DIRTY_CONVEX & dirtyBits ) )
+ {
+ complexShape = false;
+ final int sz = this.getOutlineCount();
+ for(int i=0; i<sz && !complexShape; ++i) {
+ complexShape = getOutline(i).isComplex();
}
+ dirtyBits &= ~DIRTY_CONVEX;
}
- return convexFlag;
+ return complexShape;
}
/**
- * Overrides {@link #isConvex()} using the given value instead of computing via {@link Outline#isConvex()}.
+ * Overrides {@link #isComplex()} using the given value instead of computing via {@link Outline#isComplex()}.
* @see #clearOverrideConvex()
- * @see #isConvex()
+ * @see #isComplex()
*/
public void setOverrideConvex(final boolean convex) {
- dirtyBits |= OVERRIDE_CONVEX;
- convexFlag = convex;
+ if( !FORCE_COMPLEXSHAPE && !FORCE_SIMPLESHAPE ) {
+ dirtyBits |= OVERRIDE_CONVEX;
+ complexShape = convex;
+ }
}
/**
- * Clears the {@link #isConvex()} override done by {@link #setOverrideConvex(boolean)}
+ * Clears the {@link #isComplex()} override done by {@link #setOverrideConvex(boolean)}
* @see #setOverrideConvex(boolean)
- * @see #isConvex()
+ * @see #isComplex()
*/
public void clearOverrideConvex() {
dirtyBits &= ~OVERRIDE_CONVEX;
@@ -1018,7 +1033,7 @@ public final class OutlineShape implements Comparable<OutlineShape> {
triangles.clear();
final Triangulator triangulator2d = Triangulation.create();
- triangulator2d.setConvexShape( isConvex() );
+ triangulator2d.setComplexShape( isComplex() );
for(int index = 0; index<outlines.size(); index++) {
triangulator2d.addCurve(triangles, outlines.get(index), sharpness);
}
diff --git a/src/jogl/classes/com/jogamp/graph/curve/tess/Triangulator.java b/src/jogl/classes/com/jogamp/graph/curve/tess/Triangulator.java
index eaebde076..a9f9b06c2 100644
--- a/src/jogl/classes/com/jogamp/graph/curve/tess/Triangulator.java
+++ b/src/jogl/classes/com/jogamp/graph/curve/tess/Triangulator.java
@@ -49,8 +49,16 @@ import com.jogamp.graph.geom.Triangle;
*/
public interface Triangulator {
- /** Mark the to be triangulated shape convex or non-convex, causing further processing costs if non-convex like intersection tests. Default is assuming a convex shape. */
- public void setConvexShape(boolean convex);
+ /**
+ * Mark the to be triangulated shape complex or non-complex.
+ * <p>
+ * Complex shapes may cause further processing costs, e.g. intersection tests to overcome self-intersecting shapes.
+ * </p>
+ * <p>
+ * Default is assuming a simple non-complex shape.
+ * </p>
+ */
+ public void setComplexShape(boolean complex);
/**
* Add a curve to the list of Outlines
diff --git a/src/jogl/classes/com/jogamp/graph/geom/Outline.java b/src/jogl/classes/com/jogamp/graph/geom/Outline.java
index 8c39004a0..1525483c5 100644
--- a/src/jogl/classes/com/jogamp/graph/geom/Outline.java
+++ b/src/jogl/classes/com/jogamp/graph/geom/Outline.java
@@ -57,11 +57,11 @@ public class Outline implements Comparable<Outline> {
private final AABBox bbox;
private boolean dirtyBBox;
private Winding winding;
- private boolean convexFlag;
+ private boolean complexShape;
private int dirtyBits;
private static final int DIRTY_WINDING = 1 << 0;
- private static final int DIRTY_CONVEX = 1 << 0;
+ private static final int DIRTY_COMPLEXSHAPE = 1 << 0;
/**Create an outline defined by control vertices.
* An outline can contain off Curve vertices which define curved
@@ -73,7 +73,7 @@ public class Outline implements Comparable<Outline> {
bbox = new AABBox();
dirtyBBox = false;
winding = Winding.CCW;
- convexFlag = false;
+ complexShape = false;
dirtyBits = 0;
}
@@ -84,8 +84,16 @@ public class Outline implements Comparable<Outline> {
final int count = src.vertices.size();
vertices = new ArrayList<Vertex>(count);
winding = Winding.CCW;
- convexFlag = false;
- dirtyBits = DIRTY_WINDING | DIRTY_CONVEX;
+ complexShape = false;
+ dirtyBits = DIRTY_WINDING | DIRTY_COMPLEXSHAPE;
+ if( 0 == ( src.dirtyBits & DIRTY_WINDING ) ) {
+ winding = src.winding;
+ dirtyBits &= ~DIRTY_WINDING;
+ }
+ if( 0 == ( src.dirtyBits & DIRTY_COMPLEXSHAPE ) ) {
+ complexShape = src.complexShape;
+ dirtyBits &= ~DIRTY_COMPLEXSHAPE;
+ }
for(int i=0; i<count; i++) {
vertices.add( src.vertices.get(i).copy() );
}
@@ -105,15 +113,10 @@ public class Outline implements Comparable<Outline> {
public Outline(final Outline src, final Winding enforce) {
final int count = src.vertices.size();
vertices = new ArrayList<Vertex>(count);
+ complexShape = false;
+ dirtyBits = DIRTY_COMPLEXSHAPE;
final Winding had_winding = src.getWinding();
winding = had_winding;
- if( 0 == ( src.dirtyBits & DIRTY_CONVEX ) ) {
- convexFlag = src.convexFlag;
- dirtyBits = 0;
- } else {
- convexFlag = false;
- dirtyBits = DIRTY_CONVEX;
- }
if( enforce != had_winding ) {
for(int i=count-1; i>=0; --i) {
vertices.add( src.vertices.get(i).copy() );
@@ -124,6 +127,10 @@ public class Outline implements Comparable<Outline> {
vertices.add( src.vertices.get(i).copy() );
}
}
+ if( 0 == ( src.dirtyBits & DIRTY_COMPLEXSHAPE ) ) {
+ complexShape = src.complexShape;
+ dirtyBits &= ~DIRTY_COMPLEXSHAPE;
+ }
closed = src.closed;
bbox = new AABBox(src.bbox);
dirtyBBox = src.dirtyBBox;
@@ -171,22 +178,22 @@ public class Outline implements Comparable<Outline> {
}
/**
- * Returns the cached or computed result whether this {@link Outline}s {@code polyline} has a convex shape using {@link VectorUtil#isConvex(ArrayList, boolean)}.
+ * Returns cached or computed result if whether this {@link Outline}s {@code polyline} is a complex shape.
* <p>
- * A polyline with less than 3 elements is marked convex for simplicity,
- * since a non-convex complex shape may need to pass intersection testing within triangulation.
+ * A polyline with less than 3 elements is marked a simple shape for simplicity.
* </p>
* <p>
* The result is cached.
* </p>
*/
- public boolean isConvex() {
- if( 0 == ( dirtyBits & DIRTY_CONVEX ) ) {
- return convexFlag;
+ public boolean isComplex() {
+ if( 0 == ( dirtyBits & DIRTY_COMPLEXSHAPE ) ) {
+ return complexShape;
}
- convexFlag = VectorUtil.isConvex1( getVertices(), true );
- dirtyBits &= ~DIRTY_CONVEX;
- return convexFlag;
+ complexShape = !VectorUtil.isConvex1( getVertices(), true );
+ // complexShape = VectorUtil.isSelfIntersecting1( getVertices() );
+ dirtyBits &= ~DIRTY_COMPLEXSHAPE;
+ return complexShape;
}
public final int getVertexCount() {
@@ -217,7 +224,7 @@ public class Outline implements Comparable<Outline> {
if(!dirtyBBox) {
bbox.resize(vertex.getCoord());
}
- dirtyBits |= DIRTY_WINDING | DIRTY_CONVEX;
+ dirtyBits |= DIRTY_WINDING | DIRTY_COMPLEXSHAPE;
}
/** Replaces the {@link Vertex} element at the given {@code position}.
@@ -234,7 +241,7 @@ public class Outline implements Comparable<Outline> {
}
vertices.set(position, vertex);
dirtyBBox = true;
- dirtyBits |= DIRTY_WINDING | DIRTY_CONVEX;
+ dirtyBits |= DIRTY_WINDING | DIRTY_COMPLEXSHAPE;
}
public final Vertex getVertex(final int index){
@@ -253,7 +260,7 @@ public class Outline implements Comparable<Outline> {
*/
public final Vertex removeVertex(final int position) throws IndexOutOfBoundsException {
dirtyBBox = true;
- dirtyBits |= DIRTY_WINDING | DIRTY_CONVEX;
+ dirtyBits |= DIRTY_WINDING | DIRTY_COMPLEXSHAPE;
return vertices.remove(position);
}
diff --git a/src/jogl/classes/jogamp/graph/curve/tess/CDTriangulator2D.java b/src/jogl/classes/jogamp/graph/curve/tess/CDTriangulator2D.java
index 08b75478d..d69b33f1f 100644
--- a/src/jogl/classes/jogamp/graph/curve/tess/CDTriangulator2D.java
+++ b/src/jogl/classes/jogamp/graph/curve/tess/CDTriangulator2D.java
@@ -50,15 +50,13 @@ public class CDTriangulator2D implements Triangulator {
protected static final boolean DEBUG = Debug.debug("graph.curve.Triangulation");
- private static final boolean FORCE_NONCONVEX = Debug.debug("graph.curve.triangulation.force.non-convex");
- private static final boolean FORCE_CONVEX = Debug.debug("graph.curve.triangulation.force.convex");
private static final boolean TEST_LINE_AA = Debug.debug("graph.curve.triangulation.LINE_AA");
private static final boolean TEST_MARK_LINE = Debug.debug("graph.curve.triangulation.MARK_AA");
private static final boolean TEST_ENABLED = TEST_LINE_AA || TEST_MARK_LINE;
private final ArrayList<Loop> loops = new ArrayList<Loop>();
- private boolean convexFlag;
+ private boolean complexShape;
private int addedVerticeCount;
private int maxTriID;
@@ -66,19 +64,13 @@ public class CDTriangulator2D implements Triangulator {
/** Constructor for a new Delaunay triangulator
*/
public CDTriangulator2D() {
- if( FORCE_NONCONVEX ) {
- convexFlag = false;
- } else {
- convexFlag = true;
- }
+ complexShape = false;
reset();
}
@Override
- public void setConvexShape(final boolean convex) {
- if( !FORCE_NONCONVEX && !FORCE_CONVEX ) {
- convexFlag = convex;
- }
+ public void setComplexShape(final boolean complex) {
+ complexShape = complex;
}
@Override
@@ -114,7 +106,7 @@ public class CDTriangulator2D implements Triangulator {
final GraphOutline innerPoly = extractBoundaryTriangles(sink, outline, false /* hole */, sharpness);
// vertices.addAll(polyline.getVertices());
if( innerPoly.getGraphPoint().size() >= 3 ) {
- loop = Loop.createBoundary(innerPoly, convexFlag);
+ loop = Loop.createBoundary(innerPoly, complexShape);
if( null != loop ) {
loops.add(loop);
}
diff --git a/src/jogl/classes/jogamp/graph/curve/tess/Loop.java b/src/jogl/classes/jogamp/graph/curve/tess/Loop.java
index a69fbd6b5..838cf8b5f 100644
--- a/src/jogl/classes/jogamp/graph/curve/tess/Loop.java
+++ b/src/jogl/classes/jogamp/graph/curve/tess/Loop.java
@@ -41,13 +41,13 @@ import com.jogamp.graph.geom.Triangle;
public class Loop {
private final AABBox box = new AABBox();
private final GraphOutline initialOutline;
- private final boolean isConvex;
+ private final boolean complexShape;
private HEdge root;
private final List<GraphOutline> outlines = new ArrayList<GraphOutline>();
- private Loop(final GraphOutline polyline, final int edgeType, final boolean isConvex){
+ private Loop(final GraphOutline polyline, final int edgeType, final boolean complexShape){
this.initialOutline = polyline;
- this.isConvex = isConvex;
+ this.complexShape = complexShape;
this.root = initFromPolyline(initialOutline, edgeType);
}
@@ -249,7 +249,7 @@ public class Loop {
final Vertex rootPoint = root.getGraphPoint().getPoint();
final Vertex nextPoint = next1.getGraphPoint().getPoint();
final Vertex candPoint = next1.getNext().getGraphPoint().getPoint();
- if( !isConvex && intersectsOutline(rootPoint, nextPoint, candPoint) ) {
+ if( complexShape && intersectsOutline(rootPoint, nextPoint, candPoint) ) {
return null;
}
return new Triangle(rootPoint, nextPoint, candPoint, checkVerticesBoundary(root));
@@ -290,7 +290,7 @@ public class Loop {
final Vertex rootPoint = root.getGraphPoint().getPoint();
final Vertex nextPoint = next1.getGraphPoint().getPoint();
final Vertex candPoint = next1.getNext().getGraphPoint().getPoint();
- if( !isConvex && intersectsOutlineDbg(rootPoint, nextPoint, candPoint) ) {
+ if( complexShape && intersectsOutlineDbg(rootPoint, nextPoint, candPoint) ) {
System.err.printf("Loop.cut.X0: last-simplex intersects%n");
return null;
}
@@ -409,7 +409,7 @@ public class Loop {
if( !VectorUtil.isCCW( rootPoint, nextPoint, candPoint) ) {
return null;
}
- if( !isConvex && intersectsOutline(rootPoint, nextPoint, candPoint) ) {
+ if( complexShape && intersectsOutline(rootPoint, nextPoint, candPoint) ) {
return null;
}
if( !delaunay ) {
@@ -440,7 +440,7 @@ public class Loop {
candPoint, rootPoint, nextPoint, candPoint);
return null;
}
- if( !isConvex && intersectsOutlineDbg(rootPoint, nextPoint, candPoint) ) {
+ if( complexShape && intersectsOutlineDbg(rootPoint, nextPoint, candPoint) ) {
return null;
}
if( !delaunay ) {