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 fixed = true;
37 private boolean rotate = false;
38 private boolean reverse = false;
39 private boolean deletable = true;
40 private boolean sub = false;
42 public PipeControlPoint(PipelineComponent component) {
43 this.component = component;
44 if (component.getPipeRun() != null)
45 component.getPipeRun().addChild(this);
49 public PipeControlPoint(PipelineComponent component, PipeRun piperun) {
50 this.component = component;
51 piperun.addChild(this);
55 public void update(vtkRenderer ren) {
57 PipingRules.requestUpdate(this);
58 } catch (Exception e) {
64 public PipeRun getPipeRun() {
65 return (PipeRun)getParent();
68 public PipelineComponent getPipelineComponent() {
72 public PointType getType() {
76 public void setType(PointType type) {
80 @GetPropertyValue(name="Fixed",tabId="Debug",value="fixed")
81 public boolean isFixed() {
86 public void setFixed(boolean fixed) {
90 @GetPropertyValue(name="Rotate",tabId="Debug",value="rotate")
91 public boolean isRotate() {
95 public void setRotate(boolean rotate) {
99 @GetPropertyValue(name="Reverse",tabId="Debug",value="reverse")
100 public boolean isReverse() {
104 public void setReverse(boolean reverse) {
105 this.reverse = reverse;
108 public void setSub(boolean sub) {
112 @GetPropertyValue(name="Deletable",tabId="Debug",value="deletable")
113 public boolean isDeletable() {
117 public void setDeletable(boolean deletable) {
118 this.deletable = deletable;
121 public boolean isPathLegEnd() {
122 return type != PointType.INLINE;
125 public boolean isEnd() {
126 return type == PointType.END;
129 public boolean isTurn() {
130 return type == PointType.TURN;
133 public boolean isInline() {
134 return type == PointType.INLINE;
137 public boolean isDirected() {
138 return fixed && isEnd();
141 public boolean isNonDirected() {
142 return !fixed && isEnd();
145 public boolean isVariableLength() {
146 return !fixed && isInline();
149 public boolean isVariableAngle() {
150 return !fixed && isTurn();
153 public boolean isBranchEnd() {
154 return deletable && isEnd();
157 public boolean isOffset() {
158 return offset != null;
161 public boolean isDualSub() {
162 return parent != null && sub;
165 public boolean isDualInline() {
166 return children.size() == 1 && children.get(0).isDualSub();
169 public boolean isSizeChange() {
170 if (children.size() == 0)
174 return getPipeRun() != children.get(0).getPipeRun();
178 private PipeControlPoint next;
179 private PipeControlPoint previous;
181 public PipeControlPoint getNext() {
185 public PipeControlPoint getPrevious() {
189 public void setNext(PipeControlPoint next) {
190 if (isEnd() && previous != null && next != null)
191 throw new RuntimeException("End control points are allowed to have only one connection");
192 if (this.next == next)
194 if (DEBUG) System.out.println(this + " next " + next);
196 if (component != null) {
197 if (parent == null || sub)
198 component.setNext(next != null ? next.component : null);
200 component.setBranch0(next != null ? next.component : null);
206 public void setPrevious(PipeControlPoint previous) {
207 if (isEnd() && next != null && previous != null)
208 throw new RuntimeException("End control points are allowed to have only one connection");
209 if (this.previous == previous)
211 if (DEBUG) System.out.println(this + " previous " + previous);
212 this.previous = previous;
213 if (component != null) {
214 if (parent == null || sub)
215 component.setPrevious(previous != null ? previous.component : null);
217 component.setBranch0(previous != null ? previous.component : null);
223 public PipeControlPoint parent;
224 public List<PipeControlPoint> children = new ArrayList<PipeControlPoint>();
226 public List<PipeControlPoint> getSubPoint() {
230 public PipeControlPoint getParentPoint() {
235 private double length;
236 private Double turnAngle;
237 private Vector3d turnAxis;
239 private Double offset;
240 private Double rotationAngle;
241 private Boolean reversed;
243 @GetPropertyValue(name="Length",tabId="Debug",value="length")
244 public double getLength() {
248 public void setLength(double l) {
249 if (Double.isInfinite(l) || Double.isNaN(l)) {
252 if (Math.abs(this.length-l) < MathTools.NEAR_ZERO)
255 firePropertyChanged("length");
257 getSubPoint().get(0).setLength(l);
260 @GetPropertyValue(name="Turn Angle",tabId="Debug",value="turnAngle")
261 public Double getTurnAngle() {
265 @GetPropertyValue(name="Turn Axis",tabId="Debug",value="turnAxis")
266 public Vector3d getTurnAxis() {
270 @GetPropertyValue(name="Offset",tabId="Debug",value="offset")
271 public Double getOffset() {
275 @GetPropertyValue(name="Rotation Angle",tabId="Debug",value="rotationAngle")
276 public Double getRotationAngle() {
277 return rotationAngle;
280 @GetPropertyValue(name="Reversed",tabId="Debug",value="reversed")
281 public Boolean getReversed() {
285 public boolean _getReversed() {
286 if (reversed == null)
291 public void setTurnAngle(Double turnAngle) {
292 if (turnAngle == null || Double.isInfinite(turnAngle) || Double.isNaN(turnAngle)) {
295 if (this.turnAngle != null && Math.abs(this.turnAngle-turnAngle) < MathTools.NEAR_ZERO)
297 this.turnAngle = turnAngle;
298 firePropertyChanged("turnAngle");
301 public void setTurnAxis(Vector3d turnAxis) {
302 if (this.turnAxis != null && MathTools.equals(turnAxis, this.turnAxis))
304 this.turnAxis = turnAxis;
305 firePropertyChanged("turnAxis");
308 public void setOffset(Double offset) {
309 if (Double.isInfinite(offset) || Double.isNaN(offset)) {
312 if (this.offset != null && Math.abs(this.offset-offset) < MathTools.NEAR_ZERO)
314 this.offset = offset;
315 firePropertyChanged("offset");
318 public void setRotationAngle(Double rotationAngle) {
319 if (Double.isInfinite(rotationAngle) || Double.isNaN(rotationAngle)) {
322 if (this.rotationAngle != null && Math.abs(this.rotationAngle-rotationAngle) < MathTools.NEAR_ZERO)
324 this.rotationAngle = rotationAngle;
325 firePropertyChanged("rotationAngle");
328 public void setReversed(Boolean reversed) {
329 this.reversed = reversed;
330 firePropertyChanged("reversed");
333 public Vector3d getSizeChangeOffsetVector(Vector3d dir) {
335 if (rotationAngle == null)
336 q = getControlPointOrientationQuat(dir, 0.0);
338 q = getControlPointOrientationQuat(dir, rotationAngle);
339 Vector3d v = new Vector3d(0.0,offset,0.0);
340 Vector3d offset = new Vector3d();
341 MathTools.rotate(q, v, offset);
345 public Vector3d getSizeChangeOffsetVector() {
347 if (rotationAngle == null)
348 q = getControlPointOrientationQuat(0.0);
350 q = getControlPointOrientationQuat(rotationAngle);
351 Vector3d v = new Vector3d(0.0,offset,0.0);
352 Vector3d offset = new Vector3d();
353 MathTools.rotate(q, v, offset);
357 @GetPropertyValue(name="Next",tabId="Debug",value="next")
358 private String getNextString() {
361 return next.toString();
364 @GetPropertyValue(name="Previous",tabId="Debug",value="previous")
365 private String getPrevString() {
366 if (previous == null)
368 return previous.toString();
371 @GetPropertyValue(name="Sub",tabId="Debug",value="sub")
372 private String getSubString() {
373 if (children.size() == 0)
375 return Arrays.toString(children.toArray());
378 @GetPropertyValue(name="Type",tabId="Debug",value="type")
379 public String getTypeString() {
383 public Quat4d getControlPointOrientationQuat(double angle) {
385 if (turnAxis == null) {
386 Vector3d dir = getPathLegDirection(Direction.NEXT);
387 if (dir.lengthSquared() > MathTools.NEAR_ZERO)
389 return getControlPointOrientationQuat(dir, angle);
391 Vector3d dir = getPathLegDirection(Direction.PREVIOUS);
393 if (dir.lengthSquared() > MathTools.NEAR_ZERO)
395 return getControlPointOrientationQuat(dir, turnAxis, angle);
399 public Quat4d getControlPointOrientationQuat(double angle, boolean reversed) {
401 if (turnAxis == null) {
402 Vector3d dir = getPathLegDirection(Direction.NEXT);
403 if (dir.lengthSquared() > MathTools.NEAR_ZERO)
405 Quat4d q = getControlPointOrientationQuat(dir, angle);
407 Quat4d q2 = new Quat4d();
408 q2.set(new AxisAngle4d(MathTools.Y_AXIS, Math.PI));
413 Vector3d dir = getPathLegDirection(Direction.PREVIOUS);
415 if (dir.lengthSquared() > MathTools.NEAR_ZERO)
417 return getControlPointOrientationQuat(dir, turnAxis, angle);
423 public static Quat4d getControlPointOrientationQuat(Vector3d dir, double angle) {
424 if (dir.lengthSquared() < MathTools.NEAR_ZERO)
425 return MathTools.getIdentityQuat();
428 Vector3d up = new Vector3d(0.0, 1.0, 0.0);
429 double a = up.angle(dir);
430 if (a < 0.1 || (Math.PI - a) < 0.1) {
431 up.set(1.0, 0.0, 0.0);
435 return getControlPointOrientationQuat(dir, up, angle);
438 public static Quat4d getControlPointOrientationQuat(Vector3d dir, Vector3d up, double angle) {
439 if (dir.lengthSquared() < MathTools.NEAR_ZERO)
440 return MathTools.getIdentityQuat();
442 final Vector3d front = new Vector3d(1.0,0.0,0.0);
444 Quat4d q1 = new Quat4d();
447 Vector3d right = new Vector3d();
449 right.cross(dir, up);
450 up.cross(right, dir);
454 Matrix3d m = new Matrix3d();
465 //q1.set(m); MathTools contains more stable conversion
466 MathTools.getQuat(m, q1);
468 // if (DEBUG) System.out.println("PipingTools.getPipeComponentOrientationQuat() " + dir+ " " + up + " " + right);
470 Quat4d q2 = new Quat4d();
471 q2.set(new AxisAngle4d(front, angle));
476 public Vector3d getDirection(Direction direction) {
478 return getDirectedControlPointDirection();
479 if (isTurn() && isFixed()) {
480 if (direction == Direction.NEXT) {
481 if (previous != null) {
482 PipeControlPoint pcp = this;
483 Vector3d dir = new Vector3d();
484 dir.sub(pcp.getWorldPosition(),previous.getWorldPosition());
485 if (dir.lengthSquared() > MathTools.NEAR_ZERO)
489 Quat4d q = getControlPointOrientationQuat(dir, pcp.getRotationAngle() != null ? pcp.getRotationAngle() : 0.0);
490 AxisAngle4d aa = new AxisAngle4d(MathTools.Y_AXIS,pcp.getTurnAngle() == null ? 0.0 : pcp.getTurnAngle());
491 Quat4d q2 = MathTools.getQuat(aa);
492 Vector3d v = new Vector3d(1.,0.,0.);
493 Vector3d offset = new Vector3d();
494 MathTools.rotate(q2, v, offset);
495 MathTools.rotate(q, offset, dir);
500 PipeControlPoint pcp = this;
501 Vector3d dir = new Vector3d();
502 dir.sub(next.getWorldPosition(),pcp.getWorldPosition());
503 if (dir.lengthSquared() > MathTools.NEAR_ZERO)
507 Quat4d q = getControlPointOrientationQuat(dir, pcp.getRotationAngle() != null ? pcp.getRotationAngle() : 0.0);
508 AxisAngle4d aa = new AxisAngle4d(MathTools.Y_AXIS,pcp.getTurnAngle() == null ? 0.0 : pcp.getTurnAngle());
509 Quat4d q2 = MathTools.getQuat(aa);
510 Vector3d v = new Vector3d(1.,0.,0.);
511 Vector3d offset = new Vector3d();
512 MathTools.rotate(q2, v, offset);
513 MathTools.rotate(q, offset, dir);
521 public void insert(PipeControlPoint previous, PipeControlPoint next) {
522 // inserting an offsetpoint is error,
524 throw new RuntimeException("Dual sub points cannot be inserted.");
525 // size change control point cannot be inserted this way, because it ends PipeRun
527 throw new RuntimeException("Size change points cannot be inserted.");
528 PipeRun piperun = previous.getPipeRun();
529 // and just to make sure that control point structure is not corrupted
530 if (getPipeRun() != null) {
531 if (piperun != getPipeRun() || piperun != next.getPipeRun())
532 throw new RuntimeException("All controls points must be located on the same pipe run");
534 piperun.addChild(this);
537 // insert new BranchControlPoint between straight's control points
538 PipeControlPoint previousNext = previous.getNext();
539 PipeControlPoint previousPrevious = previous.getPrevious();
541 PipeControlPoint offsetCP = null;
543 offsetCP = getSubPoint().get(0);
545 if (previousNext != null && previousNext == next) {
546 if (previous.isDualInline()) {
547 throw new RuntimeException();
549 if (next.isDualSub()) {
550 throw new RuntimeException();
552 previous.setNext(this);
553 this.setPrevious(previous);
554 if (previous.isDualSub()) {
555 previous.getParentPoint().setNext(this);
559 if (offsetCP == null) {
560 next.setPrevious(this);
562 next.setPrevious(offsetCP);
563 offsetCP.setNext(next);
564 offsetCP.setPrevious(previous);
567 if (next.isDualInline()) {
568 next.getSubPoint().get(0).setPrevious(this);
570 } else if (previousPrevious != null && previousPrevious == next) {
571 // control point were given in reverse order
572 if (next.isDualInline())
573 throw new RuntimeException();
574 if (previous.isDualSub())
575 throw new RuntimeException();
577 this.setNext(previous);
578 if (offsetCP == null) {
579 previous.setNext(this);
581 previous.setPrevious(offsetCP);
582 offsetCP.setNext(previous);
583 offsetCP.setPrevious(next);
585 if (previous.isDualInline()) {
586 previous.getSubPoint().get(0).setPrevious(this);
588 this.setPrevious(next);
590 if (next.isDualSub()) {
591 next.getParentPoint().setNext(this);
595 throw new RuntimeException();
598 PipingRules.validate(piperun);
603 public void insert(PipeControlPoint pcp, Direction direction) {
605 throw new RuntimeException();
606 if (direction == Direction.NEXT) {
607 // if direction is next, user must have given OffsetPoint
608 if (pcp.isDualInline())
609 throw new RuntimeException();
610 // basic next/prev links
612 this.setPrevious(pcp);
613 // and last take care of sizechange / offset points
614 if (pcp.isDualSub()) {
615 pcp.getParentPoint().setNext(this);
617 if (isDualInline()) {
618 getSubPoint().get(0).setPrevious(this);
621 // if direction is previous, user must have given sizechange
623 throw new RuntimeException();
624 // previous direction is more complicated, since if newCP is SizeChangeControlPoint,
625 // we must link pcp to newCP's OffsetPoint
626 PipeControlPoint nocp = null;
627 if (isDualInline()) {
628 nocp = getSubPoint().get(0);
632 pcp.setPrevious(this);
634 pcp.setPrevious(nocp);
637 if (pcp.isDualInline()) {
638 PipeControlPoint ocp = pcp.getSubPoint().get(0);
640 ocp.setPrevious(this);
642 ocp.setPrevious(nocp);
646 PipingRules.validate(getPipeRun());
649 public Vector3d getDirectedControlPointDirection() {
650 assert (isDirected());
651 Vector3d dir = new Vector3d();
652 MathTools.rotate(getWorldOrientation(), new Vector3d(1.0, 0.0, 0.0), dir);
657 public Vector3d getPathLegDirection(Direction direction) {
658 if (direction == Direction.NEXT) {
660 PipeControlPoint pcp = this;
661 if (pcp.isDualInline()) {
662 pcp = pcp.getSubPoint().get(0);
664 Vector3d v = new Vector3d();
665 v.sub(next.getWorldPosition(),pcp.getWorldPosition());
668 if (previous == null) {
670 throw new RuntimeException("Cannot calculate path leg direction for unconnected control point");
671 return getDirectedControlPointDirection();
674 if (isVariableAngle())
675 throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point");
677 PipeControlPoint pcp = this;
678 if (pcp.isDualSub()) {
679 pcp = pcp.getParentPoint();
681 Vector3d v = new Vector3d();
682 v.sub(pcp.getWorldPosition(),previous.getWorldPosition());
684 } else if (isDirected()) {
685 return getDirectedControlPointDirection();
686 } else if (isEnd()) {
687 Vector3d v = new Vector3d();
688 v.sub(getWorldPosition(),previous.getWorldPosition());
690 } else if (isTurn() && isFixed() && !_getReversed()) {
691 return getDirection(Direction.NEXT);
693 throw new RuntimeException("Missing implementation");
697 if (previous != null) {
698 PipeControlPoint pcp = this;
700 pcp = getParentPoint();
701 Vector3d v = new Vector3d();
702 v.sub(previous.getWorldPosition(),pcp.getWorldPosition());
707 throw new RuntimeException("Cannot calculate path leg direction for unconnected control point");
708 Vector3d v = getDirectedControlPointDirection();
712 if (isVariableAngle())
713 throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point");
715 PipeControlPoint pcp = this;
716 if (pcp.isDualInline()) {
717 pcp = pcp.getSubPoint().get(0);
719 Vector3d v = new Vector3d();
720 v.sub(pcp.getWorldPosition(),next.getWorldPosition());
722 } else if (isDirected()) {
723 Vector3d v = getDirectedControlPointDirection();
726 } else if (isEnd()) {
727 Vector3d v = new Vector3d();
728 v.sub(getWorldPosition(),next.getWorldPosition());
730 } else if (isTurn() && isFixed() && _getReversed()) {
731 return getDirection(Direction.PREVIOUS);
733 throw new RuntimeException("Missing implementation");
739 public void getInlineControlPointEnds(Tuple3d p1, Tuple3d p2) {
742 Vector3d pos = getWorldPosition();
743 Vector3d dir = getPathLegDirection(Direction.NEXT);
745 dir.scale(length * 0.5);
752 public void getControlPointEnds(Tuple3d p1, Tuple3d p2) {
753 Vector3d pos = getWorldPosition();
754 Vector3d dir1 = getPathLegDirection(Direction.PREVIOUS);
756 Vector3d dir2 = getPathLegDirection(Direction.NEXT);
759 dir1.scale(length * 0.5);
760 dir2.scale(length * 0.5);
771 public void getInlineControlPointEnds(Tuple3d p1, Tuple3d p2, Vector3d dir) {
774 Vector3d pos = getWorldPosition();
775 dir.set(getPathLegDirection(Direction.NEXT));
777 dir.scale(length * 0.5);
784 public void getInlineControlPointEnds(Tuple3d center, Tuple3d p1, Tuple3d p2, Vector3d dir) {
787 Vector3d pos = getWorldPosition();
789 dir.set(getPathLegDirection(Direction.NEXT));
791 dir.scale(length * 0.5);
798 public double getInlineLength() {
799 if (type == PointType.TURN)
801 else if (type == PointType.INLINE)
806 public Vector3d getRealPosition(PositionType type) {
807 Vector3d pos = getWorldPosition();
810 Vector3d dir = getPathLegDirection(Direction.NEXT);
811 double length = getInlineLength();
818 Vector3d dir = getPathLegDirection(Direction.PREVIOUS);
819 double length = getInlineLength();
826 // IEntity portDir = pcp.getSingleRelatedObject(ProcessResource.plant3Dresource.HasDirection);
827 // TODO : how we calculated needed space for a port; does it has an offset from control point's position or not?
837 public void getInlineMovement(Tuple3d start, Tuple3d end) {
838 // FIXME : check type of neighbor components and allow movement on top of variable length components,
839 // find proper range for movement (pcp's position is not)
840 PipeControlPoint p = previous.getPrevious();
841 PipeControlPoint n = next.getNext();
842 start.set(p.getWorldPosition());
843 end.set(n.getWorldPosition());
846 public PipeControlPoint findNextEnd() {
847 ArrayList<PipeControlPoint> t = new ArrayList<PipeControlPoint>();
848 return findNextEnd( t);
851 public PipeControlPoint findPreviousEnd() {
852 ArrayList<PipeControlPoint> t = new ArrayList<PipeControlPoint>();
853 return findPreviousEnd(t);
856 public PipeControlPoint findNextEnd(List<PipeControlPoint> nextList) {
858 PipeControlPoint pcp = null;
859 PipeControlPoint p = null;
860 if (nextList.size() == 0)
864 p = nextList.get(nextList.size() - 1);
869 if (nextList.size() > 0)
870 nextList.remove(nextList.size() - 1);
871 // if (DEBUG) System.out.println(" " + pcp.getResource() + " not full");
875 if (pcp.isPathLegEnd()) {
876 //if (DEBUG) System.out.println(" " + pcp.getResource());
880 // if (DEBUG) System.out.print(" " + pcp.getResource());
885 public PipeControlPoint findPreviousEnd(List<PipeControlPoint> prevList) {
887 PipeControlPoint pcp = null;
888 PipeControlPoint p = null;
889 if (prevList.size() == 0)
893 p = prevList.get(prevList.size() - 1);
895 pcp = p.getPrevious();
898 if (prevList.size() > 0)
899 prevList.remove(prevList.size() - 1);
900 // if (DEBUG) System.out.println(" " + pcp.getResource() + " not full");
903 if (pcp.isPathLegEnd()) {
904 // if (DEBUG) System.out.println(" " + pcp.getResource());
908 // if (DEBUG)System.out.print(" " + pcp.getResource());
913 public void _remove() {
914 if (component == null && next == null && previous == null)
916 if (isDualInline() || isDualSub()) {
920 PipeRun pipeRun = getPipeRun();
924 PipeControlPoint additionalRemove = null;
925 if (!PipingRules.isEnabled()) {
930 PipeControlPoint currentPrev = previous;
931 PipeControlPoint currentNext = next;
932 if (currentNext == null && currentPrev == null) {
934 pipeRun.remChild(this);
937 if (currentNext != null && currentPrev != null) {
939 if (currentNext.isBranchEnd()) {
941 // currentNext.setPrevious(null);
942 // currentNext.setNext(null);
943 currentNext.remove();
947 if (currentPrev.isBranchEnd()) {
949 // currentPrev.setPrevious(null);
950 // currentPrev.setNext(null);
951 currentPrev.remove();
955 if (link && currentPrev.isDirected() && currentNext.isDirected()) {
958 if (currentNext == null) {
960 } else if (currentNext.isDualInline()) {
961 PipeControlPoint sccp = currentNext;
962 PipeControlPoint ocp = sccp.getSubPoint().get(0);
964 throw new RuntimeException("Removing PipeControlPoint " + this+ " structure damaged, no offset control point");
967 sccp.setPrevious(currentPrev);
968 ocp.setPrevious(currentPrev);
970 sccp.setPrevious(null);
971 ocp.setPrevious(null);
974 } else if (currentNext.isDualSub()) {
975 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, next control point is offset control point");
976 } else if (currentNext.previous == this) {
978 currentNext.setPrevious(currentPrev);
980 currentNext.setPrevious(null);
984 throw new RuntimeException("Removing PipeControlPoint "+ this+ " structure damaged");
986 if (currentPrev == null) {
988 } else if (currentPrev.isDualInline()) {
989 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, previous control point is size change control point");
990 } else if (currentPrev.isDualSub()) {
991 PipeControlPoint ocp = currentPrev;
992 PipeControlPoint sccp = ocp.getParentPoint();
994 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, no size change control point");
996 ocp.setNext(currentNext);
997 sccp.setNext(currentNext);
1003 } else if (currentPrev.next == this) {
1005 currentPrev.setNext(currentNext);
1007 currentPrev.setNext(null);
1011 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged");
1014 if (currentNext.isVariableLength() && currentPrev.isVariableLength()) {
1015 // we have to join them into single variable length component.
1016 additionalRemove = currentPrev;
1017 // combine lengths and set the location of remaining control point to the center.
1018 Point3d ps = new Point3d();
1019 Point3d pe = new Point3d();
1020 Point3d ns = new Point3d();
1021 Point3d ne = new Point3d();
1022 currentPrev.getInlineControlPointEnds(ps, pe);
1023 currentNext.getInlineControlPointEnds(ns, ne);
1024 double l = currentPrev.getLength() + currentNext.getLength();
1025 Vector3d cp = new Vector3d();
1028 currentNext.setLength(l);
1029 currentNext.setWorldPosition(cp);
1032 // FIXME : pipe run must be split into two parts, since the control point structure is no more continuous.
1034 } else if (next != null) {
1035 if (next.isDualInline()) {
1036 PipeControlPoint sccp = next;
1037 PipeControlPoint ocp = sccp.getSubPoint().get(0);
1039 throw new RuntimeException("Removing PipeControlPoint " + this+ " structure damaged, no offset control point");
1041 sccp.setPrevious(null);
1042 ocp.setPrevious(null);
1043 } else if (next.isDualSub()) {
1044 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, next control point is offset control point");
1045 } else if (next.previous == this) {
1046 next.setPrevious(null);
1048 throw new RuntimeException("Removing PipeControlPoint "+ this+ " structure damaged");
1051 } else { //(previous != null)
1052 if(previous.isDualInline()) {
1053 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, previous control point is size change control point");
1054 } else if (previous.isDualSub()) {
1055 PipeControlPoint ocp = previous;
1056 PipeControlPoint sccp = ocp.getParentPoint();
1058 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, no size change control point");
1062 } else if (previous.next == this) {
1063 previous.setNext(null);
1065 throw new RuntimeException("Removing PipeControlPoint "+ this+ " structure damaged");
1069 if (children.size() > 0 ) {
1071 } else if (parent!= null) {
1072 removeParentPoint();
1078 pipeRun.remChild(this);
1079 checkRemove(pipeRun);
1080 if (PipingRules.isEnabled() && pipeRun.getParent() != null && pipeRun.getControlPoints().size() > 0)
1081 PipingRules.validate(pipeRun);
1082 if (additionalRemove != null)
1083 additionalRemove.remove();
1086 public void remove() {
1087 PipeControlPoint currentPrev = previous;
1088 PipeControlPoint currentNext = next;
1091 if (currentNext != null)
1092 PipingRules.requestUpdate(currentNext);
1093 if (currentPrev != null)
1094 PipingRules.requestUpdate(currentPrev);
1095 } catch (Exception e) {
1096 e.printStackTrace();
1100 private void checkRemove(PipeRun pipeRun) {
1101 Collection<PipeControlPoint> points = pipeRun.getControlPoints();
1102 if (points.size() == 0) {
1104 } else if (points.size() == 1) {
1105 PipeControlPoint pcp = points.iterator().next();
1106 if (pcp.isDeletable())
1111 private void removeDualPoint() {
1112 if (previous != null)
1113 previous.setNext(null);
1115 next.setPrevious(null);
1116 PipeControlPoint ocp;
1117 PipeControlPoint sccp;
1118 if (isDualInline()) {
1120 ocp = getSubPoint().get(0);
1123 sccp = getParentPoint();
1125 PipeRun p1 = ocp.getPipeRun();
1126 PipeRun p2 = sccp.getPipeRun();
1128 ocp.removeComponent();
1129 sccp.removeComponent();
1134 // TODO : now we assume that this is size change, and we do
1135 if (ocp.next != null)
1136 ocp.next.setPrevious(null);
1137 if (ocp.previous != null)
1138 ocp.previous.setNext(null);
1139 if (sccp.next != null)
1140 sccp.next.setPrevious(null);
1141 if (sccp.previous != null)
1142 sccp.previous.setNext(null);
1144 ocp.setPrevious(null);
1146 sccp.setPrevious(null);
1152 private void removeSubPoints() {
1153 for (PipeControlPoint p : children) {
1154 // TODO : this may affect delete routine, since classification of the point changes.
1161 private void removeParentPoint() {
1162 throw new RuntimeException("Child points cannot be removed directly");
1165 private void removeComponent() {
1166 if (component == null)
1168 PipelineComponent next = component.getNext();
1169 PipelineComponent prev = component.getPrevious();
1170 PipelineComponent br0 = component.getBranch0();
1171 component.setNext(null);
1172 component.setPrevious(null);
1173 component.setBranch0(null);
1175 if (next.getNext() == component)
1177 else if (next.getPrevious() == component)
1178 next.setPrevious(null);
1179 else if (next.getBranch0() == component)
1180 next.setBranch0(null);
1183 if (prev.getNext() == component)
1185 else if (prev.getPrevious() == component)
1186 prev.setPrevious(null);
1187 else if (prev.getBranch0() == component)
1188 prev.setBranch0(null);
1191 if (br0.getNext() == component)
1193 else if (br0.getPrevious() == component)
1194 br0.setPrevious(null);
1195 else if (br0.getBranch0() == component)
1196 br0.setBranch0(null);
1198 PipelineComponent comp = component;
1205 public void setOrientation(Quat4d orientation) {
1206 if (MathTools.equals(orientation, getOrientation()))
1208 super.setOrientation(orientation);
1209 if (getParentPoint() == null && component != null)
1210 component._setWorldOrientation(getWorldOrientation());
1215 public void setPosition(Vector3d position) {
1216 if (MathTools.equals(position, getPosition()))
1218 if (Double.isNaN(position.x) || Double.isNaN(position.y) || Double.isNaN(position.z))
1219 throw new IllegalArgumentException("NaN is not supported");
1220 super.setPosition(position);
1221 if (getParentPoint() == null && component != null)
1222 component._setWorldPosition(getWorldPosition());
1226 private void updateSubPoint() {
1228 if (next == null && previous == null) {
1229 for (PipeControlPoint sub : getSubPoint()) {
1230 sub.setWorldPosition(getWorldPosition());
1231 sub.setWorldOrientation(getWorldOrientation());
1235 for (PipeControlPoint sub : getSubPoint()) {
1236 Vector3d wp = getWorldPosition();
1237 wp.add(getSizeChangeOffsetVector());
1238 sub.setWorldPosition(wp);
1239 sub.setWorldOrientation(getWorldOrientation());
1242 for (PipeControlPoint sub : getSubPoint()) {
1243 sub.setWorldPosition(getWorldPosition());
1244 sub.setWorldOrientation(getWorldOrientation());
1250 public void _setWorldPosition(Vector3d position) {
1251 Vector3d localPos = getLocalPosition(position);
1252 super.setPosition(localPos);
1256 public void _setWorldOrientation(Quat4d orientation) {
1257 Quat4d localOr = getLocalOrientation(orientation);
1258 super.setOrientation(localOr);
1263 public String toString() {
1264 return getClass().getName() + "@" + Integer.toHexString(hashCode());