Ejemplo n.º 1
0
            public Switcharoo(IHalfEdgeBuilder tag)
            {
                Contract.Requires(tag != null);

                _tag = tag;

                var n = Direction.Perpendicular() * Width * 0.5f;

                _left  = new Ray2(HalfEdge.EndVertex.Position - n, Direction);
                _right = new Ray2(HalfEdge.EndVertex.Position + n, Direction);
            }
Ejemplo n.º 2
0
        private void ExtractPointsFromParallelRoads(IHalfEdgeBuilder at, IHalfEdgeBuilder bt)
        {
            Contract.Requires(at != null);
            Contract.Requires(bt != null);

            if (at.Width.TolerantEquals(bt.Width, 0.01f))
            {
                //Roads are totally parallel, have the same width, and join to the same vertex... a.k.a: a straight line
                var w    = at.Width * 0.5f;
                var d    = at.Direction.Perpendicular();
                var side = d * w;

                at.LeftEnd = _vertex.Position - side;
                //at.RightEnd = _vertex.Position + side;

                //bt.LeftEnd = at.RightEnd;
                bt.RightEnd = at.LeftEnd;
            }
            else
            {
                //Roads are totally parallel, but have different widths
                var ad  = _vertex.Position - at.HalfEdge.Pair.EndVertex.Position;
                var al  = ad.Length();
                var adn = ad / al;

                var bd  = _vertex.Position - bt.HalfEdge.Pair.EndVertex.Position;
                var bl  = bd.Length();
                var bdn = bd / bl;

                //What's the difference in widths?
                var widthDif = Math.Abs(at.Width - bt.Width);

                //Calculate a ramped junction shape from some distance along this roads segment (dependent upon width delta)
                var aAlong = adn * (al - Math.Min(0.9f * al, widthDif * 1.5f));
                var aSide  = adn.Perpendicular() * at.Width * 0.5f;
                at.LeftEnd = at.HalfEdge.Pair.EndVertex.Position + aAlong - aSide;
                //at.RightEnd = at.HalfEdge.Pair.EndVertex.Position + aAlong + aSide;

                var bAlong = bdn * (bl - Math.Min(0.9f * bl, widthDif * 1.5f));
                var bSide  = bdn.Perpendicular() * bt.Width * 0.5f;
                //bt.LeftEnd = bt.HalfEdge.Pair.EndVertex.Position + bAlong - bSide;
                bt.RightEnd = bt.HalfEdge.Pair.EndVertex.Position + bAlong + bSide;
            }
        }
Ejemplo n.º 3
0
        private void CreateFootpathFromPair(ISubdivisionGeometry geometry, string material, float height, IHalfEdgeBuilder a, IHalfEdgeBuilder b)
        {
            Contract.Requires(geometry != null);
            Contract.Requires(a != null);
            Contract.Requires(b != null);

            //Determine the inner point we're curving around
            bool r1LeftInner  = a.LeftEnd.TolerantEquals(b.RightEnd, 0.01f);
            bool r1RightInner = a.RightEnd.TolerantEquals(b.LeftEnd, 0.01f);

            //Straight on, no junction and no paths needed
            if (r1LeftInner && r1RightInner)
            {
                return;
            }

            if (r1LeftInner)
            {
                //One side is an inner side, create a footpath around that point
                CreateFootpath2Inner(geometry, material, height, true, a, b);
            }
            else
            {
                //No point is an inner point, follow around the outer edge connecting these two roads
                CreateFootpath2Outer(geometry, material, height, a, b);
            }
        }
Ejemplo n.º 4
0
        private void CreateFootpath2Inner(ISubdivisionGeometry geometry, string material, float height, bool r1LeftInner, IHalfEdgeBuilder r1, IHalfEdgeBuilder r2)
        {
            Contract.Requires(r1 != null);
            Contract.Requires(r2 != null);
            Contract.Requires(geometry != null);

            var innerPoint = r1LeftInner ? r1.LeftEnd : r1.RightEnd;

            var points = new List <Vector2> {
                innerPoint
            };

            //Points where the footpath terminates at the end of the road
            var r1Across = r1LeftInner ? r1.Direction.Perpendicular() : -r1.Direction.Perpendicular();
            var r1Point  = innerPoint + r1Across * r1.SidewalkWidth;
            var r2Across = r1LeftInner ? -r2.Direction.Perpendicular() : r2.Direction.Perpendicular();
            var r2Point  = innerPoint + r2Across * r2.SidewalkWidth;

            //Point to turn the connect around
            var centerPoint = new Ray2(r1Point, r1.Direction.Perpendicular()).Intersects(new Ray2(r2Point, r2.Direction.Perpendicular()));

            //Sanity check!
            if (!centerPoint.HasValue)
            {
                return;
            }

            //Evaluate segment
            var curve = new CircleSegment {
                CenterPoint = centerPoint.Value.Position,
                StartPoint  = r1Point,
                EndPoint    = r2Point,
            };

            points.AddRange(curve.Evaluate(0.05f));

            //Helpers function for creating prisms
            Action <IEnumerable <Vector2>, bool> unionPrism = (footprint, check) => geometry.Union(geometry
                                                                                                   .CreatePrism(material, footprint.ConvexHull().ToArray(), height)
                                                                                                   .Translate(new Vector3(0, this.GroundOffset(height), 0))
                                                                                                   .Transform(InverseWorldTransformation),
                                                                                                   check
                                                                                                   );

            //Materialize result
            unionPrism(points, false);

            //Extend straight sections to edge of node
            //We only need to do this if we were turning precisely about the contact points of these two roads
            if (centerPoint.Value.Position.TolerantEquals(innerPoint, 0.1f))
            {
                unionPrism(new[] {
                    r1Point,
                    innerPoint,
                    innerPoint - r1.Direction * r1.SidewalkWidth,
                    r1Point - r1.Direction * r1.SidewalkWidth
                }, true);

                unionPrism(new[] {
                    r2Point,
                    innerPoint,
                    innerPoint - r2.Direction * r2.SidewalkWidth,
                    r2Point - r2.Direction * r2.SidewalkWidth
                }, true);
            }
        }
Ejemplo n.º 5
0
        private void CreateFootpath2Outer(ISubdivisionGeometry geometry, string material, float height, IHalfEdgeBuilder r1, IHalfEdgeBuilder r2)
        {
            Contract.Requires(geometry != null);
            Contract.Requires(r1 != null);
            Contract.Requires(r2 != null);

            //r1.LeftEnd and r2.RightEnd are the outsides of the roads
            //Trace a path along the boundary between these points, use the path which does *not* include the other points
            Vector2[] cwp, ccwp;
            bool      cw, ccw;

            Bounds.Footprint.TraceConnectingPath(
                Vector3.Transform(r1.LeftEnd.X_Y(0), InverseWorldTransformation).XZ(),
                Vector3.Transform(r2.RightEnd.X_Y(0), InverseWorldTransformation).XZ(),
                0.01f, out cwp, out cw, out ccwp, out ccw,
                Vector3.Transform(r1.RightEnd.X_Y(0), InverseWorldTransformation).XZ(),
                Vector3.Transform(r2.LeftEnd.X_Y(0), InverseWorldTransformation).XZ());

            //Sanity check (only 1 direction should be acceptable)
            if (!(cw ^ ccw))
            {
                return;
            }

            //Follow along edge, then back along edge (pushed inwards by footpath width)
            //todo: Offset width by angle at end of road
            var outerPoints = cw ? cwp : ccwp;
            var innerPoints = new Vector2[cw ? cwp.Length : ccwp.Length];

            Contract.Assert(innerPoints.Length == outerPoints.Length);

            var widthStart = cw ? r1.SidewalkWidth : r2.SidewalkWidth;
            var widthEnd   = cw ? r2.SidewalkWidth : r1.SidewalkWidth;

            for (var i = 0; i < outerPoints.Length && outerPoints.Length > 1; i++)
            {
                Vector2 dir;
                float   w;
                if (i == 0)
                {
                    dir = Vector2.Normalize(cw ? r1.RightEnd - r1.LeftEnd : r2.LeftEnd - r2.RightEnd);
                    w   = CalculateFootpathAngleScale(cw ? r1.Direction : r2.Direction, dir, widthStart);
                }
                else if (i == outerPoints.Length - 1)
                {
                    dir = Vector2.Normalize(cw ? r2.LeftEnd - r2.RightEnd : r1.RightEnd - r1.LeftEnd);
                    w   = CalculateFootpathAngleScale(cw ? r2.Direction : r1.Direction, -dir, widthEnd);
                }
                else
                {
                    //perpendicular to path direction
                    dir = Vector2.Normalize(outerPoints[i] - outerPoints[i - 1]).Perpendicular() * (cw ? 1 : -1);
                    //Interpolate widths along path
                    var t = i / (float)(outerPoints.Length - 1);
                    w = MathHelper.Lerp(widthStart, widthEnd, t);
                }

                innerPoints[i] = outerPoints[i] + dir * w;
            }

            //Create footprint from 2 halves
            var footprint = cw ? outerPoints.Concat(innerPoints.Reverse()) : outerPoints.Reverse().Concat(innerPoints);

            geometry.Union(geometry
                           .CreatePrism(material, footprint.ToArray(), height)
                           .Translate(new Vector3(0, this.GroundOffset(height), 0))
                           );
        }
Ejemplo n.º 6
0
 public NWayJunctionEdgeData(IHalfEdgeBuilder builder)
 {
     Builder = builder;
 }