/// Tells whether this segments intersects the other segment //----------------------------------------------------------------------- // //ORIGINAL LINE: bool intersects(const Segment2D& STLAllocator<U, AllocPolicy>) const public bool intersects(Segment2D segment2d) { // Early out if segments have nothing in common Vector2 min1 = Utils.min(mA, mB); Vector2 max1 = Utils.max(mA, mB); Vector2 min2 = Utils.min(segment2d.mA, segment2d.mB); Vector2 max2 = Utils.max(segment2d.mA, segment2d.mB); if (max1.x < min2.x || max1.y < min2.y || max2.x < min1.x || max2.y < min2.y) { return(false); } Vector2 t = new Vector2(); return(findIntersect(segment2d, ref t)); }
// * // * Computes the interesction between current segment and another segment // * @param other the other segment // * @param intersection the point of intersection if outputed there if it exists // * @return true if segments intersect, false otherwise // //----------------------------------------------------------------------- // //ORIGINAL LINE: bool findIntersect(const Segment2D& STLAllocator<U, AllocPolicy>, Vector2& intersection) const public bool findIntersect(Segment2D segment2d, ref Vector2 intersection) { Vector2 p1 = mA; Vector2 p2 = mB; Vector2 p3 = segment2d.mA; Vector2 p4 = segment2d.mB; Vector2 d1 = p2 - p1; float a1 = d1.y; float b1 = -d1.x; float g1 = d1.x * p1.y - d1.y * p1.x; Vector2 d3 = p4 - p3; float a2 = d3.y; float b2 = -d3.x; float g2 = d3.x * p3.y - d3.y * p3.x; // if both segments are parallel, early out if (d1.CrossProduct(d3) == 0.0f) { return(false); } //Vector2 GlobalMembersProceduralGeometryHelpers.intersect = new Vector2(); float intersectx = (b2 * g1 - b1 * g2) / (b1 * a2 - b2 * a1); float intersecty = (a2 * g1 - a1 * g2) / (a1 * b2 - a2 * b1); Vector2 intersect = new Vector2(intersectx, intersecty); if ((intersect - p1).DotProduct(intersect - p2) < 0f && (intersect - p3).DotProduct(intersect - p4) < 0f) { intersection = intersect; return(true); } return(false); }
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; } } } }
// //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();*/ }
//----------------------------------------------------------------------- public static void _retriangulate(ref TriangleBuffer newMesh, TriangleBuffer inputMesh, std_vector <Intersect> intersectionList, bool first) { std_vector <TriangleBuffer.Vertex> vec = inputMesh.getVertices(); std_vector <int> ind = inputMesh.getIndices(); // Triangulate // Group intersections by triangle indice std_map <int, std_vector <Segment3D> > meshIntersects = new std_map <int, std_vector <Segment3D> >(); //for (List<Intersect>.Enumerator it = intersectionList.GetEnumerator(); it.MoveNext(); ++it) foreach (var it in intersectionList) { int it2_find; if (first) { it2_find = meshIntersects.find(it.mTri1); } else { it2_find = meshIntersects.find(it.mTri2); } if (it2_find != -1) { std_pair <int, std_vector <Segment3D> > it2 = meshIntersects.get((uint)it2_find); it2.second.push_back(it.mSeg); } else { std_vector <Segment3D> vec2 = new std_vector <Segment3D>(); vec2.push_back(it.mSeg); if (first) { meshIntersects[it.mTri1] = vec2; } else { meshIntersects[it.mTri2] = vec2; } } } // Build a new TriangleBuffer holding non-intersected triangles and retriangulated-intersected triangles //for (List<TriangleBuffer.Vertex>.Enumerator it = vec.GetEnumerator(); it.MoveNext(); ++it) foreach (var it in vec) { newMesh.vertex(it); } //for (int i = 0; i < (int)ind.Count / 3; i++) // if (meshIntersects.find(i) == meshIntersects.end()) // newMesh.triangle(ind[i * 3], ind[i * 3 + 1], ind[i * 3 + 2]); for (int i = 0; i < (int)ind.size() / 3; i++) { if (meshIntersects.find(i) == -1) { newMesh.triangle(ind[i * 3], ind[i * 3 + 1], ind[i * 3 + 2]); } } int numNonIntersected1 = newMesh.getIndices().size(); //for (std.map<int, List<Segment3D> >.Enumerator it = meshIntersects.begin(); it.MoveNext(); ++it) foreach (var it in meshIntersects) { std_vector <Segment3D> segments = it.Value; int triIndex = it.Key; Vector3 v1 = vec[ind[triIndex * 3]].mPosition; Vector3 v2 = vec[ind[triIndex * 3 + 1]].mPosition; Vector3 v3 = vec[ind[triIndex * 3 + 2]].mPosition; Vector3 triNormal = ((v2 - v1).CrossProduct(v3 - v1)).NormalisedCopy; Vector3 xAxis = triNormal.Perpendicular; Vector3 yAxis = triNormal.CrossProduct(xAxis); Vector3 planeOrigin = vec[ind[triIndex * 3]].mPosition; // Project intersection segments onto triangle plane std_vector <Segment2D> segments2 = new std_vector <Segment2D>(); //for (List<Segment3D>.Enumerator it2 = segments.GetEnumerator(); it2.MoveNext(); it2++) // segments2.Add(projectOnAxis(it2.Current, planeOrigin, xAxis, yAxis)); foreach (var it2 in segments) { segments2.push_back(projectOnAxis(it2, planeOrigin, xAxis, yAxis)); } //for (List<Segment2D>.Enumerator it2 = segments2.GetEnumerator(); it2.MoveNext();) int it2_c = segments2.Count; for (int j = it2_c - 1; j >= 0; j--) { Segment2D it2 = segments2[j]; if ((it2.mA - it2.mB).SquaredLength < 1e-5) { //C++ TO C# CONVERTER TODO TASK: There is no direct equivalent to the STL vector 'erase' method in C#: //it2 = segments2.erase(it2); segments2.RemoveAt(j); } //else } // Triangulate Triangulator t = new Triangulator(); //Triangle2D[[]] tri = new Triangle2D[ind[triIndex * 3]](projectOnAxis(vec.mPosition, planeOrigin, xAxis, yAxis), projectOnAxis(vec[ind[triIndex * 3 + 1]].mPosition, planeOrigin, xAxis, yAxis), projectOnAxis(vec[ind[triIndex * 3 + 2]].mPosition, planeOrigin, xAxis, yAxis)); Triangle2D tri = new Triangle2D(projectOnAxis(vec[ind[triIndex * 3]].mPosition, planeOrigin, xAxis, yAxis), projectOnAxis(vec[ind[triIndex * 3 + 1]].mPosition, planeOrigin, xAxis, yAxis), projectOnAxis(vec[ind[triIndex * 3 + 2]].mPosition, planeOrigin, xAxis, yAxis)); std_vector <Vector2> outPointList = new std_vector <Vector2>();//PointList outPointList; std_vector <int> outIndice = new std_vector <int>(); t.setManualSuperTriangle(tri).setRemoveOutside(false).setSegmentListToTriangulate(ref segments2).triangulate(outIndice, outPointList); // Deproject and add to triangleBuffer newMesh.rebaseOffset(); //for (List<int>.Enumerator it = outIndice.GetEnumerator(); it.MoveNext(); ++it) // newMesh.index(it.Current); foreach (var oindex in outIndice) { newMesh.index(oindex); } float x1 = tri.mPoints[0].x; float y1 = tri.mPoints[0].y; Vector2 uv1 = vec[ind[triIndex * 3]].mUV; float x2 = tri.mPoints[1].x; float y2 = tri.mPoints[1].y; Vector2 uv2 = vec[ind[triIndex * 3 + 1]].mUV; float x3 = tri.mPoints[2].x; float y3 = tri.mPoints[2].y; Vector2 uv3 = vec[ind[triIndex * 3 + 2]].mUV; float DET = x1 * y2 - x2 * y1 + x2 * y3 - x3 * y2 + x3 * y1 - x1 * y3; Vector2 A = ((y2 - y3) * uv1 + (y3 - y1) * uv2 + (y1 - y2) * uv3) / DET; Vector2 B = ((x3 - x2) * uv1 + (x1 - x3) * uv2 + (x2 - x1) * uv3) / DET; Vector2 C = ((x2 * y3 - x3 * y2) * uv1 + (x3 * y1 - x1 * y3) * uv2 + (x1 * y2 - x2 * y1) * uv3) / DET; //for (List<Vector2>.Enumerator it = outPointList.GetEnumerator(); it.MoveNext(); ++it) foreach (var it2 in outPointList) { Vector2 uv = A * it2.x + B * it2.y + C; newMesh.position(deprojectOnAxis(it2, planeOrigin, xAxis, yAxis)); newMesh.normal(triNormal); newMesh.textureCoord(uv); } } }