1 /*******************************************************************************
\r
2 * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.
\r
3 * All rights reserved. This program and the accompanying materials
\r
4 * are made available under the terms of the Eclipse Public License v1.0
\r
5 * which accompanies this distribution, and is available at
\r
6 * http://www.eclipse.org/legal/epl-v10.html
\r
9 * VTT Technical Research Centre of Finland - initial API and implementation
\r
10 *******************************************************************************/
\r
11 package org.simantics.processeditor.common;
\r
13 import java.nio.FloatBuffer;
\r
14 import java.nio.IntBuffer;
\r
16 import javax.vecmath.AxisAngle4d;
\r
17 import javax.vecmath.Point3d;
\r
18 import javax.vecmath.Quat4d;
\r
19 import javax.vecmath.Vector3d;
\r
21 import org.simantics.layer0.utils.IEntity;
\r
22 import org.simantics.processeditor.ProcessResource;
\r
23 import org.simantics.processeditor.stubs.PipeControlPoint;
\r
24 import org.simantics.processeditor.stubs.PipelineComponent;
\r
25 import org.simantics.processeditor.stubs.TurnControlPoint;
\r
26 import org.simantics.proconf.g3d.base.G3DTools;
\r
27 import org.simantics.proconf.g3d.base.GeometryProvider;
\r
28 import org.simantics.proconf.g3d.base.MathTools;
\r
29 import org.simantics.utils.ui.ErrorLogger;
\r
31 import com.jme.scene.Geometry;
\r
32 import com.jme.scene.Line;
\r
33 import com.jme.scene.TriMesh;
\r
34 import com.jme.util.geom.BufferUtils;
\r
39 * Geometry provider for pipe components.
\r
40 * TODO : split into three providers (one for each type) to faster access (ShapeNodes can cache geometry provider)
\r
42 * @author Marko Luukkainen
\r
45 public class PipeComponentProvider implements GeometryProvider {
\r
48 //private static double ELBOW_RING_ANGLE = 12.0/ Math.PI;
\r
49 //private static int RING_SEGMENTS = 8;
\r
51 private static double ELBOW_RING_ANGLE = 24.0/ Math.PI;
\r
52 private static int RING_SEGMENTS = 16;
\r
54 public boolean canHandle(IEntity instance) {
\r
55 if (instance.isInstanceOf(ProcessResource.plant3Dresource.Elbow))
\r
57 if (instance.isInstanceOf(ProcessResource.plant3Dresource.Straight))
\r
59 if (instance.isInstanceOf(ProcessResource.plant3Dresource.Reducer))
\r
65 public Geometry[] getGeometryFromResource(IEntity instance, boolean transform) {
\r
66 if (instance.isInstanceOf(ProcessResource.plant3Dresource.Elbow)) {
\r
67 Geometry[] g = new Geometry[]{new TriMesh(),new Line()};
\r
68 if( getElbowGeometry(instance,g)) {
\r
74 if (instance.isInstanceOf(ProcessResource.plant3Dresource.Straight)) {
\r
75 Geometry[] g = new Geometry[]{new TriMesh(),new Line()};
\r
76 if( getStraightGeometry(instance,g)) {
\r
81 if (instance.isInstanceOf(ProcessResource.plant3Dresource.Reducer)) {
\r
82 Geometry[] g = new Geometry[]{new TriMesh(),new Line()};
\r
83 if (getReducerGeometry(instance,g)) {
\r
91 public boolean reconstructGeometry(IEntity instance, boolean transform, Geometry[] geometry) {
\r
92 if (instance.isInstanceOf(ProcessResource.plant3Dresource.Elbow))
\r
93 return getElbowGeometry(instance,geometry);
\r
94 if (instance.isInstanceOf(ProcessResource.plant3Dresource.Straight))
\r
95 return getStraightGeometry(instance,geometry);
\r
96 if (instance.isInstanceOf(ProcessResource.plant3Dresource.Reducer))
\r
97 return getReducerGeometry(instance,geometry);
\r
102 public boolean getElbowGeometry(IEntity instance, Geometry[] geometry) {
\r
103 PipelineComponent elbow = new PipelineComponent(instance);
\r
104 PipeControlPoint pcp = elbow.getControlPoint();
\r
106 ErrorLogger.defaultLogError("Elbow " + instance + " has no control point", null);
\r
109 TurnControlPoint tcp = new TurnControlPoint(pcp);
\r
110 // double turnAngleValue = tcp.getTurnAngleValue();
\r
112 double pipeRadius = elbow.getPipeDiameter()[0]*0.5;
\r
113 double elbowRadius = elbow.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasTurnRadius);
\r
114 double R = tcp.getLength()[0]; //getComponentOffset();
\r
115 double turnAngle = tcp.getTurnAngle()[0];
\r
117 PipeControlPoint startControlPoint = tcp.getPrevious();
\r
118 PipeControlPoint endControlPoint = tcp.getNext();
\r
119 if (startControlPoint == null || endControlPoint == null)
\r
122 //Point3d start = getLocalPoint(pipeline,startControlPoint);
\r
123 //Point3d middle = getLocalPoint(pipeline,tcp);
\r
124 //Point3d end = getLocalPoint(pipeline,endControlPoint);
\r
126 Point3d start = G3DTools.getPoint(startControlPoint.getWorldPosition());
\r
127 Point3d middle = G3DTools.getPoint(tcp.getWorldPosition());
\r
128 Point3d end = G3DTools.getPoint(endControlPoint.getWorldPosition());
\r
130 Vector3d dir1 = new Vector3d(middle);
\r
132 Vector3d dir2 = new Vector3d(end);
\r
135 Vector3d n = new Vector3d(dir1);
\r
137 Vector3d offset = new Vector3d(n);
\r
140 Vector3d startPipe = new Vector3d(middle);
\r
141 startPipe.sub(offset);
\r
142 // normal of the plane
\r
143 Vector3d normal = new Vector3d();
\r
144 normal.cross(dir1, dir2);
\r
145 Vector3d elbowCenter = new Vector3d();
\r
146 elbowCenter.cross(normal, dir1);
\r
147 elbowCenter.normalize();
\r
148 elbowCenter.scale(elbowRadius);
\r
149 elbowCenter.add(startPipe);
\r
151 elbowCenter.sub(middle);
\r
153 // creates sweep shape by rotating a circle
\r
154 // several values must be checked if they are infinite (OCC crashes if they are)
\r
155 if (turnAngle > 0.001 && normal.lengthSquared() > 0.0 && !(Double.isInfinite(turnAngle)) && isValid(n) && isValid(startPipe)) {
\r
156 // System.out.println(startPipe + " " + middle + " " + n + " " + elbowCenter + " " + normal + " " + turnAngle);
\r
157 // gp_Circ circ = new gp_Circ(new double[] { startPipe.x - middle.x, startPipe.y - middle.y,
\r
158 // startPipe.z - middle.z, n.x, n.y, n.z }, pipeRadius);
\r
159 // TopoDS_Edge ed = (TopoDS_Edge) new BRepBuilderAPI_MakeEdge(circ).shape();
\r
160 // TopoDS_Wire w = (TopoDS_Wire) new BRepBuilderAPI_MakeWire(ed).shape();
\r
161 // TopoDS_Face F = (TopoDS_Face) new BRepBuilderAPI_MakeFace(w).shape();
\r
162 // TopoDS_Shape S4 = new BRepPrimAPI_MakeRevol(F, new double[] { elbowCenter.x, elbowCenter.y, elbowCenter.z,
\r
163 // normal.x, normal.y, normal.z }, turnAngle).shape();
\r
166 // return OccTriangulator.getGeometry(S4, true);
\r
168 // } catch (Exception e) {
\r
169 // e.printStackTrace();
\r
172 elbow(pipeRadius,elbowRadius,n,normal,turnAngle,elbowCenter,geometry);
\r
179 public void elbow(double radius, double turnRadius, Vector3d sn, Vector3d rn, double angle, Vector3d p, Geometry[] geometry) {
\r
180 Vector3d t = new Vector3d();
\r
183 t.scale(turnRadius);
\r
184 Vector3d vs[][] = calcCirc(RING_SEGMENTS, 0.0, 0.0, 0.0, sn.x, sn.y, sn.z, radius);
\r
185 int rings = (int)Math.ceil(angle * ELBOW_RING_ANGLE * Math.sqrt(turnRadius));
\r
188 FloatBuffer v = BufferUtils.createFloatBuffer(vs[0].length * rings * 3);
\r
189 FloatBuffer n = BufferUtils.createFloatBuffer(vs[0].length * rings * 3);
\r
190 Quat4d q = new Quat4d();
\r
191 AxisAngle4d aa = new AxisAngle4d();
\r
192 Vector3d pos = new Vector3d();
\r
193 Vector3d t2 = new Vector3d();
\r
198 for (int i = 0; i < rings; i++) {
\r
199 double a = (double)i/(double)(rings-1) * angle;
\r
202 MathTools.rotate(q, t, pos);
\r
203 for (int j = 0; j < vs[0].length; j++) {
\r
204 MathTools.rotate(q, vs[0][j], t2);
\r
207 v.put((float)t2.x);
\r
208 v.put((float)t2.y);
\r
209 v.put((float)t2.z);
\r
210 MathTools.rotate(q, vs[1][j], t2);
\r
211 n.put((float)t2.x);
\r
212 n.put((float)t2.y);
\r
213 n.put((float)t2.z);
\r
216 int indexCount = indexCount(RING_SEGMENTS, rings);
\r
217 int edgeIndexCount = edgeIndexCount(RING_SEGMENTS, rings);
\r
218 IntBuffer i = BufferUtils.createIntBuffer(indexCount);
\r
219 IntBuffer ei = BufferUtils.createIntBuffer(edgeIndexCount);
\r
220 createIndices(i, RING_SEGMENTS, rings);
\r
221 createEdgeIndices(ei, RING_SEGMENTS, rings);
\r
222 TriMesh m = (TriMesh)geometry[0];//new TriMesh();
\r
223 Line l = (Line)geometry[1];//new Line();
\r
224 m.reconstruct(v, n, null, null,i);
\r
225 l.reconstruct(v, null, null, null,ei);
\r
226 //return new Geometry[]{m,l};
\r
229 public boolean getStraightGeometry(IEntity instance, Geometry[] geometry) {
\r
230 //Straight straight = new Straight(instance);
\r
231 PipelineComponent straight = new PipelineComponent(instance);
\r
232 double pipeRadius = straight.getPipeDiameter()[0] * 0.5;
\r
233 //PipeRun pipeline = (PipeRun)PipingTools2.getPipeRun(straight.toPipelineComponent());//parent.getGraphicsNode();
\r
234 //double pipeRadius = pipeline.getPipeDiameter()[0] * 0.5;
\r
237 // PipeControlPoint startControlPoint = (PipeControlPoint)StubFactory.getStubForResource(this.getClass().getClassLoader(),straight.getHasPreviousControlPoint().getResource());
\r
238 // PipeControlPoint endControlPoint = (PipeControlPoint)StubFactory.getStubForResource(this.getClass().getClassLoader(),straight.getHasNextControlPoint().getResource());
\r
240 // start and end position of the pipe
\r
241 // positions may be linked to other components, like nozzles
\r
242 // and then their coordinates are in component's local coordinates
\r
243 // which must be transformed into pipeline's local coordinates
\r
245 Point3d startPipe = new Point3d();//getLocalPoint(pipeline,startControlPoint);
\r
248 Point3d endPipe = new Point3d(); //getLocalPoint(pipeline, endControlPoint);
\r
253 PipingTools2.getInlineComponentEnds(straight, startPipe, endPipe);
\r
254 boolean b = createStraightGeometry(startPipe, endPipe, pipeRadius, geometry);
\r
256 ErrorLogger.getDefault().logWarning("Straight pipe " + instance + " is too short", null);
\r
260 public static boolean createStraightGeometry(Point3d startPipe, Point3d endPipe, double pipeRadius, Geometry geometry[]) {
\r
261 Vector3d dir = new Vector3d(endPipe);
\r
262 dir.sub(startPipe);
\r
264 double h = dir.length();
\r
265 // several values must be checked if they are infinite (OCC crashes if they are)
\r
266 if (h > 0.001 && h < 10000.0 && pipeRadius > 0.01) {
\r
270 Vector3d[][] v1 = calcCirc(RING_SEGMENTS, startPipe.x, startPipe.y, startPipe.z, dir.x, dir.y, dir.z, pipeRadius);
\r
271 Vector3d[][] v2 = calcCirc(RING_SEGMENTS, endPipe.x, endPipe.y, endPipe.z, dir.x, dir.y, dir.z, pipeRadius);
\r
272 TriMesh m = (TriMesh)geometry[0];//new TriMesh();
\r
274 if (geometry.length>1)
\r
275 l = (Line)geometry[1];//new Line();
\r
276 FloatBuffer v = BufferUtils.createFloatBuffer(v1[0].length * 2 * 3);
\r
277 FloatBuffer n = BufferUtils.createFloatBuffer(v1[0].length * 2 * 3 );
\r
278 for (int i = 0; i < v1[0].length; i++) {
\r
279 v.put((float)v1[0][i].x);
\r
280 v.put((float)v1[0][i].y);
\r
281 v.put((float)v1[0][i].z);
\r
282 n.put((float)v1[1][i].x);
\r
283 n.put((float)v1[1][i].y);
\r
284 n.put((float)v1[1][i].z);
\r
286 for (int i = 0; i < v2[0].length; i++) {
\r
287 v.put((float)v2[0][i].x);
\r
288 v.put((float)v2[0][i].y);
\r
289 v.put((float)v2[0][i].z);
\r
290 n.put((float)v2[1][i].x);
\r
291 n.put((float)v2[1][i].y);
\r
292 n.put((float)v2[1][i].z);
\r
295 IntBuffer i = BufferUtils.createIntBuffer(indexCount(RING_SEGMENTS, 2));
\r
296 createIndices(i, RING_SEGMENTS, 2);
\r
297 m.reconstruct(v, n, null, null,i);
\r
299 IntBuffer ei = BufferUtils.createIntBuffer(edgeIndexCount(RING_SEGMENTS, 2));
\r
300 createEdgeIndices(ei, RING_SEGMENTS, 2);
\r
301 l.reconstruct(v, null, null, null,ei);
\r
308 public static void createStraightEdges(Line l, Point3d startPipe, Point3d endPipe, double pipeRadius) {
\r
309 Vector3d dir = new Vector3d(endPipe);
\r
310 dir.sub(startPipe);
\r
312 Vector3d[][] v1 = calcCirc(8, startPipe.x, startPipe.y, startPipe.z, dir.x, dir.y, dir.z, pipeRadius);
\r
313 Vector3d[][] v2 = calcCirc(8, endPipe.x, endPipe.y, endPipe.z, dir.x, dir.y, dir.z, pipeRadius);
\r
314 FloatBuffer v = BufferUtils.createFloatBuffer(v1[0].length * 2 * 3);
\r
315 FloatBuffer n = BufferUtils.createFloatBuffer(v1[0].length * 2 * 3 );
\r
316 for (int i = 0; i < v1[0].length; i++) {
\r
317 v.put((float)v1[0][i].x);
\r
318 v.put((float)v1[0][i].y);
\r
319 v.put((float)v1[0][i].z);
\r
320 n.put((float)v1[1][i].x);
\r
321 n.put((float)v1[1][i].y);
\r
322 n.put((float)v1[1][i].z);
\r
324 for (int i = 0; i < v2[0].length; i++) {
\r
325 v.put((float)v2[0][i].x);
\r
326 v.put((float)v2[0][i].y);
\r
327 v.put((float)v2[0][i].z);
\r
328 n.put((float)v2[1][i].x);
\r
329 n.put((float)v2[1][i].y);
\r
330 n.put((float)v2[1][i].z);
\r
334 IntBuffer ei = BufferUtils.createIntBuffer(edgeIndexCount(8, 2));
\r
335 createEdgeIndices(ei, 8, 2);
\r
336 l.reconstruct(v, null, null, null,ei);
\r
339 public boolean getReducerGeometry(IEntity instance,Geometry[] geometry) {
\r
340 //Reducer reducer = new Reducer(instance);
\r
341 PipelineComponent reducer = new PipelineComponent(instance);
\r
342 PipeControlPoint pcp = reducer.getControlPoint();
\r
343 PipeControlPoint pcp2 = pcp.getSubPoint().iterator().next();
\r
344 //PipeControlPoint pcp = reducer.getHasControlPoint();
\r
345 //PipeControlPoint prev = pcp.getPreviousPoint();
\r
346 //assert (prev != null);
\r
347 //Point3d prevPoint = GraphicsNodeTools.getPoint(prev.getLocalPosition());
\r
348 //Point3d point = GraphicsNodeTools.getPoint(pcp.getLocalPosition());
\r
349 //Vector3d dir = new Vector3d(point);
\r
350 //dir.sub(prevPoint);
\r
352 double h = reducer.getSingleRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength);
\r
353 double r1 = pcp.getPipeDiameter()[0] * 0.5;//reducer.getBottomRadius();
\r
354 double r2 = pcp2.getPipeDiameter()[0] * 0.5;//reducer.getTopRadiusValue();
\r
356 if (h > 0.001 && r1 > 0.001 && r2 > 0.001 ) {
\r
357 // TopoDS_Shape S4 = getShape(h,r1,r2, instance.isInstanceOf(GlobalIdMap.get(PSK3DModelingOntologyMapping.ECCENTRIC_REDUCER)));
\r
361 // return OccTriangulator.getGeometry(S4, true);
\r
363 // } catch (Exception e) {
\r
364 // e.printStackTrace();
\r
367 Vector3d[][] v1 = calcCirc(RING_SEGMENTS, -h * 0.5, 0.0, 0.0, 1.0, 0.0, 0.0, r1);
\r
368 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);
\r
369 TriMesh m = (TriMesh)geometry[0];//new TriMesh();
\r
370 Line l = (Line)geometry[1];//new Line();
\r
371 FloatBuffer v = BufferUtils.createFloatBuffer(v1[0].length * 2 * 3);
\r
372 FloatBuffer n = BufferUtils.createFloatBuffer(v1[0].length * 2 * 3 );
\r
373 for (int i = 0; i < v1[0].length; i++) {
\r
374 v.put((float)v1[0][i].x);
\r
375 v.put((float)v1[0][i].y);
\r
376 v.put((float)v1[0][i].z);
\r
377 n.put((float)v1[1][i].x);
\r
378 n.put((float)v1[1][i].y);
\r
379 n.put((float)v1[1][i].z);
\r
381 for (int i = 0; i < v2[0].length; i++) {
\r
382 v.put((float)v2[0][i].x);
\r
383 v.put((float)v2[0][i].y);
\r
384 v.put((float)v2[0][i].z);
\r
385 n.put((float)v2[1][i].x);
\r
386 n.put((float)v2[1][i].y);
\r
387 n.put((float)v2[1][i].z);
\r
390 IntBuffer i = BufferUtils.createIntBuffer(indexCount(RING_SEGMENTS, 2));
\r
391 IntBuffer ei = BufferUtils.createIntBuffer(edgeIndexCount(RING_SEGMENTS, 2));
\r
392 createIndices(i, RING_SEGMENTS, 2);
\r
393 createEdgeIndices(ei, RING_SEGMENTS, 2);
\r
394 m.reconstruct(v, n, null, null,i);
\r
395 l.reconstruct(v, null, null, null,ei);
\r
396 //return new Geometry[]{m,l};
\r
404 // protected TopoDS_Shape getShape(double h, double r1, double r2, boolean eccentric) {
\r
405 // TopoDS_Shape S4 = null;
\r
407 // gp_Circ circ1 = new gp_Circ(new double[] { -h * 0.5, 0.0, 0.0, 1.0, 0.0, 0.0 }, r1);
\r
408 // TopoDS_Edge ed1 = (TopoDS_Edge) new BRepBuilderAPI_MakeEdge(circ1)
\r
410 // TopoDS_Wire w1 = (TopoDS_Wire) new BRepBuilderAPI_MakeWire(ed1).shape();
\r
411 // 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);
\r
412 // TopoDS_Edge ed2 = (TopoDS_Edge) new BRepBuilderAPI_MakeEdge(circ2)
\r
414 // TopoDS_Wire w2 = (TopoDS_Wire) new BRepBuilderAPI_MakeWire(ed2).shape();
\r
415 //// BRepOffsetAPI_ThruSections generatorb = new BRepOffsetAPI_ThruSections(
\r
417 // BRepOffsetAPI_ThruSections generatorb = new BRepOffsetAPI_ThruSections(true, true);
\r
418 // generatorb.addWire(w1);
\r
419 // generatorb.addWire(w2);
\r
420 // generatorb.build();
\r
421 // S4 = generatorb.shape();
\r
425 private boolean isValid(Vector3d v) {
\r
426 if (Double.isInfinite(v.x) ||
\r
427 Double.isNaN(v.x) ||
\r
428 Double.isInfinite(v.y) ||
\r
429 Double.isNaN(v.y) ||
\r
430 Double.isInfinite(v.z) ||
\r
436 private static Vector3d[][] calcCirc(int segmentCount,double x, double y, double z, double dx, double dy, double dz, double r) {
\r
437 Vector3d res[][] = new Vector3d[2][segmentCount + 1];
\r
438 Vector3d t = new Vector3d();
\r
439 if (Math.abs(dy) + Math.abs(dz) < 0.001) {
\r
444 Vector3d d = new Vector3d(dx,dy,dz);
\r
445 Vector3d a = new Vector3d();
\r
449 Quat4d q = new Quat4d();
\r
450 AxisAngle4d aa = new AxisAngle4d();
\r
454 for (int i = 0; i <= segmentCount; i++) {
\r
455 aa.angle = (double)i / (double) segmentCount * Math.PI * 2.0;
\r
457 res[0][i] = new Vector3d();
\r
458 res[1][i] = new Vector3d();
\r
459 MathTools.rotate(q, a, res[0][i]);
\r
460 res[1][i].normalize(res[0][i]);
\r
461 //res[1][i].negate();
\r
470 private static int indexCount(int segmentCount, int ringCount) {
\r
471 return 6 * segmentCount * (ringCount - 1);
\r
474 private static void createIndices(IntBuffer buf, int segmentCount, int ringCount) {
\r
475 int s = segmentCount + 1;
\r
476 for (int ring = 0; ring < ringCount - 1; ring++) {
\r
477 for (int segment = 0; segment < segmentCount; segment++) {
\r
478 int index = ring * s + segment;
\r
480 buf.put(index + 1);
\r
481 buf.put(index + s);
\r
482 buf.put(index + s + 1);
\r
483 buf.put(index + s);
\r
484 buf.put(index + 1);
\r
489 private static int edgeIndexCount(int segmentCount, int ringCount) {
\r
490 if (ringCount > 1) {
\r
491 return segmentCount * 4 + ringCount * 4 * (segmentCount / 4);
\r
493 return ringCount * segmentCount * 2;
\r
497 private static void createEdgeIndices(IntBuffer buf, int segmentCount, int ringCount) {
\r
498 int s = segmentCount + 1;
\r
499 if (ringCount > 1) {
\r
501 for (int segment = 0; segment < segmentCount; segment++) {
\r
502 int index = ring * s + segment;
\r
504 buf.put(index + 1);
\r
506 ring = ringCount - 1;
\r
507 for (int segment = 0; segment < segmentCount; segment++) {
\r
508 int index = ring * s + segment;
\r
510 buf.put(index + 1);
\r
512 int space = segmentCount / 4;
\r
513 for (ring = 0; ring < ringCount - 1; ring++) {
\r
514 for (int segment = 0; segment < segmentCount; segment+=space) {
\r
515 int index = ring * s + segment;
\r
517 buf.put(index + s);
\r
522 for (int segment = 0; segment < segmentCount; segment++) {
\r
523 int index = ring * s + segment;
\r
525 buf.put(index + 1);
\r
528 buf.limit(buf.position());
\r