예제 #1
0
        // Add a new gap an an array of gaps. The resulting array is simplified. The original array may be null.
        public static         CircleGap[] AddGap(CircleGap[] original, float startAngle, float stopAngle)
        {
            CircleGap newGap;

            CircleGap[] newGaps;

            // Create the new gap.
            newGap = new CircleGap(startAngle, stopAngle);

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

            // Simplify
            return(SimplifyGaps(newGaps));
        }
예제 #2
0
        // Add a gap defined by two points. The gap is assumed to be <=180 degrees.
        public static         CircleGap[] AddGap(PointF center, CircleGap[] original, PointF pt1, PointF pt2)
        {
            if (center == pt1 || center == pt2)
            {
                return(original);
            }

            float angle1 = Geometry.Angle(center, pt1);
            float angle2 = Geometry.Angle(center, pt2);

            CircleGap.OrderGapAngles(ref angle1, ref angle2);
            return(AddGap(original, angle1, angle2));
        }
예제 #3
0
        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.
            CircleGap[] newGaps        = CircleGap.AddGap(courseObjStart.location, courseObjStart.gaps, startDrag, location);
            CircleGap[] newMovableGaps = CircleGap.AddGap(courseObjStart.location, courseObjStart.movableGaps, startDrag, location);

            // Put the new gaps into the highlight.
            courseObjDrag             = (PointCourseObj)courseObjStart.Clone();
            courseObjDrag.gaps        = newGaps;
            courseObjDrag.movableGaps = newMovableGaps;

            displayUpdateNeeded = true;
        }
예제 #4
0
        // Add a new gap an an array of gaps. The resulting array is simplified. The original array may be null.
        public static CircleGap[] AddGap(CircleGap[] original, float startAngle, float stopAngle)
        {
            CircleGap newGap;
            CircleGap[] newGaps;

            // Create the new gap.
            newGap = new CircleGap(startAngle, stopAngle);

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

            // Simplify
            return SimplifyGaps(newGaps);
        }
예제 #5
0
        // Move a gap start/stop point to a new location. Return the new gap array. The gap array is NOT simplified.
        public static         CircleGap[] MoveStartStopPoint(PointF center, float radius, CircleGap[] gaps, PointF oldPt, PointF newPt)
        {
            CircleGap[] newGaps = (CircleGap[])gaps.Clone();

            if (newPt != center)
            {
                for (int i = 0; i < newGaps.Length; ++i)
                {
                    PointF startPt = Geometry.MoveDistance(center, radius, gaps[i].startAngle);
                    PointF stopPt = Geometry.MoveDistance(center, radius, gaps[i].stopAngle);
                    float  newStart, newStop;

                    if (Geometry.Distance(startPt, oldPt) < 0.01)
                    {
                        // Moving start point of the gap.
                        newStart = Geometry.Angle(center, newPt);
                        newStop  = gaps[i].stopAngle;
                    }
                    else if (Geometry.Distance(stopPt, oldPt) < 0.01)
                    {
                        // Moving end point of the gap.
                        newStart = gaps[i].startAngle;
                        newStop  = Geometry.Angle(center, newPt);
                    }
                    else
                    {
                        continue;
                    }

                    if (OrderGapAngles(ref newStart, ref newStop))
                    {
                        float t = newStart; newStart = newStop; newStop = t;
                    }
                    newGaps[i] = new CircleGap(newStart, newStop);
                    break;
                }
            }

            return(newGaps);
        }
예제 #6
0
        // Add a gap defined by two points. The gap is assumed to be <=180 degrees.
        public static CircleGap[] AddGap(PointF center, CircleGap[] original, PointF pt1, PointF pt2)
        {
            if (center == pt1 || center == pt2)
                return original;

            float angle1 = Geometry.Angle(center, pt1);
            float angle2 = Geometry.Angle(center, pt2);
            CircleGap.OrderGapAngles(ref angle1, ref angle2);
            return AddGap(original, angle1, angle2);
        }
예제 #7
0
        // Return start and stop points of the gaps, as used by MapModel.
        public static float[] StartsAndStops(CircleGap[] gaps)
        {
            if (gaps == null || gaps.Length == 0)
                return null;

            float[] arcs = new float[gaps.Length * 2];
            for (int i = 0; i < gaps.Length; i += 1) {
                arcs[i * 2] = gaps[i].startAngle;
                arcs[i * 2 + 1] = gaps[i].stopAngle;
            }
            return arcs;
        }
예제 #8
0
        // Simplify a gap array. Sorts in order, combines overlapping gaps, and removes gaps before and beyond end of length.
        public static         CircleGap[] SimplifyGaps(CircleGap[] gaps)
        {
            if (gaps == null || gaps.Length == 0)
            {
                return(null);
            }

            List <CircleGap> newGaps = new List <CircleGap>();

            // Remove gaps that have start before end.
            // Simplify to end angle between 0 and 360, startAngle between -360 and end angle.
            int i;

            for (i = 0; i < gaps.Length; ++i)
            {
                if (gaps[i].stopAngle <= gaps[i].startAngle)
                {
                    continue;
                }

                float stop = gaps[i].stopAngle % 360.0F;
                if (stop < 0)
                {
                    stop += 360.0F;
                }
                float start = gaps[i].startAngle % 360.0F;
                if (start < 0)
                {
                    start += 360.0F;
                }
                if (start > stop)
                {
                    start -= 360.0F;
                }

                newGaps.Add(new CircleGap(start, stop));
            }

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

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

            // Last and first can overlap
            while (newGaps.Count >= 2 && newGaps[0].startAngle < newGaps[newGaps.Count - 1].stopAngle - 360.0F)
            {
                newGaps[0] = new CircleGap(newGaps[newGaps.Count - 1].startAngle - 360.0F, newGaps[0].stopAngle);
                newGaps.RemoveAt(newGaps.Count - 1);
            }

            // And we're done.
            return((newGaps.Count > 0) ? newGaps.ToArray() : null);
        }
예제 #9
0
        // Remove a gap (if any) from an array of gaps.
        public static CircleGap[] RemoveGap(CircleGap[] original, float angle)
        {
            angle = angle % 360F;
            if (angle < 0)
                angle += 360F;

            if (original == null)
                return null;

            List<CircleGap> newgaps = new List<CircleGap>(SimplifyGaps(original));
            for (int i = 0; i < newgaps.Count; ++i) {
                if ((newgaps[i].startAngle <= angle && newgaps[i].stopAngle >= angle) ||
                    (newgaps[i].startAngle <= angle-360F && newgaps[i].stopAngle >= angle-360F))
                    newgaps.RemoveAt(i);
            }

            if (newgaps.Count == 0)
                return null;
            else
                return newgaps.ToArray();
        }
예제 #10
0
        // Simplify a gap array. Sorts in order, combines overlapping gaps, and removes gaps before and beyond end of length.
        public static CircleGap[] SimplifyGaps(CircleGap[] gaps)
        {
            if (gaps == null || gaps.Length == 0)
                return null;

            List<CircleGap> newGaps = new List<CircleGap>();

            // Remove gaps that have start before end.
            // Simplify to end angle between 0 and 360, startAngle between -360 and end angle.
            int i;
            for (i = 0; i < gaps.Length; ++i) {
                if (gaps[i].stopAngle <= gaps[i].startAngle)
                    continue;

                float stop = gaps[i].stopAngle % 360.0F;
                if (stop < 0)
                    stop += 360.0F;
                float start = gaps[i].startAngle % 360.0F;
                if (start < 0)
                    start += 360.0F;
                if (start > stop)
                    start -= 360.0F;

                newGaps.Add(new CircleGap(start, stop));
            }

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

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

            // Last and first can overlap
            while (newGaps.Count >= 2 && newGaps[0].startAngle < newGaps[newGaps.Count - 1].stopAngle - 360.0F) {
                newGaps[0] = new CircleGap(newGaps[newGaps.Count - 1].startAngle - 360.0F, newGaps[0].stopAngle);
                newGaps.RemoveAt(newGaps.Count - 1);
            }

            // And we're done.
            return (newGaps.Count > 0) ? newGaps.ToArray() : null;
        }
예제 #11
0
        // Get the start/stop points of the gaps. Primarily useful for finding where the handles should be.
        public static PointF[] GapStartStopPoints(PointF center, float radius, CircleGap[] 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] = Geometry.MoveDistance(center, radius, gaps[i].startAngle);
                pts[i * 2 + 1] = Geometry.MoveDistance(center, radius, gaps[i].stopAngle);
            }

            return pts;
        }
예제 #12
0
        // Move a gap start/stop point to a new location. Return the new gap array. The gap array is NOT simplified.
        public static CircleGap[] MoveStartStopPoint(PointF center, float radius, CircleGap[] gaps, PointF oldPt, PointF newPt)
        {
            CircleGap[] newGaps = (CircleGap[])gaps.Clone();

            if (newPt != center) {
                for (int i = 0; i < newGaps.Length; ++i) {
                    PointF startPt = Geometry.MoveDistance(center, radius, gaps[i].startAngle);
                    PointF stopPt = Geometry.MoveDistance(center, radius, gaps[i].stopAngle);
                    float newStart, newStop;

                    if (Geometry.Distance(startPt, oldPt) < 0.01) {
                        // Moving start point of the gap.
                        newStart = Geometry.Angle(center, newPt);
                        newStop = gaps[i].stopAngle;
                    }
                    else if (Geometry.Distance(stopPt, oldPt) < 0.01) {
                        // Moving end point of the gap.
                        newStart = gaps[i].startAngle;
                        newStop = Geometry.Angle(center, newPt);
                    }
                    else {
                        continue;
                    }

                    if (OrderGapAngles(ref newStart, ref newStop)) {
                        float t = newStart; newStart = newStop; newStop = t;
                    }
                    newGaps[i] = new CircleGap(newStart, newStop);
                    break;
                }
            }

            return newGaps;
        }
예제 #13
0
        // Put the gaps into a old-style bit field approximating these gaps.
        public static uint ComputeApproximateOldStyleGaps(CircleGap[] gaps)
        {
            if (gaps == null || gaps.Length == 0)
                return 0xFFFFFFFF;              // no gaps

            uint bits = 0xFFFFFFFF;     // Start with all circle on.
            foreach (CircleGap gap in gaps) {
                // Go through each bit and determine if on or off.  A bit inefficient, but simple
                // to get right.
                for (int bitNum = 0; bitNum < 32; ++bitNum) {
                    float angle = (bitNum + 0.5F) * 360F / 32F;  // center point of gap represented by this bit
                    if ((angle >= gap.startAngle && angle <= gap.stopAngle) ||
                        ((angle - 360F) >= gap.startAngle && (angle - 360F) <= gap.stopAngle))
                    {
                        // Clear bit.
                        bits = Util.SetBit(bits, bitNum, false);
                    }
                }
            }

            return bits;
        }
예제 #14
0
        // Encode a gap array as text. Format is 45-180,181-185,...
        public static string EncodeGaps(CircleGap[] gaps)
        {
            if (gaps == null || gaps.Length == 0)
                return "";

            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < gaps.Length; ++i) {
                if (i != 0)
                    builder.Append(",");
                builder.AppendFormat(CultureInfo.InvariantCulture, "{0:R}:{1:R}", gaps[i].startAngle, gaps[i].stopAngle);
            }
            return builder.ToString();
        }
예제 #15
0
        // Remove a gap at a particular radians
        public static CircleGap[] RemoveGap(CircleGap[] start, double radians)
        {
            float angleInDegrees = (float)(180 * radians / Math.PI);

            return CircleGap.RemoveGap(start, angleInDegrees);
        }
예제 #16
0
        // Get a series of arc start angle/sweep angle pairs to draw a circle with the gaps. Gaps must be in simplified form.
        public static float[] ArcStartSweeps(CircleGap[] gaps)
        {
            if (gaps == null || gaps.Length == 0)
                return new float[2] { 0F, 360F };

            float[] arcs = new float[gaps.Length * 2];
            for (int i = 0; i < gaps.Length; i += 1) {
                float startArc = gaps[i].stopAngle;
                float endArc = (i == gaps.Length - 1) ? gaps[0].startAngle : gaps[i + 1].startAngle;
                arcs[i * 2] = -startArc;
                arcs[i * 2 + 1] = -((endArc - startArc + 360.0F) % 360.0F);
            }
            return arcs;
        }
예제 #17
0
 public ControlCourseObj(Id<ControlPoint> controlId, Id<CourseControl> courseControlId, float scaleRatio, CourseAppearance appearance, CircleGap[] gaps, PointF location)
     : base(controlId, courseControlId, Id<Special>.None, scaleRatio, appearance, gaps, 0, 3.0F, location)
 {
 }
예제 #18
0
        float radius; // radius of the object (for hit-testing) -- unscaled.

        #endregion Fields

        #region Constructors

        protected PointCourseObj(Id<ControlPoint> controlId, Id<CourseControl> courseControlId, Id<Special> specialId, float scaleRatio, CourseAppearance appearance, CircleGap[] gaps, float orientation, float radius, PointF location)
            : base(controlId, courseControlId, specialId, scaleRatio, appearance)
        {
            this.gaps = gaps;
            this.movableGaps = gaps;
            this.orientation = orientation;
            this.location = location;
            this.radius = radius;
        }
예제 #19
0
 public FinishCourseObj(Id<ControlPoint> controlId, Id<CourseControl> courseControlId, float scaleRatio, CourseAppearance appearance, 
     CircleGap[] gaps, PointF location, CrossHairOptions crossHairOptions)
     : base(controlId, courseControlId, Id<Special>.None, scaleRatio, appearance, gaps, 0, 3.5F, location)
 {
     this.crossHairOptions = crossHairOptions;
 }
예제 #20
0
        // Change the gaps of a control for a given scale.
        public static void ChangeControlGaps(EventDB eventDB, Id<ControlPoint> controlId, float scale, CircleGap[] newGaps)
        {
            ControlPoint control = eventDB.GetControl(controlId);

            control = (ControlPoint) control.Clone();

            int scaleInt = (int) Math.Round(scale);     // scale is stored as int in the gaps to prevent rounding problems.

            if (newGaps == null || newGaps.Length == 0) {
                if (control.gaps != null)
                    control.gaps.Remove(scaleInt);
            }
            else {
                if (control.gaps == null)
                    control.gaps = new Dictionary<int, CircleGap[]>();
                control.gaps[scaleInt] = newGaps;
            }

            eventDB.ReplaceControlPoint(controlId, control);
        }
예제 #21
0
 // Add a gap at a particular radians to a circle gaps.
 public static CircleGap[] AddGap(CircleGap[] gaps, double radians)
 {
     float angleInDegrees = (float)(180 * radians / Math.PI);
     const float gapAngle = 30;
     return CircleGap.AddGap(gaps, angleInDegrees - gapAngle / 2, angleInDegrees + gapAngle / 2);
 }