Exemplo n.º 1
0
        BspSegment GetOriginalSourceBspSegment(BspSegment segment)
        {
            var bspSegment = segment;

            while (bspSegment.OriginalSegment != null)
            {
                bspSegment = bspSegment.OriginalSegment;
            }
            var collisionBspSegment = bspSegment as BspSegmentForCollsion;

            if (collisionBspSegment == null)
            {
                throw new InvalidProgramException("不是BspSegmentForCollsion!");
            }
            return(collisionBspSegment.SourceSegment);
        }
Exemplo n.º 2
0
        public static IEnumerable <BspSegmentForCollsion> CreateSegmentsForCollision(BspSegment segment, double range)
        {
            var startPoint  = segment.LineSegment.StartPoint;
            var endPoint    = segment.LineSegment.EndPoint;
            var direction   = segment.LineSegment.Direction;
            var perp        = direction.GetPerpendicularVector().GetNormal() * range;
            var topleft     = startPoint + perp;
            var topright    = endPoint + perp;
            var bottomleft  = startPoint - perp;
            var bottomright = endPoint - perp;
            var topSegment  = new BspSegmentForCollsion()
            {
                EntityId      = segment.EntityId,
                LineSegment   = new LineSegment2d(topleft, topright),
                SourceSegment = segment
            };
            var rightSegment = new BspSegmentForCollsion()
            {
                EntityId      = segment.EntityId,
                LineSegment   = new LineSegment2d(topright, bottomright),
                SourceSegment = segment
            };
            var bottomSegment = new BspSegmentForCollsion()
            {
                EntityId      = segment.EntityId,
                LineSegment   = new LineSegment2d(bottomright, bottomleft),
                SourceSegment = segment
            };
            var leftSegment = new BspSegmentForCollsion()
            {
                EntityId      = segment.EntityId,
                LineSegment   = new LineSegment2d(bottomleft, topleft),
                SourceSegment = segment
            };

            return(new BspSegmentForCollsion[]
            {
                topSegment,
                rightSegment,
                bottomSegment,
                leftSegment
            });
        }
Exemplo n.º 3
0
 public CurveBspNode(BspSegment segment)
 {
     Segments = new BspSegment[] { segment };
 }
Exemplo n.º 4
0
        private void SplitSegment(BspSegment sourceSegment, BspSegment targetSegment,
                                  out BspSegment left, out BspSegment right, out BspSegment inline,
                                  out double startVal, out double endVal)
        {
            left     = null;
            right    = null;
            inline   = null;
            startVal = 0.0;
            endVal   = 0.0;

            var sourceStart = sourceSegment.LineSegment.StartPoint;
            var sourceEnd   = sourceSegment.LineSegment.EndPoint;

            var targetStart = targetSegment.LineSegment.StartPoint;
            var targetEnd   = targetSegment.LineSegment.EndPoint;

            // We need to make sure targetSegment is not a point
            if (targetStart == targetEnd)
            {
                return;
            }

            // Allan: I found IsLeft is not good to determine whether a point is left or right
            // if the segment is too long, so divide it by length.
            var sourceLength = sourceSegment.LineSegment.Length;
            var targetLength = targetSegment.LineSegment.Length;
            var length       = sourceLength + targetLength;

            startVal = IsLeft(sourceStart, sourceEnd, targetStart) / length;
            endVal   = IsLeft(sourceStart, sourceEnd, targetEnd) / length;

            //// For fixing some error by small values.
            //using (var switcher = new SafeToleranceOverride(0.0005, 0.0005))
            //{
            //    if (targetStart.IsEqualTo(sourceStart) || targetStart.IsEqualTo(sourceEnd))
            //        startVal = 0.0;
            //    if (targetEnd.IsEqualTo(sourceStart) || targetEnd.IsEqualTo(sourceEnd))
            //        endVal = 0.0;
            //}

            // Left
            if (startVal.EqualsWithTolerance(0.0) && endVal.EqualsWithTolerance(0.0))
            {
                inline = targetSegment;
            }
            else if (startVal.Larger(0.0) && endVal.Larger(0.0))
            {
                left = targetSegment;
            }
            else if (startVal.Smaller(0.0) && endVal.Smaller(0.0))
            {
                right = targetSegment;
            }
            else if (startVal.EqualsWithTolerance(0.0))
            {
                var sourceParam = sourceSegment.LineSegment.GetParameterOf(targetStart);
                var splitInfos  = new List <BspSplitInfo>();
                if (targetSegment.StartSplitInfos != null && targetSegment.StartSplitInfos.Any())
                {
                    splitInfos.AddRange(targetSegment.StartSplitInfos);
                }

                splitInfos.Add(new BspSplitInfo()
                {
                    IsSplitted    = false,
                    SourceSegment = sourceSegment,
                    SourceParam   = sourceParam
                });
                targetSegment.StartSplitInfos = splitInfos.ToArray();

                if (endVal.Larger(0.0))
                {
                    left = targetSegment;
                }
                else
                {
                    right = targetSegment;
                }
            }
            else if (endVal.EqualsWithTolerance(0.0))
            {
                var sourceParam = sourceSegment.LineSegment.GetParameterOf(targetEnd);
                var splitInfos  = new List <BspSplitInfo>();
                if (targetSegment.EndSplitInfos != null && targetSegment.EndSplitInfos.Any())
                {
                    splitInfos.AddRange(targetSegment.EndSplitInfos);
                }

                splitInfos.Add(new BspSplitInfo()
                {
                    IsSplitted    = false,
                    SourceSegment = sourceSegment,
                    SourceParam   = sourceParam
                });
                targetSegment.EndSplitInfos = splitInfos.ToArray();

                if (startVal.Larger(0.0))
                {
                    left = targetSegment;
                }
                else
                {
                    right = targetSegment;
                }
            }
            else
            {
                // Split
                var line2d = new Line2d(sourceStart, sourceEnd);
                var points = line2d.IntersectWith(targetSegment.LineSegment);
                if (points != null && points.Length > 0)
                {
                    // Only one intersect point here.
                    var intersect    = points[0];
                    var segmentStart = new LineSegment2d(targetStart, intersect);
                    var segmentEnd   = new LineSegment2d(intersect, targetEnd);
                    // 如果segmentStart过短,就认为交点是targetStart。
                    // 否则在计算过程中就会矫枉过正,导致本不是相交点的地方成为相交点
                    if (segmentStart.Length.SmallerOrEqual(DoubleExtensions.STolerance))
                    {
                        if (endVal.EqualsWithTolerance(0.0))
                        {
                            inline = targetSegment;
                        }
                        else if (endVal.Larger(0.0))
                        {
                            left = targetSegment;
                        }
                        else if (endVal.Smaller(0.0))
                        {
                            right = targetSegment;
                        }
                    }
                    else if (segmentEnd.Length.SmallerOrEqual(DoubleExtensions.STolerance))
                    {
                        if (startVal.EqualsWithTolerance(0.0))
                        {
                            inline = targetSegment;
                        }
                        else if (startVal.Larger(0.0))
                        {
                            left = targetSegment;
                        }
                        else if (startVal.Smaller(0.0))
                        {
                            right = targetSegment;
                        }
                    }
                    else
                    {
                        var sourceParam = sourceSegment.LineSegment.GetParameterOf(intersect);
                        var splitInfo   = new BspSplitInfo()
                        {
                            SourceSegment = sourceSegment,
                            SourceParam   = sourceParam
                        };

                        BspSegment templeft = null;
                        if (segmentStart.Length.Larger(0.0))
                        {
                            templeft = new BspSegment()
                            {
                                LineSegment     = segmentStart,
                                EntityId        = targetSegment.EntityId,
                                StartSplitInfos = targetSegment.StartSplitInfos,
                                EndSplitInfos   = new BspSplitInfo[] { splitInfo },
                                OriginalSegment = targetSegment
                            };
                        }

                        BspSegment tempRight = null;
                        if (segmentEnd.Length.Larger(0.0))
                        {
                            tempRight = new BspSegment()
                            {
                                LineSegment     = segmentEnd,
                                EntityId        = targetSegment.EntityId,
                                StartSplitInfos = new BspSplitInfo[] { splitInfo },
                                EndSplitInfos   = targetSegment.EndSplitInfos,
                                OriginalSegment = targetSegment
                            };
                        }

                        if (startVal.LargerOrEqual(0.0))
                        {
                            left  = templeft;
                            right = tempRight;
                        }
                        else
                        {
                            left  = tempRight;
                            right = templeft;
                        }
                    }
                }
                else
                {
                    // 如果没有任何交点,我们就认为它是inline的,因为往往因为计算精度,
                    // 导致startVal和endVal的值在0.001左右,但是用IntersectWith计算不出任何交点
                    inline = targetSegment;
                }
            }
        }
Exemplo n.º 5
0
        private void UpdateSplitInfoForInlineSegments(BspSegment segment, List <BspSegment> inlineSegments)
        {
            // If the segment is not splited, just return.
            if (segment.StartSplitInfos == null && segment.EndSplitInfos == null)
            {
                return;
            }

            bool start = false;
            bool end   = false;

            var startSplitInfos = segment.StartSplitInfos;

            if (startSplitInfos != null && startSplitInfos.Length > 0)
            {
                var param = inlineSegments[0].LineSegment.GetParameterOf(segment.LineSegment.StartPoint);
                var info  = startSplitInfos.FirstOrDefault(it => it.SourceSegment == inlineSegments[0] && it.SourceParam.EqualsWithTolerance(param));
                if (info != null)
                {
                    start = true;
                }
            }

            if (!start)
            {
                var endSplitInfos = segment.EndSplitInfos;
                if (endSplitInfos != null && endSplitInfos.Length > 0)
                {
                    var param = inlineSegments[0].LineSegment.GetParameterOf(segment.LineSegment.EndPoint);
                    var info  = endSplitInfos.FirstOrDefault(it => it.SourceSegment == inlineSegments[0] && it.SourceParam.EqualsWithTolerance(param));
                    if (info != null)
                    {
                        end = true;
                    }
                }
            }

            if (!start && !end)
            {
                return;
            }

            // Set segment's splitinfo
            var point      = start ? segment.LineSegment.StartPoint : segment.LineSegment.EndPoint;
            var splitInfos = new List <BspSplitInfo>();

            for (int i = 1; i < inlineSegments.Count; i++)
            {
                // 需要判断是否在线上,因为GetParameterOf函数是不准确的。
                // 另外,虽然共线,也是近似共线,所以要用IsOn
                var isOn = inlineSegments[i].LineSegment.IsOn(point);
                if (!isOn)
                {
                    continue;
                }

                var param = inlineSegments[i].LineSegment.GetParameterOf(point);
                splitInfos.Add(new BspSplitInfo()
                {
                    SourceSegment = inlineSegments[i],
                    SourceParam   = param
                });
            }

            if (start)
            {
                splitInfos.InsertRange(0, segment.StartSplitInfos);
                segment.StartSplitInfos = splitInfos.ToArray();
            }
            else
            {
                splitInfos.InsertRange(0, segment.EndSplitInfos);
                segment.EndSplitInfos = splitInfos.ToArray();
            }
        }
Exemplo n.º 6
0
        private CurveBspNode Create(IEnumerable <BspSegment> segments, int depth, CurveBspNode parent, bool isLeft)
        {
            if (segments == null || !segments.Any())
            {
                return(null);
            }

            BspSegment segment = null;

            // We need to make sure segment is not a point
            foreach (var bspSegment in segments)
            {
                var startPoint = bspSegment.LineSegment.StartPoint;
                var endPoint   = bspSegment.LineSegment.EndPoint;
                if (startPoint != endPoint)
                {
                    segment = bspSegment;
                    break;
                }
            }

            if (segment == null)
            {
                return(null);
            }

            var node = new CurveBspNode(segment);

            node.Depth  = depth;
            node.Parent = parent;
            node.IsLeft = isLeft;

            // Left segments
            var leftSegments = new List <BspSegment>();
            // Right segments
            var rightSegments = new List <BspSegment>();
            // Inline segments
            var inlineSegments = new List <BspSegment>();

            inlineSegments.Add(segment);

            var leftSegsStartOnSplitLine  = new List <BspSegment>();
            var leftSegsEndOnSplitLine    = new List <BspSegment>();
            var rightSegsStartOnSplitLine = new List <BspSegment>();
            var rightSegsEndOnSplitLine   = new List <BspSegment>();

            foreach (var nextSegment in segments)
            {
                if (nextSegment == segment)
                {
                    continue;
                }

                BspSegment left, right, inline;
                double     startVal, endVal;
                SplitSegment(segment, nextSegment, out left, out right, out inline, out startVal, out endVal);
                if (left != null)
                {
                    leftSegments.Add(left);
                }
                if (right != null)
                {
                    rightSegments.Add(right);
                }
                if (inline != null)
                {
                    inlineSegments.Add(inline);
                }

                if (left != null && right == null)
                {
                    if (startVal.EqualsWithTolerance(0.0))
                    {
                        leftSegsStartOnSplitLine.Add(left);
                    }
                    else if (endVal.EqualsWithTolerance(0.0))
                    {
                        leftSegsEndOnSplitLine.Add(left);
                    }
                }
                else if (left == null && right != null)
                {
                    if (startVal.EqualsWithTolerance(0.0))
                    {
                        rightSegsStartOnSplitLine.Add(right);
                    }
                    else if (endVal.EqualsWithTolerance(0.0))
                    {
                        rightSegsEndOnSplitLine.Add(right);
                    }
                }
            }

            // Update node's segment's information.
            if (inlineSegments.Count > 1)
            {
                node.Segments = inlineSegments.ToArray();
                // Update all left segments and right segment's split info
                foreach (var leftSegment in leftSegments)
                {
                    UpdateSplitInfoForInlineSegments(leftSegment, inlineSegments);
                }
                foreach (var rightSegment in rightSegments)
                {
                    UpdateSplitInfoForInlineSegments(rightSegment, inlineSegments);
                }
            }

            //
            if (leftSegsStartOnSplitLine.Count > 0)
            {
                foreach (var bspSegment in leftSegsStartOnSplitLine)
                {
                    var startPoint     = bspSegment.LineSegment.StartPoint;
                    var rightStartSegs = rightSegsStartOnSplitLine.Where(
                        it => it.LineSegment.StartPoint.IsEqualTo(startPoint));
                    var rightEndSegs = rightSegsEndOnSplitLine.Where(
                        it => it.LineSegment.EndPoint.IsEqualTo(startPoint));
                    var splitInfos = new List <BspSplitInfo>();
                    foreach (var rightStartSeg in rightStartSegs)
                    {
                        splitInfos.Add(new BspSplitInfo()
                        {
                            IsSplitted    = false,
                            SourceSegment = rightStartSeg,
                            SourceParam   = 0.0
                        });
                    }
                    foreach (var rightEndSeg in rightEndSegs)
                    {
                        splitInfos.Add(new BspSplitInfo()
                        {
                            IsSplitted    = false,
                            SourceSegment = rightEndSeg,
                            SourceParam   = 1.0
                        });
                    }
                    if (splitInfos.Count > 0)
                    {
                        if (bspSegment.StartSplitInfos != null && bspSegment.StartSplitInfos.Length > 0)
                        {
                            splitInfos.InsertRange(0, bspSegment.StartSplitInfos);
                        }
                        bspSegment.StartSplitInfos = splitInfos.ToArray();
                    }
                }
            }

            if (leftSegsEndOnSplitLine.Count > 0)
            {
                foreach (var bspSegment in leftSegsEndOnSplitLine)
                {
                    var endPoint       = bspSegment.LineSegment.EndPoint;
                    var rightStartSegs = rightSegsStartOnSplitLine.Where(
                        it => it.LineSegment.StartPoint.IsEqualTo(endPoint));
                    var rightEndSegs = rightSegsEndOnSplitLine.Where(
                        it => it.LineSegment.EndPoint.IsEqualTo(endPoint));
                    var splitInfos = new List <BspSplitInfo>();
                    foreach (var rightStartSeg in rightStartSegs)
                    {
                        splitInfos.Add(new BspSplitInfo()
                        {
                            IsSplitted    = false,
                            SourceSegment = rightStartSeg,
                            SourceParam   = 0.0
                        });
                    }
                    foreach (var rightEndSeg in rightEndSegs)
                    {
                        splitInfos.Add(new BspSplitInfo()
                        {
                            IsSplitted    = false,
                            SourceSegment = rightEndSeg,
                            SourceParam   = 1.0
                        });
                    }
                    if (splitInfos.Count > 0)
                    {
                        if (bspSegment.EndSplitInfos != null && bspSegment.EndSplitInfos.Length > 0)
                        {
                            splitInfos.InsertRange(0, bspSegment.EndSplitInfos);
                        }
                        bspSegment.EndSplitInfos = splitInfos.ToArray();
                    }
                }
            }

            if (depth < this._parallelDepth)
            {
                // Parellel to improve performance.
                System.Threading.Tasks.Parallel.Invoke(
                    () => node.LeftChild  = Create(leftSegments, depth + 1, node, true),
                    () => node.RightChild = Create(rightSegments, depth + 1, node, false));
            }
            else
            {
                node.LeftChild  = Create(leftSegments, depth + 1, node, true);
                node.RightChild = Create(rightSegments, depth + 1, node, false);
            }

            return(node);
        }