]> gerrit.simantics Code Review - simantics/3d.git/blobdiff - org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipingRules.java
Handle variable length free end updates properly
[simantics/3d.git] / org.simantics.plant3d / src / org / simantics / plant3d / scenegraph / controlpoint / PipingRules.java
index b096266f7af72901d2718812b9dd77d3570d3689..386cc56a211d3245d6bb07137550d538d31a50f6 100644 (file)
@@ -44,29 +44,41 @@ public class PipingRules {
        private static boolean triedIR = false;
 
        
-       private static List<PipeControlPoint> updates = new ArrayList<PipeControlPoint>();
+       private static List<PipeControlPoint> requestUpdates = new ArrayList<PipeControlPoint>();
+       private static List<PipeControlPoint> currentUpdates = new ArrayList<PipeControlPoint>();
        
-       private static Object mutex = new Object();
+       private static Object updateMutex = new Object();
+       private static Object ruleMutex = new Object();
        
        public static void requestUpdate(PipeControlPoint pcp) {
                if (DEBUG) System.out.println("PipingRules request " + pcp);
-               synchronized (mutex) {
-               if (!updates.contains(pcp))
-                       updates.add(pcp);
+               synchronized (updateMutex) {
+                   if (!requestUpdates.contains(pcp))
+                       requestUpdates.add(pcp);
                }
        }
        
-       public static synchronized boolean update() throws Exception {
-               if (updates.size() == 0)
+       public static boolean update() throws Exception {
+               if (requestUpdates.size() == 0)
                        return false;
-               List<PipeControlPoint> temp = new ArrayList<PipeControlPoint>(updates.size());
-               synchronized(mutex) {
-                       temp.addAll(updates);
-                       updates.clear();
+               
+               List<PipeControlPoint> temp = new ArrayList<PipeControlPoint>(requestUpdates.size());
+               synchronized(updateMutex) {
+                   temp.addAll(requestUpdates);
+               requestUpdates.clear();
+               }
+               synchronized (ruleMutex) {
+                   currentUpdates.clear();
+                   currentUpdates.addAll(temp);
+                   // TODO : we should remove already processed control points from currentUpdates after each _positionUpdate call.
+                   for (PipeControlPoint pcp : currentUpdates)
+                   _positionUpdate(pcp, true);
+                   currentUpdates.clear();
+        }
+               synchronized(updateMutex) {
+                   requestUpdates.removeAll(temp);
                }
                
-               for (PipeControlPoint pcp : temp)
-                       positionUpdate(pcp);
                return true;
        }
        
@@ -76,6 +88,16 @@ public class PipingRules {
        }
        
        public static boolean positionUpdate(PipeControlPoint pcp, boolean allowIR) throws Exception {
+           synchronized (ruleMutex) {
+           currentUpdates.add(pcp);
+           boolean b = _positionUpdate(pcp, allowIR);
+           currentUpdates.clear();
+           return b;
+           }
+           
+       }
+       
+       private static boolean _positionUpdate(PipeControlPoint pcp, boolean allowIR) throws Exception {
                if (updating || !enabled)
                        return true;
                if (pcp.getPipeRun() == null)
@@ -106,7 +128,7 @@ public class PipingRules {
        public static void setEnabled(boolean enabled) {
                PipingRules.enabled = enabled;
                if(!enabled)
-                       updates.clear();
+                       currentUpdates.clear();
        }
        
        public static boolean isEnabled() {
@@ -527,15 +549,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 {
@@ -544,11 +566,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.
@@ -587,18 +609,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 {
@@ -607,9 +629,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.
@@ -714,11 +736,13 @@ public class PipingRules {
         Vector3d dir = new Vector3d();
         dir.sub(currentPos, prevPos);
         
-           boolean simple = true;
+           boolean simple = currentUpdates.contains(icp);
            if (simple) {
+               // Update based on position -> adjust length
                double currentLength = (dir.length() - prev.getInlineLength()) * 2.0;
                icp.setLength(currentLength);
            } else {
+               // Update based on neighbour movement -> adjust length and position, so that free end stays in place.
                double currentLength = icp.getLength();
                if (currentLength < MathTools.NEAR_ZERO) {
                        currentLength = (dir.length() - prev.getInlineLength()) * 2.0;
@@ -828,6 +852,13 @@ public class PipingRules {
                }
 
                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);
@@ -997,17 +1028,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);
@@ -1540,12 +1581,25 @@ public class PipingRules {
                
                if (!tcp.isFixed()) {
                    if (next == null || prev == null)
-                   return Math.PI; // FIXME : argh
+                   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)
@@ -1563,7 +1617,7 @@ public class PipingRules {
                 Vector3d middlePoint = tcp.getWorldPosition();
                 Vector3d nextPoint = next.getWorldPosition();
                 dir = new Vector3d();
-                dir.sub(nextPoint,middlePoint);
+                dir.sub(middlePoint, nextPoint);
                    }
                    dir.normalize();
             
@@ -1695,6 +1749,12 @@ public class PipingRules {
                                }
                                
                        }
+                       if (current.isTurn() && current.isFixed()) {
+                           current.setReversed(!current._getReversed());
+                       }
+                       if (current.isInline() && current.isReverse()) {
+                           current.setReversed(!current._getReversed());
+                       }   
                }
        }