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