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.Nozzle;
20 import org.simantics.plant3d.scenegraph.P3DRootNode;
21 import org.simantics.plant3d.scenegraph.PipeRun;
22 import org.simantics.plant3d.scenegraph.PipelineComponent;
24 import vtk.vtkRenderer;
27 public class PipeControlPoint extends G3DNode implements IP3DNode {
29 private static boolean DEBUG = false;
31 public enum PointType{INLINE,TURN,END};
32 public enum Direction{NEXT,PREVIOUS};
33 public enum PositionType {SPLIT,NEXT,PREVIOUS,PORT}
35 private PipelineComponent component;
37 private PointType type;
38 private boolean isFixed = true;
39 private boolean isRotate = false;
40 private boolean isReverse = false;
41 private boolean isDeletable = true;
42 private boolean isSizeChange = false;
43 private boolean isSub = false;
45 public PipeControlPoint(PipelineComponent component) {
46 this.component = component;
47 if (component.getPipeRun() != null)
48 component.getPipeRun().addChild(this);
52 public PipeControlPoint(PipelineComponent component, PipeRun piperun) {
53 this.component = component;
54 piperun.addChild(this);
58 public void update(vtkRenderer ren) {
60 PipingRules.requestUpdate(this);
61 } catch (Exception e) {
67 public PipeRun getPipeRun() {
68 return (PipeRun)getParent();
71 public PipelineComponent getPipelineComponent() {
75 public PointType getType() {
79 public void setType(PointType type) {
83 @GetPropertyValue(name="Fixed",tabId="Debug",value="fixed")
84 public boolean isFixed() {
89 public void setFixed(boolean fixed) {
93 @GetPropertyValue(name="Rotate",tabId="Debug",value="rotate")
94 public boolean isRotate() {
98 public void setRotate(boolean rotate) {
99 this.isRotate = rotate;
102 @GetPropertyValue(name="Reverse",tabId="Debug",value="reverse")
103 public boolean isReverse() {
107 public void setReverse(boolean reverse) {
108 this.isReverse = reverse;
111 public void setSub(boolean sub) {
115 @GetPropertyValue(name="Deletable",tabId="Debug",value="deletable")
116 public boolean isDeletable() {
120 public void setDeletable(boolean deletable) {
121 this.isDeletable = deletable;
124 public boolean isPathLegEnd() {
125 return type != PointType.INLINE;
128 public boolean isEnd() {
129 return type == PointType.END;
132 public boolean isTurn() {
133 return type == PointType.TURN;
136 public boolean isInline() {
137 return type == PointType.INLINE;
140 public boolean isDirected() {
141 return isFixed && isEnd();
144 public boolean isNonDirected() {
145 return !isFixed && isEnd();
148 public boolean isVariableLength() {
149 return !isFixed && isInline();
152 public boolean isVariableAngle() {
153 return !isFixed && isTurn();
156 public boolean isBranchEnd() {
157 return isDeletable && isEnd();
160 public boolean isOffset() {
161 return offset != null;
164 public boolean isDualSub() {
165 return parent != null && isSub;
168 public boolean isDualInline() {
169 return children.size() == 1 && children.get(0).isDualSub();
172 public boolean isAxial() {
173 return isInline() && !isDualInline();
176 public boolean isSizeChange() {
178 // if (children.size() == 0)
180 // if (!isDualInline())
182 // return getPipeRun() != children.get(0).getPipeRun();
185 public void setSizeChange(boolean isSizeChange) {
186 this.isSizeChange = isSizeChange;
190 private PipeControlPoint next;
191 private PipeControlPoint previous;
193 public PipeControlPoint getNext() {
197 public PipeControlPoint getPrevious() {
201 public void setNext(PipeControlPoint next) {
202 if (isEnd() && previous != null && next != null)
203 throw new RuntimeException("End control points are allowed to have only one connection");
205 throw new RuntimeException("Cannot connect to self");
206 if (this.next == next)
208 if (DEBUG) System.out.println(this + " next " + next);
210 if (component != null) {
211 if (parent == null || isSub)
212 component.setNext(next != null ? next.component : null);
214 component.setBranch0(next != null ? next.component : null);
220 public void setPrevious(PipeControlPoint previous) {
221 if (isEnd() && next != null && previous != null)
222 throw new RuntimeException("End control points are allowed to have only one connection");
223 if (previous == this)
224 throw new RuntimeException("Cannot connect to self");
225 if (this.previous == previous)
227 if (DEBUG) System.out.println(this + " previous " + previous);
228 this.previous = previous;
229 if (component != null) {
230 if (parent == null || isSub)
231 component.setPrevious(previous != null ? previous.component : null);
233 component.setBranch0(previous != null ? previous.component : null);
239 public PipeControlPoint parent;
240 public List<PipeControlPoint> children = new ArrayList<PipeControlPoint>();
242 public List<PipeControlPoint> getSubPoint() {
246 public PipeControlPoint getParentPoint() {
251 private double length;
252 private Double turnAngle;
253 private Vector3d turnAxis;
255 private Double offset;
256 private Double rotationAngle;
257 private Boolean reversed;
259 @GetPropertyValue(name="Length",tabId="Debug",value="length")
260 public double getLength() {
264 public void setLength(double l) {
265 if (Double.isInfinite(l) || Double.isNaN(l)) {
268 if (Math.abs(this.length-l) < MathTools.NEAR_ZERO)
271 firePropertyChanged("length");
273 getSubPoint().get(0).setLength(l);
276 @GetPropertyValue(name="Turn Angle",tabId="Debug",value="turnAngle")
277 public Double getTurnAngle() {
281 @GetPropertyValue(name="Turn Axis",tabId="Debug",value="turnAxis")
282 public Vector3d getTurnAxis() {
286 @GetPropertyValue(name="Offset",tabId="Debug",value="offset")
287 public Double getOffset() {
291 @GetPropertyValue(name="Rotation Angle",tabId="Debug",value="rotationAngle")
292 public Double getRotationAngle() {
293 return rotationAngle;
296 @GetPropertyValue(name="Reversed",tabId="Debug",value="reversed")
297 public Boolean getReversed() {
301 public boolean _getReversed() {
302 if (reversed == null)
307 public void setTurnAngle(Double turnAngle) {
308 if (turnAngle == null || Double.isInfinite(turnAngle) || Double.isNaN(turnAngle)) {
311 if (this.turnAngle != null && Math.abs(this.turnAngle-turnAngle) < MathTools.NEAR_ZERO)
313 this.turnAngle = turnAngle;
314 firePropertyChanged("turnAngle");
317 public void setTurnAxis(Vector3d turnAxis) {
318 if (this.turnAxis != null && MathTools.equals(turnAxis, this.turnAxis))
320 this.turnAxis = turnAxis;
321 firePropertyChanged("turnAxis");
324 public void setOffset(Double offset) {
325 if (Double.isInfinite(offset) || Double.isNaN(offset)) {
328 if (this.offset != null && Math.abs(this.offset-offset) < MathTools.NEAR_ZERO)
330 this.offset = offset;
331 firePropertyChanged("offset");
334 public void setRotationAngle(Double rotationAngle) {
335 if (Double.isInfinite(rotationAngle) || Double.isNaN(rotationAngle)) {
338 if (this.rotationAngle != null && Math.abs(this.rotationAngle-rotationAngle) < MathTools.NEAR_ZERO)
340 this.rotationAngle = rotationAngle;
341 firePropertyChanged("rotationAngle");
344 public void setReversed(Boolean reversed) {
345 this.reversed = reversed;
346 firePropertyChanged("reversed");
349 public Vector3d getSizeChangeOffsetVector(Vector3d dir) {
351 if (rotationAngle == null)
352 q = getControlPointOrientationQuat(dir, 0.0);
354 q = getControlPointOrientationQuat(dir, rotationAngle);
355 Vector3d v = new Vector3d(0.0,offset,0.0);
356 Vector3d offset = new Vector3d();
357 MathTools.rotate(q, v, offset);
361 public Vector3d getSizeChangeOffsetVector() {
363 if (rotationAngle == null)
364 q = getControlPointOrientationQuat(0.0);
366 q = getControlPointOrientationQuat(rotationAngle);
367 Vector3d v = new Vector3d(0.0,offset,0.0);
368 Vector3d offset = new Vector3d();
369 MathTools.rotate(q, v, offset);
373 @GetPropertyValue(name="Next",tabId="Debug",value="next")
374 private String getNextString() {
377 return next.toString();
380 @GetPropertyValue(name="Previous",tabId="Debug",value="previous")
381 private String getPrevString() {
382 if (previous == null)
384 return previous.toString();
387 @GetPropertyValue(name="Sub",tabId="Debug",value="sub")
388 private String getSubString() {
389 if (children.size() == 0)
391 return Arrays.toString(children.toArray());
394 @GetPropertyValue(name="Type",tabId="Debug",value="type")
395 public String getTypeString() {
399 public Quat4d getControlPointOrientationQuat(double angle) {
401 if (turnAxis == null) {
402 Vector3d dir = getPathLegDirection(Direction.NEXT);
403 if (dir.lengthSquared() > MathTools.NEAR_ZERO)
405 return getControlPointOrientationQuat(dir, angle);
407 Vector3d dir = getPathLegDirection(Direction.PREVIOUS);
409 if (dir.lengthSquared() > MathTools.NEAR_ZERO)
411 return getControlPointOrientationQuat(dir, turnAxis, angle);
415 public Quat4d getControlPointOrientationQuat(double angle, boolean reversed) {
417 if (turnAxis == null) {
418 Vector3d dir = getPathLegDirection(Direction.NEXT);
419 if (dir.lengthSquared() > MathTools.NEAR_ZERO)
421 Quat4d q = getControlPointOrientationQuat(dir, angle);
423 Quat4d q2 = new Quat4d();
424 q2.set(new AxisAngle4d(MathTools.Y_AXIS, Math.PI));
429 Vector3d dir = getPathLegDirection(Direction.PREVIOUS);
431 if (dir.lengthSquared() > MathTools.NEAR_ZERO)
433 return getControlPointOrientationQuat(dir, turnAxis, angle);
439 public static Quat4d getControlPointOrientationQuat(Vector3d dir, double angle) {
440 if (dir.lengthSquared() < MathTools.NEAR_ZERO)
441 return MathTools.getIdentityQuat();
444 Vector3d up = new Vector3d(0.0, 1.0, 0.0);
445 double a = up.angle(dir);
446 if (a < 0.1 || (Math.PI - a) < 0.1) {
447 up.set(1.0, 0.0, 0.0);
451 return getControlPointOrientationQuat(dir, up, angle);
454 public static Quat4d getControlPointOrientationQuat(Vector3d dir, Vector3d up, double angle) {
455 if (dir.lengthSquared() < MathTools.NEAR_ZERO)
456 return MathTools.getIdentityQuat();
458 final Vector3d front = new Vector3d(1.0,0.0,0.0);
460 Quat4d q1 = new Quat4d();
463 Vector3d right = new Vector3d();
465 right.cross(dir, up);
466 up.cross(right, dir);
470 Matrix3d m = new Matrix3d();
481 //q1.set(m); MathTools contains more stable conversion
482 MathTools.getQuat(m, q1);
484 // if (DEBUG) System.out.println("PipingTools.getPipeComponentOrientationQuat() " + dir+ " " + up + " " + right);
486 Quat4d q2 = new Quat4d();
487 q2.set(new AxisAngle4d(front, angle));
492 public void insert(PipeControlPoint previous, PipeControlPoint next) {
493 // inserting an offsetpoint is error,
495 throw new RuntimeException("Dual sub points cannot be inserted.");
496 // size change control point cannot be inserted this way, because it ends PipeRun
498 throw new RuntimeException("Size change points cannot be inserted.");
499 PipeRun piperun = previous.getPipeRun();
500 // and just to make sure that control point structure is not corrupted
501 if (getPipeRun() != null) {
502 if (piperun != getPipeRun() || piperun != next.getPipeRun())
503 throw new RuntimeException("All controls points must be located on the same pipe run");
505 piperun.addChild(this);
508 // insert new BranchControlPoint between straight's control points
509 PipeControlPoint previousNext = previous.getNext();
510 PipeControlPoint previousPrevious = previous.getPrevious();
512 PipeControlPoint offsetCP = null;
514 offsetCP = getSubPoint().get(0);
516 if (previousNext != null && previousNext == next) {
517 if (previous.isDualInline()) {
518 throw new RuntimeException();
520 if (next.isDualSub()) {
521 throw new RuntimeException();
523 previous.setNext(this);
524 this.setPrevious(previous);
525 if (previous.isDualSub()) {
526 previous.getParentPoint().setNext(this);
530 if (offsetCP == null) {
531 next.setPrevious(this);
533 next.setPrevious(offsetCP);
534 offsetCP.setNext(next);
535 offsetCP.setPrevious(previous);
538 if (next.isDualInline()) {
539 next.getSubPoint().get(0).setPrevious(this);
541 } else if (previousPrevious != null && previousPrevious == next) {
542 // control point were given in reverse order
543 if (next.isDualInline())
544 throw new RuntimeException();
545 if (previous.isDualSub())
546 throw new RuntimeException();
548 this.setNext(previous);
549 if (offsetCP == null) {
550 previous.setNext(this);
552 previous.setPrevious(offsetCP);
553 offsetCP.setNext(previous);
554 offsetCP.setPrevious(next);
556 if (previous.isDualInline()) {
557 previous.getSubPoint().get(0).setPrevious(this);
559 this.setPrevious(next);
561 if (next.isDualSub()) {
562 next.getParentPoint().setNext(this);
566 throw new RuntimeException();
569 PipingRules.validate(piperun);
574 public void insert(PipeControlPoint pcp, Direction direction) {
576 throw new RuntimeException();
577 if (direction == Direction.NEXT) {
578 // if direction is next, user must have given OffsetPoint
579 if (pcp.isDualInline())
580 throw new RuntimeException();
581 // basic next/prev links
583 this.setPrevious(pcp);
584 // and last take care of sizechange / offset points
585 if (pcp.isDualSub()) {
586 pcp.getParentPoint().setNext(this);
588 if (isDualInline()) {
589 getSubPoint().get(0).setPrevious(this);
592 // if direction is previous, user must have given sizechange
594 throw new RuntimeException();
595 // previous direction is more complicated, since if newCP is SizeChangeControlPoint,
596 // we must link pcp to newCP's OffsetPoint
597 PipeControlPoint nocp = null;
598 if (isDualInline()) {
599 nocp = getSubPoint().get(0);
603 pcp.setPrevious(this);
605 pcp.setPrevious(nocp);
608 if (pcp.isDualInline()) {
609 PipeControlPoint ocp = pcp.getSubPoint().get(0);
611 ocp.setPrevious(this);
613 ocp.setPrevious(nocp);
617 PipingRules.validate(getPipeRun());
620 public Vector3d getDirectedControlPointDirection() {
621 assert (isDirected());
622 Vector3d dir = new Vector3d();
623 MathTools.rotate(getWorldOrientation(), new Vector3d(1.0, 0.0, 0.0), dir);
628 public Vector3d getDirection(Direction direction) {
630 return getDirectedControlPointDirection();
631 if (isTurn() && isFixed()) {
632 if (direction == Direction.NEXT) {
633 if (previous != null) {
634 PipeControlPoint pcp = this;
635 Vector3d dir = new Vector3d();
636 dir.sub(pcp.getWorldPosition(),previous.getWorldPosition());
637 if (dir.lengthSquared() > MathTools.NEAR_ZERO)
641 Quat4d q = getControlPointOrientationQuat(dir, pcp.getRotationAngle() != null ? pcp.getRotationAngle() : 0.0);
642 AxisAngle4d aa = new AxisAngle4d(MathTools.Y_AXIS,pcp.getTurnAngle() == null ? 0.0 : pcp.getTurnAngle());
643 Quat4d q2 = MathTools.getQuat(aa);
644 Vector3d v = new Vector3d(1.,0.,0.);
645 Vector3d offset = new Vector3d();
646 MathTools.rotate(q2, v, offset);
647 MathTools.rotate(q, offset, dir);
652 PipeControlPoint pcp = this;
653 Vector3d dir = new Vector3d();
654 dir.sub(next.getWorldPosition(),pcp.getWorldPosition());
655 if (dir.lengthSquared() > MathTools.NEAR_ZERO)
659 Quat4d q = getControlPointOrientationQuat(dir, pcp.getRotationAngle() != null ? pcp.getRotationAngle() : 0.0);
660 AxisAngle4d aa = new AxisAngle4d(MathTools.Y_AXIS,pcp.getTurnAngle() == null ? 0.0 : pcp.getTurnAngle());
661 Quat4d q2 = MathTools.getQuat(aa);
662 Vector3d v = new Vector3d(1.,0.,0.);
663 Vector3d offset = new Vector3d();
664 MathTools.rotate(q2, v, offset);
665 MathTools.rotate(q, offset, dir);
673 public Vector3d getPathLegDirection(Direction direction) {
674 if (direction == Direction.NEXT) {
676 PipeControlPoint pcp = this;
677 if (pcp.isDualInline()) {
678 pcp = pcp.getSubPoint().get(0);
680 Vector3d v = new Vector3d();
681 v.sub(next.getWorldPosition(),pcp.getWorldPosition());
684 if (previous == null) {
686 throw new RuntimeException("Cannot calculate path leg direction for unconnected control point " + this);
687 return getDirectedControlPointDirection();
690 if (isVariableAngle())
691 throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point " + this);
693 PipeControlPoint pcp = this;
694 if (pcp.isDualSub()) {
695 pcp = pcp.getParentPoint();
697 Vector3d v = new Vector3d();
698 v.sub(pcp.getWorldPosition(),previous.getWorldPosition());
700 } else if (isDirected()) {
701 return getDirectedControlPointDirection();
702 } else if (isEnd()) {
703 Vector3d v = new Vector3d();
704 v.sub(getWorldPosition(),previous.getWorldPosition());
706 } else if (isTurn() && isFixed() && !_getReversed()) {
707 return getDirection(Direction.NEXT);
709 throw new RuntimeException("Missing implementation " + this);
713 if (previous != null) {
714 PipeControlPoint pcp = this;
716 pcp = getParentPoint();
717 Vector3d v = new Vector3d();
718 v.sub(previous.getWorldPosition(),pcp.getWorldPosition());
723 throw new RuntimeException("Cannot calculate path leg direction for unconnected control point " + this);
724 Vector3d v = getDirectedControlPointDirection();
728 if (isVariableAngle())
729 throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point " + this);
731 PipeControlPoint pcp = this;
732 if (pcp.isDualInline()) {
733 pcp = pcp.getSubPoint().get(0);
735 Vector3d v = new Vector3d();
736 v.sub(pcp.getWorldPosition(),next.getWorldPosition());
738 } else if (isDirected()) {
739 Vector3d v = getDirectedControlPointDirection();
742 } else if (isEnd()) {
743 Vector3d v = new Vector3d();
744 v.sub(getWorldPosition(),next.getWorldPosition());
746 } else if (isTurn() && isFixed() && _getReversed()) {
747 return getDirection(Direction.PREVIOUS);
749 throw new RuntimeException("Missing implementation " + this);
755 public void getInlineControlPointEnds(Tuple3d p1, Tuple3d p2) {
758 PipeControlPoint sub = isAxial() ? this : getSubPoint().get(0);
759 Vector3d pos = getWorldPosition(), pos2 = sub == this ? pos : sub.getWorldPosition();
760 Vector3d dir = sub.getPathLegDirection(Direction.NEXT);
763 dir.scale(length * 0.5);
770 public void getControlPointEnds(Tuple3d p1, Tuple3d p2) {
771 PipeControlPoint sub = isAxial() || isDirected() || isTurn() ? this : getSubPoint().get(0);
772 Vector3d pos = getWorldPosition(), pos2 = sub == this ? pos : sub.getWorldPosition();
774 Vector3d dir1 = getPathLegDirection(Direction.PREVIOUS);
776 Vector3d dir2 = sub.getPathLegDirection(Direction.NEXT);
779 dir1.scale(length * 0.5);
780 dir2.scale(length * 0.5);
791 public void getEndDirections(Tuple3d v1, Tuple3d v2) {
792 PipeControlPoint sub = isAxial() ? this : getSubPoint().get(0);
794 Vector3d dir1 = getPathLegDirection(Direction.PREVIOUS);
796 Vector3d dir2 = sub.getPathLegDirection(Direction.NEXT);
802 public void getInlineControlPointEnds(Tuple3d p1, Tuple3d p2, Vector3d dir) {
805 Vector3d pos = getWorldPosition();
806 dir.set(getPathLegDirection(Direction.NEXT));
808 dir.scale(length * 0.5);
815 public void getInlineControlPointEnds(Tuple3d center, Tuple3d p1, Tuple3d p2, Vector3d dir) {
818 Vector3d pos = getWorldPosition();
820 dir.set(getPathLegDirection(Direction.NEXT));
822 dir.scale(length * 0.5);
829 public double getInlineLength() {
830 if (type == PointType.TURN)
832 else if (type == PointType.INLINE)
837 public Vector3d getRealPosition(PositionType type) {
838 Vector3d pos = getWorldPosition();
841 Vector3d dir = getPathLegDirection(Direction.NEXT);
842 double length = getInlineLength();
849 Vector3d dir = getPathLegDirection(Direction.PREVIOUS);
850 double length = getInlineLength();
857 // IEntity portDir = pcp.getSingleRelatedObject(ProcessResource.plant3Dresource.HasDirection);
858 // TODO : how we calculated needed space for a port; does it has an offset from control point's position or not?
868 public void getInlineMovement(Tuple3d start, Tuple3d end) {
869 // FIXME : check type of neighbor components and allow movement on top of variable length components,
870 // find proper range for movement (pcp's position is not)
871 PipeControlPoint p = previous.getPrevious();
872 PipeControlPoint n = next.getNext();
873 start.set(p.getWorldPosition());
874 end.set(n.getWorldPosition());
877 public PipeControlPoint findNextEnd() {
878 ArrayList<PipeControlPoint> t = new ArrayList<PipeControlPoint>();
879 return findNextEnd( t);
882 public PipeControlPoint findPreviousEnd() {
883 ArrayList<PipeControlPoint> t = new ArrayList<PipeControlPoint>();
884 return findPreviousEnd(t);
887 public PipeControlPoint findNextEnd(List<PipeControlPoint> nextList) {
889 PipeControlPoint pcp = null;
890 PipeControlPoint p = null;
891 if (nextList.size() == 0)
895 p = nextList.get(nextList.size() - 1);
900 if (nextList.size() > 0)
901 nextList.remove(nextList.size() - 1);
902 // if (DEBUG) System.out.println(" " + pcp.getResource() + " not full");
906 if (pcp.isPathLegEnd()) {
907 //if (DEBUG) System.out.println(" " + pcp.getResource());
911 // if (DEBUG) System.out.print(" " + pcp.getResource());
916 public PipeControlPoint findPreviousEnd(List<PipeControlPoint> prevList) {
918 PipeControlPoint pcp = null;
919 PipeControlPoint p = null;
920 if (prevList.size() == 0)
924 p = prevList.get(prevList.size() - 1);
926 pcp = p.getPrevious();
929 if (prevList.size() > 0)
930 prevList.remove(prevList.size() - 1);
931 // if (DEBUG) System.out.println(" " + pcp.getResource() + " not full");
934 if (pcp.isPathLegEnd()) {
935 // if (DEBUG) System.out.println(" " + pcp.getResource());
939 // if (DEBUG)System.out.print(" " + pcp.getResource());
944 public void _remove() {
948 public void _remove(boolean renconnect) {
949 if (component == null && next == null && previous == null)
951 if (DEBUG) System.out.println(this + " Remove " + renconnect);
952 if (isDualInline() || isDualSub()) {
956 if (getParentPoint() != null) {
957 getParentPoint()._remove(renconnect);
959 PipeRun pipeRun = getPipeRun();
963 PipeControlPoint additionalRemove = null;
964 if (!PipingRules.isEnabled()) {
969 PipeControlPoint currentPrev = previous;
970 PipeControlPoint currentNext = next;
971 if (currentNext == null && currentPrev == null) {
973 pipeRun.remChild(this);
976 if (currentNext != null && currentPrev != null) {
977 boolean link = renconnect;
978 if (currentNext.isBranchEnd()) {
980 // currentNext.setPrevious(null);
981 // currentNext.setNext(null);
982 currentNext.remove();
986 if (currentPrev.isBranchEnd()) {
988 // currentPrev.setPrevious(null);
989 // currentPrev.setNext(null);
990 currentPrev.remove();
994 if (link && currentPrev.isDirected() && currentNext.isDirected()) {
997 if (currentNext == null) {
999 } else if (currentNext.isDualInline()) {
1000 PipeControlPoint sccp = currentNext;
1001 PipeControlPoint ocp = sccp.getSubPoint().get(0);
1003 throw new RuntimeException("Removing PipeControlPoint " + this+ " structure damaged, no offset control point");
1006 sccp.setPrevious(currentPrev);
1007 ocp.setPrevious(currentPrev);
1009 sccp.setPrevious(null);
1010 ocp.setPrevious(null);
1013 } else if (currentNext.isDualSub()) {
1014 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, next control point is offset control point");
1015 } else if (currentNext.previous == this) {
1017 currentNext.setPrevious(currentPrev);
1019 currentNext.setPrevious(null);
1023 throw new RuntimeException("Removing PipeControlPoint "+ this+ " structure damaged");
1025 if (currentPrev == null) {
1027 } else if (currentPrev.isDualInline()) {
1028 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, previous control point is size change control point");
1029 } else if (currentPrev.isDualSub()) {
1030 PipeControlPoint ocp = currentPrev;
1031 PipeControlPoint sccp = ocp.getParentPoint();
1033 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, no size change control point");
1035 ocp.setNext(currentNext);
1036 sccp.setNext(currentNext);
1042 } else if (currentPrev.next == this) {
1044 currentPrev.setNext(currentNext);
1046 currentPrev.setNext(null);
1050 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged");
1053 if (currentNext.isVariableLength() && currentPrev.isVariableLength()) {
1054 // we have to join them into single variable length component.
1055 additionalRemove = currentPrev;
1056 // combine lengths and set the location of remaining control point to the center.
1057 Point3d ps = new Point3d();
1058 Point3d pe = new Point3d();
1059 Point3d ns = new Point3d();
1060 Point3d ne = new Point3d();
1061 currentPrev.getInlineControlPointEnds(ps, pe);
1062 currentNext.getInlineControlPointEnds(ns, ne);
1063 double l = currentPrev.getLength() + currentNext.getLength();
1064 Vector3d cp = new Vector3d();
1067 currentNext.setLength(l);
1068 currentNext.setWorldPosition(cp);
1071 // FIXME : pipe run must be split into two parts, since the control point structure is no more continuous.
1073 } else if (next != null) {
1074 if (next.isDualInline()) {
1075 PipeControlPoint sccp = next;
1076 PipeControlPoint ocp = sccp.getSubPoint().get(0);
1078 throw new RuntimeException("Removing PipeControlPoint " + this+ " structure damaged, no offset control point");
1080 sccp.setPrevious(null);
1081 ocp.setPrevious(null);
1082 } else if (next.isDualSub()) {
1083 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, next control point is offset control point");
1084 } else if (next.previous == this) {
1085 next.setPrevious(null);
1087 throw new RuntimeException("Removing PipeControlPoint "+ this+ " structure damaged");
1090 } else { //(previous != null)
1091 if(previous.isDualInline()) {
1092 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, previous control point is size change control point");
1093 } else if (previous.isDualSub()) {
1094 PipeControlPoint ocp = previous;
1095 PipeControlPoint sccp = ocp.getParentPoint();
1097 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, no size change control point");
1101 } else if (previous.next == this) {
1102 previous.setNext(null);
1104 throw new RuntimeException("Removing PipeControlPoint "+ this+ " structure damaged");
1108 if (children.size() > 0 ) {
1110 } else if (parent!= null) {
1111 removeParentPoint();
1117 pipeRun.remChild(this);
1118 checkRemove(pipeRun);
1119 if (PipingRules.isEnabled() && pipeRun.getParent() != null && pipeRun.getControlPoints().size() > 0)
1120 PipingRules.validate(pipeRun);
1121 if (additionalRemove != null)
1122 additionalRemove.remove();
1126 * Removes control point and attempts to reconnect next/prev
1128 * If this point is size change (PipeRuns are different on both sides), then reconnection cannot be made.
1130 public void remove() {
1131 PipeControlPoint currentPrev = previous;
1132 PipeControlPoint currentNext = next;
1135 if (currentNext != null)
1136 if (!currentNext.checkRemove())
1137 PipingRules.requestUpdate(currentNext);
1138 if (currentPrev != null)
1139 if (!currentPrev.checkRemove())
1140 PipingRules.requestUpdate(currentPrev);
1141 } catch (Exception e) {
1142 e.printStackTrace();
1148 * Removes control point without attempting to reconnect next/prev.
1149 * This usually leads to creation of another PipeRun for the control points after this point.
1151 public void removeAndSplit() {
1152 PipeControlPoint currentPrev = previous;
1153 PipeControlPoint currentNext = next;
1155 if (next != null && previous != null) {
1156 P3DRootNode root = (P3DRootNode)getPipelineComponent().getRootNode();
1157 PipeRun nextPipeRun = new PipeRun();
1158 nextPipeRun.setName(root.getUniqueName("PipeRun"));
1159 root.addChild(nextPipeRun);
1161 PipeRun previousRun = previous.getPipeRun();
1162 nextPipeRun.setPipeDiameter(previousRun.getPipeDiameter());
1163 nextPipeRun.setTurnRadius(previousRun.getTurnRadius());
1165 PipelineComponent n = next.getPipelineComponent();
1167 if (! (n instanceof Nozzle)) {
1169 nextPipeRun.addChild(n);
1171 n.setPipeRun(nextPipeRun);
1177 if (currentNext != null)
1178 if (!currentNext.checkRemove())
1179 PipingRules.requestUpdate(currentNext);
1180 if (currentPrev != null)
1181 if (!currentPrev.checkRemove())
1182 PipingRules.requestUpdate(currentPrev);
1183 } catch (Exception e) {
1184 e.printStackTrace();
1189 * This is called when adjacent control point is removed.
1191 * This call should remove the give point, if the point cannot exist alone.
1192 * At the moment there is one such case: branch.
1196 protected boolean checkRemove() {
1197 if (getParentPoint() != null) {
1198 return getParentPoint().checkRemove();
1200 if (getPipelineComponent() == null)
1201 return true; // already removed
1202 if (getPipelineComponent().getType().equals("Plant3D.URIs.Builtin_BranchSplitComponent")) {
1203 if (getSubPoint().get(0).getNext() == null && getSubPoint().get(0).getPrevious() == null) {
1212 private void checkRemove(PipeRun pipeRun) {
1213 Collection<PipeControlPoint> points = pipeRun.getControlPoints();
1214 if (points.size() == 0) {
1216 } else if (points.size() == 1) {
1217 PipeControlPoint pcp = points.iterator().next();
1218 if (pcp.isDeletable())
1223 private void removeDualPoint() {
1224 if (previous != null)
1225 previous.setNext(null);
1227 next.setPrevious(null);
1228 PipeControlPoint ocp;
1229 PipeControlPoint sccp;
1230 if (isDualInline()) {
1232 ocp = getSubPoint().get(0);
1235 sccp = getParentPoint();
1237 PipeRun p1 = ocp.getPipeRun();
1238 PipeRun p2 = sccp.getPipeRun();
1240 ocp.removeComponent();
1241 sccp.removeComponent();
1248 // TODO : now we assume that this is size change, and we do
1249 if (ocp.next != null)
1250 ocp.next.setPrevious(null);
1251 if (ocp.previous != null)
1252 ocp.previous.setNext(null);
1253 if (sccp.next != null)
1254 sccp.next.setPrevious(null);
1255 if (sccp.previous != null)
1256 sccp.previous.setNext(null);
1258 ocp.setPrevious(null);
1260 sccp.setPrevious(null);
1268 private void removeSubPoints() {
1269 for (PipeControlPoint p : children) {
1270 // TODO : this may affect delete routine, since classification of the point changes.
1277 private void removeParentPoint() {
1278 throw new RuntimeException("Child points cannot be removed directly");
1281 private void removeComponent() {
1282 if (component == null)
1284 PipelineComponent next = component.getNext();
1285 PipelineComponent prev = component.getPrevious();
1286 PipelineComponent br0 = component.getBranch0();
1287 component.setNext(null);
1288 component.setPrevious(null);
1289 component.setBranch0(null);
1291 if (next.getNext() == component)
1293 else if (next.getPrevious() == component)
1294 next.setPrevious(null);
1295 else if (next.getBranch0() == component)
1296 next.setBranch0(null);
1299 if (prev.getNext() == component)
1301 else if (prev.getPrevious() == component)
1302 prev.setPrevious(null);
1303 else if (prev.getBranch0() == component)
1304 prev.setBranch0(null);
1307 if (br0.getNext() == component)
1309 else if (br0.getPrevious() == component)
1310 br0.setPrevious(null);
1311 else if (br0.getBranch0() == component)
1312 br0.setBranch0(null);
1314 PipelineComponent comp = component;
1321 public void setOrientation(Quat4d orientation) {
1322 if (MathTools.equals(orientation, getOrientation()))
1324 super.setOrientation(orientation);
1325 if (getParentPoint() == null && component != null)
1326 component._setWorldOrientation(getWorldOrientation());
1331 public void setPosition(Vector3d position) {
1332 if (MathTools.equals(position, getPosition()))
1334 if (Double.isNaN(position.x) || Double.isNaN(position.y) || Double.isNaN(position.z))
1335 throw new IllegalArgumentException("NaN is not supported");
1336 super.setPosition(position);
1337 if (getParentPoint() == null && component != null)
1338 component._setWorldPosition(getWorldPosition());
1342 private void updateSubPoint() {
1344 if (next == null && previous == null) {
1345 for (PipeControlPoint sub : getSubPoint()) {
1346 sub.setWorldPosition(getWorldPosition());
1347 sub.setWorldOrientation(getWorldOrientation());
1351 for (PipeControlPoint sub : getSubPoint()) {
1352 Vector3d wp = getWorldPosition();
1353 wp.add(getSizeChangeOffsetVector());
1354 sub.setWorldPosition(wp);
1355 sub.setWorldOrientation(getWorldOrientation());
1358 for (PipeControlPoint sub : getSubPoint()) {
1359 sub.setWorldPosition(getWorldPosition());
1360 sub.setWorldOrientation(getWorldOrientation());
1366 public void _setWorldPosition(Vector3d position) {
1367 Vector3d localPos = getLocalPosition(position);
1368 super.setPosition(localPos);
1372 public void _setWorldOrientation(Quat4d orientation) {
1373 Quat4d localOr = getLocalOrientation(orientation);
1374 super.setOrientation(localOr);
1379 public String toString() {
1380 return getClass().getName() + "@" + Integer.toHexString(hashCode());