//----------------------------------------------------------------------- // //ORIGINAL LINE: MultiShape _booleanOperation(const Shape& STLAllocator<U, AllocPolicy>, BooleanOperationType opType) const private MultiShape _booleanOperation(Shape other, BooleanOperationType opType) { if (!mClosed || mPoints.size() < 2) OGRE_EXCEPT("Ogre::Exception::ERR_INVALID_STATE", "Current shapes must be closed and has to contain at least 2 points!", "Procedural::Shape::_booleanOperation(const Procedural::Shape&, Procedural::BooleanOperationType)"); if (!other.mClosed || other.mPoints.size() < 2) OGRE_EXCEPT("Ogre::Exception::ERR_INVALIDPARAMS", "Other shapes must be closed and has to contain at least 2 points!", "Procedural::Shape::_booleanOperation(const Procedural::Shape&, Procedural::BooleanOperationType)"); ; // Compute the intersection between the 2 shapes std_vector<IntersectionInShape> intersections = new std_vector<IntersectionInShape>(); _findAllIntersections(other, ref intersections); // Build the resulting shape if (intersections.empty()) { if (isPointInside(other.getPoint(0))) { // Shape B is completely inside shape A if (opType == BooleanOperationType.BOT_UNION) { MultiShape ms = new MultiShape(); ms.addShape(this); return ms; } else if (opType == BooleanOperationType.BOT_INTERSECTION) { MultiShape ms = new MultiShape(); ms.addShape(other); return ms; } else if (opType == BooleanOperationType.BOT_DIFFERENCE) { MultiShape ms = new MultiShape(); ms.addShape(this); ms.addShape(other); ms.getShape(1).switchSide(); return ms; } } else if (other.isPointInside(getPoint(0))) { // Shape A is completely inside shape B if (opType == BooleanOperationType.BOT_UNION) { MultiShape ms = new MultiShape(); ms.addShape(other); return ms; } else if (opType == BooleanOperationType.BOT_INTERSECTION) { MultiShape ms = new MultiShape(); ms.addShape(this); return ms; } else if (opType == BooleanOperationType.BOT_DIFFERENCE) { MultiShape ms = new MultiShape(); ms.addShape(this); ms.addShape(other); ms.getShape(0).switchSide(); return ms; } } else { if (opType == BooleanOperationType.BOT_UNION) { MultiShape ms = new MultiShape(); ms.addShape(this); ms.addShape(other); return ms; } else if (opType == BooleanOperationType.BOT_INTERSECTION) return new MultiShape(); //empty result else if (opType == BooleanOperationType.BOT_DIFFERENCE) return new MultiShape(); //empty result } } MultiShape outputMultiShape = new MultiShape(); Shape[] inputShapes = new Shape[2]; inputShapes[0] = this; inputShapes[1] = other; while (!intersections.empty()) { Shape outputShape = new Shape(); byte shapeSelector = 0; // 0 : first shape, 1 : second shape Vector2 currentPosition = intersections[0].position;//intersections.GetEnumerator().position; IntersectionInShape firstIntersection = intersections[0];//*intersections.GetEnumerator(); uint currentSegment = firstIntersection.index[shapeSelector]; //C++ TO C# CONVERTER TODO TASK: There is no direct equivalent to the STL vector 'erase' method in C#: //intersections.erase(intersections.GetEnumerator());//ÒƳý intersections.erase(firstIntersection, true); outputShape.addPoint(currentPosition); sbyte isIncreasing = 0; // +1 if increasing, -1 if decreasing, 0 if undefined if (!_findWhereToGo(inputShapes, opType, firstIntersection, ref shapeSelector, ref isIncreasing, ref currentSegment)) { // That intersection is located on a place where the resulting shape won't go => discard continue; } while (true) { // find the closest intersection on the same segment, in the correct direction //List<IntersectionInShape>.Enumerator found_next_intersection = intersections.end(); IntersectionInShape found_next_intersection = intersections[intersections.Count - 1]; int found_next_intersection_pos = -1; float distanceToNextIntersection = float.MaxValue;// std.numeric_limits<Real>.max(); uint nextPoint = currentSegment + (uint)(isIncreasing == 1 ? 1 : 0); bool nextPointIsOnIntersection = false; //for (List<IntersectionInShape>.Enumerator it = intersections.GetEnumerator(); it.MoveNext(); ++it) for (int i = 0; i < intersections.Count; i++) { IntersectionInShape it = intersections[i]; if (currentSegment == it.index[shapeSelector]) { if (((it.position - currentPosition).DotProduct(it.position - inputShapes[shapeSelector].getPoint((int)nextPoint)) < 0f) || (it.onVertex[shapeSelector] && nextPoint == it.index[shapeSelector])) { // found an intersection between the current one and the next segment point float d = (it.position - currentPosition).Length; if (d < distanceToNextIntersection) { // check if we have the nearest intersection found_next_intersection = it; found_next_intersection_pos = i; distanceToNextIntersection = d; } } } if (nextPoint == it.index[shapeSelector] && it.onVertex[shapeSelector]) nextPointIsOnIntersection = true; } // stop condition if (currentSegment == firstIntersection.index[shapeSelector]) { // we found ourselves on the same segment as the first intersection and no other if ((firstIntersection.position - currentPosition).DotProduct(firstIntersection.position - inputShapes[shapeSelector].getPoint((int)nextPoint)) < 0f) { float d = (firstIntersection.position - currentPosition).Length; if (d > 0.0f && d < distanceToNextIntersection) { outputShape.close(); break; } } } // We actually found the next intersection => change direction and add current intersection to the list //if (found_next_intersection.MoveNext()) //if (intersections.Count > 1) { if (found_next_intersection_pos != -1) { //IntersectionInShape currentIntersection = found_next_intersection.Current; IntersectionInShape currentIntersection = found_next_intersection; intersections.erase(found_next_intersection, true); //IntersectionInShape currentIntersection = intersections[intersections.Count - 1]; outputShape.addPoint(currentIntersection.position); bool result = _findWhereToGo(inputShapes, opType, currentIntersection, ref shapeSelector, ref isIncreasing, ref currentSegment); if (result == null) { OGRE_EXCEPT("Ogre::Exception::ERR_INTERNAL_ERROR", "We should not be here!", "Procedural::Shape::_booleanOperation(const Procedural::Shape&, Procedural::BooleanOperationType)"); ; } } else { // no intersection found for the moment => just continue on the current segment if (!nextPointIsOnIntersection) { if (isIncreasing == 1) currentPosition = inputShapes[shapeSelector].getPoint((int)currentSegment + 1); else currentPosition = inputShapes[shapeSelector].getPoint((int)currentSegment); outputShape.addPoint(currentPosition); } currentSegment = (uint)Utils.modulo((int)currentSegment + isIncreasing, inputShapes[shapeSelector].getSegCount()); } } outputMultiShape.addShape(outputShape); } return outputMultiShape; }
//----------------------------------------------------------------------- // //ORIGINAL LINE: void addToTriangleBuffer(TriangleBuffer& buffer) const public override void addToTriangleBuffer(ref TriangleBuffer buffer) { std_vector <TriangleBuffer.Vertex> vec1 = mMesh1.getVertices(); std_vector <int> ind1 = mMesh1.getIndices(); std_vector <TriangleBuffer.Vertex> vec2 = mMesh2.getVertices(); std_vector <int> ind2 = mMesh2.getIndices(); Segment3D intersectionResult = new Segment3D(); std_vector <Intersect> intersectionList = new std_vector <Intersect>(); // Find all intersections between mMesh1 and mMesh2 int idx1 = 0; //for (std::vector<int>::const_iterator it = ind1.begin(); it != ind1.end(); idx1++) for (int i = 0; i < ind1.Count; i += 3, idx1++) { int it = ind1[i]; //Triangle3D t1(vec1[*it++].mPosition, vec1[*it++].mPosition, vec1[*it++].mPosition); Triangle3D t1 = new Triangle3D(vec1[it].mPosition, vec1[it + 1].mPosition, vec1[it + 2].mPosition); int idx2 = 0; //for (std::vector<int>::const_iterator it2 = ind2.begin(); it2 != ind2.end(); idx2++) for (int j = 0; j < ind2.Count; j += 3, idx2++) { int it2 = ind2[j]; //Triangle3D t2(vec2[*it2++].mPosition, vec2[*it2++].mPosition, vec2[*it2++].mPosition); Triangle3D t2 = new Triangle3D(vec2[it2].mPosition, vec2[it2 + 1].mPosition, vec2[it2 + 2].mPosition); if (t1.findIntersect(t2, ref intersectionResult)) { Intersect intersect = new Intersect(intersectionResult, idx1, idx2); intersectionList.push_back(intersect); } } } // Remove all intersection segments too small to be relevant //for (std::vector<Intersect>::iterator it = intersectionList.begin(); it != intersectionList.end();) // if ((it.mSeg.mB - it.mSeg.mA).squaredLength() < 1e-8) // it = intersectionList.erase(it); // else // ++it; for (int i = intersectionList.Count - 1; i >= 0; i--) { Intersect it = intersectionList[i]; if ((it.mSeg.mB - it.mSeg.mA).SquaredLength < 1e-8) { intersectionList.erase((uint)i); } } // Retriangulate TriangleBuffer newMesh1 = new TriangleBuffer(); TriangleBuffer newMesh2 = new TriangleBuffer(); GlobalMembersProceduralBoolean._retriangulate(ref newMesh1, mMesh1, intersectionList, true); GlobalMembersProceduralBoolean._retriangulate(ref newMesh2, mMesh2, intersectionList, false); //buffer.append(newMesh1); //buffer.append(newMesh2); //return; // Trace contours std_vector <Path> contours = new std_vector <Path>(); std_vector <Segment3D> segmentSoup = new std_vector <Segment3D>(); //for (std::vector<Intersect>::iterator it = intersectionList.begin(); it != intersectionList.end(); ++it) foreach (var it in intersectionList) { segmentSoup.push_back(it.mSeg); } new Path().buildFromSegmentSoup(segmentSoup, ref contours); // Build a lookup from segment to triangle TriLookup triLookup1 = new std_multimap <Segment3D, int>(new Seg3Comparator()), triLookup2 = new std_multimap <Segment3D, int>(new Seg3Comparator()); GlobalMembersProceduralBoolean._buildTriLookup(ref triLookup1, newMesh1); GlobalMembersProceduralBoolean._buildTriLookup(ref triLookup2, newMesh2); std_set <Segment3D> limits = new std_set <Segment3D>(new Seg3Comparator()); //for (std::vector<Segment3D>::iterator it = segmentSoup.begin(); it != segmentSoup.end(); ++it) foreach (var it in segmentSoup) { limits.insert(it.orderedCopy()); } // Build resulting mesh //for (std::vector<Path>::iterator it = contours.begin(); it != contours.end(); ++it) foreach (var it in contours) { // Find 2 seed triangles for each contour Segment3D firstSeg = new Segment3D(it.getPoint(0), it.getPoint(1)); //std_pair<TriLookup::iterator, TriLookup::iterator> it2mesh1 = triLookup1.equal_range(firstSeg.orderedCopy()); //std_pair<TriLookup::iterator, TriLookup::iterator> it2mesh2 = triLookup2.equal_range(firstSeg.orderedCopy()); std_pair <std_pair <Segment3D, List <int> >, std_pair <Segment3D, List <int> > > it2mesh1 = triLookup1.equal_range(firstSeg.orderedCopy()); std_pair <std_pair <Segment3D, List <int> >, std_pair <Segment3D, List <int> > > it2mesh2 = triLookup2.equal_range(firstSeg.orderedCopy()); int mesh1seed1 = 0, mesh1seed2 = 0, mesh2seed1 = 0, mesh2seed2 = 0; //if (it2mesh1.first != triLookup1.end() && it2mesh2.first != triLookup2.end()) if (it2mesh1.first != null && it2mesh2.first != null) { // check which of seed1 and seed2 must be included (it can be 0, 1 or both) //mesh1seed1 = it2mesh1.first.second; //mesh1seed2 = (--it2mesh1.second).second; //mesh2seed1 = it2mesh2.first.second; //mesh2seed2 = (--it2mesh2.second).second; mesh1seed1 = it2mesh1.first.second[0]; mesh1seed2 = it2mesh1.first.second[it2mesh1.first.second.Count - 1]; //(--it2mesh1.second).second[0]; mesh2seed1 = it2mesh2.first.second[0]; mesh2seed2 = it2mesh2.first.second[it2mesh2.first.second.Count - 1]; //(--it2mesh2.second).second[0]; if (mesh1seed1 == mesh1seed2) { mesh1seed2 = -1; } if (mesh2seed1 == mesh2seed2) { mesh2seed2 = -1; } Vector3 vMesh1 = new Vector3(0f, 0f, 0f), nMesh1 = new Vector3(0f, 0f, 0f), vMesh2 = new Vector3(0f, 0f, 0f), nMesh2 = new Vector3(0f, 0f, 0f); for (int i = 0; i < 3; i++) { Vector3 pos = newMesh1.getVertices()[newMesh1.getIndices()[mesh1seed1 * 3 + i]].mPosition; if ((pos - firstSeg.mA).SquaredLength > 1e-6 && (pos - firstSeg.mB).SquaredLength > 1e-6) { vMesh1 = pos; nMesh1 = newMesh1.getVertices()[newMesh1.getIndices()[mesh1seed1 * 3 + i]].mNormal; break; } } for (int i = 0; i < 3; i++) { Vector3 pos = newMesh2.getVertices()[newMesh2.getIndices()[mesh2seed1 * 3 + i]].mPosition; if ((pos - firstSeg.mA).SquaredLength > 1e-6 && (pos - firstSeg.mB).SquaredLength > 1e-6) { vMesh2 = pos; nMesh2 = newMesh2.getVertices()[newMesh2.getIndices()[mesh2seed1 * 3 + i]].mNormal; break; } } bool M2S1InsideM1 = (nMesh1.DotProduct(vMesh2 - firstSeg.mA) < 0f); bool M1S1InsideM2 = (nMesh2.DotProduct(vMesh1 - firstSeg.mA) < 0f); GlobalMembersProceduralBoolean._removeFromTriLookup(mesh1seed1, ref triLookup1); GlobalMembersProceduralBoolean._removeFromTriLookup(mesh2seed1, ref triLookup2); GlobalMembersProceduralBoolean._removeFromTriLookup(mesh1seed2, ref triLookup1); GlobalMembersProceduralBoolean._removeFromTriLookup(mesh2seed2, ref triLookup2); // Recursively add all neighbours of these triangles // Stop when a contour is touched switch (mBooleanOperation) { case BooleanOperation.BT_UNION: if (M1S1InsideM2) { GlobalMembersProceduralBoolean._recursiveAddNeighbour(ref buffer, newMesh1, mesh1seed2, ref triLookup1, limits, false); } else { GlobalMembersProceduralBoolean._recursiveAddNeighbour(ref buffer, newMesh1, mesh1seed1, ref triLookup1, limits, false); } if (M2S1InsideM1) { GlobalMembersProceduralBoolean._recursiveAddNeighbour(ref buffer, newMesh2, mesh2seed2, ref triLookup2, limits, false); } else { GlobalMembersProceduralBoolean._recursiveAddNeighbour(ref buffer, newMesh2, mesh2seed1, ref triLookup2, limits, false); } break; case BooleanOperation.BT_INTERSECTION: if (M1S1InsideM2) { GlobalMembersProceduralBoolean._recursiveAddNeighbour(ref buffer, newMesh1, mesh1seed1, ref triLookup1, limits, false); } else { GlobalMembersProceduralBoolean._recursiveAddNeighbour(ref buffer, newMesh1, mesh1seed2, ref triLookup1, limits, false); } if (M2S1InsideM1) { GlobalMembersProceduralBoolean._recursiveAddNeighbour(ref buffer, newMesh2, mesh2seed1, ref triLookup2, limits, false); } else { GlobalMembersProceduralBoolean._recursiveAddNeighbour(ref buffer, newMesh2, mesh2seed2, ref triLookup2, limits, false); } break; case BooleanOperation.BT_DIFFERENCE: if (M1S1InsideM2) { GlobalMembersProceduralBoolean._recursiveAddNeighbour(ref buffer, newMesh1, mesh1seed2, ref triLookup1, limits, false); } else { GlobalMembersProceduralBoolean._recursiveAddNeighbour(ref buffer, newMesh1, mesh1seed1, ref triLookup1, limits, false); } if (M2S1InsideM1) { GlobalMembersProceduralBoolean._recursiveAddNeighbour(ref buffer, newMesh2, mesh2seed1, ref triLookup2, limits, true); } else { GlobalMembersProceduralBoolean._recursiveAddNeighbour(ref buffer, newMesh2, mesh2seed2, ref triLookup2, limits, true); } break; } } } }