/************************************************************************ MxStdModel Copyright (C) 1998 Michael Garland. See "COPYING.txt" for details. $Id: MxStdModel.cxx,v 1.36 1999/02/09 17:30:03 garland Exp $ ************************************************************************/ #include "stdmix.h" #include "MxStdModel.h" #include "MxVector.h" MxPairContraction& MxPairContraction::operator=(const MxPairContraction& c) { v1 = c.v1; v2 = c.v2; mxv_set(dv1, c.dv1, 3); mxv_set(dv2, c.dv2, 3); delta_faces.reset(); dead_faces.reset(); for(uint i=0; i0 ) mxv_unitize(n, 3); } void MxStdModel::synthesize_normals() { float n[3]; if( normal_binding() == MX_PERFACE ) { for(MxFaceID f=0; f 0 ); unsigned int vnew = add_vertex(x,y,z); for(unsigned int i=0; ivnew face(f).remap_vertex(v2, vnew); neighbors(vnew).add(f); // remove f from neighbors(v2) remove_neighbor(neighbors(v2), f); // assure orientation is consistent if( face(f).is_inorder(vnew, v3) ) add_face(vnew, v2, v3); else add_face(vnew, v3, v2); } return vnew; } void MxStdModel::flip_edge(unsigned int v1, unsigned int v2) { MxFaceList faces; collect_edge_neighbors(v1, v2, faces); if( faces.length() != 2 ) return; unsigned int f1 = faces(0); unsigned int f2 = faces(1); unsigned int v3 = face(f1).opposite_vertex(v1, v2); unsigned int v4 = face(f2).opposite_vertex(v1, v2); // ?? Should we check for convexity or assume thats been taken care of? remove_neighbor(neighbors(v1), f2); remove_neighbor(neighbors(v2), f1); neighbors(v3).add(f2); neighbors(v4).add(f1); face(f1).remap_vertex(v2, v4); face(f2).remap_vertex(v1, v3); } void MxStdModel::split_face4(unsigned int f, unsigned int *newverts) { unsigned int v0 = face(f).v[0]; unsigned int v1 = face(f).v[1]; unsigned int v2 = face(f).v[2]; unsigned int pivot = split_edge(v0, v1); unsigned int new1 = split_edge(v1, v2); unsigned int new2 = split_edge(v0, v2); if( newverts ) { newverts[0] = pivot; newverts[1] = new1; newverts[2] = new2; } flip_edge(pivot, v2); } void MxStdModel::compact_vertices() { MxVertexID oldID; MxVertexID newID = 0; for(oldID=0; oldID 0 ); SanityCheck( !neighbors(f(0)).find(fid, &j) ); SanityCheck( !neighbors(f(1)).find(fid, &j) ); SanityCheck( !neighbors(f(2)).find(fid, &j) ); } void MxStdModel::remove_degeneracy(MxFaceList& faces) { for(unsigned int i=0; iv1 = v1; conx->v2 = v2; if( vnew ) { mxv_sub(conx->dv1, vnew, vertex(v1), 3); mxv_sub(conx->dv2, vnew, vertex(v2), 3); } else { conx->dv1[X] = conx->dv1[Y] = conx->dv1[Z] = 0.0; conx->dv2[X] = conx->dv2[Y] = conx->dv2[Z] = 0.0; } conx->delta_faces.reset(); conx->dead_faces.reset(); // Mark the neighborhood of (v1,v2) such that each face is // tagged with the number of times the vertices v1,v2 occur // in it. Possible values are 1 or 2. // mark_neighborhood(v2, 0); mark_neighborhood(v1, 1); mark_neighborhood_delta(v2, 1); // Now partition the neighborhood of (v1,v2) into those faces // which degenerate during contraction and those which are merely // reshaped. // partition_marked_neighbors(v1, 2, conx->delta_faces, conx->dead_faces); conx->delta_pivot = conx->delta_faces.length(); partition_marked_neighbors(v2, 2, conx->delta_faces, conx->dead_faces); } void MxStdModel::apply_contraction(const MxPairContraction& conx) { MxVertexID v1=conx.v1, v2=conx.v2; // Move v1 to new position mxv_addinto(vertex(v1), conx.dv1, 3); uint i; // // Remove dead faces for(i=0; idv1, vnew, vertex(v1), 3); mxv_sub(conx->dv2, vnew, vertex(v2), 3); apply_contraction(*conx); } void MxStdModel::compute_contraction(MxFaceID fid, MxFaceContraction *conx) { const MxFace& f = face(fid); conx->f = fid; conx->dv1[X] = conx->dv1[Y] = conx->dv1[Z] = 0.0; conx->dv2[X] = conx->dv2[Y] = conx->dv2[Z] = 0.0; conx->dv3[X] = conx->dv3[Y] = conx->dv3[Z] = 0.0; conx->delta_faces.reset(); conx->dead_faces.reset(); PARANOID( mark_neighborhood(f[0], 0) ); mark_neighborhood(f[1], 0); mark_neighborhood(f[2], 0); mark_neighborhood(f[0], 1); mark_neighborhood_delta(f[1], +1); mark_neighborhood_delta(f[2], +1); fmark(fid, 0); // don't include f in dead_faces partition_marked_neighbors(f[0], 2, conx->delta_faces, conx->dead_faces); partition_marked_neighbors(f[1], 2, conx->delta_faces, conx->dead_faces); partition_marked_neighbors(f[2], 2, conx->delta_faces, conx->dead_faces); } void MxStdModel::contract(MxVertexID v1, MxVertexID v2, MxVertexID v3, const float *vnew, MxFaceList& changed) { mark_neighborhood(v1, 0); mark_neighborhood(v2, 0); mark_neighborhood(v3, 0); changed.reset(); collect_unmarked_neighbors(v1, changed); collect_unmarked_neighbors(v2, changed); collect_unmarked_neighbors(v3, changed); // Move v1 to vnew vertex(v1)(0) = vnew[X]; vertex(v1)(1) = vnew[Y]; vertex(v1)(2) = vnew[Z]; // Replace occurrences of v2 & v3 with v1 remap_vertex(v2, v1); remap_vertex(v3, v1); remove_degeneracy(changed); // // !!HACK: Only a temporary solution if( normal_binding() == MX_PERFACE ) { float n[3]; for(uint i=0; i