//-----------------------------------------------------------------------
        //
        //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;
        }
Esempio n. 2
0
        //-----------------------------------------------------------------------

        //
        //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;
                    }
                }
            }
        }