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.Quat4d;
11 import javax.vecmath.Tuple3d;
12 import javax.vecmath.Vector3d;
14 import org.simantics.g3d.math.MathTools;
15 import org.simantics.g3d.property.annotations.GetPropertyValue;
16 import org.simantics.g3d.scenegraph.G3DNode;
17 import org.simantics.plant3d.scenegraph.IP3DNode;
18 import org.simantics.plant3d.scenegraph.PipeRun;
19 import org.simantics.plant3d.scenegraph.PipelineComponent;
21 import vtk.vtkRenderer;
24 public class PipeControlPoint extends G3DNode implements IP3DNode {
26 private static boolean DEBUG = false;
28 public enum Type{INLINE,TURN,END};
29 public enum Direction{NEXT,PREVIOUS};
30 public enum PositionType {SPLIT,NEXT,PREVIOUS,PORT}
32 private PipelineComponent component;
35 private boolean fixed = true;
36 private boolean rotate = false;
37 private boolean reverse = false;
38 private boolean deletable = true;
39 private boolean sub = false;
41 public PipeControlPoint(PipelineComponent component) {
42 this.component = component;
43 if (component.getPipeRun() != null)
44 component.getPipeRun().addChild(this);
48 public PipeControlPoint(PipelineComponent component, PipeRun piperun) {
49 this.component = component;
50 piperun.addChild(this);
54 public void update(vtkRenderer ren) {
56 PipingRules.requestUpdate(this);
57 } catch (Exception e) {
63 public PipeRun getPipeRun() {
64 return (PipeRun)getParent();
67 public PipelineComponent getPipelineComponent() {
71 public Type getType() {
75 public void setType(Type type) {
79 @GetPropertyValue(name="Fixed",tabId="Debug",value="fixed")
80 public boolean isFixed() {
85 public void setFixed(boolean fixed) {
89 @GetPropertyValue(name="Rotate",tabId="Debug",value="rotate")
90 public boolean isRotate() {
94 public void setRotate(boolean rotate) {
98 @GetPropertyValue(name="Reverse",tabId="Debug",value="reverse")
99 public boolean isReverse() {
103 public void setReverse(boolean reverse) {
104 this.reverse = reverse;
107 public void setSub(boolean sub) {
111 @GetPropertyValue(name="Deletable",tabId="Debug",value="deletable")
112 public boolean isDeletable() {
116 public void setDeletable(boolean deletable) {
117 this.deletable = deletable;
120 public boolean isPathLegEnd() {
121 return type != Type.INLINE;
124 public boolean isEnd() {
125 return type == Type.END;
128 public boolean isTurn() {
129 return type == Type.TURN;
132 public boolean isInline() {
133 return type == Type.INLINE;
136 public boolean isDirected() {
137 return fixed && isEnd();
140 public boolean isNonDirected() {
141 return !fixed && isEnd();
144 public boolean isVariableLength() {
145 return !fixed && isInline();
148 public boolean isVariableAngle() {
149 return !fixed && isTurn();
152 public boolean isBranchEnd() {
153 return deletable && isEnd();
156 public boolean isOffset() {
157 return offset != null;
160 public boolean isDualSub() {
161 return parent != null && sub;
164 public boolean isDualInline() {
165 return children.size() == 1 && children.get(0).isDualSub();
168 public boolean isSizeChange() {
169 if (children.size() == 0)
173 return getPipeRun() != children.get(0).getPipeRun();
177 private PipeControlPoint next;
178 private PipeControlPoint previous;
180 public PipeControlPoint getNext() {
184 public PipeControlPoint getPrevious() {
188 public void setNext(PipeControlPoint next) {
189 if (isEnd() && previous != null && next != null)
190 throw new RuntimeException("End control points are allowed to have only one connection");
191 if (this.next == next)
193 if (DEBUG) System.out.println(this + " next " + next);
195 if (component != null) {
196 if (parent == null || sub)
197 component.setNext(next != null ? next.component : null);
199 component.setBranch0(next != null ? next.component : null);
205 public void setPrevious(PipeControlPoint previous) {
206 if (isEnd() && next != null && previous != null)
207 throw new RuntimeException("End control points are allowed to have only one connection");
208 if (this.previous == previous)
210 if (DEBUG) System.out.println(this + " previous " + previous);
211 this.previous = previous;
212 if (component != null) {
213 if (parent == null || sub)
214 component.setPrevious(previous != null ? previous.component : null);
216 component.setBranch0(previous != null ? previous.component : null);
222 public PipeControlPoint parent;
223 public List<PipeControlPoint> children = new ArrayList<PipeControlPoint>();
225 public List<PipeControlPoint> getSubPoint() {
229 public PipeControlPoint getParentPoint() {
234 private double length;
235 private Double turnAngle;
236 private Vector3d turnAxis;
238 private Double offset;
239 private Double rotationAngle;
240 private Boolean reversed;
242 @GetPropertyValue(name="Length",tabId="Debug",value="length")
243 public double getLength() {
247 public void setLength(double l) {
248 if (Double.isInfinite(l) || Double.isNaN(l)) {
251 if (Math.abs(this.length-l) < MathTools.NEAR_ZERO)
254 firePropertyChanged("length");
256 getSubPoint().get(0).setLength(l);
259 @GetPropertyValue(name="Turn Angle",tabId="Debug",value="turnAngle")
260 public Double getTurnAngle() {
264 @GetPropertyValue(name="Turn Axis",tabId="Debug",value="turnAxis")
265 public Vector3d getTurnAxis() {
269 @GetPropertyValue(name="Offset",tabId="Debug",value="offset")
270 public Double getOffset() {
274 @GetPropertyValue(name="Rotation Angle",tabId="Debug",value="rotationAngle")
275 public Double getRotationAngle() {
276 return rotationAngle;
279 @GetPropertyValue(name="Reversed",tabId="Debug",value="reversed")
280 public Boolean getReversed() {
284 public boolean _getReversed() {
285 if (reversed == null)
290 public void setTurnAngle(Double turnAngle) {
291 if (Double.isInfinite(turnAngle) || Double.isNaN(turnAngle)) {
294 if (this.turnAngle != null && Math.abs(this.turnAngle-turnAngle) < MathTools.NEAR_ZERO)
296 this.turnAngle = turnAngle;
297 firePropertyChanged("turnAngle");
300 public void setTurnAxis(Vector3d turnAxis) {
301 if (this.turnAxis != null && MathTools.equals(turnAxis, this.turnAxis))
303 this.turnAxis = turnAxis;
304 firePropertyChanged("turnAxis");
307 public void setOffset(Double offset) {
308 if (Double.isInfinite(offset) || Double.isNaN(offset)) {
311 if (this.offset != null && Math.abs(this.offset-offset) < MathTools.NEAR_ZERO)
313 this.offset = offset;
314 firePropertyChanged("offset");
317 public void setRotationAngle(Double rotationAngle) {
318 if (Double.isInfinite(rotationAngle) || Double.isNaN(rotationAngle)) {
321 if (this.rotationAngle != null && Math.abs(this.rotationAngle-rotationAngle) < MathTools.NEAR_ZERO)
323 this.rotationAngle = rotationAngle;
324 firePropertyChanged("rotationAngle");
327 public void setReversed(Boolean reversed) {
328 this.reversed = reversed;
329 firePropertyChanged("reversed");
332 public Vector3d getSizeChangeOffsetVector(Vector3d dir) {
334 if (rotationAngle == null)
335 q = getControlPointOrientationQuat(dir, 0.0);
337 q = getControlPointOrientationQuat(dir, rotationAngle);
338 Vector3d v = new Vector3d(0.0,offset,0.0);
339 Vector3d offset = new Vector3d();
340 MathTools.rotate(q, v, offset);
344 public Vector3d getSizeChangeOffsetVector() {
346 if (rotationAngle == null)
347 q = getControlPointOrientationQuat(0.0);
349 q = getControlPointOrientationQuat(rotationAngle);
350 Vector3d v = new Vector3d(0.0,offset,0.0);
351 Vector3d offset = new Vector3d();
352 MathTools.rotate(q, v, offset);
356 @GetPropertyValue(name="Next",tabId="Debug",value="next")
357 private String getNextString() {
360 return next.toString();
363 @GetPropertyValue(name="Previous",tabId="Debug",value="previous")
364 private String getPrevString() {
365 if (previous == null)
367 return previous.toString();
370 @GetPropertyValue(name="Sub",tabId="Debug",value="sub")
371 private String getSubString() {
372 if (children.size() == 0)
374 return Arrays.toString(children.toArray());
377 @GetPropertyValue(name="Type",tabId="Debug",value="type")
378 public String getTypeString() {
382 public Quat4d getControlPointOrientationQuat(double angle) {
384 if (turnAxis == null) {
385 Vector3d dir = getPathLegDirection(Direction.NEXT);
386 if (dir.lengthSquared() > MathTools.NEAR_ZERO)
388 return getControlPointOrientationQuat(dir, angle);
390 Vector3d dir = getPathLegDirection(Direction.PREVIOUS);
392 if (dir.lengthSquared() > MathTools.NEAR_ZERO)
394 return getControlPointOrientationQuat(dir, turnAxis, angle);
398 public Quat4d getControlPointOrientationQuat(double angle, boolean reversed) {
400 if (turnAxis == null) {
401 Vector3d dir = getPathLegDirection(Direction.NEXT);
402 if (dir.lengthSquared() > MathTools.NEAR_ZERO)
404 Quat4d q = getControlPointOrientationQuat(dir, angle);
406 Quat4d q2 = new Quat4d();
407 q2.set(new AxisAngle4d(MathTools.Y_AXIS, Math.PI));
412 Vector3d dir = getPathLegDirection(Direction.PREVIOUS);
414 if (dir.lengthSquared() > MathTools.NEAR_ZERO)
416 return getControlPointOrientationQuat(dir, turnAxis, angle);
422 public static Quat4d getControlPointOrientationQuat(Vector3d dir, double angle) {
423 if (dir.lengthSquared() < MathTools.NEAR_ZERO)
424 return MathTools.getIdentityQuat();
427 Vector3d up = new Vector3d(0.0, 1.0, 0.0);
428 double a = up.angle(dir);
429 if (a < 0.1 || (Math.PI - a) < 0.1) {
430 up.set(1.0, 0.0, 0.0);
434 return getControlPointOrientationQuat(dir, up, angle);
437 public static Quat4d getControlPointOrientationQuat(Vector3d dir, Vector3d up, double angle) {
438 if (dir.lengthSquared() < MathTools.NEAR_ZERO)
439 return MathTools.getIdentityQuat();
441 final Vector3d front = new Vector3d(1.0,0.0,0.0);
443 Quat4d q1 = new Quat4d();
446 Vector3d right = new Vector3d();
448 right.cross(dir, up);
449 up.cross(right, dir);
453 Matrix3d m = new Matrix3d();
464 //q1.set(m); MathTools contains more stable conversion
465 MathTools.getQuat(m, q1);
467 // if (DEBUG) System.out.println("PipingTools.getPipeComponentOrientationQuat() " + dir+ " " + up + " " + right);
469 Quat4d q2 = new Quat4d();
470 q2.set(new AxisAngle4d(front, angle));
475 public Vector3d getDirection(Direction direction) {
477 return getDirectedControlPointDirection();
478 if (isTurn() && isFixed()) {
479 if (direction == Direction.NEXT) {
480 if (previous != null) {
481 PipeControlPoint pcp = this;
482 Vector3d dir = new Vector3d();
483 dir.sub(pcp.getWorldPosition(),previous.getWorldPosition());
484 if (dir.lengthSquared() > MathTools.NEAR_ZERO)
488 Quat4d q = getControlPointOrientationQuat(dir, pcp.getRotationAngle() != null ? pcp.getRotationAngle() : 0.0);
489 AxisAngle4d aa = new AxisAngle4d(MathTools.Y_AXIS,pcp.getTurnAngle() == null ? 0.0 : pcp.getTurnAngle());
490 Quat4d q2 = MathTools.getQuat(aa);
491 Vector3d v = new Vector3d(1.,0.,0.);
492 Vector3d offset = new Vector3d();
493 MathTools.rotate(q2, v, offset);
494 MathTools.rotate(q, offset, dir);
499 PipeControlPoint pcp = this;
500 Vector3d dir = new Vector3d();
501 dir.sub(next.getWorldPosition(),pcp.getWorldPosition());
502 if (dir.lengthSquared() > MathTools.NEAR_ZERO)
506 Quat4d q = getControlPointOrientationQuat(dir, pcp.getRotationAngle() != null ? pcp.getRotationAngle() : 0.0);
507 AxisAngle4d aa = new AxisAngle4d(MathTools.Y_AXIS,pcp.getTurnAngle() == null ? 0.0 : pcp.getTurnAngle());
508 Quat4d q2 = MathTools.getQuat(aa);
509 Vector3d v = new Vector3d(1.,0.,0.);
510 Vector3d offset = new Vector3d();
511 MathTools.rotate(q2, v, offset);
512 MathTools.rotate(q, offset, dir);
520 public void insert(PipeControlPoint previous, PipeControlPoint next) {
521 // inserting an offsetpoint is error,
523 throw new RuntimeException("Dual sub points cannot be inserted.");
524 // size change control point cannot be inserted this way, because it ends PipeRun
526 throw new RuntimeException("Size change points cannot be inserted.");
527 PipeRun piperun = previous.getPipeRun();
528 // and just to make sure that control point structure is not corrupted
529 if (getPipeRun() != null) {
530 if (piperun != getPipeRun() || piperun != next.getPipeRun())
531 throw new RuntimeException("All controls points must be located on the same pipe run");
533 piperun.addChild(this);
536 // insert new BranchControlPoint between straight's control points
537 PipeControlPoint previousNext = previous.getNext();
538 PipeControlPoint previousPrevious = previous.getPrevious();
540 PipeControlPoint offsetCP = null;
542 offsetCP = getSubPoint().get(0);
544 if (previousNext != null && previousNext == next) {
545 if (previous.isDualInline()) {
546 throw new RuntimeException();
548 if (next.isDualSub()) {
549 throw new RuntimeException();
551 previous.setNext(this);
552 this.setPrevious(previous);
553 if (previous.isDualSub()) {
554 previous.getParentPoint().setNext(this);
558 if (offsetCP == null) {
559 next.setPrevious(this);
561 next.setPrevious(offsetCP);
562 offsetCP.setNext(next);
563 offsetCP.setPrevious(previous);
566 if (next.isDualInline()) {
567 next.getSubPoint().get(0).setPrevious(this);
569 } else if (previousPrevious != null && previousPrevious == next) {
570 // control point were given in reverse order
571 if (next.isDualInline())
572 throw new RuntimeException();
573 if (previous.isDualSub())
574 throw new RuntimeException();
576 this.setNext(previous);
577 if (offsetCP == null) {
578 previous.setNext(this);
580 previous.setPrevious(offsetCP);
581 offsetCP.setNext(previous);
582 offsetCP.setPrevious(next);
584 if (previous.isDualInline()) {
585 previous.getSubPoint().get(0).setPrevious(this);
587 this.setPrevious(next);
589 if (next.isDualSub()) {
590 next.getParentPoint().setNext(this);
594 throw new RuntimeException();
597 PipingRules.validate(piperun);
602 public void insert(PipeControlPoint pcp, Direction direction) {
604 throw new RuntimeException();
605 if (direction == Direction.NEXT) {
606 // if direction is next, user must have given OffsetPoint
607 if (pcp.isDualInline())
608 throw new RuntimeException();
609 // basic next/prev links
611 this.setPrevious(pcp);
612 // and last take care of sizechange / offset points
613 if (pcp.isDualSub()) {
614 pcp.getParentPoint().setNext(this);
616 if (isDualInline()) {
617 getSubPoint().get(0).setPrevious(this);
620 // if direction is previous, user must have given sizechange
622 throw new RuntimeException();
623 // previous direction is more complicated, since if newCP is SizeChangeControlPoint,
624 // we must link pcp to newCP's OffsetPoint
625 PipeControlPoint nocp = null;
626 if (isDualInline()) {
627 nocp = getSubPoint().get(0);
631 pcp.setPrevious(this);
633 pcp.setPrevious(nocp);
636 if (pcp.isDualInline()) {
637 PipeControlPoint ocp = pcp.getSubPoint().get(0);
639 ocp.setPrevious(this);
641 ocp.setPrevious(nocp);
645 PipingRules.validate(getPipeRun());
648 public Vector3d getDirectedControlPointDirection() {
649 assert (isDirected());
650 Vector3d dir = new Vector3d();
651 MathTools.rotate(getWorldOrientation(), new Vector3d(1.0, 0.0, 0.0), dir);
656 public Vector3d getPathLegDirection(Direction direction) {
657 if (direction == Direction.NEXT) {
659 PipeControlPoint pcp = this;
660 if (pcp.isDualInline()) {
661 pcp = pcp.getSubPoint().get(0);
663 Vector3d v = new Vector3d();
664 v.sub(next.getWorldPosition(),pcp.getWorldPosition());
667 if (previous == null) {
669 throw new RuntimeException("Cannot calculate path leg direction for unconnected control point");
670 return getDirectedControlPointDirection();
673 if (isVariableAngle())
674 throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point");
676 PipeControlPoint pcp = this;
677 if (pcp.isDualSub()) {
678 pcp = pcp.getParentPoint();
680 Vector3d v = new Vector3d();
681 v.sub(pcp.getWorldPosition(),previous.getWorldPosition());
683 } else if (isDirected()) {
684 return getDirectedControlPointDirection();
685 } else if (isEnd()) {
686 Vector3d v = new Vector3d();
687 v.sub(getWorldPosition(),previous.getWorldPosition());
689 } else if (isTurn() && isFixed() && !_getReversed()) {
690 return getDirection(Direction.NEXT);
692 throw new RuntimeException("Missing implementation");
696 if (previous != null) {
697 PipeControlPoint pcp = this;
699 pcp = getParentPoint();
700 Vector3d v = new Vector3d();
701 v.sub(previous.getWorldPosition(),pcp.getWorldPosition());
706 throw new RuntimeException("Cannot calculate path leg direction for unconnected control point");
707 Vector3d v = getDirectedControlPointDirection();
711 if (isVariableAngle())
712 throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point");
714 PipeControlPoint pcp = this;
715 if (pcp.isDualInline()) {
716 pcp = pcp.getSubPoint().get(0);
718 Vector3d v = new Vector3d();
719 v.sub(pcp.getWorldPosition(),next.getWorldPosition());
721 } else if (isDirected()) {
722 Vector3d v = getDirectedControlPointDirection();
725 } else if (isEnd()) {
726 Vector3d v = new Vector3d();
727 v.sub(getWorldPosition(),next.getWorldPosition());
729 } else if (isTurn() && isFixed() && _getReversed()) {
730 return getDirection(Direction.PREVIOUS);
732 throw new RuntimeException("Missing implementation");
738 public void getInlineControlPointEnds(Tuple3d p1, Tuple3d p2) {
741 Vector3d pos = getWorldPosition();
742 Vector3d dir = getPathLegDirection(Direction.NEXT);
744 dir.scale(length * 0.5);
751 public void getControlPointEnds(Tuple3d p1, Tuple3d p2) {
752 Vector3d pos = getWorldPosition();
753 Vector3d dir1 = getPathLegDirection(Direction.PREVIOUS);
755 Vector3d dir2 = getPathLegDirection(Direction.NEXT);
758 dir1.scale(length * 0.5);
759 dir2.scale(length * 0.5);
770 public void getInlineControlPointEnds(Tuple3d p1, Tuple3d p2, Vector3d dir) {
773 Vector3d pos = getWorldPosition();
774 dir.set(getPathLegDirection(Direction.NEXT));
776 dir.scale(length * 0.5);
783 public void getInlineControlPointEnds(Tuple3d center, Tuple3d p1, Tuple3d p2, Vector3d dir) {
786 Vector3d pos = getWorldPosition();
788 dir.set(getPathLegDirection(Direction.NEXT));
790 dir.scale(length * 0.5);
797 public double getInlineLength() {
798 if (type == Type.TURN)
800 else if (type == Type.INLINE)
805 public Vector3d getRealPosition(PositionType type) {
806 Vector3d pos = getWorldPosition();
809 Vector3d dir = getPathLegDirection(Direction.NEXT);
810 double length = getInlineLength();
817 Vector3d dir = getPathLegDirection(Direction.PREVIOUS);
818 double length = getInlineLength();
825 // IEntity portDir = pcp.getSingleRelatedObject(ProcessResource.plant3Dresource.HasDirection);
826 // TODO : how we calculated needed space for a port; does it has an offset from control point's position or not?
836 public void getInlineMovement(Tuple3d start, Tuple3d end) {
837 // FIXME : check type of neighbor components and allow movement on top of variable length components,
838 // find proper range for movement (pcp's position is not)
839 PipeControlPoint p = previous.getPrevious();
840 PipeControlPoint n = next.getNext();
841 start.set(p.getWorldPosition());
842 end.set(n.getWorldPosition());
845 public PipeControlPoint findNextEnd() {
846 ArrayList<PipeControlPoint> t = new ArrayList<PipeControlPoint>();
847 return findNextEnd( t);
850 public PipeControlPoint findPreviousEnd() {
851 ArrayList<PipeControlPoint> t = new ArrayList<PipeControlPoint>();
852 return findPreviousEnd(t);
855 public PipeControlPoint findNextEnd(List<PipeControlPoint> nextList) {
857 PipeControlPoint pcp = null;
858 PipeControlPoint p = null;
859 if (nextList.size() == 0)
863 p = nextList.get(nextList.size() - 1);
868 if (nextList.size() > 0)
869 nextList.remove(nextList.size() - 1);
870 // if (DEBUG) System.out.println(" " + pcp.getResource() + " not full");
874 if (pcp.isPathLegEnd()) {
875 //if (DEBUG) System.out.println(" " + pcp.getResource());
879 // if (DEBUG) System.out.print(" " + pcp.getResource());
884 public PipeControlPoint findPreviousEnd(List<PipeControlPoint> prevList) {
886 PipeControlPoint pcp = null;
887 PipeControlPoint p = null;
888 if (prevList.size() == 0)
892 p = prevList.get(prevList.size() - 1);
894 pcp = p.getPrevious();
897 if (prevList.size() > 0)
898 prevList.remove(prevList.size() - 1);
899 // if (DEBUG) System.out.println(" " + pcp.getResource() + " not full");
902 if (pcp.isPathLegEnd()) {
903 // if (DEBUG) System.out.println(" " + pcp.getResource());
907 // if (DEBUG)System.out.print(" " + pcp.getResource());
912 public void _remove() {
913 if (component == null && next == null && previous == null)
915 if (isDualInline() || isDualSub()) {
919 PipeRun pipeRun = getPipeRun();
923 PipeControlPoint additionalRemove = null;
924 if (!PipingRules.isEnabled()) {
929 PipeControlPoint currentPrev = previous;
930 PipeControlPoint currentNext = next;
931 if (currentNext == null && currentPrev == null) {
933 pipeRun.remChild(this);
936 if (currentNext != null && currentPrev != null) {
938 if (currentNext.isBranchEnd()) {
940 // currentNext.setPrevious(null);
941 // currentNext.setNext(null);
942 currentNext.remove();
946 if (currentPrev.isBranchEnd()) {
948 // currentPrev.setPrevious(null);
949 // currentPrev.setNext(null);
950 currentPrev.remove();
954 if (link && currentPrev.isDirected() && currentNext.isDirected()) {
957 if (currentNext == null) {
959 } else if (currentNext.isDualInline()) {
960 PipeControlPoint sccp = currentNext;
961 PipeControlPoint ocp = sccp.getSubPoint().get(0);
963 throw new RuntimeException("Removing PipeControlPoint " + this+ " structure damaged, no offset control point");
966 sccp.setPrevious(currentPrev);
967 ocp.setPrevious(currentPrev);
969 sccp.setPrevious(null);
970 ocp.setPrevious(null);
973 } else if (currentNext.isDualSub()) {
974 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, next control point is offset control point");
975 } else if (currentNext.previous == this) {
977 currentNext.setPrevious(currentPrev);
979 currentNext.setPrevious(null);
983 throw new RuntimeException("Removing PipeControlPoint "+ this+ " structure damaged");
985 if (currentPrev == null) {
987 } else if (currentPrev.isDualInline()) {
988 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, previous control point is size change control point");
989 } else if (currentPrev.isDualSub()) {
990 PipeControlPoint ocp = currentPrev;
991 PipeControlPoint sccp = ocp.getParentPoint();
993 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, no size change control point");
995 ocp.setNext(currentNext);
996 sccp.setNext(currentNext);
1002 } else if (currentPrev.next == this) {
1004 currentPrev.setNext(currentNext);
1006 currentPrev.setNext(null);
1010 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged");
1013 if (currentNext.isVariableLength() && currentPrev.isVariableLength()) {
1014 // we have to join them into single variable length component.
1015 additionalRemove = currentPrev;
1016 //currentPrev.remove();
1019 // FIXME : pipe run must be split into two parts, since the control point structure is no more continuous.
1021 } else if (next != null) {
1022 if (next.isDualInline()) {
1023 PipeControlPoint sccp = next;
1024 PipeControlPoint ocp = sccp.getSubPoint().get(0);
1026 throw new RuntimeException("Removing PipeControlPoint " + this+ " structure damaged, no offset control point");
1028 sccp.setPrevious(null);
1029 ocp.setPrevious(null);
1030 } else if (next.isDualSub()) {
1031 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, next control point is offset control point");
1032 } else if (next.previous == this) {
1033 next.setPrevious(null);
1035 throw new RuntimeException("Removing PipeControlPoint "+ this+ " structure damaged");
1038 } else { //(previous != null)
1039 if(previous.isDualInline()) {
1040 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, previous control point is size change control point");
1041 } else if (previous.isDualSub()) {
1042 PipeControlPoint ocp = previous;
1043 PipeControlPoint sccp = ocp.getParentPoint();
1045 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, no size change control point");
1049 } else if (previous.next == this) {
1050 previous.setNext(null);
1052 throw new RuntimeException("Removing PipeControlPoint "+ this+ " structure damaged");
1056 if (children.size() > 0 ) {
1058 } else if (parent!= null) {
1059 removeParentPoint();
1065 pipeRun.remChild(this);
1066 checkRemove(pipeRun);
1067 if (PipingRules.isEnabled() && pipeRun.getParent() != null && pipeRun.getControlPoints().size() > 0)
1068 PipingRules.validate(pipeRun);
1069 if (additionalRemove != null)
1070 additionalRemove.remove();
1073 public void remove() {
1074 PipeControlPoint currentPrev = previous;
1075 PipeControlPoint currentNext = next;
1078 if (currentNext != null)
1079 PipingRules.requestUpdate(currentNext);
1080 if (currentPrev != null)
1081 PipingRules.requestUpdate(currentPrev);
1082 } catch (Exception e) {
1083 e.printStackTrace();
1087 private void checkRemove(PipeRun pipeRun) {
1088 Collection<PipeControlPoint> points = pipeRun.getControlPoints();
1089 if (points.size() == 0) {
1091 } else if (points.size() == 1) {
1092 PipeControlPoint pcp = points.iterator().next();
1093 if (pcp.isDeletable())
1098 private void removeDualPoint() {
1099 if (previous != null)
1100 previous.setNext(null);
1102 next.setPrevious(null);
1103 PipeControlPoint ocp;
1104 PipeControlPoint sccp;
1105 if (isDualInline()) {
1107 ocp = getSubPoint().get(0);
1110 sccp = getParentPoint();
1112 PipeRun p1 = ocp.getPipeRun();
1113 PipeRun p2 = sccp.getPipeRun();
1115 ocp.removeComponent();
1116 sccp.removeComponent();
1121 // TODO : now we assume that this is size change, and we do
1122 if (ocp.next != null)
1123 ocp.next.setPrevious(null);
1124 if (ocp.previous != null)
1125 ocp.previous.setNext(null);
1126 if (sccp.next != null)
1127 sccp.next.setPrevious(null);
1128 if (sccp.previous != null)
1129 sccp.previous.setNext(null);
1131 ocp.setPrevious(null);
1133 sccp.setPrevious(null);
1139 private void removeSubPoints() {
1140 for (PipeControlPoint p : children) {
1141 // TODO : this may affect delete routine, since classification of the point changes.
1148 private void removeParentPoint() {
1149 throw new RuntimeException("Child points cannot be removed directly");
1152 private void removeComponent() {
1153 if (component == null)
1155 PipelineComponent next = component.getNext();
1156 PipelineComponent prev = component.getPrevious();
1157 PipelineComponent br0 = component.getBranch0();
1158 component.setNext(null);
1159 component.setPrevious(null);
1160 component.setBranch0(null);
1162 if (next.getNext() == component)
1164 else if (next.getPrevious() == component)
1165 next.setPrevious(null);
1166 else if (next.getBranch0() == component)
1167 next.setBranch0(null);
1170 if (prev.getNext() == component)
1172 else if (prev.getPrevious() == component)
1173 prev.setPrevious(null);
1174 else if (prev.getBranch0() == component)
1175 prev.setBranch0(null);
1178 if (br0.getNext() == component)
1180 else if (br0.getPrevious() == component)
1181 prev.setPrevious(null);
1182 else if (br0.getBranch0() == component)
1183 br0.setBranch0(null);
1185 PipelineComponent comp = component;
1192 public void setOrientation(Quat4d orientation) {
1193 if (MathTools.equals(orientation, getOrientation()))
1195 super.setOrientation(orientation);
1196 if (getParentPoint() == null && component != null)
1197 component._setWorldOrientation(getWorldOrientation());
1202 public void setPosition(Vector3d position) {
1203 if (MathTools.equals(position, getPosition()))
1205 if (Double.isNaN(position.x) || Double.isNaN(position.y) || Double.isNaN(position.z))
1206 throw new IllegalArgumentException("NaN is not supported");
1207 super.setPosition(position);
1208 if (getParentPoint() == null && component != null)
1209 component._setWorldPosition(getWorldPosition());
1213 private void updateSubPoint() {
1215 if (next == null && previous == null) {
1216 for (PipeControlPoint sub : getSubPoint()) {
1217 sub.setWorldPosition(getWorldPosition());
1218 sub.setWorldOrientation(getWorldOrientation());
1222 for (PipeControlPoint sub : getSubPoint()) {
1223 Vector3d wp = getWorldPosition();
1224 wp.add(getSizeChangeOffsetVector());
1225 sub.setWorldPosition(wp);
1226 sub.setWorldOrientation(getWorldOrientation());
1229 for (PipeControlPoint sub : getSubPoint()) {
1230 sub.setWorldPosition(getWorldPosition());
1231 sub.setWorldOrientation(getWorldOrientation());
1237 public void _setWorldPosition(Vector3d position) {
1238 Vector3d localPos = getLocalPosition(position);
1239 super.setPosition(localPos);
1243 public void _setWorldOrientation(Quat4d orientation) {
1244 Quat4d localOr = getLocalOrientation(orientation);
1245 super.setOrientation(localOr);
1250 public String toString() {
1251 return getClass().getName() + "@" + Integer.toHexString(hashCode());