]> gerrit.simantics Code Review - simantics/3d.git/blobdiff - org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipingRules.java
Yesterdays change introduced infinite loop for directed path leg updates
[simantics/3d.git] / org.simantics.plant3d / src / org / simantics / plant3d / scenegraph / controlpoint / PipingRules.java
index b64a9e93cce04a303747931499753e76d002645b..57ee4ba86a382e9ac49ed7253ccdaf03f0a248e4 100644 (file)
@@ -117,6 +117,8 @@ public class PipingRules {
                        allowInsertRemove = allowIR;
                        triedIR = false;
                        validate(pcp.getPipeRun());
+                       if (pcp.getParentPoint() != null)
+                           pcp = pcp.getParentPoint();
                        if (pcp.asPathLegEnd()) {
                                updatePathLegEndControlPoint(pcp); // FIXME: Rules won't work properly, if they are not run twice.
                                //updatePathLegEndControlPoint(pcp);
@@ -362,9 +364,12 @@ public class PipingRules {
        }
 
        @SuppressWarnings("unused")
-       private static boolean calculateOffset(Vector3d startPoint, Vector3d endPoint, ArrayList<PipeControlPoint> list, Vector3d dir, Vector3d offset) {
+       private static boolean calculateOffset(Vector3d startPoint, Vector3d endPoint, PipeControlPoint start, ArrayList<PipeControlPoint> list, PipeControlPoint end, Vector3d dir, Vector3d offset) {
                boolean hasOffsets = false;
                List<PipeControlPoint> offsets = new ArrayList<PipeControlPoint>(list.size());
+               // Only start offset affects the calculation
+               if (start.isOffset())
+                   offsets.add(start);
                for (PipeControlPoint icp : list) {
                        if (icp.isOffset()) {
                                offsets.add(icp);
@@ -441,7 +446,7 @@ public class PipingRules {
                Vector3d startPoint = start.getWorldPosition();
                Vector3d endPoint = end.getWorldPosition();
                Vector3d dir = new Vector3d();
-               hasOffsets = calculateOffset(startPoint, endPoint, list, dir, offset);
+               hasOffsets = calculateOffset(startPoint, endPoint, start, list, end, dir, offset);
                return new UpdateStruct2(start, startPoint, list, end, endPoint, dir, offset, hasOffsets, iter, direction == Direction.PREVIOUS, toRemove, updated);
        }
        
@@ -526,7 +531,13 @@ public class PipingRules {
                Vector3d ep = new Vector3d(end);
                ep.sub(u.offset);
                
-       
+               if (u.start.isOffset()) {
+                   Vector3d offset = u.start.getSizeChangeOffsetVector(u.dir);
+                   updateOffsetPoint(u.start, offset);
+            sp.add(offset);
+            ep.add(offset);
+               }
+                   
                for (PipeControlPoint icp : u.list) {
                        updateInlineControlPoint(icp, sp, ep, u.dir);
                        if (icp.isOffset()) {
@@ -853,7 +864,8 @@ public class PipingRules {
                double l2next = icp.getInlineLength();
                double l2 = l2prev + l2next;
                double l2s = l2 * l2;
-               if (l > l2s) {
+               double diff = l - l2s;
+               if (diff >= MIN_INLINE_LENGTH) {
                        if (allowInsertRemove) {
                                dir.normalize();
                                double length = Math.sqrt(l) - l2; // true length of the variable length component
@@ -937,7 +949,7 @@ public class PipingRules {
                // FIXME : extra loop (dir should be calculated here)
                Vector3d dir = new Vector3d();
                Vector3d offset = new Vector3d();
-               hasOffsets = calculateOffset(startPoint, endPoint, list, dir, offset);
+               hasOffsets = calculateOffset(startPoint, endPoint, start, list, end, dir, offset);
                ppNoOffset(new UpdateStruct2(start, startPoint, list, end, endPoint, dir, null, hasOffsets, iter, reversed, toRemove, updated));
        }
 
@@ -978,7 +990,7 @@ public class PipingRules {
                        position = u.startPoint;
                        dcpStart = true;
                        if (!u.reversed)
-                               canMoveOther = true;
+                canMoveOther = true;
                        inlineEnd = u.end.isInline();
                                
                } else {
@@ -986,10 +998,10 @@ public class PipingRules {
                        other = u.start;
                        position = u.endPoint;
                        if (u.reversed)
-                               canMoveOther = true;
+                canMoveOther = true;
                        inlineEnd = u.start.isInline();
                }
-
+               
                Vector3d directedDirection = direction(dcp, dcpStart ? Direction.NEXT : Direction.PREVIOUS);
                if (directedDirection == null) {
                        //updateTurnControlPointTurn(dcp, dcp.getPrevious(), dcp.getNext());
@@ -1001,7 +1013,7 @@ public class PipingRules {
                }
                Point3d directedEndPoint = new Point3d(u.endPoint);
                if (u.hasOffsets)
-                       directedEndPoint.add(u.offset);
+                       directedEndPoint.sub(u.offset);
 
                double mu[] = new double[2];
 
@@ -1018,6 +1030,16 @@ public class PipingRules {
 
                double distance = t.length();
                boolean aligned = (distance < ALLOWED_OFFSET);
+               double requiredSpace  = 0.0;
+               if (other.isVariableAngle()) {
+                   requiredSpace = spaceForTurn(other, dcp);
+               }
+               if (mu[0] < requiredSpace) {
+                   // At the moment, if next component is directly behind the nozzle, we must force moving the other component.
+                   // Trying to solve the situation by adding new turn creates infinite loop...   
+                   aligned = false;
+                   canMoveOther = true;
+               }
                if (aligned) {
                        if (u.start.isInline() || u.end.isInline() || u.start.asFixedAngle() || u.end.asFixedAngle())
                                processPathLeg(u, true, false);
@@ -1041,15 +1063,14 @@ public class PipingRules {
                                if (other.isVariableAngle()) {
 
                                        // TODO calculate needed space from next run end.
-                                   double space = spaceForTurn(other);
-                                       if (mu[0] < space) {
+                                   if (mu[0] < requiredSpace) {
                                                if (dcpStart) {
                                                        closest.set(u.startPoint);
                                                } else {
                                                        closest.set(u.endPoint);
                                                }
                                                Vector3d v = new Vector3d(directedDirection);
-                                               v.scale(space);
+                                               v.scale(requiredSpace);
                                                closest.add(v);
                                        }
 
@@ -1225,11 +1246,54 @@ public class PipingRules {
                
        }
        
-       private static double spaceForTurn(PipeControlPoint tcp) {
-               // TODO : this returns now space for 90 deg turn.
-               // The challenge: position of tcp affects the turn angle, which then affects the required space. Perhaps we need to iterate...
-               // Additionally, if the path legs contain offset, using just positions of opposite path leg ends is not enough,    
-               return ((TurnComponent)tcp.getPipelineComponent()).getTurnRadius();
+       private static double spaceForTurn(PipeControlPoint tcp, PipeControlPoint dcp) {
+               // TODO : if the path legs contain offset, using just positions of opposite path leg ends is not enough.
+           // TODO : current iterative way for calculating required space may return longer length that is required.
+               double tr = ((TurnComponent)tcp.getPipelineComponent()).getTurnRadius();
+           if (dcp == null)
+               return tr; // space for 90 deg
+           PipeControlPoint ne = tcp.findNextEnd();
+           PipeControlPoint pe = tcp.findPreviousEnd();
+           PipeControlPoint other = null;
+           if (dcp == ne)
+               other = pe;
+           else if (dcp == pe)
+               other = ne;
+           else
+               return tr; // space for 90 deg
+           if (other == null)
+               return tr; // space for 90 deg
+           Vector3d dir = dcp.getDirectedControlPointDirection();
+           Vector3d dp = dcp.getWorldPosition();
+           Vector3d op = other.getWorldPosition();
+           double u[] = new double[1];
+           Vector3d closest = MathTools.closestPointOnStraight(op, dp, dir,u);
+           if (MathTools.distanceSquared(closest, op) <= MIN_INLINE_LENGTH) {
+               if (u[0] > -MIN_INLINE_LENGTH)
+                   return 0.0; // point following turn is directly in the front of the nozzle.
+               else
+                   return tr*2.0; // point following turn is directly behind the nozzle, in theory, we should return Double.Inf...
+           }
+           double curr = tr*0.1; 
+           int iter = 10;
+           Vector3d v1 = new Vector3d();
+           Vector3d v2 = new Vector3d();
+           while (iter > 0) {
+               Vector3d tp = new Vector3d(dp);
+               MathTools.mad(tp, dir, curr);
+               v1.sub(tp, dp); // Vector from nozzle to turn 
+               v2.sub(op,tp);  // Vector from turn to other 
+               double a = v1.angle(v2);
+               double t = Math.tan((Math.PI - a) * 0.5);
+               double R = 0.0;
+               if (t > MathTools.NEAR_ZERO)
+                   R = tr / t;
+               if (R <= curr)
+                   break;
+               curr = R*1.001;
+               iter--;
+           }
+           return curr;
        }
 
        private static void insertElbowUpdate(UpdateStruct2 u, PipeControlPoint dcp, PipeControlPoint next, boolean dcpStart, Vector3d position, Vector3d directedDirection) throws Exception{
@@ -1247,9 +1311,8 @@ public class PipingRules {
                        closest = MathTools.closestPointOnStraight(dcp.getWorldPosition(), position, directedDirection);
                        tcp = insertElbow(next, dcp, closest);
                }
-               // TODO properly calculate required distance between start and inserted elbow.
                double d = MathTools.distance(position, closest);
-               double s = spaceForTurn(tcp);
+               double s = spaceForTurn(tcp,dcp);
                if (d < s)  {
                        d = s - d;
                        Vector3d p = new Vector3d(directedDirection);
@@ -1633,9 +1696,9 @@ public class PipingRules {
        private static void updateEndComponentControlPoint(PipeControlPoint ecp, Vector3d dir) throws Exception {
                if (DEBUG)
                        System.out.println("PipingRules.updateEndComponentControlPoint() " + ecp);
-               //FIXME : end control point cannot be fixed!
-               //if (!ecp.isFixed())
-               updateControlPointOrientation(ecp, dir);
+               
+               if (!ecp.isFixed()) // prevent overriding nozzle orientations..
+                  updateControlPointOrientation(ecp, dir);
 
                for (PipeControlPoint pcp : ecp.getChildPoints()) {
                        // TODO update position
@@ -1795,7 +1858,10 @@ public class PipingRules {
                        List<PipeControlPoint> points = getControlPoints(pipeRun);
                        PipeControlPoint pcp = points.get(0);
                        if (pcp.isSizeChange() && pcp.getChildPoints().size() > 0) {
-                               pipeRun = pcp.getPipeRun();
+                               PipeRun pr = pcp.getPipeRun();
+                               if (pr != pipeRun)
+                                   pipeRun = pr;
+                               else break;
                        } else {
                                break;
                        }
@@ -1829,7 +1895,6 @@ public class PipingRules {
                                List<PipeControlPoint> list2 = pcps.get(i+1);
                                PipeControlPoint prev = list.get(list.size()-1);
                                PipeControlPoint next = list2.get(0);
-                               System.out.println();
                                if (prev == next) {
                                        // Reverse the component on the boundary.
                                        InlineComponent ic = (InlineComponent)prev.getPipelineComponent();