653 lines
13 KiB
C++
653 lines
13 KiB
C++
/**
|
|
* $Id$
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program 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 General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
|
* All rights reserved.
|
|
*
|
|
* The Original Code is: all of this file.
|
|
*
|
|
* Contributor(s): none yet.
|
|
*
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
*/
|
|
|
|
|
|
#include "BSP_CSGMesh.h"
|
|
#include "MT_assert.h"
|
|
#include "CTR_TaggedSetOps.h"
|
|
#include "MT_Plane3.h"
|
|
#include "BSP_CSGException.h"
|
|
|
|
// for vector reverse
|
|
#include <iostream>
|
|
#include <algorithm>
|
|
using namespace std;
|
|
|
|
BSP_CSGMesh::
|
|
BSP_CSGMesh(
|
|
) :
|
|
MEM_RefCountable()
|
|
{
|
|
m_verts = NULL;
|
|
m_faces = NULL;
|
|
m_edges = NULL;
|
|
}
|
|
|
|
BSP_CSGMesh *
|
|
BSP_CSGMesh::
|
|
New(
|
|
){
|
|
return new BSP_CSGMesh();
|
|
}
|
|
|
|
BSP_CSGMesh *
|
|
BSP_CSGMesh::
|
|
NewCopy(
|
|
) const {
|
|
|
|
BSP_CSGMesh *mesh = New();
|
|
if (mesh == NULL) return NULL;
|
|
|
|
mesh->m_bbox_max = m_bbox_max;
|
|
mesh->m_bbox_min = m_bbox_min;
|
|
|
|
if (m_edges != NULL) {
|
|
mesh->m_edges = new vector<BSP_MEdge>(*m_edges);
|
|
if (mesh->m_edges == NULL) {
|
|
delete mesh;
|
|
return NULL;
|
|
}
|
|
}
|
|
if (m_verts != NULL) {
|
|
mesh->m_verts = new vector<BSP_MVertex>(*m_verts);
|
|
if (mesh->m_verts == NULL) {
|
|
if (m_edges != NULL) free(mesh->m_edges);
|
|
delete mesh;
|
|
return NULL;
|
|
}
|
|
}
|
|
if (m_faces != NULL) {
|
|
mesh->m_faces = new vector<BSP_MFace>(*m_faces);
|
|
if (mesh->m_faces == NULL) {
|
|
delete mesh;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return mesh;
|
|
}
|
|
|
|
void
|
|
BSP_CSGMesh::
|
|
Invert(
|
|
){
|
|
|
|
vector<BSP_MFace> & faces = FaceSet();
|
|
|
|
vector<BSP_MFace>::const_iterator faces_end = faces.end();
|
|
vector<BSP_MFace>::iterator faces_it = faces.begin();
|
|
|
|
for (; faces_it != faces_end; ++faces_it) {
|
|
faces_it->Invert();
|
|
}
|
|
}
|
|
|
|
bool
|
|
BSP_CSGMesh::
|
|
SetVertices(
|
|
vector<BSP_MVertex> *verts
|
|
){
|
|
if (verts == NULL) return false;
|
|
|
|
// create polygon and edge arrays and reserve some space.
|
|
m_faces = new vector<BSP_MFace>;
|
|
if (!m_faces) return false;
|
|
|
|
m_faces->reserve(verts->size()/2);
|
|
|
|
// previous verts get deleted here.
|
|
m_verts = verts;
|
|
return true;
|
|
}
|
|
|
|
void
|
|
BSP_CSGMesh::
|
|
AddPolygon(
|
|
const int * verts,
|
|
int num_verts
|
|
){
|
|
MT_assert(verts != NULL);
|
|
MT_assert(num_verts >=3);
|
|
|
|
if (verts == NULL || num_verts <3) return;
|
|
|
|
// make a polyscone from these vertex indices.
|
|
|
|
const BSP_FaceInd fi = m_faces->size();
|
|
m_faces->push_back(BSP_MFace());
|
|
BSP_MFace & face = m_faces->back();
|
|
|
|
insert_iterator<vector<BSP_VertexInd> > insert_point(face.m_verts,face.m_verts.end());
|
|
copy (verts,verts + num_verts,insert_point);
|
|
|
|
// compute and store the plane equation for this face.
|
|
|
|
MT_Plane3 face_plane = FacePlane(fi);
|
|
face.m_plane = face_plane;
|
|
};
|
|
|
|
// assumes that the face already has a plane equation
|
|
void
|
|
BSP_CSGMesh::
|
|
AddPolygon(
|
|
const BSP_MFace &face
|
|
){
|
|
m_faces->push_back(face);
|
|
};
|
|
|
|
|
|
bool
|
|
BSP_CSGMesh::
|
|
BuildEdges(
|
|
){
|
|
|
|
if (m_faces == NULL) return false;
|
|
|
|
if (m_edges != NULL) {
|
|
DestroyEdges();
|
|
}
|
|
|
|
m_edges = new vector<BSP_MEdge>;
|
|
|
|
if (m_edges == NULL) {
|
|
return false;
|
|
}
|
|
|
|
|
|
//iterate through the face set and add edges for all polygon
|
|
//edges
|
|
|
|
vector<BSP_MFace>::const_iterator f_it_end = FaceSet().end();
|
|
vector<BSP_MFace>::iterator f_it_begin = FaceSet().begin();
|
|
vector<BSP_MFace>::iterator f_it = FaceSet().begin();
|
|
|
|
vector<BSP_EdgeInd> dummy;
|
|
|
|
for (;f_it != f_it_end; ++f_it) {
|
|
|
|
BSP_MFace & face = *f_it;
|
|
|
|
int vertex_num = face.m_verts.size();
|
|
BSP_VertexInd prev_vi(face.m_verts[vertex_num-1]);
|
|
|
|
for (int vert = 0; vert < vertex_num; ++vert) {
|
|
|
|
BSP_FaceInd fi(size_t (f_it - f_it_begin));
|
|
InsertEdge(prev_vi,face.m_verts[vert],fi,dummy);
|
|
prev_vi = face.m_verts[vert];
|
|
}
|
|
|
|
}
|
|
dummy.clear();
|
|
return true;
|
|
}
|
|
|
|
void
|
|
BSP_CSGMesh::
|
|
DestroyEdges(
|
|
){
|
|
if ( m_edges != NULL ) {
|
|
delete m_edges;
|
|
m_edges = NULL;
|
|
}
|
|
|
|
// Run through the vertices
|
|
// and clear their edge arrays.
|
|
|
|
if (m_verts){
|
|
|
|
vector<BSP_MVertex>::const_iterator vertex_end = VertexSet().end();
|
|
vector<BSP_MVertex>::iterator vertex_it = VertexSet().begin();
|
|
|
|
for (; vertex_it != vertex_end; ++vertex_it) {
|
|
vertex_it->m_edges.clear();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BSP_EdgeInd
|
|
BSP_CSGMesh::
|
|
FindEdge(
|
|
const BSP_VertexInd & v1,
|
|
const BSP_VertexInd & v2
|
|
) const {
|
|
|
|
vector<BSP_MVertex> &verts = VertexSet();
|
|
vector<BSP_MEdge> &edges = EdgeSet();
|
|
|
|
BSP_MEdge e;
|
|
e.m_verts[0] = v1;
|
|
e.m_verts[1] = v2;
|
|
|
|
vector<BSP_EdgeInd> &v1_edges = verts[v1].m_edges;
|
|
vector<BSP_EdgeInd>::const_iterator v1_end = v1_edges.end();
|
|
vector<BSP_EdgeInd>::const_iterator v1_begin = v1_edges.begin();
|
|
|
|
for (; v1_begin != v1_end; ++v1_begin) {
|
|
if (edges[*v1_begin] == e) return *v1_begin;
|
|
}
|
|
|
|
return BSP_EdgeInd::Empty();
|
|
}
|
|
|
|
void
|
|
BSP_CSGMesh::
|
|
InsertEdge(
|
|
const BSP_VertexInd & v1,
|
|
const BSP_VertexInd & v2,
|
|
const BSP_FaceInd & f,
|
|
vector<BSP_EdgeInd> &new_edges
|
|
){
|
|
|
|
MT_assert(!v1.IsEmpty());
|
|
MT_assert(!v2.IsEmpty());
|
|
MT_assert(!f.IsEmpty());
|
|
|
|
if (v1.IsEmpty() || v2.IsEmpty() || f.IsEmpty()) {
|
|
BSP_CSGException e(e_mesh_error);
|
|
throw (e);
|
|
}
|
|
|
|
vector<BSP_MVertex> &verts = VertexSet();
|
|
vector<BSP_MEdge> &edges = EdgeSet();
|
|
|
|
BSP_EdgeInd e;
|
|
|
|
e = FindEdge(v1,v2);
|
|
if (e.IsEmpty()) {
|
|
// This edge does not exist -- make a new one
|
|
|
|
BSP_MEdge temp_e;
|
|
temp_e.m_verts[0] = v1;
|
|
temp_e.m_verts[1] = v2;
|
|
|
|
e = m_edges->size();
|
|
// set the face index from the edge back to this polygon.
|
|
temp_e.m_faces.push_back(f);
|
|
|
|
m_edges->push_back(temp_e);
|
|
|
|
// add the edge index to it's vertices
|
|
verts[v1].AddEdge(e);
|
|
verts[v2].AddEdge(e);
|
|
|
|
new_edges.push_back(e);
|
|
|
|
} else {
|
|
|
|
// edge already exists
|
|
// insure that there is no polygon already
|
|
// attached to the other side of this edge
|
|
// swap the empty face pointer in edge with f
|
|
|
|
BSP_MEdge &edge = edges[e];
|
|
|
|
// set the face index from the edge back to this polygon.
|
|
edge.m_faces.push_back(f);
|
|
}
|
|
}
|
|
|
|
|
|
// geometry access
|
|
//////////////////
|
|
|
|
vector<BSP_MVertex> &
|
|
BSP_CSGMesh::
|
|
VertexSet(
|
|
) const {
|
|
return *m_verts;
|
|
}
|
|
|
|
vector<BSP_MFace> &
|
|
BSP_CSGMesh::
|
|
FaceSet(
|
|
) const {
|
|
return *m_faces;
|
|
}
|
|
|
|
vector<BSP_MEdge> &
|
|
BSP_CSGMesh::
|
|
EdgeSet(
|
|
) const {
|
|
return *m_edges;
|
|
}
|
|
|
|
BSP_CSGMesh::
|
|
~BSP_CSGMesh(
|
|
){
|
|
if ( m_verts != NULL ) delete m_verts;
|
|
if ( m_faces != NULL ) delete m_faces;
|
|
if ( m_edges != NULL ) delete m_edges;
|
|
}
|
|
|
|
// local geometry queries.
|
|
/////////////////////////
|
|
|
|
// face queries
|
|
///////////////
|
|
|
|
void
|
|
BSP_CSGMesh::
|
|
FaceVertices(
|
|
const BSP_FaceInd & f,
|
|
vector<BSP_VertexInd> &output
|
|
){
|
|
vector<BSP_MFace> & face_set = FaceSet();
|
|
output.insert(
|
|
output.end(),
|
|
face_set[f].m_verts.begin(),
|
|
face_set[f].m_verts.end()
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
BSP_CSGMesh::
|
|
FaceEdges(
|
|
const BSP_FaceInd & fi,
|
|
vector<BSP_EdgeInd> &output
|
|
){
|
|
// take intersection of the edges emminating from all the vertices
|
|
// of this polygon;
|
|
|
|
vector<BSP_MFace> &faces = FaceSet();
|
|
vector<BSP_MEdge> &edges = EdgeSet();
|
|
|
|
const BSP_MFace & f = faces[fi];
|
|
|
|
// collect vertex edges;
|
|
|
|
vector<BSP_VertexInd>::const_iterator face_verts_it = f.m_verts.begin();
|
|
vector<BSP_VertexInd>::const_iterator face_verts_end = f.m_verts.end();
|
|
|
|
vector< vector<BSP_EdgeInd> > vertex_edges(f.m_verts.size());
|
|
|
|
int vector_slot = 0;
|
|
|
|
for (;face_verts_it != face_verts_end; ++face_verts_it, ++vector_slot) {
|
|
VertexEdges(*face_verts_it,vertex_edges[vector_slot]);
|
|
}
|
|
|
|
int prev = vector_slot - 1;
|
|
|
|
// intersect pairs of edge sets
|
|
|
|
for (int i = 0; i < vector_slot;i++) {
|
|
CTR_TaggedSetOps<BSP_EdgeInd,BSP_MEdge>::IntersectPair(vertex_edges[prev],vertex_edges[i],edges,output);
|
|
prev = i;
|
|
}
|
|
|
|
// should always have 3 or more unique edges per face.
|
|
MT_assert(output.size() >=3);
|
|
|
|
if (output.size() < 3) {
|
|
BSP_CSGException e(e_mesh_error);
|
|
throw(e);
|
|
}
|
|
};
|
|
|
|
// edge queries
|
|
///////////////
|
|
|
|
void
|
|
BSP_CSGMesh::
|
|
EdgeVertices(
|
|
const BSP_EdgeInd & e,
|
|
vector<BSP_VertexInd> &output
|
|
){
|
|
const vector<BSP_MEdge> &edges = EdgeSet();
|
|
output.push_back(edges[e].m_verts[0]);
|
|
output.push_back(edges[e].m_verts[1]);
|
|
}
|
|
|
|
void
|
|
BSP_CSGMesh::
|
|
EdgeFaces(
|
|
const BSP_EdgeInd & e,
|
|
vector<BSP_FaceInd> &output
|
|
){
|
|
|
|
vector<BSP_MEdge> & edge_set = EdgeSet();
|
|
output.insert(
|
|
output.end(),
|
|
edge_set[e].m_faces.begin(),
|
|
edge_set[e].m_faces.end()
|
|
);
|
|
|
|
}
|
|
|
|
// vertex queries
|
|
/////////////////
|
|
|
|
void
|
|
BSP_CSGMesh::
|
|
VertexEdges(
|
|
const BSP_VertexInd &v,
|
|
vector<BSP_EdgeInd> &output
|
|
){
|
|
|
|
vector<BSP_MVertex> & vertex_set = VertexSet();
|
|
output.insert(
|
|
output.end(),
|
|
vertex_set[v].m_edges.begin(),
|
|
vertex_set[v].m_edges.end()
|
|
);
|
|
}
|
|
|
|
void
|
|
BSP_CSGMesh::
|
|
VertexFaces(
|
|
const BSP_VertexInd &vi,
|
|
vector<BSP_FaceInd> &output
|
|
) {
|
|
|
|
vector<BSP_MEdge> &edges = EdgeSet();
|
|
vector<BSP_MFace> &faces = FaceSet();
|
|
vector<BSP_MVertex> &verts = VertexSet();
|
|
|
|
const vector<BSP_EdgeInd> &v_edges = verts[vi].m_edges;
|
|
vector<BSP_EdgeInd>::const_iterator e_it = v_edges.begin();
|
|
|
|
for (; e_it != v_edges.end(); ++e_it) {
|
|
|
|
BSP_MEdge &e = edges[*e_it];
|
|
|
|
// iterate through the faces of this edge - push unselected
|
|
// edges to ouput and then select the edge
|
|
|
|
vector<BSP_FaceInd>::const_iterator e_faces_end = e.m_faces.end();
|
|
vector<BSP_FaceInd>::iterator e_faces_it = e.m_faces.begin();
|
|
|
|
for (;e_faces_it != e_faces_end; ++e_faces_it) {
|
|
|
|
if (!faces[*e_faces_it].SelectTag()) {
|
|
output.push_back(*e_faces_it);
|
|
faces[*e_faces_it].SetSelectTag(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
// deselect selected faces.
|
|
vector<BSP_FaceInd>::iterator f_it = output.begin();
|
|
|
|
for (; f_it != output.end(); ++f_it) {
|
|
faces[*f_it].SetSelectTag(false);
|
|
}
|
|
}
|
|
|
|
bool
|
|
BSP_CSGMesh::
|
|
SC_Face(
|
|
BSP_FaceInd f
|
|
){
|
|
|
|
|
|
|
|
#if 0
|
|
{
|
|
// check area is greater than zero.
|
|
|
|
vector<BSP_MVertex> & verts = VertexSet();
|
|
|
|
vector<BSP_VertexInd> f_verts;
|
|
FaceVertices(f,f_verts);
|
|
|
|
MT_assert(f_verts.size() >= 3);
|
|
|
|
BSP_VertexInd root = f_verts[0];
|
|
|
|
MT_Scalar area = 0;
|
|
|
|
for (int i=2; i < f_verts.size(); i++) {
|
|
MT_Vector3 a = verts[root].m_pos;
|
|
MT_Vector3 b = verts[f_verts[i-1]].m_pos;
|
|
MT_Vector3 c = verts[f_verts[i]].m_pos;
|
|
|
|
MT_Vector3 l1 = b-a;
|
|
MT_Vector3 l2 = c-b;
|
|
|
|
area += (l1.cross(l2)).length()/2;
|
|
}
|
|
|
|
MT_assert(!MT_fuzzyZero(area));
|
|
}
|
|
#endif
|
|
// Check coplanarity
|
|
#if 0
|
|
MT_Plane3 plane = FacePlane(f);
|
|
|
|
const BSP_MFace & face = FaceSet()[f];
|
|
vector<BSP_VertexInd>::const_iterator f_verts_it = face.m_verts.begin();
|
|
vector<BSP_VertexInd>::const_iterator f_verts_end = face.m_verts.end();
|
|
|
|
for (;f_verts_it != f_verts_end; ++f_verts_it) {
|
|
MT_Scalar dist = plane.signedDistance(
|
|
VertexSet()[*f_verts_it].m_pos
|
|
);
|
|
|
|
MT_assert(fabs(dist) < BSP_SPLIT_EPSILON);
|
|
}
|
|
#endif
|
|
|
|
|
|
// Check connectivity
|
|
|
|
vector<BSP_EdgeInd> f_edges;
|
|
FaceEdges(f,f_edges);
|
|
|
|
MT_assert(f_edges.size() == FaceSet()[f].m_verts.size());
|
|
|
|
unsigned int i;
|
|
for (i = 0; i < f_edges.size(); ++i) {
|
|
|
|
int matches = 0;
|
|
for (unsigned int j = 0; j < EdgeSet()[f_edges[i]].m_faces.size(); j++) {
|
|
|
|
if (EdgeSet()[f_edges[i]].m_faces[j] == f) matches++;
|
|
}
|
|
|
|
MT_assert(matches == 1);
|
|
|
|
}
|
|
return true;
|
|
}
|
|
|
|
MT_Plane3
|
|
BSP_CSGMesh::
|
|
FacePlane(
|
|
const BSP_FaceInd & fi
|
|
) const{
|
|
|
|
const BSP_MFace & f0 = FaceSet()[fi];
|
|
|
|
// Have to be a bit careful here coz the poly may have
|
|
// a lot of parallel edges. Should walk round the polygon
|
|
// and check length of cross product.
|
|
|
|
const MT_Vector3 & p1 = VertexSet()[f0.m_verts[0]].m_pos;
|
|
const MT_Vector3 & p2 = VertexSet()[f0.m_verts[1]].m_pos;
|
|
|
|
int face_size = f0.m_verts.size();
|
|
MT_Vector3 n;
|
|
|
|
for (int i = 2 ; i <face_size; i++) {
|
|
const MT_Vector3 & pi = VertexSet()[f0.m_verts[i]].m_pos;
|
|
|
|
MT_Vector3 l1 = p2-p1;
|
|
MT_Vector3 l2 = pi-p2;
|
|
n = l1.cross(l2);
|
|
MT_Scalar length = n.length();
|
|
|
|
if (!MT_fuzzyZero(length)) {
|
|
n = n * (1/length);
|
|
break;
|
|
}
|
|
}
|
|
return MT_Plane3(n,p1);
|
|
}
|
|
|
|
void
|
|
BSP_CSGMesh::
|
|
ComputeFacePlanes(
|
|
){
|
|
|
|
int fsize = FaceSet().size();
|
|
int i=0;
|
|
for (i = 0; i < fsize; i++) {
|
|
|
|
FaceSet()[i].m_plane = FacePlane(i);
|
|
}
|
|
};
|
|
|
|
|
|
int
|
|
BSP_CSGMesh::
|
|
CountTriangles(
|
|
) const {
|
|
|
|
// Each polygon of n sides can be partitioned into n-3 triangles.
|
|
// So we just go through and sum this function of polygon size.
|
|
|
|
vector<BSP_MFace> & face_set = FaceSet();
|
|
|
|
vector<BSP_MFace>::const_iterator face_it = face_set.begin();
|
|
vector<BSP_MFace>::const_iterator face_end = face_set.end();
|
|
|
|
int sum = 0;
|
|
|
|
for (;face_it != face_end; face_it++) {
|
|
|
|
// Should be careful about degenerate faces here.
|
|
sum += face_it->m_verts.size() - 2;
|
|
}
|
|
|
|
return sum;
|
|
}
|
|
|