JavaCAD
Edge.java
Go to the documentation of this file.
1 /*
2  * To change this license header, choose License Headers in Project Properties.
3  * To change this template file, choose Tools | Templates
4  * and open the template in the editor.
5  */
6 package eu.mihosoft.vrl.v3d;
7 
8 import java.util.ArrayList;
9 import java.util.Collections;
10 import java.util.List;
11 import java.util.Objects;
12 import java.util.Optional;
13 import java.util.stream.Collectors;
14 import java.util.stream.Stream;
15 import eu.mihosoft.vrl.v3d.ext.org.poly2tri.PolygonUtil;
16 
22 public class Edge {
23 
25  private final Vertex p1;
26 
28  private final Vertex p2;
29 
31  private final Vector3d direction;
32 
39  public Edge(Vertex p1, Vertex p2) {
40  this.p1 = p1;
41  this.p2 = p2;
42 
44  }
45 
51  public Vertex getP1() {
52  return p1;
53  }
54 
55 // /**
56 // * @param p1 the p1 to set
57 // */
58 // public void setP1(Vertex p1) {
59 // this.p1 = p1;
60 // }
66  public Vertex getP2() {
67  return p2;
68  }
69 
70 // /**
71 // * @param p2 the p2 to set
72 // */
73 // public void setP2(Vertex p2) {
74 // this.p2 = p2;
81 // }
82  public static List<Edge> fromPolygon(Polygon poly) {
83  List<Edge> result = new ArrayList<>();
84 
85  for (int i = 0; i < poly.vertices.size(); i++) {
86  Edge e = new Edge(poly.vertices.get(i), poly.vertices.get((i + 1) % poly.vertices.size()));
87 
88  result.add(e);
89  }
90 
91  return result;
92  }
93 
100  public static List<Vertex> toVertices(List<Edge> edges) {
101  return edges.stream().map(e -> e.p1).collect(Collectors.toList());
102  }
103 
110  public static List<Vector3d> toPoints(List<Edge> edges) {
111  return edges.stream().map(e -> e.p1.pos).collect(Collectors.toList());
112  }
113 
121  public static Polygon toPolygon(List<Vector3d> points, Plane plane) {
122 
123 // List<Vector3d> points = edges.stream().().map(e -> e.p1.pos).
124 // collect(Collectors.toList());
125  Polygon p = Polygon.fromPoints(points);
126 
127  p.vertices.stream().forEachOrdered((vertex) -> {
128  vertex.normal = plane.normal.clone();
129  });
130 
131 // // we try to detect wrong orientation by comparing normals
132 // if (p.plane.normal.angle(plane.normal) > 0.1) {
133 // p.flip();
134 // }
135  return p;
136  }
137 
145  public static List<Polygon> toPolygons(List<Edge> boundaryEdges, Plane plane) {
146 
147  List<Vector3d> boundaryPath = new ArrayList<>();
148 
149  boolean[] used = new boolean[boundaryEdges.size()];
150  Edge edge = boundaryEdges.get(0);
151  used[0] = true;
152  while (true) {
153  Edge finalEdge = edge;
154 
155  boundaryPath.add(finalEdge.p1.pos);
156 
157  int nextEdgeIndex = boundaryEdges.indexOf(boundaryEdges.stream().
158  filter(e -> finalEdge.p2.equals(e.p1)).findFirst().get());
159 
160  if (used[nextEdgeIndex]) {
161 // System.out.println("nexIndex: " + nextEdgeIndex);
162  break;
163  }
164 // System.out.print("edge: " + edge.p2.pos);
165  edge = boundaryEdges.get(nextEdgeIndex);
166 // System.out.println("-> edge: " + edge.p1.pos);
167  used[nextEdgeIndex] = true;
168  }
169 
170  List<Polygon> result = new ArrayList<>();
171 
172  System.out.println("#bnd-path-length: " + boundaryPath.size());
173 
174  result.add(toPolygon(boundaryPath, plane));
175 
176  return result;
177  }
178 
184  private static class Node<T> {
185 
187  private Node parent;
188 
190  private final List<Node> children = new ArrayList<>();
191 
193  private final int index;
194 
196  private final T value;
197 
199  private boolean isHole;
200 
207  public Node(int index, T value) {
208  this.index = index;
209  this.value = value;
210  }
211 
218  public void addChild(int index, T value) {
219  children.add(new Node(index, value));
220  }
221 
227  public List<Node> getChildren() {
228  return this.children;
229  }
230 
236  public Node getParent() {
237  return parent;
238  }
239 
245  public int getIndex() {
246  return index;
247  }
248 
254  public T getValue() {
255  return value;
256  }
257 
258  /* (non-Javadoc)
259  * @see java.lang.Object#hashCode()
260  */
261  @Override
262  public int hashCode() {
263  int hash = 7;
264  hash = 67 * hash + this.index;
265  return hash;
266  }
267 
268  /* (non-Javadoc)
269  * @see java.lang.Object#equals(java.lang.Object)
270  */
271  @Override
272  public boolean equals(Object obj) {
273  if (obj == null) {
274  return false;
275  }
276  if (getClass() != obj.getClass()) {
277  return false;
278  }
279  final Node<?> other = (Node<?>) obj;
280  if (this.index != other.index) {
281  return false;
282  }
283  return true;
284  }
285 
291  public int distanceToRoot() {
292  int dist = 0;
293 
294  Node pNode = getParent();
295 
296  while (pNode != null) {
297  dist++;
298  pNode = getParent();
299  }
300 
301  return dist;
302  }
303 
309  public boolean isIsHole() {
310  return isHole;
311  }
312 
318  public void setIsHole(boolean isHole) {
319  this.isHole = isHole;
320  }
321 
322  }
323 
325  public static final String KEY_POLYGON_HOLES = "jcsg:edge:polygon-holes";
326 
333  public static List<Polygon> boundaryPathsWithHoles(List<Polygon> boundaryPaths) {
334 
335  List<Polygon> result = boundaryPaths.stream().
336  map(p -> p.clone()).collect(Collectors.toList());
337 
338  List<List<Integer>> parents = new ArrayList<>();
339  boolean[] isHole = new boolean[result.size()];
340 
341  for (int i = 0; i < result.size(); i++) {
342  Polygon p1 = result.get(i);
343  List<Integer> parentsOfI = new ArrayList<>();
344  parents.add(parentsOfI);
345  for (int j = 0; j < result.size(); j++) {
346  Polygon p2 = result.get(j);
347  if (i != j) {
348  if (p2.contains(p1)) {
349  parentsOfI.add(j);
350  }
351  }
352  }
353  isHole[i] = parentsOfI.size() % 2 != 0;
354  }
355 
356  int[] parent = new int[result.size()];
357 
358  for (int i = 0; i < parent.length; i++) {
359  parent[i] = -1;
360  }
361 
362  for (int i = 0; i < parents.size(); i++) {
363  List<Integer> par = parents.get(i);
364 
365  int max = 0;
366  int maxIndex = 0;
367  for (int pIndex : par) {
368 
369  int pSize = parents.get(pIndex).size();
370 
371  if (max < pSize) {
372  max = pSize;
373  maxIndex = pIndex;
374  }
375  }
376 
377  parent[i] = maxIndex;
378 
379  if (!isHole[maxIndex] && isHole[i]) {
380 
381  List<Polygon> holes;
382 
383  Optional<List<Polygon>> holesOpt = result.get(maxIndex).
384  getStorage().getValue(KEY_POLYGON_HOLES);
385 
386  if (holesOpt.isPresent()) {
387  holes = holesOpt.get();
388  } else {
389  holes = new ArrayList<>();
390  result.get(maxIndex).getStorage().
391  set(KEY_POLYGON_HOLES, holes);
392  }
393 
394  holes.add(result.get(i));
395  }
396  }
397 
398  return result;
399  }
400 
407  public static List<Polygon> boundaryPaths(List<Edge> boundaryEdges) {
408  List<Polygon> result = new ArrayList<>();
409 
410  boolean[] used = new boolean[boundaryEdges.size()];
411  int startIndex = 0;
412  Edge edge = boundaryEdges.get(startIndex);
413  used[startIndex] = true;
414 
415  startIndex = 1;
416 
417  while (startIndex > 0) {
418  List<Vector3d> boundaryPath = new ArrayList<>();
419 
420  while (true) {
421  Edge finalEdge = edge;
422 
423  boundaryPath.add(finalEdge.p1.pos);
424 
425 // System.out.print("edge: " + edge.p2.pos);
426 
427  Optional<Edge> nextEdgeResult = boundaryEdges.stream().
428  filter(e -> finalEdge.p2.equals(e.p1)).findFirst();
429 
430  if (!nextEdgeResult.isPresent()) {
431 // System.out.println("ERROR: unclosed path:"
432 // + " no edge found with " + finalEdge.p2);
433  break;
434  }
435 
436  Edge nextEdge = nextEdgeResult.get();
437 
438  int nextEdgeIndex = boundaryEdges.indexOf(nextEdge);
439 
440  if (used[nextEdgeIndex]) {
441  break;
442  }
443 
444  edge = nextEdge;
445 // System.out.println("-> edge: " + edge.p1.pos);
446  used[nextEdgeIndex] = true;
447  }
448 
449  if (boundaryPath.size() < 3) {
450  break;
451  }
452 
453  result.add(Polygon.fromPoints(boundaryPath));
454  startIndex = nextUnused(used);
455 
456  if (startIndex > 0) {
457  edge = boundaryEdges.get(startIndex);
458  used[startIndex] = true;
459  }
460 
461  }
462 //
463 // System.out.println("paths: " + result.size());
464 
465  return result;
466  }
467 
474  private static int nextUnused(boolean[] usage) {
475  for (int i = 0; i < usage.length; i++) {
476  if (usage[i] == false) {
477  return i;
478  }
479  }
480 
481  return -1;
482  }
483 
491  public static List<Polygon> _toPolygons(List<Edge> boundaryEdges, Plane plane) {
492 
493  List<Vector3d> boundaryPath = new ArrayList<>();
494 
495  boolean[] used = new boolean[boundaryEdges.size()];
496  Edge edge = boundaryEdges.get(0);
497  used[0] = true;
498  while (true) {
499  Edge finalEdge = edge;
500 
501  boundaryPath.add(finalEdge.p1.pos);
502 
503  int nextEdgeIndex = boundaryEdges.indexOf(boundaryEdges.stream().
504  filter(e -> finalEdge.p2.equals(e.p1)).findFirst().get());
505 
506  if (used[nextEdgeIndex]) {
507 // System.out.println("nexIndex: " + nextEdgeIndex);
508  break;
509  }
510 // System.out.print("edge: " + edge.p2.pos);
511  edge = boundaryEdges.get(nextEdgeIndex);
512 // System.out.println("-> edge: " + edge.p1.pos);
513  used[nextEdgeIndex] = true;
514  }
515 
516  List<Polygon> result = new ArrayList<>();
517 
518  System.out.println("#bnd-path-length: " + boundaryPath.size());
519 
520  result.add(toPolygon(boundaryPath, plane));
521 
522  return result;
523  }
531  public boolean colinear(Vector3d p) {
532  return colinear(p,Plane.EPSILON_Point);
533  }
534  public boolean colinear(Vector3d p, double TOL) {
535 
536  double x = p.x;
537  double x1 = this.p1.pos.x;
538  double x2 = this.p2.pos.x;
539 
540  double y = p.y;
541  double y1 = this.p1.pos.y;
542  double y2 = this.p2.pos.y;
543 
544  double z = p.z;
545  double z1 = this.p1.pos.z;
546  double z2 = this.p2.pos.z;
547 
548  double slopeSelfxy = (x1-x2)/(y1-y2);
549  double slopeSelfxz = (x1-x2)/(z1-z2);
550  double slopeSelfyz = (y1-y2)/(z1-z2);
551 
552 
553  double slopeTestxy = (x-x2)/(y-y2);
554  double slopeTestxz = (x-x2)/(z-z2);
555  double slopeTestyz = (y-y2)/(z-z2);
556 
557 
558  return Math.abs(slopeSelfxy - slopeTestxy) < TOL &&
559  Math.abs(slopeSelfxz - slopeTestxz) < TOL&&
560  Math.abs(slopeSelfyz - slopeTestyz) < TOL;
561  }
570  public boolean contains(Vector3d p, double TOL) {
571 
572  double x = p.x;
573  double x1 = this.p1.pos.x;
574  double x2 = this.p2.pos.x;
575 
576  double y = p.y;
577  double y1 = this.p1.pos.y;
578  double y2 = this.p2.pos.y;
579 
580  double z = p.z;
581  double z1 = this.p1.pos.z;
582  double z2 = this.p2.pos.z;
583 
584  double AB = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) + (z2 - z1) * (z2 - z1));
585  double AP = Math.sqrt((x - x1) * (x - x1) + (y - y1) * (y - y1) + (z - z1) * (z - z1));
586  double PB = Math.sqrt((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y) + (z2 - z) * (z2 - z));
587 
588  return Math.abs(AB - (AP + PB)) < TOL;
589  }
590 
598  public boolean contains(Vector3d p) {
599  return contains(p, Plane.EPSILON);
600  }
601 
602  /* (non-Javadoc)
603  * @see java.lang.Object#hashCode()
604  */
605  @Override
606  public int hashCode() {
607  int hash = 7;
608  hash = 71 * hash + Objects.hashCode(this.p1);
609  hash = 71 * hash + Objects.hashCode(this.p2);
610  return hash;
611  }
612 
613  /* (non-Javadoc)
614  * @see java.lang.Object#equals(java.lang.Object)
615  */
616  @Override
617  public boolean equals(Object obj) {
618  if (obj == null) {
619  return false;
620  }
621  if (getClass() != obj.getClass()) {
622  return false;
623  }
624  final Edge other = (Edge) obj;
625  if(this.p1.pos.test( other.p1.pos,Plane.EPSILON_Point) && this.p2.pos.test( other.p2.pos,Plane.EPSILON_Point)) {
626  return true;
627  }
628  if(this.p1.pos.test( other.p2.pos,Plane.EPSILON_Point) && this.p2.pos.test( other.p1.pos,Plane.EPSILON_Point)) {
629  return true;
630  }
631  if (!(Objects.equals(this.p1, other.p1) || Objects.equals(this.p2, other.p1))) {
632  return false;
633  }
634  if (!(Objects.equals(this.p2, other.p2) || Objects.equals(this.p1, other.p2))) {
635  return false;
636  }
637  return true;
638  }
639 
640  public boolean isThisPointOneOfMine(Vertex test) {
641  return p1.pos.test(test.pos, Plane.EPSILON_Point)||p2.pos.test(test.pos, Plane.EPSILON_Point);
642  }
643 
644  @Override
645  public String toString()
646  {
647  return "[[" + this.p1.getX() + ", " + this.p1.getY() + ", " + this.p1.getZ() + "]" +
648  ", [" + this.p2.getX() + ", " + this.p2.getY() + ", " + this.p2.getZ() + "]]";
649  }
650 
657  return direction;
658  }
659 
668  public Optional<Vector3d> getClosestPoint(Edge e) {
669 
670  // algorithm from:
671  // org.apache.commons.math3.geometry.euclidean.threed/Line.java.html
672  Vector3d ourDir = getDirection();
673 
674  double cos = ourDir.dot(e.getDirection());
675  double n = 1 - cos * cos;
676 
677  if (n < Plane.EPSILON) {
678  // the lines are parallel
679  return Optional.empty();
680  }
681 
682  final Vector3d thisDelta = p2.pos.minus(p1.pos);
683  final double norm2This = thisDelta.magnitudeSq();
684 
685  final Vector3d eDelta = e.p2.pos.minus(e.p1.pos);
686  final double norm2E = eDelta.magnitudeSq();
687 
688  // line points above the origin
689  Vector3d thisZero = p1.pos.plus(thisDelta.times(-p1.pos.dot(thisDelta) / norm2This));
690  Vector3d eZero = e.p1.pos.plus(eDelta.times(-e.p1.pos.dot(eDelta) / norm2E));
691 
692  final Vector3d delta0 = eZero.minus(thisZero);
693  final double a = delta0.dot(direction);
694  final double b = delta0.dot(e.direction);
695 
696  Vector3d closestP = thisZero.plus(direction.times((a - b * cos) / n));
697 
698  if (!contains(closestP)) {
699  if (closestP.minus(p1.pos).magnitudeSq()
700  < closestP.minus(p2.pos).magnitudeSq()) {
701  return Optional.of(p1.pos);
702  } else {
703  return Optional.of(p2.pos);
704  }
705  }
706 
707  return Optional.of(closestP);
708  }
709 
719  public Optional<Vector3d> getIntersection(Edge e) {
720  Optional<Vector3d> closestPOpt = getClosestPoint(e);
721 
722  if (!closestPOpt.isPresent()) {
723  // edges are parallel
724  return Optional.empty();
725  }
726 
727  Vector3d closestP = closestPOpt.get();
728 
729  if (e.contains(closestP)) {
730  return closestPOpt;
731  } else {
732  // intersection point outside of segment
733  return Optional.empty();
734  }
735  }
736 
743  public static List<Polygon> boundaryPolygons(CSG csg) {
744  List<Polygon> result = new ArrayList<>();
745 
746  for (List<Polygon> polygonGroup : searchPlaneGroups(csg.getPolygons())) {
747  result.addAll(boundaryPolygonsOfPlaneGroup(polygonGroup));
748  }
749 
750  return result;
751  }
752 
759  public static List<Edge> boundaryEdgesOfPlaneGroup(List<Polygon> planeGroup) {
760  List<Edge> edges = new ArrayList<>();
761 
762  Stream<Polygon> pStream;
763 
764  if (planeGroup.size() > 200) {
765  pStream = planeGroup.parallelStream();
766  } else {
767  pStream = planeGroup.stream();
768  }
769 
770  pStream.map((p) -> Edge.fromPolygon(p)).forEach((pEdges) -> {
771  edges.addAll(pEdges);
772  });
773 
774  Stream<Edge> edgeStream;
775 
776  if (edges.size() > 200) {
777  edgeStream = edges.parallelStream();
778  } else {
779  edgeStream = edges.stream();
780  }
781 
782  // find potential boundary edges, i.e., edges that occur once (freq=1)
783  List<Edge> potentialBoundaryEdges = new ArrayList<>();
784  edgeStream.forEachOrdered((e) -> {
785  int count = Collections.frequency(edges, e);
786  if (count == 1) {
787  potentialBoundaryEdges.add(e);
788  }
789  });
790 
791  // now find "false boundary" edges end remove them from the
792  // boundary-edge-list
793  //
794  // thanks to Susanne Höllbacher for the idea :)
795  Stream<Edge> bndEdgeStream;
796 
797  if (potentialBoundaryEdges.size() > 200) {
798  bndEdgeStream = potentialBoundaryEdges.parallelStream();
799  } else {
800  bndEdgeStream = potentialBoundaryEdges.stream();
801  }
802 
803  List<Edge> realBndEdges = bndEdgeStream.
804  filter(be -> edges.stream().filter(
806  ).count() == 0).collect(Collectors.toList());
807 
808  //
809 // System.out.println("#bnd-edges: " + realBndEdges.size()
810 // + ",#edges: " + edges.size()
811 // + ", #del-bnd-edges: " + (boundaryEdges.size() - realBndEdges.size()));
812  return realBndEdges;
813  }
814 
821  private static List<Polygon> boundaryPolygonsOfPlaneGroup(
822  List<Polygon> planeGroup) {
823 
824  List<Polygon> polygons = boundaryPathsWithHoles(
826 
827  System.out.println("polygons: " + polygons.size());
828 
829  List<Polygon> result = new ArrayList<>(polygons.size());
830 
831  for (Polygon p : polygons) {
832 
833  Optional<List<Polygon>> holesOfPresult
834  = p.
835  getStorage().getValue(Edge.KEY_POLYGON_HOLES);
836 
837  if (!holesOfPresult.isPresent()) {
838  result.add(p);
839  } else {
840  result.addAll(PolygonUtil.concaveToConvex(p));
841  }
842  }
843 
844  return result;
845  }
846 
854  public static boolean falseBoundaryEdgeSharedWithOtherEdge(Edge fbe, Edge e) {
855 
856  // we don't consider edges with shared end-points since we are only
857  // interested in "false-boundary-edge"-cases
858  boolean sharedEndPoints = e.getP1().pos.equals(fbe.getP1().pos)
859  || e.getP1().pos.equals(fbe.getP2().pos)
860  || e.getP2().pos.equals(fbe.getP1().pos)
861  || e.getP2().pos.equals(fbe.getP2().pos);
862 
863  if (sharedEndPoints) {
864  return false;
865  }
866 
867  return fbe.contains(e.getP1().pos) || fbe.contains(e.getP2().pos);
868  }
869 
876  private static List<List<Polygon>> searchPlaneGroups(List<Polygon> polygons) {
877  List<List<Polygon>> planeGroups = new ArrayList<>();
878  boolean[] used = new boolean[polygons.size()];
879  System.out.println("#polys: " + polygons.size());
880  for (int pOuterI = 0; pOuterI < polygons.size(); pOuterI++) {
881 
882  if (used[pOuterI]) {
883  continue;
884  }
885 
886  Polygon pOuter = polygons.get(pOuterI);
887 
888  List<Polygon> otherPolysInPlane = new ArrayList<>();
889 
890  otherPolysInPlane.add(pOuter);
891 
892  for (int pInnerI = 0; pInnerI < polygons.size(); pInnerI++) {
893 
894  Polygon pInner = polygons.get(pInnerI);
895 
896  if (pOuter.equals(pInner)) {
897  continue;
898  }
899 
900  Vector3d nOuter = pOuter.plane.normal;
901  Vector3d nInner = pInner.plane.normal;
902 
903  double angle = nOuter.angle(nInner);
904 
905 // System.out.println("angle: " + angle + " between " + pOuterI+" -> " + pInnerI);
906  if (angle < 0.01 /*&& abs(pOuter.plane.dist - pInner.plane.dist) < 0.1*/) {
907  otherPolysInPlane.add(pInner);
908  used[pInnerI] = true;
909  System.out.println("used: " + pOuterI + " -> " + pInnerI);
910  }
911  }
912 
913  if (!otherPolysInPlane.isEmpty()) {
914  planeGroups.add(otherPolysInPlane);
915  }
916  }
917  return planeGroups;
918  }
919 
920  public double length() {
921  // TODO Auto-generated method stub
922  return p1.pos.minus(p2.pos).length();
923  }
924 
925 }
List< Polygon > getPolygons()
Definition: CSG.java:698
final Vertex p2
Definition: Edge.java:28
boolean isThisPointOneOfMine(Vertex test)
Definition: Edge.java:640
static int nextUnused(boolean[] usage)
Definition: Edge.java:474
boolean contains(Vector3d p)
Definition: Edge.java:598
static List< Polygon > toPolygons(List< Edge > boundaryEdges, Plane plane)
Definition: Edge.java:145
static boolean falseBoundaryEdgeSharedWithOtherEdge(Edge fbe, Edge e)
Definition: Edge.java:854
boolean colinear(Vector3d p)
Definition: Edge.java:531
Optional< Vector3d > getClosestPoint(Edge e)
Definition: Edge.java:668
static Polygon toPolygon(List< Vector3d > points, Plane plane)
Definition: Edge.java:121
Edge(Vertex p1, Vertex p2)
Definition: Edge.java:39
static List< List< Polygon > > searchPlaneGroups(List< Polygon > polygons)
Definition: Edge.java:876
Vector3d getDirection()
Definition: Edge.java:656
static List< Vertex > toVertices(List< Edge > edges)
Definition: Edge.java:100
boolean contains(Vector3d p, double TOL)
Definition: Edge.java:570
static List< Edge > fromPolygon(Polygon poly)
Definition: Edge.java:82
static List< Polygon > _toPolygons(List< Edge > boundaryEdges, Plane plane)
Definition: Edge.java:491
boolean colinear(Vector3d p, double TOL)
Definition: Edge.java:534
final Vertex p1
Definition: Edge.java:25
final Vector3d direction
Definition: Edge.java:31
static List< Polygon > boundaryPaths(List< Edge > boundaryEdges)
Definition: Edge.java:407
static final String KEY_POLYGON_HOLES
Definition: Edge.java:325
static List< Vector3d > toPoints(List< Edge > edges)
Definition: Edge.java:110
static List< Edge > boundaryEdgesOfPlaneGroup(List< Polygon > planeGroup)
Definition: Edge.java:759
static List< Polygon > boundaryPolygonsOfPlaneGroup(List< Polygon > planeGroup)
Definition: Edge.java:821
boolean equals(Object obj)
Definition: Edge.java:617
Optional< Vector3d > getIntersection(Edge e)
Definition: Edge.java:719
static List< Polygon > boundaryPolygons(CSG csg)
Definition: Edge.java:743
static List< Polygon > boundaryPathsWithHoles(List< Polygon > boundaryPaths)
Definition: Edge.java:333
static final double EPSILON
Definition: Plane.java:55
static final double EPSILON_Point
Definition: Plane.java:56
final List< Vertex > vertices
Definition: Polygon.java:54
static Polygon fromPoints(List< Vector3d > points, PropertyStorage shared)
Definition: Polygon.java:386
boolean equals(Object obj)
Definition: Vector3d.java:401
Vector3d times(double a)
Definition: Vector3d.java:191
Vector3d plus(Vector3d v)
Definition: Vector3d.java:165
double angle(Vector3d v)
Definition: Vector3d.java:431
static Vector3d y(double y)
Definition: Vector3d.java:484
double dot(Vector3d a)
Definition: Vector3d.java:230
Vector3d minus(Vector3d v)
Definition: Vector3d.java:178
static Vector3d z(double z)
Definition: Vector3d.java:494
boolean test(Object obj, double epsilon)
Definition: Vector3d.java:405
static Vector3d x(double x)
Definition: Vector3d.java:474
boolean equals(Object obj)
Definition: Vertex.java:205
static List< eu.mihosoft.vrl.v3d.Polygon > concaveToConvex(eu.mihosoft.vrl.v3d.Polygon incoming)