static typename DerivedF::Scalar add_vertex(const Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 1> &values, const Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 3> &points, unsigned int i0, unsigned int i1, PointMatrixType &vertices, int &num_vertices, MyMap &edge2vertex) { // find vertex if it has been computed already MyMapIterator it = edge2vertex.find(EdgeKey(i0, i1)); if (it != edge2vertex.end()) return it->second; ; // generate new vertex const Eigen::Matrix<typename DerivedV::Scalar, 1, 3> & p0 = points.row(i0); const Eigen::Matrix<typename DerivedV::Scalar, 1, 3> & p1 = points.row(i1); typename DerivedV::Scalar s0 = fabs(values[i0]); typename DerivedV::Scalar s1 = fabs(values[i1]); typename DerivedV::Scalar t = s0 / (s0+s1); num_vertices++; if (num_vertices > vertices.rows()) vertices.conservativeResize(vertices.rows()+10000, Eigen::NoChange); vertices.row(num_vertices-1) = (1.0f-t)*p0 + t*p1; edge2vertex[EdgeKey(i0, i1)] = num_vertices-1; return num_vertices-1; }
//---------------------------------------------------------------------------- void PartitionMesh::SplitTriangleMMP (std::vector<int>& negIndices, std::vector<int>& posIndices, int v0, int v1, int v2) { int v12 = mEMap[EdgeKey(v1, v2)].second; int v20 = mEMap[EdgeKey(v2, v0)].second; negIndices.push_back(v0); negIndices.push_back(v1); negIndices.push_back(v12); negIndices.push_back(v0); negIndices.push_back(v12); negIndices.push_back(v20); posIndices.push_back(v2); posIndices.push_back(v20); posIndices.push_back(v12); }
//---------------------------------------------------------------------------- void PartitionMesh::SplitTriangleMPZ (std::vector<int>& negIndices, std::vector<int>& posIndices, int v0, int v1, int v2) { int v01 = mEMap[EdgeKey(v0, v1)].second; negIndices.push_back(v2); negIndices.push_back(v0); negIndices.push_back(v01); posIndices.push_back(v2); posIndices.push_back(v01); posIndices.push_back(v1); }
void PoissonReconstruction::SetConnectedComponents( const std::vector< std::vector< int > >& polygons , std::vector< std::vector< int > >& components ) { std::vector< int > polygonRoots( polygons.size() ); for( size_t i=0 ; i<polygons.size() ; i++ ) polygonRoots[i] = int(i); hash_map< long long , int > edgeTable; for( size_t i=0 ; i<polygons.size() ; i++ ) { int sz = int( polygons[i].size() ); for( int j=0 ; j<sz ; j++ ) { int j1 = j , j2 = (j+1)%sz; int v1 = polygons[i][j1] , v2 = polygons[i][j2]; long long eKey = EdgeKey( v1 , v2 ); hash_map< long long , int >::iterator iter = edgeTable.find( eKey ); if( iter==edgeTable.end() ) edgeTable[ eKey ] = int(i); else { int p = iter->second; while( polygonRoots[p]!=p ) { int temp = polygonRoots[p]; polygonRoots[p] = int(i); p = temp; } polygonRoots[p] = int(i); } } } for( size_t i=0 ; i<polygonRoots.size() ; i++ ) { int p = int(i); while( polygonRoots[p]!=p ) p = polygonRoots[p]; int root = p; p = int(i); while( polygonRoots[p]!=p ) { int temp = polygonRoots[p]; polygonRoots[p] = root; p = temp; } } int cCount = 0; hash_map< int , int > vMap; for( int i= 0 ; i<int(polygonRoots.size()) ; i++ ) if( polygonRoots[i]==i ) vMap[i] = cCount++; components.resize( cCount ); for( int i=0 ; i<int(polygonRoots.size()) ; i++ ) components[ vMap[ polygonRoots[i] ] ].push_back(i); }
//-------------------------------------------------------------------------------------------------- /// Add mesh line indices by analyzing the triangle indices and only adding 'unique' edges //-------------------------------------------------------------------------------------------------- void StructGridCutPlane::addMeshLineIndices(const uint* triangleIndices, uint triangleCount) { std::vector<int64> edges; edges.reserve(3*triangleCount); std::vector<int64>::iterator it; uint t; for (t = 0; t < triangleCount; t++) { uint i; for (i = 0; i < 3; i++) { const uint vertexIdx1 = triangleIndices[3*t + i]; const uint vertexIdx2 = (i < 2) ? triangleIndices[3*t + i + 1] : triangleIndices[3*t]; int64 edgeKeyVal = EdgeKey(vertexIdx1, vertexIdx2).toKeyVal(); it = find(edges.begin(), edges.end(), edgeKeyVal); if (it == edges.end()) { edges.push_back(edgeKeyVal); } else { edges.erase(it); } } } for (it = edges.begin(); it != edges.end(); ++it) { EdgeKey ek = EdgeKey::fromkeyVal(*it); m_meshLineIndices.push_back(ek.index1()); m_meshLineIndices.push_back(ek.index2()); } }
void BoxManager<Real>::Initialize () { // Get the box endpoints. int intrSize = (int)mBoxes->size(), endpSize = 2*intrSize; mXEndpoints.resize(endpSize); mYEndpoints.resize(endpSize); mZEndpoints.resize(endpSize); int i, j; for (i = 0, j = 0; i < intrSize; ++i) { mXEndpoints[j].Type = 0; mXEndpoints[j].Value = (*mBoxes)[i].Min[0]; mXEndpoints[j].Index = i; mYEndpoints[j].Type = 0; mYEndpoints[j].Value = (*mBoxes)[i].Min[1]; mYEndpoints[j].Index = i; mZEndpoints[j].Type = 0; mZEndpoints[j].Value = (*mBoxes)[i].Min[2]; mZEndpoints[j].Index = i; j++; mXEndpoints[j].Type = 1; mXEndpoints[j].Value = (*mBoxes)[i].Max[0]; mXEndpoints[j].Index = i; mYEndpoints[j].Type = 1; mYEndpoints[j].Value = (*mBoxes)[i].Max[1]; mYEndpoints[j].Index = i; mZEndpoints[j].Type = 1; mZEndpoints[j].Value = (*mBoxes)[i].Max[2]; mZEndpoints[j].Index = i; j++; } // Sort the rectangle endpoints. std::sort(mXEndpoints.begin(), mXEndpoints.end()); std::sort(mYEndpoints.begin(), mYEndpoints.end()); std::sort(mZEndpoints.begin(), mZEndpoints.end()); // Create the interval-to-endpoint lookup tables. mXLookup.resize(endpSize); mYLookup.resize(endpSize); mZLookup.resize(endpSize); for (j = 0; j < endpSize; ++j) { mXLookup[2*mXEndpoints[j].Index + mXEndpoints[j].Type] = j; mYLookup[2*mYEndpoints[j].Index + mYEndpoints[j].Type] = j; mZLookup[2*mZEndpoints[j].Index + mZEndpoints[j].Type] = j; } // Active set of rectangles (stored by index in array). std::set<int> active; // set of overlapping rectangles (stored by pairs of indices in array) mOverlap.clear(); // Sweep through the endpoints to determine overlapping x-intervals. for (i = 0; i < endpSize; ++i) { Endpoint& endpoint = mXEndpoints[i]; int index = endpoint.Index; if (endpoint.Type == 0) // an interval 'begin' value { // In the 1D problem, the current interval overlaps with all the // active intervals. In 3D this we also need to check for // y-overlap and z-overlap. std::set<int>::iterator iter = active.begin(); std::set<int>::iterator end = active.end(); for (/**/; iter != end; ++iter) { // Rectangles activeIndex and index overlap in the // x-dimension. Test for overlap in the y-dimension and // z-dimension. int activeIndex = *iter; const AxisAlignedBox3<Real>& b0 = (*mBoxes)[activeIndex]; const AxisAlignedBox3<Real>& b1 = (*mBoxes)[index]; if (b0.HasYOverlap(b1) && b0.HasZOverlap(b1)) { if (activeIndex < index) { mOverlap.insert(EdgeKey(activeIndex, index)); } else { mOverlap.insert(EdgeKey(index, activeIndex)); } } } active.insert(index); } else // an interval 'end' value { active.erase(index); } } }
void BoxManager<Real>::InsertionSort (std::vector<Endpoint>& endpoint, std::vector<int>& lookup) { // Apply an insertion sort. Under the assumption that the rectangles // have not changed much since the last call, the endpoints are nearly // sorted. The insertion sort should be very fast in this case. int endpSize = (int)endpoint.size(); for (int j = 1; j < endpSize; ++j) { Endpoint key = endpoint[j]; int i = j - 1; while (i >= 0 && key < endpoint[i]) { Endpoint e0 = endpoint[i]; Endpoint e1 = endpoint[i+1]; // Update the overlap status. if (e0.Type == 0) { if (e1.Type == 1) { // The 'b' of interval E0.mIndex was smaller than the 'e' // of interval E1.mIndex, and the intervals *might have // been* overlapping. Now 'b' and 'e' are swapped, and // the intervals cannot overlap. Remove the pair from // the overlap set. The removal operation needs to find // the pair and erase it if it exists. Finding the pair // is the expensive part of the operation, so there is no // real time savings in testing for existence first, then // deleting if it does. mOverlap.erase(EdgeKey(e0.Index, e1.Index)); } } else { if (e1.Type == 0) { // The 'b' of interval E1.index was larger than the 'e' // of interval E0.index, and the intervals were not // overlapping. Now 'b' and 'e' are swapped, and the // intervals *might be* overlapping. Determine if they // are overlapping and then insert. const AxisAlignedBox3<Real>& b0 = (*mBoxes)[e0.Index]; const AxisAlignedBox3<Real>& b1 = (*mBoxes)[e1.Index]; if (b0.TestIntersection(b1)) { mOverlap.insert(EdgeKey(e0.Index, e1.Index)); } } } // Reorder the items to maintain the sorted list. endpoint[i] = e1; endpoint[i+1] = e0; lookup[2*e1.Index + e1.Type] = i; lookup[2*e0.Index + e0.Type] = i+1; i--; } endpoint[i+1] = key; lookup[2*key.Index + key.Type] = i+1; } }
MinBox3<Real>::MinBox3 (int numPoints, const Vector3<Real>* points, Real epsilon, Query::Type queryType) { // Get the convex hull of the points. ConvexHull3<Real> kHull(numPoints,(Vector3<Real>*)points, epsilon, false, queryType); int hullDim = kHull.GetDimension(); if (hullDim == 0) { mMinBox.Center = points[0]; mMinBox.Axis[0] = Vector3<Real>::UNIT_X; mMinBox.Axis[1] = Vector3<Real>::UNIT_Y; mMinBox.Axis[2] = Vector3<Real>::UNIT_Z; mMinBox.Extent[0] = (Real)0; mMinBox.Extent[1] = (Real)0; mMinBox.Extent[2] = (Real)0; return; } if (hullDim == 1) { ConvexHull1<Real>* pkHull1 = kHull.GetConvexHull1(); const int* hullIndices = pkHull1->GetIndices(); mMinBox.Center = ((Real)0.5)*(points[hullIndices[0]] + points[hullIndices[1]]); Vector3<Real> diff = points[hullIndices[1]] - points[hullIndices[0]]; mMinBox.Extent[0] = ((Real)0.5)*diff.Normalize(); mMinBox.Extent[1] = (Real)0; mMinBox.Extent[2] = (Real)0; mMinBox.Axis[0] = diff; Vector3<Real>::GenerateComplementBasis(mMinBox.Axis[1], mMinBox.Axis[2], mMinBox.Axis[0]); delete0(pkHull1); return; } int i, j; Vector3<Real> origin, diff, U, V, W; Vector2<Real>* points2; Box2<Real> box2; if (hullDim == 2) { // When ConvexHull3 reports that the point set is 2-dimensional, the // caller is responsible for projecting the points onto a plane and // calling ConvexHull2. ConvexHull3 does provide information about // the plane of the points. In this application, we need only // project the input points onto that plane and call ContMinBox in // two dimensions. // Get a coordinate system relative to the plane of the points. origin = kHull.GetPlaneOrigin(); W = kHull.GetPlaneDirection(0).Cross(kHull.GetPlaneDirection(1)); Vector3<Real>::GenerateComplementBasis(U, V, W); // Project the input points onto the plane. points2 = new1<Vector2<Real> >(numPoints); for (i = 0; i < numPoints; ++i) { diff = points[i] - origin; points2[i].X() = U.Dot(diff); points2[i].Y() = V.Dot(diff); } // Compute the minimum area box in 2D. box2 = MinBox2<Real>(numPoints, points2, epsilon, queryType, false); delete1(points2); // Lift the values into 3D. mMinBox.Center = origin + box2.Center.X()*U + box2.Center.Y()*V; mMinBox.Axis[0] = box2.Axis[0].X()*U + box2.Axis[0].Y()*V; mMinBox.Axis[1] = box2.Axis[1].X()*U + box2.Axis[1].Y()*V; mMinBox.Axis[2] = W; mMinBox.Extent[0] = box2.Extent[0]; mMinBox.Extent[1] = box2.Extent[1]; mMinBox.Extent[2] = (Real)0; return; } int hullQuantity = kHull.GetNumSimplices(); const int* hullIndices = kHull.GetIndices(); Real volume, minVolume = Math<Real>::MAX_REAL; // Create the unique set of hull vertices to minimize the time spent // projecting vertices onto planes of the hull faces. std::set<int> uniqueIndices; for (i = 0; i < 3*hullQuantity; ++i) { uniqueIndices.insert(hullIndices[i]); } // Use the rotating calipers method on the projection of the hull onto // the plane of each face. Also project the hull onto the normal line // of each face. The minimum area box in the plane and the height on // the line produce a containing box. If its volume is smaller than the // current volume, this box is the new candidate for the minimum volume // box. The unique edges are accumulated into a set for use by a later // step in the algorithm. const int* currentHullIndex = hullIndices; Real height, minHeight, maxHeight; std::set<EdgeKey> edges; points2 = new1<Vector2<Real> >(uniqueIndices.size()); for (i = 0; i < hullQuantity; ++i) { // Get the triangle. int v0 = *currentHullIndex++; int v1 = *currentHullIndex++; int v2 = *currentHullIndex++; // Save the edges for later use. edges.insert(EdgeKey(v0, v1)); edges.insert(EdgeKey(v1, v2)); edges.insert(EdgeKey(v2, v0)); // Get 3D coordinate system relative to plane of triangle. origin = (points[v0] + points[v1] + points[v2])/(Real)3.0; Vector3<Real> edge1 = points[v1] - points[v0]; Vector3<Real> edge2 = points[v2] - points[v0]; W = edge2.UnitCross(edge1); // inner-pointing normal if (W == Vector3<Real>::ZERO) { // The triangle is needle-like, so skip it. continue; } Vector3<Real>::GenerateComplementBasis(U, V, W); // Project points onto plane of triangle, onto normal line of plane. // TO DO. In theory, minHeight should be zero since W points to the // interior of the hull. However, the snap rounding used in the 3D // convex hull finder involves loss of precision, which in turn can // cause a hull facet to have the wrong ordering (clockwise instead // of counterclockwise when viewed from outside the hull). The // height calculations here trap that problem (the incorrectly ordered // face will not affect the minimum volume box calculations). minHeight = (Real)0; maxHeight = (Real)0; j = 0; std::set<int>::const_iterator iter = uniqueIndices.begin(); while (iter != uniqueIndices.end()) { int index = *iter++; diff = points[index] - origin; points2[j].X() = U.Dot(diff); points2[j].Y() = V.Dot(diff); height = W.Dot(diff); if (height > maxHeight) { maxHeight = height; } else if (height < minHeight) { minHeight = height; } j++; } if (-minHeight > maxHeight) { maxHeight = -minHeight; } // Compute minimum area box in 2D. box2 = MinBox2<Real>((int)uniqueIndices.size(), points2, epsilon, queryType, false); // Update current minimum-volume box (if necessary). volume = maxHeight*box2.Extent[0]*box2.Extent[1]; if (volume < minVolume) { minVolume = volume; // Lift the values into 3D. mMinBox.Extent[0] = box2.Extent[0]; mMinBox.Extent[1] = box2.Extent[1]; mMinBox.Extent[2] = ((Real)0.5)*maxHeight; mMinBox.Axis[0] = box2.Axis[0].X()*U + box2.Axis[0].Y()*V; mMinBox.Axis[1] = box2.Axis[1].X()*U + box2.Axis[1].Y()*V; mMinBox.Axis[2] = W; mMinBox.Center = origin + box2.Center.X()*U + box2.Center.Y()*V + mMinBox.Extent[2]*W; } } // The minimum-volume box can also be supported by three mutually // orthogonal edges of the convex hull. For each triple of orthogonal // edges, compute the minimum-volume box for that coordinate frame by // projecting the points onto the axes of the frame. std::set<EdgeKey>::const_iterator e2iter; for (e2iter = edges.begin(); e2iter != edges.end(); e2iter++) { W = points[e2iter->V[1]] - points[e2iter->V[0]]; W.Normalize(); std::set<EdgeKey>::const_iterator e1iter = e2iter; for (++e1iter; e1iter != edges.end(); e1iter++) { V = points[e1iter->V[1]] - points[e1iter->V[0]]; V.Normalize(); Real dot = V.Dot(W); if (Math<Real>::FAbs(dot) > Math<Real>::ZERO_TOLERANCE) { continue; } std::set<EdgeKey>::const_iterator e0iter = e1iter; for (++e0iter; e0iter != edges.end(); e0iter++) { U = points[e0iter->V[1]] - points[e0iter->V[0]]; U.Normalize(); dot = U.Dot(V); if (Math<Real>::FAbs(dot) > Math<Real>::ZERO_TOLERANCE) { continue; } dot = U.Dot(W); if (Math<Real>::FAbs(dot) > Math<Real>::ZERO_TOLERANCE) { continue; } // The three edges are mutually orthogonal. Project the // hull points onto the lines containing the edges. Use // hull point zero as the origin. Real umin = (Real)0, umax = (Real)0; Real vmin = (Real)0, vmax = (Real)0; Real wmin = (Real)0, wmax = (Real)0; origin = points[hullIndices[0]]; std::set<int>::const_iterator iter = uniqueIndices.begin(); while (iter != uniqueIndices.end()) { int index = *iter++; diff = points[index] - origin; Real fU = U.Dot(diff); if (fU < umin) { umin = fU; } else if (fU > umax) { umax = fU; } Real fV = V.Dot(diff); if (fV < vmin) { vmin = fV; } else if (fV > vmax) { vmax = fV; } Real fW = W.Dot(diff); if (fW < wmin) { wmin = fW; } else if (fW > wmax) { wmax = fW; } } Real uExtent = ((Real)0.5)*(umax - umin); Real vExtent = ((Real)0.5)*(vmax - vmin); Real wExtent = ((Real)0.5)*(wmax - wmin); // Update current minimum-volume box (if necessary). volume = uExtent*vExtent*wExtent; if (volume < minVolume) { minVolume = volume; mMinBox.Extent[0] = uExtent; mMinBox.Extent[1] = vExtent; mMinBox.Extent[2] = wExtent; mMinBox.Axis[0] = U; mMinBox.Axis[1] = V; mMinBox.Axis[2] = W; mMinBox.Center = origin + ((Real)0.5)*(umin+umax)*U + ((Real)0.5)*(vmin+vmax)*V + ((Real)0.5)*(wmin+wmax)*W; } } } } delete1(points2); }
//-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void OutlineEdgeExtractor::addPrimitives(uint verticesPerPrimitive, const uint* indices, size_t indexCount) { CVF_ASSERT(verticesPerPrimitive > 0); CVF_ASSERT(indices); CVF_ASSERT(indexCount > 0); // Points will never become edges if (verticesPerPrimitive < 2) { return; } size_t numPrimitives = indexCount/verticesPerPrimitive; size_t ip; for (ip = 0; ip < numPrimitives; ip++) { size_t myFaceIndex = m_faceNormals.size(); size_t firstIdxInPrimitive = ip*verticesPerPrimitive; // Normal computation accepts points and lines, but in that case returns a zero vector Vec3f faceNormal = computeFaceNormal(&indices[firstIdxInPrimitive], verticesPerPrimitive); m_faceNormals.push_back(faceNormal); uint i; for (i = 0; i < verticesPerPrimitive; i++) { const uint vertexIdx1 = indices[firstIdxInPrimitive + i]; const uint vertexIdx2 = (i < verticesPerPrimitive - 1) ? indices[firstIdxInPrimitive + i + 1] : indices[firstIdxInPrimitive]; // Never add collapsed edges if (vertexIdx1 == vertexIdx2) { continue; } int64 edgeKeyVal = EdgeKey(vertexIdx1, vertexIdx2).toKeyVal(); std::map<int64, size_t>::iterator it = m_edgeToFaceIndexMap.find(edgeKeyVal); if (it == m_edgeToFaceIndexMap.end()) { // Not found, so add and register face index m_edgeToFaceIndexMap[edgeKeyVal] = myFaceIndex; } else { size_t otherFaceIdx = it->second; if (otherFaceIdx < OEE_MULTIREF_EDGE) { // An edge is already there, check angle if (isFaceAngleAboveThreshold(myFaceIndex, otherFaceIdx)) { m_edgeToFaceIndexMap[edgeKeyVal] = OEE_OUTLINE_EDGE; } else { m_edgeToFaceIndexMap[edgeKeyVal] = OEE_NON_OUTLINE_EDGE; } } else { // Three or more faces share an edge m_edgeToFaceIndexMap[edgeKeyVal] = OEE_MULTIREF_EDGE; } } } } }
void IntervalManager<Real>::Initialize () { // Get the interval endpoints. int intrSize = (int)mInterval->size(), endpSize = 2*intrSize; mEndpoint.resize(endpSize); int i, j; for (i = 0, j = 0; i < intrSize; ++i) { Endpoint& emin = mEndpoint[j++]; emin.Type = 0; emin.Value = (*mInterval)[i][0]; emin.Index = i; Endpoint& emax = mEndpoint[j++]; emax.Type = 1; emax.Value = (*mInterval)[i][1]; emax.Index = i; } // Sort the interval endpoints. std::sort(mEndpoint.begin(), mEndpoint.end()); // Create the interval-to-endpoint lookup table. mLookup.resize(endpSize); for (j = 0; j < endpSize; ++j) { Endpoint& endpoint = mEndpoint[j]; mLookup[2*endpoint.Index + endpoint.Type] = j; } // Active set of intervals (stored by index in array). std::set<int> active; // Set of overlapping intervals (stored by pairs of indices in array). mOverlap.clear(); // Sweep through the endpoints to determine overlapping intervals. for (i = 0; i < endpSize; ++i) { Endpoint& endpoint = mEndpoint[i]; int index = endpoint.Index; if (endpoint.Type == 0) // an interval 'begin' value { std::set<int>::iterator iter = active.begin(); std::set<int>::iterator end = active.end(); for (/**/; iter != end; ++iter) { int activeIndex = *iter; if (activeIndex < index) { mOverlap.insert(EdgeKey(activeIndex, index)); } else { mOverlap.insert(EdgeKey(index, activeIndex)); } } active.insert(index); } else // an interval 'end' value { active.erase(index); } } }
void IntervalManager<Real>::Update () { // Apply an insertion sort. Under the assumption that the intervals // have not changed much since the last call, the end points are nearly // sorted. The insertion sort should be very fast in this case. int endpSize = (int)mEndpoint.size(); for (int j = 1; j < endpSize; ++j) { Endpoint key = mEndpoint[j]; int i = j - 1; while (i >= 0 && key < mEndpoint[i]) { Endpoint e0 = mEndpoint[i]; Endpoint e1 = mEndpoint[i+1]; // Update the overlap status. if (e0.Type == 0) { if (e1.Type == 1) { // The 'b' of interval E0.mIndex was smaller than the 'e' // of interval E1.mIndex, and the intervals *might have // been* overlapping. Now 'b' and 'e' are swapped, and // the intervals cannot overlap. Remove the pair from // the overlap set. The removal operation needs to find // the pair and erase it if it exists. Finding the pair // is the expensive part of the operation, so there is no // time savings in testing for existence first and then // deleting. mOverlap.erase(EdgeKey(e0.Index, e1.Index)); } } else { if (e1.Type == 0) { // The 'b' of interval E1.index was larger than the 'e' // of interval E0.index, and the intervals were not // overlapping. Now 'b' and 'e' are swapped, and the // intervals *might be* overlapping. Determine if they // are overlapping and then insert. const Vector2<Real>& i0 = (*mInterval)[e0.Index]; const Vector2<Real>& i1 = (*mInterval)[e1.Index]; if (i0[0] <= i1[1]) { mOverlap.insert(EdgeKey(e0.Index, e1.Index)); } } } // Reorder the items to maintain the sorted list. mEndpoint[i] = e1; mEndpoint[i+1] = e0; mLookup[2*e1.Index + e1.Type] = i; mLookup[2*e0.Index + e0.Type] = i+1; i--; } mEndpoint[i+1] = key; mLookup[2*key.Index + key.Type] = i+1; } }
//---------------------------------------------------------------------------- void PartitionMesh::ClassifyEdges (std::vector<APoint>& clipVertices, const std::vector<int>& indices) { const int numTriangles = (int)indices.size()/3; int nextIndex = (int)clipVertices.size(); for (int i = 0; i < numTriangles; ++i) { int v0 = indices[3*i+0]; int v1 = indices[3*i+1]; int v2 = indices[3*i+2]; float sDist0 = mSignedDistances[v0]; float sDist1 = mSignedDistances[v1]; float sDist2 = mSignedDistances[v2]; EdgeKey key; float t; APoint intr; AVector diff; // The change-in-sign tests are structured this way to avoid numerical // round-off problems. For example, sDist0 > 0 and sDist1 < 0, but // both are very small and sDist0*sDist1 = 0 due to round-off // errors. The tests also guarantee consistency between this function // and ClassifyTriangles, the latter function using sign tests only on // the individual sDist values. if ((sDist0 > 0.0f && sDist1 < 0.0f) || (sDist0 < 0.0f && sDist1 > 0.0f)) { key = EdgeKey(v0, v1); if (mEMap.find(key) == mEMap.end()) { t = sDist0/(sDist0 - sDist1); diff = clipVertices[v1] - clipVertices[v0]; intr = clipVertices[v0] + t*diff; clipVertices.push_back(intr); mEMap[key] = std::make_pair(intr, nextIndex); ++nextIndex; } } if ((sDist1 > 0.0f && sDist2 < 0.0f) || (sDist1 < 0.0f && sDist2 > 0.0f)) { key = EdgeKey(v1,v2); if (mEMap.find(key) == mEMap.end()) { t = sDist1/(sDist1 - sDist2); diff = clipVertices[v2] - clipVertices[v1]; intr = clipVertices[v1] + t*diff; clipVertices.push_back(intr); mEMap[key] = std::make_pair(intr, nextIndex); ++nextIndex; } } if ((sDist2 > 0.0f && sDist0 < 0.0f) || (sDist2 < 0.0f && sDist0 > 0.0f)) { key = EdgeKey(v2,v0); if (mEMap.find(key) == mEMap.end()) { t = sDist2/(sDist2 - sDist0); diff = clipVertices[v0] - clipVertices[v2]; intr = clipVertices[v2] + t*diff; clipVertices.push_back(intr); mEMap[key] = std::make_pair(intr, nextIndex); ++nextIndex; } } } }
void SplitPolygon ( const std::vector< int >& polygon , std::vector< PlyValueVertex< Real > >& vertices , std::vector< std::vector< int > >* ltPolygons , std::vector< std::vector< int > >* gtPolygons , std::vector< bool >* ltFlags , std::vector< bool >* gtFlags , hash_map< long long , int >& vertexTable , Real trimValue ) { int sz = int( polygon.size() ); std::vector< bool > gt( sz ); int gtCount = 0; for( int j=0 ; j<sz ; j++ ) { gt[j] = ( vertices[ polygon[j] ].value>trimValue ); if( gt[j] ) gtCount++; } if ( gtCount==sz ){ if( gtPolygons ) gtPolygons->push_back( polygon ) ; if( gtFlags ) gtFlags->push_back( false ); } else if( gtCount==0 ){ if( ltPolygons ) ltPolygons->push_back( polygon ) ; if( ltFlags ) ltFlags->push_back( false ); } else { int start; for( start=0 ; start<sz ; start++ ) if( gt[start] && !gt[(start+sz-1)%sz] ) break; bool gtFlag = true; std::vector< int > poly; // Add the initial vertex { int j1 = (start+int(sz)-1)%sz , j2 = start; int v1 = polygon[j1] , v2 = polygon[j2]; int vIdx; hash_map< long long , int >::iterator iter = vertexTable.find( EdgeKey( v1 , v2 ) ); if( iter==vertexTable.end() ) { vertexTable[ EdgeKey( v1 , v2 ) ] = vIdx = int( vertices.size() ); vertices.push_back( InterpolateVertices( vertices[v1] , vertices[v2] , trimValue ) ); } else vIdx = iter->second; poly.push_back( vIdx ); } for( int _j=0 ; _j<=sz ; _j++ ) { int j1 = (_j+start+sz-1)%sz , j2 = (_j+start)%sz; int v1 = polygon[j1] , v2 = polygon[j2]; if( gt[j2]==gtFlag ) poly.push_back( v2 ); else { int vIdx; hash_map< long long , int >::iterator iter = vertexTable.find( EdgeKey( v1 , v2 ) ); if( iter==vertexTable.end() ) { vertexTable[ EdgeKey( v1 , v2 ) ] = vIdx = int( vertices.size() ); vertices.push_back( InterpolateVertices( vertices[v1] , vertices[v2] , trimValue ) ); } else vIdx = iter->second; poly.push_back( vIdx ); if( gtFlag ){ if( gtPolygons ) gtPolygons->push_back( poly ) ; if( ltFlags ) ltFlags->push_back( true ); } else { if( ltPolygons ) ltPolygons->push_back( poly ) ; if( gtFlags ) gtFlags->push_back( true ); } poly.clear() , poly.push_back( vIdx ) , poly.push_back( v2 ); gtFlag = !gtFlag; } } } }