]> gerrit.simantics Code Review - simantics/3d.git/blob - org.simantics.plant3d/src/org/simantics/plant3d/utils/ComponentUtils.java
939d1551a5343e20526b9db50e0ad87039a43dc8
[simantics/3d.git] / org.simantics.plant3d / src / org / simantics / plant3d / utils / ComponentUtils.java
1 package org.simantics.plant3d.utils;
2
3 import java.util.ArrayList;
4 import java.util.HashMap;
5 import java.util.List;
6 import java.util.Map;
7
8 import javax.vecmath.Vector3d;
9
10 import org.simantics.Simantics;
11 import org.simantics.db.ReadGraph;
12 import org.simantics.db.Resource;
13 import org.simantics.db.common.request.ReadRequest;
14 import org.simantics.db.common.utils.NameUtils;
15 import org.simantics.db.exception.DatabaseException;
16 import org.simantics.g3d.math.MathTools;
17 import org.simantics.g3d.scenegraph.GeometryProvider;
18 import org.simantics.g3d.scenegraph.ParametricGeometryProvider;
19 import org.simantics.layer0.Layer0;
20 import org.simantics.plant3d.geometry.ParameterRead;
21 import org.simantics.plant3d.ontology.Plant3D;
22 import org.simantics.plant3d.scenegraph.EndComponent;
23 import org.simantics.plant3d.scenegraph.Equipment;
24 import org.simantics.plant3d.scenegraph.InlineComponent;
25 import org.simantics.plant3d.scenegraph.Nozzle;
26 import org.simantics.plant3d.scenegraph.P3DRootNode;
27 import org.simantics.plant3d.scenegraph.PipeRun;
28 import org.simantics.plant3d.scenegraph.PipelineComponent;
29 import org.simantics.plant3d.scenegraph.TurnComponent;
30 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint;
31 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.Direction;
32 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.PositionType;
33 import org.simantics.plant3d.scenegraph.controlpoint.PipingRules;
34
35 public class ComponentUtils {
36
37         
38         private static Map<String,Class<? extends PipelineComponent>> clazzes = new HashMap<String, Class<? extends PipelineComponent>>();
39         private static Map<String,GeometryProvider> providers = new HashMap<String,GeometryProvider>();
40         private static Map<String,String> names = new HashMap<String,String>();
41         
42         public static void preloadCache() {
43                 Simantics.getSession().asyncRequest(new ReadRequest() {
44                         
45                         @Override
46                         public void run(ReadGraph graph) throws DatabaseException {
47                                 List<String> types = new ArrayList<String>();
48                                 types.add(Plant3D.URIs.Builtin_Straight);
49                                 types.add(Plant3D.URIs.Builtin_Elbow);
50                                 types.add(Plant3D.URIs.Builtin_ConcentricReducer);
51                                 types.add(Plant3D.URIs.Builtin_BranchSplitComponent);
52                                 types.add(Plant3D.URIs.Builtin_EccentricReducer);
53                                 types.add(Plant3D.URIs.Builtin_Elbow45);
54                                 types.add(Plant3D.URIs.Builtin_Elbow90);
55                                 
56                                 for (String typeURI : types) {
57                                         load(graph, typeURI);
58                                 }
59                         }
60                 });
61         }
62         
63         private static GeometryProvider getProvider(ReadGraph graph, Resource type) throws DatabaseException {
64                 
65                 Layer0 l0 = Layer0.getInstance(graph);
66                 Plant3D p3d = Plant3D.getInstance(graph);
67                 Resource geom = graph.getPossibleObject(type,p3d.hasGeometry);
68                 if (geom == null) {
69                         for (Resource a : graph.getObjects(type, l0.Asserts)) {
70                                 if (p3d.hasGeometry.equals(graph.getPossibleObject(a, l0.HasPredicate))) {
71                                         geom = graph.getPossibleObject(a, l0.HasObject);
72                                         break;
73                                 }
74                         }
75                 }
76                 if (geom != null) {
77                         GeometryProvider provider = graph.adapt(geom, GeometryProvider.class);
78                         if (provider instanceof ParametricGeometryProvider) {
79                         Map<String,Object> params = graph.syncRequest(new ParameterRead(type));
80                         if (params.size() > 0)
81                             ((ParametricGeometryProvider)provider).setProperties(params);
82                         }
83                         return provider;
84                 }
85                 return null;
86         }
87         
88         private static Class<? extends PipelineComponent> getClazz(ReadGraph graph, Resource type) throws DatabaseException {
89                 Plant3D p3d = Plant3D.getInstance(graph);
90                 if (graph.isInheritedFrom(type, p3d.InlineComponent))
91                         return InlineComponent.class;
92                 if (graph.isInheritedFrom(type, p3d.TurnComponent))
93                         return TurnComponent.class;
94                 if (graph.isInheritedFrom(type, p3d.EndComponent))
95                         return EndComponent.class;
96                 if (graph.isInheritedFrom(type, p3d.Nozzle))
97                         return Nozzle.class;
98                 return null;
99         }
100         
101         private static void load(ReadGraph graph, String typeURI) throws DatabaseException {
102                 Plant3D p3d = Plant3D.getInstance(graph);
103                 Resource type = graph.getResource(typeURI);
104                 
105                 GeometryProvider provider = getProvider(graph, type);
106                 if (provider != null || graph.hasStatement(type,p3d.NonVisibleComponent)) {
107                         providers.put(typeURI, provider);
108                         if (graph.isInheritedFrom(type, p3d.PipelineComponent))
109                                 clazzes.put(typeURI,getClazz(graph, type));
110                         names.put(typeURI, NameUtils.getSafeName(graph, type));
111                         return;
112                 }
113                 throw new DatabaseException("Cannot find component for " + typeURI);
114         }
115         
116         private static void load(final String typeURI) throws DatabaseException {
117                 Simantics.getSession().syncRequest(new ReadRequest() {
118                         
119                         @Override
120                         public void run(ReadGraph graph) throws DatabaseException {
121                                 load(graph,typeURI);    
122                         }
123                 });
124         }
125         
126         /**
127          * Creates a component
128          * 
129          * Does not set the name or add the component to a piperun.
130          * @param root
131          * @param typeURI
132          * @return
133          * @throws Exception
134          */
135         public static PipelineComponent createComponent(P3DRootNode root, String typeURI) throws Exception {
136                 Class<? extends PipelineComponent> type = clazzes.get(typeURI);
137                 GeometryProvider provider = providers.get(typeURI);
138                 if (type == null || provider == null) {
139                         load(typeURI);
140                         type = clazzes.get(typeURI);
141                         provider = providers.get(typeURI);
142                 }
143                 //PipelineComponent component = type.newInstance();
144                 PipelineComponent component = null;
145                 if (type == InlineComponent.class) {
146                         component = root.createInline();
147                 } else if (type == TurnComponent.class) {
148                         component = root.createTurn();
149                 } else if (type == EndComponent.class) {
150                         component = root.createTurn();
151                 } else if (type == Nozzle.class) {
152                         component = root.createNozzle();
153                 }
154                 component.setType(typeURI);
155                 component.setGeometry(provider);
156                 return component;
157         }
158         
159         /**
160          * Creates a equipment
161          * 
162          * Does not set the name
163          * 
164          * @param root
165          * @param typeURI
166          * @return
167          * @throws Exception
168          */
169         
170         public static Equipment createEquipment(P3DRootNode root, String typeURI) throws Exception {
171                 GeometryProvider provider = providers.get(typeURI);
172                 if (provider == null) {
173                         load(typeURI);
174                         provider = providers.get(typeURI);
175                 }
176                 Equipment equipment = root.createEquipment();
177                 equipment.setType(typeURI);
178                 equipment.setGeometry(provider);
179                 root.addChild(equipment);
180                 return equipment;
181         }
182         
183         public static InlineComponent createStraight(P3DRootNode root) throws Exception{
184                 InlineComponent component = root.createInline();
185                 component.setType(Plant3D.URIs.Builtin_Straight);
186                 component.setGeometry(providers.get(Plant3D.URIs.Builtin_Straight));
187                 return component;
188         }
189         
190         public static TurnComponent createTurn(P3DRootNode root) throws Exception {
191                 TurnComponent elbow = root.createTurn();
192                 elbow.setType(Plant3D.URIs.Builtin_Elbow);
193                 elbow.setGeometry(providers.get(Plant3D.URIs.Builtin_Elbow));
194                 return elbow;
195         }
196         
197         public static InlineComponent createReducer(P3DRootNode root) throws Exception {
198                 InlineComponent component = root.createInline();
199                 component.setType(Plant3D.URIs.Builtin_ConcentricReducer);
200                 component.setGeometry(providers.get(Plant3D.URIs.Builtin_ConcentricReducer));
201                 return component;
202         }
203         
204         public static InlineComponent createBranchSplit(P3DRootNode root) throws Exception {
205                 InlineComponent component = root.createInline();
206                 component.setType(Plant3D.URIs.Builtin_BranchSplitComponent);
207                 return component;
208         }
209         
210         public static Equipment createEquipment(P3DRootNode root, Item equipmentType) throws Exception {
211                 Equipment equipment = createEquipment(root, equipmentType.getUri());
212                 String n = root.getUniqueName(equipmentType.getName());
213                 equipment.setName(n);
214                 return equipment;
215         }
216         
217         
218         
219         public static Nozzle createDefaultNozzle(P3DRootNode root, Equipment equipment) throws Exception {
220                 return createNozzle(root, equipment, new Item(Plant3D.URIs.Builtin_Nozzle, "Nozzle"));
221         }
222         
223         public static Nozzle createNozzle(P3DRootNode root, Equipment equipment, Item nozzleType) throws Exception {
224                 Nozzle nozzle = root.createNozzle();
225                 nozzle.setType(nozzleType.getUri());
226                 String n = root.getUniqueName(nozzleType.getName());
227                 nozzle.setName(n);
228                 PipeRun pipeRun = new PipeRun();
229                 n = root.getUniqueName("PipeRun");
230                 pipeRun.setName(n);
231                 nozzle.setPipeRun(pipeRun);
232                 
233                 equipment.addChild(nozzle);
234                 root.addChild(pipeRun);
235                 // root.getNodeMap().commit("Add nozzle " + n);
236                 return nozzle;
237         }
238         
239         public static class InsertInstruction {
240                 public String typeUri;
241                 
242                 public PositionType position = PositionType.NEXT;
243                 public PositionType insertPosition = PositionType.NEXT;
244                 
245                 // Reducer requires pipe specs
246                 public Double diameter;
247                 public Double turnRadius;
248                 
249                 // Variable length 
250                 public Double length;
251                 
252                 // Variable angle
253                 public Double angle;
254
255                 public String getTypeUri() {
256                         return typeUri;
257                 }
258
259                 public void setTypeUri(String typeUri) {
260                         this.typeUri = typeUri;
261                 }
262
263                 public PositionType getPosition() {
264                         return position;
265                 }
266
267                 public void setPosition(PositionType position) {
268                         this.position = position;
269                 }
270
271                 public PositionType getInsertPosition() {
272                         return insertPosition;
273                 }
274
275                 public void setInsertPosition(PositionType insertPosition) {
276                         this.insertPosition = insertPosition;
277                 }
278
279                 public Double getDiameter() {
280                         return diameter;
281                 }
282
283                 public void setDiameter(Double diameter) {
284                         this.diameter = diameter;
285                 }
286
287                 public Double getTurnRadius() {
288                         return turnRadius;
289                 }
290
291                 public void setTurnRadius(Double turnRadius) {
292                         this.turnRadius = turnRadius;
293                 }
294
295                 public Double getLength() {
296                         return length;
297                 }
298
299                 public void setLength(Double length) {
300                         this.length = length;
301                 }
302
303                 public Double getAngle() {
304                         return angle;
305                 }
306
307                 public void setAngle(Double angle) {
308                         this.angle = angle;
309                 }
310
311         }
312         
313         public static PipelineComponent addComponent(P3DRootNode root, PipelineComponent component,  InsertInstruction inst) throws Exception {
314                 
315                 PipelineComponent newComponent = ComponentUtils.createComponent(root, inst.typeUri);
316                 PipeControlPoint newPcp = newComponent.getControlPoint();
317                 
318                 PipeControlPoint toPcp = component.getControlPoint();
319                 PipeRun pipeRun = toPcp.getPipeRun();
320                 
321                 String typeName = names.get(inst.typeUri);
322                 if (typeName == null)
323                         typeName = "Component";
324                 
325                 Vector3d dir = null;
326                 Vector3d pos = null;
327         
328                 PositionType position = inst.position;
329                 PositionType insertPosition = inst.insertPosition;
330                 boolean lengthAdjustable = false;
331                 if (newComponent instanceof InlineComponent) {
332                         lengthAdjustable = ((InlineComponent)newComponent).isVariableLength() || ((InlineComponent)newComponent).isModifialble(); 
333                 }
334                 boolean insertAdjustable = false;
335                 if (component instanceof InlineComponent) {
336                         insertAdjustable = ((InlineComponent)component).isVariableLength();
337                 }
338                 boolean sizeChange = false;
339                 if (newComponent instanceof InlineComponent) {
340                         sizeChange = ((InlineComponent)newComponent).isSizeChange();
341                 }
342                 
343                 if (toPcp.isInline()) {
344                         switch (position) {
345                         case NEXT: 
346                                 if (toPcp.isDualInline()) {
347                                         toPcp = toPcp.getDualSub();
348                                         pipeRun = toPcp.getPipeRun();
349                                 }
350                                 
351                                 break;
352                         case PREVIOUS:
353                                 if (toPcp.isDualSub()) {
354                                         toPcp = toPcp.parent;
355                                         pipeRun = toPcp.getPipeRun();
356                                 }
357                                 break;
358                         default:
359                                 break;
360                         }
361                         Vector3d start = new Vector3d();
362                         Vector3d end = new Vector3d();
363                         dir = new Vector3d();
364                         toPcp.getInlineControlPointEnds(start, end, dir);
365                         dir.normalize();
366                         switch (position) {
367                         case NEXT:
368                                 pos = new Vector3d(end);
369                                 break;
370                         case PREVIOUS:
371                                 pos = new Vector3d(start);
372                                 break;
373                         case SPLIT:
374                                 pos = new Vector3d(toPcp.getWorldPosition());
375                                 break;
376                         default:
377                                 break;
378                         }
379
380                 } else if (toPcp.isDirected()) {
381                         dir = new Vector3d(toPcp.getDirection(Direction.NEXT));
382                         pos = new Vector3d(toPcp.getWorldPosition());
383                 } else if (toPcp.isTurn() && toPcp.asFixedAngle()) {
384                         dir = new Vector3d(toPcp.getDirection(position == PositionType.NEXT ? Direction.NEXT : Direction.PREVIOUS));
385                         pos = new Vector3d(toPcp.getWorldPosition());
386                         if (!lengthAdjustable) {
387                                 Vector3d v = new Vector3d(dir);
388                                 v.scale(toPcp.getInlineLength());
389                                 pos.add(v);
390                         } else {
391                                 if (insertPosition == PositionType.NEXT) {
392                                         Vector3d v = new Vector3d(dir);
393                                         v.scale(toPcp.getInlineLength());
394                                         pos.add(v);
395                                 } else if (insertPosition == PositionType.SPLIT) {
396                                         // scale 0.5*length so that we don't remove the length twice from the new component
397                                         Vector3d v = new Vector3d(dir);
398                                         v.scale(toPcp.getInlineLength()*0.5);  
399                                         pos.add(v);
400                                 }
401                         }
402                 }
403                 
404                 
405                 if (!sizeChange) {
406                         String name = component.getPipeRun().getUniqueName(typeName);
407                         newComponent.setName(name);
408
409                         pipeRun.addChild(newComponent);
410
411                         if (newComponent instanceof InlineComponent) {
412                             InlineComponent inlineComponent = (InlineComponent)newComponent;
413                             if (inlineComponent.isVariableLength()|| inlineComponent.isModifialble()) {
414                                 newPcp.setLength(inst.length);
415                                 newComponent.setParameter("length", inst.length);
416                             }
417                         } else if (newComponent instanceof TurnComponent) {
418                             TurnComponent turnComponent = (TurnComponent)newComponent;
419                             if  (turnComponent.isVariableAngle()) {
420                                 newPcp.setTurnAngle(inst.angle);
421                                 newComponent.setParameter("turnAngle", inst.angle);
422                             }
423                         }
424                         
425                         newComponent.updateParameters();
426                         
427                         Vector3d v = new Vector3d(dir);
428                         if (insertAdjustable) {
429                                 if (insertPosition == PositionType.NEXT)
430                                         v.scale(newComponent.getControlPoint().getInlineLength());
431                                 else if (insertPosition == PositionType.SPLIT)
432                                         v.set(0, 0, 0);
433                                 else if (insertPosition == PositionType.PREVIOUS)
434                                         v.scale(-newComponent.getControlPoint().getInlineLength());
435                         } else {
436                                 v.scale(newComponent.getControlPoint().getInlineLength());
437                         }
438                         switch (position) {
439                         case NEXT:
440                                 pos.add(v);
441                                 break;
442                         case PREVIOUS:
443                                 pos.sub(v);
444                                 break;
445                         case SPLIT:
446                                 break;
447                         default:
448                                 break;
449                         }
450                         
451                         switch (position) {
452                         case NEXT: 
453                                 if (toPcp.isDualInline())
454                                         toPcp = toPcp.getDualSub();
455                                 newPcp.insert(toPcp, Direction.NEXT);
456                                 newPcp.setWorldPosition(pos);
457                                 break;
458                         case PREVIOUS:
459                                 if (toPcp.isDualSub())
460                                         toPcp = toPcp.parent;
461                                 newPcp.insert(toPcp, Direction.PREVIOUS);
462                                 newPcp.setWorldPosition(pos);
463                                 break;
464                         case SPLIT:
465                                 PipingRules.splitVariableLengthComponent(newComponent, (InlineComponent)component, true);
466                         default:
467                                 break;
468                         }
469                 } else {
470                         PipeRun other = new PipeRun();
471                         String n = root.getUniqueName("PipeRun");
472                         other.setName(n);
473                         other.setPipeDiameter(inst.diameter);
474                         other.setTurnRadius(inst.turnRadius);
475                         root.addChild(other);
476                         
477                         
478                         if (position == PositionType.NEXT) {
479                                 PipingRules.addSizeChange(false, pipeRun, other, (InlineComponent)newComponent, toPcp, null);
480                         } else if (position == PositionType.PREVIOUS){
481                                 PipingRules.addSizeChange(true, pipeRun, other, (InlineComponent)newComponent, toPcp, null);
482                         }
483                         newPcp.setWorldPosition(pos);
484                         // TODO : chicken-egg problem
485                         newComponent.updateParameters();
486                         Vector3d v = new Vector3d(dir);
487                         v.scale(newComponent.getControlPoint().getLength()*0.5);
488                         switch (position) {
489                         case NEXT:
490                                 pos.add(v);
491                                 break;
492                         case PREVIOUS:
493                                 pos.sub(v);
494                                 break;
495                         case SPLIT:
496                                 break;
497                         default:
498                                 break;
499                         }
500                         newPcp.setWorldPosition(pos);
501                         
502                 }
503                                 
504                 
505                 return newComponent;
506         }
507         public static boolean connect(PipelineComponent current, PipelineComponent endTo) throws Exception {
508                 return connect(current, endTo, null, null);
509         }
510         
511         /**
512          * Connects component to another component
513          * @param current
514          * @param endTo
515          * @param endType
516          * @param position
517          * @return
518          * @throws Exception
519          */
520         public static boolean connect(PipelineComponent current, PipelineComponent endTo, PositionType endType, Vector3d position) throws Exception{
521                 PipeControlPoint endCP = endTo.getControlPoint();
522                 boolean reversed;
523                 if (current.getNext() == null)
524                         reversed = false;
525                 else if (current.getPrevious() == null)
526                         reversed = true;
527                 else
528                         return false;
529                 
530                 PipeRun pipeRun = current.getPipeRun();
531                 P3DRootNode root = (P3DRootNode)current.getRootNode();
532                 PipeControlPoint currentCP = current.getControlPoint();
533                 
534                 if (endType == null || endType == PositionType.NEXT || endType == PositionType.PREVIOUS) {
535                         
536                         
537                         
538                         boolean requiresReverse = false;
539                         if (!reversed && endCP.getPrevious() != null) {
540                                 if (endCP.getNext() != null)
541                                         return false;
542                                 requiresReverse = true;
543                         } else if (reversed && endCP.getNext() != null) {
544                                 if (endCP.getPrevious() != null)
545                                         return false;
546                                 requiresReverse = true;
547                         }
548                         PipeRun other = endCP.getPipeRun();
549                         boolean mergeRuns = other == null ? true : pipeRun.canMerge(other);
550                         
551                         if (requiresReverse) {
552                                 // Pipe line must be traversible with next/previous relations without direction change.
553                                 // Now the component, where we are connecting the created pipeline is defined in different order.
554                                 PipingRules.reverse(other);
555                                 
556                         }
557
558                         if (mergeRuns) {
559                                 // Runs have compatible specs and must be merged
560                                 if (other != null && pipeRun != other)
561                                         pipeRun.merge(other);
562                                 else if (other == null) {
563                                         if (!(endTo instanceof Nozzle)) {
564                                                 pipeRun.addChild(endTo);
565                                         } else {
566                                                 endTo.setPipeRun(pipeRun);
567                                         }
568                                 }
569                                 if (!reversed) {
570                                         currentCP.setNext(endCP);
571                                         endCP.setPrevious(currentCP);
572                                 } else {
573                                         currentCP.setPrevious(endCP);
574                                         endCP.setNext(currentCP);
575                                 }
576                         } else {
577                                 // Runs do not have compatible specs, and a reducer must be attached in between.
578                                 InlineComponent reducer = ComponentUtils.createReducer(root);
579                                 PipeControlPoint pcp = reducer.getControlPoint();
580                                 
581                                 Vector3d endPos = endCP.getWorldPosition();
582                                 Vector3d currentPos = currentCP.getWorldPosition();
583                                 Vector3d v = new Vector3d(endPos);
584                                 v.sub(currentPos);
585                                 v.scale(0.5);
586                                 v.add(currentPos);
587                                 
588                                 PipingRules.addSizeChange(reversed, pipeRun, other, reducer, currentCP, endCP);
589                                 
590                                 pcp.setWorldPosition(v);
591                                 reducer.updateParameters();
592                         }
593                         PipingRules.positionUpdate(endCP);
594                         return true;
595                         
596                 } else if (endType == PositionType.SPLIT) {
597                         InlineComponent branchSplit = createBranchSplit((InlineComponent)endTo, position);
598                         if (branchSplit == null)
599                                 return false;
600                         PipeControlPoint branchSplitCP = branchSplit.getControlPoint();
601                         PipeControlPoint pcp = new PipeControlPoint(branchSplit,pipeRun);
602                         branchSplitCP.children.add(pcp);
603                         pcp.parent = branchSplitCP;
604                         pcp.setWorldOrientation(branchSplitCP.getWorldOrientation());
605                         pcp.setWorldPosition(branchSplitCP.getWorldPosition());
606                                                 
607                         
608                         if(!reversed) {
609                                 pcp.setPrevious(currentCP);
610                                 currentCP.setNext(pcp);
611                         } else {
612                                 pcp.setNext(currentCP);
613                                 currentCP.setPrevious(pcp);
614                         }
615                         PipingRules.positionUpdate(endCP);
616                         return true;
617                 }
618                 return false;
619         }
620         
621         public static InlineComponent createBranchSplit(InlineComponent component, Vector3d pos) throws Exception{
622                 if (!component.isVariableLength())
623                         return null;
624                 PipeRun pipeRun = component.getPipeRun();
625                 Vector3d sStart = new Vector3d();
626                 Vector3d sEnd = new Vector3d();
627                 component.getControlPoint().getInlineControlPointEnds(sStart, sEnd);
628                 
629                 if (MathTools.distance(sStart, sEnd) < (pipeRun.getPipeDiameter()*0.5))
630                         return null;
631                 
632                 
633                 Vector3d p = MathTools.closestPointOnEdge(new Vector3d(pos), sStart, sEnd);
634                 if (p == sStart) {
635                         Vector3d v = new Vector3d(sEnd);
636                         v.sub(sStart);
637                         v.normalize();
638                         v.scale(component.getPipeRun().getPipeDiameter()*0.5);
639                         p.add(v);
640                 } else if (p == sEnd) {
641                         Vector3d v = new Vector3d(sStart);
642                         v.sub(sEnd);
643                         v.normalize();
644                         v.scale(component.getPipeRun().getPipeDiameter()*0.5);
645                         p.add(v);
646                 }
647                 
648                 P3DRootNode root = (P3DRootNode)component.getRootNode();
649                 InlineComponent branchSplit = ComponentUtils.createBranchSplit(root);
650                 String branchName = component.getPipeRun().getUniqueName("Branch");
651                 branchSplit.setName(branchName);
652                 component.getPipeRun().addChild(branchSplit);
653                 PipeControlPoint branchSplitCP = branchSplit.getControlPoint();
654                 branchSplitCP.setWorldPosition(p);
655                 PipingRules.splitVariableLengthComponent(branchSplit, component, false);
656                 return branchSplit;
657         }
658 }