--- /dev/null
+package org.simantics.g3d.jme.shape;\r
+\r
+import java.util.List;\r
+\r
+import javax.vecmath.AxisAngle4d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.g3d.math.MathTools;\r
+\r
+import com.jme3.app.Application;\r
+import com.jme3.material.Material;\r
+import com.jme3.math.ColorRGBA;\r
+import com.jme3.scene.Geometry;\r
+import com.jme3.scene.Mesh;\r
+import com.jme3.scene.VertexBuffer.Type;\r
+\r
+public class TubeActor extends Geometry {\r
+ \r
+ List<Vector3d> vertices;\r
+ List<ColorRGBA> colors;\r
+ List<Double> radiis;\r
+ Double radius = 1.0;\r
+ int resolution = 8;\r
+ \r
+ public TubeActor() {\r
+ super();\r
+ }\r
+ \r
+ public void setResolution(int resolution) {\r
+ if (resolution > 2)\r
+ this.resolution = resolution;\r
+ }\r
+ \r
+ public void setVertices(List<Vector3d> vertices) {\r
+ this.vertices = vertices;\r
+ }\r
+\r
+ public void setColors(List<ColorRGBA> colors) {\r
+ this.colors = colors;\r
+ }\r
+ \r
+ public void setRadiis(List<Double> radiis) {\r
+ this.radiis = radiis;\r
+ }\r
+ \r
+ public void setRadius(Double radius) {\r
+ this.radius = radius;\r
+ }\r
+ \r
+ \r
+ \r
+ public void createTube(Application app) {\r
+ if (vertices.size() < 2 )\r
+ throw new IllegalArgumentException("Tube must have at least two vertices");\r
+ \r
+ Vector3d t = new Vector3d();\r
+ \r
+ for (int i = 0; i < vertices.size() - 1; i++) {\r
+ t.set(vertices.get(i+1));\r
+ t.sub(vertices.get(i));\r
+ if (t.lengthSquared() < 0.0001)\r
+ throw new IllegalArgumentException("vertices at index " + i + " are too close to each other");\r
+ }\r
+ \r
+ float points[] = new float[vertices.size()*resolution*3];\r
+ float normals[] = new float[vertices.size()*resolution*3];\r
+ float clrs[] = null;\r
+ if (this.colors != null)\r
+ clrs = new float[vertices.size()*resolution*4];\r
+ \r
+ for (int i = 0; i < vertices.size(); i++) {\r
+ createCircle(i,points,normals, clrs);\r
+ }\r
+ \r
+ int index[] = new int[(vertices.size()-1)*resolution*6];\r
+ \r
+ createIndices(index);\r
+ \r
+ Mesh mesh = new Mesh();\r
+ mesh.setBuffer(Type.Index, 3, index);\r
+ mesh.setBuffer(Type.Position, 3, points);\r
+ mesh.setBuffer(Type.Normal, 3, normals);\r
+ if (clrs != null)\r
+ mesh.setBuffer(Type.Color, 4, clrs);\r
+ setMesh(mesh);\r
+ updateModelBound();\r
+ \r
+ ColorRGBA color = new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f);\r
+ Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Light/Lighting.j3md");\r
+ mat.setColor("Diffuse", color);\r
+ mat.setColor("Ambient", color);\r
+ mat.setColor("Specular", new ColorRGBA(1, 1, 1, 1));\r
+ mat.setBoolean("UseMaterialColors", true);\r
+ if (clrs != null)\r
+ mat.setBoolean("UseVertexColor", true);\r
+ setMaterial(mat);\r
+ \r
+ vertices.clear();\r
+ if (colors != null)\r
+ colors.clear();\r
+ if (radiis != null)\r
+ radiis.clear();\r
+ \r
+ }\r
+ \r
+ private void createCircle(int i, float points[],float normals[], float clrs[]) {\r
+ final Vector3d up = new Vector3d(0,1,0);\r
+ final Vector3d up2 = new Vector3d(0,0,1);\r
+ ColorRGBA c = null;\r
+ if (clrs != null)\r
+ c = this.colors.get(i);\r
+ Vector3d p = vertices.get(i);\r
+ Vector3d t = getTangent(i);\r
+ Vector3d n = new Vector3d();\r
+ if (up.dot(t) < 0.99) {\r
+ n.cross(up, t);\r
+ } else {\r
+ n.cross(up2, t);\r
+ }\r
+ n.normalize();\r
+ if (radiis != null) {\r
+ n.scale(radiis.get(i));\r
+ } else {\r
+ n.scale(radius);\r
+ }\r
+ \r
+ for (int index = 0; index < resolution; index ++) {\r
+ Vector3d v;\r
+ if (index == 0) {\r
+ v = new Vector3d(n);\r
+ \r
+ } else {\r
+ AxisAngle4d aa = new AxisAngle4d(t, (Math.PI * 2 * (double)index)/(double)resolution);\r
+ v = new Vector3d();\r
+ MathTools.rotate(MathTools.getQuat(aa), n, v);\r
+ }\r
+ int vIndex = (i*resolution + index)*3; \r
+ points[vIndex+0] = (float)(p.x+v.x);\r
+ points[vIndex+1] = (float)(p.y + v.y);\r
+ points[vIndex+2] = (float)(p.z + v.z);\r
+ v.normalize();\r
+ normals[vIndex+0] = (float)(v.x);\r
+ normals[vIndex+1] = (float)(v.y);\r
+ normals[vIndex+2] = (float)(v.z);\r
+ if (colors != null) {\r
+ int cIndex = (i*resolution + index)*4;\r
+ clrs[cIndex] = c.r;\r
+ clrs[cIndex+1] = c.g;\r
+ clrs[cIndex+2] = c.b;\r
+ clrs[cIndex+3] = c.a;\r
+ }\r
+ }\r
+ }\r
+ \r
+ private Vector3d getTangent(int i) {\r
+ Vector3d p,n;\r
+ if (i == 0) {\r
+ p = vertices.get(0);\r
+ n = vertices.get(1);\r
+ } else if (i == vertices.size() - 1) {\r
+ p = vertices.get(i-1);\r
+ n = vertices.get(i);\r
+ } else {\r
+ p = vertices.get(i-1);\r
+ n = vertices.get(i+1);\r
+ }\r
+ n = new Vector3d(n);\r
+ n.sub(p);\r
+ n.normalize();\r
+ return n;\r
+ }\r
+ \r
+ private void createIndices(int index[]) {\r
+ for (int c = 0; c < vertices.size() - 1; c++) {\r
+ for (int s = 0; s < resolution; s++) {\r
+ int ii = (c * resolution + s) * 6;\r
+ int iv = c*resolution + s;\r
+ \r
+ /*\r
+ iv+1 ---- iv + resolution + 1\r
+ | /|\r
+ |/ |\r
+ iv ---- iv + resolution \r
+ */\r
+ if (s < resolution - 1) {\r
+ index[ii+2] = iv;\r
+ index[ii+1] = iv+resolution;\r
+ index[ii+0] = iv+resolution+1;\r
+ \r
+ index[ii+5] = iv;\r
+ index[ii+4] = iv+resolution+1;\r
+ index[ii+3] = iv+1;\r
+ } else {\r
+ index[ii+2] = iv;\r
+ index[ii+1] = iv+resolution;\r
+ index[ii+0] = iv+1;\r
+ \r
+ index[ii+5] = iv;\r
+ index[ii+4] = iv+1;\r
+ index[ii+3] = iv+1-resolution;\r
+ }\r
+ }\r
+ }\r
+ }\r
+}\r