]> gerrit.simantics Code Review - simantics/3d.git/blobdiff - org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipeControlPoint.java
Convert variable angle turn turn to fixed angle
[simantics/3d.git] / org.simantics.plant3d / src / org / simantics / plant3d / scenegraph / controlpoint / PipeControlPoint.java
index 93186779e60d580aa31d23a95585ce4886ff9f7b..086bdb2b5d408de5fcc8109dba50eae6ea8ca452 100644 (file)
@@ -16,6 +16,8 @@ import org.simantics.g3d.math.MathTools;
 import org.simantics.g3d.property.annotations.GetPropertyValue;
 import org.simantics.g3d.scenegraph.G3DNode;
 import org.simantics.plant3d.scenegraph.IP3DNode;
+import org.simantics.plant3d.scenegraph.Nozzle;
+import org.simantics.plant3d.scenegraph.P3DRootNode;
 import org.simantics.plant3d.scenegraph.PipeRun;
 import org.simantics.plant3d.scenegraph.PipelineComponent;
 
@@ -33,12 +35,12 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
        private PipelineComponent component;
 
        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;
+       private boolean isFixed = true;        // In-line: fixed-length Turn: fixed-angle
+       private boolean isRotate = false;      // rotates around path leg axis.
+       private boolean isReverse = false;     // definition direction can be swapped
+       private boolean isDeletable = true;    // can be removed by rules
+       private boolean isSizeChange = false;  // changes size of the pipe. The next control point / component is on different PipeRun
+       private boolean isSub = false;         // child point
 
        public PipeControlPoint(PipelineComponent component) {
                this.component = component;
@@ -83,7 +85,6 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
                return isFixed;
        }
 
-
        public void setFixed(boolean fixed) {
                this.isFixed = fixed;
        }
@@ -135,10 +136,20 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
                return type == PointType.INLINE;
        }
 
+       /**
+        * True for end components, if control point defines absolute position direction, which rules cannot modify. 
+        * This is typical for nozzles.
+        * @return
+        */
        public boolean isDirected() {
                return isFixed && isEnd();
        }
 
+       /**
+     * True for end components, if control is opposite to directed, and rules can modify position and orientation.
+     * This is typical for caps, and other end components.
+     * @return
+     */
        public boolean isNonDirected() {
                return !isFixed && isEnd();
        }
@@ -146,10 +157,35 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
        public boolean isVariableLength() {
                return !isFixed && isInline();
        }
+       
+       /**
+        * Fixed length in-line component is such that piping rules cannot modify the length.
+        * @return
+        */
+       public boolean isFixedLength() {
+        return isFixed && isInline();
+    }
 
        public boolean isVariableAngle() {
                return !isFixed && isTurn();
        }
+       
+       /**
+        * Fixed angle turn component is such that piping rules cannot modify the angle.
+        * @return
+        */
+       public boolean isFixedAngle() {
+        return isFixed && isTurn();
+    }
+       
+       /**
+        * Does the turn behave like fixed angle?
+        * For variable angle turns, the turn angle is defined by connected components, and without them, we must handle the component as fixed angle. 
+        * @return
+        */
+       public boolean asFixedAngle() {
+        return isTurn() && (isFixed || next == null || previous == null);
+    }
 
        public boolean isBranchEnd() {
                return isDeletable && isEnd();
@@ -204,6 +240,9 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
                if (this.next == next)
                        return;
                if (DEBUG) System.out.println(this + " next " + next);
+               if (next == null && isVariableAngle() && previous != null && !isRemoved()) {
+                   convertVariableAngleToFixed(Direction.NEXT);
+               }
                this.next = next;
                if (component != null) {
                        if (parent == null || isSub)
@@ -212,7 +251,6 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
                                component.setBranch0(next != null ? next.component : null);
                        updateSubPoint();
                }
-
        }
 
        public void setPrevious(PipeControlPoint previous) {
@@ -223,6 +261,9 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
                if (this.previous == previous)
                        return;
                if (DEBUG) System.out.println(this + " previous " + previous);
+               if (previous == null && isVariableAngle() && next != null && !isRemoved()) {
+            convertVariableAngleToFixed(Direction.PREVIOUS);
+        }
                this.previous = previous;
                if (component != null) {
                        if (parent == null || isSub)
@@ -231,7 +272,32 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
                                component.setBranch0(previous != null ? previous.component : null);
                        updateSubPoint();
                }
-
+       }
+       
+       private void convertVariableAngleToFixed(Direction direction) {
+           // We are removing reference, which transforms variable angle to fixed angle.
+        // Since fixed angle is defined differently, we need to calculate fixed angle parameters based on current data
+        // We need to calculate turnAngle and rotationAngle
+           Vector3d dirOut = getPathLegDirection(direction == Direction.NEXT ? Direction.NEXT : Direction.PREVIOUS);
+        Vector3d dir = getPathLegDirection(direction == Direction.NEXT ? Direction.PREVIOUS : Direction.NEXT);
+        dir.negate();
+        dirOut.normalize();
+        dir.normalize();
+        double angle = dir.angle(dirOut);
+        //super._setNext(null);
+        if (direction == Direction.NEXT)
+            next = null;
+        else
+            previous = null;
+        setRotationAngle(0.0);
+        setReversed(direction == Direction.NEXT ? false : true);
+        Vector3d dirOutN = getPathLegDirection(direction == Direction.NEXT ? Direction.NEXT : Direction.PREVIOUS);
+        dirOutN.normalize();
+        AxisAngle4d aa = new AxisAngle4d();
+        if (MathTools.createRotation(dirOutN, dirOut, dir, aa)) {
+            setRotationAngle(aa.angle);
+            setTurnAngle(angle);
+        }
        }
 
        public PipeControlPoint parent;
@@ -288,7 +354,9 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
 
        @GetPropertyValue(name="Rotation Angle",tabId="Debug",value="rotationAngle")
        public Double getRotationAngle() {
-               return rotationAngle;
+           if (asFixedAngle())
+               return rotationAngle;
+           return null;
        }
 
        @GetPropertyValue(name="Reversed",tabId="Debug",value="reversed")
@@ -626,7 +694,7 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
        public Vector3d getDirection(Direction direction) {
         if (isDirected())
             return getDirectedControlPointDirection();
-        if (isTurn() && isFixed()) {
+        if (isTurn() && asFixedAngle()) {
             if (direction == Direction.NEXT) {
                 if (previous != null) {
                     PipeControlPoint pcp = this;
@@ -681,12 +749,12 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
                        } else {
                                if (previous == null) {
                                        if (!isDirected())
-                                               throw new RuntimeException("Cannot calculate path leg direction for unconnected control point");
+                                               throw new RuntimeException("Cannot calculate path leg direction for unconnected control point " + this);
                                        return getDirectedControlPointDirection();
 
                                } else {
-                                       if (isVariableAngle())
-                                               throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point");
+                                       if (isVariableAngle() && !asFixedAngle())
+                                               throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point " + this);
                                        if (isInline()) {
                                                PipeControlPoint pcp = this;
                                                if (pcp.isDualSub()) {
@@ -701,10 +769,10 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
                                                Vector3d v = new Vector3d();
                                                v.sub(getWorldPosition(),previous.getWorldPosition());
                                                return v;
-                                       } else if (isTurn() && isFixed() && !_getReversed()) {
+                                       } else if (isTurn() && asFixedAngle() && !_getReversed()) {
                                                return getDirection(Direction.NEXT);
                                        }
-                                       throw new RuntimeException("Missing implementation");
+                                       throw new RuntimeException("Missing implementation " + this);
                                }
                        }
                } else {
@@ -718,13 +786,13 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
                        } else {
                                if (next == null)  {
                                        if (!isDirected())
-                                               throw new RuntimeException("Cannot calculate path leg direction for unconnected control point");
+                                               throw new RuntimeException("Cannot calculate path leg direction for unconnected control point " + this);
                                        Vector3d v = getDirectedControlPointDirection();
                                        v.negate();
                                        return v;
                                } else {
-                                       if (isVariableAngle())
-                                               throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point");
+                                       if (isVariableAngle() && !asFixedAngle())
+                                               throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point " + this);
                                        if (isInline()) {
                                                PipeControlPoint pcp = this;
                                                if (pcp.isDualInline()) {
@@ -741,10 +809,10 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
                                                Vector3d v = new Vector3d();
                                                v.sub(getWorldPosition(),next.getWorldPosition());
                                                return v;
-                                       } else if (isTurn() && isFixed() && _getReversed()) {
+                                       } else if (isTurn() && asFixedAngle() && _getReversed()) {
                                                return getDirection(Direction.PREVIOUS);
                                        }
-                                       throw new RuntimeException("Missing implementation");
+                                       throw new RuntimeException("Missing implementation " + this);
                                }
                        }
                }
@@ -766,7 +834,7 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
        }
 
        public void getControlPointEnds(Tuple3d p1, Tuple3d p2) {
-               PipeControlPoint sub = isAxial() ? this : getSubPoint().get(0);
+               PipeControlPoint sub = isAxial() || isDirected() || isTurn() ? this : getSubPoint().get(0);
                Vector3d pos = getWorldPosition(), pos2 = sub == this ? pos : sub.getWorldPosition();
                
                Vector3d dir1 = getPathLegDirection(Direction.PREVIOUS);
@@ -938,20 +1006,29 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
                        }
                }
        }
-
+       
        public void _remove() {
+           _remove(true);
+       }
+
+       public void _remove(boolean renconnect) {
                if (component == null && next == null && previous == null)
                        return;
+               if (DEBUG) System.out.println(this + " Remove " + renconnect);
                if (isDualInline() || isDualSub()) {
                        removeDualPoint();
                        return;
                }
+               if (getParentPoint() != null) {
+                   getParentPoint()._remove(renconnect);
+               }
                PipeRun pipeRun = getPipeRun();
                if (pipeRun == null)
                        return;
 
                PipeControlPoint additionalRemove = null;
                if (!PipingRules.isEnabled()) {
+                   component = null;
                        setPrevious(null);
                        setNext(null);
                } else {
@@ -964,7 +1041,7 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
                                return;
                        }
                        if (currentNext != null && currentPrev != null) {
-                               boolean link = true;
+                               boolean link = renconnect;
                                if (currentNext.isBranchEnd()) {
                                        link = false;
                                        //                                      currentNext.setPrevious(null);
@@ -1112,19 +1189,92 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
                        additionalRemove.remove();
        }
 
+       /**
+        * Removes control point and attempts to reconnect next/prev
+        * 
+        * If this point is size change (PipeRuns are different on both sides), then reconnection cannot be made.
+        */
        public void remove() {
                PipeControlPoint currentPrev = previous;
                PipeControlPoint currentNext = next;
                _remove();
                try {
                        if (currentNext != null)
-                               PipingRules.requestUpdate(currentNext);
+                           if (!currentNext.checkRemove())
+                               PipingRules.requestUpdate(currentNext);
                        if (currentPrev != null)
-                               PipingRules.requestUpdate(currentPrev);
+                           if (!currentPrev.checkRemove())
+                               PipingRules.requestUpdate(currentPrev);
                } catch (Exception e) {
                        e.printStackTrace();
                }
        }
+       
+       
+       /**
+        * Removes control point without attempting to reconnect next/prev.
+        * This usually leads to creation of another PipeRun for the control points after this point. 
+        */
+       public void removeAndSplit() {
+        PipeControlPoint currentPrev = previous;
+        PipeControlPoint currentNext = next;
+        
+        if (next != null && previous != null) {
+            P3DRootNode root = (P3DRootNode)getPipelineComponent().getRootNode();
+            PipeRun nextPipeRun = new PipeRun();
+            nextPipeRun.setName(root.getUniqueName("PipeRun"));
+            root.addChild(nextPipeRun);
+            
+            PipeRun previousRun = previous.getPipeRun();
+            nextPipeRun.setPipeDiameter(previousRun.getPipeDiameter());
+            nextPipeRun.setTurnRadiusArray(previousRun.getTurnRadiusArray());
+            
+            PipelineComponent n = next.getPipelineComponent();
+            while (n != null) {
+                if (! (n instanceof Nozzle)) {
+                    n.deattach();
+                    nextPipeRun.addChild(n);
+                } else
+                    n.setPipeRun(nextPipeRun);
+                n = n.getNext();
+            }
+        }
+        _remove(false);
+        try {
+            if (currentNext != null)
+                if (!currentNext.checkRemove())
+                    PipingRules.requestUpdate(currentNext);
+            if (currentPrev != null)
+                if (!currentPrev.checkRemove())
+                    PipingRules.requestUpdate(currentPrev);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+       
+       /**
+        * This is called when adjacent control point is removed.
+        * 
+        * This call should remove the give point, if the point cannot exist alone. 
+        * At the moment there is one such case: branch.
+        * 
+        * @return
+        */
+       protected boolean checkRemove() {
+           if (getParentPoint() != null) {
+               return getParentPoint().checkRemove();
+           } else {
+               if (getPipelineComponent() == null)
+                   return true; // already removed
+           if (getPipelineComponent().getType().equals("Plant3D.URIs.Builtin_BranchSplitComponent")) {
+               if (getSubPoint().get(0).getNext() == null && getSubPoint().get(0).getPrevious() == null) {
+                       remove();
+                       return true;
+               }
+           }
+            return false;
+           }
+    }
 
        private void checkRemove(PipeRun pipeRun) {
                Collection<PipeControlPoint> points = pipeRun.getControlPoints();
@@ -1194,6 +1344,10 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
        private void removeParentPoint() {
                throw new RuntimeException("Child points cannot be removed directly");
        }
+       
+       public boolean isRemoved() {
+           return component == null;
+       }
 
        private void removeComponent() {
                if (component == null)