]> gerrit.simantics Code Review - simantics/3d.git/blobdiff - org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipingRules.java
Merge "Improve elbow placement when dual directed pathleg is no loner aligned"
[simantics/3d.git] / org.simantics.plant3d / src / org / simantics / plant3d / scenegraph / controlpoint / PipingRules.java
index e1d9ae2d3971a57548a8821f9c118acb4c4934ff..6a5d04fb345731d9fb88cbbc86c7494611bc4f9c 100644 (file)
@@ -442,12 +442,28 @@ public class PipingRules {
                updatePathLeg(new UpdateStruct2(start, startPoint, list, end, endPoint, dir, offset, hasOffsets, iter, reversed, toRemove, updated), lengthChange);
 
        }
-
+       
+       private static boolean asDirected(PipeControlPoint pcp, Direction direction) {
+           if (pcp.isDirected())
+               return true;
+           if (pcp.isTurn() && pcp.isFixed()) {
+              if (!pcp._getReversed())
+                  return direction == Direction.NEXT;
+              else
+                  return direction == Direction.PREVIOUS;
+           }
+           return false;
+       }
+       
+       private static Vector3d direction(PipeControlPoint pcp, Direction direction) {
+           return pcp.getDirection(direction);
+       }
        private static void updatePathLeg(UpdateStruct2 u, PathLegUpdateType lengthChange) throws Exception {
                int directed = 0;
-               if (u.start.isDirected())
+               if (asDirected(u.start, Direction.NEXT))
                        directed++;
-               if (u.end.isDirected())
+               if (asDirected(u.end, Direction.PREVIOUS))
                        directed++;
                switch (directed) {
                case 0:
@@ -467,7 +483,7 @@ public class PipingRules {
                if (DEBUG)
                        System.out.println("PipingRules.updateFreePipeRun " + u + " " + lengthChange);
                checkExpandPathLeg(u, lengthChange);
-               if (u.start.isInline() || u.end.isInline())
+               if (u.start.isInline() || u.end.isInline() || u.start.isFixed() || u.end.isFixed())
                        processPathLeg(u, true, false);
        }
 
@@ -475,14 +491,19 @@ public class PipingRules {
                if (DEBUG)
                        System.out.println("PipingRules.updateInlineControlPoints() " + u);
 
+               Vector3d start = new Vector3d(u.startPoint);
+               Vector3d end = new Vector3d(u.endPoint);
+               
+               if (checkSizes) {
+                       // create offsets for leg ends.
+                       MathTools.mad(start, u.dir, u.start.getInlineLength());
+                       MathTools.mad(end, u.dir, -u.end.getInlineLength());
+               }
+               
                boolean recalcline = false;
                if (!u.hasOffsets) {
                        
-                       Vector3d start = new Vector3d(u.startPoint);
-                       Vector3d end = new Vector3d(u.endPoint);
-                       // create offsets.
-                       MathTools.mad(start, u.dir, u.start.getInlineLength());
-                       MathTools.mad(end, u.dir, -u.end.getInlineLength());
+                       
                        for (PipeControlPoint icp : u.list) {
                                updateInlineControlPoint(icp, start, end, u.dir);
                                
@@ -506,15 +527,15 @@ public class PipingRules {
                        pathLegPoints.add(u.end);
 
                        // TODO : values can be cached in the loop
-                       for (int i = 1; i < pathLegPoints.size(); i++) {
+                       for (int i = 0; i < pathLegPoints.size(); i++) {
                                PipeControlPoint icp = pathLegPoints.get(i);
 
-                               PipeControlPoint prev = pathLegPoints.get(i - 1);
-                               
+                               PipeControlPoint prev = i > 0 ? pathLegPoints.get(i - 1) : null;
+                               PipeControlPoint next = i < pathLegPoints.size() - 1 ? pathLegPoints.get(i + 1) : null;
 
                                if (icp.isVariableLength()) {
-                                       if (i != pathLegPoints.size() - 1) {
-                                               PipeControlPoint next = pathLegPoints.get(i + 1);
+                                       if (prev != null && next != null) {
+                                               
                                                recalcline = recalcline | updateVariableLength(icp,  prev, next);
 
                                        } else {
@@ -523,11 +544,11 @@ public class PipingRules {
                                                // the problem is that we want to keep unconnected end
                                                // of the component in the same
                                                // place, but center of the component must be moved.
-                                               updateVariableLengthEnd(icp, prev);
+                                               updateVariableLengthEnd(icp, prev != null ? prev : next);
                                        }
 
 
-                               } else if (!prev.isVariableLength()) {
+                               } else if (prev != null && !prev.isVariableLength()) {
                                        // If this and previous control point are not variable
                                        // length pcps, we'll have to check if there is no empty
                                        // space between them.
@@ -537,8 +558,8 @@ public class PipingRules {
                                }
                        }
                } else { // with offset
-                       Vector3d sp = new Vector3d(u.startPoint);
-                       Vector3d ep = new Vector3d(u.endPoint);
+                       Vector3d sp = new Vector3d(start);
+                       Vector3d ep = new Vector3d(end);
                        ep.sub(u.offset);
                        
                        ArrayList<PipeControlPoint> pathLegPoints = new ArrayList<PipeControlPoint>();
@@ -566,18 +587,18 @@ public class PipingRules {
                        ep = new Vector3d(u.endPoint);
                        ep.sub(u.offset);
                        
-                       for (int i = 1; i < pathLegPoints.size(); i++) {
+                       for (int i = 0; i < pathLegPoints.size(); i++) {
                                PipeControlPoint icp = pathLegPoints.get(i);
 
-                               PipeControlPoint prev = pathLegPoints.get(i - 1);
-                               if (prev.isDualInline())
+                               PipeControlPoint prev = i > 0 ? pathLegPoints.get(i - 1) : null;
+                PipeControlPoint next = i < pathLegPoints.size() - 1 ? pathLegPoints.get(i + 1) : null;
+                
+                               if (prev != null && prev.isDualInline())
                                        prev = prev.getSubPoint().get(0);
                                
 
                                if (icp.isVariableLength()) {
-                                       if (i != pathLegPoints.size() - 1) {
-                                               PipeControlPoint next;
-                                               next = pathLegPoints.get(i + 1);
+                                       if (prev != null && next != null) {
                                                recalcline = recalcline | updateVariableLength(icp,  prev, next);
 
                                        } else {
@@ -586,9 +607,9 @@ public class PipingRules {
                                                // the problem is that we want to keep unconnected end
                                                // of the component in the same
                                                // place, but center of the component must be moved.
-                                               updateVariableLengthEnd(icp, prev);
+                                               updateVariableLengthEnd(icp, prev != null ? prev : next);
                                        }
-                               } else if (!prev.isVariableLength()) {
+                               } else if (prev != null && !prev.isVariableLength()) {
                                        // If this and previous control point are not variable
                                        // length pcps, we'll have to check if there is no empty
                                        // space between them.
@@ -687,43 +708,47 @@ public class PipingRules {
        }
        
        private static void updateVariableLengthEnd(PipeControlPoint icp,  PipeControlPoint prev) {
-               double currentLength = icp.getLength();
-               Vector3d currentPos = icp.getWorldPosition();
-               Vector3d prevPos = prev.getWorldPosition();
-               
-               Vector3d dir = new Vector3d();
-               dir.sub(currentPos, prevPos);
-               
-               if (currentLength < MathTools.NEAR_ZERO) {
-                       currentLength = (dir.length() - prev.getInlineLength()) * 2.0;
-               }
-               
-               if (dir.lengthSquared() > MathTools.NEAR_ZERO)
-                       dir.normalize();
-               Point3d endPos = new Point3d(dir);
-               endPos.scale(currentLength * 0.5);
-               endPos.add(currentPos); // this is the free end of the
-                                                               // component
-
-               double offset = prev.getInlineLength();
-               Point3d beginPos = new Point3d(dir);
-               beginPos.scale(offset);
-               beginPos.add(prevPos); // this is the connected end of
-                                                               // the component
-
-               double l = beginPos.distance(endPos);
-               
-               if (Double.isNaN(l))
-                       System.out.println("Length for " + icp + " is NaN");
-
-               dir.scale(l * 0.5);
-               beginPos.add(dir); // center position
-
-               if (DEBUG)
-                       System.out.println("PipingRules.updateInlineControlPoints() setting variable length to " + l);
-               icp.setLength(l);
-
-               icp.setWorldPosition(new Vector3d(beginPos));
+           Vector3d currentPos = icp.getWorldPosition();
+        Vector3d prevPos = prev.getWorldPosition();
+        
+        Vector3d dir = new Vector3d();
+        dir.sub(currentPos, prevPos);
+        
+           boolean simple = true;
+           if (simple) {
+               double currentLength = (dir.length() - prev.getInlineLength()) * 2.0;
+               icp.setLength(currentLength);
+           } else {
+               double currentLength = icp.getLength();
+               if (currentLength < MathTools.NEAR_ZERO) {
+                       currentLength = (dir.length() - prev.getInlineLength()) * 2.0;
+               }
+               
+               if (dir.lengthSquared() > MathTools.NEAR_ZERO)
+                       dir.normalize();
+               Point3d endPos = new Point3d(dir);
+               endPos.scale(currentLength * 0.5);
+               endPos.add(currentPos); // this is the free end of the component
+    
+               double offset = prev.getInlineLength();
+               Point3d beginPos = new Point3d(dir);
+               beginPos.scale(offset);
+               beginPos.add(prevPos); // this is the connected end of the component
+    
+               double l = beginPos.distance(endPos);
+               
+               if (Double.isNaN(l))
+                       System.out.println("Length for " + icp + " is NaN");
+    
+               dir.scale(l * 0.5);
+               beginPos.add(dir); // center position
+    
+               if (DEBUG)
+                       System.out.println("PipingRules.updateInlineControlPoints() setting variable length to " + l);
+               icp.setLength(l);
+    
+               icp.setWorldPosition(new Vector3d(beginPos));
+           }
        }
 
        private static void ppNoOffset(UpdateStruct2 u) throws Exception {
@@ -784,7 +809,7 @@ public class PipingRules {
                boolean dcpStart = false;
                boolean inlineEnd = false;
                Vector3d position;
-               if (u.start.isDirected()) {
+               if (asDirected(u.start, Direction.NEXT)) {
                        dcp = u.start;
                        other = u.end;
                        position = u.startPoint;
@@ -802,7 +827,14 @@ public class PipingRules {
                        inlineEnd = u.start.isInline();
                }
 
-               Vector3d directedDirection = dcp.getDirection();
+               Vector3d directedDirection = direction(dcp, dcpStart ? Direction.NEXT : Direction.PREVIOUS);
+               if (directedDirection == null) {
+                   updateTurnControlPointTurn(dcp, dcp.getPrevious(), dcp.getNext());
+                   directedDirection = direction(dcp, dcpStart ? Direction.NEXT : Direction.PREVIOUS);
+                   if (directedDirection == null) {
+                       return;
+                   }
+               }
                Point3d directedEndPoint = new Point3d(u.endPoint);
                if (u.hasOffsets)
                        directedEndPoint.add(u.offset);
@@ -823,6 +855,8 @@ public class PipingRules {
                double distance = t.length();
                boolean aligned = (distance < ALLOWED_OFFSET);
                if (aligned) {
+                   if (u.start.isInline() || u.end.isInline() || u.start.isFixed() || u.end.isFixed())
+                   processPathLeg(u, true, false);
                        checkExpandPathLeg(u, lengthChange, inlineEnd);
                        
                } else {
@@ -939,8 +973,8 @@ public class PipingRules {
                position1offset.sub(u.offset);
                Point3d position2offset = new Point3d(position2);
                position2offset.add(u.offset);
-               Vector3d dir1 = dcp1.getDirection();
-               Vector3d dir2 = dcp2.getDirection();
+               Vector3d dir1 = direction(dcp1, Direction.NEXT);
+               Vector3d dir2 = direction(dcp2, Direction.PREVIOUS);
                Vector3d p1 = MathTools.closestPointOnStraight(position1offset, position2, dir2);
                Vector3d p2 = MathTools.closestPointOnStraight(position2offset, position1, dir1);
                double d1 = position1.distance(new Point3d(p1));
@@ -970,17 +1004,27 @@ public class PipingRules {
                                }
                                
                                p1 = dcp.getWorldPosition();
-                               // FIXME: calculate position of the elbows properly.
+                               Vector3d v = new Vector3d();
                                if (!u.reversed)
-                                       p1.add(dir1);
+                                   v.set(dir1);
                                else
-                                       p1.add(dir2);
+                                       v.set(dir2);
+                               
+                               // Reserve space for 90 deg elbow
+                               double off = dcp1.getPipeRun().getTurnRadius();
+                               v.scale(off);
+                               p1.add(v);
 
                                if (!u.reversed)
                                        p2 = MathTools.closestPointOnStraight(new Point3d(p1), position2, dir2);
                                else
                                        p2 = MathTools.closestPointOnStraight(new Point3d(p1), position1, dir1);
 
+                               // By default, the elbows are placed next to each other, by using 90 deg angles.
+                               // If the distance between elbows is not enough, we must move the other elbow (and create more shallow angle elbows)
+                               if (MathTools.distance(p1, p2) < off*2.05) {
+                                   p2.add(v);
+                               }
                                
                                PipeControlPoint tcp1 = insertElbow(dcp, next, p1);
                                PipeControlPoint tcp2 = insertElbow(tcp1, next, p2);
@@ -1268,8 +1312,7 @@ public class PipingRules {
                                        info.getEnd()._remove();
                                }
                        }
-                       // ControlPointTools.removeControlPoint may remove mo0re than one
-                       // CP;
+                       // ControlPointTools.removeControlPoint may remove more than one CP;
                        // we must populate inline CP list again.
                        u.list.clear();
                        u.start.findNextEnd( u.list);
@@ -1471,8 +1514,11 @@ public class PipingRules {
                double angle = 0.0;
                if (angleO != null)
                        angle = angleO;
-
-               Quat4d q = pcp.getControlPointOrientationQuat(angle);
+               Boolean reversedO = pcp.getReversed();
+               boolean reversed = false;
+               if (reversedO != null)
+                       reversed = reversedO;
+               Quat4d q = pcp.getControlPointOrientationQuat(angle, reversed);
                pcp.setWorldOrientation(q);
        }
 
@@ -1508,12 +1554,56 @@ public class PipingRules {
        private static double updateTurnControlPointTurn(PipeControlPoint tcp, PipeControlPoint prev, PipeControlPoint next) {
                if (DEBUG)
                        System.out.println("PipingTools.updateTurnControlPointTurn()" + tcp);
-               if (next == null || prev == null)
-                       return Math.PI; // FIXME : argh
-               Vector3d middlePoint = tcp.getWorldPosition();
-               Vector3d nextPoint = next.getWorldPosition();
-               Vector3d prevPoint = prev.getWorldPosition();
-               return updateTurnControlPointTurn(tcp, middlePoint, prevPoint, nextPoint);
+               
+               if (!tcp.isFixed()) {
+                   if (next == null || prev == null)
+                   return tcp.getTurnAngle();
+               Vector3d middlePoint = tcp.getWorldPosition();
+               Vector3d nextPoint = next.getWorldPosition();
+               Vector3d prevPoint = prev.getWorldPosition();
+               return updateTurnControlPointTurn(tcp, middlePoint, prevPoint, nextPoint);
+               } else {
+                   // Verify that fixed turn is properly defined.
+                   // TODO : when reversed flag is changed, rotation angle should be recalculated, otherwise the orientation will change.
+                   // TODO : should reverse flag toggle to be done already when we are removing defining side?
+                   if (prev != null && next != null) {
+                       // Nothing to do
+                   } else if (prev == null) {
+                       if (!tcp._getReversed())
+                           tcp.setReversed(true);
+                   } else if (next == null) {
+                       if (tcp._getReversed())
+                           tcp.setReversed(false);
+                   }
+                   
+                   Vector3d dir;
+                   if (!tcp._getReversed()) {
+                   if (prev == null)
+                   return Math.PI; // FIXME : argh
+                   
+                   Vector3d middlePoint = tcp.getWorldPosition();
+                   Vector3d prevPoint = prev.getWorldPosition();
+                   dir = new Vector3d();
+                   dir.sub(middlePoint, prevPoint);        
+                  
+                   } else {
+                       if (next == null)
+                    return Math.PI; // FIXME : argh
+                
+                Vector3d middlePoint = tcp.getWorldPosition();
+                Vector3d nextPoint = next.getWorldPosition();
+                dir = new Vector3d();
+                dir.sub(middlePoint, nextPoint);
+                   }
+                   dir.normalize();
+            
+            Quat4d q = PipeControlPoint.getControlPointOrientationQuat(dir, tcp.getRotationAngle() != null ? tcp.getRotationAngle() : 0.0);
+            Vector3d v = new Vector3d();
+            MathTools.rotate(q, MathTools.Y_AXIS,v);
+            tcp.setTurnAxis(v);
+            tcp.setWorldOrientation(q);
+            return tcp.getTurnAngle();
+               }
        }
 
        /**
@@ -1555,7 +1645,7 @@ public class PipingRules {
                        turnAngle = 0.0;
                        tcp.setTurnAngle(0.0);
                        tcp.setLength(0.0);
-                       tcp.setTurnAxis(MathTools.Y_AXIS);
+                       tcp.setTurnAxis(new Vector3d(MathTools.Y_AXIS));
                }
                updateControlPointOrientation(tcp);
                if (DEBUG)
@@ -1635,6 +1725,12 @@ public class PipingRules {
                                }
                                
                        }
+                       if (current.isTurn() && current.isFixed()) {
+                           current.setReversed(!current._getReversed());
+                       }
+                       if (current.isInline() && current.isReverse()) {
+                           current.setReversed(!current._getReversed());
+                       }   
                }
        }
        
@@ -1668,13 +1764,14 @@ public class PipingRules {
                        return;
                Collection<PipeControlPoint> pcps = pipeRun.getControlPoints();
                int count = 0;
+               //System.out.println("Validate " + pipeRun.getName());
                for (PipeControlPoint pcp : pcps) {
                        if (pcp.getParentPoint() == null || pcp.getParentPoint().getPipeRun() != pipeRun)
                                count++;
                }
                List<PipeControlPoint> runPcps = getControlPoints(pipeRun);
                if (runPcps.size() != count) {
-                       System.out.println("Run is not connected");
+                       System.out.println("Run " + pipeRun.getName() + " contains unconnected control points");
                }
                for (PipeControlPoint pcp : pcps) {
                        if (!pcp.isDirected() && pcp.getNext() == null && pcp.getPrevious() == null)