diff --git a/.gitignore b/.gitignore
index c8b7c802..a80040b0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -40,3 +40,7 @@ html
/file.txt
/file2.txt
/public.pgp
+/HoleCut.stl.png
+/Bolt.stl.png
+/hs_err_*.log
+/vows.svg.png
diff --git a/flame.svg b/flame.svg
new file mode 100644
index 00000000..30638c10
--- /dev/null
+++ b/flame.svg
@@ -0,0 +1,47 @@
+
+
+
+
diff --git a/src/main/java/com/piro/bezier/BezierPath.java b/src/main/java/com/piro/bezier/BezierPath.java
index fb44b453..47924fb5 100644
--- a/src/main/java/com/piro/bezier/BezierPath.java
+++ b/src/main/java/com/piro/bezier/BezierPath.java
@@ -7,26 +7,25 @@
import java.util.regex.Pattern;
import eu.mihosoft.vrl.v3d.Edge;
+import eu.mihosoft.vrl.v3d.Extrude;
import eu.mihosoft.vrl.v3d.Plane;
import eu.mihosoft.vrl.v3d.Vector3d;
import eu.mihosoft.vrl.v3d.Vertex;
public class BezierPath {
+ private static final double MaximumInterpolationStep = 0.5;
+
static final Matcher matchPoint = Pattern.compile("\\s*(\\d+)[^\\d]+(\\d+)\\s*").matcher("");
BezierListProducer path;
private ArrayList plInternal = new ArrayList();
- double resolution = 0.075;
+ private final int resolutionPoints;
/** Creates a new instance of Animate */
- public BezierPath() {
- }
-
- /** Creates a new instance of Animate */
- public BezierPath(String path) {
- parsePathString(path);
+ public BezierPath(int resolution) {
+ this.resolutionPoints = resolution;
}
public void parsePathString(String d) {
@@ -57,7 +56,7 @@ protected void parsePathList(String list) {
} else {
tokens.addFirst(curToken);
}
- double x, y;
+ double x, y;
switch (curCmd) {
case 'M':
x = nextFloat(tokens);
@@ -108,53 +107,37 @@ protected void parsePathList(String list) {
break;
case 'Q':
path.curvetoQuadraticAbs(nextFloat(tokens), nextFloat(tokens), nextFloat(tokens), nextFloat(tokens));
- for (double i = resolution; i < 1; i += resolution) {
- addingPoint(i);
- }
+ expandPath();
break;
case 'q':
path.curvetoQuadraticAbs(nextFloat(tokens), nextFloat(tokens), nextFloat(tokens), nextFloat(tokens));
- for (double i = resolution; i < 1; i += resolution) {
- addingPoint(i);
- }
+ expandPath();
break;
case 'T':
path.curvetoQuadraticSmoothAbs(nextFloat(tokens), nextFloat(tokens));
- for (double i = resolution; i < 1; i += resolution) {
- addingPoint(i);
- }
+ expandPath();
break;
case 't':
path.curvetoQuadraticSmoothRel(nextFloat(tokens), nextFloat(tokens));
- for (double i = resolution; i < 1; i += resolution) {
- addingPoint(i);
- }
+ expandPath();
break;
case 'C':
path.curvetoCubicAbs(nextFloat(tokens), nextFloat(tokens), nextFloat(tokens), nextFloat(tokens),
nextFloat(tokens), nextFloat(tokens));
- for (double i = resolution; i < 1; i += resolution) {
- addingPoint(i);
- }
+ expandPath();
break;
case 'c':
path.curvetoCubicRel(nextFloat(tokens), nextFloat(tokens), nextFloat(tokens), nextFloat(tokens),
nextFloat(tokens), nextFloat(tokens));
- for (double i = resolution; i < 1; i += resolution) {
- addingPoint(i);
- }
+ expandPath();
break;
case 'S':
path.curvetoCubicSmoothAbs(nextFloat(tokens), nextFloat(tokens), nextFloat(tokens), nextFloat(tokens));
- for (double i = resolution; i < 1; i += resolution) {
- addingPoint(i);
- }
+ expandPath();
break;
case 's':
path.curvetoCubicSmoothRel(nextFloat(tokens), nextFloat(tokens), nextFloat(tokens), nextFloat(tokens));
- for (double i = resolution; i < 1; i += resolution) {
- addingPoint(i);
- }
+ expandPath();
break;
case 'Z':
case 'z':
@@ -170,22 +153,49 @@ protected void parsePathList(String list) {
}
}
+ private void expandPath() {
+ double resolution = getResolution();
+ for (double i = 0; i < 1; i += resolution) {
+ addingPoint(i);
+ }
+ addingPoint(1);
+ }
+
+ private double getResolution() {
+ Vector3d start = path.bezierSegs.get(path.bezierSegs.size() - 1).eval(0);
+ Vector3d end = path.bezierSegs.get(path.bezierSegs.size() - 1).eval(1);
+ double magnitude = start.minus(end).magnitude();
+ if (magnitude < Plane.getEPSILON())
+ return 1;
+ double dpoints = magnitude /0.75;
+ if (dpoints < 1)
+ dpoints = 1;
+ double increment = 1.0 / dpoints;
+ double min = 1.0 / ((double) resolutionPoints);
+ if (increment < min)
+ increment = min;
+ if (increment > MaximumInterpolationStep)
+ increment = MaximumInterpolationStep;
+// System.out.println("Path with inc "+points);
+ return increment;
+ }
+
private boolean addingPoint(double i) {
Vector3d eval = path.bezierSegs.get(path.bezierSegs.size() - 1).eval(i);
return setThePoint(eval);
}
private boolean setThePoint(Vector3d eval) {
- int end = plInternal.size()-1;
-
- for(Vector3d v:plInternal) {
- if(Math.abs(v.minus(eval).magnitude())<0.001) {
- return false;
+ int end = plInternal.size() - 1;
+ for (int i = 0; i < plInternal.size(); i++)
+ if (end > 0) {
+ if (Math.abs(plInternal.get(i).minus(eval).magnitude()) < Extrude.getMinimumDIstance()) {
+ return false;
+ }
}
- }
- if(plInternal.size()>1) {
- Edge e = new Edge(new Vertex(plInternal.get(end-1),null), new Vertex(plInternal.get(end),null));
- if(e.colinear(eval)) {
+ if (plInternal.size() > 1) {
+ 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;
}
@@ -193,7 +203,7 @@ private boolean setThePoint(Vector3d eval) {
return plInternal.add(eval);
}
- static protected double nextFloat(LinkedList l) {
+ static protected double nextFloat(LinkedList l) {
String s = l.removeFirst();
return Float.parseFloat(s);
}
@@ -202,12 +212,12 @@ static protected double nextFloat(LinkedList l) {
* Evaluates this animation element for the passed interpolation time. Interp
* must be on [0..1].
*/
- public Vector3d eval(double interp) {
+ public Vector3d eval(double interp) {
Vector3d point = new Vector3d(0, 0);// = new Vector3d();
- if (interp < 0.001)
- interp = (double ) 0.001;
- if (interp > 0.9999)
- interp = (double ) 0.9999;
+// if (interp < 0.001)
+// interp = (double ) 0.001;
+// if (interp > 0.9999)
+// interp = (double ) 0.9999;
double curLength = path.curveLength * interp;
for (Iterator it = path.bezierSegs.iterator(); it.hasNext();) {
diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Bounds.java b/src/main/java/eu/mihosoft/vrl/v3d/Bounds.java
index 05dc80f2..a1ae02ca 100644
--- a/src/main/java/eu/mihosoft/vrl/v3d/Bounds.java
+++ b/src/main/java/eu/mihosoft/vrl/v3d/Bounds.java
@@ -162,19 +162,7 @@ public boolean contains(Polygon p) {
return p.getVertices().stream().allMatch(v -> contains(v));
}
- /**
- * Indicates whether the specified polygon intersects with this bounding box
- * (check includes box boundary).
- *
- * @param p polygon to check
- * @return {@code true} if the polygon intersects this bounding box;
- * {@code false} otherwise
- * @deprecated not implemented yet
- */
- @Deprecated
- public boolean intersects(Polygon p) {
- throw new UnsupportedOperationException("Implementation missing!");
- }
+
/**
* Indicates whether the specified bounding box intersects with this
diff --git a/src/main/java/eu/mihosoft/vrl/v3d/CSG.java b/src/main/java/eu/mihosoft/vrl/v3d/CSG.java
index 72afe5bb..cfcd0e49 100644
--- a/src/main/java/eu/mihosoft/vrl/v3d/CSG.java
+++ b/src/main/java/eu/mihosoft/vrl/v3d/CSG.java
@@ -43,6 +43,7 @@
import java.io.IOException;
import java.io.Serializable;
+import java.lang.reflect.Field;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
@@ -52,6 +53,9 @@
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.ForkJoinWorkerThread;
+import java.util.concurrent.TimeUnit;
import java.util.function.BooleanSupplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -61,6 +65,7 @@
import com.aparapi.Range;
import com.aparapi.device.Device;
import com.aparapi.internal.kernel.KernelManager;
+import com.aparapi.internal.kernel.KernelRunner;
import com.neuronrobotics.interaction.CadInteractionEvent;
import javafx.scene.paint.Color;
@@ -128,6 +133,7 @@
@SuppressWarnings("restriction")
public class CSG implements IuserAPI, Serializable {
+ private static final double POINTS_CONTACT_DISTANCE = 0.00001;
private static int MinPolygonsForOffloading = 200;
private static final long serialVersionUID = 4071874097772427063L;
private static IDebug3dProvider providerOf3d = null;
@@ -187,6 +193,7 @@ public void progressUpdate(int currentIndex, int finalIndex, String type, CSG in
System.err.println(type + " cur:" + currentIndex + " of " + finalIndex);
}
};
+ private static ForkJoinPool poolGlobal=null;
/**
* Instantiates a new csg.
@@ -882,27 +889,82 @@ public CSG dumbUnion(CSG csg) {
*
* @return union of this csg and the specified csgs
*/
- public CSG union(List csgs) {
+ public CSG union(List incoming) {
if (CSGClient.isRunning()) {
ArrayList go = new ArrayList();
go.add(this);
- go.addAll(csgs);
+ go.addAll(incoming);
try {
return CSGClient.getClient().union(go).get(0);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
- CSG result = this;
+ CSG solid = this.isHole()?null:this;
+ CSG hole = this.isHole()?this:null;
+ ArrayList csgs=new ArrayList();
+ CSG dumb = null;
+ if(incoming.size()<10) {
+ csgs.addAll(incoming);
+ }else {
+ for( int i=0;i()).historySync(this).historySync(csg);
}
- Node a = new Node(this.clone().getPolygons());
- Node b = new Node(csg.clone().getPolygons());
- a.invert();
- b.clipTo(a);
- b.invert();
- a.clipTo(b);
- b.clipTo(a);
- a.build(b.allPolygons());
- a.invert();
- CSG back = CSG.fromPolygons(a.allPolygons()).optimization(getOptType()).historySync(csg).historySync(this);
- if (getName().length() != 0 && csg.getName().length() != 0) {
- back.setName(name);
+ Node a;
+ try {
+ a = new Node(this.clone().getPolygons(),this.getPolygons().get(0).getPlane());
+ Node b = new Node(csg.clone().getPolygons(),csg.getPolygons().get(0).getPlane());
+ a.invert();
+ b.clipTo(a);
+ b.invert();
+ a.clipTo(b);
+ b.clipTo(a);
+ a.build(b.allPolygons());
+ a.invert();
+ CSG back = CSG.fromPolygons(a.allPolygons()).optimization(getOptType()).historySync(csg).historySync(this);
+ if (getName().length() != 0 && csg.getName().length() != 0) {
+ back.setName(name);
+ }
+ return back;
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
}
- return back;
+ return this;
}
/**
@@ -1559,7 +1643,7 @@ public StringBuilder toStlString(StringBuilder sb) {
sb.append("solid v3d.csg\n");
for (Polygon p : getPolygons()) {
try {
- Plane.computeNormal(p.getVertices());
+ Plane.createFromPoints(p.getVertices(),null);
p.toStlString(sb);
} catch (Exception ex) {
System.out.println("Prune Polygon on export");
@@ -1694,11 +1778,11 @@ private int runGPUMakeManifold(int iteration, int np, int longLength, int numPol
}
// System.out.println("Data loaded!");
- float eps = 0.00001f;
+ float eps = (float)POINTS_CONTACT_DISTANCE;
float epsSq = (float) (eps * eps);
int[] added = new int[numberOfPolygons];
- int testPointChunk = 50;
- int snapChunk = 500;
+ int testPointChunk = 100;
+ int snapChunk = 1000;
int[] tp = new int[] { 0, snapChunk };
// Aparapi-compatible kernel with flattened data
@@ -1986,84 +2070,181 @@ public void run() {
// }
// pointIndexSet.add(pointIndex);
Vector3d thispoint = orderedPoints[pointIndex];
- points.add(new Vertex(thispoint, pl.getNormal()));
+ points.add(new Vertex(thispoint));
}
if (points.size() < 3) {
System.out.println("ERR polygon " + i + " pruned because of too few points");
continue;
}
- Polygon p = new Polygon(points, polygon.getStorage(), true, pl);
- newPoly.add(p);
+ Polygon p;
+ try {
+ p = new Polygon(points, polygon.getStorage(), true, pl);
+ newPoly.add(p);
+ } catch (ColinearPointsException e) {
+ System.out.println("Prining "+points+" "+e);
+ }
polygon.getPoints().clear();
}
polygons.clear();
polygons = newPoly;
return pointsAdded;
}
+ public static List getForkJoinWorkers(ForkJoinPool pool) {
+ return Thread.getAllStackTraces().keySet().stream()
+ .filter(thread -> thread instanceof ForkJoinWorkerThread)
+ .map(thread -> (ForkJoinWorkerThread) thread)
+ .collect(Collectors.toList());
+ }
+ public static void setPrivateThreadPool(KernelRunner kernelRunner, ForkJoinPool newThreadPool) throws Exception {
+ // Get the class of the object
+ Class> clazz = kernelRunner.getClass();
+ // Get the private field
+ Field threadPoolField = clazz.getDeclaredField("threadPool");
+
+ // Make it accessible
+ threadPoolField.setAccessible(true);
+
+ // Set the new value
+ threadPoolField.set(kernelRunner, newThreadPool);
+ }
+
+ public static ForkJoinPool getPrivateThreadPool(KernelRunner kernelRunner) throws Exception {
+ Class> clazz = kernelRunner.getClass();
+ Field threadPoolField = clazz.getDeclaredField("threadPool");
+ threadPoolField.setAccessible(true);
+ return (ForkJoinPool) threadPoolField.get(kernelRunner);
+ }
public static void gpuRun(int numberOfPoints, Kernel kernel, float[] done, String type, BooleanSupplier test,
int itr, int expectedIterations) {
- progressMoniter.progressUpdate(0, 100, "Start " + typOfCPU(kernel) + type, null);
+ // progressMoniter.progressUpdate(0, 100, "Start " + typOfCPU(kernel) + type,
+ // null);
+ String valueOf = String.valueOf(Runtime.getRuntime().availableProcessors() );
+ System.setProperty("com.aparapi.threadPoolSize", valueOf);
if (!useGPU) {
- String valueOf = String.valueOf(Runtime.getRuntime().availableProcessors() * 4);
progressMoniter.progressUpdate(0, 100, "CPU mode " + valueOf, null);
- System.setProperty("com.aparapi.threadPoolSize", valueOf);
kernel.setExecutionMode(Kernel.EXECUTION_MODE.JTP); // Java Thread Pool
}
int[] iteration = new int[] { 0 };
- Thread thread = new Thread(() -> {
- long begin = System.currentTimeMillis();
+ long begin = System.currentTimeMillis();
+ boolean print = false;
+ long timeSinceLastPrint = 0;
+ long printLimit = 800;
+ String typOfCPU = typOfCPU(kernel);
+// ForkJoinPool commonPool = ForkJoinPool.commonPool();
+// System.out.println("Common ForkJoinPool Status:");
+// System.out.println(" Pool Size: " + commonPool.getPoolSize());
+// System.out.println(" Active Thread Count: " + commonPool.getActiveThreadCount());
+// System.out.println(" Running Thread Count: " + commonPool.getRunningThreadCount());
+// System.out.println(" Queued Task Count: " + commonPool.getQueuedTaskCount());
+// System.out.println(" Queued Submission Count: " + commonPool.getQueuedSubmissionCount());
+// System.out.println(" Steal Count: " + commonPool.getStealCount());
+// System.out.println(" Parallelism: " + commonPool.getParallelism());
+// System.out.println(" Is Shutdown: " + commonPool.isShutdown());
+// System.out.println(" Is Terminated: " + commonPool.isTerminated());
+// List workersInitial=null;
+// try {
+//
+// workersInitial = getForkJoinWorkers(commonPool);
+//
+// if (workersInitial != null) {
+// System.out.println("Worker threads in pool:");
+// for (int i = 0; i < workersInitial.size(); i++) {
+// ForkJoinWorkerThread worker = workersInitial.get(i);
+// if (worker != null) {
+// System.out.println(" Worker[" + i + "]: " + worker.getName() +
+// " | State: " + worker.getState() +
+// " | Pool Index: " + worker.getPoolIndex() +
+// " | ID: " + worker.getId());
+// }
+// }
+// }
+// }catch(Exception ex) {
+// ex.printStackTrace();
+// }
+ try {
do {
- kernel.execute(numberOfPoints);
+ KernelRunner kernelRunner = new KernelRunner(kernel);
+ if(poolGlobal==null)
+ poolGlobal=getPrivateThreadPool(kernelRunner);
+ else
+ setPrivateThreadPool(kernelRunner, poolGlobal);
+
+ kernelRunner.execute("run", Range.create(null,numberOfPoints), 1);
+ typOfCPU = typOfCPU(kernel);
iteration[0] += 1;
- long sinceStart = System.currentTimeMillis() - begin;
+ long now = System.currentTimeMillis();
+ long sinceStart = now - begin;
long took = sinceStart / iteration[0];
long expected = took * (expectedIterations + 2);
- long remaining = expected - sinceStart;
- for (int i = 0; i < done.length; i++) {
- done[i] = 0;
+ print = expected > printLimit || print;
+ if (print) {
+ if (now - timeSinceLastPrint > printLimit) {
+ timeSinceLastPrint = now;
+ long remaining = expected - sinceStart;
+ if (done != null)
+ for (int i = 0; i < done.length; i++) {
+ done[i] = 0;
+ }
+ if (remaining < 0)
+ remaining = 0;
+ String dur = makeTimestamp(expected);
+ String rem = makeTimestamp(remaining);
+ progressMoniter.progressUpdate(iteration[0], expectedIterations, "Rem->" + rem + " " + type
+ + typOfCPU + " \nTot->" + dur, null);
+ }
}
- if (remaining < 0)
- remaining = 0;
- String dur = makeTimestamp(expected);
- String rem = makeTimestamp(remaining);
- progressMoniter.progressUpdate(iteration[0], expectedIterations, "Rem->" + rem + " " + type
- + typOfCPU(kernel) + "(" + iteration[0] + ") Estimated Total: " + dur, null);
+
} while (test.getAsBoolean());
- });
- thread.start();
- do {
- if (kernel.getTargetDevice().getType().toString().contains("JTP")) {
- useGPU = false;
- }
- if (!useGPU) {
- float doneness = 0;
- for (int i = 0; i < done.length; i++) {
- doneness += done[i];
- }
- float percent = doneness / ((float) done.length) * 100.0f;
- // int currentPass = kernel.getCurrentPass();
- // percent=(float)currentPass/(float)numberOfPoints;
- if (expectedIterations == 1)
- progressMoniter.progressUpdate((int) (percent), 100,
- typOfCPU(kernel) + type + "(" + iteration[0] + ")", null);
- }
- try {
- Thread.sleep(useGPU ? 1 : 100);
- } catch (InterruptedException e) {
- // Auto-generated catch block
- e.printStackTrace();
- }
- } while (kernel.isExecuting() && thread.isAlive());
- try {
- thread.join();
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
+ } catch (Exception ex) {
+ ex.printStackTrace();
}
- progressMoniter.progressUpdate(100, 100, "Finished on " + typOfCPU(kernel), null);
+// commonPool.awaitQuiescence(10, TimeUnit.MILLISECONDS);
+// List workers=null;
+// List workersInit=workersInitial;
+// try {
+// workers = getForkJoinWorkers(commonPool).stream()
+// .filter(afterThread -> workersInit.stream()
+// .noneMatch(beforeThread -> beforeThread.getId() == afterThread.getId()))
+// .collect(Collectors.toList());;
+//
+// if (workers != null) {
+// System.out.println("After Worker threads in pool:");
+// for (int i = 0; i < workers.size(); i++) {
+// ForkJoinWorkerThread worker = workers.get(i);
+// if (worker != null) {
+// System.out.println(" Worker[" + i + "]: " + worker.getName() +
+// " | State: " + worker.getState() +
+// " | Pool Index: " + worker.getPoolIndex() +
+// " | ID: " + worker.getId());
+// worker.interrupt();
+// }
+// }
+// }
+// }catch(Exception ex) {
+// ex.printStackTrace();
+// }
+// System.out.println("\n2 Common ForkJoinPool Status:");
+// System.out.println(" 2 Pool Size: " + commonPool.getPoolSize());
+// System.out.println(" 2 Active Thread Count: " + commonPool.getActiveThreadCount());
+// System.out.println(" 2 Running Thread Count: " + commonPool.getRunningThreadCount());
+// System.out.println(" 2 Queued Task Count: " + commonPool.getQueuedTaskCount());
+// System.out.println(" 2 Queued Submission Count: " + commonPool.getQueuedSubmissionCount());
+// System.out.println(" 2 Steal Count: " + commonPool.getStealCount());
+// System.out.println(" 2 Parallelism: " + commonPool.getParallelism());
+// System.out.println(" 2 Is Shutdown: " + commonPool.isShutdown());
+// System.out.println(" 2 Is Terminated: " + commonPool.isTerminated());
+ boolean executing ;
+ do {
+ executing=kernel.isExecuting();
+ }while(executing );
+ long sinceStart = System.currentTimeMillis() - begin;
+ if (print)
+ progressMoniter.progressUpdate(100, 100,
+ "Took " + makeTimestamp(sinceStart) + " Finished " + type + " on " + typOfCPU, null);
+
}
private static String typOfCPU(Kernel kernel) {
@@ -2076,8 +2257,15 @@ private static String makeTimestamp(long expected) {
long hours = duration.toHours();
long minutes = duration.toMinutes() % 60;
long seconds = duration.getSeconds() % 60;
-
- String dur = String.format("%02d:%02d:%02d", hours, minutes, seconds);
+ long ms = duration.getNano() / 1000000;
+ if (hours > 0) {
+ return String.format("h%02d:m%02d", hours, minutes);
+ }
+ if (minutes > 0)
+ return String.format("m%02d:s%02d", minutes, seconds);
+ if (seconds > 0)
+ return String.format("s%02d:ms%03d", seconds, ms);
+ String dur = String.format("ms%03d", ms);
return dur;
}
@@ -2087,22 +2275,17 @@ private void updatePolygons(ArrayList toAdd, Polygon p) {
toAdd.add(p);
} else {
- try {
- if (!p.areAllPointsCollinear()) {
- List triangles = PolygonUtil.concaveToConvex(p);
+
+ List triangles;
+ try {
+ triangles = PolygonUtil.triangulatePolygon(p);
for (Polygon poly : triangles) {
toAdd.add(poly);
}
- } else {
- System.err.println("Polygon is colinear, removing " + p);
- return;
+ } catch (ColinearPointsException e) {
+ System.out.println(e.getMessage()+" Polygon pruned "+p);
}
- } catch (Throwable ex) {
-// System.err.println("Failed to triangulate "+p);
- ex.printStackTrace();
- progressMoniter.progressUpdate(1, 1, "Pruning bad polygon CSG::updatePolygons " + p, null);
- return;
- }
+
}
return;
@@ -2170,8 +2353,8 @@ public PolygonStruct(PropertyStorage storage, List indices, String mate
int startingIndex = vertices.size() + 1;
sb.append("\n# Reference Datum").append("\n");
for (Transform t : datumReferences) {
- Vertex v = new Vertex(new Vector3d(0, 0, 0), new Vector3d(0, 0, 1)).transform(t);
- Vertex v1 = new Vertex(new Vector3d(0, 0, 1), new Vector3d(0, 0, 1)).transform(t);
+ Vertex v = new Vertex(new Vector3d(0, 0, 0)).transform(t);
+ Vertex v1 = new Vertex(new Vector3d(0, 0, 1)).transform(t);
mapping.put(v, startingIndex++);
mapping.put(v1, startingIndex++);
mappingTF.put(t, v);
@@ -2246,7 +2429,7 @@ public CSG transformed(Transform transform) {
return p.transformed(transform);
} catch (Exception e) {
// e.printStackTrace();
- System.err.println("Removing Polygon during transform");
+ System.err.println("Removing Polygon during transform " + p);
return null;
}
}).filter(Objects::nonNull).collect(Collectors.toCollection(ArrayList::new));
@@ -3748,7 +3931,7 @@ public static boolean isPreventNonManifoldTriangles() {
public static void setPreventNonManifoldTriangles(boolean preventNonManifoldTriangles) {
if (!preventNonManifoldTriangles) {
- if(!warned)
+ if (!warned)
System.err.println(
"WARNING:This will make STL's incompatible with low quality slicing engines like Slice3r and PrusaSlicer");
warned=true;
@@ -3765,6 +3948,8 @@ public static void setUseGPU(boolean useGPU) {
}
public boolean isBoundsTouching(CSG incoming) {
+ if(incoming==null)
+ return false;
return getBounds().isBoundsTouching(incoming.getBounds());
}
diff --git a/src/main/java/eu/mihosoft/vrl/v3d/ColinearPointsException.java b/src/main/java/eu/mihosoft/vrl/v3d/ColinearPointsException.java
new file mode 100644
index 00000000..2d888a4e
--- /dev/null
+++ b/src/main/java/eu/mihosoft/vrl/v3d/ColinearPointsException.java
@@ -0,0 +1,11 @@
+package eu.mihosoft.vrl.v3d;
+
+public class ColinearPointsException extends Exception {
+
+ public ColinearPointsException(String string) {
+ super(string);
+ }
+
+ private static final long serialVersionUID = -4762994948568812906L;
+
+}
diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Cube.java b/src/main/java/eu/mihosoft/vrl/v3d/Cube.java
index 760078d2..96d1c52f 100644
--- a/src/main/java/eu/mihosoft/vrl/v3d/Cube.java
+++ b/src/main/java/eu/mihosoft/vrl/v3d/Cube.java
@@ -143,13 +143,14 @@ public List toPolygons() {
center.y + dimensions.y * (1 * Math.min(1, i & 2) - 0.5),
center.z + dimensions.z * (1 * Math.min(1, i & 4) - 0.5)
);
- vertices.add(new Vertex(pos, new Vector3d(
- (double) info[1][0],
- (double) info[1][1],
- (double) info[1][2]
- )));
+ vertices.add(new Vertex(pos));
}
- polygons.add(new Polygon(vertices, properties));
+ try {
+ polygons.add(new Polygon(vertices, properties));
+ } catch (ColinearPointsException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
}
if (!centered) {
@@ -157,7 +158,12 @@ public List toPolygons() {
Transform centerTransform = Transform.unity().translate(dimensions.x / 2.0, dimensions.y / 2.0, dimensions.z / 2.0);
for (Polygon p : polygons) {
- p.transform(centerTransform);
+ try {
+ p.transform(centerTransform);
+ } catch (ColinearPointsException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
}
}
diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Cylinder.java b/src/main/java/eu/mihosoft/vrl/v3d/Cylinder.java
index 2816c696..77a9ed47 100644
--- a/src/main/java/eu/mihosoft/vrl/v3d/Cylinder.java
+++ b/src/main/java/eu/mihosoft/vrl/v3d/Cylinder.java
@@ -227,32 +227,47 @@ public List toPolygons() {
final Vector3d axisX = new Vector3d(isY ? 1 : 0, !isY ? 1 : 0, 0).
cross(axisZ).normalized();
final Vector3d axisY = axisX.cross(axisZ).normalized();
- Vertex startV = new Vertex(s, axisZ.negated());
- Vertex endV = new Vertex(e, axisZ.normalized());
+ Vertex startV = new Vertex(s);
+ Vertex endV = new Vertex(e);
List polygons = new ArrayList<>();
for (int i = 0; i < numSlices; i++) {
double t0 = i / (double) numSlices, t1 = (i + 1) / (double) numSlices;
- polygons.add(new Polygon(Arrays.asList(
- startV,
- cylPoint(axisX, axisY, axisZ, ray, s, startRadius, 0, t0, -1),
- cylPoint(axisX, axisY, axisZ, ray, s, startRadius, 0, t1, -1)),
- properties
- ));
- polygons.add(new Polygon(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
- ));
- polygons.add(new Polygon(
- Arrays.asList(
- endV,
- cylPoint(axisX, axisY, axisZ, ray, s, endRadius, 1, t1, 1),
- cylPoint(axisX, axisY, axisZ, ray, s, endRadius, 1, t0, 1)),
- properties
- ));
+ try {
+ polygons.add(new Polygon(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) {
+ // TODO Auto-generated catch block
+ e1.printStackTrace();
+ }
+ try {
+ polygons.add(new Polygon(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) {
+ // TODO Auto-generated catch block
+ e1.printStackTrace();
+ }
+ try {
+ polygons.add(new Polygon(
+ 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) {
+ // TODO Auto-generated catch block
+ e1.printStackTrace();
+ }
}
return polygons;
@@ -279,7 +294,7 @@ private Vertex cylPoint(
Vector3d out = axisX.times(Math.cos(angle)).plus(axisY.times(Math.sin(angle)));
Vector3d pos = s.plus(ray.times(stack)).plus(out.times(r));
Vector3d normal = out.times(1.0 - Math.abs(normalBlend)).plus(axisZ.times(normalBlend));
- return new Vertex(pos, normal);
+ return new Vertex(pos);
}
/**
diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Edge.java b/src/main/java/eu/mihosoft/vrl/v3d/Edge.java
index d2fb55c4..922c3e6c 100644
--- a/src/main/java/eu/mihosoft/vrl/v3d/Edge.java
+++ b/src/main/java/eu/mihosoft/vrl/v3d/Edge.java
@@ -118,16 +118,12 @@ public static List toPoints(List edges) {
* @param plane the plane
* @return the polygon
*/
- public static Polygon toPolygon(List points, Plane plane) {
+ 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);
- p.getVertices().stream().forEachOrdered((vertex) -> {
- vertex.normal = plane.getNormal().clone();
- });
-
// // we try to detect wrong orientation by comparing normals
// if (p.plane.normal.angle(plane.normal) > 0.1) {
// p.flip();
@@ -141,8 +137,9 @@ public static Polygon toPolygon(List points, Plane plane) {
* @param boundaryEdges the boundary edges
* @param plane the plane
* @return the list
+ * @throws ColinearPointsException
*/
- public static List toPolygons(List boundaryEdges, Plane plane) {
+ public static List toPolygons(List boundaryEdges, Plane plane) throws ColinearPointsException {
List boundaryPath = new ArrayList<>();
@@ -406,7 +403,7 @@ public static List boundaryPathsWithHoles(List boundaryPaths)
* @param boundaryEdges boundary edges (all paths must be closed)
* @return the list
*/
- public static List boundaryPaths(List boundaryEdges) {
+ public static List boundaryPaths(List boundaryEdges) throws ColinearPointsException{
List result = new ArrayList<>();
boolean[] used = new boolean[boundaryEdges.size()];
@@ -489,8 +486,9 @@ private static int nextUnused(boolean[] usage) {
* @param boundaryEdges the boundary edges
* @param plane the plane
* @return the list
+ * @throws ColinearPointsException
*/
- public static List _toPolygons(List boundaryEdges, Plane plane) {
+ public static List _toPolygons(List boundaryEdges, Plane plane) throws ColinearPointsException {
List boundaryPath = new ArrayList<>();
@@ -533,11 +531,11 @@ public static List _toPolygons(List boundaryEdges, Plane plane) {
* false otherwise
*/
public boolean colinear(Vector3d p) {
- return colinear(p, Plane.EPSILON_Point);
+ return colinear(p, Plane.getEPSILON_Point());
}
public boolean colinear(Edge p) {
- return colinear(p.getP1().pos, Plane.EPSILON_Point) && colinear(p.getP2().pos, Plane.EPSILON_Point);
+ return colinear(p.getP1().pos, Plane.getEPSILON_Point()) && colinear(p.getP2().pos, Plane.getEPSILON_Point());
}
@@ -637,7 +635,7 @@ public boolean contains(Vector3d p, double TOL) {
double t = dotProduct / edgeLengthSq;
// If 0 ≤ t ≤ 1, the point is within the bounds of the edge
- return t >= 0 && t <= 1;
+ return t > 0 && t < 1;
}
/**
@@ -678,12 +676,12 @@ public boolean equals(Object obj) {
return false;
}
final Edge other = (Edge) obj;
- if (this.p1.pos.test(other.p1.pos, Plane.EPSILON_Point)
- && this.p2.pos.test(other.p2.pos, Plane.EPSILON_Point)) {
+ if (this.p1.pos.test(other.p1.pos, Plane.getEPSILON_Point())
+ && this.p2.pos.test(other.p2.pos, Plane.getEPSILON_Point())) {
return true;
}
- if (this.p1.pos.test(other.p2.pos, Plane.EPSILON_Point)
- && this.p2.pos.test(other.p1.pos, Plane.EPSILON_Point)) {
+ if (this.p1.pos.test(other.p2.pos, Plane.getEPSILON_Point())
+ && this.p2.pos.test(other.p1.pos, Plane.getEPSILON_Point())) {
return true;
}
if (!(Objects.equals(this.p1, other.p1) || Objects.equals(this.p2, other.p1))) {
@@ -781,7 +779,7 @@ public Optional getIntersection(Edge e) {
Vector3d closestP = closestPOpt.get();
- if (e.contains(closestP)) {
+ if (e.contains(closestP, Plane.getEPSILON())) {
return closestPOpt;
} else {
// intersection point outside of segment
@@ -812,8 +810,9 @@ public Optional getCrossingPoint(Edge e) {
*
* @param csg the csg
* @return the list
+ * @throws ColinearPointsException
*/
- public static List boundaryPolygons(CSG csg) {
+ public static List boundaryPolygons(CSG csg) throws ColinearPointsException {
List result = new ArrayList<>();
for (List polygonGroup : searchPlaneGroups(csg.getPolygons())) {
@@ -874,7 +873,7 @@ public static List boundaryEdgesOfPlaneGroup(List planeGroup) {
}
List realBndEdges = bndEdgeStream
- .filter(be -> edges.stream().filter(e -> falseBoundaryEdgeSharedWithOtherEdge(be, e)).count() == 0)
+ .filter(be -> edges.stream().filter(e -> falseBoundaryEdgeSharedWithOtherEdge(be, e)!=null).count() == 0)
.collect(Collectors.toList());
//
@@ -889,8 +888,9 @@ public static List boundaryEdgesOfPlaneGroup(List planeGroup) {
*
* @param planeGroup the plane group
* @return the list
+ * @throws ColinearPointsException
*/
- private static List boundaryPolygonsOfPlaneGroup(List planeGroup) {
+ private static List boundaryPolygonsOfPlaneGroup(List planeGroup) throws ColinearPointsException {
List polygons = boundaryPathsWithHoles(boundaryPaths(boundaryEdgesOfPlaneGroup(planeGroup)));
@@ -905,42 +905,48 @@ private static List boundaryPolygonsOfPlaneGroup(List planeGro
if (!holesOfPresult.isPresent()) {
result.add(p);
} else {
- result.addAll(PolygonUtil.concaveToConvex(p));
+ result.addAll(PolygonUtil.triangulatePolygon(p));
}
}
return result;
}
- /**
- * False boundary edge shared with other edge.
- *
- * @param fbe the fbe
- * @param e the e
- * @return true, if successful
- */
- public static boolean falseBoundaryEdgeSharedWithOtherEdge(Edge fbe, Edge e) {
+ public static Vertex falseBoundaryEdgeSharedWithOtherEdge(Edge fbe, Edge e) {
// we don't consider edges with shared end-points since we are only
// interested in "false-boundary-edge"-cases
- boolean sharedEndPointsp1 = e.getP1().pos.test(fbe.getP1().pos) || e.getP1().pos.test(fbe.getP2().pos);
+ boolean test1 = e.getP1().pos.test(fbe.getP1().pos);
+ boolean test3 = e.getP1().pos.test(fbe.getP2().pos);
+ boolean sharedEndPointsp1 = test1 || test3;
- boolean sharedP2= e.getP2().pos.test(fbe.getP1().pos) || e.getP2().pos.test(fbe.getP2().pos);
+ boolean test = e.getP2().pos.test(fbe.getP1().pos);
+ boolean test2 = e.getP2().pos.test(fbe.getP2().pos);
+ boolean sharedP2= test || test2;
boolean containsP2 = fbe.contains(e.getP2().pos);
boolean containsP1 = fbe.contains(e.getP1().pos);
- if(containsP2||containsP1) {
+ if(sharedEndPointsp1 && sharedP2) {
//System.out.println("Edge Contains point!");
}
- if ((!sharedP2) && containsP2) {
- return true;
+ if ((sharedP2) && containsP1) {
+ return e.getP2();
}
- if ((!sharedEndPointsp1) && containsP1) {
- return true;
+ if ((sharedEndPointsp1) && containsP2) {
+ return e.getP1();
}
- return false;//fbe.contains(e.getP1().pos) || fbe.contains(e.getP2().pos);
+ return null;
}
+//
+// /** Distance from point r to the infinite line through a → b */
+// private static double distancePointToLine(Vector3d r, Vector3d a, Vector3d b) {
+// Vector3d ab = b.minus(a);
+// Vector3d ar = r.minus(a);
+// Vector3d cross = ab.cross(ar);
+// return cross.length() / ab.length();
+// }
+
/**
* Search plane groups.
diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Extrude.java b/src/main/java/eu/mihosoft/vrl/v3d/Extrude.java
index a84dff94..2cb9f53c 100644
--- a/src/main/java/eu/mihosoft/vrl/v3d/Extrude.java
+++ b/src/main/java/eu/mihosoft/vrl/v3d/Extrude.java
@@ -37,6 +37,8 @@
import com.piro.bezier.BezierPath;
import eu.mihosoft.vrl.v3d.Transform;
import eu.mihosoft.vrl.v3d.svg.*;
+import javafx.scene.paint.Color;
+
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -53,6 +55,7 @@
* @author Michael Hoffer <info@michaelhoffer.de>
*/
public class Extrude {
+ private static double MINIMUM_DISTANCE = 0.005;
private static IExtrusion extrusionEngine = new IExtrusion() {
/**
* Extrudes the specified path (convex or concave polygon without holes or
@@ -62,12 +65,13 @@ public class Extrude {
* @param points path (convex or concave polygon without holes or intersections)
*
* @return a CSG object that consists of the extruded polygon
+ * @throws ColinearPointsException
*/
- public CSG points(Vector3d dir, List points) {
+ public CSG points(Vector3d dir, List points) throws ColinearPointsException {
List newList = new ArrayList<>(points);
-
- return extrude(dir, Polygon.fromPoints(toCCW(newList)));
+ Polygon fromPoints = Polygon.fromPoints(toCCW(newList));
+ return extrude(dir, fromPoints);
}
/**
@@ -79,56 +83,42 @@ public CSG points(Vector3d dir, List points) {
*/
public CSG extrude(Vector3d dir, Polygon polygon1) {
- return monotoneExtrude(dir, polygon1);
+ try {
+ return monotoneExtrude(dir, polygon1);
+ } catch (ColinearPointsException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ return new Cube(10).toCSG().setColor(Color.PINK);
}
- private CSG monotoneExtrude(Vector3d dir, Polygon polygon1) {
+
+ private CSG monotoneExtrude(Vector3d dir, Polygon polygon1) throws ColinearPointsException {
ArrayList newPolygons = new ArrayList<>();
CSG extrude;
- //polygon1=polygon1.flipped();
-// List newVertices = new ArrayList<>();
-// polygon1.getVertices().forEach((vertex) -> {
-// newVertices.add(vertex.clone());
-// });
-// Polygon top= new Polygon(newVertices, polygon1.getStorage(),true,polygon1.getPlane().clone()).setColor(polygon1.getColor());
- Polygon top=polygon1.flipped();
- newPolygons.addAll(PolygonUtil.concaveToConvex(top));
- Polygon polygon2 = polygon1.transformed(new Transform().move(dir));
-
- int numvertices = polygon1.getVertices().size();
- //com.neuronrobotics.sdk.common.Log.error("Building Polygon "+polygon1.getPoints().size());
- for (int i = 0; i < numvertices; i++) {
-
- int nexti = (i + 1) % numvertices;
-
- Vector3d bottomV1 = polygon1.getVertices().get(i).pos;
- Vector3d topV1 = polygon2.getVertices().get(i).pos;
- Vector3d bottomV2 = polygon1.getVertices().get(nexti).pos;
- Vector3d topV2 = polygon2.getVertices().get(nexti).pos;
- double distance = bottomV1.minus(bottomV2).magnitude();
- if(Math.abs(distance)<0.001) {
- //com.neuronrobotics.sdk.common.Log.error("Skipping invalid polygon "+i+" to "+nexti);
- continue;
- }
- try {
- newPolygons.add(Polygon.fromPoints(Arrays.asList(bottomV2, topV2, topV1), polygon1.getStorage()));
- newPolygons.add(Polygon.fromPoints(Arrays.asList(bottomV2, topV1, bottomV1), polygon1.getStorage()));
- }catch(Exception ex) {
- //com.neuronrobotics.sdk.common.Log.error("Polygon has problems: ");
- ex.printStackTrace();
- }
+ ArrayList triangulatePolygon = PolygonUtil.triangulatePolygon(polygon1);
+ for(Polygon p:triangulatePolygon) {
+ newPolygons.add(p.flipped());
+ 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);
- ArrayList topPolygons = PolygonUtil.concaveToConvex(polygon2);
-
- newPolygons.addAll(topPolygons);
+ //ArrayList topPolygons = PolygonUtil.triangulatePolygon(polygon2);
+
extrude = CSG.fromPolygons(newPolygons);
-
return extrude;
}
@Override
public CSG extrude(Vector3d dir, List points) {
- return points(dir, points);
+ try {
+ return points(dir, points);
+ } catch (ColinearPointsException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ return new Cube(10).toCSG().setColor(Color.PINK);
}
};
@@ -139,76 +129,9 @@ private Extrude() {
throw new AssertionError("Don't instantiate me!", null);
}
- public static CSG polygons(Polygon polygon1, Number zDistance) {
- return polygons(polygon1, polygon1.transformed(new Transform().movez(zDistance)));
- }
-
- public static CSG polygons(Polygon polygon1, Polygon polygon2) {
- // if(!isCCW(polygon1)) {
- // polygon1=Polygon.fromPoints(toCCW(polygon1.getPoints()));
- // }
- // if(!isCCW(polygon2)) {
- // polygon2=Polygon.fromPoints(toCCW(polygon2.getPoints()));
- // }
-
- ArrayList newPolygons = new ArrayList<>();
- CSG extrude;
- newPolygons.addAll(PolygonUtil.concaveToConvex(polygon1.flipped()));
- if (polygon1.getVertices().size() != polygon2.getVertices().size()) {
- throw new RuntimeException("These polygons do not match");
- }
- int numvertices = polygon1.getVertices().size();
- for (int i = 0; i < numvertices; i++) {
- int nexti = (i + 1) % numvertices;
-
- Vector3d bottomV1 = polygon1.getVertices().get(i).pos;
- Vector3d topV1 = polygon2.getVertices().get(i).pos;
- Vector3d bottomV2 = polygon1.getVertices().get(nexti).pos;
- Vector3d topV2 = polygon2.getVertices().get(nexti).pos;
-
- List pPoints = Arrays.asList(bottomV2, topV2, topV1, bottomV1);
-
- newPolygons.add(Polygon.fromPoints(pPoints, polygon1.getStorage()));
-
- }
-
- polygon2 = polygon2.flipped();
- List topPolygons = PolygonUtil.concaveToConvex(polygon2.flipped());
-
- newPolygons.addAll(topPolygons);
- extrude = CSG.fromPolygons(newPolygons);
-
- return extrude;
- }
-
- public static ArrayList polygons(eu.mihosoft.vrl.v3d.Polygon polygon1, ArrayList transforms) {
- if (transforms.size() == 1)
- transforms.add(0, new Transform());
- polygon1 = Polygon.fromPoints(toCCW(polygon1.getPoints()));
- if (transforms.size() < 2) {
- transforms.add(0, new Transform());
- }
- ArrayList parts = new ArrayList<>();
- Transform transform = new Transform();
- // transform.rotY(90);
- for (int i = 0; i < transforms.size() - 1; i++) {
- CSG tmp = polygons(polygon1.transformed(transform).transformed(transforms.get(i)),
- polygon1.transformed(transform).transformed(transforms.get(i + 1)));
- parts.add(tmp);
- }
- return parts;
-
- }
-
- public static ArrayList polygons(eu.mihosoft.vrl.v3d.Polygon polygon1, Transform... transformparts) {
-
- return polygons(polygon1, (ArrayList) Arrays.asList(transformparts));
-
- }
-
- public static CSG points(Vector3d dir, List points) {
+ public static CSG points(Vector3d dir, List points) throws ColinearPointsException {
return getExtrusionEngine().extrude(dir, points);
}
@@ -221,8 +144,9 @@ public static CSG points(Vector3d dir, List points) {
* @param points path (convex or concave polygon without holes or intersections)
*
* @return a CSG object that consists of the extruded polygon
+ * @throws ColinearPointsException
*/
- public static CSG points(Vector3d dir, Vector3d... points) {
+ public static CSG points(Vector3d dir, Vector3d... points) throws ColinearPointsException {
return points(dir, Arrays.asList(points));
}
@@ -232,12 +156,13 @@ public static CSG points(Vector3d dir, Vector3d... points) {
*
* @param points the points
* @return the list
+ * @throws ColinearPointsException
*/
- public static List toCCW(List points) {
+ public static List toCCW(List points) throws ColinearPointsException {
List result = new ArrayList<>(points);
- if (!isCCW(Polygon.fromPoints(result))) {
+ if (!isCCWv3d(result)) {
Collections.reverse(result);
}
@@ -249,12 +174,13 @@ public static List toCCW(List points) {
*
* @param points the points
* @return the list
+ * @throws ColinearPointsException
*/
- static List toCW(List points) {
+ static List toCW(List points) throws ColinearPointsException {
List result = new ArrayList<>(points);
- if (isCCW(Polygon.fromPoints(result))) {
+ if (isCCWv3d(result)) {
Collections.reverse(result);
}
@@ -266,65 +192,108 @@ static List toCW(List points) {
*
* @param polygon the polygon
* @return true, if is ccw
+ * @throws ColinearPointsException
*/
- public static boolean isCCW(Polygon polygon) {
-
- // thanks to Sepp Reiter for explaining me the algorithm!
-
- if (polygon.getVertices().size() < 3) {
- throw new IllegalArgumentException("Only polygons with at least 3 vertices are supported!");
- }
-
- // search highest left vertex
- int highestLeftVertexIndex = 0;
- Vertex highestLeftVertex = polygon.getVertices().get(0);
- for (int i = 0; i < polygon.getVertices().size(); i++) {
- Vertex v = polygon.getVertices().get(i);
-
- if (v.pos.y > highestLeftVertex.pos.y) {
- highestLeftVertex = v;
- highestLeftVertexIndex = i;
- } else if (v.pos.y == highestLeftVertex.pos.y && v.pos.x < highestLeftVertex.pos.x) {
- highestLeftVertex = v;
- highestLeftVertexIndex = i;
- }
- }
-
- // determine next and previous vertex indices
- int nextVertexIndex = (highestLeftVertexIndex + 1) % polygon.getVertices().size();
- int prevVertexIndex = highestLeftVertexIndex - 1;
- if (prevVertexIndex < 0) {
- prevVertexIndex = polygon.getVertices().size() - 1;
- }
- Vertex nextVertex = polygon.getVertices().get(nextVertexIndex);
- Vertex prevVertex = polygon.getVertices().get(prevVertexIndex);
-
- // edge 1
- double a1 = normalizedX(highestLeftVertex.pos, nextVertex.pos);
-
- // edge 2
- double a2 = normalizedX(highestLeftVertex.pos, prevVertex.pos);
-
- // select vertex with lowest x value
- int selectedVIndex;
-
- if (a2 > a1) {
- selectedVIndex = nextVertexIndex;
- } else {
- selectedVIndex = prevVertexIndex;
- }
-
- if (selectedVIndex == 0 && highestLeftVertexIndex == polygon.getVertices().size() - 1) {
- selectedVIndex = polygon.getVertices().size();
- }
-
- if (highestLeftVertexIndex == 0 && selectedVIndex == polygon.getVertices().size() - 1) {
- highestLeftVertexIndex = polygon.getVertices().size();
- }
+ public static boolean isCCW(Polygon polygon) throws ColinearPointsException {
+ return isCCWv3d(polygon.getPoints());
+ }
+ /**
+ * Checks if is ccw.
+ *
+ * @param polygon the polygon
+ * @return true, if is ccw
+ * @throws ColinearPointsException
+ */
+ public static boolean isCCW(List vertices) throws ColinearPointsException {
+ return isCCW(vertices, new Vector3d(0, 0,1));
+ }
+ /**
+ * Checks if is ccw.
+ *
+ * @param polygon the polygon
+ * @param normal the normal to check the CCW against.
+ * @return true, if is ccw
+ * @throws ColinearPointsException
+ */
+ public static boolean isCCW(List vertices, Vector3d normal) throws ColinearPointsException {
+ Plane p = Plane.createFromPoints(vertices);
+
+ double dot = normal.dot(p.getNormal());
+ return dot > (1.0 - Plane.getEPSILON());
+ }
- // indicates whether edge points from highestLeftVertexIndex towards
- // the sel index (ccw)
- return selectedVIndex > highestLeftVertexIndex;
+ /**
+ * Checks if is ccw.
+ *
+ * @param polygon the polygon
+ * @return true, if is ccw
+ */
+ public static boolean isCCWv3d(List vertices) throws ColinearPointsException {
+ ArrayList v = new ArrayList();
+ for(Vector3d vc:vertices)
+ v.add(new Vertex(vc));
+ return isCCW(v);
+
+// // thanks to Sepp Reiter for explaining me the algorithm!
+// if (vertices.size() < 3) {
+// throw new IllegalArgumentException("Only polygons with at least 3 vertices are supported!");
+// }
+//
+// // search highest left vertex
+// int highestLeftVertexIndex = 0;
+// Vector3d highestLeftVertex = vertices.get(0);
+// double zSet = highestLeftVertex.z;
+// for (int i = 0; i < vertices.size(); i++) {
+//
+// Vector3d v = vertices.get(i);
+// double abs = Math.abs(zSet - v.z);
+// if (abs > Plane.getEPSILON()) {
+// throw new RuntimeException("isCCW can only be performed on the X Y plane "+abs);
+// }
+// if (v.y > highestLeftVertex.y) {
+// highestLeftVertex = v;
+// highestLeftVertexIndex = i;
+// } else if (v.y == highestLeftVertex.y && v.x < highestLeftVertex.x) {
+// highestLeftVertex = v;
+// highestLeftVertexIndex = i;
+// }
+// }
+//
+// // determine next and previous vertex indices
+// int nextVertexIndex = (highestLeftVertexIndex + 1) % vertices.size();
+// int prevVertexIndex = highestLeftVertexIndex - 1;
+// if (prevVertexIndex < 0) {
+// prevVertexIndex = vertices.size() - 1;
+// }
+// Vector3d nextVertex = vertices.get(nextVertexIndex);
+// Vector3d prevVertex = vertices.get(prevVertexIndex);
+//
+// // edge 1
+// double a1 = normalizedX(highestLeftVertex, nextVertex);
+//
+// // edge 2
+// double a2 = normalizedX(highestLeftVertex, prevVertex);
+//
+// // select vertex with lowest x value
+// int selectedVIndex;
+//
+// if (a2 > a1) {
+// selectedVIndex = nextVertexIndex;
+// } else {
+// selectedVIndex = prevVertexIndex;
+// }
+//
+// if (selectedVIndex == 0 && highestLeftVertexIndex == vertices.size() - 1) {
+// selectedVIndex = vertices.size();
+// }
+//
+// if (highestLeftVertexIndex == 0 && selectedVIndex == vertices.size() - 1) {
+// highestLeftVertexIndex = vertices.size();
+// }
+//
+// // indicates whether edge points from highestLeftVertexIndex towards
+// // the sel index (ccw)
+// return selectedVIndex > highestLeftVertexIndex;
}
@@ -349,13 +318,13 @@ public static void setExtrusionEngine(IExtrusion extrusionEngine) {
Extrude.extrusionEngine = extrusionEngine;
}
- public static CSG byPath(List> points, double height) {
+ public static CSG byPath(List> points, double height) throws ColinearPointsException {
return byPath(points, height, 200);
}
- public static CSG byPath(List> points, double height, int resolution) {
+ public static CSG byPath(List> points, double height, int resolution) throws ColinearPointsException {
ArrayList trPath = pathToTransforms(points, resolution);
ArrayList finalPath = new ArrayList<>();
for (Transform tr : trPath) {
@@ -415,9 +384,9 @@ public static ArrayList pathToTransforms(List> points,
}
// println "A string = " +pathStringA
// println "B String = " +pathStringB
- BezierPath path = new BezierPath();
+ BezierPath path = new BezierPath(10);
path.parsePathString(pathStringA);
- BezierPath path2 = new BezierPath();
+ BezierPath path2 = new BezierPath(10);
path2.parsePathString(pathStringB);
return bezierToTransforms(path, path2, resolution, null, null);
@@ -430,10 +399,10 @@ public static ArrayList moveAlongProfile(CSG object, List> p
public static ArrayList bezierToTransforms(Vector3d controlA, Vector3d controlB, Vector3d endPoint,
int iterations) {
- BezierPath path = new BezierPath();
+ BezierPath path = new BezierPath(10);
path.parsePathString("C " + controlA.x + "," + controlA.y + " " + controlB.x + "," + controlB.y + " "
+ endPoint.x + "," + endPoint.y);
- BezierPath path2 = new BezierPath();
+ BezierPath path2 = new BezierPath(10);
path2.parsePathString("C " + controlA.x + "," + controlA.z + " " + controlB.x + "," + controlB.z + " "
+ endPoint.x + "," + endPoint.z);
@@ -465,7 +434,7 @@ public static ArrayList bezierToTransforms(BezierPath pathA, BezierPa
Vector3d pointBStart = pathB.eval(0);
double x = pointAStart.x, y = pointAStart.y, z = pointBStart.y;
double lastx = x, lasty = y, lastz = z;
- // double min = (double ) 0.0001;
+ // double min = (double ) 0.0001;
int startIndex = 0;
if (controlA != null) {
startIndex = 1;
@@ -475,7 +444,8 @@ public static ArrayList bezierToTransforms(BezierPath pathA, BezierPa
double rise = zdiff;
double run = Math.sqrt((ydiff * ydiff) + (xdiff * xdiff));
double rotz = 90 - Math.toDegrees(Math.atan2(xdiff, ydiff));
- // //com.neuronrobotics.sdk.common.Log.error("Rot z = "+rotz+" x="+xdiff+" y="+ydiff);
+ // //com.neuronrobotics.sdk.common.Log.error("Rot z = "+rotz+" x="+xdiff+"
+ // y="+ydiff);
double roty = Math.toDegrees(Math.atan2(rise, run));
Transform t = new Transform();
t.translateX(x);
@@ -494,7 +464,7 @@ public static ArrayList bezierToTransforms(BezierPath pathA, BezierPa
double rotz;
double roty;
for (int i = startIndex; i < iterations - 1; i++) {
- double pathFunction = (double ) (((double ) i) / ((double ) (iterations - 1)));
+ double pathFunction = (double) (((double) i) / ((double) (iterations - 1)));
Vector3d pointA = pathA.eval(pathFunction);
Vector3d pointB = pathB.eval(pathFunction);
@@ -508,8 +478,8 @@ public static ArrayList bezierToTransforms(BezierPath pathA, BezierPa
t.translateY(y);
t.translateZ(z);
- Vector3d pointAEst = pathA.eval((double ) (pathFunction + d));
- Vector3d pointBEst = pathB.eval((double ) (pathFunction + d));
+ Vector3d pointAEst = pathA.eval((double) (pathFunction + d));
+ Vector3d pointBEst = pathB.eval((double) (pathFunction + d));
double xest = pointAEst.x;
double yest = pointAEst.y;
double zest = pointBEst.y;
@@ -521,13 +491,15 @@ public static ArrayList bezierToTransforms(BezierPath pathA, BezierPa
rise = zdiff;
run = Math.sqrt((ydiff * ydiff) + (xdiff * xdiff));
rotz = 90 - Math.toDegrees(Math.atan2(xdiff, ydiff));
- // //com.neuronrobotics.sdk.common.Log.error("Rot z = "+rotz+" x="+xdiff+" y="+ydiff);
+ // //com.neuronrobotics.sdk.common.Log.error("Rot z = "+rotz+" x="+xdiff+"
+ // y="+ydiff);
roty = Math.toDegrees(Math.atan2(rise, run));
t.rotZ(-rotz);
t.rotY(roty);
// if(i==0)
- // //com.neuronrobotics.sdk.common.Log.error( " Tr = "+x+" "+y+" "+z+" path = "+pathFunction);
+ // //com.neuronrobotics.sdk.common.Log.error( " Tr = "+x+" "+y+" "+z+" path =
+ // "+pathFunction);
// println "z = "+rotz+" y = "+roty
p.add(t);
lastx = x;
@@ -535,8 +507,8 @@ public static ArrayList bezierToTransforms(BezierPath pathA, BezierPa
lastz = z;
}
- Vector3d pointA = pathA.eval((double ) 1);
- Vector3d pointB = pathB.eval((double ) 1);
+ Vector3d pointA = pathA.eval((double) 1);
+ Vector3d pointB = pathB.eval((double) 1);
x = pointA.x;
y = pointA.y;
@@ -574,42 +546,50 @@ public static ArrayList bezierToTransforms(Vector3d start, Vector3d c
String b = "M " + start.x + "," + start.z + "\n" + "C " + controlA.x + "," + controlA.z + " " + controlB.x + ","
+ controlB.z + " " + endPoint.x + "," + endPoint.z;
// println "Start = "+startString
- BezierPath path = new BezierPath();
+ BezierPath path = new BezierPath(10);
path.parsePathString(startString);
- BezierPath path2 = new BezierPath();
+ BezierPath path2 = new BezierPath(10);
path2.parsePathString(b);
// newParts.remove(parts.size()-1)
// newParts.remove(0)
- // //com.neuronrobotics.sdk.common.Log.error("Parsing "+startString+" \nand\n"+b);
+ // //com.neuronrobotics.sdk.common.Log.error("Parsing "+startString+"
+ // \nand\n"+b);
return bezierToTransforms(path, path2, iterations, controlA, controlB);
}
- public static CSG sweep(Polygon p, Transform increment, Transform offset, int steps) {
- return sweep(p,increment,offset,steps, (u,d)->{return new Transform();});
+
+ public static CSG sweep(Polygon p, Transform increment, Transform offset, int steps)
+ throws ColinearPointsException {
+ return sweep(p, increment, offset, steps, (u, d) -> {
+ return new Transform();
+ });
}
- public static CSG sweep(Polygon p, Transform increment, Transform offset, int steps,ITransformProvider provider) {
+
+ public static CSG sweep(Polygon p, Transform increment, Transform offset, int steps, ITransformProvider provider)
+ throws ColinearPointsException {
Polygon offsetP = p.transformed(offset);
ArrayList newPolygons = new ArrayList<>();
- newPolygons.addAll(PolygonUtil.concaveToConvex(offsetP));
+ newPolygons.addAll(PolygonUtil.triangulatePolygon(offsetP));
Transform running = new Transform();
Polygon prev = offsetP.transformed(provider.get(0, steps));
for (int i = 0; i < steps; i++) {
running.apply(increment);
- double unit = ((double)i)/((double)steps);
+ 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);
}
Polygon polygon2 = prev.clone();
- List topPolygons = PolygonUtil.concaveToConvex(polygon2.flipped());
+ List topPolygons = PolygonUtil.triangulatePolygon(polygon2.flipped());
newPolygons.addAll(topPolygons);
return CSG.fromPolygons(newPolygons);
}
- public static CSG sweep(Polygon p, double angle, double z, double radius, int steps) {
+ public static CSG sweep(Polygon p, double angle, double z, double radius, int steps) throws ColinearPointsException {
return sweep(p, new Transform().rotX(angle).movex(z), new Transform().movey(radius), steps);
}
+
public static List monotoneExtrude(Polygon polygon2, Polygon polygon1) {
List newPolygons = new ArrayList<>();
@@ -624,43 +604,44 @@ public static List monotoneExtrude(Polygon polygon2, Polygon polygon1)
Vector3d bottomV2 = polygon1.getVertices().get(nexti).pos;
Vector3d topV2 = polygon2.getVertices().get(nexti).pos;
double distance = bottomV1.minus(bottomV2).magnitude();
- if (Math.abs(distance) < Plane.getEPSILON()) {
- continue;
+ double z1Dist = topV1.minus(bottomV1).magnitude();
+ 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()));
+ } catch (ColinearPointsException ex) {
+ System.out.println(ex.getMessage()+" Pruning from extrude");
+ }
}
- try {
- newPolygons.add(Polygon.fromPoints(Arrays.asList(bottomV2, topV2, topV1), polygon1.getStorage()));
- newPolygons.add(Polygon.fromPoints(Arrays.asList(bottomV2, topV1, bottomV1), polygon1.getStorage()));
- } catch (Exception ex) {
- ex.printStackTrace();
+ double distance2 = topV2.minus(topV1).magnitude();
+ double z1Dist2 = topV2.minus(bottomV2).magnitude();
+ 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()));
+ } catch (ColinearPointsException ex) {
+ System.out.println(ex.getMessage()+" Pruning from extrude");
+ }
}
}
return newPolygons;
}
+
public static ArrayList revolve(CSG slice, double radius, int numSlices) {
return revolve(slice, radius, 360.0, null, numSlices);
}
- public static ArrayList revolve(Polygon poly, int numSlices) {
+ public static ArrayList revolve(Polygon poly, int numSlices) throws ColinearPointsException {
return revolve(poly, 0, numSlices);
}
- public static ArrayList revolve(Polygon poly, double radius, int numSlices) {
- ArrayList parts = new ArrayList();
- ArrayList slices = new ArrayList();
-
- for (int i = 0; i < numSlices; i++) {
- double angle = 360.0 / ((double) numSlices) * ((double) i);
- slices.add(poly.transformed(new Transform().movex(radius).roty(angle)));
- }
- for (int i = 0; i < slices.size(); i++) {
- int next = i + 1;
- if (next == slices.size())
- next = 0;
- // println "Extruding "+i+" to "+next
- parts.add(Extrude.polygons(slices.get(i), slices.get(next)));
- }
-
- return parts;
+ public static ArrayList revolve(Polygon poly, double radius, int numSlices) throws ColinearPointsException {
+ Polygon p=poly;
+ double angle=360;
+ double z=0;
+ int steps=numSlices;
+ CSG result=sweep( p, angle, z, radius, steps);
+ return new ArrayList(Arrays.asList(result));
}
public static ArrayList revolve(CSG slice, double radius, double archLen, int numSlices) {
@@ -782,9 +763,9 @@ private static Vector3d fromDouble(ArrayList controlA) {
}
public static ArrayList moveBezier(CSG slice, BezierPath pathA, int numSlices) {
- Vector3d pointA = pathA.eval((double ) 1.0);
+ Vector3d pointA = pathA.eval((double) 1.0);
String zpath = "C 0,0 " + pointA.x + "," + pointA.y + " " + pointA.x + "," + pointA.y;
- BezierPath pathB = new BezierPath();
+ BezierPath pathB = new BezierPath(10);
pathB.parsePathString(zpath);
return moveBezier(slice, pathA, pathB, numSlices);
@@ -798,19 +779,22 @@ public static ArrayList moveBezier(CSG slice, BezierPath pathA, BezierPath
}
- public static Polygon toCCW(Polygon concave) {
- if (!isCCW(concave)) {
-// List points = concave.getPoints();
-// List result = new ArrayList<>(points);
-// Collections.reverse(result);
-// return Polygon.fromPoints(result);
- List points = concave.getVertices();
- List result = new ArrayList<>(points);
- Collections.reverse(result);
- Plane p = concave.getPlane().clone();
- p.flip();
- return new Polygon(result, concave.getStorage(), true, p);
- }
- return concave;
+// public static Polygon toCCW(Polygon concave) throws ColinearPointsException {
+// if (!isCCW(concave)) {
+//// List points = concave.getPoints();
+//// List result = new ArrayList<>(points);
+//// Collections.reverse(result);
+//// return Polygon.fromPoints(result);
+// return concave.flipped();
+// }
+// return concave;
+// }
+
+ public static double getMinimumDIstance() {
+ return MINIMUM_DISTANCE;
+ }
+
+ public static void setMinimumDIstance(double mINIMUM_DISTANCE) {
+ MINIMUM_DISTANCE = mINIMUM_DISTANCE;
}
}
diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Fillet.java b/src/main/java/eu/mihosoft/vrl/v3d/Fillet.java
index f7314e8e..1205c76b 100644
--- a/src/main/java/eu/mihosoft/vrl/v3d/Fillet.java
+++ b/src/main/java/eu/mihosoft/vrl/v3d/Fillet.java
@@ -33,7 +33,7 @@ public static CSG corner(double rad, double angle) {
// .rotz(180)
}
- public static CSG outerFillet(CSG base, double rad) {
+ public static CSG outerFillet(CSG base, double rad) throws ColinearPointsException {
List polys = Slice.slice(base);
return base.union(outerFillet(polys, rad));
}
diff --git a/src/main/java/eu/mihosoft/vrl/v3d/IExtrusion.java b/src/main/java/eu/mihosoft/vrl/v3d/IExtrusion.java
index 2df69b49..7d14e817 100644
--- a/src/main/java/eu/mihosoft/vrl/v3d/IExtrusion.java
+++ b/src/main/java/eu/mihosoft/vrl/v3d/IExtrusion.java
@@ -9,7 +9,7 @@ public interface IExtrusion {
* @param points
* @return
*/
- CSG extrude(Vector3d dir, List points) ;
+ CSG extrude(Vector3d dir, List points) throws ColinearPointsException;
/**
* Extrude.
*
@@ -19,5 +19,5 @@ public interface IExtrusion {
* the polygon1
* @return the csg
*/
- CSG extrude(Vector3d dir, Polygon polygon1);
+ CSG extrude(Vector3d dir, Polygon polygon1)throws ColinearPointsException;
}
diff --git a/src/main/java/eu/mihosoft/vrl/v3d/IPolygonRepairTool.java b/src/main/java/eu/mihosoft/vrl/v3d/IPolygonRepairTool.java
index d09ee286..aec99b2a 100644
--- a/src/main/java/eu/mihosoft/vrl/v3d/IPolygonRepairTool.java
+++ b/src/main/java/eu/mihosoft/vrl/v3d/IPolygonRepairTool.java
@@ -1,5 +1,5 @@
package eu.mihosoft.vrl.v3d;
public interface IPolygonRepairTool {
- Polygon repairOverlappingEdges(Polygon concave);
+ Polygon repairOverlappingEdges(Polygon concave) throws ColinearPointsException;
}
diff --git a/src/main/java/eu/mihosoft/vrl/v3d/ISlice.java b/src/main/java/eu/mihosoft/vrl/v3d/ISlice.java
index 02e43bf3..3ac51ea5 100644
--- a/src/main/java/eu/mihosoft/vrl/v3d/ISlice.java
+++ b/src/main/java/eu/mihosoft/vrl/v3d/ISlice.java
@@ -10,5 +10,5 @@ public interface ISlice {
* @param normalInsetDistance Inset for sliced output
* @return A set of polygons defining the sliced shape
*/
- List slice(CSG incoming, Transform slicePlane, double normalInsetDistance);
+ List slice(CSG incoming, Transform slicePlane, double normalInsetDistance) throws ColinearPointsException;
}
diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Isosceles.java b/src/main/java/eu/mihosoft/vrl/v3d/Isosceles.java
index 5a1bc861..1e08834b 100644
--- a/src/main/java/eu/mihosoft/vrl/v3d/Isosceles.java
+++ b/src/main/java/eu/mihosoft/vrl/v3d/Isosceles.java
@@ -40,13 +40,19 @@ public List toPolygons() {
throw new NumberFormatException("h can not be negative");
if(d<=0)
throw new NumberFormatException("d can not be negative");
- CSG polygon = Extrude.points(new Vector3d(0, 0, w),// This is the extrusion depth
- new Vector3d(0,0),// All values after this are the points in the polygon
- new Vector3d(0,-h/2),// upper right corner
- new Vector3d(d,0),// Bottom right corner
- new Vector3d(0,h/2)// upper right corner
- ).roty(90)
- .rotz(180);
+ CSG polygon=null;
+ try {
+ polygon = Extrude.points(new Vector3d(0, 0, w),// This is the extrusion depth
+ new Vector3d(0,0),// All values after this are the points in the polygon
+ new Vector3d(0,-h/2),// upper right corner
+ new Vector3d(d,0),// Bottom right corner
+ new Vector3d(0,h/2)// upper right corner
+ ).roty(90)
+ .rotz(180);
+ } catch (ColinearPointsException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
return polygon.getPolygons();
}
diff --git a/src/main/java/eu/mihosoft/vrl/v3d/Node.java b/src/main/java/eu/mihosoft/vrl/v3d/Node.java
index 72837de2..5b55fb88 100644
--- a/src/main/java/eu/mihosoft/vrl/v3d/Node.java
+++ b/src/main/java/eu/mihosoft/vrl/v3d/Node.java
@@ -33,12 +33,20 @@
*/
package eu.mihosoft.vrl.v3d;
+import java.math.BigInteger;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import com.aparapi.Kernel;
+import com.aparapi.device.Device;
+import com.aparapi.device.OpenCLDevice;
+import com.aparapi.internal.kernel.KernelManager;
+
import eu.mihosoft.vrl.v3d.ext.org.poly2tri.PolygonUtil;
+import javafx.scene.paint.Color;
// Auto-generated Javadoc
/**
@@ -49,10 +57,12 @@
* no distinction between internal and leaf nodes.
*/
public final class Node {
- private static final int COPLANAR = 0;
- private static final int FRONT = 1;
- private static final int BACK = 2;
- private static final int SPANNING = 3; // == some in the FRONT + some in the BACK
+ private static final int LIMIT_FOR_GPU = 5000;
+ public static final int COPLANAR = 0;
+ public static final int FRONT = 1;
+ public static final int BACK = 2;
+ public static final int SPANNING = 3; // == some in the FRONT + some in the BACK
+
/**
* Polygons.
*/
@@ -60,7 +70,7 @@ public final class Node {
/**
* Plane used for BSP.
*/
- private Plane plane;
+ private final Plane myNodePlane;
/**
* Polygons in front of the plane.
*/
@@ -72,14 +82,19 @@ public final class Node {
private long maxDepth = -1;
+ private int count = 1;
+ private static boolean GPUTest = false;;
+
/**
* Constructor.
*
- * Creates a BSP node consisting of the specified polygons.
+ * Creates a Binary Space Partition (BSP) node consisting of the specified polygons.
*
* @param polygons polygons
+ * @throws Exception
*/
- public Node(ArrayList polygons) {
+ public Node(ArrayList polygons,Plane p) throws Exception {
+ myNodePlane=p.clone();
this.polygons = new ArrayList<>();
if (polygons != null) {
this.build(polygons);
@@ -89,8 +104,8 @@ public Node(ArrayList polygons) {
// /**
// * Constructor. Creates a node without polygons.
// */
- private Node() {
- this(null);
+ private Node(Plane p) throws Exception {
+ this(null,p);
}
/*
@@ -100,25 +115,32 @@ private Node() {
*/
@Override
public Node clone() {
- Node node = new Node();
- node.setPlane(this.getPlane() == null ? null : this.getPlane().clone());
- node.front = this.front == null ? null : this.front.clone();
- node.back = this.back == null ? null : this.back.clone();
-// node.polygons = new ArrayList<>();
-// polygons.parallelStream().forEach((Polygon p) -> {
-// node.polygons.add(p.clone());
-// });
+ Node node;
+ try {
+ node = new Node(this.getThisNodePlane().clone());
+// node.setPlane(this.getPlane() == null ? null : this.getPlane().clone());
+ node.front = this.front == null ? null : this.front.clone();
+ node.back = this.back == null ? null : this.back.clone();
+// node.polygons = new ArrayList<>();
+// polygons.parallelStream().forEach((Polygon p) -> {
+// node.polygons.add(p.clone());
+// });
- Stream polygonStream;
+ Stream polygonStream;
- if (polygons.size() > 200) {
- polygonStream = polygons.parallelStream();
- } else
- polygonStream = polygons.stream();
+ if (polygons.size() > 200) {
+ polygonStream = polygons.parallelStream();
+ } else
+ polygonStream = polygons.stream();
- node.polygons = polygonStream.map(p -> p.clone()).collect(Collectors.toCollection(ArrayList::new));
+ node.polygons = polygonStream.map(p -> p.clone()).collect(Collectors.toCollection(ArrayList::new));
- return node;
+ return node;
+ } catch (Exception e) {
+ // Auto-generated catch block
+ e.printStackTrace();
+ }
+ throw new RuntimeException("Failed to clone");
}
/**
@@ -137,17 +159,17 @@ public void invert() {
polygon.flip();
});
- if (this.getPlane() == null && !polygons.isEmpty()) {
- this.setPlane(polygons.get(0).getPlane().clone());
- } else if (this.getPlane() == null && polygons.isEmpty()) {
-
- // com.neuronrobotics.sdk.common.Log.error("Please fix me! I don't know what to
- // do?");
- throw new RuntimeException("Please fix me! Plane = " + plane + " and polygons are empty");
- // return;
- }
+// if (this.getPlane() == null && !polygons.isEmpty()) {
+// this.setPlane(polygons.get(0).getPlane().clone());
+// } else if (this.getPlane() == null && polygons.isEmpty()) {
+//
+// // com.neuronrobotics.sdk.common.Log.error("Please fix me! I don't know what to
+// // do?");
+// throw new RuntimeException("Please fix me! Plane = " + getPlane() + " and polygons are empty");
+// // return;
+// }
- this.getPlane().flip();
+ this.getThisNodePlane().flip();
if (this.front != null) {
this.front.invert();
@@ -159,7 +181,51 @@ public void invert() {
this.front = this.back;
this.back = temp;
}
-
+// public void invert() {
+// // Use ArrayList as a stack to track nodes to process
+// ArrayList stack = new ArrayList<>();
+// stack.add(this);
+//
+// while (!stack.isEmpty()) {
+// // Pop the last node from our stack
+// Node current = stack.remove(stack.size() - 1);
+//
+// // Process polygons for current node
+// Stream polygonStream;
+// if (current.polygons.size() > 200) {
+// polygonStream = current.polygons.parallelStream();
+// } else {
+// polygonStream = current.polygons.stream();
+// }
+//
+// polygonStream.forEach((polygon) -> {
+// polygon.flip();
+// });
+//
+// // Handle plane logic
+// if (current.getPlane() == null && !current.polygons.isEmpty()) {
+// current.setPlane(current.polygons.get(0).getPlane().clone());
+// } else if (current.getPlane() == null && current.polygons.isEmpty()) {
+// throw new RuntimeException("Please fix me! Plane = " + current.plane + " and polygons are empty");
+// }
+//
+// current.getPlane().flip();
+//
+// // Add child nodes to stack for processing (if they exist)
+// // Note: We add them in reverse order so they're processed in the same order as the recursive version
+// if (current.back != null) {
+// stack.add(current.back);
+// }
+// if (current.front != null) {
+// stack.add(current.front);
+// }
+//
+// // Swap front and back
+// Node temp = current.front;
+// current.front = current.back;
+// current.back = temp;
+// }
+// }
/**
* Recursively removes all polygons in the {@link polygons} list that are
* contained within this BSP tree.
@@ -169,31 +235,658 @@ public void invert() {
* @param polygons the polygons to clip
*
* @return the cliped list of polygons
+ * @throws Exception
*/
- private ArrayList clipPolygons(ArrayList polygons) {
+ private ArrayList clipPolygons(ArrayList polygons) throws Exception {
- if (this.getPlane() == null) {
- return new ArrayList<>(polygons);
+ if (this.getThisNodePlane() == null) {
+ throw new RuntimeException("Plane can not be null");
}
-
- ArrayList frontP = new ArrayList<>();
- ArrayList backP = new ArrayList<>();
+ // preallocate the lists so they do not use dynamic memory in split
+ ArrayList frontP = new ArrayList<>(polygons.size());
+ ArrayList backP = new ArrayList<>(polygons.size());
splitPolygon(polygons, frontP, backP, frontP, backP);
-
if (this.front != null) {
frontP = this.front.clipPolygons(frontP);
}
if (this.back != null) {
backP = this.back.clipPolygons(backP);
} else {
- backP = new ArrayList<>(0);
+ backP=new ArrayList(0);
}
-
frontP.addAll(backP);
return frontP;
}
+ private static int add(List l, int polygonIndex, int[] polygonStartIndex, int[] polygonSize,
+ ArrayList orderedPoints, double[] polygonPointX, double[] polygonPointY, double[] polygonPointZ,
+ Polygon polygon, boolean[] isCopy) {
+ int polygonBase = polygonStartIndex[polygonIndex];
+ int size = polygonSize[polygonIndex];
+ if (polygonBase < 0)
+ return 0;
+ if (isCopy[polygonIndex]) {
+ l.add(polygon);
+ return 1;
+ }
+ try {
+ testAddPolygon(l, orderedPoints, polygonPointX, polygonPointY, polygonPointZ, polygon, polygonBase, size,
+ false);
+ return 1;
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ System.err.println("Pruning bad polygon Node::splitPolygon::add " + l.size());
+ }
+ return 0;
+ }
+
+ private static void testAddPolygon(List l, ArrayList orderedPoints, double[] polygonPointX,
+ double[] polygonPointY, double[] polygonPointZ, Polygon polygon, int polygonBase, int size, boolean test) {
+ List f = new ArrayList<>();
+ for (int i = polygonBase; i < polygonBase + size; i++) {
+ if (i < orderedPoints.size()) {
+ f.add(orderedPoints.get(i).clone());
+ } else {
+ double x = (polygonPointX[i]);
+ double y = (polygonPointY[i]);
+ double z = (polygonPointZ[i]);
+ Vertex v = new Vertex(new Vector3d(x, y, z));
+ addPoint(f, v);
+ }
+ }
+
+ add(l, f, polygon, test);
+ }
+
+ private static boolean addPoint(List f, Vertex v) {
+ if (f.size() > 0) {
+// if (Math.abs(v.pos.distance(f.get(0).pos)) < Plane.getEPSILON()) {
+// return false;
+// }
+// if (Math.abs(v.pos.distance(f.get(f.size() - 1).pos)) < Plane.getEPSILON()) {
+// return false;
+// }
+ }
+ 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, boolean test) {
+ if (f.size() < 3)
+ return;
+ try {
+ if(!Extrude.isCCW(f, polygon.getPlane().getNormal())) {
+ Collections.reverse(f);
+ }
+ Polygon fpoly = new Polygon(f, polygon.getStorage(), true, polygon.getPlane())
+ .setColor(polygon.getColor());
+ if (!test)
+ l.add(fpoly);
+ }catch(ColinearPointsException ex) {
+ System.err.println(ex.getMessage()+" Pruned Colinear polygon "+f );
+ }
+ }
+
+ /**
+ * Splits a {@link Polygon} by this plane if needed. After that it puts the
+ * polygons or the polygon fragments in the appropriate lists ({@code front},
+ * {@code back}). Coplanar polygons go into either {@code coplanarFront},
+ * {@code coplanarBack} depending on their orientation with respect to this
+ * plane. Polygons in front or back of this plane go into either {@code front}
+ * or {@code back}.
+ *
+ * @param polygon polygon to split
+ * @param coplanarFront "coplanar front" polygons
+ * @param coplanarBack "coplanar back" polygons
+ * @param front front polygons
+ * @param back back polgons
+ * @throws Exception
+ */
+ public void splitPolygon(ArrayList polygons, List cf, List cb,
+ List f, List b) throws Exception {
+ if (polygons.size() > LIMIT_FOR_GPU) {
+ splitPolygonGPU(polygons, cf, cb, f, b);
+ return;
+ }
+ splitPolygonOriginal(polygons, cf, cb, f, b);
+
+// List cf1 = new ArrayList();
+// List cb1= new ArrayList();
+// List f1= new ArrayList();
+// List b1= new ArrayList();
+// List cf2= new ArrayList();
+// List cb2= new ArrayList();
+// List f2= new ArrayList();
+// List b2= new ArrayList();
+// splitPolygonOriginal(polygons, cf2, cb2, f2, b2);
+// splitPolygonGPU(polygons, cf1, cb1, f1, b1);
+//
+// if(cf1.size()!=cf2.size()
+// ||cb1.size()!=cb2.size()
+// || f1.size()!=f2.size()
+// ||b1.size()!=b2.size()) {
+// throw new RuntimeException("Node split mismathch");
+// }
+// for (int i = 0; i < cf1.size(); i++) {
+// Polygon p1 = cf1.get(i);
+// Polygon p2 = cf2.get(i);
+// if(p1.size()!=p2.size())
+// throw new RuntimeException("Node slit mismathch, polygon size mismatch");
+//
+// }
+// for (int i = 0; i < cb1.size(); i++) {
+// Polygon p1 = cb1.get(i);
+// Polygon p2 = cb2.get(i);
+// if(p1.size()!=p2.size())
+// throw new RuntimeException("Node slit mismathch, polygon size mismatch");
+//
+// }
+// for (int i = 0; i < f1.size(); i++) {
+// Polygon p1 = f1.get(i);
+// Polygon p2 = f2.get(i);
+// if(p1.size()!=p2.size())
+// throw new RuntimeException("Node slit mismathch, polygon size mismatch");
+//
+// }
+// for (int i = 0; i < b1.size(); i++) {
+// Polygon p1 = b1.get(i);
+// Polygon p2 = b2.get(i);
+// if(p1.size()!=p2.size())
+// throw new RuntimeException("Node slit mismathch, polygon size mismatch");
+//
+// }
+// f.addAll(f1);
+// b.addAll(b1);
+// cb.addAll(cb1);
+// cf.addAll(cf1);
+ }
+
+ /**
+ * An attempt to make part of the CSG stack GPu accelerated
+ *
+ * this is worth exploring in the future
+ *
+ * @param polygons
+ * @param coplanarFront
+ * @param coplanarBack
+ * @param front
+ * @param back
+ * @throws Exception
+ */
+ @SuppressWarnings("deprecation")
+ public void splitPolygonGPU(ArrayList polygons, List coplanarFront, List coplanarBack,
+ List front, List back) throws Exception {
+
+ // Main conversion of your original code
+ int numberOfPointsTmp = 0;
+ int polygonNumber = polygons.size();
+ int max = 0;
+
+ ArrayList orderedPoints = new ArrayList();
+ int[] polygonStartIndex = new int[polygonNumber];
+ int[] polygonSize = new int[polygonNumber];
+ int[] newPointStartIndex = new int[polygonNumber];
+
+ // Convert to fixed point arrays
+ double[] normalPolygonX = new double[polygonNumber];
+ double[] normalPolygonY = new double[polygonNumber];
+ double[] normalPolygonZ = new double[polygonNumber];
+ double[] normalPolygonDistance = new double[polygonNumber];
+
+ for (int k = 0; k < polygonNumber; k++) {
+ Polygon polygon = polygons.get(k);
+ List vertices = polygon.getVertices();
+ int size = vertices.size();
+ if (size > max)
+ max = size;
+ numberOfPointsTmp += size;
+ polygonStartIndex[k] = orderedPoints.size();
+ polygonSize[k] = size;
+
+ // Convert to fixed point
+ normalPolygonX[k] = (polygon.getPlane().getNormal().x);
+ normalPolygonY[k] = (polygon.getPlane().getNormal().y);
+ normalPolygonZ[k] = (polygon.getPlane().getNormal().z);
+ normalPolygonDistance[k] = (polygon.getPlane().getDist());
+ orderedPoints.addAll(vertices);
+ }
+ int ExtraSpace = max * 2 + 2;
+ int[] coplanarFrontStartIndex = new int[polygonNumber];
+ int[] coplanarFrontSize = new int[polygonNumber];
+ int[] coplanarBackStartIndex = new int[polygonNumber];
+ int[] coplanarBackSize = new int[polygonNumber];
+ int[] frontStartIndex = new int[polygonNumber];
+ int[] frontspace = new int[polygonNumber];
+ int[] frontSize = new int[polygonNumber];
+ int[] backStartIndex = new int[polygonNumber];
+ int[] backspace = new int[polygonNumber];
+ int[] backSize = new int[polygonNumber];
+
+ int pointsNumber = numberOfPointsTmp + 1 + ((ExtraSpace) * (polygonNumber + 1) * 2);
+ boolean[] memoryError = new boolean[polygonNumber];
+ boolean[] isCopy = new boolean[polygonNumber];
+
+ for (int k = 0; k < polygonNumber; k++) {
+ newPointStartIndex[k] = numberOfPointsTmp + (k * ExtraSpace * 2);
+ coplanarFrontStartIndex[k] = -1;
+ coplanarBackStartIndex[k] = -1;
+ frontStartIndex[k] = -1;
+ backStartIndex[k] = -1;
+ memoryError[k] = false;
+ isCopy[k] = false;
+ frontspace[k] = ExtraSpace;
+ backspace[k] = ExtraSpace;
+ }
+
+ int pointsEmptyIndex = 0;
+ int[] types = new int[max * (polygonNumber + 1)];
+ int maxPolygonSize = max;
+
+ // Convert point arrays to fixed point
+ double[] polygonPointX = new double[pointsNumber];
+ double[] polygonPointY = new double[pointsNumber];
+ double[] polygonPointZ = new double[pointsNumber];
+
+ for (; pointsEmptyIndex < orderedPoints.size(); pointsEmptyIndex++) {
+ Vertex vertex = orderedPoints.get(pointsEmptyIndex);
+ polygonPointX[pointsEmptyIndex] = (vertex.getX());
+ polygonPointY[pointsEmptyIndex] = (vertex.getY());
+ polygonPointZ[pointsEmptyIndex] = (vertex.getZ());
+ }
+ for (int i = orderedPoints.size(); i < polygonPointX.length; i++) {
+ polygonPointX[i] = -1;
+ polygonPointY[i] = -1;
+ polygonPointZ[i] = -1;
+ }
+ // Convert plane normal to fixed point
+ double planeNormalX = (this.getThisNodePlane().getNormal().x);
+ double planeNormalY = (this.getThisNodePlane().getNormal().y);
+ double planeNormalZ = (this.getThisNodePlane().getNormal().z);
+ double planeNormalDistance = (this.getThisNodePlane().getDist());
+
+ double epsilon = Plane.getEPSILON();
+
+ int chunkSize =5000;
+ int loops = polygonNumber / chunkSize;
+ if (loops < 0)
+ loops = 1;
+
+ //System.out.println("\n\nStarting Kernel "+polygonNumber+" polygons in "+loops+" loops ");
+ Kernel splitPolygonsKernel = new Kernel() {
+
+ int size(int polygonIndex, int[] mypolygonSize) {
+ return mypolygonSize[polygonIndex];
+ }
+
+ int addPolygon(int polygonIndex, int size, int[] mypolygonStartIndex, int[] mypolygonSize, int[] space) {
+ int w = polygonIndex;
+ mypolygonStartIndex[w] = newPointStartIndex[w];
+ newPointStartIndex[w] += size;
+ mypolygonSize[w] = 0;
+ space[w] -= size;
+ double fx = polygonPointX[mypolygonStartIndex[w]];
+ double fy = polygonPointY[mypolygonStartIndex[w]];
+ double fz = polygonPointZ[mypolygonStartIndex[w]];
+ if (Math.abs(fx + 1) > epsilon || Math.abs(fy + 1) > epsilon || Math.abs(fz + 1) > epsilon) {
+ memoryError[polygonIndex] = true;
+ return -1;
+ }
+ return space[w];
+ }
+
+ void copy(int polygonIndex, int[] mypolygonStartIndex, int[] mypolygonSize) {
+ mypolygonStartIndex[polygonIndex] = polygonStartIndex[polygonIndex];
+ mypolygonSize[polygonIndex] = polygonSize[polygonIndex];
+ }
+
+ void clear(int polygonIndex, int[] mypolygonSize) {
+ mypolygonSize[polygonIndex] = 0;
+ }
+
+ void incrementSize(int polygonIndex, int[] mypolygonStartIndex, int[] mypolygonSize) {
+ mypolygonSize[polygonIndex]++;
+ int ni = mypolygonSize[polygonIndex];
+ if (polygonIndex == polygonNumber - 1) {
+ if (ni >= pointsNumber) {
+ memoryError[polygonIndex] = true;
+ }
+ } else {
+ if (ni + mypolygonStartIndex[polygonIndex] == mypolygonStartIndex[polygonIndex + 1]) {
+ memoryError[polygonIndex] = true;
+ }
+ }
+ }
+
+ int writeIncrementPoint(int polygonIndex, int source, int[] mypolygonStartIndex, int[] mypolygonSize) {
+ int pointInPolygon = mypolygonSize[polygonIndex];// get the end of the current list
+ incrementSize(polygonIndex, mypolygonStartIndex, mypolygonSize);
+ double x = polygonPointX[source];
+ double y = polygonPointY[source];
+ double z = polygonPointZ[source];
+ return writePoint(polygonIndex, pointInPolygon, x, y, z, mypolygonStartIndex);
+ }
+
+ int interpolate(int polygonIndex, int vi, int vj, int[] mypolygonStartIndex, int[] mypolygonSize) {
+
+ int globalVi = polygonStartIndex[polygonIndex] + vi;
+ int globalVj = polygonStartIndex[polygonIndex] + vj;
+ double planeDot = dotProductFixed(planeNormalX, planeNormalY, planeNormalZ, polygonPointX[globalVi],
+ polygonPointY[globalVi], polygonPointZ[globalVi]);
+
+ double d = (planeNormalDistance - planeDot);
+ // Get fixed point coordinates
+ double xvi = polygonPointX[globalVi];
+ double yvi = polygonPointY[globalVi];
+ double zvi = polygonPointZ[globalVi];
+ double diff_x = (polygonPointX[globalVj] - xvi);
+ double diff_y = (polygonPointY[globalVj] - yvi);
+ double diff_z = (polygonPointZ[globalVj] - zvi);
+
+ double dotMinus = dotProductFixed(planeNormalX, planeNormalY, planeNormalZ, diff_x, diff_y, diff_z);
+ // Paralell case where one point is slightly infront by the same amount that the
+ // other is slightly behind. when summed, they make a point that is exactly on
+ // the plane
+ // therefor the intersection point is halfway between i and j
+ double t = 0.5;
+ if (dotMinus != 0)
+ t = (d / dotMinus);
+ else
+ return -1;
+ if(t<0||t>1)
+ return -1;
+
+ // Fixed point interpolation: lerp = vi + (vj - vi) * t
+ double sx = diff_x * t;
+ double sy = diff_y * t;
+ double sz = diff_z * t;
+
+ double lerp_x = (xvi + sx);
+ double lerp_y = (yvi + sy);
+ double lerp_z = (zvi + sz);
+
+// new Vertex(new Vector3d(lerp_x , lerp_y , lerp_z ), polygons.get(polygonIndex).plane.getNormal());
+
+ int pointInPolygon = mypolygonSize[polygonIndex];
+ incrementSize(polygonIndex, mypolygonStartIndex, mypolygonSize);
+
+ int ret = writePoint(polygonIndex, pointInPolygon, lerp_x, lerp_y, lerp_z, mypolygonStartIndex);
+
+ return ret;
+ }
+
+ double dotProductFixed(double ax, double ay, double az, double bx, double by, double bz) {
+ return (az * bz) + (ay * by) + (ax * bx);
+ }
+
+ int writePoint(int polygonIndex, int pointInPolygon, double x, double y, double z,
+ int[] mypolygonStartIndex) {
+ int pointIndex = mypolygonStartIndex[polygonIndex] + pointInPolygon;
+ double fx = polygonPointX[pointIndex];
+ double fy = polygonPointY[pointIndex];
+ double fz = polygonPointZ[pointIndex];
+ if (Math.abs(fx + 1) > epsilon || Math.abs(fy + 1) > epsilon || Math.abs(fz + 1) > epsilon) {
+ memoryError[polygonIndex] = true;
+ return -1;
+ }
+ polygonPointX[pointIndex] = x;
+ polygonPointY[pointIndex] = y;
+ polygonPointZ[pointIndex] = z;
+ return pointIndex;
+ }
+
+ double polygonPointDistance(int polygonIndex, int pointIndex) {
+ int globalIndex = polygonStartIndex[polygonIndex] + pointIndex;
+ double dotResult = dotProductFixed(normalPolygonX[polygonIndex], normalPolygonY[polygonIndex],
+ normalPolygonZ[polygonIndex], polygonPointX[globalIndex], polygonPointY[globalIndex],
+ polygonPointZ[globalIndex]);
+
+ double result = (dotResult - normalPolygonDistance[polygonIndex]);
+ return (result);
+ }
+
+ double planePointDistance(int polygonIndex, int pointIndex) {
+ int globalIndex = polygonStartIndex[polygonIndex] + pointIndex;
+ double dotResult = dotProductFixed(planeNormalX, planeNormalY, planeNormalZ, polygonPointX[globalIndex],
+ polygonPointY[globalIndex], polygonPointZ[globalIndex]);
+
+ double result = (dotResult - planeNormalDistance);
+ return (result);
+ }
+
+ double planeDotPolygonNormal(int polygonIndex) {
+ double result = dotProductFixed(planeNormalX, planeNormalY, planeNormalZ, normalPolygonX[polygonIndex],
+ normalPolygonY[polygonIndex], normalPolygonZ[polygonIndex]);
+ return (result);
+ }
+ void runOnePolygon(int polygonIndex) {
+ // search for the epsilon values of the incoming plane
+ double negEpsilon = -epsilon;
+ double posEpsilon = epsilon;
+// for (int i = 0; i < size(polygonIndex, polygonSize); i++) {
+// double t = polygonPointDistance(polygonIndex, i);
+// if (t > posEpsilon) {
+// posEpsilon = (float) (t + epsilon);
+// }
+// if (t < negEpsilon) {
+// negEpsilon = (float) (t - epsilon);
+// }
+// }
+ int polygonType = COPLANAR;;
+// boolean someF =false;
+// boolean someB=false;
+ for (int i = 0; i < size(polygonIndex, polygonSize); i++) {
+ double t = planePointDistance(polygonIndex, i);
+ int type = (t < negEpsilon) ? BACK : (t > posEpsilon) ? FRONT : COPLANAR;
+ types[i + polygonIndex * maxPolygonSize] = type;
+ polygonType |= type;
+// if(type==BACK)
+// someB=true;
+// if(type==FRONT)
+// someF=true;
+ }
+// polygonType=COPLANAR;
+// if(someF && (!someB) ) {
+// polygonType=FRONT;
+// }
+// if((!someF) && (someB) ) {
+// polygonType=BACK;
+// }
+// if((someF) && (someB) ) {
+// polygonType=SPANNING;
+// }
+
+// List cf2= new ArrayList();
+// List cb2= new ArrayList();
+// List f2= new ArrayList();
+// List b2= new ArrayList();
+// splitSinglePolygon(polygons.get(polygonIndex), cf2, cb2, f2, b2);
+ if (polygonType == COPLANAR) {
+ isCopy[polygonIndex] = true;
+ if (planeDotPolygonNormal(polygonIndex) > 0) {
+// if(cf2.size()!=1) {
+// memoryError[polygonIndex] = true;
+// return;
+// }
+ copy(polygonIndex, coplanarFrontStartIndex, coplanarFrontSize);
+ } else {
+// if(cb2.size()!=1) {
+// memoryError[polygonIndex] = true;
+// return;
+// }
+ copy(polygonIndex, coplanarBackStartIndex, coplanarBackSize);
+ }
+ } else if (polygonType == FRONT) {
+// if(f2.size()!=1) {
+// memoryError[polygonIndex] = true;
+// return;
+// }
+ isCopy[polygonIndex] = true;
+ copy(polygonIndex, frontStartIndex, frontSize);
+ } else if (polygonType == BACK) {
+// if(b2.size()!=1) {
+// memoryError[polygonIndex] = true;
+// return;
+// }
+ isCopy[polygonIndex] = true;
+ copy(polygonIndex, backStartIndex, backSize);
+ } else if (polygonType == SPANNING) {
+// if(b2.size()!=1 && f2.size()!=1) {
+// memoryError[polygonIndex] = true;
+// return;
+// }
+ isCopy[polygonIndex] = false;
+
+ int size = size(polygonIndex, polygonSize);
+ int polygonMax = size * 2;
+ int retF = addPolygon(polygonIndex, polygonMax, frontStartIndex, frontSize, frontspace);
+ if (retF < 0) {
+ memoryError[polygonIndex] = true;
+ return;
+ }
+ int retB = addPolygon(polygonIndex, polygonMax, backStartIndex, backSize, backspace);
+ if (retB < 0) {
+ memoryError[polygonIndex] = true;
+ return;
+ }
+ clear(polygonIndex, frontSize);
+ clear(polygonIndex, backSize);
+
+ for (int i = 0; i < size; i++) {
+ int j = (i + 1) % size;
+ int ti = types[i + polygonIndex * maxPolygonSize];
+ int tj = types[j + polygonIndex * maxPolygonSize];
+ int sourctPointIndex = polygonStartIndex[polygonIndex] + i;
+ if (ti != BACK) {
+ writeIncrementPoint(polygonIndex, sourctPointIndex, frontStartIndex, frontSize);
+ }
+ if (ti != FRONT) {
+ writeIncrementPoint(polygonIndex, sourctPointIndex, backStartIndex, backSize);
+ }
+ if ((ti|tj)==SPANNING) {
+ int newPointIndex = interpolate(polygonIndex, i, j, frontStartIndex, frontSize);
+ if (newPointIndex > 0) {
+ writeIncrementPoint(polygonIndex, newPointIndex, backStartIndex, backSize);
+ }
+ }
+ if (memoryError[polygonIndex])
+ return;
+ int fsize = frontSize[polygonIndex];
+ int bsize = backSize[polygonIndex];
+ if (fsize > (polygonMax) || bsize > (polygonMax)) {
+ memoryError[polygonIndex] = true;
+ return;
+ }
+ }
+// ArrayList testF=new ArrayList();
+// ArrayList testB=new ArrayList();
+//
+// int size23 = frontSize[polygonIndex];
+// int polygonBase = frontStartIndex[polygonIndex];
+// testAddPolygon(testF, orderedPoints, polygonPointX, polygonPointY, polygonPointZ, polygons.get(polygonIndex), polygonBase, size23,
+// false);
+// int size22 = backSize[polygonIndex];
+// int polygonBase2 = backStartIndex[polygonIndex];
+//
+// testAddPolygon(testB, orderedPoints, polygonPointX, polygonPointY, polygonPointZ, polygons.get(polygonIndex), polygonBase2, size22,
+// false);
+// if(testF.size()!=f2.size()||testB.size()!=b2.size()) {
+// memoryError[polygonIndex] = true;
+// return;
+// }
+// if(testB.size()>0)
+// if(testB.get(0).size()!=b2.get(0).size()) {
+// memoryError[polygonIndex] = true;
+// return;
+// }
+// if(testF.size()>0)
+// if(testF.get(0).size()!=f2.get(0).size()) {
+// memoryError[polygonIndex] = true;
+// return;
+// }
+ } else {
+ memoryError[polygonIndex] = true;
+ return;
+ }
+ int polygonBase = frontStartIndex[polygonIndex];
+ int polygonBase22 = backStartIndex[polygonIndex];
+ if (coplanarBackStartIndex[polygonIndex] < 0 && coplanarFrontStartIndex[polygonIndex] < 0
+ && polygonBase < 0 && polygonBase22 < 0) {
+ memoryError[polygonIndex] = true;
+ return;
+ }
+
+ }
+ @Override
+ public void run() {
+ int pi = getGlobalId() * chunkSize;
+ int end = pi + chunkSize;
+ if(end>polygonNumber)
+ end=polygonNumber;
+ //System.out.println("#"+getGlobalId()+" Start "+pi+" to "+end);
+ for (int polygonIndex = pi; (polygonIndex < end); polygonIndex++) {
+ if (memoryError[polygonIndex])
+ return;
+ runOnePolygon(polygonIndex);
+ } // outer for loop of all polygons
+ }// run
+ };
+ if(!GPUTest) {
+ try {
+ splitPolygonsKernel.compile(splitPolygonsKernel.getTargetDevice());
+ }catch(Exception ex) {
+ System.err.println("GPU missing feature "+ex.getMessage());
+ GPUTest=true;
+ }
+ }
+ if(GPUTest)
+ splitPolygonsKernel.setExecutionMode(Kernel.EXECUTION_MODE.JTP); // Java Thread Pool
+
+ CSG.gpuRun(loops+3, splitPolygonsKernel, null, "split ", () -> {
+ return false;
+ }, 1, 1);
+
+ for (int k = 0; k < polygonNumber; k++)
+ if (memoryError[k])
+ throw new RuntimeException("Memory error here!");
+
+ // Collect the polygon data into the return structures
+ //int copies = 0;
+ for (int k = 0; k < polygonNumber; k++) {
+ copyDataIntoPolygon(polygons, coplanarFront, coplanarBack, front, back, orderedPoints,
+ coplanarFrontStartIndex, coplanarFrontSize, coplanarBackStartIndex, coplanarBackSize,
+ frontStartIndex, frontSize, backStartIndex, backSize, isCopy, polygonPointX, polygonPointY,
+ polygonPointZ, k);
+
+ }
+
+ }
+
+ private void copyDataIntoPolygon(ArrayList polygons, List coplanarFront,
+ List coplanarBack, List front, List back, ArrayList orderedPoints,
+ int[] coplanarFrontStartIndex, int[] coplanarFrontSize, int[] coplanarBackStartIndex,
+ int[] coplanarBackSize, int[] frontStartIndex, int[] frontSize, int[] backStartIndex, int[] backSize,
+ boolean[] isCopy, double[] polygonPointX, double[] polygonPointY, double[] polygonPointZ, int k) {
+ int copies;
+ Polygon polygon = polygons.get(k);
+ copies = 0;
+
+ copies += add(coplanarFront, k, coplanarFrontStartIndex, coplanarFrontSize, orderedPoints, polygonPointX,
+ polygonPointY, polygonPointZ, polygon, isCopy);
+ copies += add(coplanarBack, k, coplanarBackStartIndex, coplanarBackSize, orderedPoints, polygonPointX,
+ polygonPointY, polygonPointZ, polygon, isCopy);
+ copies += add(front, k, frontStartIndex, frontSize, orderedPoints, polygonPointX, polygonPointY, polygonPointZ,
+ polygon, isCopy);
+ copies += add(back, k, backStartIndex, backSize, orderedPoints, polygonPointX, polygonPointY, polygonPointZ,
+ polygon, isCopy);
+ if (copies != 1 && copies != 2) {
+ throw new RuntimeException("Failed to load all polygons??");
+ }
+ }
+
/**
* Splits a {@link Polygon} by this plane if needed. After that it puts the
* polygons or the polygon fragments in the appropriate lists ({@code front},
@@ -208,121 +901,171 @@ private ArrayList clipPolygons(ArrayList polygons) {
* @param front front polygons
* @param back back polgons
*/
- public void splitPolygon(ArrayList polygons, List coplanarFront, List coplanarBack,
+ public void splitPolygonOriginal(List polygons, List coplanarFront, List coplanarBack,
List front, List back) {
+
for (int k = 0; k < polygons.size(); k++) {
Polygon polygon = polygons.get(k);
+ splitSinglePolygon(polygon,coplanarFront, coplanarBack, front, back);
+ }
+ if(Debug3dProvider.isProviderAvailible()) {
+// Debug3dProvider.clearScreen();
+// Debug3dProvider.addObject(polygons.get(0).getVertices().get(0));
+// Debug3dProvider.addObject(front.stream().map(polygon -> polygon.setColor(Color.RED)).collect(Collectors.toList()));
+// List collect = back.stream().map(polygon -> polygon.setColor(Color.WHITE)).collect(Collectors.toList());
+// Debug3dProvider.addObject(collect);
+// Debug3dProvider.addObject(coplanarBack.stream().map(polygon -> polygon.setColor(Color.YELLOW)).collect(Collectors.toList()));
+// Debug3dProvider.addObject(coplanarFront.stream().map(polygon -> polygon.setColor(Color.GREEN)).collect(Collectors.toList()));
+// Debug3dProvider.clearScreen();
+ }
+ }
-
- // search for the epsilon values of the incoming plane
- double negEpsilon = -Plane.getEPSILON();
- double posEpsilon = Plane.getEPSILON();
- for (int i = 0; i < polygon.getVertices().size(); i++) {
- double t = polygon.getPlane().getNormal().dot(polygon.getVertices().get(i).pos)
+ private void splitSinglePolygon(Polygon polygon,List coplanarFront, List coplanarBack, List front,
+ List back) {
+ // search for the epsilon values of the incoming plane
+ double negEpsilon = -Plane.getEPSILON();
+ 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 = dot
- polygon.getPlane().getDist();
+ if(Math.abs(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 + Plane.getEPSILON();
+ posEpsilon = t;
}
if (t < negEpsilon) {
// com.neuronrobotics.sdk.common.Log.error("Non flat polygon, decreasing
// negative epsilon "+t);
- negEpsilon = t - Plane.getEPSILON();
+ negEpsilon = t;
}
}
- int polygonType = 0;
- List types = new ArrayList<>();
- boolean somePointsInfront = false;
- boolean somePointsInBack = false;
- for (int i = 0; i < polygon.getVertices().size(); i++) {
- double t = this.getPlane().getNormal().dot(polygon.getVertices().get(i).pos)
- - this.getPlane().getDist();
- int type = (t < negEpsilon) ? BACK : (t > posEpsilon) ? FRONT : COPLANAR;
- if (type == BACK)
- somePointsInBack = true;
- if (type == FRONT)
- somePointsInfront = true;
- types.add(type);
- }
- if (somePointsInBack && somePointsInfront)
- polygonType = SPANNING;
- else if (somePointsInBack) {
- polygonType = BACK;
- } else if (somePointsInfront)
- polygonType = FRONT;
-
- // Put the polygon in the correct list, splitting it when necessary.
- switch (polygonType) {
- case COPLANAR:
- (this.getPlane().getNormal().dot(polygon.getPlane().getNormal()) > 0 ? coplanarFront : coplanarBack)
- .add(polygon);
- break;
- case FRONT:
- front.add(polygon);
- break;
- case BACK:
- back.add(polygon);
- break;
- case SPANNING:
- List f = new ArrayList<>();
- List b = new ArrayList<>();
- for (int i = 0; i < polygon.getVertices().size(); i++) {
- int j = (i + 1) % polygon.getVertices().size();
- int ti = types.get(i);
- int tj = types.get(j);
- Vertex vi = polygon.getVertices().get(i);
- Vertex vj = polygon.getVertices().get(j);
- if (ti != BACK) {
- f.add(vi);
- }
- if (ti != FRONT) {
- b.add(ti != BACK ? vi.clone() : vi);
- }
- if ((ti | tj) == SPANNING) {
- double t = (this.getPlane().getDist() - this.getPlane().getNormal().dot(vi.pos))
- / this.getPlane().getNormal().dot(vj.pos.minus(vi.pos));
- Vertex v = vi.interpolate(vj, t);
- f.add(v);
- b.add(v.clone());
- }
+ int polygonType = 0;
+ List types = new ArrayList<>();
+// boolean someF =false;
+// boolean someB=false;
+
+ //double distP = polygon.getPlane().getDist();
+ for (int i = 0; i < size; i++) {
+ Vector3d pos = polygon.getVertices().get(i).pos;
+// double dot = normal.dot(pos);
+// double ep = Math.abs( dot-distP);// this is this points distance from its plane
+ double t = getThisNodePlane().getNormal().dot(pos) - getThisNodePlane().getDist();
+ int type = (t < negEpsilon) ? BACK : (t > posEpsilon) ? FRONT : COPLANAR;
+ types.add(type);
+ polygonType = polygonType|type;
+
+// if(type==BACK)
+// someB=true;
+// if(type==FRONT)
+// someF=true;
+ }
+// polygonType=COPLANAR;
+// if(someF && (!someB) ) {
+// polygonType=FRONT;
+// }
+// if((!someF) && (someB) ) {
+// polygonType=BACK;
+// }
+// if((someF) && (someB) ) {
+// polygonType=SPANNING;
+// }
+ // Put the polygon in the correct list, splitting it when necessary.
+ switch (polygonType) {
+ case COPLANAR:
+ double cp = getThisNodePlane().getNormal().dot(normal);
+ (cp > 0 ? coplanarFront : coplanarBack).add(polygon);
+ break;
+ case FRONT:
+ front.add(polygon);
+ break;
+ case BACK:
+ back.add(polygon);
+ break;
+ case SPANNING:
+ List