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 isAxial() {
171 return isInline() && !isDualInline();
174 public boolean isSizeChange() {
176 // if (children.size() == 0)
178 // if (!isDualInline())
180 // return getPipeRun() != children.get(0).getPipeRun();
183 public void setSizeChange(boolean isSizeChange) {
184 this.isSizeChange = isSizeChange;
188 private PipeControlPoint next;
189 private PipeControlPoint previous;
191 public PipeControlPoint getNext() {
195 public PipeControlPoint getPrevious() {
199 public void setNext(PipeControlPoint next) {
200 if (isEnd() && previous != null && next != null)
201 throw new RuntimeException("End control points are allowed to have only one connection");
203 throw new RuntimeException("Cannot connect to self");
204 if (this.next == next)
206 if (DEBUG) System.out.println(this + " next " + next);
208 if (component != null) {
209 if (parent == null || isSub)
210 component.setNext(next != null ? next.component : null);
212 component.setBranch0(next != null ? next.component : null);
218 public void setPrevious(PipeControlPoint previous) {
219 if (isEnd() && next != null && previous != null)
220 throw new RuntimeException("End control points are allowed to have only one connection");
221 if (previous == this)
222 throw new RuntimeException("Cannot connect to self");
223 if (this.previous == previous)
225 if (DEBUG) System.out.println(this + " previous " + previous);
226 this.previous = previous;
227 if (component != null) {
228 if (parent == null || isSub)
229 component.setPrevious(previous != null ? previous.component : null);
231 component.setBranch0(previous != null ? previous.component : null);
237 public PipeControlPoint parent;
238 public List<PipeControlPoint> children = new ArrayList<PipeControlPoint>();
240 public List<PipeControlPoint> getSubPoint() {
244 public PipeControlPoint getParentPoint() {
249 private double length;
250 private Double turnAngle;
251 private Vector3d turnAxis;
253 private Double offset;
254 private Double rotationAngle;
255 private Boolean reversed;
257 @GetPropertyValue(name="Length",tabId="Debug",value="length")
258 public double getLength() {
262 public void setLength(double l) {
263 if (Double.isInfinite(l) || Double.isNaN(l)) {
266 if (Math.abs(this.length-l) < MathTools.NEAR_ZERO)
269 firePropertyChanged("length");
271 getSubPoint().get(0).setLength(l);
274 @GetPropertyValue(name="Turn Angle",tabId="Debug",value="turnAngle")
275 public Double getTurnAngle() {
279 @GetPropertyValue(name="Turn Axis",tabId="Debug",value="turnAxis")
280 public Vector3d getTurnAxis() {
284 @GetPropertyValue(name="Offset",tabId="Debug",value="offset")
285 public Double getOffset() {
289 @GetPropertyValue(name="Rotation Angle",tabId="Debug",value="rotationAngle")
290 public Double getRotationAngle() {
291 return rotationAngle;
294 @GetPropertyValue(name="Reversed",tabId="Debug",value="reversed")
295 public Boolean getReversed() {
299 public boolean _getReversed() {
300 if (reversed == null)
305 public void setTurnAngle(Double turnAngle) {
306 if (turnAngle == null || Double.isInfinite(turnAngle) || Double.isNaN(turnAngle)) {
309 if (this.turnAngle != null && Math.abs(this.turnAngle-turnAngle) < MathTools.NEAR_ZERO)
311 this.turnAngle = turnAngle;
312 firePropertyChanged("turnAngle");
315 public void setTurnAxis(Vector3d turnAxis) {
316 if (this.turnAxis != null && MathTools.equals(turnAxis, this.turnAxis))
318 this.turnAxis = turnAxis;
319 firePropertyChanged("turnAxis");
322 public void setOffset(Double offset) {
323 if (Double.isInfinite(offset) || Double.isNaN(offset)) {
326 if (this.offset != null && Math.abs(this.offset-offset) < MathTools.NEAR_ZERO)
328 this.offset = offset;
329 firePropertyChanged("offset");
332 public void setRotationAngle(Double rotationAngle) {
333 if (Double.isInfinite(rotationAngle) || Double.isNaN(rotationAngle)) {
336 if (this.rotationAngle != null && Math.abs(this.rotationAngle-rotationAngle) < MathTools.NEAR_ZERO)
338 this.rotationAngle = rotationAngle;
339 firePropertyChanged("rotationAngle");
342 public void setReversed(Boolean reversed) {
343 this.reversed = reversed;
344 firePropertyChanged("reversed");
347 public Vector3d getSizeChangeOffsetVector(Vector3d dir) {
349 if (rotationAngle == null)
350 q = getControlPointOrientationQuat(dir, 0.0);
352 q = getControlPointOrientationQuat(dir, rotationAngle);
353 Vector3d v = new Vector3d(0.0,offset,0.0);
354 Vector3d offset = new Vector3d();
355 MathTools.rotate(q, v, offset);
359 public Vector3d getSizeChangeOffsetVector() {
361 if (rotationAngle == null)
362 q = getControlPointOrientationQuat(0.0);
364 q = getControlPointOrientationQuat(rotationAngle);
365 Vector3d v = new Vector3d(0.0,offset,0.0);
366 Vector3d offset = new Vector3d();
367 MathTools.rotate(q, v, offset);
371 @GetPropertyValue(name="Next",tabId="Debug",value="next")
372 private String getNextString() {
375 return next.toString();
378 @GetPropertyValue(name="Previous",tabId="Debug",value="previous")
379 private String getPrevString() {
380 if (previous == null)
382 return previous.toString();
385 @GetPropertyValue(name="Sub",tabId="Debug",value="sub")
386 private String getSubString() {
387 if (children.size() == 0)
389 return Arrays.toString(children.toArray());
392 @GetPropertyValue(name="Type",tabId="Debug",value="type")
393 public String getTypeString() {
397 public Quat4d getControlPointOrientationQuat(double angle) {
399 if (turnAxis == null) {
400 Vector3d dir = getPathLegDirection(Direction.NEXT);
401 if (dir.lengthSquared() > MathTools.NEAR_ZERO)
403 return getControlPointOrientationQuat(dir, angle);
405 Vector3d dir = getPathLegDirection(Direction.PREVIOUS);
407 if (dir.lengthSquared() > MathTools.NEAR_ZERO)
409 return getControlPointOrientationQuat(dir, turnAxis, angle);
413 public Quat4d getControlPointOrientationQuat(double angle, boolean reversed) {
415 if (turnAxis == null) {
416 Vector3d dir = getPathLegDirection(Direction.NEXT);
417 if (dir.lengthSquared() > MathTools.NEAR_ZERO)
419 Quat4d q = getControlPointOrientationQuat(dir, angle);
421 Quat4d q2 = new Quat4d();
422 q2.set(new AxisAngle4d(MathTools.Y_AXIS, Math.PI));
427 Vector3d dir = getPathLegDirection(Direction.PREVIOUS);
429 if (dir.lengthSquared() > MathTools.NEAR_ZERO)
431 return getControlPointOrientationQuat(dir, turnAxis, angle);
437 public static Quat4d getControlPointOrientationQuat(Vector3d dir, double angle) {
438 if (dir.lengthSquared() < MathTools.NEAR_ZERO)
439 return MathTools.getIdentityQuat();
442 Vector3d up = new Vector3d(0.0, 1.0, 0.0);
443 double a = up.angle(dir);
444 if (a < 0.1 || (Math.PI - a) < 0.1) {
445 up.set(1.0, 0.0, 0.0);
449 return getControlPointOrientationQuat(dir, up, angle);
452 public static Quat4d getControlPointOrientationQuat(Vector3d dir, Vector3d up, double angle) {
453 if (dir.lengthSquared() < MathTools.NEAR_ZERO)
454 return MathTools.getIdentityQuat();
456 final Vector3d front = new Vector3d(1.0,0.0,0.0);
458 Quat4d q1 = new Quat4d();
461 Vector3d right = new Vector3d();
463 right.cross(dir, up);
464 up.cross(right, dir);
468 Matrix3d m = new Matrix3d();
479 //q1.set(m); MathTools contains more stable conversion
480 MathTools.getQuat(m, q1);
482 // if (DEBUG) System.out.println("PipingTools.getPipeComponentOrientationQuat() " + dir+ " " + up + " " + right);
484 Quat4d q2 = new Quat4d();
485 q2.set(new AxisAngle4d(front, angle));
490 public Vector3d getDirection(Direction direction) {
492 return getDirectedControlPointDirection();
493 if (isTurn() && isFixed()) {
494 if (direction == Direction.NEXT) {
495 if (previous != null) {
496 PipeControlPoint pcp = this;
497 Vector3d dir = new Vector3d();
498 dir.sub(pcp.getWorldPosition(),previous.getWorldPosition());
499 if (dir.lengthSquared() > MathTools.NEAR_ZERO)
503 Quat4d q = getControlPointOrientationQuat(dir, pcp.getRotationAngle() != null ? pcp.getRotationAngle() : 0.0);
504 AxisAngle4d aa = new AxisAngle4d(MathTools.Y_AXIS,pcp.getTurnAngle() == null ? 0.0 : pcp.getTurnAngle());
505 Quat4d q2 = MathTools.getQuat(aa);
506 Vector3d v = new Vector3d(1.,0.,0.);
507 Vector3d offset = new Vector3d();
508 MathTools.rotate(q2, v, offset);
509 MathTools.rotate(q, offset, dir);
514 PipeControlPoint pcp = this;
515 Vector3d dir = new Vector3d();
516 dir.sub(next.getWorldPosition(),pcp.getWorldPosition());
517 if (dir.lengthSquared() > MathTools.NEAR_ZERO)
521 Quat4d q = getControlPointOrientationQuat(dir, pcp.getRotationAngle() != null ? pcp.getRotationAngle() : 0.0);
522 AxisAngle4d aa = new AxisAngle4d(MathTools.Y_AXIS,pcp.getTurnAngle() == null ? 0.0 : pcp.getTurnAngle());
523 Quat4d q2 = MathTools.getQuat(aa);
524 Vector3d v = new Vector3d(1.,0.,0.);
525 Vector3d offset = new Vector3d();
526 MathTools.rotate(q2, v, offset);
527 MathTools.rotate(q, offset, dir);
535 public void insert(PipeControlPoint previous, PipeControlPoint next) {
536 // inserting an offsetpoint is error,
538 throw new RuntimeException("Dual sub points cannot be inserted.");
539 // size change control point cannot be inserted this way, because it ends PipeRun
541 throw new RuntimeException("Size change points cannot be inserted.");
542 PipeRun piperun = previous.getPipeRun();
543 // and just to make sure that control point structure is not corrupted
544 if (getPipeRun() != null) {
545 if (piperun != getPipeRun() || piperun != next.getPipeRun())
546 throw new RuntimeException("All controls points must be located on the same pipe run");
548 piperun.addChild(this);
551 // insert new BranchControlPoint between straight's control points
552 PipeControlPoint previousNext = previous.getNext();
553 PipeControlPoint previousPrevious = previous.getPrevious();
555 PipeControlPoint offsetCP = null;
557 offsetCP = getSubPoint().get(0);
559 if (previousNext != null && previousNext == next) {
560 if (previous.isDualInline()) {
561 throw new RuntimeException();
563 if (next.isDualSub()) {
564 throw new RuntimeException();
566 previous.setNext(this);
567 this.setPrevious(previous);
568 if (previous.isDualSub()) {
569 previous.getParentPoint().setNext(this);
573 if (offsetCP == null) {
574 next.setPrevious(this);
576 next.setPrevious(offsetCP);
577 offsetCP.setNext(next);
578 offsetCP.setPrevious(previous);
581 if (next.isDualInline()) {
582 next.getSubPoint().get(0).setPrevious(this);
584 } else if (previousPrevious != null && previousPrevious == next) {
585 // control point were given in reverse order
586 if (next.isDualInline())
587 throw new RuntimeException();
588 if (previous.isDualSub())
589 throw new RuntimeException();
591 this.setNext(previous);
592 if (offsetCP == null) {
593 previous.setNext(this);
595 previous.setPrevious(offsetCP);
596 offsetCP.setNext(previous);
597 offsetCP.setPrevious(next);
599 if (previous.isDualInline()) {
600 previous.getSubPoint().get(0).setPrevious(this);
602 this.setPrevious(next);
604 if (next.isDualSub()) {
605 next.getParentPoint().setNext(this);
609 throw new RuntimeException();
612 PipingRules.validate(piperun);
617 public void insert(PipeControlPoint pcp, Direction direction) {
619 throw new RuntimeException();
620 if (direction == Direction.NEXT) {
621 // if direction is next, user must have given OffsetPoint
622 if (pcp.isDualInline())
623 throw new RuntimeException();
624 // basic next/prev links
626 this.setPrevious(pcp);
627 // and last take care of sizechange / offset points
628 if (pcp.isDualSub()) {
629 pcp.getParentPoint().setNext(this);
631 if (isDualInline()) {
632 getSubPoint().get(0).setPrevious(this);
635 // if direction is previous, user must have given sizechange
637 throw new RuntimeException();
638 // previous direction is more complicated, since if newCP is SizeChangeControlPoint,
639 // we must link pcp to newCP's OffsetPoint
640 PipeControlPoint nocp = null;
641 if (isDualInline()) {
642 nocp = getSubPoint().get(0);
646 pcp.setPrevious(this);
648 pcp.setPrevious(nocp);
651 if (pcp.isDualInline()) {
652 PipeControlPoint ocp = pcp.getSubPoint().get(0);
654 ocp.setPrevious(this);
656 ocp.setPrevious(nocp);
660 PipingRules.validate(getPipeRun());
663 public Vector3d getDirectedControlPointDirection() {
664 assert (isDirected());
665 Vector3d dir = new Vector3d();
666 MathTools.rotate(getWorldOrientation(), new Vector3d(1.0, 0.0, 0.0), dir);
671 public Vector3d getPathLegDirection(Direction direction) {
672 if (direction == Direction.NEXT) {
674 PipeControlPoint pcp = this;
675 if (pcp.isDualInline()) {
676 pcp = pcp.getSubPoint().get(0);
678 Vector3d v = new Vector3d();
679 v.sub(next.getWorldPosition(),pcp.getWorldPosition());
682 if (previous == null) {
684 throw new RuntimeException("Cannot calculate path leg direction for unconnected control point");
685 return getDirectedControlPointDirection();
688 if (isVariableAngle())
689 throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point");
691 PipeControlPoint pcp = this;
692 if (pcp.isDualSub()) {
693 pcp = pcp.getParentPoint();
695 Vector3d v = new Vector3d();
696 v.sub(pcp.getWorldPosition(),previous.getWorldPosition());
698 } else if (isDirected()) {
699 return getDirectedControlPointDirection();
700 } else if (isEnd()) {
701 Vector3d v = new Vector3d();
702 v.sub(getWorldPosition(),previous.getWorldPosition());
704 } else if (isTurn() && isFixed() && !_getReversed()) {
705 return getDirection(Direction.NEXT);
707 throw new RuntimeException("Missing implementation");
711 if (previous != null) {
712 PipeControlPoint pcp = this;
714 pcp = getParentPoint();
715 Vector3d v = new Vector3d();
716 v.sub(previous.getWorldPosition(),pcp.getWorldPosition());
721 throw new RuntimeException("Cannot calculate path leg direction for unconnected control point");
722 Vector3d v = getDirectedControlPointDirection();
726 if (isVariableAngle())
727 throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point");
729 PipeControlPoint pcp = this;
730 if (pcp.isDualInline()) {
731 pcp = pcp.getSubPoint().get(0);
733 Vector3d v = new Vector3d();
734 v.sub(pcp.getWorldPosition(),next.getWorldPosition());
736 } else if (isDirected()) {
737 Vector3d v = getDirectedControlPointDirection();
740 } else if (isEnd()) {
741 Vector3d v = new Vector3d();
742 v.sub(getWorldPosition(),next.getWorldPosition());
744 } else if (isTurn() && isFixed() && _getReversed()) {
745 return getDirection(Direction.PREVIOUS);
747 throw new RuntimeException("Missing implementation");
753 public void getInlineControlPointEnds(Tuple3d p1, Tuple3d p2) {
756 PipeControlPoint sub = isAxial() ? this : getSubPoint().get(0);
757 Vector3d pos = getWorldPosition(), pos2 = sub == this ? pos : sub.getWorldPosition();
758 Vector3d dir = sub.getPathLegDirection(Direction.NEXT);
761 dir.scale(length * 0.5);
768 public void getControlPointEnds(Tuple3d p1, Tuple3d p2) {
769 PipeControlPoint sub = isAxial() ? this : getSubPoint().get(0);
770 Vector3d pos = getWorldPosition(), pos2 = sub == this ? pos : sub.getWorldPosition();
772 Vector3d dir1 = getPathLegDirection(Direction.PREVIOUS);
774 Vector3d dir2 = sub.getPathLegDirection(Direction.NEXT);
777 dir1.scale(length * 0.5);
778 dir2.scale(length * 0.5);
789 public void getEndDirections(Tuple3d v1, Tuple3d v2) {
790 PipeControlPoint sub = isAxial() ? this : getSubPoint().get(0);
792 Vector3d dir1 = getPathLegDirection(Direction.PREVIOUS);
794 Vector3d dir2 = sub.getPathLegDirection(Direction.NEXT);
800 public void getInlineControlPointEnds(Tuple3d p1, Tuple3d p2, Vector3d dir) {
803 Vector3d pos = getWorldPosition();
804 dir.set(getPathLegDirection(Direction.NEXT));
806 dir.scale(length * 0.5);
813 public void getInlineControlPointEnds(Tuple3d center, Tuple3d p1, Tuple3d p2, Vector3d dir) {
816 Vector3d pos = getWorldPosition();
818 dir.set(getPathLegDirection(Direction.NEXT));
820 dir.scale(length * 0.5);
827 public double getInlineLength() {
828 if (type == PointType.TURN)
830 else if (type == PointType.INLINE)
835 public Vector3d getRealPosition(PositionType type) {
836 Vector3d pos = getWorldPosition();
839 Vector3d dir = getPathLegDirection(Direction.NEXT);
840 double length = getInlineLength();
847 Vector3d dir = getPathLegDirection(Direction.PREVIOUS);
848 double length = getInlineLength();
855 // IEntity portDir = pcp.getSingleRelatedObject(ProcessResource.plant3Dresource.HasDirection);
856 // TODO : how we calculated needed space for a port; does it has an offset from control point's position or not?
866 public void getInlineMovement(Tuple3d start, Tuple3d end) {
867 // FIXME : check type of neighbor components and allow movement on top of variable length components,
868 // find proper range for movement (pcp's position is not)
869 PipeControlPoint p = previous.getPrevious();
870 PipeControlPoint n = next.getNext();
871 start.set(p.getWorldPosition());
872 end.set(n.getWorldPosition());
875 public PipeControlPoint findNextEnd() {
876 ArrayList<PipeControlPoint> t = new ArrayList<PipeControlPoint>();
877 return findNextEnd( t);
880 public PipeControlPoint findPreviousEnd() {
881 ArrayList<PipeControlPoint> t = new ArrayList<PipeControlPoint>();
882 return findPreviousEnd(t);
885 public PipeControlPoint findNextEnd(List<PipeControlPoint> nextList) {
887 PipeControlPoint pcp = null;
888 PipeControlPoint p = null;
889 if (nextList.size() == 0)
893 p = nextList.get(nextList.size() - 1);
898 if (nextList.size() > 0)
899 nextList.remove(nextList.size() - 1);
900 // if (DEBUG) System.out.println(" " + pcp.getResource() + " not full");
904 if (pcp.isPathLegEnd()) {
905 //if (DEBUG) System.out.println(" " + pcp.getResource());
909 // if (DEBUG) System.out.print(" " + pcp.getResource());
914 public PipeControlPoint findPreviousEnd(List<PipeControlPoint> prevList) {
916 PipeControlPoint pcp = null;
917 PipeControlPoint p = null;
918 if (prevList.size() == 0)
922 p = prevList.get(prevList.size() - 1);
924 pcp = p.getPrevious();
927 if (prevList.size() > 0)
928 prevList.remove(prevList.size() - 1);
929 // if (DEBUG) System.out.println(" " + pcp.getResource() + " not full");
932 if (pcp.isPathLegEnd()) {
933 // if (DEBUG) System.out.println(" " + pcp.getResource());
937 // if (DEBUG)System.out.print(" " + pcp.getResource());
942 public void _remove() {
943 if (component == null && next == null && previous == null)
945 if (isDualInline() || isDualSub()) {
949 PipeRun pipeRun = getPipeRun();
953 PipeControlPoint additionalRemove = null;
954 if (!PipingRules.isEnabled()) {
959 PipeControlPoint currentPrev = previous;
960 PipeControlPoint currentNext = next;
961 if (currentNext == null && currentPrev == null) {
963 pipeRun.remChild(this);
966 if (currentNext != null && currentPrev != null) {
968 if (currentNext.isBranchEnd()) {
970 // currentNext.setPrevious(null);
971 // currentNext.setNext(null);
972 currentNext.remove();
976 if (currentPrev.isBranchEnd()) {
978 // currentPrev.setPrevious(null);
979 // currentPrev.setNext(null);
980 currentPrev.remove();
984 if (link && currentPrev.isDirected() && currentNext.isDirected()) {
987 if (currentNext == null) {
989 } else if (currentNext.isDualInline()) {
990 PipeControlPoint sccp = currentNext;
991 PipeControlPoint ocp = sccp.getSubPoint().get(0);
993 throw new RuntimeException("Removing PipeControlPoint " + this+ " structure damaged, no offset control point");
996 sccp.setPrevious(currentPrev);
997 ocp.setPrevious(currentPrev);
999 sccp.setPrevious(null);
1000 ocp.setPrevious(null);
1003 } else if (currentNext.isDualSub()) {
1004 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, next control point is offset control point");
1005 } else if (currentNext.previous == this) {
1007 currentNext.setPrevious(currentPrev);
1009 currentNext.setPrevious(null);
1013 throw new RuntimeException("Removing PipeControlPoint "+ this+ " structure damaged");
1015 if (currentPrev == null) {
1017 } else if (currentPrev.isDualInline()) {
1018 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, previous control point is size change control point");
1019 } else if (currentPrev.isDualSub()) {
1020 PipeControlPoint ocp = currentPrev;
1021 PipeControlPoint sccp = ocp.getParentPoint();
1023 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, no size change control point");
1025 ocp.setNext(currentNext);
1026 sccp.setNext(currentNext);
1032 } else if (currentPrev.next == this) {
1034 currentPrev.setNext(currentNext);
1036 currentPrev.setNext(null);
1040 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged");
1043 if (currentNext.isVariableLength() && currentPrev.isVariableLength()) {
1044 // we have to join them into single variable length component.
1045 additionalRemove = currentPrev;
1046 // combine lengths and set the location of remaining control point to the center.
1047 Point3d ps = new Point3d();
1048 Point3d pe = new Point3d();
1049 Point3d ns = new Point3d();
1050 Point3d ne = new Point3d();
1051 currentPrev.getInlineControlPointEnds(ps, pe);
1052 currentNext.getInlineControlPointEnds(ns, ne);
1053 double l = currentPrev.getLength() + currentNext.getLength();
1054 Vector3d cp = new Vector3d();
1057 currentNext.setLength(l);
1058 currentNext.setWorldPosition(cp);
1061 // FIXME : pipe run must be split into two parts, since the control point structure is no more continuous.
1063 } else if (next != null) {
1064 if (next.isDualInline()) {
1065 PipeControlPoint sccp = next;
1066 PipeControlPoint ocp = sccp.getSubPoint().get(0);
1068 throw new RuntimeException("Removing PipeControlPoint " + this+ " structure damaged, no offset control point");
1070 sccp.setPrevious(null);
1071 ocp.setPrevious(null);
1072 } else if (next.isDualSub()) {
1073 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, next control point is offset control point");
1074 } else if (next.previous == this) {
1075 next.setPrevious(null);
1077 throw new RuntimeException("Removing PipeControlPoint "+ this+ " structure damaged");
1080 } else { //(previous != null)
1081 if(previous.isDualInline()) {
1082 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, previous control point is size change control point");
1083 } else if (previous.isDualSub()) {
1084 PipeControlPoint ocp = previous;
1085 PipeControlPoint sccp = ocp.getParentPoint();
1087 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, no size change control point");
1091 } else if (previous.next == this) {
1092 previous.setNext(null);
1094 throw new RuntimeException("Removing PipeControlPoint "+ this+ " structure damaged");
1098 if (children.size() > 0 ) {
1100 } else if (parent!= null) {
1101 removeParentPoint();
1107 pipeRun.remChild(this);
1108 checkRemove(pipeRun);
1109 if (PipingRules.isEnabled() && pipeRun.getParent() != null && pipeRun.getControlPoints().size() > 0)
1110 PipingRules.validate(pipeRun);
1111 if (additionalRemove != null)
1112 additionalRemove.remove();
1115 public void remove() {
1116 PipeControlPoint currentPrev = previous;
1117 PipeControlPoint currentNext = next;
1120 if (currentNext != null)
1121 PipingRules.requestUpdate(currentNext);
1122 if (currentPrev != null)
1123 PipingRules.requestUpdate(currentPrev);
1124 } catch (Exception e) {
1125 e.printStackTrace();
1129 private void checkRemove(PipeRun pipeRun) {
1130 Collection<PipeControlPoint> points = pipeRun.getControlPoints();
1131 if (points.size() == 0) {
1133 } else if (points.size() == 1) {
1134 PipeControlPoint pcp = points.iterator().next();
1135 if (pcp.isDeletable())
1140 private void removeDualPoint() {
1141 if (previous != null)
1142 previous.setNext(null);
1144 next.setPrevious(null);
1145 PipeControlPoint ocp;
1146 PipeControlPoint sccp;
1147 if (isDualInline()) {
1149 ocp = getSubPoint().get(0);
1152 sccp = getParentPoint();
1154 PipeRun p1 = ocp.getPipeRun();
1155 PipeRun p2 = sccp.getPipeRun();
1157 ocp.removeComponent();
1158 sccp.removeComponent();
1165 // TODO : now we assume that this is size change, and we do
1166 if (ocp.next != null)
1167 ocp.next.setPrevious(null);
1168 if (ocp.previous != null)
1169 ocp.previous.setNext(null);
1170 if (sccp.next != null)
1171 sccp.next.setPrevious(null);
1172 if (sccp.previous != null)
1173 sccp.previous.setNext(null);
1175 ocp.setPrevious(null);
1177 sccp.setPrevious(null);
1185 private void removeSubPoints() {
1186 for (PipeControlPoint p : children) {
1187 // TODO : this may affect delete routine, since classification of the point changes.
1194 private void removeParentPoint() {
1195 throw new RuntimeException("Child points cannot be removed directly");
1198 private void removeComponent() {
1199 if (component == null)
1201 PipelineComponent next = component.getNext();
1202 PipelineComponent prev = component.getPrevious();
1203 PipelineComponent br0 = component.getBranch0();
1204 component.setNext(null);
1205 component.setPrevious(null);
1206 component.setBranch0(null);
1208 if (next.getNext() == component)
1210 else if (next.getPrevious() == component)
1211 next.setPrevious(null);
1212 else if (next.getBranch0() == component)
1213 next.setBranch0(null);
1216 if (prev.getNext() == component)
1218 else if (prev.getPrevious() == component)
1219 prev.setPrevious(null);
1220 else if (prev.getBranch0() == component)
1221 prev.setBranch0(null);
1224 if (br0.getNext() == component)
1226 else if (br0.getPrevious() == component)
1227 br0.setPrevious(null);
1228 else if (br0.getBranch0() == component)
1229 br0.setBranch0(null);
1231 PipelineComponent comp = component;
1238 public void setOrientation(Quat4d orientation) {
1239 if (MathTools.equals(orientation, getOrientation()))
1241 super.setOrientation(orientation);
1242 if (getParentPoint() == null && component != null)
1243 component._setWorldOrientation(getWorldOrientation());
1248 public void setPosition(Vector3d position) {
1249 if (MathTools.equals(position, getPosition()))
1251 if (Double.isNaN(position.x) || Double.isNaN(position.y) || Double.isNaN(position.z))
1252 throw new IllegalArgumentException("NaN is not supported");
1253 super.setPosition(position);
1254 if (getParentPoint() == null && component != null)
1255 component._setWorldPosition(getWorldPosition());
1259 private void updateSubPoint() {
1261 if (next == null && previous == null) {
1262 for (PipeControlPoint sub : getSubPoint()) {
1263 sub.setWorldPosition(getWorldPosition());
1264 sub.setWorldOrientation(getWorldOrientation());
1268 for (PipeControlPoint sub : getSubPoint()) {
1269 Vector3d wp = getWorldPosition();
1270 wp.add(getSizeChangeOffsetVector());
1271 sub.setWorldPosition(wp);
1272 sub.setWorldOrientation(getWorldOrientation());
1275 for (PipeControlPoint sub : getSubPoint()) {
1276 sub.setWorldPosition(getWorldPosition());
1277 sub.setWorldOrientation(getWorldOrientation());
1283 public void _setWorldPosition(Vector3d position) {
1284 Vector3d localPos = getLocalPosition(position);
1285 super.setPosition(localPos);
1289 public void _setWorldOrientation(Quat4d orientation) {
1290 Quat4d localOr = getLocalOrientation(orientation);
1291 super.setOrientation(localOr);
1296 public String toString() {
1297 return getClass().getName() + "@" + Integer.toHexString(hashCode());