org.scijava.java3d.utils.geometry.Triangulator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of j3dutils Show documentation
Show all versions of j3dutils Show documentation
Utility functions for the Java 3D Graphics API
The newest version!
/*
* Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any
* kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
* WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
* EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
* NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
* USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
* ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
* CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
* REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
* INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or
* intended for use in the design, construction, operation or
* maintenance of any nuclear facility.
*
*/
// ----------------------------------------------------------------------
//
// The reference to Fast Industrial Strength Triangulation (FIST) code
// in this release by Sun Microsystems is related to Sun's rewrite of
// an early version of FIST. FIST was originally created by Martin
// Held and Joseph Mitchell at Stony Brook University and is
// incorporated by Sun under an agreement with The Research Foundation
// of SUNY (RFSUNY). The current version of FIST is available for
// commercial use under a license agreement with RFSUNY on behalf of
// the authors and Stony Brook University. Please contact the Office
// of Technology Licensing at Stony Brook, phone 631-632-9009, for
// licensing information.
//
// ----------------------------------------------------------------------
package org.scijava.java3d.utils.geometry;
import java.util.Random;
import org.scijava.vecmath.Point2f;
import org.scijava.vecmath.Point3f;
import org.scijava.vecmath.Vector3f;
import org.scijava.java3d.internal.J3dUtilsI18N;
/**
* Triangulator is a utility for turning arbitrary polygons into triangles
* so they can be rendered by Java 3D.
* Polygons can be concave, nonplanar, and can contain holes.
* @see GeometryInfo
*/
public class Triangulator extends Object {
GeometryInfo gInfo = null;
int faces[] = null;
int loops[] = null;
int chains[] = null;
Point2f points[] = null;
Triangle triangles[] = null;
ListNode list[] = null;
Random randomGen = null;
int numPoints = 0;
int maxNumPoints = 0;
int numList = 0;
int maxNumList = 0;
int numLoops = 0;
int maxNumLoops = 0;
int numTriangles = 0;
int maxNumTriangles = 0;
int numFaces = 0;
int numTexSets = 0;
// int maxNumFaces = 0;
int firstNode = 0;
int numChains = 0;
int maxNumChains = 0;
// For Clean class.
Point2f[] pUnsorted = null;
int maxNumPUnsorted = 0;
// For NoHash class.
boolean noHashingEdges = false;
boolean noHashingPnts = false;
int loopMin, loopMax;
PntNode vtxList[] = null;
int numVtxList = 0;
int numReflex = 0;
int reflexVertices;
// For Bridge class.
Distance distances[] = null;
int maxNumDist = 0;
Left leftMost[] = null;
int maxNumLeftMost = 0;
// For Heap class.
HeapNode heap[] = null;
int numHeap = 0;
int maxNumHeap = 0;
int numZero = 0;
// For Orientation class.
int maxNumPolyArea = 0;
double polyArea[] = null;
int stripCounts[] = null;
int vertexIndices[] = null;
Point3f vertices[] = null;
Object colors[] = null;
Vector3f normals[] = null;
boolean ccwLoop = true;
boolean earsRandom = true;
boolean earsSorted = true;
int identCntr; // Not sure what is this for. (Ask Martin)
// double epsilon = 1.0e-12;
double epsilon = 1.0e-12;
static final double ZERO = 1.0e-8;
static final int EARS_SEQUENCE = 0;
static final int EARS_RANDOM = 1;
static final int EARS_SORTED = 2;
static final int INC_LIST_BK = 100;
static final int INC_LOOP_BK = 20;
static final int INC_TRI_BK = 50;
static final int INC_POINT_BK = 100;
static final int INC_DIST_BK = 50;
private static final int DEBUG = 0;
/**
* Creates a new instance of the Triangulator.
* @deprecated This class is created automatically when needed in
* GeometryInfo and never needs to be used directly. Putting data
* into a GeometryInfo with primitive POLYGON_ARRAY automatically
* causes the triangulator to be created and used.
*/
public Triangulator() {
earsRandom = false;
earsSorted = false;
}
/**
* Creates a new instance of a Triangulator.
* @deprecated This class is created automatically when needed in
* GeometryInfo and never needs to be used directly. Putting data
* into a GeometryInfo with primitive POLYGON_ARRAY automatically
* causes the triangulator to be created and used.
*/
public Triangulator(int earOrder) {
switch(earOrder) {
case EARS_SEQUENCE:
earsRandom = false;
earsSorted = false;
break;
case EARS_RANDOM:
randomGen = new Random();
earsRandom = true;
earsSorted = false;
break;
case EARS_SORTED:
earsRandom = false;
earsSorted = true;
break;
default:
earsRandom = false;
earsSorted = false;
}
}
/**
* This routine converts the GeometryInfo object from primitive type
* POLYGON_ARRAY to primitive type TRIANGLE_ARRAY using polygon
* decomposition techniques.
*
*
* Example of usage:
* Triangulator tr = new Triangulator();
* tr.triangulate(ginfo); // ginfo contains the geometry.
* shape.setGeometry(ginfo.getGeometryArray()); // shape is a Shape3D.
*
* @param gi Geometry to be triangulated
**/
public void triangulate(GeometryInfo gi) {
int i, j, k;
int sIndex = 0, index, currLoop, lastInd, ind;
boolean proceed;
boolean reset = false, troubles = false;
boolean done[] = new boolean[1];
boolean gotIt[] = new boolean[1];
if (gi.getPrimitive() != GeometryInfo.POLYGON_ARRAY){
throw new IllegalArgumentException(J3dUtilsI18N.getString("Triangulator0"));
}
gi.indexify();
vertices = gi.getCoordinates();
if(vertices != null)
vertexIndices = gi.getCoordinateIndices();
else
vertexIndices = null;
colors = gi.getColors();
normals = gi.getNormals();
this.gInfo= gi;
stripCounts = gi.getStripCounts();
faces = gi.getContourCounts();
if(faces == null) {
if(stripCounts == null)
System.out.println("StripCounts is null! Don't know what to do.");
faces = new int[stripCounts.length];
for(i=0; i 1) {
proceed = true;
}
else if(Simple.simpleFace(this, loops[i1]))
proceed = false;
else
proceed = true;
if (proceed) {
// Do some preprocessing here.
// System.out.println("faces["+j+"] "+faces[j]);
for(int lpIndex = 0; lpIndex 1) {
NoHash.prepareNoHashEdges(this, i1, i2);
}
else {
noHashingEdges = false;
noHashingPnts = false;
}
// mark those vertices whose interior angle is convex
for (i = i1; i < i2; ++i) {
EarClip.classifyAngles(this, loops[i]);
}
/*
System.out.println("After classifyAngles ...");
printListData();
*/
// link the holes with the outer boundary by means of "bridges"
if (faces[j] > 1) Bridge.constructBridges(this, i1, i2);
// put all ears into a circular linked list
resetPolyList(loops[i1]);
NoHash.prepareNoHashPnts(this, i1);
EarClip.classifyEars(this, loops[i1]);
done[0] = false;
/*
System.out.println("Before clipEar (List)...");
printListData();
System.out.println("Before clipEar (vtxList)...");
printVtxList();
int counter = 0;
*/
// triangulate the polygon
while (!done[0]) {
if (!EarClip.clipEar(this, done)) {
/*
System.out.println(" (False case) clipEar (vtxList)...");
printListData();
printVtxList();
*/
if (reset) {
// For debugging.
// System.out.println("***** no further ear to clip! ***** \n");
// System.out.println("***** not a simple polygon, isn't it? *****\n");
ind = getNode();
resetPolyList(ind);
loops[i1] = ind;
if (Desperate.desperate(this, ind, i1, done)) {
// System.out.println("***** let's hope for the best *****\n");
if (!Desperate.letsHope(this, ind)) {
/*
System.out.println("***** sorry, I can't do it! ***** \n");
System.out.println("***** ask a triangulation wizard, or ");
System.out.println("clean-up your polyhedron! ***** \n");
*/
return;
}
}
else {
reset = false;
}
}
else {
// try again from scratch
troubles = true;
// System.out.println("\n***** re-classifying the ears! ***** \n");
ind = getNode();
resetPolyList(ind);
// System.out.println("Before classifyEars(" + ind + ")");
// printListData();
EarClip.classifyEars(this, ind);
reset = true;
}
}
else {
reset = false;
/*
System.out.println(" (True case) clipEar (vtxList)...");
printVtxList();
*/
}
if (done[0]) {
// System.out.println("In done[0] is true");
ind = getNextChain(gotIt);
if (gotIt[0]) {
// at some point of the triangulation, we could not find
// any ear and the polygon was split into two parts. now
// we have to handle (one of) the remaining parts.
resetPolyList(ind);
loops[i1] = ind;
noHashingPnts = false;
NoHash.prepareNoHashPnts(this, i1);
EarClip.classifyEars(this, ind);
reset = false;
done[0] = false;
}
}
}
}
i1 = i2;
}
/*
if (troubles)
System.out.println("\n\nTriangulation completed!\n");
else
System.out.println("\n\nTriangulation successfully completed!\n");
*/
// System.out.println("\n...writing the output data: ");
// Output triangles here.
writeTriangleToGeomInfo();
}
void printVtxList() {
int i;
System.out.println("numReflex " + numReflex + " reflexVertices " +
reflexVertices);
for(i= 0; i= 0) && (ind < numList) && (numList <= maxNumList));
}
void updateIndex(int ind, int index) {
// assert(InPolyList(ind));
list[ind].index = index;
}
int getAngle(int ind) {
return list[ind].convex;
}
void setAngle(int ind, int convex) {
list[ind].convex = convex;
}
void resetPolyList(int ind) {
// assert(InPolyList(ind));
firstNode = ind;
}
int getNode() {
// assert(InPolyList(first_node));
return firstNode;
}
boolean inLoopList(int loop) {
return ((loop >= 0) && (loop < numLoops) && (numLoops <= maxNumLoops));
}
void deleteHook(int currLoop) {
int ind1, ind2;
if(inLoopList(currLoop)==false)
System.out.println("Triangulator:deleteHook : Loop access out of range.");
ind1 = loops[currLoop];
ind2 = list[ind1].next;
if((inPolyList(ind1))&&(inPolyList(ind2))) {
deleteLinks(ind1);
loops[currLoop] = ind2;
}
else
System.out.println("Triangulator:deleteHook : List access out of range.");
}
/**
* Deletes node ind from list (with destroying its data fields)
*/
void deleteLinks(int ind) {
if((inPolyList(ind))&&(inPolyList(list[ind].prev))&&
(inPolyList(list[ind].next))) {
if (firstNode == ind)
firstNode = list[ind].next;
list[list[ind].next].prev = list[ind].prev;
list[list[ind].prev].next = list[ind].next;
list[ind].prev = list[ind].next = ind;
}
else
System.out.println("Triangulator:deleteLinks : Access out of range.");
}
void rotateLinks(int ind1, int ind2) {
int ind;
int ind0, ind3;
// assert(InPolyList(ind1));
// assert(InPolyList(ind2));
ind0 = list[ind1].next;
ind3 = list[ind2].next;
// assert(InPolyList(ind0));
// assert(InPolyList(ind3));
// Swap.
ind = list[ind1].next;
list[ind1].next = list[ind2].next;
list[ind2].next = ind;
list[ind0].prev = ind2;
list[ind3].prev = ind1;
}
void storeChain(int ind) {
if (numChains >= maxNumChains) {
// System.out.println("Triangulator:storeChain Expanding chain array ...");
maxNumChains += 20;
int old[] = chains;
chains = new int[maxNumChains];
if(old != null)
System.arraycopy(old, 0, chains, 0, old.length);
}
chains[numChains] = ind;
++numChains;
}
int getNextChain(boolean[] done) {
if (numChains > 0) {
done[0] = true;
--numChains;
return chains[numChains];
}
else {
done[0] = false;
numChains = 0;
return 0;
}
}
void splitSplice(int ind1, int ind2, int ind3, int ind4) {
list[ind1].next = ind4;
list[ind4].prev = ind1;
list[ind2].prev = ind3;
list[ind3].next = ind2;
}
/**
* Allocates storage for a dummy list node; pointers are set to itself.
* @return pointer to node
*/
int makeHook() {
int ind;
ind = numList;
if (numList >= maxNumList) {
maxNumList += INC_LIST_BK;
// System.out.println("Triangulator: Expanding list array ....");
ListNode old[] = list;
list = new ListNode[maxNumList];
System.arraycopy(old, 0, list, 0, old.length);
}
list[numList] = new ListNode(-1);
list[numList].prev = ind;
list[numList].next = ind;
list[numList].index = -1;
++numList;
return ind;
}
int makeLoopHeader() {
int i;
int ind;
ind = makeHook();
if(numLoops >= maxNumLoops) {
maxNumLoops += INC_LOOP_BK;
// System.out.println("Triangulator: Expanding loops array ....");
int old[] = loops;
loops = new int[maxNumLoops];
System.arraycopy(old, 0, loops, 0, old.length);
}
loops[numLoops] = ind;
i = numLoops;
++numLoops;
return i;
}
/**
* Allocates storage for a new list node, and stores the index of the point
* at this node. Pointers are set to -1.
* @return pointer to node
*/
int makeNode(int index) {
int ind;
if (numList >= maxNumList) {
maxNumList += INC_LIST_BK;
//System.out.println("Triangulator: Expanding list array ....");
ListNode old[] = list;
list = new ListNode[maxNumList];
System.arraycopy(old, 0, list, 0, old.length);
}
list[numList] = new ListNode(index);
ind = numList;
list[numList].index = index;
list[numList].prev = -1;
list[numList].next = -1;
++numList;
return ind;
}
/**
* Inserts node ind2 after node ind1.
*/
void insertAfter(int ind1, int ind2) {
int ind3;
if((inPolyList(ind1))&&(inPolyList(ind2))) {
list[ind2].next = list[ind1].next;
list[ind2].prev = ind1;
list[ind1].next = ind2;
ind3 = list[ind2].next;
if(inPolyList(ind3))
list[ind3].prev = ind2;
else
System.out.println("Triangulator:deleteHook : List access out of range.");
return;
}
else
System.out.println("Triangulator:deleteHook : List access out of range.");
}
/**
* Returns pointer to the successor of ind1.
*/
int fetchNextData(int ind1) {
return list[ind1].next;
}
/**
* obtains the data store at ind1
*/
int fetchData(int ind1) {
return list[ind1].index;
}
/**
* returns pointer to the successor of ind1.
*/
int fetchPrevData(int ind1) {
return list[ind1].prev;
}
/**
* swap the list pointers in order to change the orientation.
*/
void swapLinks(int ind1) {
int ind2, ind3;
ind2 = list[ind1].next;
list[ind1].next = list[ind1].prev;
list[ind1].prev = ind2;
ind3 = ind2;
while (ind2 != ind1) {
ind3 = list[ind2].next;
list[ind2].next = list[ind2].prev;
list[ind2].prev = ind3;
ind2 = ind3;
}
}
// Methods for handling Triangle.
void storeTriangle(int i, int j, int k) {
/*
if (ccwLoop)
triangles.add(new Triangle(i,j,k));
else
triangles.add(new Triangle(j,i,k));
*/
if(numTriangles >= maxNumTriangles) {
// System.out.println("Triangulator:storeTriangle Expanding triangle array..");
maxNumTriangles += INC_TRI_BK;
Triangle old[] = triangles;
triangles = new Triangle[maxNumTriangles];
if(old != null)
System.arraycopy(old, 0, triangles, 0, old.length);
}
if (ccwLoop)
triangles[numTriangles] = new Triangle(i,j,k);
else
triangles[numTriangles] = new Triangle(j,i,k);
numTriangles++;
}
// Methods for handling Point.
void initPnts(int number) {
if (maxNumPoints < number) {
maxNumPoints = number;
points = new Point2f[maxNumPoints];
}
for(int i = 0; i= 0) && (index < numPoints) &&
(numPoints <= maxNumPoints));
}
int storePoint(double x, double y) {
int i;
if (numPoints >= maxNumPoints) {
// System.out.println("Triangulator:storePoint Expanding points array ...");
maxNumPoints += INC_POINT_BK;
Point2f old[] = points;
points = new Point2f[maxNumPoints];
if(old != null)
System.arraycopy(old, 0, points, 0, old.length);
}
points[numPoints] = new Point2f((float)x, (float)y);
// points[numPoints].x = (float)x;
// points[numPoints].y = (float)y;
i = numPoints;
++numPoints;
return i;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy