Created
May 10, 2015 11:48
-
-
Save pixelpusher/d968cbbd8f18f5be7d87 to your computer and use it in GitHub Desktop.
ProfilePathAlignmentSpline2D
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* <p>Based on a toxiclibs example, a 2D polygon profile created using | |
* a smoothed triangle shape generatd by a 2D spline curve is being swept | |
* along a 3D spline path and aligned to the path direction using quaternions. | |
* This generates also a triangular mesha along the path that can be exported. | |
* The example demonstrates the usage of the alignment quaternion | |
* in combination with a 4x4 transformation matrix, as well as the use | |
* of the toAxisAngle() method to compute a rotation axis from a quat, | |
* and some manual mesh creation functionality. | |
* </p> | |
* <p> | |
* It also demostrates the limitaitons of using quarternion rotations, as they | |
* lead to some tortured, overly-twisty geometry due to simplistic rotation | |
* calcuations along the path. | |
* </p> | |
* | |
* <p><strong>Usage:</strong><ul> | |
* <li>l: toggle between line/dot rendering</li> | |
* </ul></p> | |
*/ | |
/* | |
* Original Copyright (c) 2011 Karsten Schmidt | |
* Modified 2015 by Evan Raskob (http://pixelist.info) to use splines | |
* and to create mesh geometry along the path. | |
* | |
* This library is free software; you can redistribute it and/or | |
* modify it under the terms of the GNU Lesser General Public | |
* License as published by the Free Software Foundation; either | |
* version 2.1 of the License, or (at your option) any later version. | |
* | |
* http://creativecommons.org/licenses/LGPL/2.1/ | |
* | |
* This library is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
* Lesser General Public License for more details. | |
* | |
* You should have received a copy of the GNU Lesser General Public | |
* License along with this library; if not, write to the Free Software | |
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
*/ | |
import toxi.geom.*; | |
import toxi.geom.mesh.*; | |
import toxi.processing.*; | |
import java.util.Iterator; | |
import java.util.List; | |
Spline2D spline; | |
List<Vec2D> verts, points; | |
int subDiv = 30; | |
int quality = 5; | |
TriangleMesh mesh = null; | |
ToxiclibsSupport gfx; | |
List<Vec3D> path; | |
ArrayList<Vec3D> tubeVertices=new ArrayList<Vec3D>(); | |
int pathID=0; | |
boolean doRenderPoints; | |
void setup() { | |
size(1024, 720, P3D); | |
gfx=new ToxiclibsSupport(this); | |
int triSize = 40; | |
Polygon2D tri = (new Triangle2D(new Vec2D(-triSize, 0), new Vec2D(0,0), new Vec2D(-triSize/2, -triSize/2))) | |
.toPolygon2D(); | |
//for (Vec2D p : tri.vertices) { | |
// println("vert: " + p); | |
//} | |
spline=new Spline2D(tri.vertices); | |
spline.updateCoefficients(); | |
spline.computeVertices(subDiv); | |
verts = spline.getDecimatedVertices(quality, true); | |
println("quality["+quality+"] results in " + verts.size() + " points"); | |
points = spline.pointList; | |
// compute spiral key points (every 45 degrees) | |
ArrayList spiralPoints = new ArrayList(); | |
for (float theta=-TWO_PI, r=100; theta<8*TWO_PI; theta+=QUARTER_PI) { | |
Vec3D p=Vec3D.fromXYTheta(theta).scale(r).add(200, 0, 0).rotateY(theta/9); | |
spiralPoints.add(p); | |
} | |
// use points to compute a spline and sample at regular interval | |
Spline3D s=new Spline3D(spiralPoints); | |
s.computeVertices(10); | |
path=s.getDecimatedVertices(4); | |
println("spiral path has: " + path.size() + " vertices"); | |
int totalVertsInMesh = path.size() * verts.size(); | |
int totalFacesInMesh = totalVertsInMesh/2 + 2; | |
println("totalFacesInMesh: " + totalFacesInMesh); | |
println("totalVertsInMesh: " + totalVertsInMesh); | |
mesh = new TriangleMesh("sweepspiral", totalVertsInMesh, totalFacesInMesh); | |
} | |
void draw() { | |
background(51); | |
lights(); | |
translate(width / 2, height / 2, 0); | |
rotateX(mouseY * 0.01f); | |
rotateY(mouseX * 0.01f); | |
noStroke(); | |
gfx.origin(300); | |
stroke(255, 0, 255); | |
gfx.lineStrip3D(path); | |
if (pathID<path.size()-1) { | |
// compute current curve direction | |
Vec3D dir=path.get(pathID+1).sub(path.get(pathID)).normalize(); | |
// calculate alignment orientation for direction | |
// our profile shape is in XY plane (2D) and | |
// so its "forward" direction is the positive Z axis | |
Quaternion alignment=Quaternion.getAlignmentQuat(dir, Vec3D.Z_AXIS); | |
// construct a matrix to move shape to current curve position | |
Matrix4x4 mat=new Matrix4x4().translateSelf(path.get(pathID)); | |
// then combine with alignment matrix | |
mat.multiplySelf(alignment.toMatrix4x4()); | |
// then apply matrix to (copies of) all profile shape vertices | |
// and append them to global vertex list | |
for (Vec2D p : verts) { | |
tubeVertices.add(mat.applyToSelf(p.to3DXY())); | |
} | |
if (tubeVertices.size() >= 2*verts.size()) | |
{ | |
int startIndex = tubeVertices.size() - 2*verts.size(); | |
int endIndex = tubeVertices.size()- verts.size(); | |
for (int i=startIndex; i<endIndex-1; i++) | |
{ | |
Vec3D prevProfileVert1 = tubeVertices.get(i); | |
Vec3D prevProfileVert2 = tubeVertices.get(i+1); | |
Vec3D currProfileVert1 = tubeVertices.get(i+verts.size()); | |
Vec3D currProfileVert2 = tubeVertices.get(i+verts.size()+1); | |
mesh.addFace(prevProfileVert1, prevProfileVert2, currProfileVert1); | |
mesh.addFace(prevProfileVert2, currProfileVert2, currProfileVert1); | |
} | |
// add last face a bit manually | |
// why? To avoid using % inside the above each loop, hopefully save some CPU cycles? | |
Vec3D prevProfileVert1 = tubeVertices.get(tubeVertices.size() - verts.size()-1); | |
Vec3D prevProfileVert2 = tubeVertices.get(tubeVertices.size() - 2*verts.size()); | |
Vec3D currProfileVert1 = tubeVertices.get(tubeVertices.size()-1); | |
Vec3D currProfileVert2 = tubeVertices.get(tubeVertices.size() - verts.size()); | |
mesh.addFace(prevProfileVert1, prevProfileVert2, currProfileVert1); | |
mesh.addFace(prevProfileVert2, currProfileVert2, currProfileVert1); | |
mesh.computeFaceNormals(); | |
} | |
pathID++; | |
} | |
stroke(255); | |
if (!doRenderPoints) { | |
//gfx.points3D(tubeVertices); | |
gfx.mesh(mesh); | |
} else { | |
gfx.lineStrip3D(tubeVertices); | |
} | |
// draw coordinate system for current spline direction | |
int id=constrain(pathID-2, 0, path.size()-2); | |
// current curve direction | |
Vec3D dir=path.get(id+1).sub(path.get(id)).normalize(); | |
// compute rotation axis and angle | |
float[] axis=Quaternion.getAlignmentQuat(dir, Vec3D.Z_AXIS).toAxisAngle(); | |
// move to curr/last curve point | |
gfx.translate(path.get(id+1)); | |
// rotate around computed axis | |
rotate(axis[0], axis[1], axis[2], axis[3]); | |
// draw rotated coordinate system | |
gfx.origin(new Vec3D(), 100); | |
} | |
void keyPressed() { | |
if (key=='l') { | |
doRenderPoints=!doRenderPoints; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment