1 package org.simantics.plant3d.scenegraph.controlpoint;
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.Collection;
8 import javax.vecmath.AxisAngle4d;
9 import javax.vecmath.Matrix3d;
10 import javax.vecmath.Point3d;
11 import javax.vecmath.Quat4d;
12 import javax.vecmath.Tuple3d;
13 import javax.vecmath.Vector3d;
15 import org.simantics.g3d.math.MathTools;
16 import org.simantics.g3d.property.annotations.GetPropertyValue;
17 import org.simantics.g3d.scenegraph.G3DNode;
18 import org.simantics.plant3d.scenegraph.IP3DNode;
19 import org.simantics.plant3d.scenegraph.PipeRun;
20 import org.simantics.plant3d.scenegraph.PipelineComponent;
22 import vtk.vtkRenderer;
25 public class PipeControlPoint extends G3DNode implements IP3DNode {
27 private static boolean DEBUG = false;
29 public enum PointType{INLINE,TURN,END};
30 public enum Direction{NEXT,PREVIOUS};
31 public enum PositionType {SPLIT,NEXT,PREVIOUS,PORT}
33 private PipelineComponent component;
35 private PointType type;
36 private boolean isFixed = true;
37 private boolean isRotate = false;
38 private boolean isReverse = false;
39 private boolean isDeletable = true;
40 private boolean isSizeChange = false;
41 private boolean isSub = false;
43 public PipeControlPoint(PipelineComponent component) {
44 this.component = component;
45 if (component.getPipeRun() != null)
46 component.getPipeRun().addChild(this);
50 public PipeControlPoint(PipelineComponent component, PipeRun piperun) {
51 this.component = component;
52 piperun.addChild(this);
56 public void update(vtkRenderer ren) {
58 PipingRules.requestUpdate(this);
59 } catch (Exception e) {
65 public PipeRun getPipeRun() {
66 return (PipeRun)getParent();
69 public PipelineComponent getPipelineComponent() {
73 public PointType getType() {
77 public void setType(PointType type) {
81 @GetPropertyValue(name="Fixed",tabId="Debug",value="fixed")
82 public boolean isFixed() {
87 public void setFixed(boolean fixed) {
91 @GetPropertyValue(name="Rotate",tabId="Debug",value="rotate")
92 public boolean isRotate() {
96 public void setRotate(boolean rotate) {
97 this.isRotate = rotate;
100 @GetPropertyValue(name="Reverse",tabId="Debug",value="reverse")
101 public boolean isReverse() {
105 public void setReverse(boolean reverse) {
106 this.isReverse = reverse;
109 public void setSub(boolean sub) {
113 @GetPropertyValue(name="Deletable",tabId="Debug",value="deletable")
114 public boolean isDeletable() {
118 public void setDeletable(boolean deletable) {
119 this.isDeletable = deletable;
122 public boolean isPathLegEnd() {
123 return type != PointType.INLINE;
126 public boolean isEnd() {
127 return type == PointType.END;
130 public boolean isTurn() {
131 return type == PointType.TURN;
134 public boolean isInline() {
135 return type == PointType.INLINE;
138 public boolean isDirected() {
139 return isFixed && isEnd();
142 public boolean isNonDirected() {
143 return !isFixed && isEnd();
146 public boolean isVariableLength() {
147 return !isFixed && isInline();
150 public boolean isVariableAngle() {
151 return !isFixed && isTurn();
154 public boolean isBranchEnd() {
155 return isDeletable && isEnd();
158 public boolean isOffset() {
159 return offset != null;
162 public boolean isDualSub() {
163 return parent != null && isSub;
166 public boolean isDualInline() {
167 return children.size() == 1 && children.get(0).isDualSub();
170 public boolean isSizeChange() {
172 // if (children.size() == 0)
174 // if (!isDualInline())
176 // return getPipeRun() != children.get(0).getPipeRun();
179 public void setSizeChange(boolean isSizeChange) {
180 this.isSizeChange = isSizeChange;
184 private PipeControlPoint next;
185 private PipeControlPoint previous;
187 public PipeControlPoint getNext() {
191 public PipeControlPoint getPrevious() {
195 public void setNext(PipeControlPoint next) {
196 if (isEnd() && previous != null && next != null)
197 throw new RuntimeException("End control points are allowed to have only one connection");
199 throw new RuntimeException("Cannot connect to self");
200 if (this.next == next)
202 if (DEBUG) System.out.println(this + " next " + next);
204 if (component != null) {
205 if (parent == null || isSub)
206 component.setNext(next != null ? next.component : null);
208 component.setBranch0(next != null ? next.component : null);
214 public void setPrevious(PipeControlPoint previous) {
215 if (isEnd() && next != null && previous != null)
216 throw new RuntimeException("End control points are allowed to have only one connection");
217 if (previous == this)
218 throw new RuntimeException("Cannot connect to self");
219 if (this.previous == previous)
221 if (DEBUG) System.out.println(this + " previous " + previous);
222 this.previous = previous;
223 if (component != null) {
224 if (parent == null || isSub)
225 component.setPrevious(previous != null ? previous.component : null);
227 component.setBranch0(previous != null ? previous.component : null);
233 public PipeControlPoint parent;
234 public List<PipeControlPoint> children = new ArrayList<PipeControlPoint>();
236 public List<PipeControlPoint> getSubPoint() {
240 public PipeControlPoint getParentPoint() {
245 private double length;
246 private Double turnAngle;
247 private Vector3d turnAxis;
249 private Double offset;
250 private Double rotationAngle;
251 private Boolean reversed;
253 @GetPropertyValue(name="Length",tabId="Debug",value="length")
254 public double getLength() {
258 public void setLength(double l) {
259 if (Double.isInfinite(l) || Double.isNaN(l)) {
262 if (Math.abs(this.length-l) < MathTools.NEAR_ZERO)
265 firePropertyChanged("length");
267 getSubPoint().get(0).setLength(l);
270 @GetPropertyValue(name="Turn Angle",tabId="Debug",value="turnAngle")
271 public Double getTurnAngle() {
275 @GetPropertyValue(name="Turn Axis",tabId="Debug",value="turnAxis")
276 public Vector3d getTurnAxis() {
280 @GetPropertyValue(name="Offset",tabId="Debug",value="offset")
281 public Double getOffset() {
285 @GetPropertyValue(name="Rotation Angle",tabId="Debug",value="rotationAngle")
286 public Double getRotationAngle() {
287 return rotationAngle;
290 @GetPropertyValue(name="Reversed",tabId="Debug",value="reversed")
291 public Boolean getReversed() {
295 public boolean _getReversed() {
296 if (reversed == null)
301 public void setTurnAngle(Double turnAngle) {
302 if (turnAngle == null || Double.isInfinite(turnAngle) || Double.isNaN(turnAngle)) {
305 if (this.turnAngle != null && Math.abs(this.turnAngle-turnAngle) < MathTools.NEAR_ZERO)
307 this.turnAngle = turnAngle;
308 firePropertyChanged("turnAngle");
311 public void setTurnAxis(Vector3d turnAxis) {
312 if (this.turnAxis != null && MathTools.equals(turnAxis, this.turnAxis))
314 this.turnAxis = turnAxis;
315 firePropertyChanged("turnAxis");
318 public void setOffset(Double offset) {
319 if (Double.isInfinite(offset) || Double.isNaN(offset)) {
322 if (this.offset != null && Math.abs(this.offset-offset) < MathTools.NEAR_ZERO)
324 this.offset = offset;
325 firePropertyChanged("offset");
328 public void setRotationAngle(Double rotationAngle) {
329 if (Double.isInfinite(rotationAngle) || Double.isNaN(rotationAngle)) {
332 if (this.rotationAngle != null && Math.abs(this.rotationAngle-rotationAngle) < MathTools.NEAR_ZERO)
334 this.rotationAngle = rotationAngle;
335 firePropertyChanged("rotationAngle");
338 public void setReversed(Boolean reversed) {
339 this.reversed = reversed;
340 firePropertyChanged("reversed");
343 public Vector3d getSizeChangeOffsetVector(Vector3d dir) {
345 if (rotationAngle == null)
346 q = getControlPointOrientationQuat(dir, 0.0);
348 q = getControlPointOrientationQuat(dir, rotationAngle);
349 Vector3d v = new Vector3d(0.0,offset,0.0);
350 Vector3d offset = new Vector3d();
351 MathTools.rotate(q, v, offset);
355 public Vector3d getSizeChangeOffsetVector() {
357 if (rotationAngle == null)
358 q = getControlPointOrientationQuat(0.0);
360 q = getControlPointOrientationQuat(rotationAngle);
361 Vector3d v = new Vector3d(0.0,offset,0.0);
362 Vector3d offset = new Vector3d();
363 MathTools.rotate(q, v, offset);
367 @GetPropertyValue(name="Next",tabId="Debug",value="next")
368 private String getNextString() {
371 return next.toString();
374 @GetPropertyValue(name="Previous",tabId="Debug",value="previous")
375 private String getPrevString() {
376 if (previous == null)
378 return previous.toString();
381 @GetPropertyValue(name="Sub",tabId="Debug",value="sub")
382 private String getSubString() {
383 if (children.size() == 0)
385 return Arrays.toString(children.toArray());
388 @GetPropertyValue(name="Type",tabId="Debug",value="type")
389 public String getTypeString() {
393 public Quat4d getControlPointOrientationQuat(double angle) {
395 if (turnAxis == null) {
396 Vector3d dir = getPathLegDirection(Direction.NEXT);
397 if (dir.lengthSquared() > MathTools.NEAR_ZERO)
399 return getControlPointOrientationQuat(dir, angle);
401 Vector3d dir = getPathLegDirection(Direction.PREVIOUS);
403 if (dir.lengthSquared() > MathTools.NEAR_ZERO)
405 return getControlPointOrientationQuat(dir, turnAxis, angle);
409 public Quat4d getControlPointOrientationQuat(double angle, boolean reversed) {
411 if (turnAxis == null) {
412 Vector3d dir = getPathLegDirection(Direction.NEXT);
413 if (dir.lengthSquared() > MathTools.NEAR_ZERO)
415 Quat4d q = getControlPointOrientationQuat(dir, angle);
417 Quat4d q2 = new Quat4d();
418 q2.set(new AxisAngle4d(MathTools.Y_AXIS, Math.PI));
423 Vector3d dir = getPathLegDirection(Direction.PREVIOUS);
425 if (dir.lengthSquared() > MathTools.NEAR_ZERO)
427 return getControlPointOrientationQuat(dir, turnAxis, angle);
433 public static Quat4d getControlPointOrientationQuat(Vector3d dir, double angle) {
434 if (dir.lengthSquared() < MathTools.NEAR_ZERO)
435 return MathTools.getIdentityQuat();
438 Vector3d up = new Vector3d(0.0, 1.0, 0.0);
439 double a = up.angle(dir);
440 if (a < 0.1 || (Math.PI - a) < 0.1) {
441 up.set(1.0, 0.0, 0.0);
445 return getControlPointOrientationQuat(dir, up, angle);
448 public static Quat4d getControlPointOrientationQuat(Vector3d dir, Vector3d up, double angle) {
449 if (dir.lengthSquared() < MathTools.NEAR_ZERO)
450 return MathTools.getIdentityQuat();
452 final Vector3d front = new Vector3d(1.0,0.0,0.0);
454 Quat4d q1 = new Quat4d();
457 Vector3d right = new Vector3d();
459 right.cross(dir, up);
460 up.cross(right, dir);
464 Matrix3d m = new Matrix3d();
475 //q1.set(m); MathTools contains more stable conversion
476 MathTools.getQuat(m, q1);
478 // if (DEBUG) System.out.println("PipingTools.getPipeComponentOrientationQuat() " + dir+ " " + up + " " + right);
480 Quat4d q2 = new Quat4d();
481 q2.set(new AxisAngle4d(front, angle));
486 public Vector3d getDirection(Direction direction) {
488 return getDirectedControlPointDirection();
489 if (isTurn() && isFixed()) {
490 if (direction == Direction.NEXT) {
491 if (previous != null) {
492 PipeControlPoint pcp = this;
493 Vector3d dir = new Vector3d();
494 dir.sub(pcp.getWorldPosition(),previous.getWorldPosition());
495 if (dir.lengthSquared() > MathTools.NEAR_ZERO)
499 Quat4d q = getControlPointOrientationQuat(dir, pcp.getRotationAngle() != null ? pcp.getRotationAngle() : 0.0);
500 AxisAngle4d aa = new AxisAngle4d(MathTools.Y_AXIS,pcp.getTurnAngle() == null ? 0.0 : pcp.getTurnAngle());
501 Quat4d q2 = MathTools.getQuat(aa);
502 Vector3d v = new Vector3d(1.,0.,0.);
503 Vector3d offset = new Vector3d();
504 MathTools.rotate(q2, v, offset);
505 MathTools.rotate(q, offset, dir);
510 PipeControlPoint pcp = this;
511 Vector3d dir = new Vector3d();
512 dir.sub(next.getWorldPosition(),pcp.getWorldPosition());
513 if (dir.lengthSquared() > MathTools.NEAR_ZERO)
517 Quat4d q = getControlPointOrientationQuat(dir, pcp.getRotationAngle() != null ? pcp.getRotationAngle() : 0.0);
518 AxisAngle4d aa = new AxisAngle4d(MathTools.Y_AXIS,pcp.getTurnAngle() == null ? 0.0 : pcp.getTurnAngle());
519 Quat4d q2 = MathTools.getQuat(aa);
520 Vector3d v = new Vector3d(1.,0.,0.);
521 Vector3d offset = new Vector3d();
522 MathTools.rotate(q2, v, offset);
523 MathTools.rotate(q, offset, dir);
531 public void insert(PipeControlPoint previous, PipeControlPoint next) {
532 // inserting an offsetpoint is error,
534 throw new RuntimeException("Dual sub points cannot be inserted.");
535 // size change control point cannot be inserted this way, because it ends PipeRun
537 throw new RuntimeException("Size change points cannot be inserted.");
538 PipeRun piperun = previous.getPipeRun();
539 // and just to make sure that control point structure is not corrupted
540 if (getPipeRun() != null) {
541 if (piperun != getPipeRun() || piperun != next.getPipeRun())
542 throw new RuntimeException("All controls points must be located on the same pipe run");
544 piperun.addChild(this);
547 // insert new BranchControlPoint between straight's control points
548 PipeControlPoint previousNext = previous.getNext();
549 PipeControlPoint previousPrevious = previous.getPrevious();
551 PipeControlPoint offsetCP = null;
553 offsetCP = getSubPoint().get(0);
555 if (previousNext != null && previousNext == next) {
556 if (previous.isDualInline()) {
557 throw new RuntimeException();
559 if (next.isDualSub()) {
560 throw new RuntimeException();
562 previous.setNext(this);
563 this.setPrevious(previous);
564 if (previous.isDualSub()) {
565 previous.getParentPoint().setNext(this);
569 if (offsetCP == null) {
570 next.setPrevious(this);
572 next.setPrevious(offsetCP);
573 offsetCP.setNext(next);
574 offsetCP.setPrevious(previous);
577 if (next.isDualInline()) {
578 next.getSubPoint().get(0).setPrevious(this);
580 } else if (previousPrevious != null && previousPrevious == next) {
581 // control point were given in reverse order
582 if (next.isDualInline())
583 throw new RuntimeException();
584 if (previous.isDualSub())
585 throw new RuntimeException();
587 this.setNext(previous);
588 if (offsetCP == null) {
589 previous.setNext(this);
591 previous.setPrevious(offsetCP);
592 offsetCP.setNext(previous);
593 offsetCP.setPrevious(next);
595 if (previous.isDualInline()) {
596 previous.getSubPoint().get(0).setPrevious(this);
598 this.setPrevious(next);
600 if (next.isDualSub()) {
601 next.getParentPoint().setNext(this);
605 throw new RuntimeException();
608 PipingRules.validate(piperun);
613 public void insert(PipeControlPoint pcp, Direction direction) {
615 throw new RuntimeException();
616 if (direction == Direction.NEXT) {
617 // if direction is next, user must have given OffsetPoint
618 if (pcp.isDualInline())
619 throw new RuntimeException();
620 // basic next/prev links
622 this.setPrevious(pcp);
623 // and last take care of sizechange / offset points
624 if (pcp.isDualSub()) {
625 pcp.getParentPoint().setNext(this);
627 if (isDualInline()) {
628 getSubPoint().get(0).setPrevious(this);
631 // if direction is previous, user must have given sizechange
633 throw new RuntimeException();
634 // previous direction is more complicated, since if newCP is SizeChangeControlPoint,
635 // we must link pcp to newCP's OffsetPoint
636 PipeControlPoint nocp = null;
637 if (isDualInline()) {
638 nocp = getSubPoint().get(0);
642 pcp.setPrevious(this);
644 pcp.setPrevious(nocp);
647 if (pcp.isDualInline()) {
648 PipeControlPoint ocp = pcp.getSubPoint().get(0);
650 ocp.setPrevious(this);
652 ocp.setPrevious(nocp);
656 PipingRules.validate(getPipeRun());
659 public Vector3d getDirectedControlPointDirection() {
660 assert (isDirected());
661 Vector3d dir = new Vector3d();
662 MathTools.rotate(getWorldOrientation(), new Vector3d(1.0, 0.0, 0.0), dir);
667 public Vector3d getPathLegDirection(Direction direction) {
668 if (direction == Direction.NEXT) {
670 PipeControlPoint pcp = this;
671 if (pcp.isDualInline()) {
672 pcp = pcp.getSubPoint().get(0);
674 Vector3d v = new Vector3d();
675 v.sub(next.getWorldPosition(),pcp.getWorldPosition());
678 if (previous == null) {
680 throw new RuntimeException("Cannot calculate path leg direction for unconnected control point");
681 return getDirectedControlPointDirection();
684 if (isVariableAngle())
685 throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point");
687 PipeControlPoint pcp = this;
688 if (pcp.isDualSub()) {
689 pcp = pcp.getParentPoint();
691 Vector3d v = new Vector3d();
692 v.sub(pcp.getWorldPosition(),previous.getWorldPosition());
694 } else if (isDirected()) {
695 return getDirectedControlPointDirection();
696 } else if (isEnd()) {
697 Vector3d v = new Vector3d();
698 v.sub(getWorldPosition(),previous.getWorldPosition());
700 } else if (isTurn() && isFixed() && !_getReversed()) {
701 return getDirection(Direction.NEXT);
703 throw new RuntimeException("Missing implementation");
707 if (previous != null) {
708 PipeControlPoint pcp = this;
710 pcp = getParentPoint();
711 Vector3d v = new Vector3d();
712 v.sub(previous.getWorldPosition(),pcp.getWorldPosition());
717 throw new RuntimeException("Cannot calculate path leg direction for unconnected control point");
718 Vector3d v = getDirectedControlPointDirection();
722 if (isVariableAngle())
723 throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point");
725 PipeControlPoint pcp = this;
726 if (pcp.isDualInline()) {
727 pcp = pcp.getSubPoint().get(0);
729 Vector3d v = new Vector3d();
730 v.sub(pcp.getWorldPosition(),next.getWorldPosition());
732 } else if (isDirected()) {
733 Vector3d v = getDirectedControlPointDirection();
736 } else if (isEnd()) {
737 Vector3d v = new Vector3d();
738 v.sub(getWorldPosition(),next.getWorldPosition());
740 } else if (isTurn() && isFixed() && _getReversed()) {
741 return getDirection(Direction.PREVIOUS);
743 throw new RuntimeException("Missing implementation");
749 public void getInlineControlPointEnds(Tuple3d p1, Tuple3d p2) {
752 Vector3d pos = getWorldPosition();
753 Vector3d dir = getPathLegDirection(Direction.NEXT);
755 dir.scale(length * 0.5);
762 public void getControlPointEnds(Tuple3d p1, Tuple3d p2) {
763 Vector3d pos = getWorldPosition();
764 Vector3d dir1 = getPathLegDirection(Direction.PREVIOUS);
766 Vector3d dir2 = getPathLegDirection(Direction.NEXT);
769 dir1.scale(length * 0.5);
770 dir2.scale(length * 0.5);
781 public void getInlineControlPointEnds(Tuple3d p1, Tuple3d p2, Vector3d dir) {
784 Vector3d pos = getWorldPosition();
785 dir.set(getPathLegDirection(Direction.NEXT));
787 dir.scale(length * 0.5);
794 public void getInlineControlPointEnds(Tuple3d center, Tuple3d p1, Tuple3d p2, Vector3d dir) {
797 Vector3d pos = getWorldPosition();
799 dir.set(getPathLegDirection(Direction.NEXT));
801 dir.scale(length * 0.5);
808 public double getInlineLength() {
809 if (type == PointType.TURN)
811 else if (type == PointType.INLINE)
816 public Vector3d getRealPosition(PositionType type) {
817 Vector3d pos = getWorldPosition();
820 Vector3d dir = getPathLegDirection(Direction.NEXT);
821 double length = getInlineLength();
828 Vector3d dir = getPathLegDirection(Direction.PREVIOUS);
829 double length = getInlineLength();
836 // IEntity portDir = pcp.getSingleRelatedObject(ProcessResource.plant3Dresource.HasDirection);
837 // TODO : how we calculated needed space for a port; does it has an offset from control point's position or not?
847 public void getInlineMovement(Tuple3d start, Tuple3d end) {
848 // FIXME : check type of neighbor components and allow movement on top of variable length components,
849 // find proper range for movement (pcp's position is not)
850 PipeControlPoint p = previous.getPrevious();
851 PipeControlPoint n = next.getNext();
852 start.set(p.getWorldPosition());
853 end.set(n.getWorldPosition());
856 public PipeControlPoint findNextEnd() {
857 ArrayList<PipeControlPoint> t = new ArrayList<PipeControlPoint>();
858 return findNextEnd( t);
861 public PipeControlPoint findPreviousEnd() {
862 ArrayList<PipeControlPoint> t = new ArrayList<PipeControlPoint>();
863 return findPreviousEnd(t);
866 public PipeControlPoint findNextEnd(List<PipeControlPoint> nextList) {
868 PipeControlPoint pcp = null;
869 PipeControlPoint p = null;
870 if (nextList.size() == 0)
874 p = nextList.get(nextList.size() - 1);
879 if (nextList.size() > 0)
880 nextList.remove(nextList.size() - 1);
881 // if (DEBUG) System.out.println(" " + pcp.getResource() + " not full");
885 if (pcp.isPathLegEnd()) {
886 //if (DEBUG) System.out.println(" " + pcp.getResource());
890 // if (DEBUG) System.out.print(" " + pcp.getResource());
895 public PipeControlPoint findPreviousEnd(List<PipeControlPoint> prevList) {
897 PipeControlPoint pcp = null;
898 PipeControlPoint p = null;
899 if (prevList.size() == 0)
903 p = prevList.get(prevList.size() - 1);
905 pcp = p.getPrevious();
908 if (prevList.size() > 0)
909 prevList.remove(prevList.size() - 1);
910 // if (DEBUG) System.out.println(" " + pcp.getResource() + " not full");
913 if (pcp.isPathLegEnd()) {
914 // if (DEBUG) System.out.println(" " + pcp.getResource());
918 // if (DEBUG)System.out.print(" " + pcp.getResource());
923 public void _remove() {
924 if (component == null && next == null && previous == null)
926 if (isDualInline() || isDualSub()) {
930 PipeRun pipeRun = getPipeRun();
934 PipeControlPoint additionalRemove = null;
935 if (!PipingRules.isEnabled()) {
940 PipeControlPoint currentPrev = previous;
941 PipeControlPoint currentNext = next;
942 if (currentNext == null && currentPrev == null) {
944 pipeRun.remChild(this);
947 if (currentNext != null && currentPrev != null) {
949 if (currentNext.isBranchEnd()) {
951 // currentNext.setPrevious(null);
952 // currentNext.setNext(null);
953 currentNext.remove();
957 if (currentPrev.isBranchEnd()) {
959 // currentPrev.setPrevious(null);
960 // currentPrev.setNext(null);
961 currentPrev.remove();
965 if (link && currentPrev.isDirected() && currentNext.isDirected()) {
968 if (currentNext == null) {
970 } else if (currentNext.isDualInline()) {
971 PipeControlPoint sccp = currentNext;
972 PipeControlPoint ocp = sccp.getSubPoint().get(0);
974 throw new RuntimeException("Removing PipeControlPoint " + this+ " structure damaged, no offset control point");
977 sccp.setPrevious(currentPrev);
978 ocp.setPrevious(currentPrev);
980 sccp.setPrevious(null);
981 ocp.setPrevious(null);
984 } else if (currentNext.isDualSub()) {
985 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, next control point is offset control point");
986 } else if (currentNext.previous == this) {
988 currentNext.setPrevious(currentPrev);
990 currentNext.setPrevious(null);
994 throw new RuntimeException("Removing PipeControlPoint "+ this+ " structure damaged");
996 if (currentPrev == null) {
998 } else if (currentPrev.isDualInline()) {
999 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, previous control point is size change control point");
1000 } else if (currentPrev.isDualSub()) {
1001 PipeControlPoint ocp = currentPrev;
1002 PipeControlPoint sccp = ocp.getParentPoint();
1004 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, no size change control point");
1006 ocp.setNext(currentNext);
1007 sccp.setNext(currentNext);
1013 } else if (currentPrev.next == this) {
1015 currentPrev.setNext(currentNext);
1017 currentPrev.setNext(null);
1021 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged");
1024 if (currentNext.isVariableLength() && currentPrev.isVariableLength()) {
1025 // we have to join them into single variable length component.
1026 additionalRemove = currentPrev;
1027 // combine lengths and set the location of remaining control point to the center.
1028 Point3d ps = new Point3d();
1029 Point3d pe = new Point3d();
1030 Point3d ns = new Point3d();
1031 Point3d ne = new Point3d();
1032 currentPrev.getInlineControlPointEnds(ps, pe);
1033 currentNext.getInlineControlPointEnds(ns, ne);
1034 double l = currentPrev.getLength() + currentNext.getLength();
1035 Vector3d cp = new Vector3d();
1038 currentNext.setLength(l);
1039 currentNext.setWorldPosition(cp);
1042 // FIXME : pipe run must be split into two parts, since the control point structure is no more continuous.
1044 } else if (next != null) {
1045 if (next.isDualInline()) {
1046 PipeControlPoint sccp = next;
1047 PipeControlPoint ocp = sccp.getSubPoint().get(0);
1049 throw new RuntimeException("Removing PipeControlPoint " + this+ " structure damaged, no offset control point");
1051 sccp.setPrevious(null);
1052 ocp.setPrevious(null);
1053 } else if (next.isDualSub()) {
1054 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, next control point is offset control point");
1055 } else if (next.previous == this) {
1056 next.setPrevious(null);
1058 throw new RuntimeException("Removing PipeControlPoint "+ this+ " structure damaged");
1061 } else { //(previous != null)
1062 if(previous.isDualInline()) {
1063 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, previous control point is size change control point");
1064 } else if (previous.isDualSub()) {
1065 PipeControlPoint ocp = previous;
1066 PipeControlPoint sccp = ocp.getParentPoint();
1068 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, no size change control point");
1072 } else if (previous.next == this) {
1073 previous.setNext(null);
1075 throw new RuntimeException("Removing PipeControlPoint "+ this+ " structure damaged");
1079 if (children.size() > 0 ) {
1081 } else if (parent!= null) {
1082 removeParentPoint();
1088 pipeRun.remChild(this);
1089 checkRemove(pipeRun);
1090 if (PipingRules.isEnabled() && pipeRun.getParent() != null && pipeRun.getControlPoints().size() > 0)
1091 PipingRules.validate(pipeRun);
1092 if (additionalRemove != null)
1093 additionalRemove.remove();
1096 public void remove() {
1097 PipeControlPoint currentPrev = previous;
1098 PipeControlPoint currentNext = next;
1101 if (currentNext != null)
1102 PipingRules.requestUpdate(currentNext);
1103 if (currentPrev != null)
1104 PipingRules.requestUpdate(currentPrev);
1105 } catch (Exception e) {
1106 e.printStackTrace();
1110 private void checkRemove(PipeRun pipeRun) {
1111 Collection<PipeControlPoint> points = pipeRun.getControlPoints();
1112 if (points.size() == 0) {
1114 } else if (points.size() == 1) {
1115 PipeControlPoint pcp = points.iterator().next();
1116 if (pcp.isDeletable())
1121 private void removeDualPoint() {
1122 if (previous != null)
1123 previous.setNext(null);
1125 next.setPrevious(null);
1126 PipeControlPoint ocp;
1127 PipeControlPoint sccp;
1128 if (isDualInline()) {
1130 ocp = getSubPoint().get(0);
1133 sccp = getParentPoint();
1135 PipeRun p1 = ocp.getPipeRun();
1136 PipeRun p2 = sccp.getPipeRun();
1138 ocp.removeComponent();
1139 sccp.removeComponent();
1146 // TODO : now we assume that this is size change, and we do
1147 if (ocp.next != null)
1148 ocp.next.setPrevious(null);
1149 if (ocp.previous != null)
1150 ocp.previous.setNext(null);
1151 if (sccp.next != null)
1152 sccp.next.setPrevious(null);
1153 if (sccp.previous != null)
1154 sccp.previous.setNext(null);
1156 ocp.setPrevious(null);
1158 sccp.setPrevious(null);
1166 private void removeSubPoints() {
1167 for (PipeControlPoint p : children) {
1168 // TODO : this may affect delete routine, since classification of the point changes.
1175 private void removeParentPoint() {
1176 throw new RuntimeException("Child points cannot be removed directly");
1179 private void removeComponent() {
1180 if (component == null)
1182 PipelineComponent next = component.getNext();
1183 PipelineComponent prev = component.getPrevious();
1184 PipelineComponent br0 = component.getBranch0();
1185 component.setNext(null);
1186 component.setPrevious(null);
1187 component.setBranch0(null);
1189 if (next.getNext() == component)
1191 else if (next.getPrevious() == component)
1192 next.setPrevious(null);
1193 else if (next.getBranch0() == component)
1194 next.setBranch0(null);
1197 if (prev.getNext() == component)
1199 else if (prev.getPrevious() == component)
1200 prev.setPrevious(null);
1201 else if (prev.getBranch0() == component)
1202 prev.setBranch0(null);
1205 if (br0.getNext() == component)
1207 else if (br0.getPrevious() == component)
1208 br0.setPrevious(null);
1209 else if (br0.getBranch0() == component)
1210 br0.setBranch0(null);
1212 PipelineComponent comp = component;
1219 public void setOrientation(Quat4d orientation) {
1220 if (MathTools.equals(orientation, getOrientation()))
1222 super.setOrientation(orientation);
1223 if (getParentPoint() == null && component != null)
1224 component._setWorldOrientation(getWorldOrientation());
1229 public void setPosition(Vector3d position) {
1230 if (MathTools.equals(position, getPosition()))
1232 if (Double.isNaN(position.x) || Double.isNaN(position.y) || Double.isNaN(position.z))
1233 throw new IllegalArgumentException("NaN is not supported");
1234 super.setPosition(position);
1235 if (getParentPoint() == null && component != null)
1236 component._setWorldPosition(getWorldPosition());
1240 private void updateSubPoint() {
1242 if (next == null && previous == null) {
1243 for (PipeControlPoint sub : getSubPoint()) {
1244 sub.setWorldPosition(getWorldPosition());
1245 sub.setWorldOrientation(getWorldOrientation());
1249 for (PipeControlPoint sub : getSubPoint()) {
1250 Vector3d wp = getWorldPosition();
1251 wp.add(getSizeChangeOffsetVector());
1252 sub.setWorldPosition(wp);
1253 sub.setWorldOrientation(getWorldOrientation());
1256 for (PipeControlPoint sub : getSubPoint()) {
1257 sub.setWorldPosition(getWorldPosition());
1258 sub.setWorldOrientation(getWorldOrientation());
1264 public void _setWorldPosition(Vector3d position) {
1265 Vector3d localPos = getLocalPosition(position);
1266 super.setPosition(localPos);
1270 public void _setWorldOrientation(Quat4d orientation) {
1271 Quat4d localOr = getLocalOrientation(orientation);
1272 super.setOrientation(localOr);
1277 public String toString() {
1278 return getClass().getName() + "@" + Integer.toHexString(hashCode());