//-----------------------------------------------------------------------
        //typedef std::vector<PathCoordinate> PathIntersection;
        public static void _extrudeIntersectionImpl(ref TriangleBuffer buffer, std_vector <MultiPath.PathCoordinate> intersection, MultiPath multiPath, Shape shape, Track shapeTextureTrack)
        {
            Vector3    intersectionLocation = multiPath.getPath((int)intersection[0].pathIndex).getPoint((int)intersection[0].pointIndex);
            Quaternion firstOrientation     = Utils._computeQuaternion(multiPath.getPath((int)intersection[0].pathIndex).getDirectionBefore((int)intersection[0].pointIndex));
            Vector3    refX = firstOrientation * Vector3.UNIT_X;
            Vector3    refZ = firstOrientation * Vector3.UNIT_Z;

            std_vector <Vector2> v2s = new std_vector <Vector2>();
            std_vector <MultiPath.PathCoordinate> coords = new std_vector <MultiPath.PathCoordinate>();
            std_vector <float> direction = new std_vector <float>();

            for (int i = 0; i < intersection.size(); ++i)
            {
                Path path       = multiPath.getPath((int)intersection[i].pathIndex);
                int  pointIndex = (int)intersection[i].pointIndex;
                if (pointIndex > 0 || path.isClosed())
                {
                    Vector3 vb  = path.getDirectionBefore(pointIndex);
                    Vector2 vb2 = new Vector2(vb.DotProduct(refX), vb.DotProduct(refZ));
                    v2s.push_back(vb2);
                    coords.push_back(intersection[i]);
                    direction.push_back(1);
                }
                if (pointIndex < path.getSegCount() || path.isClosed())
                {
                    Vector3 va  = -path.getDirectionAfter(pointIndex);
                    Vector2 va2 = new Vector2(va.DotProduct(refX), va.DotProduct(refZ));
                    v2s.push_back(va2);
                    coords.push_back(intersection[i]);
                    direction.push_back(-1);
                }
            }

            std_map <Radian, int> angles = new std_map <Radian, int>();

            for (int i = 1; i < v2s.Count; ++i)
            {
                //angles[Utils.angleTo(v2s[0], v2s[i])] = i;
                angles.insert(Utils.angleTo(v2s[0], v2s[i]), i);
            }
            std_vector <int> orderedIndices = new std_vector <int>();

            orderedIndices.push_back(0);
            //for (std_map<Radian, int>.Enumerator it = angles.begin(); it != angles.end(); ++it)
            foreach (var it in angles)
            {
                orderedIndices.push_back(it.Value);
            }
            for (int i = 0; i < orderedIndices.size(); ++i)
            {
                int    idx         = orderedIndices[i];
                int    idxBefore   = orderedIndices[Utils.modulo(i - 1, orderedIndices.Count)];
                int    idxAfter    = orderedIndices[Utils.modulo(i + 1, orderedIndices.Count)];
                Radian angleBefore = (Utils.angleBetween(v2s[idx], v2s[idxBefore]) - (Radian)Math.PI) / 2;
                Radian angleAfter  = ((Radian)Math.PI - Utils.angleBetween(v2s[idx], v2s[idxAfter])) / 2;

                int  pointIndex = (int)((int)coords[idx].pointIndex - direction[idx]);
                Path path       = multiPath.getPath((int)coords[idx].pathIndex);

                Quaternion qStd      = Utils._computeQuaternion(path.getAvgDirection(pointIndex) * direction[idx]);
                float      lineicPos = 0f;
                float      uTexCoord = path.getLengthAtPoint(pointIndex) / path.getTotalLength();

                // Shape making the joint with "standard extrusion"
                _extrudeShape(ref buffer, shape, path.getPoint(pointIndex), qStd, qStd, 1.0f, 1.0f, 1.0f, shape.getTotalLength(), uTexCoord, true, shapeTextureTrack);

                // Modified shape at the intersection
                Quaternion q = new Quaternion();
                if (direction[idx] > 0f)
                {
                    q = Utils._computeQuaternion(path.getDirectionBefore((int)coords[idx].pointIndex));
                }
                else
                {
                    q = Utils._computeQuaternion(-path.getDirectionAfter((int)coords[idx].pointIndex));
                }
                Quaternion qLeft      = q * new Quaternion(angleBefore, Vector3.UNIT_Y);
                Quaternion qRight     = q * new Quaternion(angleAfter, Vector3.UNIT_Y);
                float      scaleLeft  = 1.0f / Math.Abs(Math.Cos(angleBefore));
                float      scaleRight = 1.0f / Math.Abs(Math.Cos(angleAfter));

                uTexCoord = path.getLengthAtPoint((int)coords[idx].pointIndex) / path.getTotalLength();
                _extrudeShape(ref buffer, shape, path.getPoint((int)coords[idx].pointIndex), qLeft, qRight, 1.0f, scaleLeft, scaleRight, shape.getTotalLength(), uTexCoord, false, shapeTextureTrack);
            }
        }
        //-----------------------------------------------------------------------
        public static void _extrudeBodyImpl(ref TriangleBuffer buffer, Shape shapeToExtrude, Path pathToExtrude, int pathBeginIndex, int pathEndIndex, Track shapeTextureTrack, Track rotationTrack, Track scaleTrack, Track pathTextureTrack)
        {
            if (pathToExtrude == null || shapeToExtrude == null)
            {
                OGRE_EXCEPT("Ogre::Exception::ERR_INVALID_STATE", "Shape and Path must not be null!", "Procedural::Extruder::_extrudeBodyImpl(Procedural::TriangleBuffer&, const Procedural::Shape*)");
            }
            ;

            uint numSegPath  = (uint)(pathEndIndex - pathBeginIndex);
            uint numSegShape = (uint)shapeToExtrude.getSegCount();

            if (numSegPath == 0 || numSegShape == 0)
            {
                OGRE_EXCEPT("Ogre::Exception::ERR_INVALID_STATE", "Shape and path must contain at least two points", "Procedural::Extruder::_extrudeBodyImpl(Procedural::TriangleBuffer&, const Procedural::Shape*)");
            }
            ;

            float totalPathLength  = pathToExtrude.getTotalLength();
            float totalShapeLength = shapeToExtrude.getTotalLength();

            // Merge shape and path with tracks
            float lineicPos = pathToExtrude.getLengthAtPoint(pathBeginIndex);
            Path  path      = pathToExtrude;

            numSegPath  = (uint)(pathEndIndex - pathBeginIndex);
            numSegShape = (uint)shapeToExtrude.getSegCount();

            // Estimate vertex and index count
            buffer.rebaseOffset();
            buffer.estimateIndexCount(numSegShape * numSegPath * 6);
            buffer.estimateVertexCount((numSegShape + 1) * (numSegPath + 1));

            Vector3 oldup = new Vector3();

            for (int i = pathBeginIndex; i <= pathEndIndex; ++i)
            {
                Vector3 v0        = path.getPoint(i);
                Vector3 direction = path.getAvgDirection(i);

                Quaternion q = Utils._computeQuaternion(direction);

                Radian angle = Utils.angleBetween((q * Vector3.UNIT_Y), (oldup));
                if (i > pathBeginIndex && angle > (Radian)Math.HALF_PI / 2.0f)
                {
                    q = Utils._computeQuaternion(direction, oldup);
                }
                oldup = q * Vector3.UNIT_Y;

                float scale = 1.0f;

                if (i > pathBeginIndex)
                {
                    lineicPos += (v0 - path.getPoint(i - 1)).Length;
                }

                // Get the values of angle and scale
                if (rotationTrack != null)
                {
                    float angle_2 = 0f;
                    angle_2 = rotationTrack.getValue(lineicPos, lineicPos / totalPathLength, (uint)i);

                    q = q * new Quaternion((Radian)angle_2, Vector3.UNIT_Z);
                }
                if (scaleTrack != null)
                {
                    scale = scaleTrack.getValue(lineicPos, lineicPos / totalPathLength, (uint)i);
                }
                float uTexCoord = 0f;
                if (pathTextureTrack != null)
                {
                    uTexCoord = pathTextureTrack.getValue(lineicPos, lineicPos / totalPathLength, (uint)i);
                }
                else
                {
                    uTexCoord = lineicPos / totalPathLength;
                }

                _extrudeShape(ref buffer, shapeToExtrude, v0, q, q, scale, 1.0f, 1.0f, totalShapeLength, uTexCoord, i < pathEndIndex, shapeTextureTrack);
            }
        }