Пример #1
0
        public void SetPoints(List <Vector3m> points, List <List <Vector3m> > holes = null, Vector3m normal = null)
        {
            if (points == null || points.Count < 3)
            {
                throw new ArgumentException("No list or an empty list passed");
            }
            if (normal == null)
            {
                CalcNormal(points);
            }
            else
            {
                Normal = normal;
            }
            _mainPointList = new Polygon();
            LinkAndAddToList(_mainPointList, points);

            if (holes != null)
            {
                _holes = new List <Polygon>();
                for (int i = 0; i < holes.Count; i++)
                {
                    Polygon p = new Polygon();
                    LinkAndAddToList(p, holes[i]);
                    _holes.Add(p);
                }
            }
            Result = new List <Vector3m>();
        }
Пример #2
0
        public static Vector3m PlaneNormal(Vector3m v0, Vector3m v1, Vector3m v2)
        {
            Vector3m a = v1 - v0;
            Vector3m b = v2 - v0;

            return(a.Cross(b));
        }
Пример #3
0
        private ConnectionEdge FindLargest(Polygon testHole)
        {
            Rational       maximum = 0;
            ConnectionEdge maxEdge = null;
            Vector3m       v0      = testHole.Start.Origin;
            Vector3m       v1      = testHole.Start.Next.Origin;

            foreach (var connectionEdge in testHole.GetPolygonCirculator())
            {
                // we take the first two points as a reference line

                if (Misc.GetOrientation(v0, v1, connectionEdge.Origin, Normal) < 0)
                {
                    var r = Misc.PointLineDistance(v0, v1, connectionEdge.Origin);
                    if (r > maximum)
                    {
                        maximum = r;
                        maxEdge = connectionEdge;
                    }
                }
            }
            if (maxEdge == null)
            {
                return(testHole.Start);
            }
            return(maxEdge);
        }
Пример #4
0
 public Vector3m Cross(Vector3m a)
 {
     return(new Vector3m(
                this.Y * a.Z - this.Z * a.Y,
                this.Z * a.X - this.X * a.Z,
                this.X * a.Y - this.Y * a.X
                ));
 }
Пример #5
0
        public static bool PointInOrOnTriangle(Vector3m prevPoint, Vector3m curPoint, Vector3m nextPoint, Vector3m nonConvexPoint, Vector3m normal)
        {
            var res0 = Misc.GetOrientation(prevPoint, nonConvexPoint, curPoint, normal);
            var res1 = Misc.GetOrientation(curPoint, nonConvexPoint, nextPoint, normal);
            var res2 = Misc.GetOrientation(nextPoint, nonConvexPoint, prevPoint, normal);

            return(res0 != 1 && res1 != 1 && res2 != 1);
        }
Пример #6
0
        // calculating normal using Newell's method
        private void CalcNormal(List <Vector3m> points)
        {
            Vector3m normal = Vector3m.Zero();

            for (var i = 0; i < points.Count; i++)
            {
                var j = (i + 1) % (points.Count);
                normal.X += (points[i].Y - points[j].Y) * (points[i].Z + points[j].Z);
                normal.Y += (points[i].Z - points[j].Z) * (points[i].X + points[j].X);
                normal.Z += (points[i].X - points[j].X) * (points[i].Y + points[j].Y);
            }
            Normal = normal;
        }
Пример #7
0
 public bool Contains(Vector3m vector2M, out Vector3m res)
 {
     foreach (var connectionEdge in GetPolygonCirculator())
     {
         if (connectionEdge.Origin.Equals(vector2M))
         {
             res = connectionEdge.Origin;
             return(true);
         }
     }
     res = null;
     return(false);
 }
Пример #8
0
        public static int GetOrientation(Vector3m v0, Vector3m v1, Vector3m v2, Vector3m normal)
        {
            var res = (v0 - v1).Cross(v2 - v1);

            if (res.LengthSquared() == 0)
            {
                return(0);
            }
            if (res.X.Sign != normal.X.Sign || res.Y.Sign != normal.Y.Sign || res.Z.Sign != normal.Z.Sign)
            {
                return(1);
            }
            return(-1);
        }
Пример #9
0
        public static int GetOrientation(Vector3m v0, Vector3m v1, Vector3m v2, Vector3m normal)
        {
            var res = (v0 - v1).Cross(v2 - v1);

            if (res.LengthSquared() == 0)
            {
                return(0);
            }
            if (Math.Sign(res.X) != Math.Sign(normal.X) || Math.Sign(res.Y) != Math.Sign(normal.Y) || Math.Sign(res.Z) != Math.Sign(normal.Z))
            {
                return(1);
            }
            return(-1);
        }
Пример #10
0
 private bool IsPointInTriangle(Vector3m prevPoint, Vector3m curPoint, Vector3m nextPoint, List <ConnectionEdge> nonConvexPoints)
 {
     foreach (var nonConvexPoint in nonConvexPoints)
     {
         if (nonConvexPoint.Origin == prevPoint || nonConvexPoint.Origin == curPoint || nonConvexPoint.Origin == nextPoint)
         {
             continue;
         }
         if (Misc.PointInOrOnTriangle(prevPoint, curPoint, nextPoint, nonConvexPoint.Origin, Normal))
         {
             return(true);
         }
     }
     return(false);
 }
Пример #11
0
        public bool RaySegmentIntersection(out Vector3m intersection, out Rational distanceSquared, Vector3m linePoint1, Vector3m lineVec1, Vector3m linePoint3, Vector3m linePoint4, Vector3m direction)
        {
            var      lineVec2      = linePoint4 - linePoint3;
            Vector3m lineVec3      = linePoint3 - linePoint1;
            Vector3m crossVec1and2 = lineVec1.Cross(lineVec2);
            Vector3m crossVec3and2 = lineVec3.Cross(lineVec2);

            var res = Misc.PointLineDistance(linePoint3, linePoint4, linePoint1);

            if (res == 0) // line and ray are collinear
            {
                var p    = linePoint1 + lineVec1;
                var res2 = Misc.PointLineDistance(linePoint3, linePoint4, p);
                if (res2 == 0)
                {
                    var s = linePoint3 - linePoint1;
                    if (s.X == direction.X && s.Y == direction.Y && s.Z == direction.Z)
                    {
                        intersection    = linePoint3;
                        distanceSquared = s.LengthSquared();
                        return(true);
                    }
                }
            }
            //is coplanar, and not parallel
            if (/*planarFactor == 0.0f && */ crossVec1and2.LengthSquared() > 0)
            {
                var s = crossVec3and2.Dot(crossVec1and2) / crossVec1and2.LengthSquared();
                if (s >= 0)
                {
                    intersection    = linePoint1 + (lineVec1 * s);
                    distanceSquared = (lineVec1 * s).LengthSquared();
                    if ((intersection - linePoint3).LengthSquared() + (intersection - linePoint4).LengthSquared() <=
                        lineVec2.LengthSquared())
                    {
                        return(true);
                    }
                }
            }
            intersection    = Vector3m.Zero();
            distanceSquared = 0;
            return(false);
        }
Пример #12
0
        private ConnectionEdge FindMinimumAngle(List <ConnectionEdge> candidates, Vector3m M, Vector3m direction)
        {
            Rational       angle  = -double.MaxValue;
            ConnectionEdge result = null;

            foreach (var R in candidates)
            {
                var a     = direction;
                var b     = R.Origin - M;
                var num   = a.Dot(b) * a.Dot(b);
                var denom = b.Dot(b);
                var res   = num / denom;
                if (res > angle)
                {
                    result = R;
                    angle  = res;
                }
            }
            return(result);
        }
Пример #13
0
        public List <short> TriangulateAndReturnIndices()
        {
            EarClipping EarClipper = new EarClipping();

            EarClipper.SetPoints(Vertices, null, Normal);
            EarClipper.Triangulate();
            var Result = EarClipper.Result;

            List <short> Indices = new List <short>();

            for (short Index = 0; Index < Result.Count; Index++)
            {
                Vector3m Vertex = Result[Index];
                for (short IndexPoint = 0; IndexPoint < Vertices.Count; IndexPoint++)
                {
                    if (Vertex.Equals(Vertices[IndexPoint]))
                    {
                        Indices.Add(IndexPoint);
                    }
                }
            }
            return(Indices);
        }
Пример #14
0
        // Is testPoint between a and b in ccw order?
        // > 0 if strictly yes
        // < 0 if strictly no
        // = 0 if testPoint lies either on a or on b
        public static int IsBetween(Vector3m Origin, Vector3m a, Vector3m b, Vector3m testPoint, Vector3m normal)
        {
            var psca = GetOrientation(Origin, a, testPoint, normal);
            var pscb = GetOrientation(Origin, b, testPoint, normal);

            // where does b in relation to a lie? Left, right or collinear?
            var psb = GetOrientation(Origin, a, b, normal);

            if (psb > 0) // left
            {
                // if left then testPoint lies between a and b iff testPoint left of a AND testPoint right of b
                if (psca > 0 && pscb < 0)
                {
                    return(1);
                }
                if (psca == 0)
                {
                    var t  = a - Origin;
                    var t2 = testPoint - Origin;
                    if (Math.Sign(t.X) != Math.Sign(t2.X) || Math.Sign(t.Y) != Math.Sign(t2.Y))
                    {
                        return(-1);
                    }
                    return(0);
                }
                else if (pscb == 0)
                {
                    var t  = b - Origin;
                    var t2 = testPoint - Origin;
                    if (Math.Sign(t.X) != Math.Sign(t2.X) || Math.Sign(t.Y) != Math.Sign(t2.Y))
                    {
                        return(-1);
                    }
                    return(0);
                }
            }
            else if (psb < 0) // right
            {
                // if right then testPoint lies between a and b iff testPoint left of a OR testPoint right of b
                if (psca > 0 || pscb < 0)
                {
                    return(1);
                }
                if (psca == 0)
                {
                    var t  = a - Origin;
                    var t2 = testPoint - Origin;
                    if (Math.Sign(t.X) != Math.Sign(t2.X) || Math.Sign(t.Y) != Math.Sign(t2.Y))
                    {
                        return(1);
                    }
                    return(0);
                }
                else if (pscb == 0)
                {
                    var t  = b - Origin;
                    var t2 = testPoint - Origin;
                    if (Math.Sign(t.X) != Math.Sign(t2.X) || Math.Sign(t.Y) != Math.Sign(t2.Y))
                    {
                        return(1);
                    }
                    return(0);
                }
            }
            else if (psb == 0)
            {
                if (psca > 0)
                {
                    return(1);
                }
                else if (psca < 0)
                {
                    return(-1);
                }
                else
                {
                    return(0);
                }
            }
            return(-1);
        }
Пример #15
0
    /**
     * 建立自訂義的Mesh
     */
    public void CreateEarClippingMesh(List <Vector3> posList, float height, MeshFilter meshFilter)
    {
        Mesh mesh = new Mesh();

        meshFilter.mesh = mesh;
        mesh.Clear();

        //EarClipping
        EarClipperLib.EarClipping     earClipping = new EarClipperLib.EarClipping();
        List <EarClipperLib.Vector3m> points      = new List <EarClipperLib.Vector3m>();

        for (int i = 0; i < posList.Count; i++)
        {
            EarClipperLib.Vector3m point = new EarClipperLib.Vector3m(posList[i].x, posList[i].y, posList[i].z);
            points.Add(point);
        }
        earClipping.SetPoints(points);
        earClipping.Triangulate();
        var res = earClipping.Result;

        res.Reverse();
        int vert = 0;

        #region Vertices
        Vector3[] vertices = new Vector3[res.Count * 2 + 6 * posList.Count];
        //Top cap
        for (int i = 0; i < res.Count; i += 3)
        {
            vertices[vert++] = new Vector3(res[i].X, res[i].Y, res[i].Z);
            vertices[vert++] = new Vector3(res[i + 1].X, res[i + 1].Y, res[i + 1].Z);
            vertices[vert++] = new Vector3(res[i + 2].X, res[i + 2].Y, res[i + 2].Z);
        }
        //Buttom cap
        for (int i = 0; i < res.Count; i += 3)
        {
            vertices[vert++] = new Vector3(res[i + 2].X, res[i + 2].Y, res[i + 2].Z) - Vector3.up * height;
            vertices[vert++] = new Vector3(res[i + 1].X, res[i + 1].Y, res[i + 1].Z) - Vector3.up * height;
            vertices[vert++] = new Vector3(res[i].X, res[i].Y, res[i].Z) - Vector3.up * height;
        }        // Sides
        for (int i = 0; i < posList.Count; i++)
        {
            vertices[vert++] = posList[i];
            vertices[vert++] = posList[(i + 1) % posList.Count];
            vertices[vert++] = posList[i] - Vector3.up * height;


            vertices[vert++] = posList[i] - Vector3.up * height;
            vertices[vert++] = posList[(i + 1) % posList.Count];
            vertices[vert++] = posList[(i + 1) % posList.Count] - Vector3.up * height;
        }
        #endregion
        #region Normales
        Vector3[] normales = new Vector3[vertices.Length];
        vert = 0;
        for (int i = 0; i < normales.Length; i += 3)
        {
            Vector3 nor = Vector3.Cross(vertices[i + 1] - vertices[i], vertices[i + 2] - vertices[i]).normalized;
            for (int j = 0; j < 3; j++)
            {
                normales[vert++] = nor;
            }
        }
        #endregion
        #region Triangles
        int[] triangles = new int[vertices.Length];
        vert = 0;
        for (int i = 0; i < triangles.Length; i++)
        {
            triangles[vert++] = i;
        }
        #endregion
        mesh.vertices  = vertices;
        mesh.normals   = normales;
        mesh.triangles = triangles;

        mesh.RecalculateBounds();
    }
Пример #16
0
        private Candidate FindPointI(ConnectionEdge M, List <Polygon> polygons, int holeIndex, Vector3m direction)
        {
            Candidate candidate = new Candidate();

            for (int i = 0; i < polygons.Count; i++)
            {
                if (i == holeIndex) // Don't test the hole with itself
                {
                    continue;
                }
                foreach (var connectionEdge in polygons[i].GetPolygonCirculator())
                {
                    Rational rayDistanceSquared;
                    Vector3m intersectionPoint;

                    if (RaySegmentIntersection(out intersectionPoint, out rayDistanceSquared, M.Origin, direction, connectionEdge.Origin,
                                               connectionEdge.Next.Origin, direction))
                    {
                        if (rayDistanceSquared == candidate.currentDistance)  // if this is an M/I edge, then both edge and his twin have the same distance; we take the edge where the point is on the left side
                        {
                            if (Misc.GetOrientation(connectionEdge.Origin, connectionEdge.Next.Origin, M.Origin, Normal) == 1)
                            {
                                candidate.currentDistance = rayDistanceSquared;
                                candidate.Origin          = connectionEdge;
                                candidate.PolyIndex       = i;
                                candidate.I = intersectionPoint;
                            }
                        }
                        else if (rayDistanceSquared < candidate.currentDistance)
                        {
                            candidate.currentDistance = rayDistanceSquared;
                            candidate.Origin          = connectionEdge;
                            candidate.PolyIndex       = i;
                            candidate.I = intersectionPoint;
                        }
                    }
                }
            }
            return(candidate);
        }
Пример #17
0
        private ConnectionEdge FindVisiblePoint(Candidate I, List <Polygon> polygons, ConnectionEdge M, Vector3m direction)
        {
            ConnectionEdge P = null;

            if (I.Origin.Origin.X > I.Origin.Next.Origin.X)
            {
                P = I.Origin;
            }
            else
            {
                P = I.Origin.Next;
            }

            List <ConnectionEdge> nonConvexPoints = FindNonConvexPoints(polygons[I.PolyIndex]);


            nonConvexPoints.Remove(P);

            var m = M.Origin;
            var i = I.I;
            var p = P.Origin;
            List <ConnectionEdge> candidates = new List <ConnectionEdge>();

            // invert i and p if triangle is oriented CW
            if (Misc.GetOrientation(m, i, p, Normal) == -1)
            {
                var tmp = i;
                i = p;
                p = tmp;
            }

            foreach (var nonConvexPoint in nonConvexPoints)
            {
                if (Misc.PointInOrOnTriangle(m, i, p, nonConvexPoint.Origin, Normal))
                {
                    candidates.Add(nonConvexPoint);
                }
            }
            if (candidates.Count == 0)
            {
                return(P);
            }
            return(FindMinimumAngle(candidates, m, direction));
        }
Пример #18
0
 public Vector3m Plus(Vector3m a)
 {
     return(new Vector3m(this.X + a.X, this.Y + a.Y, this.Z + a.Z));
 }
Пример #19
0
        public void Triangulate()
        {
            if (Normal.Equals(Vector3m.Zero()))
            {
                throw new Exception("The input is not a valid polygon");
            }
            if (_holes != null && _holes.Count > 0)
            {
                ProcessHoles();
            }

            List <ConnectionEdge> nonConvexPoints = FindNonConvexPoints(_mainPointList);

            if (nonConvexPoints.Count == _mainPointList.PointCount)
            {
                throw new ArgumentException("The triangle input is not valid");
            }

            while (_mainPointList.PointCount > 2)
            {
                bool guard = false;
                foreach (var cur in _mainPointList.GetPolygonCirculator())
                {
                    if (!IsConvex(cur))
                    {
                        continue;
                    }

                    if (!IsPointInTriangle(cur.Prev.Origin, cur.Origin, cur.Next.Origin, nonConvexPoints))
                    {
                        // cut off ear
                        guard = true;
                        Result.Add(cur.Prev.Origin);
                        Result.Add(cur.Origin);
                        Result.Add(cur.Next.Origin);

                        // Check if prev and next are still nonconvex. If not, then remove from non convex list
                        if (IsConvex(cur.Prev))
                        {
                            int index = nonConvexPoints.FindIndex(x => x == cur.Prev);
                            if (index >= 0)
                            {
                                nonConvexPoints.RemoveAt(index);
                            }
                        }
                        if (IsConvex(cur.Next))
                        {
                            int index = nonConvexPoints.FindIndex(x => x == cur.Next);
                            if (index >= 0)
                            {
                                nonConvexPoints.RemoveAt(index);
                            }
                        }
                        _mainPointList.Remove(cur);
                        break;
                    }
                }

                if (PointsOnLine(_mainPointList))
                {
                    break;
                }
                if (!guard)
                {
                    throw new Exception("No progression. The input must be wrong");
                }
            }
        }
Пример #20
0
 public Vector3m(Vector3m v)
 {
     X = v.X;
     Y = v.Y;
     Z = v.Z;
 }
Пример #21
0
 public Vector3m Lerp(Vector3m a, float t)
 {
     return(this.Plus(a.Minus(this).Times(t)));
 }
Пример #22
0
 public ConnectionEdge(Vector3m p0, Polygon parentPolygon)
 {
     Origin  = p0;
     Polygon = parentPolygon;
     AddIncidentEdge(this);
 }
Пример #23
0
 public Vector3m Minus(Vector3m a)
 {
     return(new Vector3m(this.X - a.X, this.Y - a.Y, this.Z - a.Z));
 }
Пример #24
0
 public Vector3m Lerp(Vector3m a, Rational t)
 {
     return(this.Plus(a.Minus(this).Times(t)));
 }
Пример #25
0
 public Rational Dot(Vector3m a)
 {
     return(this.X * a.X + this.Y * a.Y + this.Z * a.Z);
 }
Пример #26
0
 public void SetNormal(double X, double Y, double Z)
 {
     Normal = new Vector3m(X, Y, Z);
 }
Пример #27
0
        public bool SameDirection(Vector3m he)
        {
            var res = this.Cross(he);

            return(res.X == 0 && res.Y == 0 && res.Z == 0);
        }
Пример #28
0
 public static float PointLineDistance(Vector3m p1, Vector3m p2, Vector3m p3)
 {
     return((p2 - p1).Cross(p3 - p1).LengthSquared());
 }
Пример #29
0
 public float Dot(Vector3m a)
 {
     return(this.X * a.X + this.Y * a.Y + this.Z * a.Z);
 }