Beispiel #1
0
        // Add a new gap an an array of gaps. The resulting array is simplified. The original array may be null.
        public static LegGap[] AddGap(SymPath path, LegGap[] original, PointF pt1, PointF pt2)
        {
            float dist1, dist2;
            LegGap newGap;
            LegGap[] newGaps;

            // map points to closes points on the line.
            path.DistanceFromPoint(pt1, out pt1);
            path.DistanceFromPoint(pt2, out pt2);

            // Map to distances along the line.
            dist1 = path.LengthToPoint(pt1);
            dist2 = path.LengthToPoint(pt2);

            // Create the new gap.
            if (dist1 < dist2)
                newGap = new LegGap(dist1, dist2 - dist1);
            else
                newGap = new LegGap(dist2, dist1 - dist2);

            // Add to the old gaps.
            if (original == null)
                newGaps = new LegGap[1] { newGap };
            else {
                newGaps = new LegGap[original.Length + 1];
                Array.Copy(original, newGaps, original.Length);
                newGaps[original.Length] = newGap;
            }

            // Simplify
            return SimplifyGaps(newGaps, path.Length);
        }
        public override void LeftButtonDrag(Pane pane, PointF location, PointF locationStart, float pixelSize, ref bool displayUpdateNeeded)
        {
            Debug.Assert(pane == Pane.Map);

            // Get the new set of gaps.
            LegGap[] newGaps = LegGap.AddGap(courseObjStart.path, courseObjStart.gaps, startDrag, location);

            // Put the new gaps into the highlight.
            courseObjDrag = new LegCourseObj(courseObjStart.controlId, courseObjStart.courseControlId, courseObjStart.courseControlId2,
                                             courseObjStart.courseObjRatio, courseObjStart.appearance, courseObjStart.path, newGaps);

            displayUpdateNeeded = true;
        }
Beispiel #3
0
        // Add a new gap an an array of gaps. The resulting array is simplified. The original array may be null.
        public static LegGap[] AddGap(SymPath path, LegGap[] original, PointF pt1, PointF pt2)
        {
            float  dist1, dist2;
            LegGap newGap;

            LegGap[] newGaps;

            // map points to closes points on the line.
            path.DistanceFromPoint(pt1, out pt1);
            path.DistanceFromPoint(pt2, out pt2);

            // Map to distances along the line.
            dist1 = path.LengthToPoint(pt1);
            dist2 = path.LengthToPoint(pt2);

            // Create the new gap.
            if (dist1 < dist2)
            {
                newGap = new LegGap(dist1, dist2 - dist1);
            }
            else
            {
                newGap = new LegGap(dist2, dist1 - dist2);
            }

            // Add to the old gaps.
            if (original == null)
            {
                newGaps = new LegGap[1] {
                    newGap
                }
            }
            ;
            else
            {
                newGaps = new LegGap[original.Length + 1];
                Array.Copy(original, newGaps, original.Length);
                newGaps[original.Length] = newGap;
            }

            // Simplify
            return(SimplifyGaps(newGaps, path.Length));
        }
Beispiel #4
0
        // Split a path into multiple paths based on an array of LegGaps.  The gaps might extend beyond the end of the
        // or the beginning of the path. The gaps array need not be in simplified form.
        public static SymPath[] SplitPathWithGaps(SymPath pathInitial, LegGap[] gaps)
        {
            // Get the length of the path.
            float pathLength = pathInitial.Length;

            // Simply and sort the gaps.
            gaps = SimplifyGaps(gaps, pathLength);

            // If no gaps length, the entire path is correct.
            if (gaps == null)
                return new SymPath[1] { pathInitial };

            // Transform into start/stop distances from beginning of path.
            float[] starts = new float[gaps.Length + 1];
            float[] ends = new float[gaps.Length + 1];
            starts[0] = 0;
            ends[gaps.Length] = pathLength;
            for (int i = 0; i < gaps.Length; ++i) {
                ends[i] = gaps[i].distanceFromStart;
                starts[i + 1] = gaps[i].distanceFromStart + gaps[i].length;
            }

            // Each 2 points is a new path.
            List<SymPath> list = new List<SymPath>(starts.Length);
            for (int i = 0; i < starts.Length; ++i) {
                SymPath p = pathInitial.Segment(pathInitial.PointAtLength(starts[i]), pathInitial.PointAtLength(ends[i]));
                if (p != null)
                    list.Add(p);
            }

            return list.ToArray();
        }
Beispiel #5
0
        // Simplify a gap array. Sorts in order, combines overlapping gaps, and removes gaps before and beyond end of length.
        public static LegGap[] SimplifyGaps(LegGap[] gaps, float pathLength)
        {
            if (gaps == null || gaps.Length == 0)
                return null;

            List<LegGap> newGaps = new List<LegGap>(gaps);

            // Truncating to the length of the path. Doesn't remove gaps, but may set their length to negative, which
            // will cause them to be removed later.
            int i;
            for (i = 0; i < newGaps.Count; ++i) {
                if (newGaps[i].distanceFromStart + newGaps[i].length > pathLength) {
                    newGaps[i] = new LegGap(newGaps[i].distanceFromStart, pathLength - newGaps[i].distanceFromStart);
                }

                if (newGaps[i].distanceFromStart < 0) {
                    newGaps[i] = new LegGap(0, newGaps[i].length + newGaps[i].distanceFromStart);
                }
            }

            // Remove any gaps with 0 or negative length.
            i = 0;
            while (i < newGaps.Count) {
                if (newGaps[i].length <= 0)
                    newGaps.RemoveAt(i);
                else
                    ++i;
            }

            // Sort gaps by their start point.
            newGaps.Sort(delegate(LegGap gap1, LegGap gap2) {
                if (gap1.distanceFromStart < gap2.distanceFromStart)
                    return -1;
                else if (gap1.distanceFromStart > gap2.distanceFromStart)
                    return 1;
                else
                    return 0;
            });

            // Combine gaps that overlap.
            i = 0;
            while (i < newGaps.Count - 1) {
                if (newGaps[i].distanceFromStart + newGaps[i].length >= newGaps[i + 1].distanceFromStart) {
                    if (newGaps[i].distanceFromStart + newGaps[i].length < newGaps[i + 1].distanceFromStart + newGaps[i + 1].length)
                        newGaps[i] = new LegGap(newGaps[i].distanceFromStart, newGaps[i + 1].length + (newGaps[i + 1].distanceFromStart - newGaps[i].distanceFromStart));
                    newGaps.RemoveAt(i + 1);
                }
                else
                    ++i;
            }

            // And we're done.
            return (newGaps.Count > 0) ? newGaps.ToArray() : null;
        }
Beispiel #6
0
        // Move a gap start/stop point to a new location. Return the new gap array. The gap array is NOT simplified.
        public static LegGap[] MoveStartStopPoint(SymPath path, LegGap[] gaps, PointF oldPt, PointF newPt)
        {
            LegGap[] newGaps = (LegGap[]) gaps.Clone();
            float newLengthAlongPath = path.LengthToPoint(newPt);

            for (int i = 0; i < newGaps.Length; ++i) {
                PointF startPt = path.PointAtLength(gaps[i].distanceFromStart);
                PointF endPt = path.PointAtLength(gaps[i].distanceFromStart + gaps[i].length);

                if (Geometry.Distance(startPt, oldPt) < 0.01) {
                    // Moving start point of the gap.
                    newGaps[i].length -= (newLengthAlongPath - newGaps[i].distanceFromStart);
                    newGaps[i].distanceFromStart = newLengthAlongPath;
                }
                else if (Geometry.Distance(endPt, oldPt) < 0.01) {
                    // Moving end point of the gap.
                    newGaps[i].length = newLengthAlongPath - gaps[i].distanceFromStart;
                }
            }

            return newGaps;
        }
Beispiel #7
0
        // Transform a gap array to a new path, keeping close gaps in the closest position on the new path. Remove far away gaps.
        public static LegGap[] MoveGapsToNewPath(LegGap[] oldGaps, SymPath oldPath, SymPath newPath)
        {
            oldGaps = SimplifyGaps(oldGaps, oldPath.Length);
            if (oldGaps == null)
                return null;

            PointF oldStart, oldEnd, newStart, newEnd;  // ends points of the gaps
            float distanceStart, distanceEnd;  // distance between oldStart and newStart, distance between oldEnd and newEnd.
            List<LegGap> newGaps = new List<LegGap>();

            // Move gap to a new gap by converting start and end to point, finding closest points on new path.
            // If the gap has moved too far, just remove it, else transformit.
            for (int i = 0; i < oldGaps.Length; ++i) {
                oldStart = oldPath.PointAtLength(oldGaps[i].distanceFromStart);
                oldEnd = oldPath.PointAtLength(oldGaps[i].distanceFromStart + oldGaps[i].length);
                distanceStart = newPath.DistanceFromPoint(oldStart, out newStart);
                distanceEnd = newPath.DistanceFromPoint(oldEnd, out newEnd);

                // If the new gap is close enough to the old gap, then add the new gap.
                if (distanceStart + distanceEnd <= 2 * oldGaps[i].length) {
                    float newDistanceToStart = newPath.LengthToPoint(newStart);
                    float newDistanceToEnd = newPath.LengthToPoint(newEnd);
                    if (newDistanceToStart < newDistanceToEnd)
                        newGaps.Add(new LegGap(newDistanceToStart, newDistanceToEnd - newDistanceToStart));
                    else
                        newGaps.Add(new LegGap(newDistanceToEnd, newDistanceToStart - newDistanceToEnd));
                }
            }

            // Simply the new gap array.
            return SimplifyGaps(newGaps.ToArray(), newPath.Length);
        }
Beispiel #8
0
        /*
         * Static functions that work on arrays of leg gaps.
         */
        // Get the start/stop points of the gaps. Primarily useful for finding where the handles should be.
        public static PointF[] GapStartStopPoints(SymPath path, LegGap[] gaps)
        {
            if (gaps == null || gaps.Length == 0)
                return null;

            PointF[] pts = new PointF[gaps.Length * 2];
            for (int i = 0; i < gaps.Length; ++i) {
                pts[i * 2] = path.PointAtLength(gaps[i].distanceFromStart);
                pts[i * 2 + 1] = path.PointAtLength(gaps[i].distanceFromStart + gaps[i].length);
            }

            return pts;
        }
Beispiel #9
0
        // Simplify a gap array. Sorts in order, combines overlapping gaps, and removes gaps before and beyond end of length.
        public static LegGap[] SimplifyGaps(LegGap[] gaps, float pathLength)
        {
            if (gaps == null || gaps.Length == 0)
            {
                return(null);
            }

            List <LegGap> newGaps = new List <LegGap>(gaps);

            // Truncating to the length of the path. Doesn't remove gaps, but may set their length to negative, which
            // will cause them to be removed later.
            int i;

            for (i = 0; i < newGaps.Count; ++i)
            {
                if (newGaps[i].distanceFromStart + newGaps[i].length > pathLength)
                {
                    newGaps[i] = new LegGap(newGaps[i].distanceFromStart, pathLength - newGaps[i].distanceFromStart);
                }

                if (newGaps[i].distanceFromStart < 0)
                {
                    newGaps[i] = new LegGap(0, newGaps[i].length + newGaps[i].distanceFromStart);
                }
            }

            // Remove any gaps with 0 or negative length.
            i = 0;
            while (i < newGaps.Count)
            {
                if (newGaps[i].length <= 0)
                {
                    newGaps.RemoveAt(i);
                }
                else
                {
                    ++i;
                }
            }

            // Sort gaps by their start point.
            newGaps.Sort(delegate(LegGap gap1, LegGap gap2) {
                if (gap1.distanceFromStart < gap2.distanceFromStart)
                {
                    return(-1);
                }
                else if (gap1.distanceFromStart > gap2.distanceFromStart)
                {
                    return(1);
                }
                else
                {
                    return(0);
                }
            });

            // Combine gaps that overlap.
            i = 0;
            while (i < newGaps.Count - 1)
            {
                if (newGaps[i].distanceFromStart + newGaps[i].length >= newGaps[i + 1].distanceFromStart)
                {
                    if (newGaps[i].distanceFromStart + newGaps[i].length < newGaps[i + 1].distanceFromStart + newGaps[i + 1].length)
                    {
                        newGaps[i] = new LegGap(newGaps[i].distanceFromStart, newGaps[i + 1].length + (newGaps[i + 1].distanceFromStart - newGaps[i].distanceFromStart));
                    }
                    newGaps.RemoveAt(i + 1);
                }
                else
                {
                    ++i;
                }
            }

            // And we're done.
            return((newGaps.Count > 0) ? newGaps.ToArray() : null);
        }
Beispiel #10
0
        // Create a path from pt1 to pt2, with the given radius around the legs. If the leg would
        // be of zero length, return null. If bends is non-null, then the path should include those bends.
        // If gaps is non-null, updates the gaps by subtracting the radius from them.
        private static SymPath GetLegPath(PointF pt1, double radius1, PointF pt2, double radius2, PointF[] bends, LegGap[] gaps)
        {
            double legLength = Geometry.Distance(pt1, pt2);

            // Check for no leg.
            if (legLength <= radius1 + radius2)
                return null;

            int bendCount = (bends == null) ? 0 : bends.Length;
            PointF[] coords = new PointF[2 + bendCount];
            PointKind[] kinds = new PointKind[2 + bendCount];

            // Set the end points.
            coords[0] = Geometry.DistanceAlongLine(pt1, (bendCount > 0) ? bends[0] : pt2, radius1);
            coords[coords.Length - 1] = Geometry.DistanceAlongLine(pt2, (bendCount > 0) ? bends[bends.Length - 1] : pt1, radius2);

            // Set the bends.
            if (bendCount > 0)
                Array.Copy(bends, 0, coords, 1, bendCount);

            // Create the path.
            for (int i = 0; i < kinds.Length; ++i)
                kinds[i] = PointKind.Normal;

            // Update the gaps (if any).
            if (gaps != null) {
                for (int i = 0; i < gaps.Length; ++i)
                    gaps[i].distanceFromStart -= (float) radius1;
            }

            return new SymPath(coords, kinds);
        }
Beispiel #11
0
        // Create a path from pt1 to pt2, with a radius aroudn the points correct for the given control kind. If the leg would
        // be of zero length, return null. The controlIds for the start and end points are optional -- if supplied, they are used
        // to deal with bends and gaps. If either is None, then the legs don't use bends or gaps. Returns the gaps to used
        // with the radius subtracted from them.
        public static SymPath GetLegPath(EventDB eventDB, PointF pt1, ControlPointKind kind1, Id<ControlPoint> controlId1, PointF pt2, ControlPointKind kind2, Id<ControlPoint> controlId2, float scaleRatio, CourseAppearance appearance, out LegGap[] gaps)
        {
            PointF[] bends = null;
            gaps = null;

            // Get bends and gaps if controls were supplied.
            if (controlId1.IsNotNone && controlId2.IsNotNone) {
                Id<Leg> legId = QueryEvent.FindLeg(eventDB, controlId1, controlId2);
                Leg leg = (legId.IsNotNone) ? eventDB.GetLeg(legId) : null;

                // Get the path of the line.
                if (leg != null) {
                    bends = leg.bends;
                    gaps = QueryEvent.GetLegGaps(eventDB, controlId1, controlId2);
                }
            }

            return GetLegPath(pt1, GetLegRadius(kind1, scaleRatio, appearance), pt2, GetLegRadius(kind2, scaleRatio, appearance), bends, gaps);
        }
Beispiel #12
0
        float thickness; // thickness of the line  (unscaled)

        #endregion Fields

        #region Constructors

        protected LineCourseObj(Id<ControlPoint> controlId, Id<CourseControl> courseControlId, Id<CourseControl> courseControlId2, Id<Special> specialId, float scaleRatio, CourseAppearance appearance, float thickness, SymPath path, LegGap[] gaps)
            : base(controlId, courseControlId, specialId, scaleRatio, appearance)
        {
            this.courseControlId2 = courseControlId2;
               this.thickness = thickness;

               this.path = path;
               this.gaps = this.movableGaps = gaps;
        }
Beispiel #13
0
 public LegCourseObj(Id<ControlPoint> controlId, Id<CourseControl> courseControlId, Id<CourseControl> courseControlId2, float scaleRatio, CourseAppearance appearance, SymPath path, LegGap[] gaps)
     : base(controlId, courseControlId, courseControlId2, Id<Special>.None, scaleRatio, appearance, NormalCourseAppearance.lineThickness * appearance.lineWidth, path, gaps)
 {
 }
Beispiel #14
0
        // Change the gaps associated with a leg.
        public static void ChangeLegGaps(EventDB eventDB, Id<ControlPoint> controlId1, Id<ControlPoint> controlId2, LegGap[] newGaps)
        {
            // Get the leg object for this leg. Create one if needed.
            Id<Leg> legId = QueryEvent.FindLeg(eventDB, controlId1, controlId2);
            Leg leg;
            if (legId.IsNone)
                leg = new Leg(controlId1, controlId2);
            else
                leg = (Leg) eventDB.GetLeg(legId).Clone();

            // Change the gaps.
            leg.gaps = (newGaps == null) ? null : (LegGap[]) newGaps.Clone();

            // Write the change leg object to the event DB. If the leg is vacuous, could involve removing the leg.
            if (leg.IsVacuous()) {
                if (legId.IsNotNone)
                    eventDB.RemoveLeg(legId);
            }
            else {
                if (legId.IsNone)
                    eventDB.AddLeg(leg);
                else
                    eventDB.ReplaceLeg(legId, leg);
            }
        }