vetmesh.java
来自「java 3d game jme 工程开发源代码」· Java 代码 · 共 957 行 · 第 1/2 页
JAVA
957 行
/*
* Copyright (c) 2003-2009 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions 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 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jme.scene.lod;
import java.util.Iterator;
import java.util.Set;
import java.util.Stack;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.Vector;
/**
* <code>VETMesh</code> originally ported from David Eberly's c++,
* modifications and enhancements made from there.<br>
* <br>
* This class is used as a base class for ClodCreator, and should have little
* use outside of a base class for clod meshes.
*
* @author Joshua Slack
* @version $Id: VETMesh.java,v 1.13 2007/08/20 10:28:23 rherlitz Exp $
* @see ClodCreator
*/
public class VETMesh {
protected TreeMap<Integer, VertexAttribute> vertexMap; // Integer,VertexAttribute
protected TreeMap<Edge, EdgeAttribute> edgeMap; // Edge,EdgeAttribute
protected TreeMap<Triangle, TriangleAttribute> triangleMap;
// construction
public VETMesh() {
vertexMap = new TreeMap<Integer, VertexAttribute>();
edgeMap = new TreeMap<Edge, EdgeAttribute>();
triangleMap = new TreeMap<Triangle, TriangleAttribute>();
}
// accessors for sizes
public int getVertexQuantity() {
return vertexMap.size();
}
public int getEdgeQuantity() {
return edgeMap.size();
}
public int getTriangleQuantity() {
return triangleMap.size();
}
// Used for operations that create new meshes from the current one. This
// allows derived class construction within the base class operations.
public VETMesh create() {
return new VETMesh();
};
// Callbacks that are executed when vertices, edges, or triangles are
// inserted or removed during triangle insertion, triangle removal, or
// edge collapsing. The default behavior for the creation is to return
// null pointers. A derived class may override the creation and return
// data to be attached to the specific mesh component. The default
// behavior for the destruction is to do nothing. A derived class may
// override the destruction and handle the data that was detached from
// the specific mesh component before its destruction.
public void onVertexInsert(Integer vert, boolean insert, VertexAttribute att) {
}
public void onVertexRemove(Integer vert, boolean remove, VertexAttribute att) {
}
public void onEdgeInsert(Edge edge, boolean insert, EdgeAttribute att) {
}
public void onEdgeRemove(Edge edge, boolean remove, EdgeAttribute att) {
}
public void onTriangleInsert(Triangle tri, boolean insert,
TriangleAttribute att) {
}
public void onTriangleRemove(Triangle tri, boolean remove,
TriangleAttribute att) {
}
public void insertTriangle(int ivert0, int ivert1, int ivert2) {
boolean hadTri = false, hadV0 = false, hadV1 = false, hadV2 = false, hadE0 = false, hadE1 = false, hadE2 = false;
Integer vert0 = new Integer(ivert0), vert1 = new Integer(ivert1), vert2 = new Integer(
ivert2);
Triangle tri = new Triangle(ivert0, ivert1, ivert2);
Edge edge0 = new Edge(ivert0, ivert1), edge1 = new Edge(ivert1, ivert2), edge2 = new Edge(
ivert2, ivert0);
// insert triangle
TriangleAttribute triAtt = new TriangleAttribute();
hadTri = (triangleMap.get(tri) != null);
triangleMap.put(tri, triAtt);
// insert vertices
VertexAttribute vert0att = vertexMap.get(vert0);
if (vert0att == null)
vert0att = new VertexAttribute();
else
hadV0 = true;
vert0att.edgeSet.add(edge0);
vert0att.edgeSet.add(edge2);
vert0att.triangleSet.add(tri);
vertexMap.put(vert0, vert0att);
VertexAttribute vert1att = vertexMap.get(vert1);
if (vert1att == null)
vert1att = new VertexAttribute();
else
hadV1 = true;
vert1att.edgeSet.add(edge0);
vert1att.edgeSet.add(edge1);
vert1att.triangleSet.add(tri);
vertexMap.put(vert1, vert1att);
VertexAttribute vert2att = vertexMap.get(vert2);
if (vert2att == null)
vert2att = new VertexAttribute();
else
hadV2 = true;
vert2att.edgeSet.add(edge1);
vert2att.edgeSet.add(edge2);
vert2att.triangleSet.add(tri);
vertexMap.put(vert2, vert2att);
// insert edges
EdgeAttribute edge0att = edgeMap.get(edge0);
if (edge0att == null)
edge0att = new EdgeAttribute();
else
hadE0 = true;
edge0att.triangleSet.add(tri);
edgeMap.put(edge0, edge0att);
EdgeAttribute edge1att = edgeMap.get(edge1);
if (edge1att == null)
edge1att = new EdgeAttribute();
else
hadE1 = true;
edge1att.triangleSet.add(tri);
edgeMap.put(edge1, edge1att);
EdgeAttribute edge2att = edgeMap.get(edge2);
if (edge2att == null)
edge2att = new EdgeAttribute();
else
hadE2 = true;
edge2att.triangleSet.add(tri);
edgeMap.put(edge2, edge2att);
// Notify derived classes that mesh components have been inserted. The
// notification occurs here to make sure the derived classes have access
// to the current state of the mesh after the triangle insertion.
onVertexInsert(vert0, !hadV0, vert0att);
onVertexInsert(vert1, !hadV1, vert1att);
onVertexInsert(vert2, !hadV2, vert2att);
onEdgeInsert(edge0, !hadE0, edge0att);
onEdgeInsert(edge1, !hadE1, edge1att);
onEdgeInsert(edge2, !hadE2, edge2att);
onTriangleInsert(tri, !hadTri, triAtt);
}
public void insertTriangle(Triangle tri) {
insertTriangle(tri.vert[0], tri.vert[1], tri.vert[2]);
}
public void removeTriangle(int ivert0, int ivert1, int ivert2) {
// remove triangle
Triangle kT = new Triangle(ivert0, ivert1, ivert2);
TriangleAttribute pkTA = triangleMap.get(kT);
if (pkTA == null) {
// triangle does not exist, nothing to do
return;
}
Integer vert0 = new Integer(ivert0), vert1 = new Integer(ivert1), vert2 = new Integer(
ivert2);
// update edges
Edge kE0 = new Edge(ivert0, ivert1), kE1 = new Edge(ivert1, ivert2), kE2 = new Edge(
ivert2, ivert0);
EdgeAttribute pkE0 = edgeMap.get(kE0);
pkE0.triangleSet.remove(kT);
EdgeAttribute pkE1 = edgeMap.get(kE1);
pkE1.triangleSet.remove(kT);
EdgeAttribute pkE2 = edgeMap.get(kE2);
pkE2.triangleSet.remove(kT);
// update vertices
VertexAttribute pkV0 = vertexMap.get(vert0);
pkV0.triangleSet.remove(kT);
VertexAttribute pkV1 = vertexMap.get(vert1);
pkV1.triangleSet.remove(kT);
VertexAttribute pkV2 = vertexMap.get(vert2);
pkV2.triangleSet.remove(kT);
if (pkE0.triangleSet.size() == 0) {
pkV0.edgeSet.remove(kE0);
pkV1.edgeSet.remove(kE0);
}
if (pkE1.triangleSet.size() == 0) {
pkV1.edgeSet.remove(kE1);
pkV2.edgeSet.remove(kE1);
}
if (pkE2.triangleSet.size() == 0) {
pkV0.edgeSet.remove(kE2);
pkV2.edgeSet.remove(kE2);
}
// Notify derived classes that mesh components are about to be destroyed.
// The notification occurs here to make sure the derived classes have
// access to the current state of the mesh before the triangle removal.
boolean bDestroy = pkV0.edgeSet.size() == 0
&& pkV0.triangleSet.size() == 0;
onVertexRemove(vert0, bDestroy, pkV0);
if (bDestroy)
vertexMap.remove(vert0);
bDestroy = pkV1.edgeSet.size() == 0 && pkV1.triangleSet.size() == 0;
onVertexRemove(vert1, bDestroy, pkV1);
if (bDestroy)
vertexMap.remove(vert1);
bDestroy = pkV2.edgeSet.size() == 0 && pkV2.triangleSet.size() == 0;
onVertexRemove(vert2, bDestroy, pkV2);
if (bDestroy)
vertexMap.remove(vert2);
bDestroy = pkE0.triangleSet.size() == 0;
onEdgeRemove(kE0, bDestroy, pkE0);
if (bDestroy)
edgeMap.remove(kE0);
bDestroy = pkE1.triangleSet.size() == 0;
onEdgeRemove(kE1, bDestroy, pkE1);
if (bDestroy)
edgeMap.remove(kE1);
bDestroy = pkE2.triangleSet.size() == 0;
onEdgeRemove(kE2, bDestroy, pkE2);
if (bDestroy)
edgeMap.remove(kE2);
onTriangleRemove(kT, true, pkTA);
triangleMap.remove(kT);
}
public void removeTriangle(Triangle tri) {
removeTriangle(tri.vert[0], tri.vert[1], tri.vert[2]);
}
// This should be called before Mesh destruction if a derived class has
// allocated vertex, edge, or triangle data and attached it to the mesh
// components. Since the creation and destruction callbacks are virtual,
// any insert/remove operations in the base Mesh destructor will only
// call the base virtual callbacks, not any derived-class ones. An
// alternative to calling this is that the derived class maintain enough
// information to know which data objects to destroy during its own
// destructor call.
public void removeAllTriangles() {
Object[] tris = triangleMap.keySet().toArray();
for (int x = 0; x < tris.length; x++) {
Triangle tri = (Triangle) tris[x];
int iV0 = tri.vert[0];
int iV1 = tri.vert[1];
int iV2 = tri.vert[2];
removeTriangle(iV0, iV1, iV2);
}
}
// vertex attributes
public TreeMap getVertexMap() {
return vertexMap;
}
// edge attributes
public TreeMap<Edge, EdgeAttribute> getEdgeMap() {
return edgeMap;
}
public ExVector getTriangles(int vert0, int vert1) { //<Triangle>
EdgeAttribute edgeAtt = edgeMap.get(new Edge(vert0,
vert1));
return (edgeAtt != null ? edgeAtt.triangleSet : null);
}
// triangle attributes
public TreeMap<Triangle, TriangleAttribute> getTriangleMap() {
return triangleMap;
}
// The mesh is manifold if each edge has at most two adjacent triangles.
// It is possible that the mesh has multiple connected components.
public boolean isManifold() {
Iterator<EdgeAttribute> it = edgeMap.values().iterator();
while (it.hasNext()) {
EdgeAttribute ea = it.next();
if (ea.triangleSet.size() > 2)
return false;
}
return true;
}
// The mesh is closed if each edge has exactly two adjacent triangles.
// It is possible that the mesh has multiple connected components.
public boolean isClosed() {
Iterator<EdgeAttribute> it = edgeMap.values().iterator();
while (it.hasNext()) {
EdgeAttribute ea = it.next();
if (ea.triangleSet.size() != 2)
return false;
}
return true;
}
// The mesh is connected if each triangle can be reached from any other
// triangle by a traversal.
public boolean isConnected() {
// Do a depth-first search of the mesh. It is connected if and only if
// all of the triangles are visited on a single search.
int iTSize = triangleMap.size();
if (iTSize == 0)
return true;
// for marking visited triangles during the traversal
TreeMap<Triangle, Boolean> kVisitedMap = new TreeMap<Triangle, Boolean>();
Iterator<Triangle> it = triangleMap.keySet().iterator();
while (it.hasNext()) {
kVisitedMap.put(it.next(), Boolean.FALSE);
}
// start the traversal at any triangle in the mesh
Stack<Triangle> kStack = new Stack<Triangle>();
kStack.push((Triangle) triangleMap.keySet().toArray()[0]);
kVisitedMap.put(kStack.get(0), Boolean.TRUE);
iTSize--;
Iterator triIt;
while (!kStack.empty()) {
// start at the current triangle
Triangle kT = kStack.pop();
for (int i = 0; i < 3; i++) {
// get an edge of the current triangle
EdgeAttribute pkE = edgeMap.get(new Edge(
kT.vert[i], kT.vert[(i + 1) % 3]));
// visit each adjacent triangle
ExVector rkTSet = (ExVector) pkE.triangleSet.clone(); // <Triangle>
triIt = rkTSet.iterator();
while (triIt.hasNext()) {
Triangle rkTAdj = (Triangle) triIt.next();
if (Boolean.FALSE.equals(kVisitedMap.get(rkTAdj))) {
// this adjacent triangle not yet visited
kStack.push(rkTAdj);
kVisitedMap.put(rkTAdj, Boolean.TRUE);
iTSize--;
}
}
}
}
return iTSize == 0;
}
// Extract the connected components from the mesh. For large data sets,
// the array of VETMesh can use a lot of memory. Instead use the
// second form that just stores a sorted connectivity array. Let N be
// the number of components. The value Index[i] indicates the starting
// index for component i with 0 <= i < N, so it is always the case that
// Index[0] = 0. The value Index[N] is the total number of indices in
// the raiConnect array. The quantity of indices for component i is
// Q(i) = Index[i+1]-Index[i] for 0 <= i < N. The application is
// responsible for deleting raiConnect.
public void getComponents(Vector<VETMesh> store) {
// Do a depth-first search of the mesh to find connected components.
int iTSize = triangleMap.size();
if (iTSize == 0)
return;
// for marking visited triangles during the traversal
TreeMap<Triangle, Boolean> kVisitedMap = new TreeMap<Triangle, Boolean>();
Iterator<Triangle> it = triangleMap.keySet().iterator();
while (it.hasNext()) {
kVisitedMap.put(it.next(), Boolean.FALSE);
}
while (iTSize > 0) {
// find an unvisited triangle in the mesh
Stack<Triangle> kStack = new Stack<Triangle>();
Iterator<Triangle> visIt = kVisitedMap.keySet().iterator();
while (visIt.hasNext()) {
Triangle tri = visIt.next();
if (Boolean.FALSE.equals(kVisitedMap.get(tri))) {
// this triangle not yet visited
kStack.push(tri);
kVisitedMap.put(tri, Boolean.TRUE);
iTSize--;
break;
}
}
// traverse the connected component of the starting triangle
VETMesh pkComponent = create();
Iterator triIt;
while (!kStack.empty()) {
// start at the current triangle
Triangle kT = kStack.pop();
pkComponent.insertTriangle(kT);
for (int i = 0; i < 3; i++) {
// get an edge of the current triangle
Edge kE = new Edge(kT.vert[i], kT.vert[(i + 1) % 3]);
EdgeAttribute pkE = edgeMap.get(kE);
// visit each adjacent triangle
ExVector rkTSet = (ExVector) pkE.triangleSet.clone(); // <Triangle>
triIt = rkTSet.iterator();
while (triIt.hasNext()) {
Triangle rkTAdj = (Triangle) triIt.next();
if (Boolean.FALSE.equals(kVisitedMap.get(rkTAdj))) {
// this adjacent triangle not yet visited
kStack.push(rkTAdj);
kVisitedMap.put(rkTAdj, Boolean.TRUE);
iTSize--;
}
}
}
}
store.add(pkComponent);
}
}
public void getComponents(Vector<Integer> rkIndex, int[] raiConnect) {
rkIndex.clear();
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?