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