示例#1
0
        public Geometry Intersection(Edge edge)
        {
            // If no coplanar, cannot intersect
            if (!edge.IsCoplanarTo(this.Origin, this.Direction))
            {
                return(null);
            }

            // Intersection can be an Edge or null
            if (this.Direction.IsParallelTo(edge.Direction))
            {
                bool containsStart = this.Contains(edge.StartVertex);
                bool containsEnd   = this.Contains(edge.EndVertex);

                if (!containsStart && !containsEnd)
                {
                    return(null);
                }
                else if (containsStart)
                {
                    return(Edge.ByStartVertexEndVertex(edge.StartVertex, this.Origin));
                }
                else
                {
                    return(Edge.ByStartVertexEndVertex(this.Origin, edge.EndVertex));
                }
            }

            // No coincident nor same extremes
            var b   = this.Direction;
            var a   = edge.Direction;
            var c   = Vector.ByTwoVertices(edge.StartVertex, this.Origin);
            var cxb = c.Cross(b);
            var axb = a.Cross(b);
            var dot = cxb.Dot(axb);

            double t = (dot) / Math.Pow(axb.Length, 2);

            if (t < 0 && !t.AlmostEqualTo(0))
            {
                return(null);
            }
            if (t > 1 && !t.AlmostEqualTo(1))
            {
                return(null);
            }

            var intersection = edge.StartVertex.Translate(edge.Direction.Scale(t));

            return(this.Contains(intersection) ? intersection : null);
        }
示例#2
0
        /// <summary>
        /// TODO: To be reviewed
        /// Returns the orientation of vertices p1-p2-p3
        /// 0 => Vertices are colinear
        /// 1 => Counterclock-wise, left turn
        /// -1 => Clock-wise, right turn
        /// </summary>
        /// <param name="p1"></param>
        /// <param name="p2"></param>
        /// <param name="p3"></param>
        /// <param name="plane"></param>
        /// <returns></returns>
        internal static int Orientation(Vertex p1, Vertex p2, Vertex p3, string plane = "xy")
        {
            // See https://www.geeksforgeeks.org/orientation-3-ordered-points/
            // for details of below formula.
            double value = 0;

            switch (plane)
            {
            case "xy":
                value = (p2.X - p1.X) * (p3.Y - p2.Y) - (p2.Y - p1.Y) * (p3.X - p2.X);
                break;

            case "xz":
                value = (p2.X - p1.X) * (p3.Z - p2.Z) - (p2.Z - p1.Z) * (p3.X - p2.X);
                break;

            case "yz":
                value = (p2.Y - p1.Y) * (p3.Z - p2.Z) - (p2.Z - p1.Z) * (p3.Y - p2.Y);
                break;

            default:
                throw new Exception("Plane not defined");
            }
            //Rounding due to floating point error.
            if (value.AlmostEqualTo(0))
            {
                return(0);
            }                             //Points are colinear

            return((value > 0) ? 1 : -1); //Counter clock or clock wise
        }
示例#3
0
        public static List <Vertex> ConvexHull(List <Vertex> vertices)
        {
            var verticesCount = vertices.Count();

            //If less than 3, cannot be created
            if (verticesCount < 3)
            {
                throw new ArgumentOutOfRangeException("vertices", verticesCount, "No ConvexHull can be created with less than 3 vertices");
            }

            // TODO: Check if they are colinear
            //if (Vertex.Colinear(vertices))
            //{
            //    throw new ArgumentException("Vertices are colinear", "vertices");
            //}

            Vertex        minVertex = Vertex.MinimumVertex(vertices);
            List <Vertex> sorted    = Vertex.OrderByRadianAndDistance(vertices, minVertex);

            Stack <Vertex> stack = new Stack <Vertex>();

            // Adding fist vertex to stack.
            stack.Push(minVertex);
            //First vertex on sorted should be the minVertex itself
            // so just skip it.
            for (int i = 1; i < verticesCount; i++)
            {
                int nextIndex  = (i + 1) % verticesCount;
                var vertex     = sorted[i];
                var nextVertex = sorted[nextIndex];

                double vertexAngle     = Vertex.RadAngle(minVertex, vertex);
                double nextVertexAngle = Vertex.RadAngle(minVertex, nextVertex);

                // If the angle is same as next, skip as we'll only use the fartest
                // vertex with same angle.
                if (vertexAngle.AlmostEqualTo(nextVertexAngle))
                {
                    continue;
                }

                // If stack is still less than 3, keep adding.
                if (stack.Count < 3)
                {
                    stack.Push(vertex);
                }
                else
                {
                    // While it is not a left turn, remove top on stack
                    while (Vertex.Orientation(GetNextToTop <Vertex>(stack), stack.Peek(), vertex) != 1)
                    {
                        stack.Pop();
                    }
                    stack.Push(vertex);
                }
            }

            return(stack.Reverse().ToList());
        }
        public override IResultValue Evaluate()
        {
            IResultValue num1 = First.Evaluate();
            IResultValue num2 = Second.Evaluate();

            double d1 = (double)num1.ToDecimal();
            double d2 = (double)num2.ToDecimal();

            return(new ResultBoolean(!d1.AlmostEqualTo(d2)));
        }
示例#5
0
        /// <summary>
        /// Determins if a Vertex lies on the left-hand side of an edge on the XY plane.
        /// 1 => for vertex left of the edge
        /// 0 => for vertex on the edge
        /// -1 => for vertex right of the edege
        /// </summary>
        /// <param name="edge"></param>
        /// <param name="vertex"></param>
        /// <returns>
        ///
        /// </returns>
        public int IsLeftFrom(Edge edge)
        {
            double value = (edge.EndVertex.X - edge.StartVertex.X) * (this.Y - edge.StartVertex.Y) - (edge.EndVertex.Y - edge.StartVertex.Y) * (this.X - edge.StartVertex.X);

            if (value.AlmostEqualTo(0))
            {
                return(0);
            }

            return(value > 0 ? 1 : -1);
        }
示例#6
0
        /// <summary>
        /// TODO: To be reviewed
        /// </summary>
        /// <param name="centre"></param>
        /// <param name="vertex"></param>
        /// <returns></returns>
        public static double RadAngle(Vertex centre, Vertex vertex)
        {
            //Rad angles http://math.rice.edu/~pcmi/sphere/drg_txt.html
            double dx      = vertex.X - centre.X;
            double dy      = vertex.Y - centre.Y;
            bool   onYAxis = dx.AlmostEqualTo(0);
            bool   onXAxis = dy.AlmostEqualTo(0);

            //TODO: Implement Z angle? that would becom UV coordinates.
            //double dz = vertex.point.Z - centre.point.Z;

            if (onYAxis && onXAxis)
            {
                return(0);
            }

            if (onYAxis)    // both Vertices on Y axis
            {
                if (dy < 0) //vertex below X axis
                {
                    return(Math.PI * 3 / 2);
                }
                else//vertex above X Axis
                {
                    return(Math.PI / 2);
                }
            }
            if (onXAxis)    // both Vertices on X Axis
            {
                if (dx < 0) // vertex on the left of Y axis
                {
                    return(Math.PI);
                }
                else//vertex on the right of Y axis
                {
                    return(0);
                }
            }
            if (dx < 0)
            {
                return(Math.PI + Math.Atan(dy / dx));
            }
            if (dy < 0)
            {
                return(2 * Math.PI + Math.Atan(dy / dx));
            }
            return(Math.Atan(dy / dx));
        }
示例#7
0
 public string VolumeToSymbol(double d)
 {
     if (d.AlmostEqualTo(0))
     {
         return("\uE198");
     }
     if (d < 33.333333)
     {
         return("\uE993");
     }
     if (d < 66.66666667)
     {
         return("\uE994");
     }
     return("\uE995");
 }
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            if (!_oldScaleFactor.AlmostEqualTo(ScaleFactor))
            {
                Image = ScaleImage(_originalImage);
            }

            if (!DesignMode && !ShowBorder)
            {
                return;
            }

            var pen       = new Pen(Color.FromArgb(45, 68, 108), 1);
            var rectangle = new Rectangle(0, 0, Size.Width - 1, Size.Height - 1);

            e.Graphics.DrawRectangle(pen, rectangle);
        }
示例#9
0
        /// <summary>
        /// Checks if the given Vertex is contained on the Ray.
        /// </summary>
        /// <param name="vertex"></param>
        /// <returns></returns>
        public bool Contains(Vertex vertex)
        {
            // If the Vector from Ray's origin to the given
            // vertex is parallel to Ray's Direction, return true.
            var vector = Vector.ByTwoVertices(this.Origin, vertex);

            if (!this.Direction.IsParallelTo(vector))
            {
                return(false);
            }

            // Need to check if point falls on the visible path of Ray.
            // Vertex = Origin + t * Direction; t = (V-O)/D
            // If t < 0, it doesn't

            double t = Double.PositiveInfinity;

            if (this.Direction.X != 0)
            {
                t = (vertex.X - this.Origin.X) / this.Direction.X;
            }
            else if (this.Direction.Y != 0)
            {
                t = (vertex.Y - this.Origin.Y) / this.Direction.Y;
            }
            else if (this.Direction.Z != 0)
            {
                t = (vertex.Z - this.Origin.Z) / this.Direction.Z;
            }
            else
            {
                throw new Exception("Something when wrong, contact Author");
            }

            return(t > 0 && !t.AlmostEqualTo(0));
        }
示例#10
0
        /// <summary>
        /// Checks if the polygon is convex
        /// </summary>
        /// <returns></returns>
        public bool IsConvex()
        {
            //https://math.stackexchange.com/questions/1743995/determine-whether-a-polygon-is-convex-based-on-its-vertices/1745427#1745427

            double wSign = 0; // First  non-zero orientation

            int xSign      = 0;
            int xFirstSign = 0;
            int xFlips     = 0;

            int ySign      = 0;
            int yFirstSign = 0;
            int yFlips     = 0;

            int    vertexCount = this.Vertices.Count();
            Vertex current     = this.Vertices[vertexCount - 2];
            Vertex next        = this.Vertices[vertexCount - 1];

            for (int i = 0; i < vertexCount; i++)
            {
                var prev = current;
                current = next;
                next    = this.Vertices[i];

                // Previous edge vector
                double prevX = current.X - prev.X;
                double prevY = current.Y - prev.Y;

                // Next edge vector
                double nextX = next.X - current.X;
                double nextY = next.Y - current.Y;

                if (!nextX.AlmostEqualTo(0))
                {
                    if (nextX > 0)
                    {
                        if (xSign == 0)
                        {
                            xFirstSign = 1;
                        }
                        else if (xSign < 0)
                        {
                            xFlips += 1;
                        }

                        xSign = 1;
                    }
                    else // nextX < 0
                    {
                        if (xSign == 0)
                        {
                            xFirstSign = -1;
                        }
                        else if (xSign > 0)
                        {
                            xFlips += 1;
                        }
                        xSign = -1;
                    }
                }

                if (xFlips > 2)
                {
                    return(false);
                }

                if (!nextY.AlmostEqualTo(0))
                {
                    if (nextY > 0)
                    {
                        if (ySign == 0)
                        {
                            yFirstSign = 1;
                        }
                        else if (ySign < 0)
                        {
                            yFlips += 1;
                        }

                        ySign = 1;
                    }
                    else // nextY < 0
                    {
                        if (ySign == 0)
                        {
                            yFirstSign = -1;
                        }
                        else if (ySign > 0)
                        {
                            yFlips += 1;
                        }

                        ySign = -1;
                    }
                }

                if (yFlips > 2)
                {
                    return(false);
                }

                // Find out the orientation of this pair of edges
                // and ensure ir does not differ from previous ones

                double w           = prevX * nextY - nextX * prevY;
                bool   wIsZero     = w.AlmostEqualTo(0);
                bool   wSignIsZero = wSign.AlmostEqualTo(0);

                if (wSignIsZero && !wIsZero)
                {
                    wSign = w;
                }
                else if (!wSignIsZero && !wIsZero)
                {
                    if ((wSign > 0 && w < 0) || (wSign > 0 && w < 0))
                    {
                        return(false);
                    }
                }
            }

            // Final/wraparound sign flips
            if (xSign != 0 && xFirstSign != 0 && xSign != xFirstSign)
            {
                xFlips += 1;
            }

            if (ySign != 0 && yFirstSign != 0 && ySign != yFirstSign)
            {
                yFlips += 1;
            }

            // Concave polygons have two sign flips along each axis
            if (xFlips != 2 || yFlips != 2)
            {
                return(false);
            }

            // This is a convex polygon
            return(true);
        }
 public void AlmostEqualTo(double num1, double num2, double tolerance, bool expected)
 {
     Assert.Equal(expected, num1.AlmostEqualTo(num2, tolerance));
 }
示例#12
0
文件: PPMath.cs 项目: mkecman/GameOne
 public static bool IsLowerEqualThan(this double value1, double value2, double precision = 0.000001)
 {
     return(value1 < value2 || value1.AlmostEqualTo(value2, precision));
 }
示例#13
0
        public GeometryBase Intersection(Edge other)
        {
            // http://mathworld.wolfram.com/Line-LineIntersection.html
            if (!this.BoundingBox.Intersects(other.BoundingBox))
            {
                return(null);
            }
            if (!this.IsCoplanarTo(other))
            {
                return(null);
            }
            if (this.Equals(other))
            {
                return(this);
            }                                        // Issues if same polygon id???

            var a = this.Direction;
            var b = other.Direction;

            if (a.IsParallelTo(b))
            {
                // Fully contains the test edge
                if (other.StartVertex.OnEdge(this) && other.EndVertex.OnEdge(this))
                {
                    return(other);
                }
                // Is fully contained by test edge
                else if (this.StartVertex.OnEdge(other) && this.EndVertex.OnEdge(other))
                {
                    return(this);
                }
                // Not fully inclusive but overlapping
                else if (this.StartVertex.OnEdge(other) || this.EndVertex.OnEdge(other))
                {
                    Vertex[] vertices = new Vertex[4]
                    {
                        this.StartVertex,
                        this.EndVertex,
                        other.StartVertex,
                        other.EndVertex
                    };
                    var sorted = vertices.OrderBy(v => v.Y).ThenBy(v => v.X).ThenBy(v => v.Z).ToList();
                    return(Edge.ByStartVertexEndVertex(sorted[1], sorted[2]));
                }
                // Not intersecting
                else
                {
                    return(null);
                }
            }

            // No parallels but intersecting on one of the extreme vertices
            if (other.Contains(this.StartVertex))
            {
                return(this.StartVertex);
            }
            else if (other.Contains(this.EndVertex))
            {
                return(this.EndVertex);
            }


            // No coincident nor same extremes
            var c   = Vector.ByTwoVertices(this.StartVertex, other.StartVertex);
            var cxb = c.Cross(b);
            var axb = a.Cross(b);
            var dot = cxb.Dot(axb);

            // If dot == 0 it means that other edge contains at least a vertex from this edge
            // and they are parallel or perpendicular. Cannot be parallel as that was tested before.
            // It might also mean they don't intersect but the would if extending the projections
            double s = (dot) / Math.Pow(axb.Length, 2);

            if (s.AlmostEqualTo(0))
            {
                if (this.StartVertex.OnEdge(other))
                {
                    return(this.StartVertex);
                }
                else if (this.EndVertex.OnEdge(other))
                {
                    return(this.EndVertex);
                }
                else if (other.StartVertex.OnEdge(this))
                {
                    return(other.StartVertex);
                }
                else if (other.EndVertex.OnEdge(this))
                {
                    return(other.EndVertex);
                }
                else
                {
                    return(null);
                }
            }



            // s > 1, means that "intersection" vertex is not on either edge
            // s == NaN means they are parallels so never intersect
            if (s < 0 || s > 1 || Double.IsNaN(s))
            {
                return(null);
            }

            Vertex intersection = this.StartVertex.Translate(a.Scale(s));

            if (intersection.Equals(other.StartVertex))
            {
                return(other.StartVertex);
            }
            if (intersection.Equals(other.EndVertex))
            {
                return(other.EndVertex);
            }
            if (!intersection.OnEdge(other))
            {
                return(null);
            }

            return(intersection);
        }