]> gerrit.simantics Code Review - simantics/3d.git/blobdiff - org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipeControlPoint.java
Merge "Move plant3d test-product specific contributions to product plugin."
[simantics/3d.git] / org.simantics.plant3d / src / org / simantics / plant3d / scenegraph / controlpoint / PipeControlPoint.java
index 02bce62246e8748612ac72f7e2b64afae4da06de..51addbb09ee9edf707af756c8d9d035807aa99d2 100644 (file)
@@ -1,11 +1,13 @@
 package org.simantics.plant3d.scenegraph.controlpoint;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 
 import javax.vecmath.AxisAngle4d;
 import javax.vecmath.Matrix3d;
+import javax.vecmath.Point3d;
 import javax.vecmath.Quat4d;
 import javax.vecmath.Tuple3d;
 import javax.vecmath.Vector3d;
@@ -21,17 +23,22 @@ import vtk.vtkRenderer;
 
 
 public class PipeControlPoint extends G3DNode implements IP3DNode {
+    
+    private static boolean DEBUG = false;
        
-       public enum Type{INLINE,TURN,END};
+       public enum PointType{INLINE,TURN,END};
        public enum Direction{NEXT,PREVIOUS};
        public enum PositionType {SPLIT,NEXT,PREVIOUS,PORT}
        
        private PipelineComponent component;
        
-       private Type type;
-       private boolean fixed = true;
-       private boolean deletable = true;
-       private boolean sub = false;
+       private PointType type;
+       private boolean isFixed = true;
+       private boolean isRotate = false;
+       private boolean isReverse = false;
+       private boolean isDeletable = true;
+       private boolean isSizeChange = false;
+       private boolean isSub = false;
        
        public PipeControlPoint(PipelineComponent component) {
                this.component = component;
@@ -63,71 +70,89 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
                return component;
        }
        
-       public Type getType() {
+       public PointType getType() {
                return type;
        }
        
-       public void setType(Type type) {
+       public void setType(PointType type) {
                this.type = type;
        }
        
        @GetPropertyValue(name="Fixed",tabId="Debug",value="fixed")
        public boolean isFixed() {
-               return fixed;
+               return isFixed;
        }
        
        
        public void setFixed(boolean fixed) {
-               this.fixed = fixed;
+               this.isFixed = fixed;
+       }
+       
+       @GetPropertyValue(name="Rotate",tabId="Debug",value="rotate")
+       public boolean isRotate() {
+               return isRotate;
+       }
+       
+       public void setRotate(boolean rotate) {
+               this.isRotate = rotate;
+       }
+       
+       @GetPropertyValue(name="Reverse",tabId="Debug",value="reverse")
+       public boolean isReverse() {
+               return isReverse;
+       }
+       
+       public void setReverse(boolean reverse) {
+               this.isReverse = reverse;
        }
        
        public void setSub(boolean sub) {
-               this.sub = sub;
+               this.isSub = sub;
        }
                
        @GetPropertyValue(name="Deletable",tabId="Debug",value="deletable")
        public boolean isDeletable() {
-               return deletable;
+               return isDeletable;
        }
        
        public void setDeletable(boolean deletable) {
-               this.deletable = deletable;
+               this.isDeletable = deletable;
        }
        
        public boolean isPathLegEnd() {
-               return type != Type.INLINE;
+               return type != PointType.INLINE;
        }
        
        public boolean isEnd() {
-               return type == Type.END;
+               return type == PointType.END;
        }
        
        public boolean isTurn() {
-               return type == Type.TURN;
+               return type == PointType.TURN;
        }
        
        public boolean isInline() {
-               return type == Type.INLINE;
+               return type == PointType.INLINE;
        }
        
        public boolean isDirected() {
-               return fixed && isEnd();
+               return isFixed && isEnd();
        }
        
        public boolean isNonDirected() {
-               return !fixed && isEnd();
+               return !isFixed && isEnd();
        }
        
        public boolean isVariableLength() {
-               return !fixed && isInline();
+               return !isFixed && isInline();
        }
        
        public boolean isVariableAngle() {
-               return !fixed && isTurn();
+               return !isFixed && isTurn();
        }
        
        public boolean isBranchEnd() {
-               return deletable && isEnd();
+               return isDeletable && isEnd();
        }
        
        public boolean isOffset() {
@@ -135,7 +160,7 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
        }
        
        public boolean isDualSub() {
-               return parent != null && sub;
+               return parent != null && isSub;
        }
        
        public boolean isDualInline() {
@@ -143,12 +168,17 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
        }
        
        public boolean isSizeChange() {
-               if (children.size() == 0)
-                       return false;
-               if (!isDualInline())
-                       return false;
-               return getPipeRun() != children.get(0).getPipeRun();
+           return isSizeChange;
+//             if (children.size() == 0)
+//                     return false;
+//             if (!isDualInline())
+//                     return false;
+//             return getPipeRun() != children.get(0).getPipeRun();
        }
+       
+       public void setSizeChange(boolean isSizeChange) {
+        this.isSizeChange = isSizeChange;
+    }
 
        
        private PipeControlPoint next;
@@ -165,28 +195,39 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
        public void setNext(PipeControlPoint next) {
                if (isEnd() && previous != null && next != null)
                        throw new RuntimeException("End control points are allowed to have only one connection");
-//             if (next != null && getPipeRun() == null)
-//                     throw new RuntimeException("Cannot connect control point befor piperun has been set");
+               if (next == this)
+            throw new RuntimeException("Cannot connect to self");
+               if (this.next == next)
+                   return;
+               if (DEBUG) System.out.println(this + " next " + next);
                this.next = next;
                if (component != null) {
-                       if (parent == null || sub)
+                       if (parent == null || isSub)
                                component.setNext(next != null ? next.component : null);
                        else
                                component.setBranch0(next != null ? next.component : null);
+                       updateSubPoint();
                }
+               
        }
        
        public void setPrevious(PipeControlPoint previous) {
                if (isEnd() && next != null && previous != null)
                        throw new RuntimeException("End control points are allowed to have only one connection");
-//             if (previous != null && getPipeRun() == null)
-//                     throw new RuntimeException("Cannot connect control point befor piperun has been set");
+               if (previous == this)
+                   throw new RuntimeException("Cannot connect to self");
+               if (this.previous == previous)
+                   return;
+               if (DEBUG) System.out.println(this + " previous " + previous);
                this.previous = previous;
-               if (component != null)
-                       if (parent == null || sub)
+               if (component != null) {
+                       if (parent == null || isSub)
                                component.setPrevious(previous != null ? previous.component : null);
                        else
                                component.setBranch0(previous != null ? previous.component : null);
+                       updateSubPoint();
+               }
+               
        }
        
        public PipeControlPoint parent;
@@ -199,20 +240,15 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
        public PipeControlPoint getParentPoint() {
                return parent;
        }
-       
-       
-       
 
        
-       
-       
-       
        private double length;
        private Double turnAngle;
        private Vector3d turnAxis;
 
        private Double offset;
        private Double rotationAngle;
+       private Boolean reversed;
        
        @GetPropertyValue(name="Length",tabId="Debug",value="length")
        public double getLength() {
@@ -251,8 +287,19 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
                return rotationAngle;
        }
        
+       @GetPropertyValue(name="Reversed",tabId="Debug",value="reversed")
+       public Boolean getReversed() {
+               return reversed;
+       }
+       
+       public boolean _getReversed() {
+           if (reversed == null)
+               return false;
+        return reversed;
+    }
+       
        public void setTurnAngle(Double turnAngle) {
-               if (Double.isInfinite(turnAngle) || Double.isNaN(turnAngle)) {
+               if (turnAngle == null || Double.isInfinite(turnAngle) || Double.isNaN(turnAngle)) {
                        return;
                }
                if (this.turnAngle != null && Math.abs(this.turnAngle-turnAngle) < MathTools.NEAR_ZERO)
@@ -262,7 +309,9 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
        }
        
        public void setTurnAxis(Vector3d turnAxis) {
-               this.turnAxis = turnAxis;
+           if (this.turnAxis != null && MathTools.equals(turnAxis, this.turnAxis))
+            return;
+           this.turnAxis = turnAxis;
                firePropertyChanged("turnAxis");
        }
        
@@ -286,11 +335,30 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
                firePropertyChanged("rotationAngle");
        }
        
+       public void setReversed(Boolean reversed) {
+               this.reversed = reversed;
+               firePropertyChanged("reversed");
+       }
+       
        public Vector3d getSizeChangeOffsetVector(Vector3d dir) {
+               Quat4d q;
+               if (rotationAngle == null)
+                       q = getControlPointOrientationQuat(dir, 0.0);
+               else
+                       q = getControlPointOrientationQuat(dir, rotationAngle);
+               Vector3d v = new Vector3d(0.0,offset,0.0);
+       Vector3d offset = new Vector3d();
+       MathTools.rotate(q, v, offset);
+       return offset;
+       }
+       
+       public Vector3d getSizeChangeOffsetVector() {
+               Quat4d q;
                if (rotationAngle == null)
-                       rotationAngle = 0.0;
-               Quat4d q = getControlPointOrientationQuat(dir, rotationAngle);
-               Vector3d v = new Vector3d(0.0,0.0,offset);
+                       q = getControlPointOrientationQuat(0.0);
+               else
+                       q = getControlPointOrientationQuat(rotationAngle);
+               Vector3d v = new Vector3d(0.0,offset,0.0);
        Vector3d offset = new Vector3d();
        MathTools.rotate(q, v, offset);
        return offset;
@@ -310,7 +378,19 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
                return previous.toString();
        }
        
-        public Quat4d getControlPointOrientationQuat(double angle) {
+       @GetPropertyValue(name="Sub",tabId="Debug",value="sub")
+       private String getSubString() {
+               if (children.size() == 0)
+                       return "";
+               return Arrays.toString(children.toArray());
+       }
+       
+       @GetPropertyValue(name="Type",tabId="Debug",value="type")
+       public String getTypeString() {
+               return type.name();
+       }
+       
+       public Quat4d getControlPointOrientationQuat(double angle) {
                 
                 if (turnAxis == null) {
                         Vector3d dir = getPathLegDirection(Direction.NEXT);
@@ -324,11 +404,33 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
                                 dir.normalize();
                         return getControlPointOrientationQuat(dir, turnAxis, angle);
                 }
-        }
+       }
+        
+    public Quat4d getControlPointOrientationQuat(double angle, boolean reversed) {
+                
+                if (turnAxis == null) {
+                        Vector3d dir = getPathLegDirection(Direction.NEXT);
+                        if (dir.lengthSquared() > MathTools.NEAR_ZERO)
+                                dir.normalize();
+                        Quat4d q =  getControlPointOrientationQuat(dir, angle);
+                        if (reversed) {
+                               Quat4d q2 = new Quat4d();
+                               q2.set(new AxisAngle4d(MathTools.Y_AXIS, Math.PI));
+                               q.mulInverse(q2);
+                        }
+                        return q;
+                } else {
+                        Vector3d dir = getPathLegDirection(Direction.PREVIOUS);
+                        dir.negate();
+                        if (dir.lengthSquared() > MathTools.NEAR_ZERO)
+                                dir.normalize();
+                        return getControlPointOrientationQuat(dir, turnAxis, angle);
+                }
+       }
         
        
        
-        public static Quat4d getControlPointOrientationQuat(Vector3d dir, double angle) {
+       public static Quat4d getControlPointOrientationQuat(Vector3d dir, double angle) {
                        if (dir.lengthSquared() < MathTools.NEAR_ZERO)
                                return MathTools.getIdentityQuat();
                
@@ -381,28 +483,63 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
                        return q1;
            }
        
-       public Vector3d getDirection() {
-               return getDirectedControlPointDirection();
+       public Vector3d getDirection(Direction direction) {
+           if (isDirected())
+               return getDirectedControlPointDirection();
+           if (isTurn() && isFixed()) {
+               if (direction == Direction.NEXT) {
+                   if (previous != null) {
+                   PipeControlPoint pcp = this;
+                    Vector3d dir = new Vector3d();
+                    dir.sub(pcp.getWorldPosition(),previous.getWorldPosition());
+                    if (dir.lengthSquared() > MathTools.NEAR_ZERO)
+                         dir.normalize();
+                    else
+                        return null;
+                    Quat4d q = getControlPointOrientationQuat(dir, pcp.getRotationAngle() != null ? pcp.getRotationAngle() : 0.0);
+                    AxisAngle4d aa = new AxisAngle4d(MathTools.Y_AXIS,pcp.getTurnAngle() == null ? 0.0 : pcp.getTurnAngle());
+                    Quat4d q2 = MathTools.getQuat(aa);
+                    Vector3d v = new Vector3d(1.,0.,0.);
+                    Vector3d offset = new Vector3d();
+                    MathTools.rotate(q2, v, offset);
+                    MathTools.rotate(q, offset, dir);
+                    return dir;
+                   }
+               } else {
+                   if (next != null) {
+                   PipeControlPoint pcp = this;
+                    Vector3d dir = new Vector3d();
+                    dir.sub(next.getWorldPosition(),pcp.getWorldPosition());
+                    if (dir.lengthSquared() > MathTools.NEAR_ZERO)
+                         dir.normalize();
+                    else
+                        return null;
+                    Quat4d q = getControlPointOrientationQuat(dir, pcp.getRotationAngle() != null ? pcp.getRotationAngle() : 0.0);
+                    AxisAngle4d aa = new AxisAngle4d(MathTools.Y_AXIS,pcp.getTurnAngle() == null ? 0.0 : pcp.getTurnAngle());
+                    Quat4d q2 = MathTools.getQuat(aa);
+                    Vector3d v = new Vector3d(1.,0.,0.);
+                    Vector3d offset = new Vector3d();
+                    MathTools.rotate(q2, v, offset);
+                    MathTools.rotate(q, offset, dir);
+                    return dir;
+                   }
+               }
+           }
+           return null;
        }
        
-       
-       
-       
-       
-
-       
        public void insert(PipeControlPoint previous, PipeControlPoint next) {
                // inserting an offsetpoint is error, 
                if (isDualSub())
-                       throw new RuntimeException();
+                       throw new RuntimeException("Dual sub points cannot be inserted.");
                // size change control point cannot be inserted this way, because it ends PipeRun
                if (isSizeChange())
-                       throw new RuntimeException();
+                       throw new RuntimeException("Size change points cannot be inserted.");
                PipeRun piperun = previous.getPipeRun();
                // and just to make sure that control point structure is not corrupted
                if (getPipeRun() != null) {
                        if (piperun != getPipeRun() || piperun != next.getPipeRun())
-                               throw new RuntimeException();
+                               throw new RuntimeException("All controls points must be located on the same pipe run");
                } else {
                        piperun.addChild(this);
                }
@@ -538,17 +675,21 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
                                v.sub(next.getWorldPosition(),pcp.getWorldPosition());
                                return v;
                        } else {
-                               if (isVariableAngle())
-                                       throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point");
                                if (previous == null) {
                                        if (!isDirected())
                                                throw new RuntimeException("Cannot calculate path leg direction for unconnected control point");
                                        return getDirectedControlPointDirection();
                                        
                                } else {
+                                   if (isVariableAngle())
+                           throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point");
                                        if (isInline()) {
+                                               PipeControlPoint pcp = this;
+                                               if (pcp.isDualSub()) {
+                                                       pcp = pcp.getParentPoint();
+                                               }
                                                Vector3d v = new Vector3d();
-                                               v.sub(getWorldPosition(),previous.getWorldPosition());
+                                               v.sub(pcp.getWorldPosition(),previous.getWorldPosition());
                                                return v;
                                        } else if (isDirected()) {
                                                return getDirectedControlPointDirection();
@@ -556,6 +697,8 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
                                                Vector3d v = new Vector3d();
                                                v.sub(getWorldPosition(),previous.getWorldPosition());
                                                return v;
+                                       } else if (isTurn() && isFixed() && !_getReversed()) {
+                                          return getDirection(Direction.NEXT);
                                        }
                                        throw new RuntimeException("Missing implementation");
                                }
@@ -569,8 +712,6 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
                                v.sub(previous.getWorldPosition(),pcp.getWorldPosition());
                                return v;
                        } else {
-                               if (isVariableAngle())
-                                       throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point");
                                if (next == null)  {
                                        if (!isDirected())
                                                throw new RuntimeException("Cannot calculate path leg direction for unconnected control point");
@@ -578,9 +719,15 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
                                        v.negate();
                                        return v;
                                } else {
-                                       if (isInline()) {
+                                   if (isVariableAngle())
+                           throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point");
+                       if (isInline()) {
+                                               PipeControlPoint pcp = this;
+                                               if (pcp.isDualInline()) {
+                                                       pcp = pcp.getSubPoint().get(0);
+                                               }
                                                Vector3d v = new Vector3d();
-                                               v.sub(getWorldPosition(),next.getWorldPosition());
+                                               v.sub(pcp.getWorldPosition(),next.getWorldPosition());
                                                return v;
                                        } else if (isDirected()) {
                                                Vector3d v = getDirectedControlPointDirection();
@@ -590,7 +737,9 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
                                                Vector3d v = new Vector3d();
                                                v.sub(getWorldPosition(),next.getWorldPosition());
                                                return v;
-                                       }
+                                       } else if (isTurn() && isFixed() && _getReversed()) {
+                                           return getDirection(Direction.PREVIOUS);
+                    }
                                        throw new RuntimeException("Missing implementation");
                                }
                        }
@@ -657,9 +806,9 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
        }
        
        public double getInlineLength() {
-               if (type == Type.TURN)
+               if (type == PointType.TURN)
                        return length;
-               else if (type == Type.INLINE)
+               else if (type == PointType.INLINE)
                        return length * 0.5;
                return 0;
        }
@@ -875,7 +1024,19 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
                                        if (currentNext.isVariableLength() && currentPrev.isVariableLength()) {
                                                // we have to join them into single variable length component.
                                                additionalRemove = currentPrev;
-                                               //currentPrev.remove();
+                                               // combine lengths and set the location of remaining control point to the center.
+                                               Point3d ps = new Point3d();
+                                           Point3d pe = new Point3d();
+                                           Point3d ns = new Point3d();
+                        Point3d ne = new Point3d();
+                                               currentPrev.getInlineControlPointEnds(ps, pe);
+                                               currentNext.getInlineControlPointEnds(ns, ne);
+                                               double l = currentPrev.getLength() + currentNext.getLength();
+                                               Vector3d cp = new Vector3d();
+                                               cp.add(ps, ne);
+                                               cp.scale(0.5);
+                                               currentNext.setLength(l);
+                                               currentNext.setWorldPosition(cp);
                                        }
                                } else {
                                        // FIXME : pipe run must be split into two parts, since the control point structure is no more continuous. 
@@ -977,16 +1138,29 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
                ocp.removeComponent();
                sccp.removeComponent();
                
-               p1.remChild(ocp);
-               p2.remChild(sccp);
+               if (p1 != null)
+                   p1.remChild(ocp);
+               if (p2 != null)
+                   p2.remChild(sccp);
                
+               // TODO : now we assume that this is size change, and we do
+               if (ocp.next != null)
+                       ocp.next.setPrevious(null);
+               if (ocp.previous != null)
+                       ocp.previous.setNext(null);
+               if (sccp.next != null)
+                       sccp.next.setPrevious(null);
+               if (sccp.previous != null)
+                       sccp.previous.setNext(null);
                ocp.setNext(null);
                ocp.setPrevious(null);
                sccp.setNext(null);
                sccp.setPrevious(null);
                
-               checkRemove(p1);
-               checkRemove(p2);
+               if (p1 != null)
+                   checkRemove(p1);
+               if (p2 != null)
+                   checkRemove(p2);
        }
        
        private void removeSubPoints() {
@@ -1006,21 +1180,38 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
                if (component == null)
                        return;
                PipelineComponent next = component.getNext();
-               PipelineComponent prev = component.getNext();
+               PipelineComponent prev = component.getPrevious();
+               PipelineComponent br0 = component.getBranch0();
+               component.setNext(null);
+               component.setPrevious(null);
+               component.setBranch0(null);
                if (next != null) {
                        if (next.getNext() == component)
                                next.setNext(null);
                        else if (next.getPrevious() == component)
                                next.setPrevious(null);
+                       else if (next.getBranch0() == component)
+                           next.setBranch0(null);
                }
                if (prev != null) {
                        if (prev.getNext() == component)
                                prev.setNext(null);
                        else if (prev.getPrevious() == component)
                                prev.setPrevious(null);
+                       else if (prev.getBranch0() == component)
+                           prev.setBranch0(null);
+               }
+               if (br0 != null) {
+                   if (br0.getNext() == component)
+                       br0.setNext(null);
+                   else if (br0.getPrevious() == component)
+                       br0.setPrevious(null);
+                   else if (br0.getBranch0() == component)
+                       br0.setBranch0(null);
                }
                PipelineComponent comp = component;
                component = null;
+               
                comp.remove();
        }
        
@@ -1031,22 +1222,41 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
                super.setOrientation(orientation);
                if (getParentPoint() == null && component != null)
                        component._setWorldOrientation(getWorldOrientation());
-               for (PipeControlPoint sub : getSubPoint()) {
-                       sub.setWorldPosition(getWorldPosition());
-                       sub.setWorldOrientation(getWorldOrientation());
-               }
+               updateSubPoint();
        }
        
        @Override
        public void setPosition(Vector3d position) {
                if (MathTools.equals(position, getPosition()))
                        return;
+               if (Double.isNaN(position.x) || Double.isNaN(position.y) || Double.isNaN(position.z))
+                       throw new IllegalArgumentException("NaN is not supported");
                super.setPosition(position);
                if (getParentPoint() == null && component != null)
                        component._setWorldPosition(getWorldPosition());
-               for (PipeControlPoint sub : getSubPoint()) {
-                       sub.setWorldPosition(getWorldPosition());
-                       sub.setWorldOrientation(getWorldOrientation());
+               updateSubPoint();
+       }
+       
+       private void updateSubPoint() {
+               if (isOffset()) {
+                       if (next == null && previous == null) {
+                               for (PipeControlPoint sub : getSubPoint()) {
+                                       sub.setWorldPosition(getWorldPosition());
+                                       sub.setWorldOrientation(getWorldOrientation());
+                               }
+                               return;
+                       }
+                       for (PipeControlPoint sub : getSubPoint()) {
+                               Vector3d wp = getWorldPosition();
+                               wp.add(getSizeChangeOffsetVector());
+                               sub.setWorldPosition(wp);
+                               sub.setWorldOrientation(getWorldOrientation());
+                       }
+               } else {
+                       for (PipeControlPoint sub : getSubPoint()) {
+                               sub.setWorldPosition(getWorldPosition());
+                               sub.setWorldOrientation(getWorldOrientation());
+                       }
                }
        }
 
@@ -1054,19 +1264,13 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
        public void _setWorldPosition(Vector3d position) {
                Vector3d localPos = getLocalPosition(position);
                super.setPosition(localPos);
-               for (PipeControlPoint sub : getSubPoint()) {
-                       sub.setWorldPosition(getWorldPosition());
-                       sub.setWorldOrientation(getWorldOrientation());
-               }
+               updateSubPoint();
        }
        
        public void _setWorldOrientation(Quat4d orientation) {
                Quat4d localOr = getLocalOrientation(orientation);
                super.setOrientation(localOr);
-               for (PipeControlPoint sub : getSubPoint()) {
-                       sub.setWorldPosition(getWorldPosition());
-                       sub.setWorldOrientation(getWorldOrientation());
-               }
+               updateSubPoint();
        }
        
        @Override