]> gerrit.simantics Code Review - simantics/3d.git/blob - org.simantics.proconf.processeditor/src/org/simantics/processeditor/common/PipeComponentProvider.java
28027363b3db7f57c0f204ff7ff8949b259e0a73
[simantics/3d.git] / org.simantics.proconf.processeditor / src / org / simantics / processeditor / common / PipeComponentProvider.java
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
7  *\r
8  * Contributors:\r
9  *     VTT Technical Research Centre of Finland - initial API and implementation\r
10  *******************************************************************************/\r
11 package org.simantics.processeditor.common;\r
12 \r
13 import java.nio.FloatBuffer;\r
14 import java.nio.IntBuffer;\r
15 \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
20 \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
30 \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
35 \r
36 \r
37 \r
38 /**\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
41  * \r
42  * @author Marko Luukkainen\r
43  *\r
44  */\r
45 public class PipeComponentProvider implements GeometryProvider {\r
46         \r
47         \r
48         //private static double ELBOW_RING_ANGLE = 12.0/ Math.PI;\r
49         //private static int RING_SEGMENTS = 8;\r
50         \r
51         private static double ELBOW_RING_ANGLE = 24.0/ Math.PI;\r
52         private static int RING_SEGMENTS = 16;\r
53         \r
54         public boolean canHandle(IEntity instance) {\r
55                 if (instance.isInstanceOf(ProcessResource.plant3Dresource.Elbow))\r
56                         return true;\r
57                 if (instance.isInstanceOf(ProcessResource.plant3Dresource.Straight))\r
58                         return true;\r
59                 if (instance.isInstanceOf(ProcessResource.plant3Dresource.Reducer))\r
60                         return true;    \r
61                 return false;\r
62         }\r
63 \r
64         \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
69                                 return g;\r
70                         }\r
71                         return null;\r
72                 }\r
73                         \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
77                                 return g;\r
78                         }\r
79                         return null;\r
80                 }\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
84                                 return g;\r
85                         }\r
86                         return null;\r
87                 }\r
88                 return null;\r
89         }\r
90         \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
98                 \r
99                 return false;\r
100         }\r
101 \r
102         public boolean getElbowGeometry(IEntity instance, Geometry[] geometry) {\r
103                 PipelineComponent elbow = new PipelineComponent(instance);\r
104                 PipeControlPoint pcp = elbow.getControlPoint();\r
105                 if (pcp == null) {\r
106                         ErrorLogger.defaultLogError("Elbow " + instance + " has no control point", null);\r
107                         return false;\r
108                 }\r
109         TurnControlPoint tcp = new TurnControlPoint(pcp);\r
110         // double turnAngleValue = tcp.getTurnAngleValue();\r
111          \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
116 \r
117         PipeControlPoint startControlPoint = tcp.getPrevious();\r
118         PipeControlPoint endControlPoint = tcp.getNext();\r
119         if (startControlPoint == null || endControlPoint == null)\r
120             return false;\r
121         \r
122         //Point3d start = getLocalPoint(pipeline,startControlPoint);\r
123         //Point3d middle = getLocalPoint(pipeline,tcp);\r
124         //Point3d end = getLocalPoint(pipeline,endControlPoint);     \r
125         \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
129         \r
130         Vector3d dir1 = new Vector3d(middle);\r
131         dir1.sub(start);\r
132         Vector3d dir2 = new Vector3d(end);\r
133         dir2.sub(middle);\r
134         \r
135         Vector3d n = new Vector3d(dir1);\r
136         n.normalize();\r
137         Vector3d offset = new Vector3d(n);\r
138 \r
139         offset.scale(R);\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
150 \r
151         elbowCenter.sub(middle);\r
152             \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
164 //\r
165 //            try {\r
166 //                return OccTriangulator.getGeometry(S4, true);\r
167 //\r
168 //            } catch (Exception e) {\r
169 //                e.printStackTrace();\r
170 //                return null;\r
171 //            }\r
172                 elbow(pipeRadius,elbowRadius,n,normal,turnAngle,elbowCenter,geometry);\r
173                 return true;\r
174         }\r
175         return false;\r
176 \r
177         }\r
178         \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
181                 t.cross(sn,rn);\r
182                 t.normalize();\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
186                 if (rings < 2)\r
187                         rings = 2;\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
194                 \r
195                 aa.x = rn.x;\r
196                 aa.y = rn.y;\r
197                 aa.z = rn.z;\r
198                 for (int i = 0; i < rings; i++) {\r
199                         double a = (double)i/(double)(rings-1) * angle;\r
200                         aa.angle = a;\r
201                         q.set(aa);\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
205                                 t2.add(pos);\r
206                                 t2.add(p);\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
214                         }\r
215                 }\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
227         }\r
228 \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
235         \r
236         \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
239         \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
244         \r
245         Point3d startPipe = new Point3d();//getLocalPoint(pipeline,startControlPoint);\r
246 \r
247         \r
248         Point3d endPipe = new Point3d(); //getLocalPoint(pipeline, endControlPoint);\r
249 \r
250         \r
251         \r
252         \r
253         PipingTools2.getInlineComponentEnds(straight, startPipe, endPipe);\r
254         boolean b = createStraightGeometry(startPipe, endPipe, pipeRadius, geometry);\r
255         if (!b)\r
256                 ErrorLogger.getDefault().logWarning("Straight pipe " + instance + " is too short", null);\r
257         return b;\r
258         }\r
259         \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
263         \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
267 \r
268             dir.normalize();\r
269 \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
273                 Line l = null;\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
285              }\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
293              }\r
294                 \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
298                 if (l != null) {\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
302                 }\r
303                 return true;\r
304         } \r
305         return false;\r
306         }\r
307         \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
311                 dir.normalize();\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
323          }\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
331          }\r
332         \r
333 \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
337         }\r
338 \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
351         //dir.normalize();\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
355             \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
358 //              \r
359 //              \r
360 //            try {\r
361 //                return OccTriangulator.getGeometry(S4, true);\r
362 //\r
363 //            } catch (Exception e) {\r
364 //                e.printStackTrace();\r
365 //                return null;\r
366 //            }\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
380             }\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
388             }\r
389                 \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
397                 return true;\r
398                 \r
399         }\r
400         return false;\r
401 \r
402         }\r
403         \r
404 //      protected TopoDS_Shape getShape(double h, double r1, double r2, boolean eccentric) {\r
405 //              TopoDS_Shape S4 = null;\r
406 //\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
409 //                              .shape();\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
413 //                              .shape();\r
414 //              TopoDS_Wire w2 = (TopoDS_Wire) new BRepBuilderAPI_MakeWire(ed2).shape();\r
415 ////            BRepOffsetAPI_ThruSections generatorb = new BRepOffsetAPI_ThruSections(\r
416 ////                            true, false);\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
422 //        return S4;\r
423 //      }\r
424         \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
431                  Double.isNaN(v.z))\r
432             return false;\r
433         return true;\r
434     }\r
435         \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
440                         t.y = 1.0;\r
441                 } else {\r
442                         t.x = 1.0;\r
443                 }\r
444                 Vector3d d = new Vector3d(dx,dy,dz);\r
445                 Vector3d a = new Vector3d();\r
446                 a.cross(t, d);\r
447                 a.normalize();\r
448                 a.scale(r);\r
449                 Quat4d q = new Quat4d();\r
450                 AxisAngle4d aa = new AxisAngle4d();\r
451                 aa.x = dx;\r
452                 aa.y = dy;\r
453                 aa.z = dz;\r
454                 for (int i = 0; i <= segmentCount; i++) {\r
455                         aa.angle = (double)i / (double) segmentCount * Math.PI * 2.0;\r
456                         q.set(aa);\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
462                         res[0][i].x += x;\r
463                         res[0][i].y += y;\r
464                         res[0][i].z += z;       \r
465                 }\r
466                 return res;\r
467                 \r
468         }\r
469         \r
470         private static int indexCount(int segmentCount, int ringCount) {\r
471                 return 6 * segmentCount * (ringCount - 1);\r
472         }\r
473         \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
479                                 buf.put(index);\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
485                         }\r
486                 }\r
487         }\r
488         \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
492                 } else {\r
493                         return ringCount * segmentCount * 2;\r
494                 }\r
495         }\r
496         \r
497         private static void createEdgeIndices(IntBuffer buf, int segmentCount, int ringCount) {\r
498                 int s = segmentCount + 1;\r
499                 if (ringCount > 1) {\r
500                         int ring = 0;\r
501                         for (int segment = 0; segment < segmentCount; segment++) {\r
502                                 int index = ring * s + segment;\r
503                                 buf.put(index);\r
504                                 buf.put(index + 1);\r
505                         }\r
506                         ring = ringCount - 1;\r
507                         for (int segment = 0; segment < segmentCount; segment++) {\r
508                                 int index = ring * s + segment;\r
509                                 buf.put(index);\r
510                                 buf.put(index + 1);\r
511                         }\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
516                                         buf.put(index);\r
517                                         buf.put(index + s);\r
518                                 }\r
519                         }\r
520                 } else {\r
521                         int ring = 0;\r
522                         for (int segment = 0; segment < segmentCount; segment++) {\r
523                                 int index = ring * s + segment;\r
524                                 buf.put(index);\r
525                                 buf.put(index + 1);\r
526                         }\r
527                 }\r
528                 buf.limit(buf.position());\r
529                 \r
530         }\r
531 }\r