Files
test/intern/bsp/intern/BSP_CSGMesh.cpp

660 lines
13 KiB
C++
Raw Normal View History

2011-02-25 10:44:20 +00:00
/*
* ***** BEGIN GPL LICENSE BLOCK *****
2002-10-12 11:37:38 +00:00
*
* 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.
2002-10-12 11:37:38 +00:00
*
* 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,
2010-02-12 13:34:04 +00:00
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
2002-10-12 11:37:38 +00:00
*
* 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 *****
2002-10-12 11:37:38 +00:00
*/
2011-02-25 10:44:20 +00:00
/** \file bsp/intern/BSP_CSGMesh.cpp
* \ingroup bsp
*/
2002-10-12 11:37:38 +00:00
#include "BSP_CSGMesh.h"
#include "MT_assert.h"
#include "CTR_TaggedSetOps.h"
#include "MT_Plane3.h"
#include "BSP_CSGException.h"
// for insert_iterator
#include <iterator>
2002-10-12 11:37:38 +00:00
// for vector reverse
#include <iostream>
2002-10-12 11:37:38 +00:00
#include <algorithm>
using namespace std;
BSP_CSGMesh::
BSP_CSGMesh(
) :
MEM_RefCountable()
{
m_verts = NULL;
m_faces = NULL;
m_edges = NULL;
2002-10-12 11:37:38 +00:00
}
BSP_CSGMesh *
BSP_CSGMesh::
New(
){
return new BSP_CSGMesh();
}
BSP_CSGMesh *
BSP_CSGMesh::
NewCopy(
) const {
BSP_CSGMesh *mesh = New();
2002-10-12 11:37:38 +00:00
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;
}
2002-10-12 11:37:38 +00:00
}
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;
}
2002-10-12 11:37:38 +00:00
}
if (m_faces != NULL) {
mesh->m_faces = new vector<BSP_MFace>(*m_faces);
if (mesh->m_faces == NULL) {
delete mesh;
return NULL;
}
2002-10-12 11:37:38 +00:00
}
return mesh;
2002-10-12 11:37:38 +00:00
}
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
2002-10-12 11:37:38 +00:00
){
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();
While building with gcc on Irix one is confronted by the message: ---------------------------->8---------------------------------------------- g++ -DHAVE_CONFIG_H -I. -I../../../blender/intern/bsp -I../.. -I../../../blender/intern/container -I../../../blender/intern/moto/include -I../../../blender/intern/memutil -I/usr/freeware/include -g -funsigned-char -c ../../../blender/intern/bsp/intern/BSP_CSGMesh.cpp -MT BSP_CSGMesh.lo -MD -MP -MF .deps/BSP_CSGMesh.TPlo -DPIC -o .libs/BSP_CSGMesh.lo /usr/freeware/lib/gcc-lib/mips-sgi-irix6.5/3.0.4/include/g++/bits/stl_iterator.h: In constructor `std::__normal_iterator<_Iterator, _Container>::__normal_iterator(const std::__normal_iterator<_Iter, _Container>&) [with _Iter = const BSP_MFace*, _Iterator = BSP_MFace*, _Container = std::vector<BSP_MFace, std::allocator<BSP_MFace> >]': ../../../blender/intern/bsp/intern/BSP_CSGMesh.cpp:270: instantiated from here /usr/freeware/lib/gcc-lib/mips-sgi-irix6.5/3.0.4/include/g++/bits/stl_iterator.h:474: cannot convert `const BSP_MFace* const' to `BSP_MFace*' in initialization *** Error code 1 (bu21) *** Error code 1 (bu21) *** Error code 1 (bu21) *** Error code 1 (bu21) ---------------------------->8---------------------------------------------- The line in question that causes the error is the middle one in this group: vector<BSP_MFace>::const_iterator f_it_end = FaceSet().end(); vector<BSP_MFace>::const_iterator f_it_begin = FaceSet().begin(); vector<BSP_MFace>::iterator f_it = FaceSet().begin(); Dropping the 'const_' from that middle line enables gcc to compile the file correctly (this is also consistent with what is going on with other parts of the file, i.e., stuff that is returned from a begin() method is declared as vector<BSP_MFace>::iterator instead of vector<BSP_MFace>::const_iterator. But I'll be honest: I have no idea what this code does, so if somebody with better C++ skills wants to check it, then please do. This change was also tested to compile and run on debian linux/x86 (well, booleans are broken right now, so I wasn't able to do too much testing). Chris
2002-12-29 15:59:51 +00:00
vector<BSP_MFace>::iterator f_it_begin = FaceSet().begin();
2002-10-12 11:37:38 +00:00
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));
2002-10-12 11:37:38 +00:00
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;
}
2002-10-12 11:37:38 +00:00
// 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;
2002-10-12 11:37:38 +00:00
}
vector<BSP_MFace> &
BSP_CSGMesh::
FaceSet(
) const {
return *m_faces;
2002-10-12 11:37:38 +00:00
}
vector<BSP_MEdge> &
BSP_CSGMesh::
EdgeSet(
) const {
return *m_edges;
2002-10-12 11:37:38 +00:00
}
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;
2002-10-12 11:37:38 +00:00
}
// 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;
}