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");
687 return getDirectedControlPointDirection();
690 if (isVariableAngle())
691 throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point");
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");
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");
724 Vector3d v = getDirectedControlPointDirection();
728 if (isVariableAngle())
729 throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point");
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");
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() ? 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 (isDualInline() || isDualSub()) {
955 PipeRun pipeRun = getPipeRun();
959 PipeControlPoint additionalRemove = null;
960 if (!PipingRules.isEnabled()) {
965 PipeControlPoint currentPrev = previous;
966 PipeControlPoint currentNext = next;
967 if (currentNext == null && currentPrev == null) {
969 pipeRun.remChild(this);
972 if (currentNext != null && currentPrev != null) {
973 boolean link = renconnect;
974 if (currentNext.isBranchEnd()) {
976 // currentNext.setPrevious(null);
977 // currentNext.setNext(null);
978 currentNext.remove();
982 if (currentPrev.isBranchEnd()) {
984 // currentPrev.setPrevious(null);
985 // currentPrev.setNext(null);
986 currentPrev.remove();
990 if (link && currentPrev.isDirected() && currentNext.isDirected()) {
993 if (currentNext == null) {
995 } else if (currentNext.isDualInline()) {
996 PipeControlPoint sccp = currentNext;
997 PipeControlPoint ocp = sccp.getSubPoint().get(0);
999 throw new RuntimeException("Removing PipeControlPoint " + this+ " structure damaged, no offset control point");
1002 sccp.setPrevious(currentPrev);
1003 ocp.setPrevious(currentPrev);
1005 sccp.setPrevious(null);
1006 ocp.setPrevious(null);
1009 } else if (currentNext.isDualSub()) {
1010 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, next control point is offset control point");
1011 } else if (currentNext.previous == this) {
1013 currentNext.setPrevious(currentPrev);
1015 currentNext.setPrevious(null);
1019 throw new RuntimeException("Removing PipeControlPoint "+ this+ " structure damaged");
1021 if (currentPrev == null) {
1023 } else if (currentPrev.isDualInline()) {
1024 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, previous control point is size change control point");
1025 } else if (currentPrev.isDualSub()) {
1026 PipeControlPoint ocp = currentPrev;
1027 PipeControlPoint sccp = ocp.getParentPoint();
1029 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, no size change control point");
1031 ocp.setNext(currentNext);
1032 sccp.setNext(currentNext);
1038 } else if (currentPrev.next == this) {
1040 currentPrev.setNext(currentNext);
1042 currentPrev.setNext(null);
1046 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged");
1049 if (currentNext.isVariableLength() && currentPrev.isVariableLength()) {
1050 // we have to join them into single variable length component.
1051 additionalRemove = currentPrev;
1052 // combine lengths and set the location of remaining control point to the center.
1053 Point3d ps = new Point3d();
1054 Point3d pe = new Point3d();
1055 Point3d ns = new Point3d();
1056 Point3d ne = new Point3d();
1057 currentPrev.getInlineControlPointEnds(ps, pe);
1058 currentNext.getInlineControlPointEnds(ns, ne);
1059 double l = currentPrev.getLength() + currentNext.getLength();
1060 Vector3d cp = new Vector3d();
1063 currentNext.setLength(l);
1064 currentNext.setWorldPosition(cp);
1067 // FIXME : pipe run must be split into two parts, since the control point structure is no more continuous.
1069 } else if (next != null) {
1070 if (next.isDualInline()) {
1071 PipeControlPoint sccp = next;
1072 PipeControlPoint ocp = sccp.getSubPoint().get(0);
1074 throw new RuntimeException("Removing PipeControlPoint " + this+ " structure damaged, no offset control point");
1076 sccp.setPrevious(null);
1077 ocp.setPrevious(null);
1078 } else if (next.isDualSub()) {
1079 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, next control point is offset control point");
1080 } else if (next.previous == this) {
1081 next.setPrevious(null);
1083 throw new RuntimeException("Removing PipeControlPoint "+ this+ " structure damaged");
1086 } else { //(previous != null)
1087 if(previous.isDualInline()) {
1088 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, previous control point is size change control point");
1089 } else if (previous.isDualSub()) {
1090 PipeControlPoint ocp = previous;
1091 PipeControlPoint sccp = ocp.getParentPoint();
1093 throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, no size change control point");
1097 } else if (previous.next == this) {
1098 previous.setNext(null);
1100 throw new RuntimeException("Removing PipeControlPoint "+ this+ " structure damaged");
1104 if (children.size() > 0 ) {
1106 } else if (parent!= null) {
1107 removeParentPoint();
1113 pipeRun.remChild(this);
1114 checkRemove(pipeRun);
1115 if (PipingRules.isEnabled() && pipeRun.getParent() != null && pipeRun.getControlPoints().size() > 0)
1116 PipingRules.validate(pipeRun);
1117 if (additionalRemove != null)
1118 additionalRemove.remove();
1121 public void remove() {
1122 PipeControlPoint currentPrev = previous;
1123 PipeControlPoint currentNext = next;
1126 if (currentNext != null)
1127 PipingRules.requestUpdate(currentNext);
1128 if (currentPrev != null)
1129 PipingRules.requestUpdate(currentPrev);
1130 } catch (Exception e) {
1131 e.printStackTrace();
1135 public void removeAndSplit() {
1136 PipeControlPoint currentPrev = previous;
1137 PipeControlPoint currentNext = next;
1139 if (next != null && previous != null) {
1140 P3DRootNode root = (P3DRootNode)getPipelineComponent().getRootNode();
1141 PipeRun nextPipeRun = new PipeRun();
1142 nextPipeRun.setName(root.getUniqueName("PipeRun"));
1143 root.addChild(nextPipeRun);
1145 PipeRun previousRun = previous.getPipeRun();
1146 nextPipeRun.setPipeDiameter(previousRun.getPipeDiameter());
1147 nextPipeRun.setTurnRadius(previousRun.getTurnRadius());
1149 PipelineComponent n = next.getPipelineComponent();
1151 if (! (n instanceof Nozzle)) {
1153 nextPipeRun.addChild(n);
1155 n.setPipeRun(nextPipeRun);
1161 if (currentNext != null)
1162 PipingRules.requestUpdate(currentNext);
1163 if (currentPrev != null)
1164 PipingRules.requestUpdate(currentPrev);
1165 } catch (Exception e) {
1166 e.printStackTrace();
1170 private void checkRemove(PipeRun pipeRun) {
1171 Collection<PipeControlPoint> points = pipeRun.getControlPoints();
1172 if (points.size() == 0) {
1174 } else if (points.size() == 1) {
1175 PipeControlPoint pcp = points.iterator().next();
1176 if (pcp.isDeletable())
1181 private void removeDualPoint() {
1182 if (previous != null)
1183 previous.setNext(null);
1185 next.setPrevious(null);
1186 PipeControlPoint ocp;
1187 PipeControlPoint sccp;
1188 if (isDualInline()) {
1190 ocp = getSubPoint().get(0);
1193 sccp = getParentPoint();
1195 PipeRun p1 = ocp.getPipeRun();
1196 PipeRun p2 = sccp.getPipeRun();
1198 ocp.removeComponent();
1199 sccp.removeComponent();
1206 // TODO : now we assume that this is size change, and we do
1207 if (ocp.next != null)
1208 ocp.next.setPrevious(null);
1209 if (ocp.previous != null)
1210 ocp.previous.setNext(null);
1211 if (sccp.next != null)
1212 sccp.next.setPrevious(null);
1213 if (sccp.previous != null)
1214 sccp.previous.setNext(null);
1216 ocp.setPrevious(null);
1218 sccp.setPrevious(null);
1226 private void removeSubPoints() {
1227 for (PipeControlPoint p : children) {
1228 // TODO : this may affect delete routine, since classification of the point changes.
1235 private void removeParentPoint() {
1236 throw new RuntimeException("Child points cannot be removed directly");
1239 private void removeComponent() {
1240 if (component == null)
1242 PipelineComponent next = component.getNext();
1243 PipelineComponent prev = component.getPrevious();
1244 PipelineComponent br0 = component.getBranch0();
1245 component.setNext(null);
1246 component.setPrevious(null);
1247 component.setBranch0(null);
1249 if (next.getNext() == component)
1251 else if (next.getPrevious() == component)
1252 next.setPrevious(null);
1253 else if (next.getBranch0() == component)
1254 next.setBranch0(null);
1257 if (prev.getNext() == component)
1259 else if (prev.getPrevious() == component)
1260 prev.setPrevious(null);
1261 else if (prev.getBranch0() == component)
1262 prev.setBranch0(null);
1265 if (br0.getNext() == component)
1267 else if (br0.getPrevious() == component)
1268 br0.setPrevious(null);
1269 else if (br0.getBranch0() == component)
1270 br0.setBranch0(null);
1272 PipelineComponent comp = component;
1279 public void setOrientation(Quat4d orientation) {
1280 if (MathTools.equals(orientation, getOrientation()))
1282 super.setOrientation(orientation);
1283 if (getParentPoint() == null && component != null)
1284 component._setWorldOrientation(getWorldOrientation());
1289 public void setPosition(Vector3d position) {
1290 if (MathTools.equals(position, getPosition()))
1292 if (Double.isNaN(position.x) || Double.isNaN(position.y) || Double.isNaN(position.z))
1293 throw new IllegalArgumentException("NaN is not supported");
1294 super.setPosition(position);
1295 if (getParentPoint() == null && component != null)
1296 component._setWorldPosition(getWorldPosition());
1300 private void updateSubPoint() {
1302 if (next == null && previous == null) {
1303 for (PipeControlPoint sub : getSubPoint()) {
1304 sub.setWorldPosition(getWorldPosition());
1305 sub.setWorldOrientation(getWorldOrientation());
1309 for (PipeControlPoint sub : getSubPoint()) {
1310 Vector3d wp = getWorldPosition();
1311 wp.add(getSizeChangeOffsetVector());
1312 sub.setWorldPosition(wp);
1313 sub.setWorldOrientation(getWorldOrientation());
1316 for (PipeControlPoint sub : getSubPoint()) {
1317 sub.setWorldPosition(getWorldPosition());
1318 sub.setWorldOrientation(getWorldOrientation());
1324 public void _setWorldPosition(Vector3d position) {
1325 Vector3d localPos = getLocalPosition(position);
1326 super.setPosition(localPos);
1330 public void _setWorldOrientation(Quat4d orientation) {
1331 Quat4d localOr = getLocalOrientation(orientation);
1332 super.setOrientation(localOr);
1337 public String toString() {
1338 return getClass().getName() + "@" + Integer.toHexString(hashCode());