]> gerrit.simantics Code Review - simantics/3d.git/blob - org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/common/PipingRules.java
d7e1619e720bc67d0458338ffcfeaff835bdc258
[simantics/3d.git] / org.simantics.proconf.processeditor / src / fi / vtt / simantics / processeditor / common / PipingRules.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
3  * All rights reserved. This program and the accompanying materials\r
4  * are made available under the terms of the Eclipse Public License v1.0\r
5  * which accompanies this distribution, and is available at\r
6  * http://www.eclipse.org/legal/epl-v10.html\r
7  *\r
8  * Contributors:\r
9  *     VTT Technical Research Centre of Finland - initial API and implementation\r
10  *******************************************************************************/\r
11 package fi.vtt.simantics.processeditor.common;\r
12 \r
13 import java.util.ArrayList;\r
14 import java.util.Collection;\r
15 \r
16 import javax.vecmath.AxisAngle4d;\r
17 import javax.vecmath.Point3d;\r
18 import javax.vecmath.Vector3d;\r
19 \r
20 import org.simantics.db.Graph;\r
21 import org.simantics.db.Resource;\r
22 import org.simantics.proconf.g3d.base.G3DTools;\r
23 import org.simantics.proconf.g3d.base.MathTools;\r
24 import org.simantics.utils.ErrorLogger;\r
25 \r
26 import fi.vtt.simantics.processeditor.ProcessResource;\r
27 import fi.vtt.simantics.processeditor.stubs.PipeControlPoint;\r
28 import fi.vtt.simantics.processeditor.stubs.PipeRun;\r
29 import fi.vtt.simantics.processeditor.stubs.PipelineComponent;\r
30 \r
31 /**\r
32  * Rules that update pipeline.\r
33  * TODO : optimize, remove stubs\r
34  * \r
35  * FIXME : transformations\r
36  * \r
37  * TODO : FixedAngleTurnComponents are handled like VariableAngleTurnComponents\r
38  * \r
39  * \r
40  * @author Marko Luukkainen <Marko.Luukkainen@vtt.fi>\r
41  *\r
42  */\r
43 public class PipingRules {\r
44         \r
45         private static final boolean DEBUG = false;\r
46         private static final boolean DUMMY = false;\r
47         \r
48         private static final double MIN_TURN_ANGLE = 0.01;\r
49         \r
50         private static final int REMOVE_NONE = 0;\r
51         private static final int REMOVE_START = 1;\r
52         private static final int REMOVE_END = 2;\r
53         private static final int REMOVE_BOTH = 3;\r
54         \r
55         private enum PathLegUpdateType {NONE,PREV,NEXT,PREV_S,NEXT_S};\r
56         \r
57         /**\r
58      * Rule\r
59      * \r
60      * @param resources\r
61      * @param pp\r
62      * @throws TransactionException\r
63      */\r
64     public static void pipeControlPointPositionUpdate(Graph g, Resource pp) {\r
65         \r
66         PipeControlPoint pcp = new PipeControlPoint(g,pp);\r
67         if (DEBUG) System.out.println("PipeControlPoint changed " + pp);\r
68         \r
69         boolean changed = ControlPointTools.isControlPointChanged(pcp);\r
70 \r
71         \r
72         if (changed) {\r
73                 if (pcp.isInstanceOf(ProcessResource.plant3Dresource.PathLegEndControlPoint)) {\r
74                         updatePathLegEndControlPoint(pcp);\r
75                 } else {\r
76                         updateInlineControlPoint(pcp);\r
77                 }\r
78         } \r
79         \r
80     }\r
81     \r
82   \r
83     \r
84     public static class ExpandIterInfo {\r
85         // these two are turn control points\r
86         private PipeControlPoint start; \r
87         private PipeControlPoint end;\r
88         private int type;\r
89         \r
90         public ExpandIterInfo() {\r
91                 \r
92         }\r
93         \r
94         public ExpandIterInfo(PipeControlPoint tcp, int type) {\r
95                 if (type == REMOVE_START)\r
96                         start = tcp;\r
97                 else \r
98                         end = tcp;\r
99                 this.type = type;\r
100         }\r
101         \r
102         public ExpandIterInfo(PipeControlPoint start, PipeControlPoint end) {\r
103                 this.start = start;\r
104                 this.end = end;\r
105                 this.type = REMOVE_BOTH;\r
106         }\r
107         \r
108                 public PipeControlPoint getEnd() {\r
109                         return end;\r
110                 }\r
111                 public void setEnd(PipeControlPoint end) {\r
112                         this.end = end;\r
113                 }\r
114                 public PipeControlPoint getStart() {\r
115                         return start;\r
116                 }\r
117                 public void setStart(PipeControlPoint start) {\r
118                         this.start = start;\r
119                 }\r
120                 public int getType() {\r
121                         return type;\r
122                 }\r
123                 public void setType(int type) {\r
124                         this.type = type;\r
125                 }\r
126         \r
127         \r
128     }\r
129     \r
130     private static void updatePathLegEndControlPoint(PipeControlPoint pcp) {\r
131         if (DEBUG) System.out.println("PipingTools.updateRunEndControlPoint() " + pcp.getResource());\r
132         if (pcp.getNext() != null) {\r
133                 updatePathLegNext(pcp,pcp,PathLegUpdateType.NEXT_S);\r
134         }\r
135         if (pcp.getPrevious() != null) {\r
136                 updatePathLegPrev(pcp,pcp,PathLegUpdateType.PREV_S);\r
137         }\r
138         \r
139     }\r
140     \r
141     private static void updateInlineControlPoint(PipeControlPoint pcp)  {\r
142         if (DEBUG) System.out.println("PipingTools.updateInlineControlPoint() " + pcp.getResource());\r
143         PipeControlPoint start = ControlPointTools.findPreviousEnd(pcp);\r
144         updatePathLegNext(start,pcp,PathLegUpdateType.NONE);\r
145     }\r
146     \r
147     private static PipeControlPoint insertElbow(PipeControlPoint pcp1 , PipeControlPoint pcp2, Point3d pos)  {\r
148         if (DEBUG) System.out.println("PipingRules.insertElbow() " + pcp1.getResource() + " " + pcp2.getResource()+ " " + pos);\r
149         PipelineComponent elbow = PipingTools2.instantiatePipelineComponent(pcp1.getGraph(), ControlPointTools.getPipeRun(pcp1).getResource(), ProcessResource.plant3Dresource.Elbow);\r
150         PipeControlPoint pcp = elbow.getControlPoint();\r
151  \r
152                 ControlPointTools.insertControlPoint(pcp, pcp1,pcp2);\r
153                 \r
154                 ControlPointTools.setWorldPosition(pcp, pos);\r
155 \r
156         return pcp;\r
157     }\r
158     \r
159     private static void updatePathLegNext(PipeControlPoint start, PipeControlPoint updated, PathLegUpdateType lengthChange){\r
160         ArrayList<PipeControlPoint> list = new ArrayList<PipeControlPoint>();\r
161         PipeControlPoint end = ControlPointTools.findNextEnd(start,list);\r
162         // this is for inline cp that is also path leg end\r
163         if (start.equals(updated))\r
164                 lengthChange = PathLegUpdateType.NEXT;\r
165         else if (end.equals(updated))\r
166                 lengthChange = PathLegUpdateType.PREV;                  \r
167         updatePathLegNext(start, list, end, updated, lengthChange);\r
168     }\r
169     \r
170     private static void updatePathLegNext(PipeControlPoint start, ArrayList<PipeControlPoint> list, PipeControlPoint end, PipeControlPoint updated, PathLegUpdateType lengthChange) {\r
171         updatePathLeg(start,list,end,false,0,new ArrayList<ExpandIterInfo>(),updated, lengthChange);\r
172     }\r
173     \r
174     private static class UpdateStruct2 {\r
175         public PipeControlPoint start;\r
176                 public Point3d startPoint;\r
177                 public ArrayList<PipeControlPoint> list;\r
178                 public PipeControlPoint end;\r
179                 public Point3d endPoint;\r
180                 public Vector3d dir;\r
181                 public Vector3d offset;\r
182                 public boolean hasOffsets;\r
183                 public int iter;\r
184                 public boolean reversed;\r
185                 public ArrayList<ExpandIterInfo> toRemove;\r
186                 public PipeControlPoint updated;\r
187                 public UpdateStruct2(PipeControlPoint start, Point3d startPoint, ArrayList<PipeControlPoint> list, PipeControlPoint end, Point3d endPoint, Vector3d dir, Vector3d offset, boolean hasOffsets, int iter, boolean reversed, ArrayList<ExpandIterInfo> toRemove, PipeControlPoint updated) {\r
188                         super();\r
189                         this.start = start;\r
190                         this.startPoint = startPoint;\r
191                         this.list = list;\r
192                         this.end = end;\r
193                         this.endPoint = endPoint;\r
194                         this.dir = dir;\r
195                         this.offset = offset;\r
196                         this.hasOffsets = hasOffsets;\r
197                         this.iter = iter;\r
198                         this.reversed = reversed;\r
199                         this.toRemove = toRemove;\r
200                         this.updated = updated;\r
201                 }\r
202                 \r
203                 public String toString() {\r
204                         return start.getResource() + " " + end.getResource() + " " + dir + " " + hasOffsets + " " + offset + " " + iter + " " + toRemove.size();\r
205                 }\r
206                 \r
207     }\r
208     \r
209     private static boolean calculateOffset(Point3d startPoint, Point3d endPoint, ArrayList<PipeControlPoint> list, Vector3d dir, Vector3d offset) {\r
210         boolean hasOffsets = false;\r
211         dir.set(startPoint);\r
212         dir.sub(endPoint);\r
213         dir.normalize();\r
214         offset.set(0.0,0.0,0.0);\r
215         for (PipeControlPoint icp : list) {\r
216                 if (icp.isInstanceOf(ProcessResource.plant3Dresource.OffsettingPoint)) {\r
217                         hasOffsets = true;\r
218                         offset.add(ControlPointTools.getSizeChangeOffsetVector(icp,dir));\r
219                 }\r
220                 else if (icp.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) \r
221                         ErrorLogger.defaultLogError("Updating pipe run, found offset controlpoint " + icp.getResource(), new Exception("ASSERT!"));\r
222         }\r
223         return hasOffsets;\r
224     }\r
225     \r
226     /**\r
227      * @param start starting point of the pipe run\r
228      * @param list list of inline control points in the pipe run\r
229      * @param end ending point of the pipe run\r
230      * @param reversed boolean flag indicating wether start or end control point was modified (if true then end point was modified)\r
231      * @throws TransactionException\r
232      */\r
233     private static void updatePathLeg(PipeControlPoint start, ArrayList<PipeControlPoint> list, PipeControlPoint end, boolean reversed, int iter, ArrayList<ExpandIterInfo> toRemove, PipeControlPoint updated, PathLegUpdateType lengthChange) {\r
234         // FIXME: direction is calculated wrong way!\r
235         boolean hasOffsets = false;\r
236         Vector3d offset = new Vector3d();\r
237         Point3d startPoint = G3DTools.getPoint(start.getWorldPosition());\r
238         Point3d endPoint = G3DTools.getPoint(end.getWorldPosition());\r
239         Vector3d dir = new Vector3d ();\r
240         hasOffsets = calculateOffset(startPoint, endPoint, list, dir, offset);\r
241         updatePathLeg(new UpdateStruct2(start, startPoint, list, end, endPoint, dir, offset, hasOffsets, iter, reversed, toRemove, updated), lengthChange);\r
242         \r
243     }\r
244     \r
245     private static void updatePathLeg(UpdateStruct2 u, PathLegUpdateType lengthChange){\r
246         int directed = 0;\r
247         if (u.start.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint))\r
248                 directed ++;\r
249         if (u.end.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint))\r
250                 directed++;\r
251         switch (directed) {\r
252         case 0:\r
253                 updateFreePathLeg(u,lengthChange);\r
254                 break;\r
255         case 1:\r
256                 updateDirectedPathLeg(u,lengthChange);\r
257                 break;\r
258         case 2:\r
259                 updateDualDirectedPathLeg(u,lengthChange);\r
260                 break;\r
261         }\r
262         \r
263         }\r
264     \r
265     private static void updateFreePathLeg(UpdateStruct2 u, PathLegUpdateType lengthChange) {\r
266         if (DEBUG) System.out.println("PipingRules.updateFreePipeRun " + u + " " + lengthChange);\r
267         checkExpandPathLeg(u, lengthChange);\r
268         }\r
269     \r
270     private static void updateInlineControlPoints(UpdateStruct2 u, boolean checkSizes) {\r
271         if (DEBUG) System.out.println("PipingTools.updateInlineControlPoints() " + u);\r
272         \r
273         if (!u.hasOffsets) {\r
274                 // FIXME : cache positions\r
275                 if (!checkSizes) {\r
276                         for (PipeControlPoint icp : u.list) {\r
277                                 updateInlineControlPoint(icp, u.startPoint, u.endPoint,u.dir);\r
278                         }\r
279                         return;\r
280                 }\r
281                 \r
282                 ArrayList<PipeControlPoint> pathLegPoints = new ArrayList<PipeControlPoint>();\r
283                 pathLegPoints.add(u.start);\r
284                         for (PipeControlPoint icp : u.list) {\r
285                                 //updateInlineControlPoint(icp, u.startPoint, u.endPoint,u.dir);\r
286                                 updateBranchControlPointBranches(icp);\r
287                                 pathLegPoints.add(icp);\r
288                         }\r
289                         pathLegPoints.add(u.end);\r
290                         \r
291                         // TODO : values can be cached in the loop\r
292                         for (int i = 1; i < pathLegPoints.size(); i++) {\r
293                                 PipeControlPoint icp = pathLegPoints.get(i);\r
294 \r
295                                 PipeControlPoint prev;\r
296                                 Point3d prevPos;\r
297                                 prev = pathLegPoints.get(i-1);\r
298                                 prevPos = G3DTools.getPoint(prev.getWorldPosition());\r
299                                 Point3d currentPos = G3DTools.getPoint(icp.getWorldPosition());\r
300                                 \r
301                                 if (icp.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthControlPoint)) {     \r
302                                         if (i != pathLegPoints.size() - 1) {\r
303                                                 PipeControlPoint next;\r
304                                                 Point3d nextPos;\r
305                                                 next = pathLegPoints.get(i + 1);\r
306                                                 nextPos = G3DTools.getPoint(next.getWorldPosition());\r
307                                                 Vector3d dir = new Vector3d(nextPos);\r
308                                                 dir.sub(prevPos);\r
309                                                 double l = dir.lengthSquared();          // distance between control points (square)\r
310                                                 double l2prev = ControlPointTools.getInlineLength(prev);          // distance taken by components\r
311                                                 double l2next = ControlPointTools.getInlineLength(next); \r
312                                                 double l2 = l2prev + l2next;\r
313                                                 double l2s = MathTools.square(l2);\r
314                                                 if (l2s < l) {                         // check if there is enough space for variable length component.\r
315                                                         // components fit\r
316                                                         dir.normalize();\r
317                                                         double length = Math.sqrt(l) - l2; // true length of the variable length component \r
318                                                         dir.scale(length*0.5 + l2prev);      // calculate center position of the component\r
319                                                         dir.add(prevPos);\r
320                                                         ControlPointTools.setWorldPosition(icp,dir);\r
321                                                         icp.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, length);\r
322                                                 } else {\r
323                                                         //components leave no space to the component and it must be removed\r
324                                                         ControlPointTools.removeControlPoint(icp);\r
325                                                 }\r
326 \r
327                                         } else {\r
328                                                 // this is variable length component at the end of the piperun.\r
329                                                 // the problem is that we want to keep unconnected end of the component in the same\r
330                                                 // place, but center of the component must be moved.\r
331                                                 double currentLength = icp.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength);\r
332                                                 Vector3d dir = new Vector3d();\r
333                                                 dir.sub(currentPos,prevPos);\r
334                                                 dir.normalize();\r
335                                                 Point3d endPos = new Point3d(dir);\r
336                                                 endPos.scale(currentLength * 0.5);\r
337                                                 endPos.add(currentPos);             //this is the free end of the component\r
338                                                 \r
339                                                 double offset = ControlPointTools.getInlineLength(prev);\r
340                                                 Point3d beginPos = new Point3d(dir);\r
341                                                 beginPos.scale(offset);\r
342                                                 beginPos.add(prevPos);              //this is the connected end of the component\r
343                                                 \r
344                                                 double l = beginPos.distance(endPos);\r
345                                                 \r
346                                                 dir.scale(l*0.5);\r
347                                                 beginPos.add(dir);                  //center position\r
348                                                 \r
349                                                 if (DEBUG) System.out.println("PipingRules.updateInlineControlPoints() setting variable length to " + l);\r
350                                                 icp.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, l);\r
351                                                 \r
352                                                 ControlPointTools.setWorldPosition(icp, beginPos);\r
353                                         }\r
354                                         i++;\r
355                                         \r
356                                 } else if (!prev.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthControlPoint)){\r
357                                         // If this and previous control point are not variable length pcps, we'll have to check if there is no empty space between them.\r
358                                         // I there is, we'll have to create new variable length component between them.\r
359                                         Vector3d dir = new Vector3d(currentPos);\r
360                                         dir.sub(prevPos);\r
361                                         double l = dir.lengthSquared();\r
362                                         double l2prev = ControlPointTools.getInlineLength(prev);\r
363                                         double l2next = ControlPointTools.getInlineLength(icp);\r
364                                         double l2 = l2prev + l2next;\r
365                                         double l2s = l2 * l2;\r
366                                         if (l > l2s) {\r
367                                                 PipelineComponent component = PipingTools2.instantiatePipelineComponent(prev.getGraph(), ControlPointTools.getPipeRun(prev).getResource(), ProcessResource.plant3Dresource.Straight);\r
368                                                 PipeControlPoint scp = component.getControlPoint();\r
369                                                 ControlPointTools.insertControlPoint(scp, prev, icp);\r
370                                                 \r
371                                                 dir.normalize();\r
372                                                 double length = Math.sqrt(l) - l2; // true length of the variable length component \r
373                                                 dir.scale(length*0.5 + l2prev);      // calculate center position of the component\r
374                                                 dir.add(prevPos);\r
375                                                 ControlPointTools.setWorldPosition(scp, dir);\r
376                                                 scp.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, length);\r
377                                         }\r
378                                 }\r
379                         }\r
380                 } else {\r
381                         u.endPoint.sub(u.offset);\r
382                         // FIXME : straights\r
383                         for (PipeControlPoint icp : u.list) {\r
384                                 updateInlineControlPoint(icp, u.startPoint, u.endPoint,u.dir);\r
385                                 updateBranchControlPointBranches(icp);\r
386                                 if (icp.isInstanceOf(ProcessResource.plant3Dresource.OffsettingPoint)) {\r
387                                         // TODO : offset vector is already calculated and should be\r
388                                         // cached\r
389                                         u.offset = ControlPointTools.getSizeChangeOffsetVector(icp, u.dir);\r
390                                         updateOffsetPoint( icp, u.offset);\r
391                                         u.startPoint.add(u.offset);\r
392                                         u.endPoint.add(u.offset);\r
393                                 }\r
394                         }\r
395                 }\r
396     }\r
397     \r
398     \r
399     \r
400     private static void ppNoOffset(UpdateStruct2 u) {\r
401         if (DEBUG)System.out.println("PipingRules.ppNoOffset() " + u);\r
402         Vector3d offset = new Vector3d();\r
403                 if (u.hasOffsets) {\r
404                 u.dir.normalize();\r
405                 for (PipeControlPoint icp : u.list) {\r
406                         if (icp.isInstanceOf(ProcessResource.plant3Dresource.OffsettingPoint)) {\r
407                                 offset.add(ControlPointTools.getSizeChangeOffsetVector(icp,u.dir));\r
408                         }\r
409                         else if (icp.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) \r
410                                 ErrorLogger.defaultLogError("Updating pipe run, found offset controlpoint " + icp.getResource(), new Exception("ASSERT!"));\r
411                 }\r
412                 }\r
413                 u.offset = offset;\r
414                 checkExpandPathLeg(u,PathLegUpdateType.NONE);\r
415     }\r
416     \r
417     private static void ppNoDir(PipeControlPoint start, Point3d startPoint,ArrayList<PipeControlPoint> list, PipeControlPoint end,Point3d endPoint, boolean hasOffsets,int iter,boolean reversed, ArrayList<ExpandIterInfo> toRemove, PipeControlPoint updated)  {\r
418         if (DEBUG)System.out.println("PipingRules.ppNoDir() " + start.getResource() + " " + end.getResource() + " " + iter + " " + toRemove.size());\r
419         // FIXME : extra loop (dir should be calculated here)\r
420         Vector3d dir = new Vector3d();\r
421         Vector3d offset = new Vector3d();\r
422         hasOffsets = calculateOffset(startPoint, endPoint, list, dir, offset);\r
423         ppNoOffset(new UpdateStruct2(start, startPoint, list, end, endPoint, dir, null, hasOffsets, iter, reversed, toRemove,updated));\r
424     }\r
425     \r
426     private static void checkExpandPathLeg(UpdateStruct2 u, PathLegUpdateType lengthChange)  {\r
427         if (DEBUG)System.out.println("PipingRules.checkExpandPathLeg() " + u + " " + lengthChange);\r
428         if (lengthChange != PathLegUpdateType.NONE) {\r
429                 // FIXME : turns cannot be checked before inline cps are updated, since their position affects calculation of turns \r
430                 processPathLeg(u,false,false);\r
431                 int type = checkTurns(u,lengthChange);\r
432                 if (type == REMOVE_NONE) {\r
433                                 processPathLeg(u,false,true);\r
434                         } else {\r
435                                 expandPathLeg(u, type);\r
436                         }\r
437         } else {\r
438                 processPathLeg(u,false,true);\r
439         }\r
440     }\r
441     \r
442     private static void updateDirectedPathLeg(UpdateStruct2 u, PathLegUpdateType lengthChange) {\r
443                 if (DEBUG)System.out.println("PipingRules.updateDirectedPipeRun() " + u + " " + lengthChange);\r
444                 PipeControlPoint dcp;\r
445                 PipeControlPoint other;\r
446                 boolean canMoveOther = false;\r
447                 boolean dcpStart = false;\r
448                 Point3d position;\r
449                 if (u.start.isInstanceOf(ProcessResource.plant3Dresource.DirectedControlPoint)) {\r
450                         dcp = u.start;\r
451                         other = u.end;\r
452                         position = u.startPoint;\r
453                         dcpStart = true;\r
454                         if (!u.reversed)\r
455                                 canMoveOther = true;\r
456                 } else {\r
457                         dcp = u.end;\r
458                         other = u.start;\r
459                         position = u.endPoint;\r
460                         if (u.reversed)\r
461                                 canMoveOther = true;\r
462                 }\r
463 \r
464                 Vector3d directedDirection = ControlPointTools.getDirectedControlPointDirection(dcp);\r
465                 Point3d directedEndPoint = new Point3d(u.endPoint);\r
466                 if (u.hasOffsets)\r
467                         directedEndPoint.add(u.offset);\r
468 \r
469                 double mu[] = new double[2];\r
470 \r
471                 Vector3d closest;\r
472                 Vector3d t = new Vector3d();\r
473       \r
474                 if (dcpStart) {\r
475                         closest = MathTools.closestPointOnStraight(directedEndPoint, u.startPoint, directedDirection, mu);\r
476                         t.sub(closest, directedEndPoint);\r
477                 } else {\r
478                         closest = MathTools.closestPointOnStraight(u.startPoint, directedEndPoint, directedDirection, mu);\r
479                         t.sub(closest, u.startPoint);\r
480                 }\r
481 \r
482       \r
483       double distance = t.lengthSquared();\r
484       boolean aligned = (distance < 0.001);\r
485       if (aligned) {\r
486           checkExpandPathLeg(u,lengthChange);\r
487       } else {\r
488           if (u.iter > 0) {\r
489                    backIter(u);\r
490           } else {\r
491                         PipeControlPoint nextToMoved;\r
492                         \r
493                                 if (u.list.size() > 0)\r
494                                         if (dcpStart)\r
495                                                 nextToMoved = u.list.get(0);\r
496                                         else\r
497                                                 nextToMoved = u.list.get(u.list.size() - 1);\r
498                                 else if (dcpStart)\r
499                                         nextToMoved = u.end;\r
500                                 else\r
501                                         nextToMoved = u.start;\r
502                                 if (other.isInstanceOf(ProcessResource.plant3Dresource.VariableAngleTurnControlPoint)) {\r
503                                         \r
504                                         // TODO calculate needed space from next run end.\r
505                                         if (mu[0] < 1.0) {\r
506                                                 if (dcpStart) {\r
507                                                         closest.set(u.startPoint);      \r
508                                                 } else {\r
509                                                         closest.set(u.endPoint);\r
510                                                 }\r
511                                                 closest.add(directedDirection);\r
512                                         }\r
513 \r
514                                         if (canMoveOther) {\r
515                                                 if (DEBUG)System.out.println("PipingRules.updateDirectedPipeRun() moved end " + other.getResource() + " to " + closest);\r
516                                                 ControlPointTools.setWorldPosition(other, closest);\r
517                                                 if (dcpStart) {\r
518                                                         ppNoOffset(new UpdateStruct2(u.start, u.startPoint, u.list, u.end, new Point3d(closest), directedDirection,null, u.hasOffsets, u.iter, u.reversed, u.toRemove,u.updated));\r
519                                                         if (u.end.getNext() != null)\r
520                                                                 updatePathLegNext(u.end,u.updated,PathLegUpdateType.NEXT);\r
521                                                 } else {\r
522                                                         ppNoOffset(new UpdateStruct2(u.start, new Point3d(closest), u.list, u.end, u.endPoint, directedDirection,null, u.hasOffsets, u.iter, u.reversed, u.toRemove,u.updated));        \r
523                                                         if (u.start.getPrevious() != null)\r
524                                                                 updatePathLegPrev(u.start,u.updated,PathLegUpdateType.PREV);\r
525                                                 }\r
526                                         } else {\r
527                                                 // TODO : calculate needed space from next run end.\r
528                                                 insertElbowUpdate(u, dcp, nextToMoved, dcpStart, position, directedDirection);\r
529                                         }\r
530                                 } else if (other.isInstanceOf(ProcessResource.plant3Dresource.UndirectedControlPoint) &&\r
531                                                    other.getSubPointOf() != null) {\r
532                                         // FIXME : this code was for updating branches\r
533                                         Vector3d bintersect = new Vector3d();\r
534                                         PipeControlPoint bcp = other.getSubPointOf();\r
535                                         if (bcp != null && canMoveOther) {\r
536                                                 Point3d bstart = new Point3d();\r
537                                                 Point3d bend = new Point3d();\r
538                                                 Vector3d bdir = new Vector3d();\r
539                                                 ControlPointTools.getInlineControlPointEnds(bcp, bstart, bend, bdir);\r
540                                                 Vector3d nintersect = new Vector3d();\r
541                                                 \r
542                                                 MathTools.intersectStraightStraight(position, directedDirection, bstart,\r
543                                                         bdir, nintersect, bintersect, mu);\r
544                                                 Vector3d dist = new Vector3d(nintersect);\r
545                                                 dist.sub(bintersect);\r
546                                                 canMoveOther = mu[1] > 0.0 && mu[1] < 1.0 && dist.lengthSquared() < 0.01;\r
547                                         } else {\r
548                                                 // TODO : endControlPoints are undirected: calculcate correct position for it\r
549                                                 throw new UnsupportedOperationException("not implemented");\r
550                                         }\r
551                                         if (canMoveOther) { \r
552                                                 if (DEBUG) System.out.println("PipingRules.updateDirectedPipeRun() moved end " + other.getResource() + " to " + bintersect);\r
553                                                 // is required branch position is in possible range\r
554                                                 ControlPointTools.setWorldPosition(bcp, bintersect);\r
555                                                 if (dcpStart) {\r
556                                                         checkExpandPathLeg(new UpdateStruct2(u.start, u.startPoint, u.list, u.end, new Point3d(bintersect),directedDirection, u.offset, u.hasOffsets, u.iter, u.reversed, u.toRemove,u.updated),lengthChange);\r
557                                                 } else {\r
558                                                         checkExpandPathLeg(new UpdateStruct2(u.start, new Point3d(bintersect), u.list, u.end, u.endPoint,directedDirection, u.offset, u.hasOffsets, u.iter, u.reversed, u.toRemove,u.updated),lengthChange);    \r
559                                                 }\r
560                                         } else {\r
561                                                 // branch cannot be moved into right position, new turn\r
562                                                 // / elbow must be inserted\r
563                                                 insertElbowUpdate(u , dcp, nextToMoved, dcpStart, position, directedDirection);\r
564                                         }\r
565 \r
566                                 } else { // assume that control point cannot be moved, but can be rotated\r
567                                         insertElbowUpdate(u, dcp, nextToMoved, dcpStart, position, directedDirection);\r
568                                 }\r
569           }\r
570       }\r
571         }\r
572     \r
573     \r
574     \r
575     private static void updateDualDirectedPathLeg(UpdateStruct2 u, PathLegUpdateType lengthChange) {\r
576                 if (DEBUG) System.out.println("PipingRules.updateDualDirectedPipeRun() " + u + " " + lengthChange);\r
577 \r
578                 PipeControlPoint dcp1 = u.start;\r
579                 PipeControlPoint dcp2 = u.end;\r
580                 Point3d position1 = u.startPoint;\r
581                 Point3d position2 = u.endPoint;\r
582                 Point3d position1offset = new Point3d(position1);\r
583                 position1offset.sub(u.offset);\r
584                 Point3d position2offset = new Point3d(position2);\r
585                 position2offset.add(u.offset);\r
586                 Vector3d dir1 = ControlPointTools.getDirectedControlPointDirection(dcp1);\r
587                 Vector3d dir2 = ControlPointTools.getDirectedControlPointDirection(dcp2);\r
588                 Vector3d p1 = MathTools.closestPointOnStraight(position1offset, position2, dir2);\r
589                 Vector3d p2 = MathTools.closestPointOnStraight(position2offset, position1, dir1);\r
590                 double d1 = position1.distance(new Point3d(p1));\r
591                 double d2 = position2.distance(new Point3d(p2));\r
592 \r
593                 boolean aligned = (d1 < 0.01 && d2 < 0.01);\r
594                 if (aligned) {\r
595                         processPathLeg(u);\r
596                 } else {\r
597                         if (u.iter > 0) {\r
598                                 backIter(u);\r
599                         } else {\r
600                                 PipeControlPoint dcp;\r
601                                 PipeControlPoint next;\r
602                                 if (!u.reversed) {\r
603                                         dcp = dcp1;\r
604                                         if (u.list.size() > 0)\r
605                                                 next = u.list.get(0);\r
606                                         else\r
607                                                 next = dcp2;\r
608                                 } else {\r
609                                         dcp = dcp2;\r
610                                         if (u.list.size() > 0)\r
611                                                 next = u.list.get(u.list.size() - 1);\r
612                                         else\r
613                                                 next = dcp1;\r
614                                 }\r
615 \r
616                                 PipeRun pipeline = ControlPointTools.getPipeRun(dcp1);\r
617                                 PipelineComponent elbow1 = PipingTools2.instantiatePipelineComponent(u.start.getGraph(), pipeline.getResource(), ProcessResource.plant3Dresource.Elbow);\r
618                                 PipelineComponent elbow2 = PipingTools2.instantiatePipelineComponent(u.start.getGraph(), pipeline.getResource(), ProcessResource.plant3Dresource.Elbow);\r
619                                 \r
620                                 PipeControlPoint tcp1 = elbow1.getControlPoint();\r
621                                 PipeControlPoint tcp2 = elbow2.getControlPoint();\r
622                                 \r
623                                 // Straight s1 = getStraight(dcp, next);\r
624                                 ControlPointTools.insertControlPoint(tcp1, dcp, next);\r
625                                 // s1 = getStraight(tcp1, next);\r
626                                 ControlPointTools.insertControlPoint(tcp2, tcp1, next);\r
627                                 p1 = G3DTools.getVector(dcp.getLocalPosition());\r
628                                 if (!u.reversed)\r
629                                         p1.add(dir1);\r
630                                 else\r
631                                         p1.add(dir2);\r
632                                 \r
633                                 if (!u.reversed)\r
634                                         p2 = MathTools.closestPointOnStraight(new Point3d(p1), position2, dir2);\r
635                                 else\r
636                                         p2 = MathTools.closestPointOnStraight(new Point3d(p1), position1, dir1);\r
637                                 \r
638                                 ControlPointTools.setWorldPosition(tcp1, p1);\r
639                                 ControlPointTools.setWorldPosition(tcp2, p2);\r
640                                 \r
641                                 if (DEBUG) System.out.println("PipingRules.updateDualDirectedPipeRun() created two turns " + tcp1.getResource() + " " + tcp2.getResource());\r
642 \r
643                                 if (!u.reversed) {\r
644                                         Vector3d dd = new Vector3d(p2);\r
645                                         dd.sub(p1);\r
646                                         dir2.negate();\r
647                                         processPathLeg(new UpdateStruct2(u.start, u.startPoint,new ArrayList<PipeControlPoint>(), tcp1, new Point3d(p1),dir1, new Vector3d(), false, 0, false,new ArrayList<ExpandIterInfo>(), u.updated));\r
648                                         processPathLeg(new UpdateStruct2(tcp1,new Point3d(p1), new ArrayList<PipeControlPoint>(),tcp2, new Point3d(p2), dd,new Vector3d(), false, 0, false,new ArrayList<ExpandIterInfo>(), u.updated));\r
649                                         // offset is recalculated\r
650                                         processPathLegNoOffset(new UpdateStruct2(tcp2, new Point3d(p2), u.list,u.end, u.endPoint, dir2, null, u.hasOffsets,u.iter, u.reversed, u.toRemove, u.updated));\r
651                                 } else {\r
652                                         Vector3d dd = new Vector3d(p1);\r
653                                         dd.sub(p2);\r
654                                         dir2.negate();\r
655                                         processPathLeg(new UpdateStruct2(tcp1,new Point3d(p1), new ArrayList<PipeControlPoint>(),u.end, u.endPoint, dir2, new Vector3d(), false, 0,false, new ArrayList<ExpandIterInfo>(), u.updated));\r
656                                         processPathLeg(new UpdateStruct2(tcp2,new Point3d(p2), new ArrayList<PipeControlPoint>(),tcp1, new Point3d(p1), dd,new Vector3d(), false, 0, false,new ArrayList<ExpandIterInfo>(), u.updated));\r
657                                         // offset is recalculated\r
658                                         processPathLegNoOffset(new UpdateStruct2(u.start, u.startPoint,u.list, tcp2, new Point3d(p2),dir1, null, u.hasOffsets, u.iter, u.reversed,u.toRemove, u.updated));\r
659                                 }\r
660                         }\r
661                 }\r
662         }\r
663     \r
664     private static void insertElbowUpdate(UpdateStruct2 u, PipeControlPoint dcp, PipeControlPoint next, boolean dcpStart, Point3d position, Vector3d directedDirection) {\r
665          \r
666         Vector3d closest = new Vector3d(position);\r
667                 closest.add(directedDirection);\r
668                 PipeControlPoint tcp = insertElbow(dcp, next, new Point3d(closest));\r
669 \r
670                 if (DEBUG) System.out.println("PipingRules.updateDirectedPipeRun() inserted " + tcp.getResource());\r
671                 \r
672                 if (dcpStart) {\r
673                         // update pipe run from new turn to other end\r
674                         ppNoDir(tcp, new Point3d(closest), u.list, u.end, u.endPoint, u.hasOffsets, u.iter, u.reversed, u.toRemove, u.updated);\r
675                         // update pipe run from directed to new turn\r
676                         processPathLeg(new UpdateStruct2(u.start, u.startPoint, new ArrayList<PipeControlPoint>(), tcp, new Point3d(closest), directedDirection, new Vector3d(), false, 0, false, new ArrayList<ExpandIterInfo>(),u.updated));                  \r
677                 } else {\r
678                         // update pipe run from other end to new turn\r
679                         ppNoDir(u.start, u.startPoint, u.list, tcp, new Point3d(closest),  u.hasOffsets, u.iter, u.reversed, u.toRemove,u.updated);\r
680                         // update pipe run from new turn to directed\r
681                         processPathLeg(new UpdateStruct2(tcp, new Point3d(closest), new ArrayList<PipeControlPoint>(), u.end, u.endPoint, directedDirection, new Vector3d(), false, 0, false, new ArrayList<ExpandIterInfo>(),u.updated));\r
682                 }\r
683     }\r
684     \r
685     /**\r
686      * Checks if turns can be removed (turn angle near zero)\r
687      */\r
688     private static int checkTurns(UpdateStruct2 u, PathLegUpdateType lengthChange) {\r
689                 if (DEBUG)\r
690                         System.out.println("PipingRules.checkTurns() " + u.start.getResource()\r
691                                         + " " + u.end.getResource());\r
692                 boolean startRemoved = false;\r
693                 boolean endRemoved = false;\r
694                 if (u.start.isInstanceOf(ProcessResource.plant3Dresource.VariableAngleTurnControlPoint)) {\r
695                         // this won't work properly if inline control points are not updated\r
696                         PipeControlPoint startPrev = u.start.getPrevious();\r
697                         if (startPrev != null) {\r
698                                 double a;\r
699                                 if (!u.hasOffsets) {\r
700                                         a = updateTurnControlPointTurn( u.start, startPrev, u.end);\r
701                                 } else {\r
702                                         Point3d ep = new Point3d(u.endPoint);\r
703                                         ep.add(u.offset);\r
704                                         a = updateTurnControlPointTurn( u.start,u.startPoint, G3DTools.getPoint(startPrev.getLocalPosition()), ep);\r
705 \r
706                                 }\r
707                                 if (a < MIN_TURN_ANGLE)\r
708                                         startRemoved = true;\r
709                                 else if (lengthChange == PathLegUpdateType.PREV || lengthChange == PathLegUpdateType.PREV_S){\r
710                                         PathLegUpdateType type;\r
711                                         if (lengthChange == PathLegUpdateType.PREV_S)\r
712                                                 type = PathLegUpdateType.PREV;\r
713                                         else\r
714                                                 type = PathLegUpdateType.NONE;\r
715                                         updatePathLegPrev(u.start, u.start, type);\r
716                                 }\r
717                         }\r
718                 }\r
719                 if (u.end.isInstanceOf(ProcessResource.plant3Dresource.VariableAngleTurnControlPoint)) {\r
720 \r
721                         PipeControlPoint endNext = u.end.getNext();\r
722                         if (endNext != null) {\r
723                                 double a;\r
724                                 if (!u.hasOffsets) {\r
725                                         a = updateTurnControlPointTurn(u.end,u.start, endNext);\r
726                                 } else {\r
727                                         Point3d sp = new Point3d(u.startPoint);\r
728                                         sp.sub(u.offset);\r
729                                         a = updateTurnControlPointTurn(u.end, u.endPoint, sp, G3DTools.getPoint(endNext.getLocalPosition()));\r
730                                 }\r
731                                 if (a < MIN_TURN_ANGLE)\r
732                                         endRemoved = true;\r
733                                 else if (lengthChange == PathLegUpdateType.NEXT || lengthChange == PathLegUpdateType.NEXT_S){\r
734                                         PathLegUpdateType type;\r
735                                         if (lengthChange == PathLegUpdateType.NEXT_S)\r
736                                                 type = PathLegUpdateType.NEXT;\r
737                                         else\r
738                                                 type = PathLegUpdateType.NONE;\r
739                                         updatePathLegNext(u.end, u.end,type);\r
740                                 }\r
741                         }\r
742                 }\r
743                 if (DEBUG)\r
744                         System.out.println("PipingRules.checkTurns() res " + startRemoved + " " + endRemoved);\r
745                 if (!startRemoved && !endRemoved)\r
746                         return REMOVE_NONE;\r
747                 if (startRemoved && endRemoved)\r
748                         return REMOVE_BOTH;\r
749                 if (startRemoved)\r
750                         return REMOVE_START;\r
751                 return REMOVE_END;\r
752         }\r
753     \r
754     /**\r
755          * Expands piperun search over turns that are going to be removed\r
756          * \r
757          */\r
758     private static void expandPathLeg(UpdateStruct2 u, int type) {\r
759         if (DEBUG) System.out.println("PipingRules.expandPipeline " + u.start.getResource() + " " + u.end.getResource());\r
760         ArrayList<PipeControlPoint> newList = new ArrayList<PipeControlPoint> ();\r
761         switch (type) {\r
762         case REMOVE_NONE :\r
763                 throw new RuntimeException("Error in piping rules");\r
764         case REMOVE_START :\r
765                 u.toRemove.add(new ExpandIterInfo(u.start,REMOVE_START));\r
766                 u.start = ControlPointTools.findPreviousEnd(u.start);\r
767                 u.startPoint = G3DTools.getPoint(u.start.getLocalPosition());\r
768                 ControlPointTools.findNextEnd(u.start,newList);\r
769                 newList.addAll(u.list);\r
770                 u.list = newList;\r
771                 break;\r
772         case REMOVE_END :\r
773                 u.toRemove.add(new ExpandIterInfo(u.end,REMOVE_END));\r
774                 u.end = ControlPointTools.findNextEnd(u.end,newList);\r
775                 u.endPoint = G3DTools.getPoint(u.end.getLocalPosition());\r
776                 u.list.addAll(newList);\r
777                 break;\r
778         case REMOVE_BOTH :\r
779                 u.toRemove.add(new ExpandIterInfo(u.start,u.end));\r
780                 u.start = ControlPointTools.findPreviousEnd(u.start);\r
781                 u.startPoint = G3DTools.getPoint(u.start.getLocalPosition());\r
782                 ControlPointTools.findNextEnd(u.start,newList);\r
783                 newList.addAll(u.list);\r
784                 u.list = newList;\r
785                 newList = new ArrayList<PipeControlPoint> ();\r
786                 u.end = ControlPointTools.findNextEnd(u.end,newList);\r
787                 u.endPoint = G3DTools.getPoint(u.end.getLocalPosition());\r
788                 u.list.addAll(newList);\r
789                 break;\r
790         default:\r
791                 throw new RuntimeException("Error in piping rules");\r
792                         \r
793         }\r
794         u.offset = new Vector3d();\r
795         if (u.hasOffsets) {\r
796                 u.dir.normalize();\r
797                 for (PipeControlPoint icp : u.list) {\r
798                         if (icp.isInstanceOf(ProcessResource.plant3Dresource.OffsettingPoint)) {\r
799                                 u.offset.add(ControlPointTools.getSizeChangeOffsetVector(icp,u.dir));\r
800                         }\r
801                         else if (icp.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) \r
802                                 ErrorLogger.defaultLogError("Updating pipe run, found offset controlpoint " + icp.getResource(), new Exception("ASSERT!"));\r
803                 }\r
804                 }\r
805         if (DEBUG) System.out.println("PipingRules.expandPipeline expanded " + u.start.getResource() + " " + u.end.getResource());\r
806         u.iter++;\r
807         updatePathLeg(u,PathLegUpdateType.NONE);\r
808     }\r
809     \r
810     /**\r
811          * reverts one iteration of turn removing back)\r
812      */\r
813     private static void backIter(UpdateStruct2 u) {\r
814                 \r
815                 if (DEBUG) System.out.println("PipingRules.backIter" + u.start.getResource() + " " + u.end.getResource());      \r
816                 if (u.iter == 0)\r
817                         throw new RuntimeException("Error in piping rules");\r
818                 ExpandIterInfo info = u.toRemove.get(u.toRemove.size()-1);\r
819                 u.toRemove.remove(u.toRemove.size()-1);\r
820                 if (info.getType() == REMOVE_START || info.getType() == REMOVE_BOTH) {\r
821                         while (u.list.size() > 0) {\r
822                                 PipeControlPoint icp = u.list.get(0);\r
823                                 if (icp.getPrevious().getResource().equals(info.getStart().getResource()))  \r
824                                         break;\r
825                                 u.list.remove(icp);\r
826                         }\r
827                         u.start = info.getStart();      \r
828                 } \r
829                 if (info.getType() == REMOVE_END || info.getType() == REMOVE_BOTH) {\r
830                         while (u.list.size() > 0) {\r
831                                 PipeControlPoint icp = u.list.get(u.list.size() - 1);\r
832                                 if (icp.getNext().getResource().equals(info.getEnd().getResource())) \r
833                                         break;\r
834                                 u.list.remove(icp);\r
835                         }\r
836                         u.end = info.getEnd();\r
837                 }\r
838                 u.offset = new Vector3d();\r
839                 if (u.hasOffsets) {\r
840                 u.dir.normalize();\r
841                 for (PipeControlPoint icp : u.list) {\r
842                         if (icp.isInstanceOf(ProcessResource.plant3Dresource.OffsettingPoint)) {\r
843                                 u.offset.add(ControlPointTools.getSizeChangeOffsetVector(icp,u.dir));\r
844                         }\r
845                         else if (icp.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) \r
846                                 ErrorLogger.defaultLogError("Updating pipe run, found offset controlpoint " + icp.getResource(), new Exception("ASSERT!"));\r
847                 }\r
848                 }\r
849                 processPathLeg(u);\r
850         \r
851     }\r
852     \r
853     /**\r
854      * Processes pipe run (removes necessary turns and updates run ends)\r
855      */\r
856    // private static void processPathLeg(PipeControlPoint start, Point3d startPoint,ArrayList<InlineControlPoint> list, PipeControlPoint end,Point3d endPoint, Vector3d dir,Vector3d offset, boolean hasOffsets,int iter, boolean reversed, ArrayList<ExpandIterInfo> toRemove) throws TransactionException {\r
857          \r
858     private static void processPathLeg(UpdateStruct2 u) {\r
859         if (DEBUG) System.out.println("PipingRules.processPathLeg " + u.start.getResource() + " " + u.end.getResource());\r
860         processPathLeg(u, true, true);\r
861     }\r
862     \r
863     \r
864     private static void processPathLeg(UpdateStruct2 u, boolean updateEnds, boolean updateInline) {\r
865         if (DEBUG) System.out.println("PipingRules.processPathLeg " + u.start.getResource() + " " + u.end.getResource());\r
866         if (u.toRemove.size() > 0) {\r
867                 for (ExpandIterInfo info : u.toRemove) {\r
868                         if (info.getStart() != null) {\r
869                                 ControlPointTools.removeControlPoint(info.getStart());\r
870                         }\r
871                         if (info.getEnd() != null) {\r
872                                 ControlPointTools.removeControlPoint(info.getEnd());\r
873                         }\r
874                 }\r
875                 // ControlPointTools.removeControlPoint may remove mo0re than one CP;\r
876                 // we must populate inline CP list again.\r
877                 u.list.clear();\r
878                 ControlPointTools.findNextEnd(u.start, u.list);\r
879                 }\r
880         // FIXME : inline CPs are update twice because their positions must be updated before and after ends.      \r
881         updateInlineControlPoints(u,false);\r
882                 if (updateEnds) {\r
883                         if (u.start.isInstanceOf(ProcessResource.plant3Dresource.TurnControlPoint)) {\r
884                                 updateTurnControlPointTurn(u.start, u.start.getPrevious(), u.start.getNext());\r
885                                 updatePathLegPrev(u.start, u.start, PathLegUpdateType.NONE);\r
886                         } else if (u.start.isInstanceOf(ProcessResource.plant3Dresource.EndComponentControlPoint)) {\r
887                                 updateEndComponentControlPoint(u.start, u.startPoint, u.endPoint);\r
888                         }\r
889                         if (u.end.isInstanceOf(ProcessResource.plant3Dresource.TurnControlPoint)) {\r
890                                 updateTurnControlPointTurn( u.end, u.end.getPrevious(), u.end.getNext());\r
891                                 updatePathLegNext(u.end, u.end, PathLegUpdateType.NONE);\r
892                         } else if (u.end.isInstanceOf(ProcessResource.plant3Dresource.EndComponentControlPoint)) {\r
893                                 updateEndComponentControlPoint(u.end, u.startPoint, u.endPoint);\r
894                         }\r
895                         \r
896                 } else {\r
897                         if (u.start.isInstanceOf(ProcessResource.plant3Dresource.EndComponentControlPoint)) {\r
898                                 updateEndComponentControlPoint(u.start, u.startPoint, u.endPoint);\r
899                         }\r
900                         if (u.end.isInstanceOf(ProcessResource.plant3Dresource.EndComponentControlPoint)) {\r
901                                 updateEndComponentControlPoint( u.end, u.startPoint, u.endPoint);\r
902                         }\r
903                 }\r
904                 if(updateInline)\r
905                         updateInlineControlPoints(u,true);\r
906         \r
907     }\r
908     \r
909     /**\r
910          * Processes pipe run and recalculates offset\r
911      */\r
912     //private static void processPathLeg(PipeControlPoint start, Point3d startPoint,ArrayList<InlineControlPoint> list, PipeControlPoint end,Point3d endPoint, Vector3d dir, boolean hasOffsets,int iter, boolean reversed, ArrayList<ExpandIterInfo> toRemove) throws TransactionException {\r
913     private static void processPathLegNoOffset(UpdateStruct2 u) {\r
914         if (DEBUG) System.out.println("PipingRules.processPathLeg " + u.start.getResource() + " " + u.end.getResource());\r
915         Vector3d offset = new Vector3d();\r
916         if (u.hasOffsets) {\r
917                 u.dir.normalize();\r
918             for (PipeControlPoint icp : u.list) {\r
919                 if (icp.isInstanceOf(ProcessResource.plant3Dresource.OffsetComponent)) {\r
920                         offset.add(ControlPointTools.getSizeChangeOffsetVector(icp,u.dir));\r
921                 } else if (icp.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) {\r
922                         ErrorLogger.defaultLogError("Updating pipe run, found offset controlpoint " + icp.getResource(), new Exception("ASSERT!"));\r
923                 }\r
924             }\r
925         }       \r
926         processPathLeg(u);\r
927     }\r
928     \r
929     private static void updateOffsetPoint(PipeControlPoint sccp, Vector3d offset) {\r
930                 Point3d world = G3DTools.getPoint(sccp.getWorldPosition());\r
931                 world.add(offset);\r
932                 PipeControlPoint ocp = sccp.getSubPoint().iterator().next();\r
933                 ControlPointTools.setWorldPosition(ocp, world);\r
934     }\r
935     \r
936     private static void updatePathLegPrev(PipeControlPoint start, PipeControlPoint updated, PathLegUpdateType lengthChange) {\r
937         ArrayList<PipeControlPoint> list = new ArrayList<PipeControlPoint>();\r
938         PipeControlPoint end = ControlPointTools.findPreviousEnd(start,list);\r
939         updatePathLegPrev(start, list, end,updated,lengthChange);\r
940     }\r
941     \r
942     private static void updatePathLegPrev(PipeControlPoint start, ArrayList<PipeControlPoint> list, PipeControlPoint end, PipeControlPoint updated, PathLegUpdateType lengthChange) {\r
943         // reverses the list\r
944         ArrayList<PipeControlPoint> nextList = new ArrayList<PipeControlPoint>();\r
945         for (PipeControlPoint icp : list) {\r
946                 if (icp.isInstanceOf(ProcessResource.plant3Dresource.DualSubControlPoint)) {\r
947                         nextList.add(0, icp.getSubPointOf());\r
948                 } else {\r
949                         nextList.add(0,icp);\r
950                 }\r
951                 \r
952         }\r
953         updatePathLeg(end, nextList, start, true,0,new ArrayList<ExpandIterInfo>(),updated,lengthChange);\r
954         \r
955     }\r
956 \r
957     \r
958     /**\r
959      * Updates InlineControlPoints position when straight pipe's end(s) have\r
960      * been changed)\r
961      * \r
962      * @param pipeline\r
963      * @param icp\r
964      * @param nextPoint\r
965      * @param prevPoint\r
966      */\r
967     private static void updateInlineControlPoint( PipeControlPoint icp, Point3d nextPoint, Point3d prevPoint, Vector3d dir) {\r
968         if (DEBUG) System.out.println("PipingRules.updateInlineControlPoint() " + icp.getResource());\r
969         \r
970         Point3d inlinePoint = G3DTools.getPoint(icp.getLocalPosition());\r
971         if (DEBUG) System.out.print("InlineControlPoint update "+icp.getResource() + " " + inlinePoint + " " + prevPoint + " " + nextPoint);\r
972         Vector3d newInlinePoint = null;\r
973         boolean branchUpdate = false;\r
974         PipeControlPoint becp = null;\r
975         for (PipeControlPoint pcp : icp.getSubPoint())\r
976                 if (pcp.isInstanceOf(ProcessResource.plant3Dresource.UndirectedControlPoint)) {\r
977                         branchUpdate = true;\r
978                         becp = pcp;\r
979                         break;\r
980                 }\r
981                         \r
982         if (DUMMY || !branchUpdate) {\r
983                 newInlinePoint = MathTools.closestPointOnEdge(new Vector3d(inlinePoint), new Vector3d(nextPoint), new Vector3d(prevPoint));\r
984         } else {\r
985                 \r
986                 // FIXME : can only handle one branch\r
987                 PipeControlPoint p = null;\r
988                 if (becp.getNext() != null) {\r
989                         p = ControlPointTools.findNextEnd(becp);\r
990                 } else if (becp.getPrevious() != null) {\r
991                         p = ControlPointTools.findPreviousEnd(becp);\r
992                 } \r
993                 if (p == null) {\r
994                         newInlinePoint = MathTools.closestPointOnEdge(new Vector3d(inlinePoint), new Vector3d(nextPoint), new Vector3d(prevPoint));\r
995                 } else {\r
996                         Point3d branchLegEnd = G3DTools.getPoint(p.getLocalPosition());\r
997                         Vector3d dir2 = new Vector3d(inlinePoint);\r
998                         dir2.sub(branchLegEnd);\r
999                         Vector3d dir1 = new Vector3d(nextPoint);\r
1000                         dir1.sub(prevPoint);\r
1001                         newInlinePoint = new Vector3d();\r
1002                         double mu[] = new double[2];\r
1003                         MathTools.intersectStraightStraight(new Vector3d(prevPoint), dir1, new Vector3d(branchLegEnd), dir2, newInlinePoint, new Vector3d(),mu);\r
1004                         if (DEBUG) System.out.println(mu[0]);\r
1005                         // FIXME : reserve space \r
1006                         if (mu[0] < 0.0) {\r
1007                                 newInlinePoint = new Vector3d(prevPoint);\r
1008                         } else if (mu[0] > 1.0) {\r
1009                                 newInlinePoint = new Vector3d(nextPoint);\r
1010                         }\r
1011                 }\r
1012         }\r
1013         if (DEBUG) System.out.println(" " + newInlinePoint);\r
1014         \r
1015         ControlPointTools.setWorldPosition(icp, newInlinePoint);\r
1016         updateControlPointOrientation(icp);\r
1017     }\r
1018     \r
1019     /**\r
1020      * Updates InlineControlPoints position when straight pipe's end(s) have\r
1021      * been changed)\r
1022      * \r
1023      * @param pipeline\r
1024      * @param icp\r
1025      * @param nextPoint\r
1026      * @param prevPoint\r
1027      */\r
1028     private static void updateEndComponentControlPoint( PipeControlPoint ecp, Point3d start, Point3d end) {\r
1029         if (DEBUG) System.out.println("PipingRules.updateEndComponentControlPoint() " + ecp.getResource());\r
1030 //        PipeControlPoint next = ecp.getNext();\r
1031 //        PipeControlPoint prev = ecp.getPrevious();\r
1032 //        if (next != null) {\r
1033 //              end = G3DTools.getPoint(next.getLocalPosition());\r
1034 //              start = G3DTools.getPoint(ecp.getLocalPosition());\r
1035 //        } else if (prev != null) {\r
1036 //              end = G3DTools.getPoint(ecp.getLocalPosition());\r
1037 //              start = G3DTools.getPoint(prev.getLocalPosition());\r
1038 //        } else {\r
1039 //              // TODO : warning?\r
1040 //              return;\r
1041 //        }\r
1042         //Vector3d dir = new Vector3d (end);\r
1043         //dir.sub(start);\r
1044         //dir.normalize();\r
1045         //G3DTools.setTuple(ecp.getDirection(), dir);\r
1046         \r
1047         updateControlPointOrientation(ecp);\r
1048         \r
1049         for (PipeControlPoint pcp : ecp.getSubPoint()) {\r
1050                 // TODO update position\r
1051                 updatePathLegEndControlPoint(pcp);\r
1052         }\r
1053     }\r
1054     \r
1055     private static void updateControlPointOrientation(PipeControlPoint pcp) {\r
1056         // FIXME : hack to bypass variable length components orientation\r
1057         if (pcp.getAtMostOneRelatedObject(ProcessResource.g3dResource.HasWorldOrientation) == null)\r
1058                 return;\r
1059         Double angleO = pcp.getAtMostOneRelatedScalarDouble(ProcessResource.plant3Dresource.HasRotationAngle);\r
1060         double angle = 0.0;\r
1061         if (angleO != null)\r
1062                 angle = angleO;\r
1063         \r
1064         AxisAngle4d aa = ControlPointTools.getControlPointWorldRotation(pcp, angle);\r
1065         ControlPointTools.setWorldOrientation(pcp,aa);\r
1066         \r
1067     }\r
1068 \r
1069     /**\r
1070      * Updates all branches when branch's position has been changed\r
1071      * @param bcp\r
1072      */\r
1073     private static void updateBranchControlPointBranches(PipeControlPoint bcp) {\r
1074         if (DEBUG) System.out.println("PipingRules.updateBranchControlPointBranches() " + bcp.getResource());\r
1075         Collection<PipeControlPoint> branches = bcp.getSubPoint();\r
1076         if (branches.size() == 0) {\r
1077             if (DEBUG) System.out.println("No Branches found");\r
1078             return;\r
1079         }\r
1080         for (PipeControlPoint pcp : branches) {\r
1081                 updatePathLegEndControlPoint(pcp);\r
1082         }\r
1083     }\r
1084     \r
1085     /**\r
1086      * Recalculates turn control point's internal data (turn angle and offset)\r
1087      * @param tcp\r
1088      * @param prev\r
1089      * @param next\r
1090      */\r
1091     private static double updateTurnControlPointTurn( PipeControlPoint tcp, PipeControlPoint prev, PipeControlPoint next) {\r
1092         if (DEBUG) System.out.println("PipingTools.updateTurnControlPointTurn()" + tcp.getResource());\r
1093         if (next == null || prev == null)\r
1094             return Math.PI; // FIXME : argh\r
1095         Point3d middlePoint = G3DTools.getPoint(tcp.getWorldPosition());\r
1096         Point3d nextPoint = G3DTools.getPoint(next.getWorldPosition());    \r
1097         Point3d prevPoint = G3DTools.getPoint(prev.getWorldPosition());     \r
1098         return updateTurnControlPointTurn(tcp, middlePoint, prevPoint, nextPoint);\r
1099     }\r
1100     \r
1101     /**\r
1102      * Recalculates turn control point's internal data (turn angle and offset)\r
1103      * @param tcp\r
1104      * @param middlePoint\r
1105      * @param nextPoint\r
1106      * @param prevPoint\r
1107      */\r
1108     private static double updateTurnControlPointTurn( PipeControlPoint tcp, Point3d middlePoint, Point3d prevPoint, Point3d nextPoint) {\r
1109         \r
1110         Vector3d dir1 = new Vector3d(middlePoint);\r
1111         dir1.sub(prevPoint);\r
1112         Vector3d dir2 = new Vector3d(nextPoint);\r
1113         dir2.sub(middlePoint);\r
1114         if (DEBUG) System.out.println("PipingTools.updateTurnControlPointTurn " + tcp.getResource() + " " + prevPoint + " " + middlePoint + " " + nextPoint);\r
1115         return updateTurnControlPointTurn(tcp, dir1, dir2);\r
1116     }\r
1117     \r
1118     private static double updateTurnControlPointTurn(PipeControlPoint tcp, Vector3d dir1, Vector3d dir2) {\r
1119          double turnAngle = dir1.angle(dir2);\r
1120          double angle = Math.PI - turnAngle;\r
1121          \r
1122          double elbowRadius = tcp.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasTurnRadius);\r
1123          double R = elbowRadius / Math.tan(angle * 0.5);\r
1124          Vector3d turnAxis = new Vector3d();\r
1125          turnAxis.cross(dir1, dir2);\r
1126          turnAxis.normalize();\r
1127          tcp.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasTurnAngle,turnAngle);\r
1128          tcp.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, R);//setComponentOffsetValue(R);\r
1129          G3DTools.setTuple3(tcp.getSingleRelatedObject(ProcessResource.plant3Dresource.HasTurnAxis), turnAxis);\r
1130          if (DEBUG) System.out.println("PipingTools.updateTurnControlPointTurn " + dir1 + " " + dir2 + " " + turnAngle + " " + turnAxis);\r
1131          return turnAngle;\r
1132     }\r
1133     \r
1134 }\r