1 package org.simantics.plant3d.utils;
3 import java.util.ArrayList;
4 import java.util.HashMap;
8 import javax.vecmath.Point3d;
9 import javax.vecmath.Vector3d;
11 import org.simantics.Simantics;
12 import org.simantics.db.ReadGraph;
13 import org.simantics.db.Resource;
14 import org.simantics.db.common.request.ReadRequest;
15 import org.simantics.db.common.utils.NameUtils;
16 import org.simantics.db.exception.DatabaseException;
17 import org.simantics.g3d.math.MathTools;
18 import org.simantics.g3d.scenegraph.GeometryProvider;
19 import org.simantics.g3d.scenegraph.ParametricGeometryProvider;
20 import org.simantics.layer0.Layer0;
21 import org.simantics.plant3d.geometry.ParameterRead;
22 import org.simantics.plant3d.ontology.Plant3D;
23 import org.simantics.plant3d.scenegraph.EndComponent;
24 import org.simantics.plant3d.scenegraph.Equipment;
25 import org.simantics.plant3d.scenegraph.InlineComponent;
26 import org.simantics.plant3d.scenegraph.Nozzle;
27 import org.simantics.plant3d.scenegraph.P3DRootNode;
28 import org.simantics.plant3d.scenegraph.PipeRun;
29 import org.simantics.plant3d.scenegraph.PipelineComponent;
30 import org.simantics.plant3d.scenegraph.TurnComponent;
31 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint;
32 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.Direction;
33 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.PositionType;
34 import org.simantics.plant3d.scenegraph.controlpoint.PipingRules;
36 public class ComponentUtils {
39 private static Map<String,Class<? extends PipelineComponent>> clazzes = new HashMap<String, Class<? extends PipelineComponent>>();
40 private static Map<String,GeometryProvider> providers = new HashMap<String,GeometryProvider>();
41 private static Map<String,String> names = new HashMap<String,String>();
43 public static void preloadCache() {
44 Simantics.getSession().asyncRequest(new ReadRequest() {
47 public void run(ReadGraph graph) throws DatabaseException {
48 List<String> types = new ArrayList<String>();
49 types.add(Plant3D.URIs.Builtin_Straight);
50 types.add(Plant3D.URIs.Builtin_Elbow);
51 types.add(Plant3D.URIs.Builtin_ConcentricReducer);
52 types.add(Plant3D.URIs.Builtin_BranchSplitComponent);
53 types.add(Plant3D.URIs.Builtin_EccentricReducer);
54 types.add(Plant3D.URIs.Builtin_Elbow45);
55 types.add(Plant3D.URIs.Builtin_Elbow90);
57 for (String typeURI : types) {
64 private static GeometryProvider getProvider(ReadGraph graph, Resource type) throws DatabaseException {
66 Layer0 l0 = Layer0.getInstance(graph);
67 Plant3D p3d = Plant3D.getInstance(graph);
68 Resource geom = graph.getPossibleObject(type,p3d.hasGeometry);
70 for (Resource a : graph.getObjects(type, l0.Asserts)) {
71 if (p3d.hasGeometry.equals(graph.getPossibleObject(a, l0.HasPredicate))) {
72 geom = graph.getPossibleObject(a, l0.HasObject);
78 GeometryProvider provider = graph.adapt(geom, GeometryProvider.class);
79 if (provider instanceof ParametricGeometryProvider) {
80 Map<String,Object> params = graph.syncRequest(new ParameterRead(type));
81 if (params.size() > 0)
82 ((ParametricGeometryProvider)provider).setProperties(params);
89 private static Class<? extends PipelineComponent> getClazz(ReadGraph graph, Resource type) throws DatabaseException {
90 Plant3D p3d = Plant3D.getInstance(graph);
91 if (graph.isInheritedFrom(type, p3d.InlineComponent))
92 return InlineComponent.class;
93 if (graph.isInheritedFrom(type, p3d.TurnComponent))
94 return TurnComponent.class;
95 if (graph.isInheritedFrom(type, p3d.EndComponent))
96 return EndComponent.class;
97 if (graph.isInheritedFrom(type, p3d.Nozzle))
102 private static void load(ReadGraph graph, String typeURI) throws DatabaseException {
103 Plant3D p3d = Plant3D.getInstance(graph);
104 Resource type = graph.getResource(typeURI);
106 GeometryProvider provider = getProvider(graph, type);
107 if (provider != null || graph.hasStatement(type,p3d.NonVisibleComponent)) {
108 providers.put(typeURI, provider);
109 if (graph.isInheritedFrom(type, p3d.PipelineComponent))
110 clazzes.put(typeURI,getClazz(graph, type));
111 names.put(typeURI, NameUtils.getSafeName(graph, type));
114 throw new DatabaseException("Cannot find component for " + typeURI);
117 private static void load(final String typeURI) throws DatabaseException {
118 Simantics.getSession().syncRequest(new ReadRequest() {
121 public void run(ReadGraph graph) throws DatabaseException {
128 * Creates a component
130 * Does not set the name or add the component to a piperun.
136 public static PipelineComponent createComponent(P3DRootNode root, String typeURI) throws Exception {
137 Class<? extends PipelineComponent> type = clazzes.get(typeURI);
138 GeometryProvider provider = providers.get(typeURI);
139 if (type == null || provider == null) {
141 type = clazzes.get(typeURI);
142 provider = providers.get(typeURI);
144 //PipelineComponent component = type.newInstance();
145 PipelineComponent component = null;
146 if (type == InlineComponent.class) {
147 component = root.createInline();
148 } else if (type == TurnComponent.class) {
149 component = root.createTurn();
150 } else if (type == EndComponent.class) {
151 component = root.createTurn();
152 } else if (type == Nozzle.class) {
153 component = root.createNozzle();
155 component.setType(typeURI);
156 component.setGeometry(provider);
161 * Creates a equipment
163 * Does not set the name
171 public static Equipment createEquipment(P3DRootNode root, String typeURI) throws Exception {
172 GeometryProvider provider = providers.get(typeURI);
173 if (provider == null) {
175 provider = providers.get(typeURI);
177 Equipment equipment = root.createEquipment();
178 equipment.setType(typeURI);
179 equipment.setGeometry(provider);
180 root.addChild(equipment);
184 public static InlineComponent createStraight(P3DRootNode root) throws Exception{
185 InlineComponent component = root.createInline();
186 component.setType(Plant3D.URIs.Builtin_Straight);
187 component.setGeometry(providers.get(Plant3D.URIs.Builtin_Straight));
191 public static TurnComponent createTurn(P3DRootNode root) throws Exception {
192 TurnComponent elbow = root.createTurn();
193 elbow.setType(Plant3D.URIs.Builtin_Elbow);
194 elbow.setGeometry(providers.get(Plant3D.URIs.Builtin_Elbow));
198 public static InlineComponent createReducer(P3DRootNode root) throws Exception {
199 InlineComponent component = root.createInline();
200 component.setType(Plant3D.URIs.Builtin_ConcentricReducer);
201 component.setGeometry(providers.get(Plant3D.URIs.Builtin_ConcentricReducer));
205 public static InlineComponent createBranchSplit(P3DRootNode root) throws Exception {
206 InlineComponent component = root.createInline();
207 component.setType(Plant3D.URIs.Builtin_BranchSplitComponent);
211 public static Equipment createEquipment(P3DRootNode root, Item equipmentType) throws Exception {
212 Equipment equipment = createEquipment(root, equipmentType.getUri());
213 String n = root.getUniqueName(equipmentType.getName());
214 equipment.setName(n);
220 public static Nozzle createDefaultNozzle(P3DRootNode root, Equipment equipment) throws Exception {
221 return createNozzle(root, equipment, new Item(Plant3D.URIs.Builtin_Nozzle, "Nozzle"));
224 public static Nozzle createNozzle(P3DRootNode root, Equipment equipment, Item nozzleType) throws Exception {
225 Nozzle nozzle = root.createNozzle();
226 nozzle.setType(nozzleType.getUri());
227 String n = root.getUniqueName(nozzleType.getName());
229 PipeRun pipeRun = new PipeRun();
230 n = root.getUniqueName("PipeRun");
232 nozzle.setPipeRun(pipeRun);
234 equipment.addChild(nozzle);
235 root.addChild(pipeRun);
236 // root.getNodeMap().commit("Add nozzle " + n);
240 public static class InsertInstruction {
241 public String typeUri;
243 public PositionType position = PositionType.NEXT;
244 public PositionType insertPosition = PositionType.NEXT;
246 // Reducer requires pipe specs
247 public Double diameter;
248 public Double turnRadius;
251 public Double length;
256 public String getTypeUri() {
260 public void setTypeUri(String typeUri) {
261 this.typeUri = typeUri;
264 public PositionType getPosition() {
268 public void setPosition(PositionType position) {
269 this.position = position;
272 public PositionType getInsertPosition() {
273 return insertPosition;
276 public void setInsertPosition(PositionType insertPosition) {
277 this.insertPosition = insertPosition;
280 public Double getDiameter() {
284 public void setDiameter(Double diameter) {
285 this.diameter = diameter;
288 public Double getTurnRadius() {
292 public void setTurnRadius(Double turnRadius) {
293 this.turnRadius = turnRadius;
296 public Double getLength() {
300 public void setLength(Double length) {
301 this.length = length;
304 public Double getAngle() {
308 public void setAngle(Double angle) {
314 public static PipelineComponent addComponent(P3DRootNode root, PipelineComponent component, InsertInstruction inst) throws Exception {
316 PipelineComponent newComponent = ComponentUtils.createComponent(root, inst.typeUri);
317 PipeControlPoint newPcp = newComponent.getControlPoint();
319 PipeControlPoint toPcp = component.getControlPoint();
320 PipeRun pipeRun = toPcp.getPipeRun();
322 String typeName = names.get(inst.typeUri);
323 if (typeName == null)
324 typeName = "Component";
329 PositionType position = inst.position;
330 PositionType insertPosition = inst.insertPosition;
331 boolean lengthAdjustable = false;
332 if (newComponent instanceof InlineComponent) {
333 lengthAdjustable = ((InlineComponent)newComponent).isVariableLength();
335 boolean insertAdjustable = false;
336 if (component instanceof InlineComponent) {
337 insertAdjustable = ((InlineComponent)component).isVariableLength();
339 boolean sizeChange = false;
340 if (newComponent instanceof InlineComponent) {
341 sizeChange = ((InlineComponent)newComponent).isSizeChange();
344 if (toPcp.isInline()) {
347 if (toPcp.isDualInline()) {
348 toPcp = toPcp.getSubPoint().get(0);
349 pipeRun = toPcp.getPipeRun();
354 if (toPcp.isDualSub()) {
355 toPcp = toPcp.parent;
356 pipeRun = toPcp.getPipeRun();
360 Vector3d start = new Vector3d();
361 Vector3d end = new Vector3d();
362 dir = new Vector3d();
363 toPcp.getInlineControlPointEnds(start, end, dir);
367 pos = new Vector3d(end);
370 pos = new Vector3d(start);
373 pos = new Vector3d(toPcp.getWorldPosition());
377 } else if (toPcp.isDirected()) {
378 dir = new Vector3d(toPcp.getDirection(Direction.NEXT));
379 pos = new Vector3d(toPcp.getWorldPosition());
380 } else if (toPcp.isTurn() && toPcp.asFixedAngle()) {
381 dir = new Vector3d(toPcp.getDirection(position == PositionType.NEXT ? Direction.NEXT : Direction.PREVIOUS));
382 pos = new Vector3d(toPcp.getWorldPosition());
383 if (!lengthAdjustable) {
384 Vector3d v = new Vector3d(dir);
385 v.scale(toPcp.getInlineLength());
388 if (insertPosition == PositionType.NEXT) {
389 Vector3d v = new Vector3d(dir);
390 v.scale(toPcp.getInlineLength());
392 } else if (insertPosition == PositionType.SPLIT) {
393 // scale 0.5*length so that we don't remove the length twice from the new component
394 Vector3d v = new Vector3d(dir);
395 v.scale(toPcp.getInlineLength()*0.5);
403 String name = component.getPipeRun().getUniqueName(typeName);
404 newComponent.setName(name);
406 pipeRun.addChild(newComponent);
407 // TODO: these options are not stored into DB. Should they?!
408 if (newComponent instanceof InlineComponent && ((InlineComponent)newComponent).isVariableLength()) {
409 newPcp.setLength(inst.length);
410 } else if (newComponent instanceof TurnComponent && ((TurnComponent)newComponent).isVariableAngle()) {
411 newPcp.setTurnAngle(inst.angle);
414 newComponent.updateParameters();
416 Vector3d v = new Vector3d(dir);
417 if (insertAdjustable) {
418 if (insertPosition == PositionType.NEXT)
419 v.scale(newComponent.getControlPoint().getInlineLength());
420 else if (insertPosition == PositionType.SPLIT)
422 else if (insertPosition == PositionType.PREVIOUS)
423 v.scale(-newComponent.getControlPoint().getInlineLength());
425 v.scale(newComponent.getControlPoint().getInlineLength());
440 if (toPcp.isDualInline())
441 toPcp = toPcp.getSubPoint().get(0);
442 newPcp.insert(toPcp, Direction.NEXT);
443 newPcp.setWorldPosition(pos);
446 if (toPcp.isDualSub())
447 toPcp = toPcp.parent;
448 newPcp.insert(toPcp, Direction.PREVIOUS);
449 newPcp.setWorldPosition(pos);
452 PipingRules.splitVariableLengthComponent(newComponent, (InlineComponent)component, true);
455 PipeRun other = new PipeRun();
456 String n = root.getUniqueName("PipeRun");
458 other.setPipeDiameter(inst.diameter);
459 other.setTurnRadius(inst.turnRadius);
460 root.addChild(other);
463 if (position == PositionType.NEXT) {
464 PipingRules.addSizeChange(false, pipeRun, other, (InlineComponent)newComponent, toPcp, null);
465 } else if (position == PositionType.PREVIOUS){
466 PipingRules.addSizeChange(true, pipeRun, other, (InlineComponent)newComponent, toPcp, null);
468 newPcp.setWorldPosition(pos);
469 // TODO : chicken-egg problem
470 newComponent.updateParameters();
471 Vector3d v = new Vector3d(dir);
472 v.scale(newComponent.getControlPoint().getLength()*0.5);
483 newPcp.setWorldPosition(pos);
490 public static boolean connect(PipelineComponent current, PipelineComponent endTo) throws Exception {
491 return connect(current, endTo, null, null);
495 * Connects component to another component
503 public static boolean connect(PipelineComponent current, PipelineComponent endTo, PositionType endType, Vector3d position) throws Exception{
504 PipeControlPoint endCP = endTo.getControlPoint();
506 if (current.getNext() == null)
508 else if (current.getPrevious() == null)
513 PipeRun pipeRun = current.getPipeRun();
514 P3DRootNode root = (P3DRootNode)current.getRootNode();
515 PipeControlPoint currentCP = current.getControlPoint();
517 if (endType == null || endType == PositionType.NEXT || endType == PositionType.PREVIOUS) {
521 boolean requiresReverse = false;
522 if (!reversed && endCP.getPrevious() != null) {
523 if (endCP.getNext() != null)
525 requiresReverse = true;
526 } else if (reversed && endCP.getNext() != null) {
527 if (endCP.getPrevious() != null)
529 requiresReverse = true;
531 PipeRun other = endCP.getPipeRun();
532 boolean mergeRuns = other == null ? true : pipeRun.equalSpecs(other);
534 if (requiresReverse) {
535 // Pipe line must be traversible with next/previous relations without direction change.
536 // Now the component, where we are connecting the created pipeline is defined in different order.
537 PipingRules.reverse(other);
541 // Runs have compatible specs and must be merged
542 if (other != null && pipeRun != other)
543 PipingRules.merge(pipeRun, other);
544 else if (other == null) {
545 if (!(endTo instanceof Nozzle)) {
546 pipeRun.addChild(endTo);
548 endTo.setPipeRun(pipeRun);
552 currentCP.setNext(endCP);
553 endCP.setPrevious(currentCP);
555 currentCP.setPrevious(endCP);
556 endCP.setNext(currentCP);
559 // Runs do not have compatible specs, and a reducer must be attached in between.
560 InlineComponent reducer = ComponentUtils.createReducer(root);
561 PipeControlPoint pcp = reducer.getControlPoint();
562 PipeControlPoint ocp = pcp.getSubPoint().get(0);
564 Vector3d endPos = endCP.getWorldPosition();
565 Vector3d currentPos = currentCP.getWorldPosition();
566 Vector3d v = new Vector3d(endPos);
571 PipingRules.addSizeChange(reversed, pipeRun, other, reducer, currentCP, endCP);
573 pcp.setWorldPosition(v);
574 reducer.updateParameters();
576 PipingRules.positionUpdate(endCP);
579 } else if (endType == PositionType.SPLIT) {
580 InlineComponent branchSplit = createBranchSplit((InlineComponent)endTo, position);
581 if (branchSplit == null)
583 PipeControlPoint branchSplitCP = branchSplit.getControlPoint();
584 PipeControlPoint pcp = new PipeControlPoint(branchSplit,pipeRun);
585 branchSplitCP.children.add(pcp);
586 pcp.parent = branchSplitCP;
587 pcp.setWorldOrientation(branchSplitCP.getWorldOrientation());
588 pcp.setWorldPosition(branchSplitCP.getWorldPosition());
592 pcp.setPrevious(currentCP);
593 currentCP.setNext(pcp);
595 pcp.setNext(currentCP);
596 currentCP.setPrevious(pcp);
598 PipingRules.positionUpdate(endCP);
604 public static InlineComponent createBranchSplit(InlineComponent component, Vector3d pos) throws Exception{
605 if (!component.isVariableLength())
607 PipeRun pipeRun = component.getPipeRun();
608 Vector3d sStart = new Vector3d();
609 Vector3d sEnd = new Vector3d();
610 component.getControlPoint().getInlineControlPointEnds(sStart, sEnd);
612 if (MathTools.distance(sStart, sEnd) < (pipeRun.getPipeDiameter()*0.5))
616 Vector3d p = MathTools.closestPointOnEdge(new Vector3d(pos), sStart, sEnd);
618 Vector3d v = new Vector3d(sEnd);
621 v.scale(component.getPipeRun().getPipeDiameter()*0.5);
623 } else if (p == sEnd) {
624 Vector3d v = new Vector3d(sStart);
627 v.scale(component.getPipeRun().getPipeDiameter()*0.5);
631 P3DRootNode root = (P3DRootNode)component.getRootNode();
632 InlineComponent branchSplit = ComponentUtils.createBranchSplit(root);
633 String branchName = component.getPipeRun().getUniqueName("Branch");
634 branchSplit.setName(branchName);
635 component.getPipeRun().addChild(branchSplit);
636 PipeControlPoint branchSplitCP = branchSplit.getControlPoint();
637 branchSplitCP.setWorldPosition(p);
638 PipingRules.splitVariableLengthComponent(branchSplit, component, false);