/******************************************************************************* * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.processeditor.common; import java.nio.FloatBuffer; import java.nio.IntBuffer; import javax.vecmath.AxisAngle4d; import javax.vecmath.Point3d; import javax.vecmath.Quat4d; import javax.vecmath.Vector3d; import org.simantics.layer0.utils.IEntity; import org.simantics.processeditor.ProcessResource; import org.simantics.processeditor.stubs.PipeControlPoint; import org.simantics.processeditor.stubs.PipelineComponent; import org.simantics.processeditor.stubs.TurnControlPoint; import org.simantics.proconf.g3d.base.G3DTools; import org.simantics.proconf.g3d.base.GeometryProvider; import org.simantics.proconf.g3d.base.MathTools; import org.simantics.utils.ErrorLogger; import com.jme.scene.Geometry; import com.jme.scene.Line; import com.jme.scene.TriMesh; import com.jme.util.geom.BufferUtils; /** * Geometry provider for pipe components. * TODO : split into three providers (one for each type) to faster access (ShapeNodes can cache geometry provider) * * @author Marko Luukkainen * */ public class PipeComponentProvider implements GeometryProvider { //private static double ELBOW_RING_ANGLE = 12.0/ Math.PI; //private static int RING_SEGMENTS = 8; private static double ELBOW_RING_ANGLE = 24.0/ Math.PI; private static int RING_SEGMENTS = 16; public boolean canHandle(IEntity instance) { if (instance.isInstanceOf(ProcessResource.plant3Dresource.Elbow)) return true; if (instance.isInstanceOf(ProcessResource.plant3Dresource.Straight)) return true; if (instance.isInstanceOf(ProcessResource.plant3Dresource.Reducer)) return true; return false; } public Geometry[] getGeometryFromResource(IEntity instance, boolean transform) { if (instance.isInstanceOf(ProcessResource.plant3Dresource.Elbow)) { Geometry[] g = new Geometry[]{new TriMesh(),new Line()}; if( getElbowGeometry(instance,g)) { return g; } return null; } if (instance.isInstanceOf(ProcessResource.plant3Dresource.Straight)) { Geometry[] g = new Geometry[]{new TriMesh(),new Line()}; if( getStraightGeometry(instance,g)) { return g; } return null; } if (instance.isInstanceOf(ProcessResource.plant3Dresource.Reducer)) { Geometry[] g = new Geometry[]{new TriMesh(),new Line()}; if (getReducerGeometry(instance,g)) { return g; } return null; } return null; } public boolean reconstructGeometry(IEntity instance, boolean transform, Geometry[] geometry) { if (instance.isInstanceOf(ProcessResource.plant3Dresource.Elbow)) return getElbowGeometry(instance,geometry); if (instance.isInstanceOf(ProcessResource.plant3Dresource.Straight)) return getStraightGeometry(instance,geometry); if (instance.isInstanceOf(ProcessResource.plant3Dresource.Reducer)) return getReducerGeometry(instance,geometry); return false; } public boolean getElbowGeometry(IEntity instance, Geometry[] geometry) { PipelineComponent elbow = new PipelineComponent(instance); PipeControlPoint pcp = elbow.getControlPoint(); if (pcp == null) { ErrorLogger.defaultLogError("Elbow " + instance + " has no control point", null); return false; } TurnControlPoint tcp = new TurnControlPoint(pcp); // double turnAngleValue = tcp.getTurnAngleValue(); double pipeRadius = elbow.getPipeDiameter()[0]*0.5; double elbowRadius = elbow.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasTurnRadius); double R = tcp.getLength()[0]; //getComponentOffset(); double turnAngle = tcp.getTurnAngle()[0]; PipeControlPoint startControlPoint = tcp.getPrevious(); PipeControlPoint endControlPoint = tcp.getNext(); if (startControlPoint == null || endControlPoint == null) return false; //Point3d start = getLocalPoint(pipeline,startControlPoint); //Point3d middle = getLocalPoint(pipeline,tcp); //Point3d end = getLocalPoint(pipeline,endControlPoint); Point3d start = G3DTools.getPoint(startControlPoint.getWorldPosition()); Point3d middle = G3DTools.getPoint(tcp.getWorldPosition()); Point3d end = G3DTools.getPoint(endControlPoint.getWorldPosition()); Vector3d dir1 = new Vector3d(middle); dir1.sub(start); Vector3d dir2 = new Vector3d(end); dir2.sub(middle); Vector3d n = new Vector3d(dir1); n.normalize(); Vector3d offset = new Vector3d(n); offset.scale(R); Vector3d startPipe = new Vector3d(middle); startPipe.sub(offset); // normal of the plane Vector3d normal = new Vector3d(); normal.cross(dir1, dir2); Vector3d elbowCenter = new Vector3d(); elbowCenter.cross(normal, dir1); elbowCenter.normalize(); elbowCenter.scale(elbowRadius); elbowCenter.add(startPipe); elbowCenter.sub(middle); // creates sweep shape by rotating a circle // several values must be checked if they are infinite (OCC crashes if they are) if (turnAngle > 0.001 && normal.lengthSquared() > 0.0 && !(Double.isInfinite(turnAngle)) && isValid(n) && isValid(startPipe)) { // System.out.println(startPipe + " " + middle + " " + n + " " + elbowCenter + " " + normal + " " + turnAngle); // gp_Circ circ = new gp_Circ(new double[] { startPipe.x - middle.x, startPipe.y - middle.y, // startPipe.z - middle.z, n.x, n.y, n.z }, pipeRadius); // TopoDS_Edge ed = (TopoDS_Edge) new BRepBuilderAPI_MakeEdge(circ).shape(); // TopoDS_Wire w = (TopoDS_Wire) new BRepBuilderAPI_MakeWire(ed).shape(); // TopoDS_Face F = (TopoDS_Face) new BRepBuilderAPI_MakeFace(w).shape(); // TopoDS_Shape S4 = new BRepPrimAPI_MakeRevol(F, new double[] { elbowCenter.x, elbowCenter.y, elbowCenter.z, // normal.x, normal.y, normal.z }, turnAngle).shape(); // // try { // return OccTriangulator.getGeometry(S4, true); // // } catch (Exception e) { // e.printStackTrace(); // return null; // } elbow(pipeRadius,elbowRadius,n,normal,turnAngle,elbowCenter,geometry); return true; } return false; } public void elbow(double radius, double turnRadius, Vector3d sn, Vector3d rn, double angle, Vector3d p, Geometry[] geometry) { Vector3d t = new Vector3d(); t.cross(sn,rn); t.normalize(); t.scale(turnRadius); Vector3d vs[][] = calcCirc(RING_SEGMENTS, 0.0, 0.0, 0.0, sn.x, sn.y, sn.z, radius); int rings = (int)Math.ceil(angle * ELBOW_RING_ANGLE * Math.sqrt(turnRadius)); if (rings < 2) rings = 2; FloatBuffer v = BufferUtils.createFloatBuffer(vs[0].length * rings * 3); FloatBuffer n = BufferUtils.createFloatBuffer(vs[0].length * rings * 3); Quat4d q = new Quat4d(); AxisAngle4d aa = new AxisAngle4d(); Vector3d pos = new Vector3d(); Vector3d t2 = new Vector3d(); aa.x = rn.x; aa.y = rn.y; aa.z = rn.z; for (int i = 0; i < rings; i++) { double a = (double)i/(double)(rings-1) * angle; aa.angle = a; q.set(aa); MathTools.rotate(q, t, pos); for (int j = 0; j < vs[0].length; j++) { MathTools.rotate(q, vs[0][j], t2); t2.add(pos); t2.add(p); v.put((float)t2.x); v.put((float)t2.y); v.put((float)t2.z); MathTools.rotate(q, vs[1][j], t2); n.put((float)t2.x); n.put((float)t2.y); n.put((float)t2.z); } } int indexCount = indexCount(RING_SEGMENTS, rings); int edgeIndexCount = edgeIndexCount(RING_SEGMENTS, rings); IntBuffer i = BufferUtils.createIntBuffer(indexCount); IntBuffer ei = BufferUtils.createIntBuffer(edgeIndexCount); createIndices(i, RING_SEGMENTS, rings); createEdgeIndices(ei, RING_SEGMENTS, rings); TriMesh m = (TriMesh)geometry[0];//new TriMesh(); Line l = (Line)geometry[1];//new Line(); m.reconstruct(v, n, null, null,i); l.reconstruct(v, null, null, null,ei); //return new Geometry[]{m,l}; } public boolean getStraightGeometry(IEntity instance, Geometry[] geometry) { //Straight straight = new Straight(instance); PipelineComponent straight = new PipelineComponent(instance); double pipeRadius = straight.getPipeDiameter()[0] * 0.5; //PipeRun pipeline = (PipeRun)PipingTools2.getPipeRun(straight.toPipelineComponent());//parent.getGraphicsNode(); //double pipeRadius = pipeline.getPipeDiameter()[0] * 0.5; // PipeControlPoint startControlPoint = (PipeControlPoint)StubFactory.getStubForResource(this.getClass().getClassLoader(),straight.getHasPreviousControlPoint().getResource()); // PipeControlPoint endControlPoint = (PipeControlPoint)StubFactory.getStubForResource(this.getClass().getClassLoader(),straight.getHasNextControlPoint().getResource()); // start and end position of the pipe // positions may be linked to other components, like nozzles // and then their coordinates are in component's local coordinates // which must be transformed into pipeline's local coordinates Point3d startPipe = new Point3d();//getLocalPoint(pipeline,startControlPoint); Point3d endPipe = new Point3d(); //getLocalPoint(pipeline, endControlPoint); PipingTools2.getInlineComponentEnds(straight, startPipe, endPipe); boolean b = createStraightGeometry(startPipe, endPipe, pipeRadius, geometry); if (!b) ErrorLogger.getDefault().logWarning("Straight pipe " + instance + " is too short", null); return b; } public static boolean createStraightGeometry(Point3d startPipe, Point3d endPipe, double pipeRadius, Geometry geometry[]) { Vector3d dir = new Vector3d(endPipe); dir.sub(startPipe); double h = dir.length(); // several values must be checked if they are infinite (OCC crashes if they are) if (h > 0.001 && h < 10000.0 && pipeRadius > 0.01) { dir.normalize(); Vector3d[][] v1 = calcCirc(RING_SEGMENTS, startPipe.x, startPipe.y, startPipe.z, dir.x, dir.y, dir.z, pipeRadius); Vector3d[][] v2 = calcCirc(RING_SEGMENTS, endPipe.x, endPipe.y, endPipe.z, dir.x, dir.y, dir.z, pipeRadius); TriMesh m = (TriMesh)geometry[0];//new TriMesh(); Line l = null; if (geometry.length>1) l = (Line)geometry[1];//new Line(); FloatBuffer v = BufferUtils.createFloatBuffer(v1[0].length * 2 * 3); FloatBuffer n = BufferUtils.createFloatBuffer(v1[0].length * 2 * 3 ); for (int i = 0; i < v1[0].length; i++) { v.put((float)v1[0][i].x); v.put((float)v1[0][i].y); v.put((float)v1[0][i].z); n.put((float)v1[1][i].x); n.put((float)v1[1][i].y); n.put((float)v1[1][i].z); } for (int i = 0; i < v2[0].length; i++) { v.put((float)v2[0][i].x); v.put((float)v2[0][i].y); v.put((float)v2[0][i].z); n.put((float)v2[1][i].x); n.put((float)v2[1][i].y); n.put((float)v2[1][i].z); } IntBuffer i = BufferUtils.createIntBuffer(indexCount(RING_SEGMENTS, 2)); createIndices(i, RING_SEGMENTS, 2); m.reconstruct(v, n, null, null,i); if (l != null) { IntBuffer ei = BufferUtils.createIntBuffer(edgeIndexCount(RING_SEGMENTS, 2)); createEdgeIndices(ei, RING_SEGMENTS, 2); l.reconstruct(v, null, null, null,ei); } return true; } return false; } public static void createStraightEdges(Line l, Point3d startPipe, Point3d endPipe, double pipeRadius) { Vector3d dir = new Vector3d(endPipe); dir.sub(startPipe); dir.normalize(); Vector3d[][] v1 = calcCirc(8, startPipe.x, startPipe.y, startPipe.z, dir.x, dir.y, dir.z, pipeRadius); Vector3d[][] v2 = calcCirc(8, endPipe.x, endPipe.y, endPipe.z, dir.x, dir.y, dir.z, pipeRadius); FloatBuffer v = BufferUtils.createFloatBuffer(v1[0].length * 2 * 3); FloatBuffer n = BufferUtils.createFloatBuffer(v1[0].length * 2 * 3 ); for (int i = 0; i < v1[0].length; i++) { v.put((float)v1[0][i].x); v.put((float)v1[0][i].y); v.put((float)v1[0][i].z); n.put((float)v1[1][i].x); n.put((float)v1[1][i].y); n.put((float)v1[1][i].z); } for (int i = 0; i < v2[0].length; i++) { v.put((float)v2[0][i].x); v.put((float)v2[0][i].y); v.put((float)v2[0][i].z); n.put((float)v2[1][i].x); n.put((float)v2[1][i].y); n.put((float)v2[1][i].z); } IntBuffer ei = BufferUtils.createIntBuffer(edgeIndexCount(8, 2)); createEdgeIndices(ei, 8, 2); l.reconstruct(v, null, null, null,ei); } public boolean getReducerGeometry(IEntity instance,Geometry[] geometry) { //Reducer reducer = new Reducer(instance); PipelineComponent reducer = new PipelineComponent(instance); PipeControlPoint pcp = reducer.getControlPoint(); PipeControlPoint pcp2 = pcp.getSubPoint().iterator().next(); //PipeControlPoint pcp = reducer.getHasControlPoint(); //PipeControlPoint prev = pcp.getPreviousPoint(); //assert (prev != null); //Point3d prevPoint = GraphicsNodeTools.getPoint(prev.getLocalPosition()); //Point3d point = GraphicsNodeTools.getPoint(pcp.getLocalPosition()); //Vector3d dir = new Vector3d(point); //dir.sub(prevPoint); //dir.normalize(); double h = reducer.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength); double r1 = pcp.getPipeDiameter()[0] * 0.5;//reducer.getBottomRadius(); double r2 = pcp2.getPipeDiameter()[0] * 0.5;//reducer.getTopRadiusValue(); if (h > 0.001 && r1 > 0.001 && r2 > 0.001 ) { // TopoDS_Shape S4 = getShape(h,r1,r2, instance.isInstanceOf(GlobalIdMap.get(PSK3DModelingOntologyMapping.ECCENTRIC_REDUCER))); // // // try { // return OccTriangulator.getGeometry(S4, true); // // } catch (Exception e) { // e.printStackTrace(); // return null; // } Vector3d[][] v1 = calcCirc(RING_SEGMENTS, -h * 0.5, 0.0, 0.0, 1.0, 0.0, 0.0, r1); Vector3d[][] v2 = calcCirc(RING_SEGMENTS, h * 0.5, 0.0, instance.isInstanceOf(ProcessResource.plant3Dresource.EccentricReducer) ? (r1 - r2) : 0.0, 1.0, 0.0, 0.0, r2); TriMesh m = (TriMesh)geometry[0];//new TriMesh(); Line l = (Line)geometry[1];//new Line(); FloatBuffer v = BufferUtils.createFloatBuffer(v1[0].length * 2 * 3); FloatBuffer n = BufferUtils.createFloatBuffer(v1[0].length * 2 * 3 ); for (int i = 0; i < v1[0].length; i++) { v.put((float)v1[0][i].x); v.put((float)v1[0][i].y); v.put((float)v1[0][i].z); n.put((float)v1[1][i].x); n.put((float)v1[1][i].y); n.put((float)v1[1][i].z); } for (int i = 0; i < v2[0].length; i++) { v.put((float)v2[0][i].x); v.put((float)v2[0][i].y); v.put((float)v2[0][i].z); n.put((float)v2[1][i].x); n.put((float)v2[1][i].y); n.put((float)v2[1][i].z); } IntBuffer i = BufferUtils.createIntBuffer(indexCount(RING_SEGMENTS, 2)); IntBuffer ei = BufferUtils.createIntBuffer(edgeIndexCount(RING_SEGMENTS, 2)); createIndices(i, RING_SEGMENTS, 2); createEdgeIndices(ei, RING_SEGMENTS, 2); m.reconstruct(v, n, null, null,i); l.reconstruct(v, null, null, null,ei); //return new Geometry[]{m,l}; return true; } return false; } // protected TopoDS_Shape getShape(double h, double r1, double r2, boolean eccentric) { // TopoDS_Shape S4 = null; // // gp_Circ circ1 = new gp_Circ(new double[] { -h * 0.5, 0.0, 0.0, 1.0, 0.0, 0.0 }, r1); // TopoDS_Edge ed1 = (TopoDS_Edge) new BRepBuilderAPI_MakeEdge(circ1) // .shape(); // TopoDS_Wire w1 = (TopoDS_Wire) new BRepBuilderAPI_MakeWire(ed1).shape(); // gp_Circ circ2 = new gp_Circ(new double[] { h * 0.5, 0.0, eccentric ? r1 - r2 : 0.0, 1.0, 0.0, 0.0 }, r2); // TopoDS_Edge ed2 = (TopoDS_Edge) new BRepBuilderAPI_MakeEdge(circ2) // .shape(); // TopoDS_Wire w2 = (TopoDS_Wire) new BRepBuilderAPI_MakeWire(ed2).shape(); //// BRepOffsetAPI_ThruSections generatorb = new BRepOffsetAPI_ThruSections( //// true, false); // BRepOffsetAPI_ThruSections generatorb = new BRepOffsetAPI_ThruSections(true, true); // generatorb.addWire(w1); // generatorb.addWire(w2); // generatorb.build(); // S4 = generatorb.shape(); // return S4; // } private boolean isValid(Vector3d v) { if (Double.isInfinite(v.x) || Double.isNaN(v.x) || Double.isInfinite(v.y) || Double.isNaN(v.y) || Double.isInfinite(v.z) || Double.isNaN(v.z)) return false; return true; } private static Vector3d[][] calcCirc(int segmentCount,double x, double y, double z, double dx, double dy, double dz, double r) { Vector3d res[][] = new Vector3d[2][segmentCount + 1]; Vector3d t = new Vector3d(); if (Math.abs(dy) + Math.abs(dz) < 0.001) { t.y = 1.0; } else { t.x = 1.0; } Vector3d d = new Vector3d(dx,dy,dz); Vector3d a = new Vector3d(); a.cross(t, d); a.normalize(); a.scale(r); Quat4d q = new Quat4d(); AxisAngle4d aa = new AxisAngle4d(); aa.x = dx; aa.y = dy; aa.z = dz; for (int i = 0; i <= segmentCount; i++) { aa.angle = (double)i / (double) segmentCount * Math.PI * 2.0; q.set(aa); res[0][i] = new Vector3d(); res[1][i] = new Vector3d(); MathTools.rotate(q, a, res[0][i]); res[1][i].normalize(res[0][i]); //res[1][i].negate(); res[0][i].x += x; res[0][i].y += y; res[0][i].z += z; } return res; } private static int indexCount(int segmentCount, int ringCount) { return 6 * segmentCount * (ringCount - 1); } private static void createIndices(IntBuffer buf, int segmentCount, int ringCount) { int s = segmentCount + 1; for (int ring = 0; ring < ringCount - 1; ring++) { for (int segment = 0; segment < segmentCount; segment++) { int index = ring * s + segment; buf.put(index); buf.put(index + 1); buf.put(index + s); buf.put(index + s + 1); buf.put(index + s); buf.put(index + 1); } } } private static int edgeIndexCount(int segmentCount, int ringCount) { if (ringCount > 1) { return segmentCount * 4 + ringCount * 4 * (segmentCount / 4); } else { return ringCount * segmentCount * 2; } } private static void createEdgeIndices(IntBuffer buf, int segmentCount, int ringCount) { int s = segmentCount + 1; if (ringCount > 1) { int ring = 0; for (int segment = 0; segment < segmentCount; segment++) { int index = ring * s + segment; buf.put(index); buf.put(index + 1); } ring = ringCount - 1; for (int segment = 0; segment < segmentCount; segment++) { int index = ring * s + segment; buf.put(index); buf.put(index + 1); } int space = segmentCount / 4; for (ring = 0; ring < ringCount - 1; ring++) { for (int segment = 0; segment < segmentCount; segment+=space) { int index = ring * s + segment; buf.put(index); buf.put(index + s); } } } else { int ring = 0; for (int segment = 0; segment < segmentCount; segment++) { int index = ring * s + segment; buf.put(index); buf.put(index + 1); } } buf.limit(buf.position()); } }