private static ObstacleSegment GetNearerSegment(RotationTreeNode node, RotationTreeNode p)
        {
            ObstacleSegment segment1 = node.Segments[0];
            ObstacleSegment segment2 = node.Segments[1];

            return(CalcDistance(p.Point, segment1.Point1.Point, segment1.Point2.Point) < CalcDistance(p.Point, segment2.Point1.Point, segment2.Point2.Point) ? segment1 : segment2);
        }
        private void HandleWithPoints(RotationTreeNode p, RotationTreeNode q)
        {
            if (p == null || q == null)
            {
                return;
            }

            if (p.X > q.X)
            {
                return;
            }

            if (p.IsSinglePoint && !q.IsSinglePoint && p.Obstacle == q.Obstacle)
            {
                p.VisibleSegment = q.VisibleSegment;
                //AddEdge(p, q);
            }
            else if (q.IsSinglePoint && !p.IsSinglePoint && q.Obstacle == p.Obstacle)
            {
                //AddEdge(p, q);
            }
            else if (q.IsSinglePoint && p.VisibleSegment != null && q.Obstacle == p.VisibleSegment.Obstacle)
            {
                AddEdge(p, q);
            }
            else if (p.IsAdjacent(q))
            {
                ObstacleSegment higher = GetHigherSegment(q, p);
                p.VisibleSegment = higher ?? q.VisibleSegment;
                if (!SameObstacle(p, q))
                {
                    AddEdge(p, q);
                }
            }
            else if (p.VisibleSegment != null && p.VisibleSegment.Contains(q))
            {
                ObstacleSegment left = GetLeftSegment(q, p);
                p.VisibleSegment = left ?? q.VisibleSegment;
                if (!SameObstacle(p, q))
                {
                    AddEdge(p, q);
                }
            }
            else if (PointLiesNearerThanSegment(p, q))
            {
                p.VisibleSegment = q.IsSinglePoint ? q.VisibleSegment : GetNearerSegment(q, p);
                if (!SameObstacle(p, q))
                {
                    AddEdge(p, q);
                }
            }
        }
示例#3
0
 public ObstacleSegment GetOtherAdjacentSegment(ObstacleSegment s)
 {
     return(_segments[0] == s ? _segments[1] : _segments[0]);
 }
        private void InitializeNodeVisibility()
        {
            foreach (RotationTreeNode obstaclePoint in _nodes)
            {
                double          minDist    = double.MaxValue;
                ObstacleSegment minDistSeg = null;
                foreach (ObstacleSegment obstacleSegment in _obstacles.SelectMany(o => o.Segments))
                {
                    if (obstacleSegment.Contains(obstaclePoint))
                    {
                        continue;
                    }
                    if (obstaclePoint.IsSinglePoint && obstaclePoint.Obstacle == obstacleSegment.Obstacle)
                    {
                        continue;
                    }

                    double pointX = obstaclePoint.X;
                    double pointY = obstaclePoint.Y;

                    double segPoint1X = obstacleSegment.Point1.X;
                    double segPoint1Y = obstacleSegment.Point1.Y;
                    double segPoint2X = obstacleSegment.Point2.X;
                    double segPoint2Y = obstacleSegment.Point2.Y;

                    double segMinX = Math.Min(segPoint1X, segPoint2X);
                    double segMinY = Math.Min(segPoint1Y, segPoint2Y);
                    double segMaxX = Math.Max(segPoint1X, segPoint2X);
                    double segMaxY = Math.Max(segPoint1Y, segPoint2Y);

                    double dist;
                    if (segMinX <= pointX && segMaxX > pointX)
                    {
                        // if segment stretches across the point in x direction

                        // We have to calculate the distance from the point
                        // straight down to the segment.
                        // Because the segment have a slope, we have to do a little math.

                        if (Math.Abs(segMinY - segMaxY) < double.Epsilon)
                        {
                            // special case: the segment is horizontal
                            dist = segMinY - pointY;
                        }
                        else if (Math.Abs(segMinX - segMaxX) < double.Epsilon)
                        {
                            // special case: the segment is vertical
                            dist = Math.Min(segMinY - pointY, segMaxY - pointY);
                        }
                        else
                        {
                            // case: angled segment
                            double pointOnSegmentX = pointX;
                            double pointOnSegmentY;
                            if (Math.Abs(pointOnSegmentX - segMinX) > double.Epsilon)
                            {
                                pointOnSegmentY = segMinY + ((segMaxY - segMinY) / (segMaxX - segMinX) * (pointOnSegmentX - segMinX));
                            }
                            else
                            {
                                pointOnSegmentY = segMinY;
                            }

                            dist = pointOnSegmentY - pointY;
                        }
                    }
                    else
                    {
                        continue;
                    }

                    if (dist > 0)
                    {                           // segment lies above point not below it
                        continue;
                    }

                    dist = Math.Abs(dist);
                    if (dist < minDist)
                    {                           // check if current distance is smaller than previous ones
                        minDist    = dist;
                        minDistSeg = obstacleSegment;
                    }
                }

                obstaclePoint.VisibleSegment = minDistSeg;
            }
        }
        private static bool PointLiesNearerThanSegment(RotationTreeNode p, RotationTreeNode q)
        {
            ObstacleSegment visSegment = p.VisibleSegment;

            if (visSegment == null)             // if there is no segment, it can not lie nearer (to p) than q
            {
                return(true);
            }

            // using a linear equation: y = mx + b
            // for the line pq
            double m1 = (q.Y - p.Y) / (q.X - p.X);
            double b1 = p.Y - (m1 * p.X);

            // getting the points of the segment
            RotationTreeNode point1 = visSegment.Point1;
            RotationTreeNode point2 = visSegment.Point2;

            // check if both segment points lie on the
            // same side of that line.
            // if they do, there is no crossing.
            if (!double.IsInfinity(m1))
            {
                double valuePoint1 = (m1 * point1.X) + b1;
                double valuePoint2 = (m1 * point2.X) + b1;
                if ((point1.Y > valuePoint1 && point2.Y > valuePoint2) ||
                    (point1.Y < valuePoint1 && point2.Y < valuePoint2))
                {
                    return(true);
                }
            }
            else if (point1.X < p.X && point2.X < p.X || point1.X > p.X && point2.X > p.X)
            {
                return(true);
            }

            // get the line for the segment
            double m2 = (point2.Y - point1.Y) / (point2.X - point1.X);
            double b2 = point1.Y - (m2 * point1.X);


            if (Math.Abs(m1 - m2) < double.Epsilon) // avoiding divide-by-zero; lines are parallel
            {
                return(true);                       // if pq and the segment are parallel, the segment can be discarded and the point "lies nearer"
            }
            // calculate the crossing point
            double x;

            if (!double.IsInfinity(m2) && !double.IsInfinity(m1))
            {
                x = (b2 - b1) / (m1 - m2);
            }
            else if (!double.IsInfinity(m2) && double.IsInfinity(m1))
            {
                x = p.X;
            }
            else
            {
                x = point1.X;
            }

            double y = m1 * x + b1;

            var crossingPoint = new Point(x, y);

            // check if distancePQ is the smallest
            return(CalcDistance(p.Point, q.Point) <= CalcDistance(p.Point, crossingPoint));
        }
        private static ObstacleSegment GetLeftSegment(RotationTreeNode node, RotationTreeNode p)
        {
            ObstacleSegment  seg1      = node.Segments[0];
            ObstacleSegment  seg2      = node.Segments[1];
            RotationTreeNode pointSeg1 = seg1.GetOtherPoint(node);
            RotationTreeNode pointSeg2 = seg2.GetOtherPoint(node);

            // using a linear equation: y = mx + b
            double m = (node.Y - p.Y) / (node.X - p.X);
            double b = p.Y - (m * p.X);

            // there now are several cases:
            // 1) one of the two segments lies to the left
            // 2) none lies to the left
            // 3) both lie to the left
            // 4) one segment lies directly behind the line p to q

            // in case
            // 1) we return that segment
            // 2) we return null
            // 3) we return the segment nearer to p
            // 4) we return that segment (if the other does not lie to the left)

            // check the cases if the line p-to-this
            // is vertical
            if (double.IsInfinity(m))
            {
                if (p.Y > node.Y)
                {                       // consider the direction of the vertical line
                                        // case 1
                    if (pointSeg1.X < node.X && node.X <= pointSeg2.X)
                    {
                        return(seg1);                           // Segment 1 lies to the left of pq
                    }
                    if (pointSeg2.X < node.X && node.X <= pointSeg1.X)
                    {
                        return(seg2);                           // Segment 2 lies to the left of pq
                    }
                    // case 3
                    if (pointSeg1.X < node.X && pointSeg2.X < node.X)
                    {
                        //return node.GetNearestSegment(p);
                        return(GetNearerSegment(node, p));
                    }


                    // case 4
                    if (Math.Abs(pointSeg1.X - node.X) < double.Epsilon)
                    {
                        return(seg1);
                    }
                    if (Math.Abs(pointSeg2.X - node.X) < double.Epsilon)
                    {
                        return(seg2);
                    }

                    // case 2
                    if (pointSeg1.X > node.X && pointSeg2.X > node.X)
                    {
                        return(null);
                    }
                }
                else
                {
                    // case 1
                    if (pointSeg1.X > node.X && node.X >= pointSeg2.X)
                    {
                        return(seg1);                           // Segment 1 lies to the left of pq
                    }
                    if (pointSeg2.X > node.X && node.X >= pointSeg1.X)
                    {
                        return(seg2);                           // Segment 2 lies to the left of pq
                    }
                    // case 3
                    if (pointSeg1.X > node.X && pointSeg2.X > node.X)
                    {
                        //return node.GetNearestSegment(p);
                        return(GetNearerSegment(node, p));
                    }

                    // case 4
                    if (Math.Abs(pointSeg1.X - node.X) < double.Epsilon)
                    {
                        return(seg1);
                    }
                    if (Math.Abs(pointSeg2.X - node.X) < double.Epsilon)
                    {
                        return(seg2);
                    }

                    // case 2
                    if (pointSeg1.X < node.X && pointSeg2.X < node.X)
                    {
                        return(null);
                    }
                }
            }
            else
            {                   // check for non-vertical lines
                                // function value for end point of segment 1
                double value1 = (m * pointSeg1.X) + b;
                // function value for end point of segment 2
                double value2 = (m * pointSeg2.X) + b;

                // case 1
                if (pointSeg1.Y > value1 && value2 >= pointSeg2.Y)
                {
                    return(seg1);                       // Segment 1 lies to the left of pq
                }
                if (pointSeg2.Y > value2 && value1 >= pointSeg1.Y)
                {
                    return(seg2);                       // Segment 2 lies to the left of pq
                }
                // case 3
                if (pointSeg1.Y > value1 && pointSeg2.Y > value2)
                {
                    //return node.GetNearestSegment(p);
                    return(GetNearerSegment(node, p));
                }

                // case 4
                if (Math.Abs(pointSeg1.Y - value1) < double.Epsilon)
                {
                    return(seg1);
                }
                if (Math.Abs(pointSeg2.Y - value2) < double.Epsilon)
                {
                    return(seg2);
                }

                // case 2
                if (pointSeg1.Y < value1 && pointSeg2.Y < value2)
                {
                    return(null);
                }
            }

            // return null if this.equals(p)
            return(null);
        }