]> gerrit.simantics Code Review - simantics/3d.git/blobdiff - org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipingRules.java
Fix issues in offset calculations in directed path legs
[simantics/3d.git] / org.simantics.plant3d / src / org / simantics / plant3d / scenegraph / controlpoint / PipingRules.java
index d00e4018de1407887cb1982e578bb2b3d967a4a5..e930b8d6d07094035a188933141c4519085c5382 100644 (file)
@@ -68,11 +68,12 @@ public class PipingRules {
            if (!PipingRules.enabled)
                return false;
            
-               if (requestUpdates.size() == 0)
-                       return false;
-               
-               List<PipeControlPoint> temp = new ArrayList<PipeControlPoint>(requestUpdates.size());
-               synchronized(updateMutex) {
+           List<PipeControlPoint> temp;
+           synchronized(updateMutex) {
+                       if (requestUpdates.size() == 0)
+                               return false;
+                       
+                       temp = new ArrayList<PipeControlPoint>(requestUpdates.size());
                        temp.addAll(requestUpdates);
                        requestUpdates.clear();
                }
@@ -216,6 +217,17 @@ public class PipingRules {
                        System.out.println("PipingRules.updateInlineControlPoint() " + pcp);
                PipeControlPoint start = pcp.findPreviousEnd();
                updatePathLegNext(start, pcp, PathLegUpdateType.NONE);
+               
+               if (pcp.isOffset()) {
+                       // Adjusting the rotation angle of an offset component may change variable angle turns
+                       PipeControlPoint end = pcp.findNextEnd();
+                       if (end.isVariableAngle()) {
+                               updatePathLegNext(end, end, PathLegUpdateType.NONE);
+                       }
+                       if (start.isVariableAngle()) {
+                               updatePathLegPrev(start, start, PathLegUpdateType.NONE);
+                       }
+               }
        }
 
        private static PipeControlPoint insertElbow(PipeControlPoint pcp1, PipeControlPoint pcp2, Vector3d pos) throws Exception{
@@ -282,7 +294,7 @@ public class PipingRules {
                scp.setWorldPosition(pos);
                Vector3d dir = new Vector3d();
                dir.sub(pcp2.getWorldPosition(), pcp1.getWorldPosition());
-               updateControlPointOrientation(scp, dir);
+               scp.orientToDirection(dir);
                scp.setLength(length);
                validate(scp.getPipeRun());
                return scp;
@@ -369,10 +381,43 @@ public class PipingRules {
 
        }
 
+       /**
+        * Calculate offset based on a given fixed component direction.
+        * 
+        * The desired component direction is provided as an input to this method,
+        * unlike the direction vector that is calculated by calculateOffset.
+        * 
+        * The returned offset vector is always perpendicular to the given direction
+        * vector.
+        * 
+        * @param startPoint Start point of leg
+        * @param endPoint   End point of leg
+        * @param start      Starting component of leg
+        * @param list       Inline components between start and end
+        * @param end        Ending component of leg
+        * @param dir        Direction at which the offset is calculated
+        * @param offset     A vector object to receive the offset vector values
+        * @return True if offsets are present
+        */
        public static boolean calculateDirectedOffset(Vector3d startPoint, Vector3d endPoint, PipeControlPoint start, ArrayList<PipeControlPoint> list, PipeControlPoint end, Vector3d dir, Vector3d offset) {
                return calculateOffset(startPoint, endPoint, start, list, end, dir, offset, true);
        }
 
+       /**
+        * Calculate offset and direction vectors for a path leg so that the given chain
+        * of components starts and ends at the given coordinates
+        * 
+        * The returned direction and offset vectors are perpendicular to each other.
+        * 
+        * @param startPoint Start point of the leg
+        * @param endPoint   End point of the leg
+        * @param start      Starting component of the leg
+        * @param list       Inline components between start and end
+        * @param end        Ending component of the leg
+        * @param dir        A vector object to receive the component direction vector
+        * @param offset     A vector object to receive the offset vector
+        * @return True if offsets are present
+        */
        public static boolean calculateOffset(Vector3d startPoint, Vector3d endPoint, PipeControlPoint start, ArrayList<PipeControlPoint> list, PipeControlPoint end, Vector3d dir, Vector3d offset) {
                return calculateOffset(startPoint, endPoint, start, list, end, dir, offset, false);
        }
@@ -385,8 +430,11 @@ public class PipingRules {
                } else {
                        Vector3d sp = new Vector3d(startPoint);
                        Point3d ep = new Point3d(endPoint);
-                       dir.set(ep);
-                       dir.sub(sp);
+                       if (!directed) {
+                               dir.set(ep);
+                               dir.sub(sp);
+                       }
+                       
                        double l = dir.lengthSquared(); 
                        if (l > MathTools.NEAR_ZERO)
                                dir.scale(1.0/Math.sqrt(l));
@@ -748,8 +796,8 @@ public class PipingRules {
                        continue;
                    double curr = gapObj.d;
                    int d = 1;
-                   while (curr < -MIN_INLINE_LENGTH) {
-                       GapObj next = i+d >= 0 ? gaps.get(i+d) : null;
+                   while (d < gaps.size() && curr < -MIN_INLINE_LENGTH) {
+                       GapObj next = i+d < gaps.size() ? gaps.get(i+d) : null;
                     GapObj prev = i-d >= 0 ? gaps.get(i-d) : null;
                        if (next != null && next.gap == Gap.SPACE) {
                            double move = Math.min(-curr, next.d);
@@ -767,12 +815,12 @@ public class PipingRules {
                                pcp.first.setWorldPosition(p);
                            }
                        }
-                       if (curr < -MIN_INLINE_LENGTH && prev != null && prev.gap == Gap.SPACE) {
+                       else if (prev != null && prev.gap == Gap.SPACE) {
                            double move = Math.min(-curr, prev.d);
                         curr+= move;
-                        next.d -= move;
-                        if (next.d < MIN_INLINE_LENGTH)
-                            next.gap = Gap.ATTACHED;
+                        prev.d -= move;
+                        if (prev.d < MIN_INLINE_LENGTH)
+                            prev.gap = Gap.ATTACHED;
                         Vector3d mv = new Vector3d(dir);
                         mv.normalize();
                         mv.scale(-move);
@@ -783,6 +831,9 @@ public class PipingRules {
                             pcp.first.setWorldPosition(p);
                         }
                        }
+                       else {
+                           d++;
+                       }
                    }
                }
            } else {
@@ -1065,15 +1116,19 @@ public class PipingRules {
                
                Point3d otherPosition = new Point3d(dcpStart ? u.endPoint : u.startPoint);
                if (u.hasOffsets) {
-                       Vector3d dir = new Vector3d(), offset = new Vector3d();
+                       Vector3d dir = dcp.getDirection(dcpStart ? Direction.NEXT : Direction.PREVIOUS);
+                       if (!dcpStart)
+                               dir.negate();
+                       
+                       Vector3d offset = new Vector3d();
                        calculateDirectedOffset(u.startPoint, u.endPoint, u.start, u.list, u.end, dir, offset);
                        u.dir = dir;
                        u.offset = offset;
                        
                        if (dcpStart)
-                               otherPosition.add(offset);
-                       else
                                otherPosition.sub(offset);
+                       else
+                               otherPosition.add(offset);
                }
 
                double mu[] = new double[2];
@@ -1221,7 +1276,7 @@ public class PipingRules {
                Point3d position1 = new Point3d(u.startPoint);
                Point3d position2 = new Point3d(u.endPoint);
                
-               Vector3d dir = new Vector3d(), offset = new Vector3d();
+               Vector3d dir = u.start.getDirection(Direction.NEXT), offset = new Vector3d();
                calculateDirectedOffset(new Vector3d(position1), new Vector3d(position2), u.start, u.list, u.end, dir, offset);
                
                Point3d position1offset = new Point3d(position1);
@@ -1348,7 +1403,7 @@ public class PipingRules {
            else if (d < -0.9999)
             return tr*2.0; // point following turn is directly behind the nozzle, in theory, we should return Double.Inf...
            
-           double curr = tr*0.1; 
+           double curr = 0.0;
            int iter = 10;
            Vector3d tp0 = tcp.getPosition();
            try {
@@ -1356,7 +1411,7 @@ public class PipingRules {
                    while (iter > 0) {
                        Vector3d tp = new Vector3d(dir);
                        tp.scaleAdd(curr, dp);
-                       tcp.setPosition(tp);
+                       tcp._setPosition(tp); // no firing of listeners here
                            if (other == ne) {
                                dir2 = pathLegDirection(tcp);
                            } else {
@@ -1365,10 +1420,12 @@ public class PipingRules {
                            }
                            
                        double a = dir.angle(dir2);
-                       double t = Math.tan(a * 0.5);
-                       double R = 0.0;
-                       if (t > MathTools.NEAR_ZERO)
-                           R = tr * t;
+                       
+                       // other is directly between dcp and tcp, a zero angle turn should do
+                       if (Math.PI - a <= MathTools.NEAR_ZERO)
+                           return 0.0;
+                       
+                       double R = tr * Math.tan(a * 0.5);
                        if (R <= curr)
                            break;
                        curr = R*1.001;
@@ -1376,7 +1433,7 @@ public class PipingRules {
                    }
            }
            finally {
-               tcp.setPosition(tp0);
+               tcp._setPosition(tp0); // return the original value
            }
            return curr;
        }
@@ -1621,7 +1678,7 @@ public class PipingRules {
                        } else if (u.start.isEnd()) {
                                updateEndComponentControlPoint(u.start, u.dir);
                        } else if (u.start.isInline()) {
-                               updateControlPointOrientation(u.start, u.dir);
+                               u.start.orientToDirection(u.dir);
                        }
                        if (u.end.isTurn()) {
                                //updateTurnControlPointTurn(u.end, u.end.getPrevious(), u.end.getNext());
@@ -1630,7 +1687,7 @@ public class PipingRules {
                        } else if (u.end.isEnd()) {
                                updateEndComponentControlPoint(u.end, u.dir);
                        } else if (u.end.isInline()) {
-                               updateControlPointOrientation(u.end, u.dir);
+                               u.end.orientToDirection(u.dir);
                        }
 
                } else {
@@ -1759,7 +1816,7 @@ public class PipingRules {
                        System.out.println(" " + newInlinePoint);
 
                icp.setWorldPosition(newInlinePoint);
-               updateControlPointOrientation(icp, dir);
+               icp.orientToDirection(dir);
        }
 
        /**
@@ -1776,7 +1833,7 @@ public class PipingRules {
                        System.out.println("PipingRules.updateEndComponentControlPoint() " + ecp);
                
                if (!ecp.isFixed()) // prevent overriding nozzle orientations..
-                  updateControlPointOrientation(ecp, dir);
+                       ecp.orientToDirection(dir);
 
                for (PipeControlPoint pcp : ecp.getChildPoints()) {
                        // TODO update position
@@ -1784,21 +1841,6 @@ public class PipingRules {
                }
        }
 
-       private static void updateControlPointOrientation(PipeControlPoint pcp, Vector3d dir) {
-               Double angleO = pcp.getRotationAngle();
-               double angle = 0.0;
-               if (angleO != null)
-                       angle = angleO;
-               boolean reversed = pcp._getReversed();
-               Quat4d q = null;
-               if (dir != null) {
-                   q = pcp.getControlPointOrientationQuat(dir, angle, reversed);
-               } else {
-                   q = pcp.getControlPointOrientationQuat(angle, reversed);
-               }
-               pcp.setWorldOrientation(q);
-       }
-
        /**
         * Updates all branches when branch's position has been changed
         * 
@@ -1842,7 +1884,9 @@ public class PipingRules {
                                        return tcp.getTurnAngle();
                                return Math.PI; // FIXME : argh
                        }
-                       double turnAngle = prev.angle(next);
+                       
+                       final boolean isDegenerate = prev.lengthSquared() < MathTools.NEAR_ZERO || next.lengthSquared() < MathTools.NEAR_ZERO;
+                       double turnAngle = isDegenerate ? 0.0 : prev.angle(next);
        
                        Vector3d turnAxis = new Vector3d();
                        turnAxis.cross(prev, next);
@@ -1862,7 +1906,7 @@ public class PipingRules {
                                tcp.setTurnAxis(new Vector3d(MathTools.Y_AXIS));
                        }
                        
-                       updateControlPointOrientation(tcp,prev);
+                       tcp.orientToDirection(prev);
                        
                        if (DEBUG)
                                System.out.println("PipingTools.updateTurnControlPointTurn " + prev + " " + next + " " + turnAngle + " " + turnAxis);
@@ -1890,7 +1934,7 @@ public class PipingRules {
                                return Math.PI; // FIXME : argh
                        }
                        
-                       Quat4d q = PipeControlPoint.getControlPointOrientationQuat(dir, tcp.getRotationAngle() != null ? tcp.getRotationAngle() : 0.0);
+                       Quat4d q = tcp.getControlPointOrientationQuat(dir, tcp.getRotationAngle() != null ? tcp.getRotationAngle() : 0.0);
                        Vector3d v = new Vector3d();
                        MathTools.rotate(q, MathTools.Y_AXIS,v);
                        tcp.setTurnAxis(v);
@@ -2057,50 +2101,52 @@ public class PipingRules {
        public static void validate(PipeRun pipeRun) {
                if (pipeRun == null)
                        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 " + pipeRun.getName() + " contains unconnected control points, found " + runPcps.size() + " connected, " + pcps.size() + " total.");
+               synchronized (ruleMutex) {
+                       Collection<PipeControlPoint> pcps = pipeRun.getControlPoints();
+                       int count = 0;
+                       //System.out.println("Validate " + pipeRun.getName());
                        for (PipeControlPoint pcp : pcps) {
-                           if (!runPcps.contains(pcp)) {
-                               System.out.println("Unconnected " + pcp + " " + pcp.getPipelineComponent());
-                           }
+                               if (pcp.getParentPoint() == null || pcp.getParentPoint().getPipeRun() != pipeRun)
+                                       count++;
                        }
-               }
-               for (PipeControlPoint pcp : pcps) {
-                   if (pcp.getPipeRun() == null) {
-                       System.out.println("PipeRun ref missing " + pcp + " " + pcp.getPipelineComponent());
-                   }
-                       if (!pcp.isDirected() && pcp.getNext() == null && pcp.getPrevious() == null)
-                               System.out.println("Orphan undirected " + pcp + " " + pcp.getPipelineComponent());
-               }
-               for (PipeControlPoint pcp : pcps) {
-                       if (pcp.getParentPoint() == null) {
-                               PipeControlPoint sub = null;
-                               if (pcp.isDualInline())
-                                       sub = pcp.getDualSub();
-                               PipeControlPoint next = pcp.getNext();
-                               PipeControlPoint prev = pcp.getPrevious();
-                               if (next != null) {
-                                       if (!(next.getPrevious() == pcp || next.getPrevious() == sub)) {
-                                               System.out.println("Inconsistency between " + pcp + " -> " +next );
-                                       }
+                       List<PipeControlPoint> runPcps = getControlPoints(pipeRun);
+                       if (runPcps.size() != count) {
+                               System.out.println("Run " + pipeRun.getName() + " contains unconnected control points, found " + runPcps.size() + " connected, " + pcps.size() + " total.");
+                               for (PipeControlPoint pcp : pcps) {
+                                   if (!runPcps.contains(pcp)) {
+                                       System.out.println("Unconnected " + pcp + " " + pcp.getPipelineComponent());
+                                   }
                                }
-                               if (prev != null) {
-                                       PipeControlPoint prevParent = null;
-                                       if (prev.isDualSub()) {
-                                               prevParent = prev.getParentPoint();
-                                       } else if (prev.isDualInline()) {
-                                               System.out.println("Inconsistency between " + pcp + " <-- " +prev );
+                       }
+                       for (PipeControlPoint pcp : pcps) {
+                           if (pcp.getPipeRun() == null) {
+                               System.out.println("PipeRun ref missing " + pcp + " " + pcp.getPipelineComponent());
+                           }
+                               if (!pcp.isDirected() && pcp.getNext() == null && pcp.getPrevious() == null)
+                                       System.out.println("Orphan undirected " + pcp + " " + pcp.getPipelineComponent());
+                       }
+                       for (PipeControlPoint pcp : pcps) {
+                               if (pcp.getParentPoint() == null) {
+                                       PipeControlPoint sub = null;
+                                       if (pcp.isDualInline())
+                                               sub = pcp.getDualSub();
+                                       PipeControlPoint next = pcp.getNext();
+                                       PipeControlPoint prev = pcp.getPrevious();
+                                       if (next != null) {
+                                               if (!(next.getPrevious() == pcp || next.getPrevious() == sub)) {
+                                                       System.out.println("Inconsistency between " + pcp + " -> " +next );
+                                               }
                                        }
-                                       if (!(prev.getNext() == pcp && (prevParent == null || prevParent.getNext() == pcp))) {
-                                               System.out.println("Inconsistency between " + pcp + " <-- " +prev );
+                                       if (prev != null) {
+                                               PipeControlPoint prevParent = null;
+                                               if (prev.isDualSub()) {
+                                                       prevParent = prev.getParentPoint();
+                                               } else if (prev.isDualInline()) {
+                                                       System.out.println("Inconsistency between " + pcp + " <-- " +prev );
+                                               }
+                                               if (!(prev.getNext() == pcp && (prevParent == null || prevParent.getNext() == pcp))) {
+                                                       System.out.println("Inconsistency between " + pcp + " <-- " +prev );
+                                               }
                                        }
                                }
                        }