JavaCAD
Polygon.java
Go to the documentation of this file.
1 
34 package eu.mihosoft.vrl.v3d;
35 
36 import java.util.ArrayList;
37 import java.util.Arrays;
38 import java.util.Collections;
39 import java.util.List;
40 import eu.mihosoft.vrl.v3d.ext.org.poly2tri.PolygonUtil;
41 
42 // TODO: Auto-generated Javadoc
51 public final class Polygon {
52 
54  public final List<Vertex> vertices;
64  public final Plane plane;
65 
66 
72  void setStorage(PropertyStorage storage) {
73  this.shared = storage;
74  }
75 
82  public static List<Polygon> fromConcavePoints(Vector3d... points) {
83  Polygon p = fromPoints(points);
84 
85  return PolygonUtil.concaveToConvex(p);
86  }
87 
94  public static List<Polygon> fromConcavePoints(List<Vector3d> points) {
95  Polygon p = fromPoints(points);
96 
97  return PolygonUtil.concaveToConvex(p);
98  }
99 
110  public Polygon(List<Vertex> vertices, PropertyStorage shared, boolean allowDegenerate) {
111  this.vertices = pruneDuplicatePoints(vertices);
112  this.shared = shared;
113  this.plane = Plane.createFromPoints(
114  vertices.get(0).pos,
115  vertices.get(1).pos,
116  vertices.get(2).pos);
117  validateAndInit(allowDegenerate);
118  }
129  public Polygon(List<Vertex> vertices, PropertyStorage shared) {
130  this(vertices,shared,true);
131  }
141  public Polygon(List<Vertex> vertices) {
142  this.vertices = pruneDuplicatePoints(vertices);
143  this.plane = Plane.createFromPoints(
144  vertices.get(0).pos,
145  vertices.get(1).pos,
146  vertices.get(2).pos);
147  validateAndInit(true);
148  }
149  public static List<Vertex> pruneDuplicatePoints(List<Vertex> incoming) {
150  return incoming;
151 // ArrayList<Vertex> newPoints = new ArrayList<Vertex>();
152 // for (int i = 0; i < incoming.size(); i++) {
153 // Vertex v = incoming.get(i);
154 // boolean duplicate = false;
155 // for (Vertex vx : newPoints) {
156 // if (vx.pos.test(v.pos, 1.0e-4)) {
157 // duplicate = true;
158 // }
159 // }
160 // if (!duplicate) {
161 // newPoints.add(v);
162 // }
163 //
164 // }
165 // try {
166 // return newPoints;
167 // } catch (java.lang.IndexOutOfBoundsException ex) {
168 // return null;
169 // }
170  }
171  private void validateAndInit( boolean allowDegenerate) {
172  for (Vertex v : vertices) {
173  v.normal = plane.normal;
174  }
175  setDegenerate(true);
177  valid = false;
178  throw new RuntimeException(
179  "Normal is zero! Probably, duplicate points have been specified!\n\n" + toStlString());
180  }
181 
182  if (vertices.size() < 3) {
183  throw new RuntimeException("Invalid polygon: at least 3 vertices expected, got: " + vertices.size());
184  }
185 
186  Edge e = new Edge(vertices.get(0), vertices.get(1));
187  for (int i = 2; i < vertices.size(); i++) {
188  if (!e.colinear(vertices.get(i).pos)) {
189  setDegenerate(false);
190  return;
191  }
192  }
193  if (!allowDegenerate) {
194  // throw runtimeException;
195  new RuntimeException("This polygon is colinear").printStackTrace();
196  }
197 
198  }
209  public Polygon(Vertex... vertices) {
210  this(Arrays.asList(vertices));
211  }
212 
213  /* (non-Javadoc)
214  * @see java.lang.Object#clone()
215  */
216  @Override
217  public Polygon clone() {
218  List<Vertex> newVertices = new ArrayList<>();
219  this.vertices.forEach((vertex) -> {
220  newVertices.add(vertex.clone());
221  });
222  return new Polygon(newVertices, getStorage(),true);
223  }
224 
230  public Polygon flip() {
231  vertices.forEach((vertex) -> {
232  vertex.flip();
233  });
234  Collections.reverse(vertices);
235 
236  plane.flip();
237 
238  return this;
239  }
240 
248  public Polygon flipped() {
249  return clone().flip();
250  }
251 
257  public String toStlString() {
258  return toStlString(new StringBuilder()).toString();
259  }
260 
268  public StringBuilder toStlString(StringBuilder sb) {
269 
270  if (this.vertices.size() == 3) {
271 
272  // TODO: improve the triangulation?
273  //
274  // STL requires triangular polygons.
275  // If our polygon has more vertices, create
276  // multiple triangles:
277  String firstVertexStl = this.vertices.get(0).toStlString();
278  for (int i = 0; i < this.vertices.size() - 2; i++) {
279  sb.
280  append(" facet normal ").append(
281  this.plane.normal.toStlString()).append("\n").
282  append(" outer loop\n").
283  append(" ").append(firstVertexStl).append("\n").
284  append(" ");
285  this.vertices.get(i + 1).toStlString(sb).append("\n").
286  append(" ");
287  this.vertices.get(i + 2).toStlString(sb).append("\n").
288  append(" endloop\n").
289  append(" endfacet\n");
290  }
291  }else {
292  throw new RuntimeException("Polygon must be a triangle before STL can be made "+vertices.size());
293  }
294 
295  return sb;
296  }
297 
305  vertices.forEach((vertex) -> {
306  vertex.pos = vertex.pos.plus(v);
307  });
308 
309  Vector3d a = this.vertices.get(0).pos;
310  Vector3d b = this.vertices.get(1).pos;
311  Vector3d c = this.vertices.get(2).pos;
312 
313  this.plane.normal = b.minus(a).cross(c.minus(a));
314 
315  return this;
316  }
317 
328  return clone().translate(v);
329  }
330 
342 
343  this.vertices.stream().forEach(
344  (v) -> {
345  v.transform(transform);
346  }
347  );
348 
349  Vector3d a = this.vertices.get(0).pos;
350  Vector3d b = this.vertices.get(1).pos;
351  Vector3d c = this.vertices.get(2).pos;
352 
353  this.plane.normal = b.minus(a).cross(c.minus(a)).normalized();
354  this.plane.dist = this.plane.normal.dot(a);
355 
356  if (transform.isMirror()) {
357  // the transformation includes mirroring. flip polygon
358  flip();
359 
360  }
361  return this;
362  }
363 
376  return clone().transform(transform);
377  }
378 
386  public static Polygon fromPoints(List<Vector3d> points,
388  return fromPoints(points, shared, null,true);
389  }
390 
397  public static Polygon fromPoints(List<Vector3d> points) {
398  return fromPoints(points, new PropertyStorage(), null,true);
399  }
400 
407  public static Polygon fromPoints(Vector3d... points) {
408  return fromPoints(Arrays.asList(points), new PropertyStorage(), null,true);
409  }
410  public static Polygon fromPointsAllowDegenerate(List<Vector3d> vertices2) {
411  return fromPoints(vertices2, new PropertyStorage(), null, true);
412  }
421  private static Polygon fromPoints(
422  List<Vector3d> points, PropertyStorage shared, Plane plane, boolean allowDegenerate) {
423 
424  Vector3d normal
425  = (plane != null) ? plane.normal.clone() : new Vector3d(0, 0, 0);
426 
427  List<Vertex> vertices = new ArrayList<>();
428 
429  for (Vector3d p : points) {
430  Vector3d vec = p.clone();
431  Vertex vertex = new Vertex(vec, normal);
432  vertices.add(vertex);
433  }
434 
435  return new Polygon(vertices, shared,allowDegenerate);
436  }
437 
443  public Bounds getBounds() {
444  double minX = Double.POSITIVE_INFINITY;
445  double minY = Double.POSITIVE_INFINITY;
446  double minZ = Double.POSITIVE_INFINITY;
447 
448  double maxX = Double.NEGATIVE_INFINITY;
449  double maxY = Double.NEGATIVE_INFINITY;
450  double maxZ = Double.NEGATIVE_INFINITY;
451 
452  for (int i = 0; i < vertices.size(); i++) {
453 
454  Vertex vert = vertices.get(i);
455 
456  if (vert.pos.x < minX) {
457  minX = vert.pos.x;
458  }
459  if (vert.pos.y < minY) {
460  minY = vert.pos.y;
461  }
462  if (vert.pos.z < minZ) {
463  minZ = vert.pos.z;
464  }
465 
466  if (vert.pos.x > maxX) {
467  maxX = vert.pos.x;
468  }
469  if (vert.pos.y > maxY) {
470  maxY = vert.pos.y;
471  }
472  if (vert.pos.z > maxZ) {
473  maxZ = vert.pos.z;
474  }
475 
476  } // end for vertices
477 
478  return new Bounds(
479  new Vector3d(minX, minY, minZ),
480  new Vector3d(maxX, maxY, maxZ));
481  }
482 
489  public boolean contains(Vector3d p) {
490  // taken from http://www.java-gaming.org/index.php?topic=26013.0
491  // and http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
492  double px = p.x;
493  double py = p.y;
494  boolean oddNodes = false;
495  double x2 = vertices.get(vertices.size() - 1).pos.x;
496  double y2 = vertices.get(vertices.size() - 1).pos.y;
497  double x1, y1;
498  for (int i = 0; i < vertices.size(); x2 = x1, y2 = y1, ++i) {
499  x1 = vertices.get(i).pos.x;
500  y1 = vertices.get(i).pos.y;
501  if (((y1 < py) && (y2 >= py))
502  || (y1 >= py) && (y2 < py)) {
503  if ((py - y1) / (y2 - y1)
504  * (x2 - x1) < (px - x1)) {
505  oddNodes = !oddNodes;
506  }
507  }
508  }
509  return oddNodes;
510  }
511 
518  public boolean contains(Polygon p) {
519 
520  for (Vertex v : p.vertices) {
521  if (!contains(v.pos)) {
522  return false;
523  }
524  }
525 
526  return true;
527  }
528 
535 
536  if (shared == null) {
537  shared = new PropertyStorage();
538  }
539 
540  return shared;
541  }
542 
543 // public Exception getCreationEventStackTrace() {
544 // return creationEventStackTrace;
545 // }
546 
547  public List<Vector3d> getPoints() {
548  ArrayList<Vector3d> p =new ArrayList<>();
549  for(Vertex v:vertices) {
550  p.add(v.pos);
551  }
552  return p;
553  }
561  // Helper/wrapper functions for movement
562  public Polygon movey(Number howFarToMove) {
563  return this.transformed(Transform.unity().translateY(howFarToMove.doubleValue()));
564  }
565 
573  public Polygon movez(Number howFarToMove) {
574  return this.transformed(Transform.unity().translateZ(howFarToMove.doubleValue()));
575  }
576 
584  public Polygon movex(Number howFarToMove) {
585  return this.transformed(Transform.unity().translateX(howFarToMove.doubleValue()));
586  }
587 
595  // Rotation function, rotates the object
596  public Polygon rotz(Number degreesToRotate) {
597  return this.transformed(new Transform().rotZ(degreesToRotate.doubleValue()));
598  }
599 
607  public Polygon roty(Number degreesToRotate) {
608  return this.transformed(new Transform().rotY(degreesToRotate.doubleValue()));
609  }
610 
618  public Polygon rotx(Number degreesToRotate) {
619  return this.transformed(new Transform().rotX(degreesToRotate.doubleValue()));
620  }
621 
629  // Scale function, scales the object
630  public Polygon scalez(Number scaleValue) {
631  return this.transformed(new Transform().scaleZ(scaleValue.doubleValue()));
632  }
633 
641  public Polygon scaley(Number scaleValue) {
642  return this.transformed(new Transform().scaleY(scaleValue.doubleValue()));
643  }
644 
652  public Polygon scalex(Number scaleValue) {
653  return this.transformed(new Transform().scaleX(scaleValue.doubleValue()));
654  }
655 
663  public Polygon scale(Number scaleValue) {
664  return this.transformed(new Transform().scale(scaleValue.doubleValue()));
665  }
666 
672  public boolean isValid() {
673  return valid;
674  }
675 
676  private boolean valid = true;
677  private boolean degenerate=false;
678 
679 
680  public void setDegenerate(boolean degenerate) {
681  this.degenerate = degenerate;
682  }
683  public boolean isDegenerate() {
684 
685  return degenerate;
686  }
687 
688  public ArrayList<Vertex> getDegeneratePoints() {
689  ArrayList<Vertex> back = new ArrayList<Vertex>();
690  if(!isDegenerate())
691  return back;
692  Edge longEdge = getLongEdge();
693  for(int i=0;i<vertices.size();i++) {
694  Vertex vertex = vertices.get(i);
695  if(vertex!= longEdge.getP1()&& vertex!=longEdge.getP2() ) {
696  back.add(vertex);
697  }
698  }
699  if(back.size()==0)
700  throw new RuntimeException("Failed to find the degenerate point in the polygon");
701  return back;
702  }
703 
704  public Edge getLongEdge() {
705  if(!isDegenerate())
706  return null;
707  ArrayList<Edge> e =edges();
708  Edge longEdge =e.get(0);
709  for(int i=1;i<e.size();i++) {
710  Edge edge = e.get(i);
711  if(edge.length()>longEdge.length()) {
712  longEdge=edge;
713  }
714  }
715  return longEdge;
716  }
717 
718  public ArrayList<Edge> edges() {
719  ArrayList<Edge> e=new ArrayList<Edge>();
720  for(int i=0;i<vertices.size();i++) {
721  int i1 = i;
722  int i2=i+1;
723  if(i2==vertices.size()) {
724  i2=0;
725  }
726  e.add(new Edge(vertices.get(i1),vertices.get(i2)));
727  }
728  return e;
729  }
730 
731 
732 }
boolean colinear(Vector3d p)
Definition: Edge.java:531
static Plane createFromPoints(Vector3d a, Vector3d b, Vector3d c)
Definition: Plane.java:100
void setDegenerate(boolean degenerate)
Definition: Polygon.java:680
Polygon rotx(Number degreesToRotate)
Definition: Polygon.java:618
Polygon scaley(Number scaleValue)
Definition: Polygon.java:641
ArrayList< Edge > edges()
Definition: Polygon.java:718
boolean contains(Vector3d p)
Definition: Polygon.java:489
void validateAndInit(boolean allowDegenerate)
Definition: Polygon.java:171
Polygon rotz(Number degreesToRotate)
Definition: Polygon.java:596
Polygon scale(Number scaleValue)
Definition: Polygon.java:663
static List< Vertex > pruneDuplicatePoints(List< Vertex > incoming)
Definition: Polygon.java:149
final List< Vertex > vertices
Definition: Polygon.java:54
Polygon(Vertex... vertices)
Definition: Polygon.java:209
Polygon(List< Vertex > vertices, PropertyStorage shared)
Definition: Polygon.java:129
Polygon movex(Number howFarToMove)
Definition: Polygon.java:584
Polygon movey(Number howFarToMove)
Definition: Polygon.java:562
ArrayList< Vertex > getDegeneratePoints()
Definition: Polygon.java:688
PropertyStorage shared
Definition: Polygon.java:58
Polygon translate(Vector3d v)
Definition: Polygon.java:304
static List< Polygon > fromConcavePoints(List< Vector3d > points)
Definition: Polygon.java:94
static Polygon fromPoints(List< Vector3d > points, PropertyStorage shared, Plane plane, boolean allowDegenerate)
Definition: Polygon.java:421
Polygon(List< Vertex > vertices)
Definition: Polygon.java:141
static List< Polygon > fromConcavePoints(Vector3d... points)
Definition: Polygon.java:82
static Polygon fromPoints(Vector3d... points)
Definition: Polygon.java:407
List< Vector3d > getPoints()
Definition: Polygon.java:547
static Polygon fromPoints(List< Vector3d > points, PropertyStorage shared)
Definition: Polygon.java:386
Polygon(List< Vertex > vertices, PropertyStorage shared, boolean allowDegenerate)
Definition: Polygon.java:110
Polygon transform(Transform transform)
Definition: Polygon.java:341
Polygon roty(Number degreesToRotate)
Definition: Polygon.java:607
Polygon movez(Number howFarToMove)
Definition: Polygon.java:573
static Polygon fromPointsAllowDegenerate(List< Vector3d > vertices2)
Definition: Polygon.java:410
boolean contains(Polygon p)
Definition: Polygon.java:518
Polygon translated(Vector3d v)
Definition: Polygon.java:327
PropertyStorage getStorage()
Definition: Polygon.java:534
static Polygon fromPoints(List< Vector3d > points)
Definition: Polygon.java:397
StringBuilder toStlString(StringBuilder sb)
Definition: Polygon.java:268
Polygon scalez(Number scaleValue)
Definition: Polygon.java:630
Polygon transformed(Transform transform)
Definition: Polygon.java:375
Polygon scalex(Number scaleValue)
Definition: Polygon.java:652
Transform translateZ(double value)
Definition: Transform.java:313
Transform translateX(double value)
Definition: Transform.java:217
static Transform unity()
Definition: Transform.java:85
Transform translateY(double value)
Definition: Transform.java:299
Vector3d cross(Vector3d a)
Definition: Vector3d.java:291
boolean equals(Object obj)
Definition: Vector3d.java:401
static Vector3d y(double y)
Definition: Vector3d.java:484
static final Vector3d ZERO
Definition: Vector3d.java:57
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
static Vector3d x(double x)
Definition: Vector3d.java:474
static List< eu.mihosoft.vrl.v3d.Polygon > concaveToConvex(eu.mihosoft.vrl.v3d.Polygon incoming)