From f0f78b3e1d2edc69fe9281828076b93e2ae61b90 Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Mon, 16 Feb 2026 10:45:48 -0500 Subject: [PATCH 01/35] adding the test back in --- src/test/java/eu/mihosoft/vrl/v3d/StlLoadTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/eu/mihosoft/vrl/v3d/StlLoadTest.java b/src/test/java/eu/mihosoft/vrl/v3d/StlLoadTest.java index 35cec2ad..bf84a31f 100644 --- a/src/test/java/eu/mihosoft/vrl/v3d/StlLoadTest.java +++ b/src/test/java/eu/mihosoft/vrl/v3d/StlLoadTest.java @@ -20,7 +20,6 @@ public void init() { JavaFXInitializer.go(); } @Test - @Ignore public void tower() throws IOException { String filename = "fixedTower.STL"; File file = new File(filename); From fcd4b2022ac4daa578d9d40d8ab678688fc3a414 Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Mon, 16 Feb 2026 14:06:33 -0500 Subject: [PATCH 02/35] Attempt to add exceptions for all errors and correct the flatness --- src/main/java/eu/mihosoft/vrl/v3d/Node.java | 42 +++----- .../java/eu/mihosoft/vrl/v3d/NormalState.java | 5 + src/main/java/eu/mihosoft/vrl/v3d/Plane.java | 96 ++++--------------- .../java/eu/mihosoft/vrl/v3d/Polygon.java | 52 ++++++---- .../java/eu/mihosoft/vrl/v3d/Vector3d.java | 34 ++++++- .../vrl/v3d/ext/imagej/STLLoader.java | 1 + 6 files changed, 102 insertions(+), 128 deletions(-) create mode 100644 src/main/java/eu/mihosoft/vrl/v3d/NormalState.java diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Node.java b/src/main/java/eu/mihosoft/vrl/v3d/Node.java index 6e16d3b6..9daab72b 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Node.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Node.java @@ -271,8 +271,7 @@ private static int add(List l, int polygonIndex, int[] polygonStartInde return 1; } try { - testAddPolygon(l, orderedPoints, polygonPointX, polygonPointY, polygonPointZ, polygon, polygonBase, size, - false); + testAddPolygon(l, orderedPoints, polygonPointX, polygonPointY, polygonPointZ, polygon, polygonBase, size); return 1; } catch (Exception ex) { ex.printStackTrace(); @@ -282,7 +281,7 @@ private static int add(List l, int polygonIndex, int[] polygonStartInde } private static void testAddPolygon(List l, ArrayList orderedPoints, double[] polygonPointX, - double[] polygonPointY, double[] polygonPointZ, Polygon polygon, int polygonBase, int size, boolean test) { + double[] polygonPointY, double[] polygonPointZ, Polygon polygon, int polygonBase, int size) { List f = new ArrayList<>(); for (int i = polygonBase; i < polygonBase + size; i++) { if (i < orderedPoints.size()) { @@ -296,7 +295,7 @@ private static void testAddPolygon(List l, ArrayList orderedPoi } } - add(l, f, polygon, test); + add(l, f, polygon); } private static boolean addPoint(List f, Vertex v) { @@ -311,24 +310,23 @@ private static boolean addPoint(List f, Vertex v) { return f.add(v); } - private static void add(List l, List f, Polygon polygon) { - add(l, f, polygon, false); - } +// private static void add(List l, List f, Polygon polygon) { +// add(l, f, polygon, false); +// } - private static void add(List l, List f, Polygon polygon, boolean test) { + private static void add(List l, List f, Polygon polygon) { if (f.size() < 3) return; try { - if(!Extrude.isCCW(f, polygon.getPlane().getNormal())) { + if(polygon.getPlane().checkNormal(f) == NormalState.FLIPPED) { Collections.reverse(f); } Polygon fpoly = new Polygon(f, polygon.getStorage(), true, polygon.getPlane()) .setColor(polygon.getColor()); - if (!test) - l.add(fpoly); + l.add(fpoly); }catch(ColinearPointsException ex) { - //ex.printStackTrace(); - System.err.println(ex.getMessage()+" Pruned Collinear polygon "+f ); + ex.printStackTrace(); + System.err.println("Pruned Collinear polygon "+f+" "+ex.getMessage() ); } } public static String getOsName() { @@ -934,21 +932,8 @@ private void splitSinglePolygon(Polygon polygon,List coplanarFront, Lis // search for the epsilon values of the incoming plane double posEpsilon = Plane.getEPSILON(); int size = polygon.getVertices().size(); - Vector3d normal = polygon.getPlane().getNormal(); - for (int i = 0; i < size; i++) { - Vector3d pos = polygon.getVertices().get(i).pos; - double dot = normal.dot(pos); - double t = Math.abs(dot - polygon.getPlane().getDist()); - if(t>0.01) { - throw new RuntimeException("A plane epsilon of "+t+" is impossible"); - } - if (t > posEpsilon) { - // com.neuronrobotics.sdk.common.Log.error("Non flat polygon, increasing - // positive epsilon "+t); - posEpsilon = t; - } + //Vector3d normal = polygon.getPlane().getNormal(); - } int polygonType = 0; List types = new ArrayList<>(); // boolean someF =false; @@ -982,7 +967,7 @@ private void splitSinglePolygon(Polygon polygon,List coplanarFront, Lis // Put the polygon in the correct list, splitting it when necessary. switch (polygonType) { case COPLANAR: - double cp = getThisNodePlane().getNormal().dot(normal); + double cp = getThisNodePlane().getNormal().dot(polygon.getPlane().getNormal()); (cp > 0 ? coplanarFront : coplanarBack).add(polygon); break; case FRONT: @@ -1042,6 +1027,7 @@ private void splitSinglePolygon(Polygon polygon,List coplanarFront, Lis // therefor the intersection point is halfway between i and j double t = (d / dotMinus); if (!Double.isFinite(t) || t < 0 || t > 1.0) { + new RuntimeException("ERROR in interpolation!").printStackTrace(); continue; } diff --git a/src/main/java/eu/mihosoft/vrl/v3d/NormalState.java b/src/main/java/eu/mihosoft/vrl/v3d/NormalState.java new file mode 100644 index 00000000..9c5f4887 --- /dev/null +++ b/src/main/java/eu/mihosoft/vrl/v3d/NormalState.java @@ -0,0 +1,5 @@ +package eu.mihosoft.vrl.v3d; + +public enum NormalState { +SAME,FLIPPED,DIVERGENT; +} diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Plane.java b/src/main/java/eu/mihosoft/vrl/v3d/Plane.java index 6ddbff94..f1dca02a 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Plane.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Plane.java @@ -101,10 +101,15 @@ public Plane(Vector3d normal, double dist) { * @throws ColinearPointsException */ public Plane(List vertices, Vector3d testNorm) throws ColinearPointsException { - Vector3d a = vertices.get(0).pos; + Vector3d n = computeNormal(vertices, testNorm); this.setNormal(n); - this.setDist(n.dot(a)); + double distAvg = 0; + for(int i=0;i vertex) { + public NormalState checkNormal(List vertex) { Plane p = null; try { p = Plane.createFromPoints(vertex, getNormal()); @@ -203,84 +208,21 @@ public boolean checkNormal(ArrayList vertex) { if (p != null) { Vector3d normal = p.getNormal(); Vector3d normal2 = getNormal(); - double dot = 1-Math.abs(normal.dot(normal2)); + double dot2 = normal.dot(normal2); + double dot = 1-dot2; + double dFlipped = 2-dot2; // check for actual misallignment - double d = Plane.getEPSILON(); - if(dot d - || e4 > d - || e5 > d) { - double e = Math.abs(normal.x) - Math.abs(normal2.x); - double e2 = Math.abs(normal.y) - Math.abs(normal2.y); - double f = Math.abs(normal.z) - Math.abs(normal2.z); - if (e > d - || e2 > d - || f > d) { - return false; - } - return false; - } + double d = Plane.getEPSILON()*100; + if(dot>d) + if(dFlipped>d) + return NormalState.DIVERGENT; + else + return NormalState.FLIPPED; + } - return true; + return NormalState.SAME; } - public static Vector3d computeNormalCrossProduct(List verts) { - int n = verts.size(); - if (n < 3) - return new Vector3d(0, 0, 1); - - // 1. Build all edge vectors - List edges = new ArrayList<>(); - - for (int j = 0; j < n; j++) { - Vector3d e = verts.get((j+1)%n).pos.minus(verts.get(j).pos); - edges.add(e); - - } - - - // 2. Find pair with smallest |dot| / (|e1||e2|) - double bestScore = Double.POSITIVE_INFINITY; - Vector3d bestE1 = null, bestE2 = null; - for (int i = 0; i < edges.size(); i++) { - Vector3d e1 = edges.get(i); - double len1 = e1.length(); - for (int j = i + 1; j < edges.size(); j++) { - Vector3d e2 = edges.get(j); - double len2 = e2.length(); - double score = Math.abs(e1.dot(e2)) / (len1 * len2); - if (score < bestScore) { - bestScore = score; - bestE1 = e1; - bestE2 = e2; - } - } - } - - // 3. Fallback: use first three vertices if no good pair found - if (bestE1 == null) { - Vector3d v0 = verts.get(0).pos; - bestE1 = verts.get(1).pos.minus(v0); - bestE2 = verts.get(2).pos.minus(v0); - } - - // 4. Compute normal - Vector3d normal = bestE1.cross(bestE2); - if (normal.magnitude() < Plane.getEPSILON()) { - throw new RuntimeException("Fail! Normal can not be computed"); - } - normal.normalize(); - Vector3d v0 = verts.get(0).pos; - Vector3d std = verts.get(1).pos.minus(v0).cross(verts.get(2).pos.minus(v0)).normalized(); - if (normal.dot(std) < 0) { - normal = normal.negated(); - } - return normal; - } diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java b/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java index 02891593..8ad65f63 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java @@ -155,7 +155,7 @@ public static ArrayList pruneDuplicatePoints(List incoming) { for (int i = 0; i < incoming.size(); i++) { Vertex v = incoming.get(i); for(Vertex vt:newPoints) { - if(vt.pos.test(v.pos,Plane.getEPSILON()/2.0)) { + if(vt.pos.test(v.pos,Plane.getEPSILON())) { v=null; break; } @@ -176,21 +176,11 @@ private void validateAndInit(boolean fixInversions) throws ColinearPointsExcepti if (getPlane() == null) { setPlane(p); } - - - //if(fixInversions) { - Vector3d minus = getPlane().getNormal().minus(p.getNormal()); - double magnitude = minus.magnitude(); - if (Math.abs( magnitude)>2-(Plane.getEPSILON()*2) ) { - Collections.reverse(vertices); - } - //} - if (!getPlane().checkNormal(vertices)) { - if(p.getLengthSquared()>Plane.getEPSILON()) - setPlane(p); - else - if (getPlane() == null) - throw new ColinearPointsException("Failed! the normal provided mismatched to calculated normal"); + if (getPlane().checkNormal(vertices)==NormalState.FLIPPED ) { + Collections.reverse(vertices); + } + if (getPlane().checkNormal(vertices)!=NormalState.SAME) { + throw new ColinearPointsException("Failed! the normal provided mismatched to calculated normal"); } this.vertices=vertices; @@ -198,10 +188,33 @@ private void validateAndInit(boolean fixInversions) throws ColinearPointsExcepti if (getVertices().size() < 3) { throw new ColinearPointsException("Invalid polygon: at least 3 vertices expected, got: " + getVertices().size()); } + Vector3d normal = getPlane().getNormal(); + double dist = getPlane().getDist(); + boolean adusted = false; + for (int i = 0; i < getVertices().size(); i++) { + Vector3d pos = getVertices().get(i).pos; + double dot = normal.dot(pos); + double a = dot - dist; + double t = Math.abs(a); + if(t>0.01) { + throw new RuntimeException("A plane epsilon of "+t+" is impossible"); + } + if (t > Plane.getEPSILON()) { + pos.x -= a * normal.x; + pos.y -= a * normal.y; + pos.z -= a * normal.z; + adusted=true; + //new ColinearPointsException("Non flat polygon, epsilon = "+a+" vs planer test of "+Plane.getEPSILON()).printStackTrace();; + } + } + if(adusted) { + validateAndInit(fixInversions); + return; + } if( !areAllPointsCollinear()) return; - new ColinearPointsException("This polygon is colinear"); + throw new ColinearPointsException("This polygon is colinear"); } @@ -257,9 +270,10 @@ public Polygon flip() { // } catch (ColinearPointsException e) { // plane.flip(); // } - if (!getPlane().checkNormal(vertices)) { + NormalState checkNormal = getPlane().checkNormal(vertices); + if (checkNormal!=NormalState.SAME) { // getPlane().checkNormal(vertices); - new RuntimeException("Failed! the normal provided mismatched to calculated normal").printStackTrace(); + throw new RuntimeException("Failed! the normal provided mismatched to calculated normal "+checkNormal); } return this; diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Vector3d.java b/src/main/java/eu/mihosoft/vrl/v3d/Vector3d.java index b3649b5f..9322885d 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Vector3d.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Vector3d.java @@ -51,9 +51,35 @@ * * @author Michael Hoffer <info@michaelhoffer.de> */ -public class Vector3d extends javax.vecmath.Vector3d { +public class Vector3d +{ + public double x,y,z; + /** + * Returns the length of this vector. + * @return the length of this vector + */ + public final double length() + { + return Math.sqrt(this.x*this.x + this.y*this.y + this.z*this.z); + } + /** + * Normalizes this vector in place. + */ + public final void normalize() + { + double norm; + + norm = 1.0/Math.sqrt(this.x*this.x + this.y*this.y + this.z*this.z); + this.x *= norm; + this.y *= norm; + this.z *= norm; + } + public boolean epsilonEquals(Vector3d in, double ep) { + return test(in, ep); + } + private static String exportString = "%.10f"; private static double EXPORTEPSILON =1.0e-10; @@ -86,9 +112,9 @@ public class Vector3d extends javax.vecmath.Vector3d { * @param z z value */ public Vector3d(double x, double y, double z) { -// if(!Double.isFinite(x)||!Double.isFinite(y)||!Double.isFinite(z)) { -// throw new NumberFormatException("Vectors must be real "+x+" "+y+" "+z); -// } + if(!Double.isFinite(x)||!Double.isFinite(y)||!Double.isFinite(z)) { + throw new NumberFormatException("Vectors must be real "+x+" "+y+" "+z); + } this.x = x; this.y = y; this.z = z; diff --git a/src/main/java/eu/mihosoft/vrl/v3d/ext/imagej/STLLoader.java b/src/main/java/eu/mihosoft/vrl/v3d/ext/imagej/STLLoader.java index a8f6a142..fb03a7b4 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/ext/imagej/STLLoader.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/ext/imagej/STLLoader.java @@ -178,6 +178,7 @@ private void parseBinary(File f, ArrayList polygons,int triangles) { try { pl = new Plane(normal, vertices); }catch(NumberFormatException ex) { + System.out.println(" STL has bad Normal "+normal); pl=Plane.createFromPoints(vertices); } polygons.add(new Polygon(vertices, null, true, pl)); From e3fa580a483d9d809ecaced4f320a9ae8f323f68 Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Mon, 16 Feb 2026 14:07:06 -0500 Subject: [PATCH 03/35] epsilon --- src/main/java/eu/mihosoft/vrl/v3d/Plane.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Plane.java b/src/main/java/eu/mihosoft/vrl/v3d/Plane.java index f1dca02a..252bf861 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Plane.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Plane.java @@ -55,7 +55,7 @@ public class Plane implements Serializable { * to decide if a point is on the plane. public static final double EPSILON */ - private static double EPSILON = 1.0e-9; + private static double EPSILON = 1.0e-8; public static double EPSILON_Point = getEPSILON(); // public static double EPSILON_duplicate = 1.0e-4; /** From 59245792a851879884833a31b91a88422bde8d5e Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Mon, 16 Feb 2026 20:03:36 -0500 Subject: [PATCH 04/35] adjust points on the loading --- src/main/java/eu/mihosoft/vrl/v3d/Node.java | 2 +- src/main/java/eu/mihosoft/vrl/v3d/Plane.java | 7 ++++++- src/main/java/eu/mihosoft/vrl/v3d/Polygon.java | 18 +++++++++++++----- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Node.java b/src/main/java/eu/mihosoft/vrl/v3d/Node.java index 9daab72b..085a9ae8 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Node.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Node.java @@ -325,7 +325,7 @@ private static void add(List l, List f, Polygon polygon) { .setColor(polygon.getColor()); l.add(fpoly); }catch(ColinearPointsException ex) { - ex.printStackTrace(); + //ex.printStackTrace(); System.err.println("Pruned Collinear polygon "+f+" "+ex.getMessage() ); } } diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Plane.java b/src/main/java/eu/mihosoft/vrl/v3d/Plane.java index 252bf861..7a3041a0 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Plane.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Plane.java @@ -121,7 +121,12 @@ public Plane(List vertices, Vector3d testNorm) throws ColinearPointsExce */ public Plane(Vector3d normal, List vertices) { this.setNormal(normal.normalized()); - this.setDist(normal.dot(vertices.get(0).pos)); + double distAvg = 0; + for(int i=0;i Plane.getEPSILON()) { - pos.x -= a * normal.x; - pos.y -= a * normal.y; - pos.z -= a * normal.z; + if(adusted) { + //new ColinearPointsException("Non flat polygon, epsilon = "+a+" vs planer test of "+Plane.getEPSILON()).printStackTrace();; + double d = a * normal.x; + double e = a * normal.y; + double e2 = a * normal.z; + pos.x -= d; + pos.y -= e; + pos.z -= e2; + }else { + getPlane().setDist(dist+a); + } adusted=true; - //new ColinearPointsException("Non flat polygon, epsilon = "+a+" vs planer test of "+Plane.getEPSILON()).printStackTrace();; } } if(adusted) { From 24285b2d210889e8f0d509867d187ef76a3be6d3 Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Wed, 18 Feb 2026 08:26:22 -0500 Subject: [PATCH 05/35] polygons can fail to load for colinear points, but also for non flat polygons. --- src/main/java/eu/mihosoft/vrl/v3d/CSG.java | 2 +- .../vrl/v3d/NonFlatPolygonException.java | 11 +++++ src/main/java/eu/mihosoft/vrl/v3d/Plane.java | 2 +- .../java/eu/mihosoft/vrl/v3d/Polygon.java | 42 +++++++------------ 4 files changed, 27 insertions(+), 30 deletions(-) create mode 100644 src/main/java/eu/mihosoft/vrl/v3d/NonFlatPolygonException.java diff --git a/src/main/java/eu/mihosoft/vrl/v3d/CSG.java b/src/main/java/eu/mihosoft/vrl/v3d/CSG.java index a6d3b5e4..fc5cdf70 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/CSG.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/CSG.java @@ -136,7 +136,7 @@ @SuppressWarnings("restriction") public class CSG implements IuserAPI, Serializable { - transient private static final double POINTS_CONTACT_DISTANCE = 0.00001; + transient private static final double POINTS_CONTACT_DISTANCE = 0.0001; transient private static int MinPolygonsForOffloading = 200; transient private static final long serialVersionUID = 4071874097772427063L; transient private static IDebug3dProvider providerOf3d = null; diff --git a/src/main/java/eu/mihosoft/vrl/v3d/NonFlatPolygonException.java b/src/main/java/eu/mihosoft/vrl/v3d/NonFlatPolygonException.java new file mode 100644 index 00000000..26bc0a39 --- /dev/null +++ b/src/main/java/eu/mihosoft/vrl/v3d/NonFlatPolygonException.java @@ -0,0 +1,11 @@ +package eu.mihosoft.vrl.v3d; + +public class NonFlatPolygonException extends Exception { + + public NonFlatPolygonException(String string) { + super(string); + } + + private static final long serialVersionUID = -7968568496236268642L; + +} diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Plane.java b/src/main/java/eu/mihosoft/vrl/v3d/Plane.java index 7a3041a0..39d8545f 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Plane.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Plane.java @@ -217,7 +217,7 @@ public NormalState checkNormal(List vertex) { double dot = 1-dot2; double dFlipped = 2-dot2; // check for actual misallignment - double d = Plane.getEPSILON()*100; + double d = Plane.getEPSILON(); if(dot>d) if(dFlipped>d) return NormalState.DIVERGENT; diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java b/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java index d149a0b1..d5963b13 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java @@ -88,7 +88,7 @@ void setStorage(PropertyStorage storage) { * @param points the points that define the polygon * @return the decomposed concave polygon (list of convex polygons) */ - public static List fromConcavePoints(Vector3d... points) throws ColinearPointsException { + public static List fromConcavePoints(Vector3d... points) throws ColinearPointsException,NonFlatPolygonException { Polygon p = fromPoints(points); return PolygonUtil.triangulatePolygon(p); @@ -100,7 +100,7 @@ public static List fromConcavePoints(Vector3d... points) throws Colinea * @param points the points that define the polygon * @return the decomposed concave polygon (list of convex polygons) */ - public static List fromConcavePoints(List points)throws ColinearPointsException { + public static List fromConcavePoints(List points)throws ColinearPointsException,NonFlatPolygonException { Polygon p = fromPoints(points); return PolygonUtil.triangulatePolygon(p); @@ -115,7 +115,7 @@ public static List fromConcavePoints(List points)throws Colin * @param vertices polygon vertices * @param shared shared property */ - public Polygon(List vertices, PropertyStorage shared, boolean allowDegenerate, Plane p) throws ColinearPointsException { + public Polygon(List vertices, PropertyStorage shared, boolean allowDegenerate, Plane p) throws ColinearPointsException,NonFlatPolygonException { this.setVertices(pruneDuplicatePoints(vertices)); this.shared = shared; if (p != null) @@ -133,7 +133,7 @@ public Polygon(List vertices, PropertyStorage shared, boolean allowDegen * @param vertices polygon vertices * @param shared shared property */ - public Polygon(List vertices, PropertyStorage shared) throws ColinearPointsException { + public Polygon(List vertices, PropertyStorage shared) throws ColinearPointsException,NonFlatPolygonException { this(vertices, shared, true, null); } @@ -145,7 +145,7 @@ public Polygon(List vertices, PropertyStorage shared) throws ColinearPoi * * @param vertices polygon vertices */ - public Polygon(List vertices) throws ColinearPointsException { + public Polygon(List vertices) throws ColinearPointsException,NonFlatPolygonException { this(vertices, new PropertyStorage(), true, null); } @@ -170,7 +170,7 @@ public static ArrayList pruneDuplicatePoints(List incoming) { } } - private void validateAndInit(boolean fixInversions) throws ColinearPointsException { + private void validateAndInit(boolean fixInversions) throws ColinearPointsException,NonFlatPolygonException { ArrayList vertices = pruneDuplicatePoints(this.vertices); Plane p = Plane.createFromPoints(vertices); if (getPlane() == null) { @@ -201,24 +201,10 @@ private void validateAndInit(boolean fixInversions) throws ColinearPointsExcepti throw new RuntimeException("A plane epsilon of "+t+" is impossible"); } if (t > Plane.getEPSILON()) { - if(adusted) { - //new ColinearPointsException("Non flat polygon, epsilon = "+a+" vs planer test of "+Plane.getEPSILON()).printStackTrace();; - double d = a * normal.x; - double e = a * normal.y; - double e2 = a * normal.z; - pos.x -= d; - pos.y -= e; - pos.z -= e2; - }else { - getPlane().setDist(dist+a); - } - adusted=true; + throw new NonFlatPolygonException("Failed because polygon is not flat"); } } - if(adusted) { - validateAndInit(fixInversions); - return; - } + if( !areAllPointsCollinear()) return; @@ -240,7 +226,7 @@ public void rotatePoints() { * @param vertices polygon vertices * */ - public Polygon(Vertex... vertices) throws ColinearPointsException { + public Polygon(Vertex... vertices) throws ColinearPointsException,NonFlatPolygonException { this(Arrays.asList(vertices)); } @@ -442,7 +428,7 @@ public Polygon transformed(Transform transform) throws ColinearPointsException { * @param shared shared property storage * @return a polygon defined by the specified point list */ - public static Polygon fromPoints(List points, PropertyStorage shared) throws ColinearPointsException { + public static Polygon fromPoints(List points, PropertyStorage shared) throws ColinearPointsException,NonFlatPolygonException { return fromPoints(points, shared, null, true); } @@ -452,7 +438,7 @@ public static Polygon fromPoints(List points, PropertyStorage shared) * @param points the points that define the polygon * @return a polygon defined by the specified point list */ - public static Polygon fromPoints(List points)throws ColinearPointsException { + public static Polygon fromPoints(List points)throws ColinearPointsException,NonFlatPolygonException { return fromPoints(points, new PropertyStorage(), null, true); } @@ -462,11 +448,11 @@ public static Polygon fromPoints(List points)throws ColinearPointsExce * @param points the points that define the polygon * @return a polygon defined by the specified point list */ - public static Polygon fromPoints(Vector3d... points)throws ColinearPointsException { + public static Polygon fromPoints(Vector3d... points)throws ColinearPointsException,NonFlatPolygonException { return fromPoints(Arrays.asList(points), new PropertyStorage(), null, true); } - public static Polygon fromPointsAllowDegenerate(List vertices2) throws ColinearPointsException { + public static Polygon fromPointsAllowDegenerate(List vertices2) throws ColinearPointsException,NonFlatPolygonException { return fromPoints(vertices2, new PropertyStorage(), null, true); } @@ -479,7 +465,7 @@ public static Polygon fromPointsAllowDegenerate(List vertices2) throws * @return a polygon defined by the specified point list */ public static Polygon fromPoints(List points, PropertyStorage shared, Plane plane, - boolean allowDegenerate)throws ColinearPointsException { + boolean allowDegenerate)throws ColinearPointsException,NonFlatPolygonException { List vertices = new ArrayList<>(); for (Vector3d p : points) { Vector3d vec = p.clone(); From 1d7daacd3d52e3facd36f32132c5b77492ad0f37 Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Wed, 18 Feb 2026 10:13:59 -0500 Subject: [PATCH 06/35] new exceptions in polygon creation --- src/test/java/eu/mihosoft/vrl/v3d/HoleDetectionTest.java | 3 ++- .../java/eu/mihosoft/vrl/v3d/PolygonClassificationTest.java | 6 ++++-- src/test/java/eu/mihosoft/vrl/v3d/SvgExportTest.java | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/test/java/eu/mihosoft/vrl/v3d/HoleDetectionTest.java b/src/test/java/eu/mihosoft/vrl/v3d/HoleDetectionTest.java index 1dce702a..b630ecb5 100644 --- a/src/test/java/eu/mihosoft/vrl/v3d/HoleDetectionTest.java +++ b/src/test/java/eu/mihosoft/vrl/v3d/HoleDetectionTest.java @@ -22,9 +22,10 @@ public class HoleDetectionTest { /** * Hole detection test. * @throws ColinearPointsException + * @throws NonFlatPolygonException */ @Test - public void holeDetectionTest() throws ColinearPointsException { + public void holeDetectionTest() throws ColinearPointsException, NonFlatPolygonException { // one polygon with one hole Polygon p1 = Polygon.fromPoints( diff --git a/src/test/java/eu/mihosoft/vrl/v3d/PolygonClassificationTest.java b/src/test/java/eu/mihosoft/vrl/v3d/PolygonClassificationTest.java index dd5feab9..fadc5e92 100644 --- a/src/test/java/eu/mihosoft/vrl/v3d/PolygonClassificationTest.java +++ b/src/test/java/eu/mihosoft/vrl/v3d/PolygonClassificationTest.java @@ -140,9 +140,10 @@ public void testPolygon6_ValidWithLargeYZDifferences() { * Test to verify that truly degenerate polygons ARE correctly rejected * * @throws ColinearPointsException + * @throws NonFlatPolygonException */ @Test(expected = ColinearPointsException.class) - public void testDegeneratePolygon_DuplicatePoints() throws ColinearPointsException { + public void testDegeneratePolygon_DuplicatePoints() throws ColinearPointsException, NonFlatPolygonException { // This SHOULD fail - duplicate points List vertices = Arrays.asList( new Vertex(new Vector3d(10.5175167546, 116.6176943528, 83.1832321598)), @@ -158,9 +159,10 @@ public void testDegeneratePolygon_DuplicatePoints() throws ColinearPointsExcepti /** * Test to verify that collinear points ARE correctly rejected * @throws ColinearPointsException + * @throws NonFlatPolygonException */ @Test(expected = ColinearPointsException.class) - public void testDegeneratePolygon_Collinear() throws ColinearPointsException { + public void testDegeneratePolygon_Collinear() throws ColinearPointsException, NonFlatPolygonException { // This SHOULD fail - all points on same line (same Y coordinate, collinear in XZ) List vertices = Arrays.asList( new Vertex(new Vector3d(10.5068817145, 98.4507751465, 35.0306403108)), diff --git a/src/test/java/eu/mihosoft/vrl/v3d/SvgExportTest.java b/src/test/java/eu/mihosoft/vrl/v3d/SvgExportTest.java index 9009f914..17ee8170 100644 --- a/src/test/java/eu/mihosoft/vrl/v3d/SvgExportTest.java +++ b/src/test/java/eu/mihosoft/vrl/v3d/SvgExportTest.java @@ -45,7 +45,7 @@ public void slicetest() throws IOException, ColinearPointsException { } @Test - public void test() throws IOException, ColinearPointsException { + public void test() throws IOException, ColinearPointsException, NonFlatPolygonException { List polygons = new ArrayList(); @@ -71,7 +71,7 @@ public void test() throws IOException, ColinearPointsException { } @Test - public void testSlices() throws IOException, ColinearPointsException { + public void testSlices() throws IOException, ColinearPointsException, NonFlatPolygonException { List polygons = new ArrayList(); From 3b61d5121d880fcde88c21714c9d76ba43c64270 Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Wed, 18 Feb 2026 10:34:30 -0500 Subject: [PATCH 07/35] processing some of the polygons failure modes --- .../mihosoft/vrl/v3d/IPolygonRepairTool.java | 4 +- .../vrl/v3d/ext/org/poly2tri/PolygonUtil.java | 54 ++++++++++++------- 2 files changed, 37 insertions(+), 21 deletions(-) diff --git a/src/main/java/eu/mihosoft/vrl/v3d/IPolygonRepairTool.java b/src/main/java/eu/mihosoft/vrl/v3d/IPolygonRepairTool.java index aec99b2a..a3b61c4d 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/IPolygonRepairTool.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/IPolygonRepairTool.java @@ -1,5 +1,7 @@ package eu.mihosoft.vrl.v3d; +import java.util.List; + public interface IPolygonRepairTool { - Polygon repairOverlappingEdges(Polygon concave) throws ColinearPointsException; + List repairOverlappingEdges(Polygon concave) throws ColinearPointsException; } diff --git a/src/main/java/eu/mihosoft/vrl/v3d/ext/org/poly2tri/PolygonUtil.java b/src/main/java/eu/mihosoft/vrl/v3d/ext/org/poly2tri/PolygonUtil.java index f0906ad7..95c1dfdf 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/ext/org/poly2tri/PolygonUtil.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/ext/org/poly2tri/PolygonUtil.java @@ -39,8 +39,10 @@ import eu.mihosoft.vrl.v3d.Edge; import eu.mihosoft.vrl.v3d.Extrude; import eu.mihosoft.vrl.v3d.IPolygonRepairTool; +import eu.mihosoft.vrl.v3d.NonFlatPolygonException; import eu.mihosoft.vrl.v3d.Plane; import eu.mihosoft.vrl.v3d.Polygon; +import eu.mihosoft.vrl.v3d.PropertyStorage; import eu.mihosoft.vrl.v3d.Transform; import eu.mihosoft.vrl.v3d.Vector3d; import eu.mihosoft.vrl.v3d.Vertex; @@ -183,10 +185,11 @@ public class PolygonUtil { if (modifiable.size() > 2) { try { Polygon polygon = new Polygon(modifiable, concave1.getStorage(), false, concave1.getPlane()); - return polygon; + return Arrays.asList(polygon); } catch (ColinearPointsException e) { System.out.println(" Pruning polygon in repair " + concave1 + " to " + modifiable); - + } catch (NonFlatPolygonException e) { + triangulatePolygon(modifiable, concave1.getStorage(), false, concave1.getPlane()); } } throw new ColinearPointsException("Fix failed!"); @@ -504,6 +507,12 @@ private PolygonUtil() { // return result; // } + /** + * Calculates a quaternion-based transform that rotates `from` vector to align + * with (0,0,1). + * + * @throws ColinearPointsException + */ /** * Calculates a quaternion-based transform that rotates `from` vector to align * with (0,0,1). @@ -511,8 +520,20 @@ private PolygonUtil() { * @throws ColinearPointsException */ public static Transform calculateNormalTransform(Polygon concave) throws ColinearPointsException { + Transform transform = calculateNormalTransform(concave.getPlane()); + Polygon test = concave.transformed(transform); + Vector3d normal = test.plane.getNormal(); + double abs = Math.abs(normal.z); + if (1 - abs > 0.1) { + System.out.println("Error with " + test+" normal "+normal); + // Plane p = Plane.createFromPoints(test.getVertices()); + new ColinearPointsException("Failed to reorent the polygon for processing! z off by "+abs+" "+normal).printStackTrace(); + } + return transform; + } + public static Transform calculateNormalTransform(Plane p) throws ColinearPointsException { // Normalize inputs - Vector3d u = concave.getPlane().getNormal(); + Vector3d u = p.getNormal(); Vector3d pureXVect = new Vector3d(1, 0, 0); Vector3d pureYVect = new Vector3d(0, 1, 0); Vector3d pureZVect = new Vector3d(0, 0, 1); @@ -552,17 +573,7 @@ public static Transform calculateNormalTransform(Polygon concave) throws Colinea transform = rotY.copy().apply(transform1); - Vector3d u3 = u.transformed(transform).normalized(); - Polygon test = concave.transformed(transform); - Vector3d normal = test.plane.getNormal(); - double abs = Math.abs(normal.z); - if (1 - abs > 0.1) { - System.out.println("Error with " + test+" normal "+normal); - // Plane p = Plane.createFromPoints(test.getVertices()); - new ColinearPointsException("Failed to reorent the polygon for processing! z off by "+abs+" "+normal).printStackTrace(); - } - Matrix4d rotation = transform.getInternalMatrix(); Quat4d q1 = transform.getQuat(); javax.vecmath.Vector3d t1 = new javax.vecmath.Vector3d(); @@ -583,22 +594,25 @@ public static Transform calculateNormalTransform(Polygon concave) throws Colinea * @return the list * @throws ColinearPointsException */ - public static ArrayList triangulatePolygon(Polygon incoming) throws ColinearPointsException { + + public static ArrayList triangulatePolygon(Polygon p) throws ColinearPointsException{ ArrayList result = new ArrayList<>(); - - if (incoming == null) + if (p == null) return result; - if (incoming.getVertices().size() < 3) + if (p.getVertices().size() < 3) return result; - Polygon tmp = incoming; - Vector3d normalOfPlane = incoming.getPlane().getNormal().clone(); + return triangulatePolygon(p.getVertices(), p.getStorage(), false, p.getPlane()); + } + public static ArrayList triangulatePolygon(List vertices, PropertyStorage shared, boolean allowDegenerate, Plane p) throws ColinearPointsException { + + Vector3d normalOfPlane = p.getNormal().clone(); normalOfPlane.normalize(); boolean reorient = Math.abs(normalOfPlane.z - 1.0) > Plane.getEPSILON(); Transform orientationInv = null; boolean debug = false; if (reorient) { - Transform orientation = calculateNormalTransform(incoming); + Transform orientation = calculateNormalTransform(p); tmp = incoming.transformed(orientation); orientationInv = orientation.inverse(); } From 2c4d11ebb6630bbd25f6d9a382a913da541913a6 Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Thu, 19 Feb 2026 08:15:45 -0500 Subject: [PATCH 08/35] Continue to add multi handeling --- .../mihosoft/vrl/v3d/IPolygonRepairTool.java | 5 +- .../vrl/v3d/ext/org/poly2tri/PolygonUtil.java | 210 +++++++----------- 2 files changed, 81 insertions(+), 134 deletions(-) diff --git a/src/main/java/eu/mihosoft/vrl/v3d/IPolygonRepairTool.java b/src/main/java/eu/mihosoft/vrl/v3d/IPolygonRepairTool.java index a3b61c4d..4d95f9d1 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/IPolygonRepairTool.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/IPolygonRepairTool.java @@ -2,6 +2,9 @@ import java.util.List; +import javafx.scene.paint.Color; + public interface IPolygonRepairTool { - List repairOverlappingEdges(Polygon concave) throws ColinearPointsException; + List repairOverlappingEdges(List vertices, PropertyStorage shared, + boolean allowDegenerate, Plane p, Color c) throws ColinearPointsException; } diff --git a/src/main/java/eu/mihosoft/vrl/v3d/ext/org/poly2tri/PolygonUtil.java b/src/main/java/eu/mihosoft/vrl/v3d/ext/org/poly2tri/PolygonUtil.java index 95c1dfdf..f3bd31aa 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/ext/org/poly2tri/PolygonUtil.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/ext/org/poly2tri/PolygonUtil.java @@ -64,7 +64,6 @@ import org.locationtech.jts.geom.GeometryFactory; import org.locationtech.jts.triangulate.polygon.ConstrainedDelaunayTriangulator; - //import earcut4j.Earcut; /** @@ -74,12 +73,13 @@ */ public class PolygonUtil { public static final double triangleScale = 1; - private static IPolygonRepairTool repair = concave1 -> { + private static IPolygonRepairTool repair = (Listvertices, PropertyStorage shared, + boolean allowDegenerate, Plane p, Color color) -> { ArrayList edges = new ArrayList(); ArrayList toRemove = new ArrayList(); HashMap replace = new HashMap<>(); - List v1 = concave1.getVertices(); + List v1 = vertices; ArrayList modifiable = new ArrayList(); for (int i = 0; i < v1.size(); i++) { @@ -184,12 +184,13 @@ public class PolygonUtil { modifiable.remove(vr); if (modifiable.size() > 2) { try { - Polygon polygon = new Polygon(modifiable, concave1.getStorage(), false, concave1.getPlane()); + Polygon polygon = new Polygon(modifiable, shared, allowDegenerate, p); + polygon.setColor(color); return Arrays.asList(polygon); } catch (ColinearPointsException e) { - System.out.println(" Pruning polygon in repair " + concave1 + " to " + modifiable); + System.out.println(" Pruning polygon in repair " + vertices + " to " + modifiable); } catch (NonFlatPolygonException e) { - triangulatePolygon(modifiable, concave1.getStorage(), false, concave1.getPlane()); + return triangulatePolygon(modifiable, shared, allowDegenerate, p, color); } } throw new ColinearPointsException("Fix failed!"); @@ -525,12 +526,14 @@ public static Transform calculateNormalTransform(Polygon concave) throws Colinea Vector3d normal = test.plane.getNormal(); double abs = Math.abs(normal.z); if (1 - abs > 0.1) { - System.out.println("Error with " + test+" normal "+normal); + System.out.println("Error with " + test + " normal " + normal); // Plane p = Plane.createFromPoints(test.getVertices()); - new ColinearPointsException("Failed to reorent the polygon for processing! z off by "+abs+" "+normal).printStackTrace(); + new ColinearPointsException("Failed to reorent the polygon for processing! z off by " + abs + " " + normal) + .printStackTrace(); } return transform; } + public static Transform calculateNormalTransform(Plane p) throws ColinearPointsException { // Normalize inputs Vector3d u = p.getNormal(); @@ -560,30 +563,28 @@ public static Transform calculateNormalTransform(Plane p) throws ColinearPointsE // return new Transform().rotX(-90); // } double aboutZ = Math.toDegrees(Math.atan2(u.y, u.x)); - if(Double.isNaN(aboutZ)) + if (Double.isNaN(aboutZ)) throw new ColinearPointsException("Failed to creat a rotation angle"); Transform transform1 = new Transform().rotZ(aboutZ); Vector3d u2 = u.transformed(transform1); Transform transform; double aboutY = Math.toDegrees(Math.atan2(u2.x, u2.z)); - if(Double.isNaN(aboutY)) + if (Double.isNaN(aboutY)) throw new ColinearPointsException("Failed to creat a rotation angle"); - + Transform rotY = new Transform().rotY(aboutY); transform = rotY.copy().apply(transform1); - - Matrix4d rotation = transform.getInternalMatrix(); Quat4d q1 = transform.getQuat(); javax.vecmath.Vector3d t1 = new javax.vecmath.Vector3d(); rotation.get(t1); List asList = Arrays.asList(t1.x, t1.y, t1.z, q1.w, q1.x, q1.y, q1.z); - for(Double d:asList){ - if(Double.isInfinite(d)||Double.isNaN(d)) + for (Double d : asList) { + if (Double.isInfinite(d) || Double.isNaN(d)) throw new ColinearPointsException("Failed to produce a matrix "); } - + return transform; } @@ -594,145 +595,81 @@ public static Transform calculateNormalTransform(Plane p) throws ColinearPointsE * @return the list * @throws ColinearPointsException */ - - public static ArrayList triangulatePolygon(Polygon p) throws ColinearPointsException{ + + public static ArrayList triangulatePolygon(Polygon p) throws ColinearPointsException { ArrayList result = new ArrayList<>(); if (p == null) return result; if (p.getVertices().size() < 3) return result; - return triangulatePolygon(p.getVertices(), p.getStorage(), false, p.getPlane()); + return triangulatePolygon(p.getVertices(), p.getStorage(), false, p.getPlane(),p.getColor()); } - public static ArrayList triangulatePolygon(List vertices, PropertyStorage shared, boolean allowDegenerate, Plane p) throws ColinearPointsException { + public static List transformed(List vertices, Transform transform) { + List tmp = new ArrayList(); + tmp.addAll(vertices); + tmp.stream().forEach((v) -> { + v.clone().transform(transform); + }); + return tmp; + } + + public static ArrayList triangulatePolygon(List vertices, PropertyStorage shared, + boolean allowDegenerate, Plane p, Color c) throws ColinearPointsException { + ArrayList result = new ArrayList<>(); Vector3d normalOfPlane = p.getNormal().clone(); normalOfPlane.normalize(); boolean reorient = Math.abs(normalOfPlane.z - 1.0) > Plane.getEPSILON(); Transform orientationInv = null; boolean debug = false; - + List tmp = vertices; if (reorient) { + Polygon incoming; Transform orientation = calculateNormalTransform(p); - tmp = incoming.transformed(orientation); + tmp = transformed(vertices, orientation); orientationInv = orientation.inverse(); } boolean cw = false; -// if(!Extrude.isCCW(tmp)) { -// ArrayList v =new ArrayList(tmp.getVertices()); -// Collections.reverse(v); -// tmp = new Polygon(v, tmp.getStorage(), false, null); -// } - Polygon concave = tmp; - double zplane = concave.getVertices().get(0).pos.z; -// for (Vector3d v : concave.getPoints()) { -// double abs = Math.abs(zplane - v.z); -// if (abs > 0.1) { -// new RuntimeException("Failed to triangulate, points must be coplainer, delta: " + abs) -// .printStackTrace(); -// } -// } - try { - if (concave.size() == 3) { - result.add(concave); - } else + double zplane = vertices.get(0).pos.z; + + if (vertices.size() == 3) { + result.add(new Polygon(vertices, shared, allowDegenerate, p)); + } else + try { makeTriangles(concave, cw, result, zplane, normalOfPlane, debug, orientationInv, reorient, - incoming.getColor()); - } catch (java.lang.IllegalStateException ex) { - - Polygon repaired = repairOverlappingEdges(concave); - int end = repaired.getVertices().size(); - if (end == 3) { - result.add(repaired); - } else { - try { - makeTriangles(repaired, cw, result, zplane, normalOfPlane, debug, orientationInv, reorient, - incoming.getColor()); - } catch (Exception e) { - makeTrianglesInternal(repaired, cw, result, zplane, normalOfPlane, debug, orientationInv, reorient, - incoming.getColor()); + c); + } catch (java.lang.IllegalStateException ex) { + + Polygon repaired = repairOverlappingEdges(concave); + int end = repaired.getVertices().size(); + if (end == 3) { + result.add(repaired); + } else { + try { + makeTriangles(repaired, cw, result, zplane, normalOfPlane, debug, orientationInv, reorient, + c); + } catch (Exception e) { + makeTrianglesInternal(repaired, cw, result, zplane, normalOfPlane, debug, orientationInv, + reorient,c); + } } - } - - if (reorient) { - repaired = repaired.transform(orientationInv); - } - incoming.setVertices(repaired.getVertices()); - } + if (reorient) { + repaired = repaired.transform(orientationInv); + } + vertices.clear(); + vertices.addAll(repaired.getVertices()); + } return result; } - private static Polygon repairOverlappingEdges(Polygon concave) throws ColinearPointsException { + private static List repairOverlappingEdges(Polygon concave) throws ColinearPointsException { - return getRepair().repairOverlappingEdges(concave); + return getRepair().repairOverlappingEdges(concave.getVertices(),concave.getStorage(),false,concave.getPlane(),concave.getColor()); } -// private static void fourPointSpecialCase(Polygon concave, boolean cw, List result, double zplane, -// Vector3d normal, boolean debug, Transform orentationInv, boolean reorent, Color color) { -// List points = concave.getPoints(); -// int size = points.size(); -// for (int i = 0; i < size; i++) { -// // Get first two points to establish a direction vector -// Vector3d p1 = points.get(i); -// Vector3d p2 = points.get((i + 1) % size); -// -// // Calculate the direction vector between first two points -// Vector3d direction = p1.minus(p2); -// // Normalize the direction vector -// double length = direction.length(); -// double ep = Plane.getEPSILON(); -// if (length < ep) { // If points are effectively identical -// continue; -// } -// direction.normalize(); -// Vector3d p3 = points.get((i + 2) % size); -// -// // Calculate cross product -// Vector3d cross = direction.cross(p1.minus(p3)); -// // Calculate magnitude of cross product -// double magnitude = Math.abs(cross.length()); -// -// // If magnitude is not close to zero, points are not collinear -// if (magnitude > ep) { -// -// Plane normal2 = concave.plane; -// try { -// Polygon one = new Polygon( -// new ArrayList(Arrays.asList(new Vertex(p1), new Vertex(p2), new Vertex(p3))), -// concave.getStorage(), true, normal2); -// if (reorent) { -// one = one.transform(orentationInv); -// } -// one.setColor(color); -// result.add(one); -// } catch (ColinearPointsException e) { -// // TODO Auto-generated catch block -// e.printStackTrace(); -// } -// try { -// Polygon two = new Polygon( -// new ArrayList(Arrays.asList(new Vertex(points.get((i + 3) % size)), -// new Vertex(points.get((i + 4) % size)), new Vertex(points.get((i + 5) % size)))), -// concave.getStorage(), true, normal2); -// if (reorent) { -// two = two.transform(orentationInv); -// } -// two.setColor(color); -// result.add(two); -// } catch (ColinearPointsException e) { -// // TODO Auto-generated catch block -// e.printStackTrace(); -// } -// -// -// return; -// } -// } -// -// } - private static void makeTrianglesInternal(Polygon concave, boolean cw, List result, double zplane, Vector3d normal, boolean debug, Transform orentationInv, boolean reorent, Color color) throws ColinearPointsException { @@ -767,7 +704,7 @@ private static void makeTrianglesInternal(Polygon concave, boolean cw, List 0.1) { - new RuntimeException("Failed to triangulate, points must be coplainer").printStackTrace(); + new RuntimeException("Failed to triangulate, points must be coplainer").printStackTrace(); } // Calculate cross product @@ -793,6 +730,9 @@ private static void makeTrianglesInternal(Polygon concave, boolean cw, List res Vertex e = null;// new Vertex(pos); for (int x = 0; x < toTri.getVertices().size(); x++) { Vector3d test = toTri.getVertices().get(x).pos; - double diffX = Math.abs( test.x-pos.x); - double diffY = Math.abs(test.y-pos.y); - if (diffY res if (e == null) { throw new RuntimeException("Failed to find point! " + pos + " missing from " + toTri); } - if(!triPoints.contains(e)) + if (!triPoints.contains(e)) triPoints.add(e); if (counter == 2) { @@ -883,6 +824,9 @@ private static void makeTriangles(Polygon concave, boolean cw, List res result.add(poly); } catch (ColinearPointsException ex) { System.out.println(ex.getMessage() + " Pruned new triangle as colinear " + triPoints); + } catch (NonFlatPolygonException e1) { + System.err.println("Impossible! it should not be possible to have anon-flat triangle"); + e1.printStackTrace(); } counter = 0; From 29d8eb09e53bbb02e6c31fee554e3fc7a1ddfe2b Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Fri, 20 Feb 2026 08:32:02 -0500 Subject: [PATCH 09/35] make the PolygonUtil work on list of verticies instead of on polygons --- .../vrl/v3d/ext/org/poly2tri/PolygonUtil.java | 87 ++++++++++--------- 1 file changed, 48 insertions(+), 39 deletions(-) diff --git a/src/main/java/eu/mihosoft/vrl/v3d/ext/org/poly2tri/PolygonUtil.java b/src/main/java/eu/mihosoft/vrl/v3d/ext/org/poly2tri/PolygonUtil.java index f3bd31aa..8309250a 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/ext/org/poly2tri/PolygonUtil.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/ext/org/poly2tri/PolygonUtil.java @@ -73,8 +73,8 @@ */ public class PolygonUtil { public static final double triangleScale = 1; - private static IPolygonRepairTool repair = (Listvertices, PropertyStorage shared, - boolean allowDegenerate, Plane p, Color color) -> { + private static IPolygonRepairTool repair = (List vertices, PropertyStorage shared, boolean allowDegenerate, + Plane p, Color color) -> { ArrayList edges = new ArrayList(); ArrayList toRemove = new ArrayList(); @@ -602,7 +602,7 @@ public static ArrayList triangulatePolygon(Polygon p) throws ColinearPo return result; if (p.getVertices().size() < 3) return result; - return triangulatePolygon(p.getVertices(), p.getStorage(), false, p.getPlane(),p.getColor()); + return triangulatePolygon(p.getVertices(), p.getStorage(), false, p.getPlane(), p.getColor()); } public static List transformed(List vertices, Transform transform) { @@ -634,40 +634,49 @@ public static ArrayList triangulatePolygon(List vertices, Prope double zplane = vertices.get(0).pos.z; if (vertices.size() == 3) { - result.add(new Polygon(vertices, shared, allowDegenerate, p)); + try { + result.add(new Polygon(vertices, shared, allowDegenerate, p)); + } catch (ColinearPointsException e) { + e.printStackTrace(); + } catch (NonFlatPolygonException e) { + e.printStackTrace(); + } } else try { - makeTriangles(concave, cw, result, zplane, normalOfPlane, debug, orientationInv, reorient, - c); + makeTriangles(vertices, shared, allowDegenerate, p, cw, result, zplane, normalOfPlane, debug, + orientationInv, reorient, c); } catch (java.lang.IllegalStateException ex) { - Polygon repaired = repairOverlappingEdges(concave); - int end = repaired.getVertices().size(); - if (end == 3) { - result.add(repaired); - } else { - try { - makeTriangles(repaired, cw, result, zplane, normalOfPlane, debug, orientationInv, reorient, - c); - } catch (Exception e) { - makeTrianglesInternal(repaired, cw, result, zplane, normalOfPlane, debug, orientationInv, - reorient,c); + List repairedList = repairOverlappingEdges(vertices, shared, allowDegenerate, p, c); + for (Polygon repaired : repairedList) { + int end = repaired.getVertices().size(); + if (end == 3) { + result.add(repaired); + } else { + try { + makeTriangles(repaired.getVertices(),repaired.getStorage(),false,repaired.getPlane(), cw, result, zplane, normalOfPlane, debug, orientationInv, reorient, + c); + } catch (Exception e) { + makeTrianglesInternal(repaired, cw, result, zplane, normalOfPlane, debug, orientationInv, + reorient, c); + } } - } - if (reorient) { - repaired = repaired.transform(orientationInv); + if (reorient) { + repaired = repaired.transform(orientationInv); + } + vertices.clear(); + vertices.addAll(repaired.getVertices()); } - vertices.clear(); - vertices.addAll(repaired.getVertices()); } return result; } - private static List repairOverlappingEdges(Polygon concave) throws ColinearPointsException { + private static List repairOverlappingEdges(List vertices, PropertyStorage shared, + boolean allowDegenerate, Plane p, Color c) throws ColinearPointsException { - return getRepair().repairOverlappingEdges(concave.getVertices(),concave.getStorage(),false,concave.getPlane(),concave.getColor()); + return getRepair().repairOverlappingEdges(vertices, shared, false, p, c); } private static void makeTrianglesInternal(Polygon concave, boolean cw, List result, double zplane, @@ -754,24 +763,24 @@ private static void makeTrianglesInternal(Polygon concave, boolean cw, List result, double zplane, Vector3d normal, - boolean debug, Transform orentationInv, boolean reorent, Color color) { + private static void makeTriangles(List vertices, PropertyStorage shared, boolean allowDegenerate, Plane p, + boolean cw, List result, double zplane, Vector3d normal, boolean debug, Transform orentationInv, + boolean reorent, Color color) { - Polygon toTri = concave; + // Polygon toTri = concave; - Coordinate[] coordinates = new Coordinate[toTri.getVertices().size() + 1]; - for (int i = 0; i < toTri.getVertices().size(); i++) { - Vector3d v = toTri.getVertices().get(i).pos; + Coordinate[] coordinates = new Coordinate[vertices.size() + 1]; + for (int i = 0; i < vertices.size(); i++) { + Vector3d v = vertices.get(i).pos; coordinates[i] = new Coordinate(v.x * triangleScale, v.y * triangleScale, v.z * triangleScale); } - Vector3d v = toTri.getVertices().get(0).pos; - coordinates[toTri.getVertices().size()] = new Coordinate(v.x * triangleScale, v.y * triangleScale, - v.z * triangleScale); + Vector3d v = vertices.get(0).pos; + coordinates[vertices.size()] = new Coordinate(v.x * triangleScale, v.y * triangleScale, v.z * triangleScale); // use the default factory, which gives full double-precision Geometry geom = new GeometryFactory().createPolygon(coordinates); Geometry triangles = ConstrainedDelaunayTriangulator.triangulate(geom); ArrayList triPoints = new ArrayList<>(); - Plane p1 = concave.getPlane().clone(); + Plane p1 = p; for (int i = 0; i < triangles.getNumGeometries(); i++) { Geometry tri = triangles.getGeometryN(i); Coordinate[] coords = tri.getCoordinates(); @@ -782,17 +791,17 @@ private static void makeTriangles(Polygon concave, boolean cw, List res Coordinate tp = coords[j]; Vector3d pos = new Vector3d(tp.getX() / triangleScale, tp.getY() / triangleScale, zplane); Vertex e = null;// new Vertex(pos); - for (int x = 0; x < toTri.getVertices().size(); x++) { - Vector3d test = toTri.getVertices().get(x).pos; + for (int x = 0; x < vertices.size(); x++) { + Vector3d test = vertices.get(x).pos; double diffX = Math.abs(test.x - pos.x); double diffY = Math.abs(test.y - pos.y); if (diffY < Plane.getEPSILON() && diffX < Plane.getEPSILON()) { - e = toTri.getVertices().get(x).clone(); + e = vertices.get(x).clone(); break; } } if (e == null) { - throw new RuntimeException("Failed to find point! " + pos + " missing from " + toTri); + throw new RuntimeException("Failed to find point! " + pos + " missing from " + vertices); } if (!triPoints.contains(e)) triPoints.add(e); @@ -804,7 +813,7 @@ private static void makeTriangles(Polygon concave, boolean cw, List res Collections.reverse(triPoints); } Polygon poly; - poly = new Polygon(triPoints, concave.getStorage(), true, p1); + poly = new Polygon(triPoints, shared, true, p1); // poly = Extrude.toCCW(poly); // poly.getPlane().setNormal(concave.getPlane().getNormal()); From f590d7ac5fd252920467d355885edad6358ef59f Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Sun, 22 Feb 2026 13:15:17 -0500 Subject: [PATCH 10/35] Polygon should not be accessed as a single object, but rather the stable API should only be to get a list of polygons. --- .../java/eu/mihosoft/vrl/v3d/Polygon.java | 202 +++++++++--------- 1 file changed, 102 insertions(+), 100 deletions(-) diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java b/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java index d5963b13..24216bb0 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java @@ -73,38 +73,6 @@ public final class Polygon implements Serializable { private boolean valid = true; private boolean degenerate = false; - /** - * Sets the storage. - * - * @param storage the new storage - */ - void setStorage(PropertyStorage storage) { - this.shared = storage; - } - - /** - * Decomposes the specified concave polygon into convex polygons. - * - * @param points the points that define the polygon - * @return the decomposed concave polygon (list of convex polygons) - */ - public static List fromConcavePoints(Vector3d... points) throws ColinearPointsException,NonFlatPolygonException { - Polygon p = fromPoints(points); - - return PolygonUtil.triangulatePolygon(p); - } - - /** - * Decomposes the specified concave polygon into convex polygons. - * - * @param points the points that define the polygon - * @return the decomposed concave polygon (list of convex polygons) - */ - public static List fromConcavePoints(List points)throws ColinearPointsException,NonFlatPolygonException { - Polygon p = fromPoints(points); - - return PolygonUtil.triangulatePolygon(p); - } /** * Constructor. Creates a new polygon that consists of the specified vertices. @@ -115,7 +83,7 @@ public static List fromConcavePoints(List points)throws Colin * @param vertices polygon vertices * @param shared shared property */ - public Polygon(List vertices, PropertyStorage shared, boolean allowDegenerate, Plane p) throws ColinearPointsException,NonFlatPolygonException { + private Polygon(List vertices, PropertyStorage shared, boolean allowDegenerate, Plane p) throws ColinearPointsException,NonFlatPolygonException { this.setVertices(pruneDuplicatePoints(vertices)); this.shared = shared; if (p != null) @@ -133,7 +101,7 @@ public Polygon(List vertices, PropertyStorage shared, boolean allowDegen * @param vertices polygon vertices * @param shared shared property */ - public Polygon(List vertices, PropertyStorage shared) throws ColinearPointsException,NonFlatPolygonException { + private Polygon(List vertices, PropertyStorage shared) throws ColinearPointsException,NonFlatPolygonException { this(vertices, shared, true, null); } @@ -145,9 +113,99 @@ public Polygon(List vertices, PropertyStorage shared) throws ColinearPoi * * @param vertices polygon vertices */ - public Polygon(List vertices) throws ColinearPointsException,NonFlatPolygonException { + private Polygon(List vertices) throws ColinearPointsException,NonFlatPolygonException { this(vertices, new PropertyStorage(), true, null); } + /** + * Constructor. Creates a new polygon that consists of the specified vertices. + * + * Note: the vertices used to initialize a polygon must be coplanar and form a + * convex loop. + * + * @param vertices polygon vertices + * + */ + private Polygon(Vertex... vertices) throws ColinearPointsException,NonFlatPolygonException { + this(Arrays.asList(vertices)); + } + /** + * Decomposes the specified concave polygon into convex polygons. + * + * @param points the points that define the polygon + * @return the decomposed concave polygon (list of convex polygons) + */ + public static List fromConcavePoints(Vector3d... points) throws ColinearPointsException,NonFlatPolygonException { + Polygon p = fromPoints(points); + + return PolygonUtil.triangulatePolygon(p); + } + /** + * Creates a polygon from the specified point list. + * + * @param points the points that define the polygon + * @param shared shared property storage + * @return a polygon defined by the specified point list + */ + public static Polygon fromPoints(List points, PropertyStorage shared) throws ColinearPointsException,NonFlatPolygonException { + return fromPoints(points, shared, null, true); + } + + /** + * Creates a polygon from the specified point list. + * + * @param points the points that define the polygon + * @return a polygon defined by the specified point list + */ + public static Polygon fromPoints(List points)throws ColinearPointsException,NonFlatPolygonException { + return fromPoints(points, new PropertyStorage(), null, true); + } + + /** + * Creates a polygon from the specified points. + * + * @param points the points that define the polygon + * @return a polygon defined by the specified point list + */ + public static Polygon fromPoints(Vector3d... points)throws ColinearPointsException,NonFlatPolygonException { + return fromPoints(Arrays.asList(points), new PropertyStorage(), null, true); + } + + public static Polygon fromPointsAllowDegenerate(List vertices2) throws ColinearPointsException,NonFlatPolygonException { + return fromPoints(vertices2, new PropertyStorage(), null, true); + } + + /** + * Creates a polygon from the specified point list. + * + * @param points the points that define the polygon + * @param shared the shared + * @param plane may be null + * @return a polygon defined by the specified point list + */ + public static Polygon fromPoints(List points, PropertyStorage shared, Plane plane, + boolean allowDegenerate)throws ColinearPointsException,NonFlatPolygonException { + List vertices = new ArrayList<>(); + for (Vector3d p : points) { + Vector3d vec = p.clone(); + Vertex vertex = new Vertex(vec); + vertices.add(vertex); + } + + return new Polygon(vertices, shared, allowDegenerate, plane); + } + + /** + * Decomposes the specified concave polygon into convex polygons. + * + * @param points the points that define the polygon + * @return the decomposed concave polygon (list of convex polygons) + */ + public static List fromConcavePoints(List points)throws ColinearPointsException,NonFlatPolygonException { + Polygon p = fromPoints(points); + + return PolygonUtil.triangulatePolygon(p); + } + public static ArrayList pruneDuplicatePoints(List incoming) { // return incoming; @@ -170,6 +228,14 @@ public static ArrayList pruneDuplicatePoints(List incoming) { } } + /** + * Sets the storage. + * + * @param storage the new storage + */ + void setStorage(PropertyStorage storage) { + this.shared = storage; + } private void validateAndInit(boolean fixInversions) throws ColinearPointsException,NonFlatPolygonException { ArrayList vertices = pruneDuplicatePoints(this.vertices); Plane p = Plane.createFromPoints(vertices); @@ -217,18 +283,7 @@ public void rotatePoints() { getVertices().add(b); } - /** - * Constructor. Creates a new polygon that consists of the specified vertices. - * - * Note: the vertices used to initialize a polygon must be coplanar and form a - * convex loop. - * - * @param vertices polygon vertices - * - */ - public Polygon(Vertex... vertices) throws ColinearPointsException,NonFlatPolygonException { - this(Arrays.asList(vertices)); - } + /* * (non-Javadoc) @@ -421,60 +476,7 @@ public Polygon transformed(Transform transform) throws ColinearPointsException { return clone().transform(transform); } - /** - * Creates a polygon from the specified point list. - * - * @param points the points that define the polygon - * @param shared shared property storage - * @return a polygon defined by the specified point list - */ - public static Polygon fromPoints(List points, PropertyStorage shared) throws ColinearPointsException,NonFlatPolygonException { - return fromPoints(points, shared, null, true); - } - - /** - * Creates a polygon from the specified point list. - * - * @param points the points that define the polygon - * @return a polygon defined by the specified point list - */ - public static Polygon fromPoints(List points)throws ColinearPointsException,NonFlatPolygonException { - return fromPoints(points, new PropertyStorage(), null, true); - } - - /** - * Creates a polygon from the specified points. - * - * @param points the points that define the polygon - * @return a polygon defined by the specified point list - */ - public static Polygon fromPoints(Vector3d... points)throws ColinearPointsException,NonFlatPolygonException { - return fromPoints(Arrays.asList(points), new PropertyStorage(), null, true); - } - - public static Polygon fromPointsAllowDegenerate(List vertices2) throws ColinearPointsException,NonFlatPolygonException { - return fromPoints(vertices2, new PropertyStorage(), null, true); - } - - /** - * Creates a polygon from the specified point list. - * - * @param points the points that define the polygon - * @param shared the shared - * @param plane may be null - * @return a polygon defined by the specified point list - */ - public static Polygon fromPoints(List points, PropertyStorage shared, Plane plane, - boolean allowDegenerate)throws ColinearPointsException,NonFlatPolygonException { - List vertices = new ArrayList<>(); - for (Vector3d p : points) { - Vector3d vec = p.clone(); - Vertex vertex = new Vertex(vec); - vertices.add(vertex); - } - return new Polygon(vertices, shared, allowDegenerate, plane); - } /** * Returns the bounds of this polygon. From a7b174d65f94fec24c30bdaaf572d09aec901330 Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Sun, 22 Feb 2026 14:27:46 -0500 Subject: [PATCH 11/35] changing the polygon creation to a static method that returns a list instead of a single public constructor. this takes care of the problem where the polygon may not be flat, and therefor may need to be many polygons. --- .../java/eu/mihosoft/vrl/v3d/Polygon.java | 142 +++++++++++------- .../vrl/v3d/ext/org/poly2tri/PolygonUtil.java | 6 +- 2 files changed, 87 insertions(+), 61 deletions(-) diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java b/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java index 24216bb0..0a19f025 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java @@ -83,13 +83,13 @@ public final class Polygon implements Serializable { * @param vertices polygon vertices * @param shared shared property */ - private Polygon(List vertices, PropertyStorage shared, boolean allowDegenerate, Plane p) throws ColinearPointsException,NonFlatPolygonException { + private Polygon(List vertices, PropertyStorage shared, Plane p) throws ColinearPointsException,NonFlatPolygonException { this.setVertices(pruneDuplicatePoints(vertices)); this.shared = shared; if (p != null) setPlane(p.clone()); - validateAndInit(allowDegenerate); + validateAndInit(); } /** @@ -102,7 +102,7 @@ private Polygon(List vertices, PropertyStorage shared, boolean allowDege * @param shared shared property */ private Polygon(List vertices, PropertyStorage shared) throws ColinearPointsException,NonFlatPolygonException { - this(vertices, shared, true, null); + this(vertices, shared, null); } /** @@ -114,7 +114,7 @@ private Polygon(List vertices, PropertyStorage shared) throws ColinearPo * @param vertices polygon vertices */ private Polygon(List vertices) throws ColinearPointsException,NonFlatPolygonException { - this(vertices, new PropertyStorage(), true, null); + this(vertices, new PropertyStorage(), null); } /** * Constructor. Creates a new polygon that consists of the specified vertices. @@ -134,77 +134,105 @@ private Polygon(Vertex... vertices) throws ColinearPointsException,NonFlatPolygo * @param points the points that define the polygon * @return the decomposed concave polygon (list of convex polygons) */ - public static List fromConcavePoints(Vector3d... points) throws ColinearPointsException,NonFlatPolygonException { - Polygon p = fromPoints(points); - - return PolygonUtil.triangulatePolygon(p); - } + public static List fromConcavePoints(Vector3d... points) throws ColinearPointsException { + List vertices = new ArrayList<>(); + for (Vector3d p : points) { + Vector3d vec = p.clone(); + Vertex vertex = new Vertex(vec); + vertices.add(vertex); + } + return PolygonUtil.triangulatePolygon(vertices,new PropertyStorage(), false, null,CSG.getDefaultColor()); + } +// /** +// * Creates a polygon from the specified point list. +// * +// * @param points the points that define the polygon +// * @param shared shared property storage +// * @return a polygon defined by the specified point list +// */ +// private static Polygon fromPoints(List points, PropertyStorage shared) throws ColinearPointsException,NonFlatPolygonException { +// return fromPoints(points, shared, null, true); +// } /** * Creates a polygon from the specified point list. * * @param points the points that define the polygon * @param shared shared property storage - * @return a polygon defined by the specified point list - */ - public static Polygon fromPoints(List points, PropertyStorage shared) throws ColinearPointsException,NonFlatPolygonException { - return fromPoints(points, shared, null, true); - } - - /** - * Creates a polygon from the specified point list. - * - * @param points the points that define the polygon - * @return a polygon defined by the specified point list - */ - public static Polygon fromPoints(List points)throws ColinearPointsException,NonFlatPolygonException { - return fromPoints(points, new PropertyStorage(), null, true); - } - - /** - * Creates a polygon from the specified points. - * - * @param points the points that define the polygon - * @return a polygon defined by the specified point list + * @param fixAFlat triangulate the non flat polygons or throw the exception + * @param p the reference plane provided to the polygon for flatness checking + * @return a List defined by the specified point list */ - public static Polygon fromPoints(Vector3d... points)throws ColinearPointsException,NonFlatPolygonException { - return fromPoints(Arrays.asList(points), new PropertyStorage(), null, true); - } - - public static Polygon fromPointsAllowDegenerate(List vertices2) throws ColinearPointsException,NonFlatPolygonException { - return fromPoints(vertices2, new PropertyStorage(), null, true); + public static List get(List vertices, PropertyStorage shared, boolean fixAFlat, Plane p) throws ColinearPointsException,NonFlatPolygonException{ + List back = new ArrayList(); + try { + back.add(new Polygon(vertices, shared, p)); + }catch(NonFlatPolygonException e) { + if(fixAFlat) + return PolygonUtil.triangulatePolygon(vertices,shared, fixAFlat, p,CSG.getDefaultColor()); + else + throw e; + } + return back; } - /** - * Creates a polygon from the specified point list. + * Decomposes the specified concave polygon into convex polygons. * * @param points the points that define the polygon - * @param shared the shared - * @param plane may be null - * @return a polygon defined by the specified point list + * @return the decomposed concave polygon (list of convex polygons) */ - public static Polygon fromPoints(List points, PropertyStorage shared, Plane plane, - boolean allowDegenerate)throws ColinearPointsException,NonFlatPolygonException { + public static List fromConcavePoints(List points)throws ColinearPointsException,NonFlatPolygonException { List vertices = new ArrayList<>(); for (Vector3d p : points) { Vector3d vec = p.clone(); Vertex vertex = new Vertex(vec); vertices.add(vertex); } + return PolygonUtil.triangulatePolygon(vertices,new PropertyStorage(), false, null,CSG.getDefaultColor()); + } +// /** +// * Creates a polygon from the specified point list. +// * +// * @param points the points that define the polygon +// * @return a polygon defined by the specified point list +// */ +// private static Polygon fromPoints(List points)throws ColinearPointsException,NonFlatPolygonException { +// return fromPoints(points, new PropertyStorage(), null, true); +// } - return new Polygon(vertices, shared, allowDegenerate, plane); - } +// /** +// * Creates a polygon from the specified points. +// * +// * @param points the points that define the polygon +// * @return a polygon defined by the specified point list +// */ +// private static Polygon fromPoints(Vector3d... points)throws ColinearPointsException,NonFlatPolygonException { +// return fromPoints(Arrays.asList(points), new PropertyStorage(), null, true); +// } +// +// private static Polygon fromPointsAllowDegenerate(List vertices2) throws ColinearPointsException,NonFlatPolygonException { +// return fromPoints(vertices2, new PropertyStorage(), null, true); +// } +// /** +// * Creates a polygon from the specified point list. +// * +// * @param points the points that define the polygon +// * @param shared the shared +// * @param plane may be null +// * @return a polygon defined by the specified point list +// */ +// private static Polygon fromPoints(List points, PropertyStorage shared, Plane plane, +// boolean allowDegenerate)throws ColinearPointsException,NonFlatPolygonException { +// List vertices = new ArrayList<>(); +// for (Vector3d p : points) { +// Vector3d vec = p.clone(); +// Vertex vertex = new Vertex(vec); +// vertices.add(vertex); +// } +// +// return new Polygon(vertices, shared, plane); +// } - /** - * Decomposes the specified concave polygon into convex polygons. - * - * @param points the points that define the polygon - * @return the decomposed concave polygon (list of convex polygons) - */ - public static List fromConcavePoints(List points)throws ColinearPointsException,NonFlatPolygonException { - Polygon p = fromPoints(points); - return PolygonUtil.triangulatePolygon(p); - } public static ArrayList pruneDuplicatePoints(List incoming) { @@ -236,7 +264,7 @@ public static ArrayList pruneDuplicatePoints(List incoming) { void setStorage(PropertyStorage storage) { this.shared = storage; } - private void validateAndInit(boolean fixInversions) throws ColinearPointsException,NonFlatPolygonException { + private void validateAndInit() throws ColinearPointsException,NonFlatPolygonException { ArrayList vertices = pruneDuplicatePoints(this.vertices); Plane p = Plane.createFromPoints(vertices); if (getPlane() == null) { @@ -299,7 +327,7 @@ public Polygon clone() { // TODO figure out why this isnt working try { //return new Polygon(newVertices, getStorage(), true, plane.clone()).setColor(getColor()); - return new Polygon(newVertices, getStorage(),false,null).setColor(getColor()); + return new Polygon(newVertices, getStorage(),null).setColor(getColor()); }catch(Exception ex) { throw new RuntimeException(ex); } diff --git a/src/main/java/eu/mihosoft/vrl/v3d/ext/org/poly2tri/PolygonUtil.java b/src/main/java/eu/mihosoft/vrl/v3d/ext/org/poly2tri/PolygonUtil.java index 8309250a..b05a3888 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/ext/org/poly2tri/PolygonUtil.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/ext/org/poly2tri/PolygonUtil.java @@ -635,12 +635,10 @@ public static ArrayList triangulatePolygon(List vertices, Prope if (vertices.size() == 3) { try { - result.add(new Polygon(vertices, shared, allowDegenerate, p)); + result.addAll(Polygon.get(vertices, shared, false, p)); } catch (ColinearPointsException e) { e.printStackTrace(); - } catch (NonFlatPolygonException e) { - e.printStackTrace(); - } + } } else try { makeTriangles(vertices, shared, allowDegenerate, p, cw, result, zplane, normalOfPlane, debug, From e1b94e74869cd2bda77127fd0867caadd5729fcb Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Sun, 22 Feb 2026 14:34:40 -0500 Subject: [PATCH 12/35] restrict the public api to list forms only --- src/main/java/eu/mihosoft/vrl/v3d/Polygon.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java b/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java index 0a19f025..c97888a0 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java @@ -189,6 +189,7 @@ public static List fromConcavePoints(List points)throws Colin } return PolygonUtil.triangulatePolygon(vertices,new PropertyStorage(), false, null,CSG.getDefaultColor()); } + // /** // * Creates a polygon from the specified point list. // * From 716e4579b726112cfb63fb34728056038f02e160 Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Sun, 22 Feb 2026 14:48:01 -0500 Subject: [PATCH 13/35] add the ability to set the color in the API --- src/main/java/eu/mihosoft/vrl/v3d/Polygon.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java b/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java index c97888a0..4103e3ba 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java @@ -162,18 +162,21 @@ public static List fromConcavePoints(Vector3d... points) throws Colinea * @param p the reference plane provided to the polygon for flatness checking * @return a List defined by the specified point list */ - public static List get(List vertices, PropertyStorage shared, boolean fixAFlat, Plane p) throws ColinearPointsException,NonFlatPolygonException{ + public static List get(List vertices, PropertyStorage shared, boolean fixAFlat, Plane p, Color c) throws ColinearPointsException,NonFlatPolygonException{ List back = new ArrayList(); try { - back.add(new Polygon(vertices, shared, p)); + back.add(new Polygon(vertices, shared, p).setColor(c)); }catch(NonFlatPolygonException e) { if(fixAFlat) - return PolygonUtil.triangulatePolygon(vertices,shared, fixAFlat, p,CSG.getDefaultColor()); + return PolygonUtil.triangulatePolygon(vertices,shared, fixAFlat, p,c); else throw e; } return back; } + public static List get(List vertices, PropertyStorage shared, boolean fixAFlat, Plane p) throws ColinearPointsException,NonFlatPolygonException{ + return get(vertices, shared, fixAFlat, p,CSG.getDefaultColor()); + } /** * Decomposes the specified concave polygon into convex polygons. * From 33b59731699e1bf72b32d4ce4e22ace330232d89 Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Sun, 22 Feb 2026 14:48:24 -0500 Subject: [PATCH 14/35] use the list of polygons --- src/main/java/eu/mihosoft/vrl/v3d/Node.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Node.java b/src/main/java/eu/mihosoft/vrl/v3d/Node.java index 085a9ae8..e0aa5ddd 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Node.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Node.java @@ -321,12 +321,13 @@ private static void add(List l, List f, Polygon polygon) { if(polygon.getPlane().checkNormal(f) == NormalState.FLIPPED) { Collections.reverse(f); } - Polygon fpoly = new Polygon(f, polygon.getStorage(), true, polygon.getPlane()) - .setColor(polygon.getColor()); - l.add(fpoly); + List fpoly = Polygon.get(f, polygon.getStorage(), true, polygon.getPlane(),polygon.getColor()); + l.addAll(fpoly); }catch(ColinearPointsException ex) { //ex.printStackTrace(); System.err.println("Pruned Collinear polygon "+f+" "+ex.getMessage() ); + } catch (NonFlatPolygonException e) { + e.printStackTrace(); } } public static String getOsName() { From 7814aa0cd93e6016b39c2133318c9945b0a8832e Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Sun, 22 Feb 2026 14:48:38 -0500 Subject: [PATCH 15/35] use the list of polygons --- .../vrl/v3d/ext/org/poly2tri/PolygonUtil.java | 57 ++++++++++--------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/src/main/java/eu/mihosoft/vrl/v3d/ext/org/poly2tri/PolygonUtil.java b/src/main/java/eu/mihosoft/vrl/v3d/ext/org/poly2tri/PolygonUtil.java index b05a3888..0ba79663 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/ext/org/poly2tri/PolygonUtil.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/ext/org/poly2tri/PolygonUtil.java @@ -184,13 +184,11 @@ public class PolygonUtil { modifiable.remove(vr); if (modifiable.size() > 2) { try { - Polygon polygon = new Polygon(modifiable, shared, allowDegenerate, p); - polygon.setColor(color); - return Arrays.asList(polygon); + return Polygon.get(modifiable, shared, true, p, color); } catch (ColinearPointsException e) { System.out.println(" Pruning polygon in repair " + vertices + " to " + modifiable); } catch (NonFlatPolygonException e) { - return triangulatePolygon(modifiable, shared, allowDegenerate, p, color); + e.printStackTrace(); } } throw new ColinearPointsException("Fix failed!"); @@ -638,7 +636,10 @@ public static ArrayList triangulatePolygon(List vertices, Prope result.addAll(Polygon.get(vertices, shared, false, p)); } catch (ColinearPointsException e) { e.printStackTrace(); - } + } catch (NonFlatPolygonException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } else try { makeTriangles(vertices, shared, allowDegenerate, p, cw, result, zplane, normalOfPlane, debug, @@ -652,8 +653,8 @@ public static ArrayList triangulatePolygon(List vertices, Prope result.add(repaired); } else { try { - makeTriangles(repaired.getVertices(),repaired.getStorage(),false,repaired.getPlane(), cw, result, zplane, normalOfPlane, debug, orientationInv, reorient, - c); + makeTriangles(repaired.getVertices(), repaired.getStorage(), false, repaired.getPlane(), cw, + result, zplane, normalOfPlane, debug, orientationInv, reorient, c); } catch (Exception e) { makeTrianglesInternal(repaired, cw, result, zplane, normalOfPlane, debug, orientationInv, reorient, c); @@ -729,12 +730,15 @@ private static void makeTrianglesInternal(Polygon concave, boolean cw, List onel = Polygon.get(vertices, concave.getStorage(), true, normal2.clone()); + for (Polygon one : onel) { + if (reorent) { + one = one.transform(orentationInv); + } + + one.setColor(color); + result.add(one); } - one.setColor(color); - result.add(one); } catch (ColinearPointsException ex) { System.out.println(ex.getMessage() + " Triangulation Pruned point " + p2); } catch (NonFlatPolygonException e) { @@ -810,25 +814,26 @@ private static void makeTriangles(List vertices, PropertyStorage shared, if (!Extrude.isCCW(triPoints)) { Collections.reverse(triPoints); } - Polygon poly; - poly = new Polygon(triPoints, shared, true, p1); + List polyl; + polyl = Polygon.get(triPoints, shared, true, p1); // poly = Extrude.toCCW(poly); // poly.getPlane().setNormal(concave.getPlane().getNormal()); + for (Polygon poly : polyl) { + if (debug) { + // Debug3dProvider.clearScreen(); + // Debug3dProvider.addObject(concave); + Debug3dProvider.addObject(poly); + } - if (debug) { - // Debug3dProvider.clearScreen(); - // Debug3dProvider.addObject(concave); - Debug3dProvider.addObject(poly); - } - - if (reorent) { - poly = poly.transform(orentationInv); + if (reorent) { + poly = poly.transform(orentationInv); - // poly = checkForValidPolyOrentation(normal, poly); + // poly = checkForValidPolyOrentation(normal, poly); + } + // poly.plane.setNormal(normalOfPlane); + poly.setColor(color); + result.add(poly); } - // poly.plane.setNormal(normalOfPlane); - poly.setColor(color); - result.add(poly); } catch (ColinearPointsException ex) { System.out.println(ex.getMessage() + " Pruned new triangle as colinear " + triPoints); } catch (NonFlatPolygonException e1) { From b7ad94ae723451adc833529c7adae5a63ed85ce8 Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Sun, 22 Feb 2026 14:52:03 -0500 Subject: [PATCH 16/35] use list api --- .../java/eu/mihosoft/vrl/v3d/SvgExportTest.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/test/java/eu/mihosoft/vrl/v3d/SvgExportTest.java b/src/test/java/eu/mihosoft/vrl/v3d/SvgExportTest.java index 17ee8170..cd4ef722 100644 --- a/src/test/java/eu/mihosoft/vrl/v3d/SvgExportTest.java +++ b/src/test/java/eu/mihosoft/vrl/v3d/SvgExportTest.java @@ -61,10 +61,10 @@ public void test() throws IOException, ColinearPointsException, NonFlatPolygonEx vertices2.add(new Vertex(new Vector3d(75, 75))); vertices2.add(new Vertex(new Vector3d(50, 75))); - Polygon outline2 = new Polygon(vertices2); - Polygon outline = new Polygon(vertices); - polygons.add(outline2); - polygons.add(outline); + List outline2 = Polygon.fromVertex(vertices2); + List outline = Polygon.fromVertex(vertices); + polygons.addAll(outline2); + polygons.addAll(outline); SVGExporter.export(polygons, new File("SVGExportTest2.svg"), false); @@ -87,10 +87,10 @@ public void testSlices() throws IOException, ColinearPointsException, NonFlatPol vertices2.add(new Vertex(new Vector3d(75, 75))); vertices2.add(new Vertex(new Vector3d(50, 75))); - Polygon outline2 = new Polygon(vertices2); - Polygon outline = new Polygon(vertices); - polygons.add(outline2); - polygons.add(outline); + List outline2 = Polygon.fromVertex(vertices2); + List outline = Polygon.fromVertex(vertices); + polygons.addAll(outline2); + polygons.addAll(outline); SVGExporter.export(polygons, new File("SVGExportTest3.svg"), false); From 1d35834c8bc657965dc6bacf60d4d7182857a521 Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Sun, 22 Feb 2026 14:52:19 -0500 Subject: [PATCH 17/35] add a from verticies method --- src/main/java/eu/mihosoft/vrl/v3d/Polygon.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java b/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java index 4103e3ba..12e8f637 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java @@ -143,6 +143,10 @@ public static List fromConcavePoints(Vector3d... points) throws Colinea } return PolygonUtil.triangulatePolygon(vertices,new PropertyStorage(), false, null,CSG.getDefaultColor()); } + public static List fromVertex(List vertices2) throws ColinearPointsException { + // TODO Auto-generated method stub + return PolygonUtil.triangulatePolygon(vertices2,new PropertyStorage(), false, null,CSG.getDefaultColor()); + } // /** // * Creates a polygon from the specified point list. // * @@ -904,4 +908,6 @@ public void setVertices(ArrayList vertices) throws ColinearPointsExcepti plane = Plane.createFromPoints(vertices); this.vertices = vertices; } + + } From ae43186850ea467cceb8424d9c2983ac065e54c3 Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Sun, 22 Feb 2026 14:54:49 -0500 Subject: [PATCH 18/35] use the list API --- src/main/java/eu/mihosoft/vrl/v3d/CSG.java | 9 ++++++--- .../vrl/v3d/PolygonClassificationTest.java | 14 +++++++------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/main/java/eu/mihosoft/vrl/v3d/CSG.java b/src/main/java/eu/mihosoft/vrl/v3d/CSG.java index fc5cdf70..81ae0fe3 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/CSG.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/CSG.java @@ -2126,13 +2126,16 @@ public void run() { System.out.println("ERR polygon " + i + " pruned because of too few points"); continue; } - Polygon p; + List p; try { - p = new Polygon(points, polygon.getStorage(), true, pl); - newPoly.add(p); + p = Polygon.get(points, polygon.getStorage(), true, pl); + newPoly.addAll(p); } catch (ColinearPointsException e) { System.err.println("Pruning " + points); e.printStackTrace(); + } catch (NonFlatPolygonException e) { + // TODO Auto-generated catch block + e.printStackTrace(); } polygon.getPoints().clear(); } diff --git a/src/test/java/eu/mihosoft/vrl/v3d/PolygonClassificationTest.java b/src/test/java/eu/mihosoft/vrl/v3d/PolygonClassificationTest.java index fadc5e92..f131e277 100644 --- a/src/test/java/eu/mihosoft/vrl/v3d/PolygonClassificationTest.java +++ b/src/test/java/eu/mihosoft/vrl/v3d/PolygonClassificationTest.java @@ -33,7 +33,7 @@ public void testPolygon1_ValidThinTriangle() { ); try { - Polygon polygon = new Polygon(vertices, storage, true, null); + Polygon polygon = Polygon.get(vertices, storage, true, null).get(0); assertNotNull("Polygon should be created successfully", polygon); assertEquals("Polygon should have 3 vertices", 3, polygon.getVertices().size()); } catch (Exception e) { @@ -58,7 +58,7 @@ public void testPolygon3_ValidWithSmallYSpan() { ); try { - Polygon polygon = new Polygon(vertices, storage, true, null); + Polygon polygon = Polygon.get(vertices, storage, true, null).get(0); assertNotNull("Polygon should be created successfully", polygon); assertEquals("Polygon should have 3 vertices", 3, polygon.getVertices().size()); } catch (Exception e) { @@ -81,7 +81,7 @@ public void testPolygon4_ValidWithXSpan() { ); try { - Polygon polygon = new Polygon(vertices, storage, true, null); + Polygon polygon = Polygon.get(vertices, storage, true, null).get(0); assertNotNull("Polygon should be created successfully", polygon); assertEquals("Polygon should have 3 vertices", 3, polygon.getVertices().size()); } catch (Exception e) { @@ -104,7 +104,7 @@ public void testPolygon5_ValidWithYAndZVariation() { ); try { - Polygon polygon = new Polygon(vertices, storage, true, null); + Polygon polygon = Polygon.get(vertices, storage, true, null).get(0); assertNotNull("Polygon should be created successfully", polygon); assertEquals("Polygon should have 3 vertices", 3, polygon.getVertices().size()); } catch (Exception e) { @@ -126,7 +126,7 @@ public void testPolygon6_ValidWithLargeYZDifferences() { ); try { - Polygon polygon = new Polygon(vertices, storage, true, null); + Polygon polygon = Polygon.get(vertices, storage, true, null).get(0); assertNotNull("Polygon should be created successfully", polygon); assertEquals("Polygon should have 3 vertices", 3, polygon.getVertices().size()); } catch (Exception e) { @@ -151,7 +151,7 @@ public void testDegeneratePolygon_DuplicatePoints() throws ColinearPointsExcepti new Vertex(new Vector3d(10.5175167546, 116.6176943528, 83.1832321598)) ); - Polygon polygon = new Polygon(vertices, storage, true, null); + Polygon polygon = Polygon.get(vertices, storage, true, null).get(0); fail("Should have thrown exception for duplicate points"); } @@ -170,7 +170,7 @@ public void testDegeneratePolygon_Collinear() throws ColinearPointsException, No new Vertex(new Vector3d(10.5068817145, 98.4507751465, 35.0306403108)) ); - Polygon polygon = new Polygon(vertices, storage, true, null); + Polygon polygon = Polygon.get(vertices, storage, true, null).get(0); fail("Should have thrown exception for collinear points"); } From 983baa7ed05cf93721f2569e3794dff1aa3e507c Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Sun, 22 Feb 2026 14:56:54 -0500 Subject: [PATCH 19/35] list api --- .../mihosoft/vrl/v3d/HoleDetectionTest.java | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/test/java/eu/mihosoft/vrl/v3d/HoleDetectionTest.java b/src/test/java/eu/mihosoft/vrl/v3d/HoleDetectionTest.java index b630ecb5..02929f5c 100644 --- a/src/test/java/eu/mihosoft/vrl/v3d/HoleDetectionTest.java +++ b/src/test/java/eu/mihosoft/vrl/v3d/HoleDetectionTest.java @@ -28,7 +28,7 @@ public class HoleDetectionTest { public void holeDetectionTest() throws ColinearPointsException, NonFlatPolygonException { // one polygon with one hole - Polygon p1 = Polygon.fromPoints( + Polygon p1 = Polygon.fromConcavePoints( new Vector3d(1, 1), new Vector3d(2, 3), new Vector3d(4, 3), @@ -36,17 +36,17 @@ public void holeDetectionTest() throws ColinearPointsException, NonFlatPolygonEx new Vector3d(4, 1), new Vector3d(3, 0), new Vector3d(2, 2) - ); - Polygon p1Hole = Polygon.fromPoints( + ).get(0); + Polygon p1Hole = Polygon.fromConcavePoints( new Vector3d(3, 1), new Vector3d(3, 2), new Vector3d(4, 2) - ); + ).get(0); createNumHolesTest(Arrays.asList(p1, p1Hole), 1, 0); // one polygon with two holes - Polygon p2 = Polygon.fromPoints( + Polygon p2 = Polygon.fromConcavePoints( new Vector3d(1, 1), new Vector3d(2, 2), new Vector3d(1, 5), @@ -56,24 +56,24 @@ public void holeDetectionTest() throws ColinearPointsException, NonFlatPolygonEx new Vector3d(6, 5), new Vector3d(6, 1), new Vector3d(3, 0) - ); - Polygon p2Hole1 = Polygon.fromPoints( + ).get(0); + Polygon p2Hole1 = Polygon.fromConcavePoints( new Vector3d(3, 2), new Vector3d(3, 3), new Vector3d(4, 2), new Vector3d(4, 1) - ); - Polygon p2Hole2 = Polygon.fromPoints( + ).get(0); + Polygon p2Hole2 = Polygon.fromConcavePoints( new Vector3d(2, 3), new Vector3d(2, 4), new Vector3d(3, 4) - ); + ).get(0); createNumHolesTest(Arrays.asList(p2, p2Hole1, p2Hole2), 2, 0, 0); // one polygon with two holes, one of the holes contains another // polygon with one hole - Polygon p3 = Polygon.fromPoints( + Polygon p3 = Polygon.fromConcavePoints( new Vector3d(1, 1), new Vector3d(2, 2), new Vector3d(1, 5), @@ -83,35 +83,35 @@ public void holeDetectionTest() throws ColinearPointsException, NonFlatPolygonEx new Vector3d(6, 5), new Vector3d(6, 1), new Vector3d(3, 0) - ); - Polygon p3Hole1 = Polygon.fromPoints( + ).get(0); + Polygon p3Hole1 = Polygon.fromConcavePoints( new Vector3d(3, 2), new Vector3d(3, 3), new Vector3d(4, 4), new Vector3d(5, 3), new Vector3d(5, 2), new Vector3d(4, 1) - ); + ).get(0); - Polygon p3p1 = Polygon.fromPoints( + Polygon p3p1 = Polygon.fromConcavePoints( new Vector3d(4, 2), new Vector3d(3.5, 2.5), new Vector3d(4, 3), new Vector3d(4.5, 2.5) - ); + ).get(0); - Polygon p3p1Hole = Polygon.fromPoints( + Polygon p3p1Hole = Polygon.fromConcavePoints( new Vector3d(4, 2.25), new Vector3d(3.75, 2.5), new Vector3d(4, 2.75), new Vector3d(4.25, 2.5) - ); + ).get(0); - Polygon p3Hole2 = Polygon.fromPoints( + Polygon p3Hole2 = Polygon.fromConcavePoints( new Vector3d(2, 3), new Vector3d(2, 4), new Vector3d(3, 4) - ); + ).get(0); createNumHolesTest( Arrays.asList(p3, p3Hole1, p3Hole2, p3p1, p3p1Hole), From c6526114d18af06fbddaa50e64277e91e6723d98 Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Sun, 22 Feb 2026 14:59:16 -0500 Subject: [PATCH 20/35] use list api --- .../java/eu/mihosoft/vrl/v3d/svg/SVGLoad.java | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/main/java/eu/mihosoft/vrl/v3d/svg/SVGLoad.java b/src/main/java/eu/mihosoft/vrl/v3d/svg/SVGLoad.java index b0b6b228..f3da105f 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/svg/SVGLoad.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/svg/SVGLoad.java @@ -40,6 +40,7 @@ import eu.mihosoft.vrl.v3d.ColinearPointsException; import eu.mihosoft.vrl.v3d.Edge; import eu.mihosoft.vrl.v3d.Extrude; +import eu.mihosoft.vrl.v3d.NonFlatPolygonException; import eu.mihosoft.vrl.v3d.Plane; import eu.mihosoft.vrl.v3d.Polygon; import eu.mihosoft.vrl.v3d.PropertyStorage; @@ -178,7 +179,7 @@ public String toCode() { for (int i = 0; i < pathObjects; i++) { SVGItem item = (SVGItem) pathList.getItem(i); - String itemLine = String.format(Locale.US,"%s%n", item.getValueAsString()); + String itemLine = String.format(Locale.US, "%s%n", item.getValueAsString()); sb += itemLine; } @@ -546,7 +547,7 @@ private void loadPath(Node pathNode, Transform startingFrame, String encapsulati for (int i = 0; i < pathObjects; i++) { SVGItem item = (SVGItem) pathList.getItem(i); - String itemLine = String.format(Locale.US,"%s%n", item.getValueAsString()); + String itemLine = String.format(Locale.US, "%s%n", item.getValueAsString()); if (sb == null) { sb = "M " + itemLine; } @@ -663,14 +664,23 @@ private void loadSingle(String code, Transform startingFrame, String encapsulati List list = getPolygonByLayers().get(encapsulatingLayer); // Polygon poly = Polygon.fromPoints(p , new PropertyStorage(), new Plane(new // Vector3d(0, 0, 1),p.get(0)) , true); - Polygon poly = Polygon.fromPoints(p); - PolygonUtil.triangulatePolygon(poly); - poly.setHole(hole); - if (c != null) { - colors.put(poly, c); - poly.setColor(c); + List polys; + try { + polys = Polygon.fromConcavePoints(p); + for (Polygon poly : polys) { + PolygonUtil.triangulatePolygon(poly); + poly.setHole(hole); + if (c != null) { + colors.put(poly, c); + poly.setColor(c); + } + list.add(poly); + } + } catch (NonFlatPolygonException e) { + // TODO Auto-generated catch block + e.printStackTrace(); } - list.add(poly); + } catch (ColinearPointsException e) { // TODO Auto-generated catch block e.printStackTrace(); From 563ad2478dd0960ac2d5a5a8d55e8199e5bff225 Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Sun, 22 Feb 2026 15:01:08 -0500 Subject: [PATCH 21/35] add a shared storeage api --- src/main/java/eu/mihosoft/vrl/v3d/Polygon.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java b/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java index 12e8f637..0cb1585e 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java @@ -196,7 +196,21 @@ public static List fromConcavePoints(List points)throws Colin } return PolygonUtil.triangulatePolygon(vertices,new PropertyStorage(), false, null,CSG.getDefaultColor()); } - + /** + * Decomposes the specified concave polygon into convex polygons. + * + * @param points the points that define the polygon + * @return the decomposed concave polygon (list of convex polygons) + */ + public static List fromConcavePoints(List points,PropertyStorage shared )throws ColinearPointsException,NonFlatPolygonException { + List vertices = new ArrayList<>(); + for (Vector3d p : points) { + Vector3d vec = p.clone(); + Vertex vertex = new Vertex(vec); + vertices.add(vertex); + } + return PolygonUtil.triangulatePolygon(vertices,shared, false, null,CSG.getDefaultColor()); + } // /** // * Creates a polygon from the specified point list. // * From 4f6d46aeab67920756ba34f3a5532a86a2f6a4cf Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Sun, 22 Feb 2026 15:01:19 -0500 Subject: [PATCH 22/35] use list api --- .../java/eu/mihosoft/vrl/v3d/ext/quickhull3d/HullUtil.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/eu/mihosoft/vrl/v3d/ext/quickhull3d/HullUtil.java b/src/main/java/eu/mihosoft/vrl/v3d/ext/quickhull3d/HullUtil.java index 5d886cf6..402fd68d 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/ext/quickhull3d/HullUtil.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/ext/quickhull3d/HullUtil.java @@ -8,6 +8,7 @@ import eu.mihosoft.vrl.v3d.CSG; import eu.mihosoft.vrl.v3d.CSGClient; import eu.mihosoft.vrl.v3d.ColinearPointsException; +import eu.mihosoft.vrl.v3d.NonFlatPolygonException; import eu.mihosoft.vrl.v3d.Vector3d; import eu.mihosoft.vrl.v3d.Polygon; import eu.mihosoft.vrl.v3d.PropertyStorage; @@ -90,10 +91,13 @@ public static CSG hull(List points, PropertyStorage storage) { } try { - polygons.add(Polygon.fromPoints(vertices, storage)); + polygons.addAll(Polygon.fromConcavePoints(vertices, storage)); } catch (ColinearPointsException e) { // TODO Auto-generated catch block e.printStackTrace(); + } catch (NonFlatPolygonException e) { + // TODO Auto-generated catch block + e.printStackTrace(); } vertices.clear(); From fef407b6d57b964120193cfa3c5a49bae1c683b6 Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Sun, 22 Feb 2026 15:02:42 -0500 Subject: [PATCH 23/35] use list api --- .../eu/mihosoft/vrl/v3d/ext/imagej/STLLoader.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/eu/mihosoft/vrl/v3d/ext/imagej/STLLoader.java b/src/main/java/eu/mihosoft/vrl/v3d/ext/imagej/STLLoader.java index fb03a7b4..18edf45f 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/ext/imagej/STLLoader.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/ext/imagej/STLLoader.java @@ -20,6 +20,7 @@ import java.util.List; import eu.mihosoft.vrl.v3d.ColinearPointsException; +import eu.mihosoft.vrl.v3d.NonFlatPolygonException; import eu.mihosoft.vrl.v3d.Plane; import eu.mihosoft.vrl.v3d.Polygon; import eu.mihosoft.vrl.v3d.Vector3d; @@ -122,9 +123,12 @@ private void parseAscii(File f,ArrayList polygons) { }catch(NumberFormatException ex) { pl=Plane.createFromPoints(vertices); } - polygons.add(new Polygon(vertices, null, true, pl)); + polygons.addAll( Polygon.get(vertices, null, true, pl)); } catch (ColinearPointsException e) { System.out.println(e.getMessage()+ " STL Load Pruned "+vertices); + } catch (NonFlatPolygonException e) { + // TODO Auto-generated catch block + e.printStackTrace(); } vertices.clear(); } @@ -181,9 +185,12 @@ private void parseBinary(File f, ArrayList polygons,int triangles) { System.out.println(" STL has bad Normal "+normal); pl=Plane.createFromPoints(vertices); } - polygons.add(new Polygon(vertices, null, true, pl)); + polygons.addAll( Polygon.get(vertices, null, true, pl)); } catch (ColinearPointsException e) { System.out.println(e.getMessage()+ " STL Load Pruned "+vertices); + } catch (NonFlatPolygonException e) { + // TODO Auto-generated catch block + e.printStackTrace(); } vertices.clear(); } From e03c488e897e9d32f01a68459d57efcfec330671 Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Sun, 22 Feb 2026 15:21:03 -0500 Subject: [PATCH 24/35] list api --- src/main/java/eu/mihosoft/vrl/v3d/Toroid.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Toroid.java b/src/main/java/eu/mihosoft/vrl/v3d/Toroid.java index 0224ade6..a51ef8e1 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Toroid.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Toroid.java @@ -74,9 +74,11 @@ public Toroid(double innerRadius, double OuterRadius, int numSlices, int facets) } Polygon poly; try { - poly = new Polygon(vertices, properties); + poly = Polygon.get(vertices, properties,true,null).get(0); } catch (ColinearPointsException e) { throw new RuntimeException(e); + } catch (NonFlatPolygonException e) { + throw new RuntimeException(e); } ArrayList slices = new ArrayList(); @@ -114,10 +116,13 @@ public Toroid(double innerRadius, double OuterRadius, int numSlices, int facets) List pPoints = Arrays.asList(bottomV2, topV2, topV1, bottomV1); try { - newPolygons.add(Polygon.fromPoints(pPoints, polygon1.getStorage())); + newPolygons.addAll(Polygon.fromConcavePoints(pPoints, polygon1.getStorage())); } catch (ColinearPointsException e) { // TODO Auto-generated catch block e.printStackTrace(); + } catch (NonFlatPolygonException e) { + // TODO Auto-generated catch block + e.printStackTrace(); } } From f85d77ef4747a77054011fb69566873a3922e356 Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Sun, 22 Feb 2026 15:22:54 -0500 Subject: [PATCH 25/35] api change --- src/main/java/eu/mihosoft/vrl/v3d/Polygon.java | 2 +- src/main/java/eu/mihosoft/vrl/v3d/Sphere.java | 2 +- src/main/java/eu/mihosoft/vrl/v3d/Toroid.java | 2 +- src/main/java/eu/mihosoft/vrl/v3d/ext/quickhull3d/HullUtil.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java b/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java index 0cb1585e..beac6b66 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java @@ -202,7 +202,7 @@ public static List fromConcavePoints(List points)throws Colin * @param points the points that define the polygon * @return the decomposed concave polygon (list of convex polygons) */ - public static List fromConcavePoints(List points,PropertyStorage shared )throws ColinearPointsException,NonFlatPolygonException { + public static List fromVector3d(List points,PropertyStorage shared )throws ColinearPointsException,NonFlatPolygonException { List vertices = new ArrayList<>(); for (Vector3d p : points) { Vector3d vec = p.clone(); diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Sphere.java b/src/main/java/eu/mihosoft/vrl/v3d/Sphere.java index 5d87646c..4e44f036 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Sphere.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Sphere.java @@ -194,7 +194,7 @@ public List toPolygons() { (j + 1) / (double) getNumStacks()) ); try { - polygons.add(new Polygon(vertices, getProperties())); + polygons.add(Polygon.fromVector3d(vertices, getProperties())); } catch (ColinearPointsException e) { // TODO Auto-generated catch block e.printStackTrace(); diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Toroid.java b/src/main/java/eu/mihosoft/vrl/v3d/Toroid.java index a51ef8e1..1fb8d311 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Toroid.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Toroid.java @@ -116,7 +116,7 @@ public Toroid(double innerRadius, double OuterRadius, int numSlices, int facets) List pPoints = Arrays.asList(bottomV2, topV2, topV1, bottomV1); try { - newPolygons.addAll(Polygon.fromConcavePoints(pPoints, polygon1.getStorage())); + newPolygons.addAll(Polygon.fromVector3d(pPoints, polygon1.getStorage())); } catch (ColinearPointsException e) { // TODO Auto-generated catch block e.printStackTrace(); diff --git a/src/main/java/eu/mihosoft/vrl/v3d/ext/quickhull3d/HullUtil.java b/src/main/java/eu/mihosoft/vrl/v3d/ext/quickhull3d/HullUtil.java index 402fd68d..85284436 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/ext/quickhull3d/HullUtil.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/ext/quickhull3d/HullUtil.java @@ -91,7 +91,7 @@ public static CSG hull(List points, PropertyStorage storage) { } try { - polygons.addAll(Polygon.fromConcavePoints(vertices, storage)); + polygons.addAll(Polygon.fromVector3d(vertices, storage)); } catch (ColinearPointsException e) { // TODO Auto-generated catch block e.printStackTrace(); From 16a296ba88c6f5c9293d402deb5b87eb0617a2f4 Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Sun, 22 Feb 2026 15:24:00 -0500 Subject: [PATCH 26/35] api change --- .../java/eu/mihosoft/vrl/v3d/Polygon.java | 4 ++-- .../java/eu/mihosoft/vrl/v3d/svg/SVGLoad.java | 2 +- .../mihosoft/vrl/v3d/HoleDetectionTest.java | 20 +++++++++---------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java b/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java index beac6b66..d40b8fdc 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java @@ -134,7 +134,7 @@ private Polygon(Vertex... vertices) throws ColinearPointsException,NonFlatPolygo * @param points the points that define the polygon * @return the decomposed concave polygon (list of convex polygons) */ - public static List fromConcavePoints(Vector3d... points) throws ColinearPointsException { + public static List fromVector3d(Vector3d... points) throws ColinearPointsException { List vertices = new ArrayList<>(); for (Vector3d p : points) { Vector3d vec = p.clone(); @@ -187,7 +187,7 @@ public static List get(List vertices, PropertyStorage shared, b * @param points the points that define the polygon * @return the decomposed concave polygon (list of convex polygons) */ - public static List fromConcavePoints(List points)throws ColinearPointsException,NonFlatPolygonException { + public static List fromVector3d(List points)throws ColinearPointsException,NonFlatPolygonException { List vertices = new ArrayList<>(); for (Vector3d p : points) { Vector3d vec = p.clone(); diff --git a/src/main/java/eu/mihosoft/vrl/v3d/svg/SVGLoad.java b/src/main/java/eu/mihosoft/vrl/v3d/svg/SVGLoad.java index f3da105f..9b87080e 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/svg/SVGLoad.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/svg/SVGLoad.java @@ -666,7 +666,7 @@ private void loadSingle(String code, Transform startingFrame, String encapsulati // Vector3d(0, 0, 1),p.get(0)) , true); List polys; try { - polys = Polygon.fromConcavePoints(p); + polys = Polygon.fromVector3d(p); for (Polygon poly : polys) { PolygonUtil.triangulatePolygon(poly); poly.setHole(hole); diff --git a/src/test/java/eu/mihosoft/vrl/v3d/HoleDetectionTest.java b/src/test/java/eu/mihosoft/vrl/v3d/HoleDetectionTest.java index 02929f5c..5f77c75c 100644 --- a/src/test/java/eu/mihosoft/vrl/v3d/HoleDetectionTest.java +++ b/src/test/java/eu/mihosoft/vrl/v3d/HoleDetectionTest.java @@ -28,7 +28,7 @@ public class HoleDetectionTest { public void holeDetectionTest() throws ColinearPointsException, NonFlatPolygonException { // one polygon with one hole - Polygon p1 = Polygon.fromConcavePoints( + Polygon p1 = Polygon.fromVector3d( new Vector3d(1, 1), new Vector3d(2, 3), new Vector3d(4, 3), @@ -37,7 +37,7 @@ public void holeDetectionTest() throws ColinearPointsException, NonFlatPolygonEx new Vector3d(3, 0), new Vector3d(2, 2) ).get(0); - Polygon p1Hole = Polygon.fromConcavePoints( + Polygon p1Hole = Polygon.fromVector3d( new Vector3d(3, 1), new Vector3d(3, 2), new Vector3d(4, 2) @@ -46,7 +46,7 @@ public void holeDetectionTest() throws ColinearPointsException, NonFlatPolygonEx createNumHolesTest(Arrays.asList(p1, p1Hole), 1, 0); // one polygon with two holes - Polygon p2 = Polygon.fromConcavePoints( + Polygon p2 = Polygon.fromVector3d( new Vector3d(1, 1), new Vector3d(2, 2), new Vector3d(1, 5), @@ -57,13 +57,13 @@ public void holeDetectionTest() throws ColinearPointsException, NonFlatPolygonEx new Vector3d(6, 1), new Vector3d(3, 0) ).get(0); - Polygon p2Hole1 = Polygon.fromConcavePoints( + Polygon p2Hole1 = Polygon.fromVector3d( new Vector3d(3, 2), new Vector3d(3, 3), new Vector3d(4, 2), new Vector3d(4, 1) ).get(0); - Polygon p2Hole2 = Polygon.fromConcavePoints( + Polygon p2Hole2 = Polygon.fromVector3d( new Vector3d(2, 3), new Vector3d(2, 4), new Vector3d(3, 4) @@ -73,7 +73,7 @@ public void holeDetectionTest() throws ColinearPointsException, NonFlatPolygonEx // one polygon with two holes, one of the holes contains another // polygon with one hole - Polygon p3 = Polygon.fromConcavePoints( + Polygon p3 = Polygon.fromVector3d( new Vector3d(1, 1), new Vector3d(2, 2), new Vector3d(1, 5), @@ -84,7 +84,7 @@ public void holeDetectionTest() throws ColinearPointsException, NonFlatPolygonEx new Vector3d(6, 1), new Vector3d(3, 0) ).get(0); - Polygon p3Hole1 = Polygon.fromConcavePoints( + Polygon p3Hole1 = Polygon.fromVector3d( new Vector3d(3, 2), new Vector3d(3, 3), new Vector3d(4, 4), @@ -93,21 +93,21 @@ public void holeDetectionTest() throws ColinearPointsException, NonFlatPolygonEx new Vector3d(4, 1) ).get(0); - Polygon p3p1 = Polygon.fromConcavePoints( + Polygon p3p1 = Polygon.fromVector3d( new Vector3d(4, 2), new Vector3d(3.5, 2.5), new Vector3d(4, 3), new Vector3d(4.5, 2.5) ).get(0); - Polygon p3p1Hole = Polygon.fromConcavePoints( + Polygon p3p1Hole = Polygon.fromVector3d( new Vector3d(4, 2.25), new Vector3d(3.75, 2.5), new Vector3d(4, 2.75), new Vector3d(4.25, 2.5) ).get(0); - Polygon p3Hole2 = Polygon.fromConcavePoints( + Polygon p3Hole2 = Polygon.fromVector3d( new Vector3d(2, 3), new Vector3d(2, 4), new Vector3d(3, 4) From b04c98af8f2956360a5bc72873be6ad244704015 Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Sun, 22 Feb 2026 15:28:20 -0500 Subject: [PATCH 27/35] new API --- src/main/java/eu/mihosoft/vrl/v3d/Polygon.java | 9 ++++++--- src/main/java/eu/mihosoft/vrl/v3d/Sphere.java | 5 ++++- src/main/java/eu/mihosoft/vrl/v3d/Toroid.java | 2 +- .../eu/mihosoft/vrl/v3d/ext/imagej/STLLoader.java | 4 ++-- .../vrl/v3d/ext/org/poly2tri/PolygonUtil.java | 8 ++++---- .../vrl/v3d/PolygonClassificationTest.java | 14 +++++++------- 6 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java b/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java index d40b8fdc..680c69c4 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java @@ -166,7 +166,7 @@ public static List fromVertex(List vertices2) throws ColinearPo * @param p the reference plane provided to the polygon for flatness checking * @return a List defined by the specified point list */ - public static List get(List vertices, PropertyStorage shared, boolean fixAFlat, Plane p, Color c) throws ColinearPointsException,NonFlatPolygonException{ + public static List fromVertex(List vertices, PropertyStorage shared, boolean fixAFlat, Plane p, Color c) throws ColinearPointsException,NonFlatPolygonException{ List back = new ArrayList(); try { back.add(new Polygon(vertices, shared, p).setColor(c)); @@ -178,8 +178,11 @@ public static List get(List vertices, PropertyStorage shared, b } return back; } - public static List get(List vertices, PropertyStorage shared, boolean fixAFlat, Plane p) throws ColinearPointsException,NonFlatPolygonException{ - return get(vertices, shared, fixAFlat, p,CSG.getDefaultColor()); + public static List fromVertex(List vertices, PropertyStorage shared) throws ColinearPointsException,NonFlatPolygonException{ + return fromVertex(vertices, shared, true, null,CSG.getDefaultColor()); + } + public static List fromVertex(List vertices, PropertyStorage shared, boolean fixAFlat, Plane p) throws ColinearPointsException,NonFlatPolygonException{ + return fromVertex(vertices, shared, fixAFlat, p,CSG.getDefaultColor()); } /** * Decomposes the specified concave polygon into convex polygons. diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Sphere.java b/src/main/java/eu/mihosoft/vrl/v3d/Sphere.java index 4e44f036..c98dc1a4 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Sphere.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Sphere.java @@ -194,10 +194,13 @@ public List toPolygons() { (j + 1) / (double) getNumStacks()) ); try { - polygons.add(Polygon.fromVector3d(vertices, getProperties())); + polygons.addAll(Polygon.fromVertex(vertices, getProperties())); } catch (ColinearPointsException e) { // TODO Auto-generated catch block e.printStackTrace(); + } catch (NonFlatPolygonException e) { + // TODO Auto-generated catch block + e.printStackTrace(); } } } diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Toroid.java b/src/main/java/eu/mihosoft/vrl/v3d/Toroid.java index 1fb8d311..a7cabae9 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Toroid.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Toroid.java @@ -74,7 +74,7 @@ public Toroid(double innerRadius, double OuterRadius, int numSlices, int facets) } Polygon poly; try { - poly = Polygon.get(vertices, properties,true,null).get(0); + poly = Polygon.fromVertex(vertices, properties,true,null).get(0); } catch (ColinearPointsException e) { throw new RuntimeException(e); } catch (NonFlatPolygonException e) { diff --git a/src/main/java/eu/mihosoft/vrl/v3d/ext/imagej/STLLoader.java b/src/main/java/eu/mihosoft/vrl/v3d/ext/imagej/STLLoader.java index 18edf45f..199d38e6 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/ext/imagej/STLLoader.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/ext/imagej/STLLoader.java @@ -123,7 +123,7 @@ private void parseAscii(File f,ArrayList polygons) { }catch(NumberFormatException ex) { pl=Plane.createFromPoints(vertices); } - polygons.addAll( Polygon.get(vertices, null, true, pl)); + polygons.addAll( Polygon.fromVertex(vertices, null, true, pl)); } catch (ColinearPointsException e) { System.out.println(e.getMessage()+ " STL Load Pruned "+vertices); } catch (NonFlatPolygonException e) { @@ -185,7 +185,7 @@ private void parseBinary(File f, ArrayList polygons,int triangles) { System.out.println(" STL has bad Normal "+normal); pl=Plane.createFromPoints(vertices); } - polygons.addAll( Polygon.get(vertices, null, true, pl)); + polygons.addAll( Polygon.fromVertex(vertices, null, true, pl)); } catch (ColinearPointsException e) { System.out.println(e.getMessage()+ " STL Load Pruned "+vertices); } catch (NonFlatPolygonException e) { diff --git a/src/main/java/eu/mihosoft/vrl/v3d/ext/org/poly2tri/PolygonUtil.java b/src/main/java/eu/mihosoft/vrl/v3d/ext/org/poly2tri/PolygonUtil.java index 0ba79663..8efcc9c5 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/ext/org/poly2tri/PolygonUtil.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/ext/org/poly2tri/PolygonUtil.java @@ -184,7 +184,7 @@ public class PolygonUtil { modifiable.remove(vr); if (modifiable.size() > 2) { try { - return Polygon.get(modifiable, shared, true, p, color); + return Polygon.fromVertex(modifiable, shared, true, p, color); } catch (ColinearPointsException e) { System.out.println(" Pruning polygon in repair " + vertices + " to " + modifiable); } catch (NonFlatPolygonException e) { @@ -633,7 +633,7 @@ public static ArrayList triangulatePolygon(List vertices, Prope if (vertices.size() == 3) { try { - result.addAll(Polygon.get(vertices, shared, false, p)); + result.addAll(Polygon.fromVertex(vertices, shared, false, p)); } catch (ColinearPointsException e) { e.printStackTrace(); } catch (NonFlatPolygonException e) { @@ -730,7 +730,7 @@ private static void makeTrianglesInternal(Polygon concave, boolean cw, List onel = Polygon.get(vertices, concave.getStorage(), true, normal2.clone()); + List onel = Polygon.fromVertex(vertices, concave.getStorage(), true, normal2.clone()); for (Polygon one : onel) { if (reorent) { one = one.transform(orentationInv); @@ -815,7 +815,7 @@ private static void makeTriangles(List vertices, PropertyStorage shared, Collections.reverse(triPoints); } List polyl; - polyl = Polygon.get(triPoints, shared, true, p1); + polyl = Polygon.fromVertex(triPoints, shared, true, p1); // poly = Extrude.toCCW(poly); // poly.getPlane().setNormal(concave.getPlane().getNormal()); for (Polygon poly : polyl) { diff --git a/src/test/java/eu/mihosoft/vrl/v3d/PolygonClassificationTest.java b/src/test/java/eu/mihosoft/vrl/v3d/PolygonClassificationTest.java index f131e277..a0dd7b0b 100644 --- a/src/test/java/eu/mihosoft/vrl/v3d/PolygonClassificationTest.java +++ b/src/test/java/eu/mihosoft/vrl/v3d/PolygonClassificationTest.java @@ -33,7 +33,7 @@ public void testPolygon1_ValidThinTriangle() { ); try { - Polygon polygon = Polygon.get(vertices, storage, true, null).get(0); + Polygon polygon = Polygon.fromVertex(vertices, storage, true, null).get(0); assertNotNull("Polygon should be created successfully", polygon); assertEquals("Polygon should have 3 vertices", 3, polygon.getVertices().size()); } catch (Exception e) { @@ -58,7 +58,7 @@ public void testPolygon3_ValidWithSmallYSpan() { ); try { - Polygon polygon = Polygon.get(vertices, storage, true, null).get(0); + Polygon polygon = Polygon.fromVertex(vertices, storage, true, null).get(0); assertNotNull("Polygon should be created successfully", polygon); assertEquals("Polygon should have 3 vertices", 3, polygon.getVertices().size()); } catch (Exception e) { @@ -81,7 +81,7 @@ public void testPolygon4_ValidWithXSpan() { ); try { - Polygon polygon = Polygon.get(vertices, storage, true, null).get(0); + Polygon polygon = Polygon.fromVertex(vertices, storage, true, null).get(0); assertNotNull("Polygon should be created successfully", polygon); assertEquals("Polygon should have 3 vertices", 3, polygon.getVertices().size()); } catch (Exception e) { @@ -104,7 +104,7 @@ public void testPolygon5_ValidWithYAndZVariation() { ); try { - Polygon polygon = Polygon.get(vertices, storage, true, null).get(0); + Polygon polygon = Polygon.fromVertex(vertices, storage, true, null).get(0); assertNotNull("Polygon should be created successfully", polygon); assertEquals("Polygon should have 3 vertices", 3, polygon.getVertices().size()); } catch (Exception e) { @@ -126,7 +126,7 @@ public void testPolygon6_ValidWithLargeYZDifferences() { ); try { - Polygon polygon = Polygon.get(vertices, storage, true, null).get(0); + Polygon polygon = Polygon.fromVertex(vertices, storage, true, null).get(0); assertNotNull("Polygon should be created successfully", polygon); assertEquals("Polygon should have 3 vertices", 3, polygon.getVertices().size()); } catch (Exception e) { @@ -151,7 +151,7 @@ public void testDegeneratePolygon_DuplicatePoints() throws ColinearPointsExcepti new Vertex(new Vector3d(10.5175167546, 116.6176943528, 83.1832321598)) ); - Polygon polygon = Polygon.get(vertices, storage, true, null).get(0); + Polygon polygon = Polygon.fromVertex(vertices, storage, true, null).get(0); fail("Should have thrown exception for duplicate points"); } @@ -170,7 +170,7 @@ public void testDegeneratePolygon_Collinear() throws ColinearPointsException, No new Vertex(new Vector3d(10.5068817145, 98.4507751465, 35.0306403108)) ); - Polygon polygon = Polygon.get(vertices, storage, true, null).get(0); + Polygon polygon = Polygon.fromVertex(vertices, storage, true, null).get(0); fail("Should have thrown exception for collinear points"); } From 2c7b69d859faa6115784c9dec5f9075d12a58e35 Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Sun, 22 Feb 2026 15:31:30 -0500 Subject: [PATCH 28/35] flip the polygon instead of manipulate points in user code --- src/main/java/eu/mihosoft/vrl/v3d/Slice.java | 23 +++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Slice.java b/src/main/java/eu/mihosoft/vrl/v3d/Slice.java index 51197a8e..0711bde4 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Slice.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Slice.java @@ -284,8 +284,14 @@ public List slice(CSG incoming, Transform slicePlane, double normalInse p.add(new Vector3d((it[0] * scaleX) + xOffset, (it[1] * scaleY) + yOffset, 0)); } - Polygon polyNew = Polygon.fromPoints(p); - polys.add(polyNew); + List polylist; + try { + polylist = Polygon.fromVector3d(p); + polys.addAll(polylist); + } catch (ColinearPointsException | NonFlatPolygonException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } listOfPointsForThisPoly.clear(); if (pixelVersionOfPoints.size() > 0) { pixStart = pixelVersionOfPoints.remove(0); @@ -305,7 +311,12 @@ public List slice(CSG incoming, Transform slicePlane, double normalInse for (int[] it : listOfPointsForThisPoly) { p.add(new Vector3d((it[0] * scaleX) + xOffset, (it[1] * scaleY) + yOffset, 0)); } - polys.add(Polygon.fromPoints(p)); + try { + polys.addAll(Polygon.fromVector3d(p)); + } catch (ColinearPointsException | NonFlatPolygonException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } // if(display)BowlerStudioController.getBowlerStudio() .addObject(polys, new // File(".")) } @@ -485,11 +496,7 @@ private static List sanatize(List slice) throws ColinearPoints Polygon me = slice.get(i); boolean bad = !Extrude.isCCW(me); if (bad) { - // println "Bad polygon!" - List points = me.getPoints(); - ArrayList result = new ArrayList(points); - Collections.reverse(result); - me = Polygon.fromPoints(result); + me.flip(); } slice.set(i, me); } From 152859e02f6e2c1c276e33e7062a269b95a7ba2c Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Sun, 22 Feb 2026 15:36:20 -0500 Subject: [PATCH 29/35] list api --- src/main/java/eu/mihosoft/vrl/v3d/Node.java | 2 +- src/main/java/eu/mihosoft/vrl/v3d/Polyhedron.java | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Node.java b/src/main/java/eu/mihosoft/vrl/v3d/Node.java index e0aa5ddd..c2eb9909 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Node.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Node.java @@ -321,7 +321,7 @@ private static void add(List l, List f, Polygon polygon) { if(polygon.getPlane().checkNormal(f) == NormalState.FLIPPED) { Collections.reverse(f); } - List fpoly = Polygon.get(f, polygon.getStorage(), true, polygon.getPlane(),polygon.getColor()); + List fpoly = Polygon.fromVertex(f, polygon.getStorage(), true, polygon.getPlane(),polygon.getColor()); l.addAll(fpoly); }catch(ColinearPointsException ex) { //ex.printStackTrace(); diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Polyhedron.java b/src/main/java/eu/mihosoft/vrl/v3d/Polyhedron.java index cdaacaea..3db0c08f 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Polyhedron.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Polyhedron.java @@ -66,18 +66,20 @@ public List toPolygons() { return points.get(i).clone(); }; - Function, Polygon> faceListToPolygon + Function, List> faceListToPolygon = (List faceList) -> { try { - return Polygon.fromPoints(faceList.stream().map(indexToPoint). + return Polygon.fromVector3d(faceList.stream().map(indexToPoint). collect(Collectors.toList()), properties); - } catch (ColinearPointsException e) { + } catch (Exception e) { throw new RuntimeException(e); } }; - return faces.stream().map(faceListToPolygon). - collect(Collectors.toList()); + return faces.stream() + .map(faceListToPolygon) + .flatMap(List::stream) + .collect(Collectors.toList()); } /* (non-Javadoc) From 45024e8d636eb02566b7811bcb99927d268d7f74 Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Sun, 22 Feb 2026 15:39:34 -0500 Subject: [PATCH 30/35] list api --- .../java/eu/mihosoft/vrl/v3d/Extrude.java | 38 ++++++++++++++----- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Extrude.java b/src/main/java/eu/mihosoft/vrl/v3d/Extrude.java index 2cb9f53c..605f0ae1 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Extrude.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Extrude.java @@ -70,8 +70,14 @@ public class Extrude { public CSG points(Vector3d dir, List points) throws ColinearPointsException { List newList = new ArrayList<>(points); - Polygon fromPoints = Polygon.fromPoints(toCCW(newList)); - return extrude(dir, fromPoints); + Polygon fromPoints; + try { + fromPoints = Polygon.fromVector3d(toCCW(newList)).get(0); + + return extrude(dir, fromPoints); + } catch (ColinearPointsException | NonFlatPolygonException e) { + throw new RuntimeException(e); + } } /** @@ -101,8 +107,14 @@ private CSG monotoneExtrude(Vector3d dir, Polygon polygon1) throws ColinearPoint newPolygons.add(p.transformed(new Transform().move(dir))); } Polygon polygon2 = polygon1.transformed(new Transform().move(dir)); - List parts = Extrude.monotoneExtrude(polygon2, polygon1); - newPolygons.addAll(parts); + List parts; + try { + parts = Extrude.monotoneExtrude(polygon2, polygon1); + newPolygons.addAll(parts); + } catch (NonFlatPolygonException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } //ArrayList topPolygons = PolygonUtil.triangulatePolygon(polygon2); @@ -575,9 +587,15 @@ public static CSG sweep(Polygon p, Transform increment, Transform offset, int st running.apply(increment); double unit = ((double) i) / ((double) steps); Polygon step = offsetP.transformed(provider.get(unit, steps)).transformed(running); - List parts = monotoneExtrude(prev, step); - prev = step; - newPolygons.addAll(parts); + List parts; + try { + parts = monotoneExtrude(prev, step); + prev = step; + newPolygons.addAll(parts); + } catch (NonFlatPolygonException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } Polygon polygon2 = prev.clone(); List topPolygons = PolygonUtil.triangulatePolygon(polygon2.flipped()); @@ -590,7 +608,7 @@ public static CSG sweep(Polygon p, double angle, double z, double radius, int st return sweep(p, new Transform().rotX(angle).movex(z), new Transform().movey(radius), steps); } - public static List monotoneExtrude(Polygon polygon2, Polygon polygon1) { + public static List monotoneExtrude(Polygon polygon2, Polygon polygon1) throws NonFlatPolygonException { List newPolygons = new ArrayList<>(); int numvertices = polygon1.getVertices().size(); @@ -608,7 +626,7 @@ public static List monotoneExtrude(Polygon polygon2, Polygon polygon1) if (Math.abs(distance) > Plane.getEPSILON() && Math.abs(z1Dist) > Plane.getEPSILON()) { List asList = Arrays.asList(bottomV2.clone(), topV1.clone(), bottomV1.clone()); try { - newPolygons.add(Polygon.fromPoints(asList, polygon1.getStorage())); + newPolygons.addAll(Polygon.fromVector3d(asList, polygon1.getStorage())); } catch (ColinearPointsException ex) { System.out.println(ex.getMessage()+" Pruning from extrude"); } @@ -618,7 +636,7 @@ public static List monotoneExtrude(Polygon polygon2, Polygon polygon1) if (Math.abs(distance2) > Plane.getEPSILON() && Math.abs(z1Dist2) > Plane.getEPSILON()) { List asList2 = Arrays.asList(bottomV2.clone(), topV2.clone(), topV1.clone()); try { - newPolygons.add(Polygon.fromPoints(asList2, polygon1.getStorage())); + newPolygons.addAll(Polygon.fromVector3d(asList2, polygon1.getStorage())); } catch (ColinearPointsException ex) { System.out.println(ex.getMessage()+" Pruning from extrude"); } From 64bccf6e488b14d668b10f164cb95dd9fef4bfd3 Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Sun, 22 Feb 2026 15:43:07 -0500 Subject: [PATCH 31/35] list api --- src/main/java/eu/mihosoft/vrl/v3d/Edge.java | 59 ++++++++++++------- .../java/eu/mihosoft/vrl/v3d/Polygon.java | 15 +++++ 2 files changed, 52 insertions(+), 22 deletions(-) diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Edge.java b/src/main/java/eu/mihosoft/vrl/v3d/Edge.java index 922c3e6c..fc8052a9 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Edge.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Edge.java @@ -111,25 +111,25 @@ public static List toPoints(List edges) { return edges.stream().map(e -> e.p1.pos).collect(Collectors.toList()); } - /** - * To polygon. - * - * @param points the points - * @param plane the plane - * @return the polygon - */ - public static Polygon toPolygon(List points, Plane plane) throws ColinearPointsException{ - -// List points = edges.stream().().map(e -> e.p1.pos). -// collect(Collectors.toList()); - Polygon p = Polygon.fromPoints(points); - -// // we try to detect wrong orientation by comparing normals -// if (p.plane.normal.angle(plane.normal) > 0.1) { -// p.flip(); -// } - return p; - } +// /** +// * To polygon. +// * +// * @param points the points +// * @param plane the plane +// * @return the polygon +// */ +// public static Polygon toPolygon(List points, Plane plane) throws ColinearPointsException{ +// +//// List points = edges.stream().().map(e -> e.p1.pos). +//// collect(Collectors.toList()); +// Polygon p = Polygon.fromPoints(points); +// +//// // we try to detect wrong orientation by comparing normals +//// if (p.plane.normal.angle(plane.normal) > 0.1) { +//// p.flip(); +//// } +// return p; +// } /** * To polygons. @@ -169,7 +169,12 @@ public static List toPolygons(List boundaryEdges, Plane plane) th // com.neuronrobotics.sdk.common.Log.error("#bnd-path-length: " + // boundaryPath.size()); - result.add(toPolygon(boundaryPath, plane)); + try { + result.addAll(Polygon.fromVector3d(boundaryPath, plane)); + } catch (ColinearPointsException | NonFlatPolygonException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } return result; } @@ -449,7 +454,12 @@ public static List boundaryPaths(List boundaryEdges) throws Colin break; } - result.add(Polygon.fromPoints(boundaryPath)); + try { + result.addAll(Polygon.fromVector3d(boundaryPath)); + } catch (ColinearPointsException | NonFlatPolygonException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } startIndex = nextUnused(used); if (startIndex > 0) { @@ -518,7 +528,12 @@ public static List _toPolygons(List boundaryEdges, Plane plane) t // com.neuronrobotics.sdk.common.Log.error("#bnd-path-length: " + // boundaryPath.size()); - result.add(toPolygon(boundaryPath, plane)); + try { + result.addAll(Polygon.fromVector3d(boundaryPath, plane)); + } catch (ColinearPointsException | NonFlatPolygonException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } return result; } diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java b/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java index 680c69c4..d6a5a1f3 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java @@ -214,6 +214,21 @@ public static List fromVector3d(List points,PropertyStorage s } return PolygonUtil.triangulatePolygon(vertices,shared, false, null,CSG.getDefaultColor()); } + /** + * Decomposes the specified concave polygon into convex polygons. + * + * @param points the points that define the polygon + * @return the decomposed concave polygon (list of convex polygons) + */ + public static List fromVector3d(List points,Plane pl )throws ColinearPointsException,NonFlatPolygonException { + List vertices = new ArrayList<>(); + for (Vector3d p : points) { + Vector3d vec = p.clone(); + Vertex vertex = new Vertex(vec); + vertices.add(vertex); + } + return PolygonUtil.triangulatePolygon(vertices,new PropertyStorage(), false, pl,CSG.getDefaultColor()); + } // /** // * Creates a polygon from the specified point list. // * From af7424a029efeeea40082fdf3915fd268f93a63f Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Sun, 22 Feb 2026 15:44:23 -0500 Subject: [PATCH 32/35] list api --- src/main/java/eu/mihosoft/vrl/v3d/Cylinder.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Cylinder.java b/src/main/java/eu/mihosoft/vrl/v3d/Cylinder.java index 93abd128..f956a992 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Cylinder.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Cylinder.java @@ -234,37 +234,37 @@ public List toPolygons() { for (int i = 0; i < numSlices; i++) { double t0 = i / (double) numSlices, t1 = (i + 1) / (double) numSlices; try { - polygons.add(new Polygon(Arrays.asList( + polygons.addAll( Polygon.fromVertex(Arrays.asList( startV, cylPoint(axisX, axisY, axisZ, ray, s, startRadius, 0, t0, -1), cylPoint(axisX, axisY, axisZ, ray, s, startRadius, 0, t1, -1)), properties )); - } catch (ColinearPointsException e1) { + } catch (Exception e1) { // TODO Auto-generated catch block e1.printStackTrace(); } try { - polygons.add(new Polygon(Arrays.asList( + polygons.addAll( Polygon.fromVertex(Arrays.asList( cylPoint(axisX, axisY, axisZ, ray, s, startRadius, 0, t1, 0), cylPoint(axisX, axisY, axisZ, ray, s, startRadius, 0, t0, 0), cylPoint(axisX, axisY, axisZ, ray, s, endRadius, 1, t0, 0), cylPoint(axisX, axisY, axisZ, ray, s, endRadius, 1, t1, 0)), properties )); - } catch (ColinearPointsException e1) { + } catch (Exception e1) { // TODO Auto-generated catch block e1.printStackTrace(); } try { - polygons.add(new Polygon( + polygons.addAll( Polygon.fromVertex( Arrays.asList( endV, cylPoint(axisX, axisY, axisZ, ray, s, endRadius, 1, t1, 1), cylPoint(axisX, axisY, axisZ, ray, s, endRadius, 1, t0, 1)), properties )); - } catch (ColinearPointsException e1) { + } catch (Exception e1) { // TODO Auto-generated catch block e1.printStackTrace(); } From 772bf32c484e1af045b2baf670137eb92eefecee Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Sun, 22 Feb 2026 15:45:01 -0500 Subject: [PATCH 33/35] list api --- src/main/java/eu/mihosoft/vrl/v3d/Cube.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Cube.java b/src/main/java/eu/mihosoft/vrl/v3d/Cube.java index 96786dc5..0e6b9dbc 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Cube.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Cube.java @@ -146,10 +146,13 @@ public List toPolygons() { vertices.add(new Vertex(pos)); } try { - polygons.add(new Polygon(vertices, properties)); + polygons.addAll( Polygon.fromVertex(vertices, properties)); } catch (ColinearPointsException e) { // TODO Auto-generated catch block e.printStackTrace(); + } catch (NonFlatPolygonException e) { + // TODO Auto-generated catch block + e.printStackTrace(); } } From 07cfcaf9892ff8d0dbd9b75b536e7bc349e05be2 Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Sun, 22 Feb 2026 15:45:18 -0500 Subject: [PATCH 34/35] list api --- src/main/java/eu/mihosoft/vrl/v3d/CSG.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/eu/mihosoft/vrl/v3d/CSG.java b/src/main/java/eu/mihosoft/vrl/v3d/CSG.java index 81ae0fe3..ae817caa 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/CSG.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/CSG.java @@ -2128,7 +2128,7 @@ public void run() { } List p; try { - p = Polygon.get(points, polygon.getStorage(), true, pl); + p = Polygon.fromVertex(points, polygon.getStorage(), true, pl); newPoly.addAll(p); } catch (ColinearPointsException e) { System.err.println("Pruning " + points); From 854e02aa56c636dedcc9a6aa799a6a843a4f7eb6 Mon Sep 17 00:00:00 2001 From: Kevin Harrington Date: Sun, 22 Feb 2026 17:19:49 -0500 Subject: [PATCH 35/35] new API compiles but unit tests still fail --- src/main/java/com/piro/bezier/BezierPath.java | 4 + src/main/java/eu/mihosoft/vrl/v3d/CSG.java | 2 +- src/main/java/eu/mihosoft/vrl/v3d/Node.java | 7 +- src/main/java/eu/mihosoft/vrl/v3d/Plane.java | 72 ++--- .../java/eu/mihosoft/vrl/v3d/Polygon.java | 262 +++++++++--------- .../java/eu/mihosoft/vrl/v3d/Vector3d.java | 2 +- .../vrl/v3d/ext/imagej/STLLoader.java | 4 +- .../vrl/v3d/ext/org/poly2tri/PolygonUtil.java | 3 + .../vrl/v3d/PolygonClassificationTest.java | 114 +------- 9 files changed, 164 insertions(+), 306 deletions(-) diff --git a/src/main/java/com/piro/bezier/BezierPath.java b/src/main/java/com/piro/bezier/BezierPath.java index d62c2eee..defc07a4 100644 --- a/src/main/java/com/piro/bezier/BezierPath.java +++ b/src/main/java/com/piro/bezier/BezierPath.java @@ -194,11 +194,15 @@ private boolean setThePoint(Vector3d eval) { } } if (plInternal.size() > 1) { + try { Edge e = new Edge(new Vertex(plInternal.get(end - 1)), new Vertex(plInternal.get(end))); if (e.colinear(eval)) { plInternal.set(end, eval); return true; } + }catch(NumberFormatException ex) { + return false; + } } return plInternal.add(eval); } diff --git a/src/main/java/eu/mihosoft/vrl/v3d/CSG.java b/src/main/java/eu/mihosoft/vrl/v3d/CSG.java index ae817caa..ab4bdb4b 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/CSG.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/CSG.java @@ -1679,7 +1679,7 @@ public StringBuilder toStlString(StringBuilder sb) { sb.append("solid v3d.csg\n"); for (Polygon p : getPolygons()) { try { - Plane.createFromPoints(p.getVertices(), null); + Plane.createFromPoints(p.getVertices()); p.toStlString(sb); } catch (Exception ex) { System.out.println("Prune Polygon on export"); diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Node.java b/src/main/java/eu/mihosoft/vrl/v3d/Node.java index c2eb9909..d369ef73 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Node.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Node.java @@ -318,10 +318,13 @@ private static void add(List l, List f, Polygon polygon) { if (f.size() < 3) return; try { - if(polygon.getPlane().checkNormal(f) == NormalState.FLIPPED) { + NormalState checkNormal = polygon.getPlane().checkNormal(f); + if(checkNormal == NormalState.FLIPPED) { Collections.reverse(f); } - List fpoly = Polygon.fromVertex(f, polygon.getStorage(), true, polygon.getPlane(),polygon.getColor()); + List fpoly = Polygon.fromVertex(f, polygon.getStorage(), true, + checkNormal==NormalState.SAME? polygon.getPlane():null, + polygon.getColor()); l.addAll(fpoly); }catch(ColinearPointsException ex) { //ex.printStackTrace(); diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Plane.java b/src/main/java/eu/mihosoft/vrl/v3d/Plane.java index 39d8545f..c7fd4526 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Plane.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Plane.java @@ -88,7 +88,7 @@ public class Plane implements Serializable { * @param normal plane normal * @param dist distance from origin */ - public Plane(Vector3d normal, double dist) { + private Plane(Vector3d normal, double dist) { this.setNormal(normal.normalized()); this.setDist(dist); } @@ -100,58 +100,24 @@ public Plane(Vector3d normal, double dist) { * @param dist distance from origin * @throws ColinearPointsException */ - public Plane(List vertices, Vector3d testNorm) throws ColinearPointsException { + public Plane(List vertices) throws ColinearPointsException { - Vector3d n = computeNormal(vertices, testNorm); + Vector3d n = computeNormal(vertices); this.setNormal(n); double distAvg = 0; for(int i=0;i0) { + diff = (distAvg/(double)(i))-dot; + } + distAvg+=dot; } - this.setDist(distAvg/((double)vertices.size())); + double dist2 = distAvg/((double)vertices.size()); + this.setDist(dist2); } - /** - * Constructor. Creates a new plane defined by its normal vector and the - * distance to the origin. - * - * @param normal plane normal - * @param dist distance from origin - */ - public Plane(Vector3d normal, List vertices) { - this.setNormal(normal.normalized()); - double distAvg = 0; - for(int i=0;i vertices) throws ColinearPointsException { - return createFromPoints(vertices, null); - } /** * Creates a plane defined by the the specified points. @@ -163,15 +129,12 @@ public static Plane createFromPoints(List vertices) throws ColinearPoint * @param c third point * @return a plane */ - public static Plane createFromPoints(List vertices, Vector3d testNorm) throws ColinearPointsException { - return new Plane(vertices, testNorm); + public static Plane createFromPoints(List vertices) throws ColinearPointsException { + return new Plane(vertices); } - public Vector3d computeNormal(List vertices) throws ColinearPointsException{ - return computeNormal(vertices, null); - } - public Vector3d computeNormal(List vertices, Vector3d testNorm) throws ColinearPointsException { + public Vector3d computeNormal(List vertices) throws ColinearPointsException { if (vertices == null || vertices.size() < 3) { throw new ColinearPointsException("Can not find normal without at least 3 points "+vertices); @@ -206,16 +169,17 @@ private boolean isValidNormal(Vector3d normal) { public NormalState checkNormal(List vertex) { Plane p = null; try { - p = Plane.createFromPoints(vertex, getNormal()); + p = Plane.createFromPoints(vertex); } catch (Exception ex) { - //ex.printStackTrace(); + ex.printStackTrace(); + return NormalState.DIVERGENT; } if (p != null) { Vector3d normal = p.getNormal(); Vector3d normal2 = getNormal(); double dot2 = normal.dot(normal2); double dot = 1-dot2; - double dFlipped = 2-dot2; + double dFlipped = 1+dot2; // check for actual misallignment double d = Plane.getEPSILON(); if(dot>d) diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java b/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java index d6a5a1f3..58b72bac 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Polygon.java @@ -66,14 +66,13 @@ public final class Polygon implements Serializable { */ public Plane plane = null; private boolean isHole = false; - private double r = CSG.getDefaultColor().getRed(); - private double g = CSG.getDefaultColor().getGreen(); - private double b = CSG.getDefaultColor().getBlue(); - private double o = CSG.getDefaultColor().getOpacity(); + private double r = -1;// CSG.getDefaultColor().getRed(); + private double g = -1;// CSG.getDefaultColor().getGreen(); + private double b = -1;// CSG.getDefaultColor().getBlue(); + private double o = -1;// CSG.getDefaultColor().getOpacity(); private boolean valid = true; private boolean degenerate = false; - /** * Constructor. Creates a new polygon that consists of the specified vertices. * @@ -83,7 +82,8 @@ public final class Polygon implements Serializable { * @param vertices polygon vertices * @param shared shared property */ - private Polygon(List vertices, PropertyStorage shared, Plane p) throws ColinearPointsException,NonFlatPolygonException { + private Polygon(List vertices, PropertyStorage shared, Plane p) + throws ColinearPointsException, NonFlatPolygonException { this.setVertices(pruneDuplicatePoints(vertices)); this.shared = shared; if (p != null) @@ -101,7 +101,8 @@ private Polygon(List vertices, PropertyStorage shared, Plane p) throws C * @param vertices polygon vertices * @param shared shared property */ - private Polygon(List vertices, PropertyStorage shared) throws ColinearPointsException,NonFlatPolygonException { + private Polygon(List vertices, PropertyStorage shared) + throws ColinearPointsException, NonFlatPolygonException { this(vertices, shared, null); } @@ -113,9 +114,10 @@ private Polygon(List vertices, PropertyStorage shared) throws ColinearPo * * @param vertices polygon vertices */ - private Polygon(List vertices) throws ColinearPointsException,NonFlatPolygonException { + private Polygon(List vertices) throws ColinearPointsException, NonFlatPolygonException { this(vertices, new PropertyStorage(), null); } + /** * Constructor. Creates a new polygon that consists of the specified vertices. * @@ -125,154 +127,134 @@ private Polygon(List vertices) throws ColinearPointsException,NonFlatPol * @param vertices polygon vertices * */ - private Polygon(Vertex... vertices) throws ColinearPointsException,NonFlatPolygonException { + private Polygon(Vertex... vertices) throws ColinearPointsException, NonFlatPolygonException { this(Arrays.asList(vertices)); } + /** * Decomposes the specified concave polygon into convex polygons. * * @param points the points that define the polygon * @return the decomposed concave polygon (list of convex polygons) */ - public static List fromVector3d(Vector3d... points) throws ColinearPointsException { + public static List fromVector3d(Vector3d... points) throws ColinearPointsException { List vertices = new ArrayList<>(); for (Vector3d p : points) { Vector3d vec = p.clone(); Vertex vertex = new Vertex(vec); vertices.add(vertex); } - return PolygonUtil.triangulatePolygon(vertices,new PropertyStorage(), false, null,CSG.getDefaultColor()); - } + try { + return fromVertex(vertices, new PropertyStorage(), false, null, CSG.getDefaultColor()); + }catch (NonFlatPolygonException e) { + throw new RuntimeException(e); + } } + public static List fromVertex(List vertices2) throws ColinearPointsException { - // TODO Auto-generated method stub - return PolygonUtil.triangulatePolygon(vertices2,new PropertyStorage(), false, null,CSG.getDefaultColor()); - } -// /** -// * Creates a polygon from the specified point list. -// * -// * @param points the points that define the polygon -// * @param shared shared property storage -// * @return a polygon defined by the specified point list -// */ -// private static Polygon fromPoints(List points, PropertyStorage shared) throws ColinearPointsException,NonFlatPolygonException { -// return fromPoints(points, shared, null, true); -// } + try { + return fromVertex(vertices2, new PropertyStorage(), false, null, CSG.getDefaultColor()); + }catch (NonFlatPolygonException e) { + throw new RuntimeException(e); + } + } + + /** * Creates a polygon from the specified point list. * - * @param points the points that define the polygon - * @param shared shared property storage + * @param points the points that define the polygon + * @param shared shared property storage * @param fixAFlat triangulate the non flat polygons or throw the exception - * @param p the reference plane provided to the polygon for flatness checking + * @param p the reference plane provided to the polygon for flatness + * checking * @return a List defined by the specified point list */ - public static List fromVertex(List vertices, PropertyStorage shared, boolean fixAFlat, Plane p, Color c) throws ColinearPointsException,NonFlatPolygonException{ + public static List fromVertex(List vertices, PropertyStorage shared, boolean fixAFlat, Plane p, + Color c) throws ColinearPointsException, NonFlatPolygonException { List back = new ArrayList(); try { back.add(new Polygon(vertices, shared, p).setColor(c)); - }catch(NonFlatPolygonException e) { - if(fixAFlat) - return PolygonUtil.triangulatePolygon(vertices,shared, fixAFlat, p,c); + } catch (NonFlatPolygonException e) { + if (fixAFlat) + return PolygonUtil.triangulatePolygon(vertices, shared, fixAFlat, p, c); else throw e; } return back; } - public static List fromVertex(List vertices, PropertyStorage shared) throws ColinearPointsException,NonFlatPolygonException{ - return fromVertex(vertices, shared, true, null,CSG.getDefaultColor()); + + public static List fromVertex(List vertices, PropertyStorage shared) + throws ColinearPointsException, NonFlatPolygonException { + return fromVertex(vertices, shared, true, null, CSG.getDefaultColor()); } - public static List fromVertex(List vertices, PropertyStorage shared, boolean fixAFlat, Plane p) throws ColinearPointsException,NonFlatPolygonException{ - return fromVertex(vertices, shared, fixAFlat, p,CSG.getDefaultColor()); + + public static List fromVertex(List vertices, PropertyStorage shared, boolean fixAFlat, Plane p) + throws ColinearPointsException, NonFlatPolygonException { + return fromVertex(vertices, shared, fixAFlat, p, CSG.getDefaultColor()); } + /** * Decomposes the specified concave polygon into convex polygons. * * @param points the points that define the polygon * @return the decomposed concave polygon (list of convex polygons) */ - public static List fromVector3d(List points)throws ColinearPointsException,NonFlatPolygonException { + public static List fromVector3d(List points) + throws ColinearPointsException, NonFlatPolygonException { List vertices = new ArrayList<>(); for (Vector3d p : points) { Vector3d vec = p.clone(); Vertex vertex = new Vertex(vec); vertices.add(vertex); } - return PolygonUtil.triangulatePolygon(vertices,new PropertyStorage(), false, null,CSG.getDefaultColor()); + try { + return fromVertex(vertices, new PropertyStorage(), false, null, CSG.getDefaultColor()); + }catch (NonFlatPolygonException e) { + throw new RuntimeException(e); + } + } + /** * Decomposes the specified concave polygon into convex polygons. * * @param points the points that define the polygon * @return the decomposed concave polygon (list of convex polygons) */ - public static List fromVector3d(List points,PropertyStorage shared )throws ColinearPointsException,NonFlatPolygonException { + public static List fromVector3d(List points, PropertyStorage shared) + throws ColinearPointsException, NonFlatPolygonException { List vertices = new ArrayList<>(); for (Vector3d p : points) { Vector3d vec = p.clone(); Vertex vertex = new Vertex(vec); vertices.add(vertex); } - return PolygonUtil.triangulatePolygon(vertices,shared, false, null,CSG.getDefaultColor()); - } + try { + return fromVertex(vertices, shared, false, null, CSG.getDefaultColor()); + }catch (NonFlatPolygonException e) { + throw new RuntimeException(e); + } } + /** * Decomposes the specified concave polygon into convex polygons. * * @param points the points that define the polygon * @return the decomposed concave polygon (list of convex polygons) */ - public static List fromVector3d(List points,Plane pl )throws ColinearPointsException,NonFlatPolygonException { + public static List fromVector3d(List points, Plane pl) + throws ColinearPointsException, NonFlatPolygonException { List vertices = new ArrayList<>(); for (Vector3d p : points) { Vector3d vec = p.clone(); Vertex vertex = new Vertex(vec); vertices.add(vertex); } - return PolygonUtil.triangulatePolygon(vertices,new PropertyStorage(), false, pl,CSG.getDefaultColor()); - } -// /** -// * Creates a polygon from the specified point list. -// * -// * @param points the points that define the polygon -// * @return a polygon defined by the specified point list -// */ -// private static Polygon fromPoints(List points)throws ColinearPointsException,NonFlatPolygonException { -// return fromPoints(points, new PropertyStorage(), null, true); -// } - -// /** -// * Creates a polygon from the specified points. -// * -// * @param points the points that define the polygon -// * @return a polygon defined by the specified point list -// */ -// private static Polygon fromPoints(Vector3d... points)throws ColinearPointsException,NonFlatPolygonException { -// return fromPoints(Arrays.asList(points), new PropertyStorage(), null, true); -// } -// -// private static Polygon fromPointsAllowDegenerate(List vertices2) throws ColinearPointsException,NonFlatPolygonException { -// return fromPoints(vertices2, new PropertyStorage(), null, true); -// } -// /** -// * Creates a polygon from the specified point list. -// * -// * @param points the points that define the polygon -// * @param shared the shared -// * @param plane may be null -// * @return a polygon defined by the specified point list -// */ -// private static Polygon fromPoints(List points, PropertyStorage shared, Plane plane, -// boolean allowDegenerate)throws ColinearPointsException,NonFlatPolygonException { -// List vertices = new ArrayList<>(); -// for (Vector3d p : points) { -// Vector3d vec = p.clone(); -// Vertex vertex = new Vertex(vec); -// vertices.add(vertex); -// } -// -// return new Polygon(vertices, shared, plane); -// } - - + try { + return fromVertex(vertices, new PropertyStorage(), false, pl, CSG.getDefaultColor()); + }catch (NonFlatPolygonException e) { + throw new RuntimeException(e); + } + } public static ArrayList pruneDuplicatePoints(List incoming) { @@ -280,13 +262,13 @@ public static ArrayList pruneDuplicatePoints(List incoming) { ArrayList newPoints = new ArrayList(); for (int i = 0; i < incoming.size(); i++) { Vertex v = incoming.get(i); - for(Vertex vt:newPoints) { - if(vt.pos.test(v.pos,Plane.getEPSILON())) { - v=null; + for (Vertex vt : newPoints) { + if (vt.pos.test(v.pos, Plane.getEPSILON())) { + v = null; break; } } - if(v!=null) + if (v != null) newPoints.add(v); } try { @@ -304,46 +286,51 @@ public static ArrayList pruneDuplicatePoints(List incoming) { void setStorage(PropertyStorage storage) { this.shared = storage; } - private void validateAndInit() throws ColinearPointsException,NonFlatPolygonException { - ArrayList vertices = pruneDuplicatePoints(this.vertices); + + private void validateAndInit() throws ColinearPointsException, NonFlatPolygonException { + ArrayList vertices = pruneDuplicatePoints(this.vertices); Plane p = Plane.createFromPoints(vertices); if (getPlane() == null) { setPlane(p); } - if (getPlane().checkNormal(vertices)==NormalState.FLIPPED ) { + if (getPlane().checkNormal(vertices) == NormalState.FLIPPED) { Collections.reverse(vertices); } - if (getPlane().checkNormal(vertices)!=NormalState.SAME) { + if (getPlane().checkNormal(vertices) != NormalState.SAME) { throw new ColinearPointsException("Failed! the normal provided mismatched to calculated normal"); } - this.vertices=vertices; - + this.vertices = vertices; if (getVertices().size() < 3) { - throw new ColinearPointsException("Invalid polygon: at least 3 vertices expected, got: " + getVertices().size()); + throw new ColinearPointsException( + "Invalid polygon: at least 3 vertices expected, got: " + getVertices().size()); } - Vector3d normal = getPlane().getNormal(); - - boolean adusted = false; + + boolean corrected = false; for (int i = 0; i < getVertices().size(); i++) { + Vector3d normal = getPlane().getNormal(); double dist = getPlane().getDist(); Vector3d pos = getVertices().get(i).pos; double dot = normal.dot(pos); double a = dot - dist; double t = Math.abs(a); - if(t>0.01) { - throw new RuntimeException("A plane epsilon of "+t+" is impossible"); - } if (t > Plane.getEPSILON()) { + if (vertices.size() == 3 && !corrected) { + setPlane(p); + i = -1; + corrected = true; + continue; + } + if (corrected && vertices.size() == 3) + throw new NonFlatPolygonException("IMPOSSIBLE 3 point polygon is not flat?? "+Plane.createFromPoints(vertices)); throw new NonFlatPolygonException("Failed because polygon is not flat"); } } - - if( !areAllPointsCollinear()) + if (!areAllPointsCollinear()) return; throw new ColinearPointsException("This polygon is colinear"); - + } public void rotatePoints() { @@ -351,8 +338,6 @@ public void rotatePoints() { getVertices().add(b); } - - /* * (non-Javadoc) * @@ -366,9 +351,10 @@ public Polygon clone() { }); // TODO figure out why this isnt working try { - //return new Polygon(newVertices, getStorage(), true, plane.clone()).setColor(getColor()); - return new Polygon(newVertices, getStorage(),null).setColor(getColor()); - }catch(Exception ex) { + // return new Polygon(newVertices, getStorage(), true, + // plane.clone()).setColor(getColor()); + return new Polygon(newVertices, new PropertyStorage(), plane.clone()).setColor(getColor()); + } catch (Exception ex) { throw new RuntimeException(ex); } } @@ -388,11 +374,11 @@ public Polygon flip() { // plane.flip(); // } NormalState checkNormal = getPlane().checkNormal(vertices); - if (checkNormal!=NormalState.SAME) { - // getPlane().checkNormal(vertices); - throw new RuntimeException("Failed! the normal provided mismatched to calculated normal "+checkNormal); + if (checkNormal != NormalState.SAME) { + // getPlane().checkNormal(vertices); + throw new RuntimeException("Failed! the normal provided mismatched to calculated normal " + checkNormal); } - + return this; } @@ -488,7 +474,7 @@ public StringBuilder toStlString(StringBuilder sb) { * @param transform the transformation to apply * * @return this polygon - * @throws ColinearPointsException + * @throws ColinearPointsException */ public Polygon transform(Transform transform) throws ColinearPointsException { @@ -497,10 +483,11 @@ public Polygon transform(Transform transform) throws ColinearPointsException { }); Vector3d a = this.getVertices().get(0).pos; - - // Given how the relative locations of the points can change in a scale operations + + // Given how the relative locations of the points can change in a scale + // operations // it is nessissary to reacalculated the normal on operation - this.plane=Plane.createFromPoints(getVertices()); + this.plane = Plane.createFromPoints(getVertices()); // if (transform.isMirror()) { // the transformation includes mirroring. flip polygon @@ -538,14 +525,12 @@ public Polygon transform(Transform transform) throws ColinearPointsException { * * @param transform the transformation to apply * @return a transformed copy of this polygon - * @throws ColinearPointsException + * @throws ColinearPointsException */ public Polygon transformed(Transform transform) throws ColinearPointsException { return clone().transform(transform); } - - /** * Returns the bounds of this polygon. * @@ -664,7 +649,7 @@ public List getPoints() { * * @param howFarToMove the how far to move * @return the csg - * @throws ColinearPointsException + * @throws ColinearPointsException */ // Helper/wrapper functions for movement public Polygon movey(Number howFarToMove) throws ColinearPointsException { @@ -676,7 +661,7 @@ public Polygon movey(Number howFarToMove) throws ColinearPointsException { * * @param howFarToMove the how far to move * @return the csg - * @throws ColinearPointsException + * @throws ColinearPointsException */ public Polygon movez(Number howFarToMove) throws ColinearPointsException { return this.transformed(Transform.unity().translateZ(howFarToMove.doubleValue())); @@ -687,7 +672,7 @@ public Polygon movez(Number howFarToMove) throws ColinearPointsException { * * @param howFarToMove the how far to move * @return the csg - * @throws ColinearPointsException + * @throws ColinearPointsException */ public Polygon movex(Number howFarToMove) throws ColinearPointsException { return this.transformed(Transform.unity().translateX(howFarToMove.doubleValue())); @@ -698,7 +683,7 @@ public Polygon movex(Number howFarToMove) throws ColinearPointsException { * * @param degreesToRotate the degrees to rotate * @return the csg - * @throws ColinearPointsException + * @throws ColinearPointsException */ // Rotation function, rotates the object public Polygon rotz(Number degreesToRotate) throws ColinearPointsException { @@ -710,7 +695,7 @@ public Polygon rotz(Number degreesToRotate) throws ColinearPointsException { * * @param degreesToRotate the degrees to rotate * @return the csg - * @throws ColinearPointsException + * @throws ColinearPointsException */ public Polygon roty(Number degreesToRotate) throws ColinearPointsException { return this.transformed(new Transform().rotY(degreesToRotate.doubleValue())); @@ -721,7 +706,7 @@ public Polygon roty(Number degreesToRotate) throws ColinearPointsException { * * @param degreesToRotate the degrees to rotate * @return the csg - * @throws ColinearPointsException + * @throws ColinearPointsException */ public Polygon rotx(Number degreesToRotate) throws ColinearPointsException { return this.transformed(new Transform().rotX(degreesToRotate.doubleValue())); @@ -732,7 +717,7 @@ public Polygon rotx(Number degreesToRotate) throws ColinearPointsException { * * @param scaleValue the scale value * @return the csg - * @throws ColinearPointsException + * @throws ColinearPointsException */ // Scale function, scales the object public Polygon scalez(Number scaleValue) throws ColinearPointsException { @@ -744,7 +729,7 @@ public Polygon scalez(Number scaleValue) throws ColinearPointsException { * * @param scaleValue the scale value * @return the csg - * @throws ColinearPointsException + * @throws ColinearPointsException */ public Polygon scaley(Number scaleValue) throws ColinearPointsException { return this.transformed(new Transform().scaleY(scaleValue.doubleValue())); @@ -755,7 +740,7 @@ public Polygon scaley(Number scaleValue) throws ColinearPointsException { * * @param scaleValue the scale value * @return the csg - * @throws ColinearPointsException + * @throws ColinearPointsException */ public Polygon scalex(Number scaleValue) throws ColinearPointsException { return this.transformed(new Transform().scaleX(scaleValue.doubleValue())); @@ -766,7 +751,7 @@ public Polygon scalex(Number scaleValue) throws ColinearPointsException { * * @param scaleValue the scale value * @return the csg - * @throws ColinearPointsException + * @throws ColinearPointsException */ public Polygon scale(Number scaleValue) throws ColinearPointsException { return this.transformed(new Transform().scale(scaleValue.doubleValue())); @@ -846,6 +831,12 @@ public Polygon setColor(Color color) { } public Color getColor() { + if (r < 0 || g < 0 || b < 0 || o < 0) { + r = CSG.getDefaultColor().getRed(); + g = CSG.getDefaultColor().getGreen(); + b = CSG.getDefaultColor().getBlue(); + o = CSG.getDefaultColor().getOpacity(); + } return new Color(r, g, b, o); } @@ -927,7 +918,7 @@ public Plane getPlane() { public void setPlane(Plane plane) { if (plane == null) throw new RuntimeException("Plane can not be null!"); - + this.plane = plane; } @@ -941,5 +932,4 @@ public void setVertices(ArrayList vertices) throws ColinearPointsExcepti this.vertices = vertices; } - } diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Vector3d.java b/src/main/java/eu/mihosoft/vrl/v3d/Vector3d.java index 9322885d..0e75a049 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/Vector3d.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/Vector3d.java @@ -51,7 +51,7 @@ * * @author Michael Hoffer <info@michaelhoffer.de> */ -public class Vector3d +public class Vector3d implements Serializable { public double x,y,z; diff --git a/src/main/java/eu/mihosoft/vrl/v3d/ext/imagej/STLLoader.java b/src/main/java/eu/mihosoft/vrl/v3d/ext/imagej/STLLoader.java index 199d38e6..1ca699e3 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/ext/imagej/STLLoader.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/ext/imagej/STLLoader.java @@ -119,7 +119,7 @@ private void parseAscii(File f,ArrayList polygons) { try { Plane pl=null; try { - pl = new Plane(normal, vertices); + pl = new Plane( vertices); }catch(NumberFormatException ex) { pl=Plane.createFromPoints(vertices); } @@ -180,7 +180,7 @@ private void parseBinary(File f, ArrayList polygons,int triangles) { try { Plane pl=null; try { - pl = new Plane(normal, vertices); + pl = new Plane( vertices); }catch(NumberFormatException ex) { System.out.println(" STL has bad Normal "+normal); pl=Plane.createFromPoints(vertices); diff --git a/src/main/java/eu/mihosoft/vrl/v3d/ext/org/poly2tri/PolygonUtil.java b/src/main/java/eu/mihosoft/vrl/v3d/ext/org/poly2tri/PolygonUtil.java index 8efcc9c5..a193a132 100644 --- a/src/main/java/eu/mihosoft/vrl/v3d/ext/org/poly2tri/PolygonUtil.java +++ b/src/main/java/eu/mihosoft/vrl/v3d/ext/org/poly2tri/PolygonUtil.java @@ -614,6 +614,9 @@ public static List transformed(List vertices, Transform transfor public static ArrayList triangulatePolygon(List vertices, PropertyStorage shared, boolean allowDegenerate, Plane p, Color c) throws ColinearPointsException { + if(p==null) { + p=Plane.createFromPoints(vertices); + } ArrayList result = new ArrayList<>(); Vector3d normalOfPlane = p.getNormal().clone(); normalOfPlane.normalize(); diff --git a/src/test/java/eu/mihosoft/vrl/v3d/PolygonClassificationTest.java b/src/test/java/eu/mihosoft/vrl/v3d/PolygonClassificationTest.java index a0dd7b0b..397ed881 100644 --- a/src/test/java/eu/mihosoft/vrl/v3d/PolygonClassificationTest.java +++ b/src/test/java/eu/mihosoft/vrl/v3d/PolygonClassificationTest.java @@ -19,120 +19,14 @@ public void setUp() { storage = new PropertyStorage(); } - @Test - public void testPolygon1_ValidThinTriangle() { - // [[187.5318756104, 115.8620758057, 55.0120964050], - // [187.5318756124, 115.8620758065, 55.0120975630], - // [187.5318756204, 115.8620758109, 55.0120975630]] - // Valid triangle - spans 0.0001 in X and Z - - List vertices = Arrays.asList( - new Vertex(new Vector3d(187.5318756104, 115.8620758057, 55.0120964050)), - new Vertex(new Vector3d(187.5318756124, 115.8620758065, 55.0120975630)), - new Vertex(new Vector3d(187.5318756204, 115.8620758109, 55.0120975630)) - ); - - try { - Polygon polygon = Polygon.fromVertex(vertices, storage, true, null).get(0); - assertNotNull("Polygon should be created successfully", polygon); - assertEquals("Polygon should have 3 vertices", 3, polygon.getVertices().size()); - } catch (Exception e) { - e.printStackTrace(); - fail("Should not throw exception for valid thin triangle: " + e.getMessage()); - } - } + - @Test - public void testPolygon3_ValidWithSmallYSpan() { - // [[10.5246505740, 94.3986129767, 35.0306323972], - // [10.5246505737, 94.3986129761, 35.0306320190], - // [10.5246505768, 94.3986129710, 35.0306323972]] - // Valid - 0.00006 Y span - - List vertices = Arrays.asList( - new Vertex(new Vector3d(10.5246505740, 94.3986129767, 35.0306323972)), - new Vertex(new Vector3d(10.5246505737, 94.3986129761, 35.0306320190)), - new Vertex(new Vector3d(10.5246505768, 94.3986129710, 35.0306323972)) - ); - - try { - Polygon polygon = Polygon.fromVertex(vertices, storage, true, null).get(0); - assertNotNull("Polygon should be created successfully", polygon); - assertEquals("Polygon should have 3 vertices", 3, polygon.getVertices().size()); - } catch (Exception e) { - e.printStackTrace(); - fail("Should not throw exception for valid triangle with small Y span: " + e.getMessage()); - } - } - - @Test - public void testPolygon4_ValidWithXSpan() { - // [[11.3266067492, 93.7161712649, 35.0305217579], - // [11.3266067505, 93.7161712646, 35.0305213928], - // [11.3266067568, 93.7161712643, 35.0305217579]] - // Valid - 0.00008 X span - - List vertices = Arrays.asList( - new Vertex(new Vector3d(11.3266067492, 93.7161712649, 35.0305217579)), - new Vertex(new Vector3d(11.3266067505, 93.7161712646, 35.0305213928)), - new Vertex(new Vector3d(11.3266067568, 93.7161712643, 35.0305217579)) - ); - - try { - Polygon polygon = Polygon.fromVertex(vertices, storage, true, null).get(0); - assertNotNull("Polygon should be created successfully", polygon); - assertEquals("Polygon should have 3 vertices", 3, polygon.getVertices().size()); - } catch (Exception e) { - e.printStackTrace(); - fail("Should not throw exception for valid triangle with X span: " + e.getMessage()); - } - } - - @Test - public void testPolygon5_ValidWithYAndZVariation() { - // [[10.8600692723, 93.9305191077, 55.0305947022], - // [10.8600692758, 93.9305191035, 55.0305947022], - // [10.8600692749, 93.9305191040, 55.0305938721]] - // Valid - Y varies by 0.00004, Z by 0.000008 - - List vertices = Arrays.asList( - new Vertex(new Vector3d(10.8600692723, 93.9305191077, 55.0305947022)), - new Vertex(new Vector3d(10.8600692758, 93.9305191035, 55.0305947022)), - new Vertex(new Vector3d(10.8600692749, 93.9305191040, 55.0305938721)) - ); - - try { - Polygon polygon = Polygon.fromVertex(vertices, storage, true, null).get(0); - assertNotNull("Polygon should be created successfully", polygon); - assertEquals("Polygon should have 3 vertices", 3, polygon.getVertices().size()); - } catch (Exception e) { - fail("Should not throw exception for valid triangle with Y and Z variation: " + e.getMessage()); - } - } + - @Test - public void testPolygon6_ValidWithLargeYZDifferences() { - // [[209.5015258789, 101.1099853516, 128.0972442627], - // [209.5015327416, 101.1190847868, 128.1390783904]] - // Valid - large Y/Z differences (0.009/0.042) - // Note: This appears to be only 2 points in the log, may need a third - - List vertices = Arrays.asList( - new Vertex(new Vector3d(209.5015258789, 101.1099853516, 128.0972442627)), - new Vertex(new Vector3d(209.5015327416, 101.1190847868, 128.1390783904)), - new Vertex(new Vector3d(209.5015327416, 101.1190847961, 128.1390783894)) - ); - - try { - Polygon polygon = Polygon.fromVertex(vertices, storage, true, null).get(0); - assertNotNull("Polygon should be created successfully", polygon); - assertEquals("Polygon should have 3 vertices", 3, polygon.getVertices().size()); - } catch (Exception e) { - fail("Should not throw exception for valid triangle with large Y/Z differences: " + e.getMessage()); - } - } + +