// //ORIGINAL LINE: void delaunay(List<Ogre::Vector2>& pointList, LinkedList<Triangle>& tbuffer) const void delaunay(PointList pointList, ref DelaunayTriangleBuffer tbuffer) { // Compute super triangle or insert manual super triangle if (mManualSuperTriangle != null) { float maxTriangleSize = 0.0f; //for (PointList::iterator it = pointList.begin(); it!=pointList.end(); ++it) foreach (Vector2 it in pointList) { maxTriangleSize = max(maxTriangleSize, Math.Abs(it.x)); maxTriangleSize = max(maxTriangleSize, Math.Abs(it.y)); } pointList.push_back(new Vector2(-3f * maxTriangleSize, -3f * maxTriangleSize)); pointList.push_back(new Vector2(3f * maxTriangleSize, -3f * maxTriangleSize)); pointList.push_back(new Vector2(0.0f, 3 * maxTriangleSize)); int maxTriangleIndex = pointList.size() - 3; Triangle superTriangle = new Triangle(pointList); superTriangle.i[0] = maxTriangleIndex; superTriangle.i[1] = maxTriangleIndex + 1; superTriangle.i[2] = maxTriangleIndex + 2; tbuffer.push_back(superTriangle); } // Point insertion loop for (int i = 0; i < pointList.size() - 3; i++) { //Utils::log("insert point " + StringConverter::toString(i)); //std::list<std::list<Triangle>::iterator> borderlineTriangles; std_list <Triangle> borderlineTriangles = new std_list <Triangle>(); // Insert 1 point, find all triangles for which the point is in circumcircle Vector2 p = pointList[i]; //std::set<DelaunaySegment> segments; std_set <DelaunaySegment> segments = new std_set <DelaunaySegment>(); IEnumerator <Triangle> et = tbuffer.GetEnumerator(); //for (DelaunayTriangleBuffer::iterator it = tbuffer.begin(); it!=tbuffer.end();) List <Triangle> need_erase = new List <Triangle>(); while (et.MoveNext()) { Triangle it = et.Current; Triangle.InsideType isInside = it.isPointInsideCircumcircle(p); if (isInside == Triangle.InsideType.IT_INSIDE) { if (!it.isDegenerate()) { //Utils::log("tri insie" + it->debugDescription()); for (int k = 0; k < 3; k++) { DelaunaySegment d1 = new DelaunaySegment(it.i[k], it.i[(k + 1) % 3]); if (segments.find(d1) != segments.end()) { segments.erase(d1); } else if (segments.find(d1.inverse()) != segments.end()) { segments.erase(d1.inverse()); } else { segments.insert(d1); } } } //it=tbuffer.erase(it); need_erase.Add(it); } else if (isInside == Triangle.InsideType.IT_BORDERLINEOUTSIDE) { //Utils::log("tri borer " + it->debugDescription()); borderlineTriangles.push_back(it); //++it; } else { //++it; } } //do delete foreach (var v in need_erase) { tbuffer.Remove(v); } // Robustification of the standard algorithm : if one triangle's circumcircle was borderline against the new point, // test whether that triangle is intersected by new segments or not (normal situation : it should not) // If intersected, the triangle is considered having the new point in its circumc std_set <DelaunaySegment> copySegment = segments; IEnumerator <Triangle> be = borderlineTriangles.GetEnumerator(); //for (std::list<std::list<Triangle>::iterator>::iterator itpTri = borderlineTriangles.begin(); itpTri!=borderlineTriangles.end(); itpTri++ ) while (be.MoveNext()) { Triangle itpTri = be.Current; //DelaunayTriangleBuffer::iterator itTri = *itpTri; Triangle itTri = itpTri; bool triRemoved = false; //for (std::set<DelaunaySegment>::iterator it = copySegment.begin(); it!=copySegment.end() && !triRemoved; ++it) IEnumerator <DelaunaySegment> cse = copySegment.GetEnumerator(); while (cse.MoveNext() && !triRemoved) { DelaunaySegment it = cse.Current; bool isTriangleIntersected = false; for (int k = 0; k < 2; k++) { int i1 = (k == 0) ? it.i1 : it.i2; int i2 = i; for (int l = 0; l < 3; l++) { //Early out if 2 points are in fact the same if (itTri.i[l] == i1 || itTri.i[l] == i2 || itTri.i[(l + 1) % 3] == i1 || itTri.i[(l + 1) % 3] == i2) { continue; } Segment2D seg2 = new Segment2D(itTri.p(l), itTri.p((l + 1) % 3)); Segment2D seg1 = new Segment2D(pointList[i1], pointList[i2]); if (seg1.intersects(seg2)) { isTriangleIntersected = true; break; } } } if (isTriangleIntersected) { if (!itTri.isDegenerate()) { //Utils::log("tri inside" + itTri->debugDescription()); for (int m = 0; m < 3; m++) { DelaunaySegment d1 = new DelaunaySegment(itTri.i[m], itTri.i[(m + 1) % 3]); if (segments.find(d1) != segments.end()) { segments.erase(d1); } else if (segments.find(d1.inverse()) != segments.end()) { segments.erase(d1.inverse()); } else { segments.insert(d1); } } } //tbuffer.erase(itTri); need_erase.Clear(); need_erase.Add(itTri); triRemoved = true; } } } //do delete foreach (var v in need_erase) { tbuffer.Remove(v); } // Find all the non-interior edges IEnumerator <DelaunaySegment> seg_ie = segments.GetEnumerator(); //for (std::set<DelaunaySegment>::iterator it = segments.begin(); it!=segments.end(); ++it) while (seg_ie.MoveNext()) { DelaunaySegment it = seg_ie.Current; //Triangle dt(&pointList); Triangle dt = new Triangle(pointList); dt.setVertices(it.i1, it.i2, i); dt.makeDirectIfNeeded(); //Utils::log("Add tri " + dt.debugDescription()); tbuffer.push_back(dt); } } // NB : Don't remove super triangle here, because all outer triangles are already removed in the addconstraints method. // Uncomment that code if delaunay triangulation ever has to be unconstrained... /*TouchSuperTriangle touchSuperTriangle(maxTriangleIndex, maxTriangleIndex+1,maxTriangleIndex+2); * tbuffer.remove_if(touchSuperTriangle); * pointList.pop_back(); * pointList.pop_back(); * pointList.pop_back();*/ }
void _addConstraints(ref DelaunayTriangleBuffer tbuffer, PointList pl, std_vector <int> segmentListIndices) { std_vector <DelaunaySegment> segList = new std_vector <DelaunaySegment>(); //Utils::log("a co"); //for (DelaunayTriangleBuffer::iterator it = tbuffer.begin(); it!=tbuffer.end();it++) // Utils::log(it->debugDescription()); // First, list all the segments that are not already in one of the delaunay triangles //for (std::vector<int>::const_iterator it2 = segmentListIndices.begin(); it2 != segmentListIndices.end(); it2++) for (int i = 0; i < segmentListIndices.Count; i++) { //int i1 = *it2; int i1 = segmentListIndices[i]; //it2++; i++; //int i2 = *it2; int i2 = segmentListIndices[i]; bool isAlreadyIn = false; //for (DelaunayTriangleBuffer::iterator it = tbuffer.begin(); it!=tbuffer.end(); ++it) foreach (var it in tbuffer) { if (it.containsSegment(i1, i2)) { isAlreadyIn = true; break; } } // only do something for segments not already in DT if (!isAlreadyIn) { segList.push_back(new DelaunaySegment(i1, i2)); } } // Re-Triangulate according to the new segments //for (std::vector<DelaunaySegment>::iterator itSeg=segList.begin(); itSeg!=segList.end(); itSeg++) for (int ii = segList.Count - 1; ii >= 0; ii--) { DelaunaySegment itSeg = segList[ii]; //Utils::log("itseg " + StringConverter::toString(itSeg->i1) + "," + StringConverter::toString(itSeg->i2) + " " + StringConverter::toString(pl[itSeg->i1]) + "," + StringConverter::toString(pl[itSeg->i2])); // Remove all triangles intersecting the segment and keep a list of outside edges std_set <DelaunaySegment> segments = new std_set <DelaunaySegment>(); Segment2D seg1 = new Segment2D(pl[itSeg.i1], pl[itSeg.i2]); //for (DelaunayTriangleBuffer::iterator itTri = tbuffer.begin(); itTri!=tbuffer.end(); ) for (int jj = tbuffer.Count - 1; jj >= 0; jj--) { Triangle itTri = tbuffer.getElement(jj).Value; bool isTriangleIntersected = false; bool isDegenerate = false; int degenIndex; for (int i = 0; i < 3; i++) { //Early out if 2 points are in fact the same if (itTri.i[i] == itSeg.i1 || itTri.i[i] == itSeg.i2 || itTri.i[(i + 1) % 3] == itSeg.i1 || itTri.i[(i + 1) % 3] == itSeg.i2) { if (itTri.isDegenerate()) { if (itTri.i[i] == itSeg.i1 || itTri.i[(i + 1) % 3] == itSeg.i1) { degenIndex = itSeg.i1; } else if (itTri.i[i] == itSeg.i2 || itTri.i[(i + 1) % 3] == itSeg.i2) { degenIndex = itSeg.i2; } isTriangleIntersected = true; isDegenerate = true; } else { continue; } } Segment2D seg2 = new Segment2D(itTri.p(i), itTri.p((i + 1) % 3)); if (seg1.intersects(seg2)) { isTriangleIntersected = true; break; } } if (isTriangleIntersected) { //if (isDegenerate) //Utils::log("degen " + itTri->debugDescription()); for (int k = 0; k < 3; k++) { DelaunaySegment d1 = new DelaunaySegment(itTri.i[k], itTri.i[(k + 1) % 3]); if (segments.find(d1) != segments.end()) { segments.erase(d1); } else if (segments.find(d1.inverse()) != segments.end()) { segments.erase(d1.inverse()); } else { segments.insert(d1); } } //itTri=tbuffer.erase(itTri); tbuffer.erase(jj); } //else // itTri++; } // Divide the list of points (coming from remaining segments) in 2 groups : "above" and "below" std_vector <int> pointsAbove = new std_vector <int>(); std_vector <int> pointsBelow = new std_vector <int>(); int pt = itSeg.i1; bool isAbove = true; while (segments.size() > 0) { //find next point //for (std::set<DelaunaySegment>::iterator it = segments.begin(); it!=segments.end(); ++it) DelaunaySegment[] segments_all = segments.get_allocator(); for (int i = 0; i < segments_all.Length; ++i) { DelaunaySegment it = segments_all[i];//segments.find(i,true); if (it.i1 == pt || it.i2 == pt) { //Utils::log("next " + StringConverter::toString(pt)); if (it.i1 == pt) { pt = it.i2; } else { pt = it.i1; } segments.erase(it); if (pt == itSeg.i2) { isAbove = false; } else if (pt != itSeg.i1) { if (isAbove) { pointsAbove.push_back(pt); } else { pointsBelow.push_back(pt); } } break; } } } // Recursively triangulate both polygons _recursiveTriangulatePolygon(itSeg, pointsAbove, tbuffer, pl); _recursiveTriangulatePolygon(itSeg.inverse(), pointsBelow, tbuffer, pl); } // Clean up segments outside of multishape if (mRemoveOutside) { if (mMultiShapeToTriangulate != null && mMultiShapeToTriangulate.isClosed()) { //for (DelaunayTriangleBuffer::iterator it = tbuffer.begin(); it!=tbuffer.end();) for (int i = tbuffer.Count - 1; i >= 0; i--) { Triangle it = tbuffer.getElement(i).Value; bool isTriangleOut = !mMultiShapeToTriangulate.isPointInside(it.getMidPoint()); if (isTriangleOut) { //it = tbuffer.erase(it); tbuffer.erase(i); } //else // ++it; } } else if (mShapeToTriangulate != null && mShapeToTriangulate.isClosed()) { //for (DelaunayTriangleBuffer::iterator it = tbuffer.begin(); it!=tbuffer.end();) for (int i = tbuffer.Count - 1; i >= 0; i--) { Triangle it = tbuffer.getElement(i).Value; bool isTriangleOut = !mShapeToTriangulate.isPointInside(it.getMidPoint()); if (isTriangleOut) { //it = tbuffer.erase(it); tbuffer.erase(i); } //else // ++it; } } } }
//----------------------------------------------------------------------- public static void _recursiveAddNeighbour(ref TriangleBuffer result, TriangleBuffer source, int triNumber, ref TriLookup lookup, std_set <Segment3D> limits, bool inverted) { if (triNumber == -1) { return; } Utils.log("tri " + (triNumber.ToString())); std_vector <int> ind = source.getIndices(); std_vector <TriangleBuffer.Vertex> vec = source.getVertices(); result.rebaseOffset(); if (inverted) { result.triangle(0, 2, 1); TriangleBuffer.Vertex v = vec[ind[triNumber * 3]]; v.mNormal = -v.mNormal; result.vertex(v); v = vec[ind[triNumber * 3 + 1]]; v.mNormal = -v.mNormal; result.vertex(v); v = vec[ind[triNumber * 3 + 2]]; v.mNormal = -v.mNormal; result.vertex(v); } else { result.triangle(0, 1, 2); result.vertex(vec[ind[triNumber * 3]]); result.vertex(vec[ind[triNumber * 3 + 1]]); result.vertex(vec[ind[triNumber * 3 + 2]]); } //Utils::log("vertex " + StringConverter::toString(vec[ind[triNumber*3]].mPosition)); //Utils::log("vertex " + StringConverter::toString(vec[ind[triNumber*3+1]].mPosition)); //Utils::log("vertex " + StringConverter::toString(vec[ind[triNumber*3+2]].mPosition)); std_pair <Segment3D, List <int> > it = null; int nextTriangle1 = -1; int nextTriangle2 = -1; int nextTriangle3 = -1; int it_find = lookup.find(new Segment3D(vec[ind[triNumber * 3]].mPosition, vec[ind[triNumber * 3 + 1]].mPosition).orderedCopy()); ////if (it != lookup.end() && limits.find(it->first.orderedCopy()) != limits.end()) //// Utils::log("Cross limit1"); //if (it != lookup.end() && limits.find(it->first.orderedCopy()) == limits.end()) { // nextTriangle1 = it->second; // _removeFromTriLookup(nextTriangle1, lookup); //} if (it_find != -1) { it = lookup.get((uint)it_find); if (limits.find(it.first.orderedCopy()) == -1) { nextTriangle1 = it.second[0]; GlobalMembersProceduralBoolean._removeFromTriLookup(nextTriangle1, ref lookup); } } // it = lookup.find(Segment3D(vec[ind[triNumber * 3 + 1]].mPosition, vec[ind[triNumber * 3 + 2]].mPosition).orderedCopy()); it_find = lookup.find(new Segment3D(vec[ind[triNumber * 3 + 1]].mPosition, vec[ind[triNumber * 3 + 2]].mPosition).orderedCopy()); ////if (it != lookup.end() && limits.find(it->first.orderedCopy()) != limits.end()) ////Utils::log("Cross limit2"); //if (it != lookup.end() && limits.find(it->first.orderedCopy()) == limits.end()) { // nextTriangle2 = it->second; // _removeFromTriLookup(nextTriangle2, lookup); //} if (it_find != -1) { it = lookup.get((uint)it_find); if (limits.find(it.first.orderedCopy()) == -1) { nextTriangle2 = it.second[0]; GlobalMembersProceduralBoolean._removeFromTriLookup(nextTriangle2, ref lookup); } } //it = lookup.find(Segment3D(vec[ind[triNumber * 3]].mPosition, vec[ind[triNumber * 3 + 2]].mPosition).orderedCopy()); ////if (it != lookup.end() && limits.find(it->first.orderedCopy()) != limits.end()) //// Utils::log("Cross limit3"); //if (it != lookup.end() && limits.find(it->first.orderedCopy()) == limits.end()) { // nextTriangle3 = it->second; // _removeFromTriLookup(nextTriangle3, lookup); //} it_find = lookup.find(new Segment3D(vec[ind[triNumber * 3]].mPosition, vec[ind[triNumber * 3 + 2]].mPosition).orderedCopy()); if (it_find != -1) { it = lookup.get((uint)it_find); if (limits.find(it.first.orderedCopy()) == -1) { nextTriangle3 = it.second[0]; GlobalMembersProceduralBoolean._removeFromTriLookup(nextTriangle3, ref lookup); } } //Utils::log("add " + StringConverter::toString(nextTriangle1) + " ," + StringConverter::toString(nextTriangle2) + " ,"+StringConverter::toString(nextTriangle3) ); _recursiveAddNeighbour(ref result, source, nextTriangle1, ref lookup, limits, inverted); _recursiveAddNeighbour(ref result, source, nextTriangle2, ref lookup, limits, inverted); _recursiveAddNeighbour(ref result, source, nextTriangle3, ref lookup, limits, inverted); }