Beispiel #1
0
        /// <summary>Returns resulting point if this point is rotated around <paramref name='reference'/> by <paramref name='degrees'/>.</summary>
        /// <param name='reference'>The center of the rotation.</param>
        /// <param name='degrees'>Positive values means a counter-clockwise rotation.</param>
        public WPoint Rotate(WPoint reference, double degrees)
        {
            WPoint a = this - reference;
            WPoint b = a.RotateAroundOrigin(degrees);

            return(b + reference);
        }
Beispiel #2
0
 /// <summary></summary>
 public WRectangle(double width, double height, WPoint corner, double rotation)
 {
     Width    = width;
     Height   = height;
     Corner   = corner;
     Rotation = rotation;
 }
        /// <summary>Finds the intersection points between the edge of this circle and circle <paramref name='b'/>.</summary>
        /// <returns>Null (no intersection), an array of length 1, or an array of length 2.</returns>
        public WPoint[] GetIntersectionPoints(WCircle b)
        {
            //following the method in math/intersectionCircleCircle.png

            WCircle a = this;
            double  d = a.Center.Distance(b.Center);            //distance between centers

            if (d > a.Radius + b.Radius)
            {
                return(null);                //circles too far apart to intersect
            }
            if (a.ContainsOrIsContained(b))
            {
                return(null);                //one circle is wholly inside the other
            }

            //the radical line is the line between the two intersecting points of the circles
            //Point c is the center of the radical line, which is also on the line between the centers
            double dA = (Math.Pow(a.Radius, 2) - Math.Pow(b.Radius, 2) + Math.Pow(d, 2)) / (2 * d);             //distance from centerA to pointC

            if (dA == a.Radius)
            {
                return(new WPoint[] { Geometry.PointOnLine(a.Center, b.Center, a.Radius) });                //circles intersect at single point
            }
            WPoint c = a.Center + dA * (b.Center - a.Center) / d;

            //h is the distance from pointC to either intersection point (the hypotenus of triangle centerA-C-intersection)
            double h = Math.Sqrt(Math.Pow(a.Radius, 2) - Math.Pow(dA, 2));

            return(new WPoint[] {
                new WPoint(c.X + (h * (b.Y - a.Y) / d), c.Y - h * (b.X - a.X) / d),
                new WPoint(c.X - (h * (b.Y - a.Y) / d), c.Y + h * (b.X - a.X) / d)
            });
        }
 /// <summary></summary>
 public Intersection(WPoint point)
 {
     Type        = IntersectionType.Point;
     this.points = new List <WPoint>()
     {
         point
     };
 }
Beispiel #5
0
 /// <exception cref='ArgumentException'>Points A and B cannot be the same.</exception>
 public WLine(WPoint a, WPoint b, bool isDirected)
 {
     if (a == b)
     {
         throw new ArgumentException("Points A and B cannot be the same.");
     }
     A          = a;
     B          = b;
     IsDirected = isDirected;
 }
        /// <returns>Null (no intercepts), or array of length 1 or 2.</returns>
        public WPoint[] GetIntersectionPoints(WLine line)
        {
            //line does not intersect if perpendicular line from circle-center to line is longer than circle-radius
            WPoint perpendicularToCenter = line.GetPerpendicularIntersect(Center);

            if (perpendicularToCenter.Distance(Center) > Radius)
            {
                return(null);
            }

            //equation of circle with radius r and center (h, k)
            //is (x - h)^2 + (y - k)^2 = r^2

            //line: y = mx + b
            //circle: (x - h)^2 + (y - k)^2 = r^2
            //substitute y: (x - h)^2 + (mx + b - k)^2 = r^2
            //expand: x^2 - 2hx + h^2 + m^2x^2 + 2(b - k)mx + (b - k)^2 - r^2 = 0
            //group: (1 + m^2)x^2 + (-2h + 2(b - k)m)x + (h^2 + (b - k)^2 - r^2) = 0
            //quadratic equation: if 0 = Ax^2 + Bx + C, then x = (-B +- sqrt(B^2 - 4AC)) / 2A
            double A = 1 + Math.Pow(line.Slope, 2);
            double B = (-2 * Center.X) + (2 * (line.YIntercept - Center.Y) * line.Slope);
            double C = Math.Pow(Center.X, 2) + Math.Pow(line.YIntercept - Center.Y, 2) - Math.Pow(Radius, 2);

            double x1 = (-1 * B + Math.Sqrt(Math.Pow(B, 2) - (4 * A * C))) / (2 * A);
            double x2 = (-1 * B - Math.Sqrt(Math.Pow(B, 2) - (4 * A * C))) / (2 * A);
            double y1 = line.Slope * x1 + line.YIntercept;
            double y2 = line.Slope * x2 + line.YIntercept;

            if (line.IsVertical)
            {
                x1 = line.A.X;
                x2 = line.A.X;
                //must use circle equation instead of line equation to find y's
                y1 = Center.Y + Math.Sqrt(Math.Pow(Radius, 2) - Math.Pow(x1 - Center.X, 2));
                y2 = Center.Y - Math.Sqrt(Math.Pow(Radius, 2) - Math.Pow(x1 - Center.X, 2));
            }
            if (line.IsHorizontal)
            {
                y1 = line.A.Y;
                y2 = line.A.Y;
            }
            WPoint        point1 = new WPoint(x1, y1);
            WPoint        point2 = new WPoint(x2, y2);
            List <WPoint> result = new List <WPoint>()
            {
                point1
            };

            if (point1 != point2)
            {
                result.Add(point2);
            }
            return(result.ToArray());
        }
Beispiel #7
0
        /// <summary>
        /// Returns true if this wedge contains point <paramref name='b'/>, including if <paramref name='b'/> lies on one of this wedge's edges.
        /// </summary>
        public bool Contains(WPoint b)
        {
            double distance = Circle.Center.Distance(b);

            if (distance > Circle.Radius)
            {
                return(false);
            }
            double degrees = Circle.DegreesAtPoint(b);

            return(Degrees.Overlaps(degrees));
        }
        /// <summary>
        /// Find the two tangent points on the circle that form lines to point <paramref name='b'/>.
        /// </summary>
        /// <returns>Array of length 2.</returns>
        public WPoint[] GetTangentPoints(WPoint b)
        {
            //point C and D are the tangents
            WCircle a            = this;
            double  distanceAB   = a.Center.Distance(b);
            double  degreesAB    = DegreesAtPoint(b);
            double  degreesAB_AC = Math.Cos(Radius / distanceAB);
            WPoint  c            = PointAtDegrees(degreesAB + degreesAB_AC);
            WPoint  d            = PointAtDegrees(degreesAB - degreesAB_AC);

            return(new WPoint[] { c, d });
        }
Beispiel #9
0
        /// <summary>Returns true if point <paramref name='c'/> lies on this line.</summary>
        public virtual bool Overlaps(WPoint c)
        {
            if (IsVertical)
            {
                return(Geometry.WithinMarginOfError(c.X, A.X));
            }

            if (!Geometry.WithinMarginOfError(c.Y, (Slope * c.X) + YIntercept))
            {
                return(false);
            }

            return(true);
        }
        //todo: better names for PointOnLine and PointPastLine, they are misleading

        /// <summary>
        /// Calculates point along line AB, starting at A and moving towards B
        /// </summary>
        /// <exception cref='ArgumentException'>Point A and B cannot be the same.</exception>
        public static WPoint PointOnLine(WPoint a, WPoint b, double distance)
        {
            double lineLength = a.Distance(b);

            if (lineLength == 0)
            {
                throw new ArgumentException("Point A and B cannot be the same.");
            }
            double lengthRatio = distance / lineLength;
            double x           = ((1d - lengthRatio) * a.X) + (lengthRatio * b.X);
            double y           = ((1d - lengthRatio) * a.Y) + (lengthRatio * b.Y);

            return(new WPoint(x, y));
        }
Beispiel #11
0
        /// <summary>Returns true if point <paramref name='c'/> lies on this line segment.</summary>
        public override bool Overlaps(WPoint c)
        {
            if (IsVertical)
            {
                return(Geometry.WithinMarginOfError(c.X, A.X));
            }

            if (!Geometry.WithinMarginOfError(c.Y, (Slope * c.X) + YIntercept))
            {
                return(false);
            }

            return(c.X >= Math.Min(A.X, B.X) && c.X <= Math.Max(A.X, B.X) &&
                   c.Y >= Math.Min(A.Y, B.Y) && c.Y <= Math.Max(A.Y, B.Y));
        }
        //todo: couldn't LineDirection be moved to Line object? probably PointOnLine and PointPastLine could to.

        /// <summary>
        /// Given directed line A to B, what direction is it pointing?
        /// </summary>
        /// <remarks>
        /// North, South, East, and West answers are exact. So "North" means exactly North.
        /// The inbetween directions cover all remaining values. So "NorthWest" covers all values between North and West.
        /// </remarks>
        /// <exception cref='NotImplementedException'>Coordinate plane not supported.</exception>
        public static Direction LineDirection(WPoint a, WPoint b)
        {
            if (a == b)
            {
                return(Direction.None);
            }
            switch (CoordinatePlane)
            {
            case CoordinatePlanes.Screen: return(LineDirection_Screen(a, b));

            case CoordinatePlanes.Paper: return(LineDirection_Paper(a, b));

            default: throw new NotImplementedException("Coordinate plane not supported.");
            }
        }
Beispiel #13
0
        //todo: verify that all line operations take vertical and horizontal lines into account

        /// <summary>
        /// Returns the point where a perpendicular line passing through point <paramref name='c'/> intersects this line.
        /// </summary>
        public WPoint GetPerpendicularIntersect(WPoint c)
        {
            if (IsVertical)
            {
                return(new WPoint(this.A.X, c.Y));
            }
            if (IsHorizontal)
            {
                return(new WPoint(c.X, this.A.Y));
            }
            double cSlope      = PerpendicularSlope;
            double cYIntercept = c.Y - (cSlope * c.X);
            double x           = (cYIntercept - this.YIntercept) / (this.Slope - cSlope);
            double y           = (this.Slope * x) + this.YIntercept;

            return(new WPoint(x, y));
        }
 private static Direction LineDirection_Paper(WPoint a, WPoint b)
 {
     if (a.X == b.X)
     {
         return((a.Y < b.Y) ? Direction.North : Direction.South);
     }
     if (a.Y == b.Y)
     {
         return((a.X < b.X) ? Direction.East : Direction.West);
     }
     if (a.X < b.X)
     {
         return((a.Y < b.Y) ? Direction.NorthEast : Direction.SouthEast);
     }
     else
     {
         return((a.Y < b.Y) ? Direction.NorthWest : Direction.SouthWest);
     }
 }
        /// <summary>
        /// Given a line from the center of this circle to a point (<paramref name='lineEnd'/>), what degrees is the line angle at?
        /// 0 degrees is East of center, increases clockwise.
        /// </summary>
        public double DegreesAtPoint(WPoint lineEnd)
        {
            if (Geometry.CoordinatePlane == Geometry.CoordinatePlanes.None)
            {
                throw new ArgumentException("Coordinate plane required.");
            }

            Geometry.Direction direction = Geometry.LineDirection(Center, lineEnd);
            switch (direction)
            {
            case Geometry.Direction.East: return(0);

            case Geometry.Direction.South: return(90);

            case Geometry.Direction.West: return(180);

            case Geometry.Direction.North: return(270);
            }

            double lineLength = Center.Distance(lineEnd);
            double radians    = Math.Abs(Math.Asin((lineEnd.Y - Center.Y) / lineLength));
            double degrees    = Shapes.WCircle.RadiansToDegrees(radians) % DEGREES_IN_CIRCLE;

            switch (direction)
            {
            case Geometry.Direction.SouthEast: return(degrees);

            case Geometry.Direction.SouthWest: return(DEGREES_IN_HALF_CIRCLE - degrees);

            case Geometry.Direction.NorthWest: return(DEGREES_IN_HALF_CIRCLE + degrees);

            case Geometry.Direction.NorthEast: return(DEGREES_IN_CIRCLE - degrees);
            }

            throw new NotImplementedException(String.Format("Direction not supported: {0}.", direction));
        }
Beispiel #16
0
 /// <summary></summary>
 public WWedgeUnbound(WPoint center, WRangeCircular degreeRange)
 {
     Center  = center;
     Degrees = degreeRange;
 }
 /// <summary>
 /// Returns true if point <paramref name='b'/> lies within or on this circle.
 /// </summary>
 public bool Contains(WPoint b)
 {
     return(Center.Distance(b) <= Radius);
 }
Beispiel #18
0
 /// <summary>Generates a vertical line through the specified point.</summary>
 public static WLine Vertical(WPoint point)
 {
     return(new WLine(point, new WPoint(point.X, point.Y + 1)));
 }
Beispiel #19
0
 /// <summary>
 /// Returns the distance between this point and point <paramref name='b'/>. Always positive.
 /// </summary>
 public double Distance(WPoint b)
 {
     return(Math.Sqrt(Math.Pow(b.X - this.X, 2) + Math.Pow(b.Y - this.Y, 2)));
 }
Beispiel #20
0
        /// <summary>Returns intersection between a line segment and another line segment.</summary>
        public override Intersection GetIntersection(WLineSegment that)
        {
            if (this.Parallel(that))
            {
                bool thisAOnThat = this.A.Overlaps(that);
                bool thisBOnThat = this.B.Overlaps(that);
                bool thatAOnThis = that.A.Overlaps(this);
                bool thatBOnThis = that.B.Overlaps(this);

                if (!thisAOnThat && !thisBOnThat && !thatAOnThis && !thatBOnThis)
                {
                    return(Intersection.NONE);
                }

                if (thisAOnThat && thisBOnThat)
                {
                    return(new Intersection(this));
                }

                if (thatAOnThis && thatBOnThis)
                {
                    return(new Intersection(that));
                }

                WPoint overlapThis = null;
                WPoint overlapThat = null;
                if (thisAOnThat)
                {
                    overlapThis = this.A;
                }
                else if (thisBOnThat)
                {
                    overlapThis = this.B;
                }
                if (thatAOnThis)
                {
                    overlapThat = that.A;
                }
                else if (thatBOnThis)
                {
                    overlapThat = that.B;
                }

                if (overlapThis == null || overlapThat == null)
                {
                    //should not reach this, but just in case
                    return(Intersection.NONE);
                }

                if (overlapThis == overlapThat)
                {
                    return(new Intersection(overlapThis));
                }

                return(new Intersection(new WLineSegment(overlapThis, overlapThat)));
            }

            Intersection possibleIntersection = (this.ToWLine()).GetIntersection(that.ToWLine());

            if (possibleIntersection.IsPoint && this.Overlaps(possibleIntersection.Point) && that.Overlaps(possibleIntersection.Point))
            {
                return(possibleIntersection);
            }

            return(Intersection.NONE);
        }
 /// <summary></summary>
 public WCircle(WPoint center, double radius)
 {
     X      = center.X;
     Y      = center.Y;
     Radius = radius;
 }
Beispiel #22
0
 /// <summary></summary>
 public WLineSegment(WPoint a, WPoint b, bool isDirected) : base(a, b, isDirected)
 {
 }
Beispiel #23
0
 /// <summary></summary>
 public WLineSegment(WPoint a, WPoint b) : base(a, b)
 {
 }
Beispiel #24
0
 /// <summary></summary>
 public WWedgeUnbound(WPoint center, double degreesRangeStart, double degreesRangeEnd)
 {
     Center  = center;
     Degrees = new WRangeCircular(degreesRangeStart, degreesRangeEnd, WCircle.DEGREES_IN_CIRCLE);
 }
Beispiel #25
0
 /// <summary>Rotation defaults to 0 degrees.</summary>
 public WRectangle(double width, double height, WPoint corner) : this(width, height, corner, 0)
 {
 }
        /// <summary>
        /// Calculates point along line AB, starting at B and moving away from A
        /// </summary>
        public static WPoint PointPastLine(WPoint a, WPoint b, double distance)
        {
            double lineLength = a.Distance(b);

            return(PointOnLine(a, b, lineLength + distance));
        }