package org.simantics.plant3d.scenegraph; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import org.simantics.g3d.math.MathTools; import org.simantics.g3d.property.annotations.GetPropertyValue; import org.simantics.g3d.property.annotations.PropertyTabBlacklist; import org.simantics.g3d.property.annotations.SetPropertyValue; import org.simantics.g3d.scenegraph.IG3DNode; import org.simantics.g3d.vtk.common.VtkView; import org.simantics.objmap.graph.annotations.GraphType; import org.simantics.objmap.graph.annotations.RelatedElementsAdd; import org.simantics.objmap.graph.annotations.RelatedElementsGet; import org.simantics.objmap.graph.annotations.RelatedElementsRem; import org.simantics.objmap.graph.annotations.RelatedGetValue; import org.simantics.objmap.graph.annotations.RelatedSetValue; import org.simantics.plant3d.ontology.Plant3D; import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint; import vtk.vtkProp3D; import vtk.vtkRenderer; @GraphType(Plant3D.URIs.PipeRun) @PropertyTabBlacklist("Transform") public class PipeRun extends P3DParentNode { private double pipeDiameter = 0.1; private double pipeThickness = 0.0; private double[] turnRadius = new double[] {0.2}; @Override public void update(vtkRenderer ren) { } @Override public void visualize(VtkView panel) { } @Override public Collection getActors() { return Collections.emptyList(); } @Override public void stopVisualize() { } @SuppressWarnings("deprecation") @RelatedGetValue(Plant3D.URIs.HasTurnRadius) @GetPropertyValue(value=Plant3D.URIs.HasTurnRadius, name = "Elbow radius") public double getTurnRadius() { return turnRadius[0]; } @SuppressWarnings("deprecation") @RelatedSetValue(Plant3D.URIs.HasTurnRadius) @SetPropertyValue(Plant3D.URIs.HasTurnRadius) public void setTurnRadius(double turnRadius) { if (this.turnRadius[0] == turnRadius) return; this.turnRadius[0] = turnRadius; firePropertyChanged(Plant3D.URIs.HasTurnRadius); firePropertyChanged(Plant3D.URIs.HasTurnRadiusArray); } @RelatedGetValue(Plant3D.URIs.HasTurnRadiusArray) @GetPropertyValue(value=Plant3D.URIs.HasTurnRadiusArray, name = "Elbow radius array") public double[] getTurnRadiusArray() { return turnRadius; } @RelatedSetValue(Plant3D.URIs.HasTurnRadiusArray) @SetPropertyValue(Plant3D.URIs.HasTurnRadiusArray) public void setTurnRadiusArray(double[] turnRadiusArray) { if (turnRadiusArray == null || turnRadiusArray.length == 0 || Arrays.equals(this.turnRadius, turnRadiusArray)) return; this.turnRadius = turnRadiusArray; firePropertyChanged(Plant3D.URIs.HasTurnRadiusArray); } @RelatedGetValue(Plant3D.URIs.HasPipeDiameter) @GetPropertyValue(value=Plant3D.URIs.HasPipeDiameter, name = "Diameter") public double getPipeDiameter() { return pipeDiameter; } @RelatedSetValue(Plant3D.URIs.HasPipeDiameter) @SetPropertyValue(Plant3D.URIs.HasPipeDiameter) public void setPipeDiameter(double pipeDiameter) { if (this.pipeDiameter == pipeDiameter) return; this.pipeDiameter = pipeDiameter; firePropertyChanged(Plant3D.URIs.HasPipeDiameter); } @RelatedGetValue(Plant3D.URIs.HasPipeThickness) @GetPropertyValue(value=Plant3D.URIs.HasPipeThickness, name = "Wall Thickness") public double getPipeThickness() { return pipeThickness; } @RelatedSetValue(Plant3D.URIs.HasPipeThickness) @SetPropertyValue(Plant3D.URIs.HasPipeThickness) public void setPipeThickness(double pipeThickness) { if (this.pipeThickness == pipeThickness) return; this.pipeThickness = pipeThickness; firePropertyChanged(Plant3D.URIs.HasPipeThickness); } @RelatedElementsAdd(Plant3D.URIs.children) public void addChild(PipelineComponent node) { addNode(Plant3D.URIs.children,node); } @RelatedElementsGet(Plant3D.URIs.children) public Collection getChild() { Collection coll = new ArrayList(); for (IG3DNode n : getNodes(Plant3D.URIs.children)) { coll.add((PipelineComponent)n); } return coll; } @RelatedElementsRem(Plant3D.URIs.children) public void _remChild(PipelineComponent node) { //since we do not now, if DB remove is actually remove or detach, we have to use detach. NodeMap will handle Component removals. deattachNode(Plant3D.URIs.children, node); } public void remChild(PipelineComponent node) { removeNode(Plant3D.URIs.children, node); } @Override public void remove() { // since we do not now, if DB remove is actually remove or detach, we have to use detach. NodeMap will handle Component removals. Collection comps = getChild(); for (PipelineComponent c : comps) c.deattach(); super.remove(); } public List getSortedChild() { List coll = new ArrayList(); for (IG3DNode n : getNodes(Plant3D.URIs.children)) { coll.add((PipelineComponent)n); } Collections.sort(coll, new ComponentComparator()); return coll; } private static String PIPECP = "pipecp"; public void addChild(PipeControlPoint node) { addNode(PIPECP,node); } public void remChild(PipeControlPoint node) { removeNode(PIPECP, node); } public void deattachChild(PipeControlPoint node) { deattachNode(PIPECP, node); } public Collection getControlPoints() { Collection coll = new ArrayList(); for (IG3DNode n : getNodes(PIPECP)) { coll.add((PipeControlPoint)n); } return coll; } public boolean equalSpecs(PipeRun other) { if (!MathTools.equals(pipeDiameter,other.pipeDiameter)) return false; if (turnRadius.length != other.turnRadius.length) return false; for (int i = 0; i < turnRadius.length; i++) { if (!MathTools.equals(turnRadius[i],other.turnRadius[i])) return false; } return true; } public boolean canMerge(PipeRun other) { return MathTools.equals(pipeDiameter,other.pipeDiameter); } /** * Merges contents of PipeRun r2 to this PipeRun. Note: does not connect boundary components! * @param r2 */ public void merge(PipeRun r2) { Map turnIndexMap = null; if (!this.equalSpecs(r2)) { if (!this.canMerge(r2)) throw new IllegalArgumentException("PipeRuns cannot be merged"); // Merge turn radii. turnIndexMap = new HashMap<>(); List mergedTurnRadius = new ArrayList<>(); for (double t : this.getTurnRadiusArray()) { mergedTurnRadius.add(t); } for (int i2 = 0; i2 < r2.getTurnRadiusArray().length; i2++) { double t2 = r2.getTurnRadiusArray()[i2]; boolean found = false; for (int i = 0; i < mergedTurnRadius.size(); i++) { if (MathTools.equals(mergedTurnRadius.get(i), t2)) { turnIndexMap.put(i2, i); found = true; break; } } if (!found) { turnIndexMap.put(i2, mergedTurnRadius.size()); mergedTurnRadius.add(t2); } } for (PipeControlPoint pcp : r2.getControlPoints()) { PipelineComponent comp = pcp.getPipelineComponent(); if (comp instanceof TurnComponent) { } } if (mergedTurnRadius.size() > this.getTurnRadiusArray().length) { double arr[] = new double[mergedTurnRadius.size()]; for (int i = 0; i < mergedTurnRadius.size(); i++) { arr[i] = mergedTurnRadius.get(i); } this.setTurnRadiusArray(arr); } } // Move components and control points Collection pcps = r2.getControlPoints(); for (PipeControlPoint pcp : pcps) { r2.deattachChild(pcp); this.addChild(pcp); PipelineComponent component = pcp.getPipelineComponent(); if (component != null) { if (!(component instanceof Nozzle)) { component.deattach(); this.addChild(component); } else { Nozzle n = (Nozzle)component; n.setPipeRun(this); } } } // Use new turn radii indexes if (turnIndexMap != null) { for (PipeControlPoint pcp : pcps) { PipelineComponent component = pcp.getPipelineComponent(); if (component instanceof TurnComponent) { TurnComponent tc = (TurnComponent)component; if (tc.getTurnRadiusIndex() == null || tc.getTurnRadiusIndex() < 0) continue; tc.setTurnRadiusIndex(turnIndexMap.get(tc.getTurnRadiusIndex())); } } } r2.remove(); } private class ComponentComparator implements Comparator { @Override public int compare(PipelineComponent o1, PipelineComponent o2) { if (o1 == o2) return 0; int i = 1; PipelineComponent c = o1.getPrevious(); while (c != null) { if (c == o2) return i; c = c.getPrevious(); i++; } i = -1; c = o1.getNext(); while (c != null) { if (c == o2) return i; c = c.getNext(); i--; } return 0; } } }