GetControl() public method

public GetControl ( Id controlId ) : ControlPoint
controlId Id
return ControlPoint
Example #1
0
        // Get the angle from the given control index to the next control.
        public static double ComputeAngleOut(EventDB eventDB, CourseView courseView, int controlIndex)
        {
            PointF pt1 = eventDB.GetControl(courseView.ControlViews[controlIndex].controlId).location;

            // Get index of next control.
            int nextControlIndex = courseView.GetNextControl(controlIndex);
            if (nextControlIndex < 0)
                return double.NaN;

            // By default, the location of the next control is the direction.
            PointF pt2 = eventDB.GetControl(courseView.ControlViews[nextControlIndex].controlId).location;

            // If there is a custom leg, then use the location of the first bend instead.
            Id<Leg> legId = QueryEvent.FindLeg(eventDB, courseView.ControlViews[controlIndex].controlId, courseView.ControlViews[nextControlIndex].controlId);
            if (legId.IsNotNone) {
                Leg leg = eventDB.GetLeg(legId);
                if (leg.bends != null && leg.bends.Length > 0)
                    pt2 = leg.bends[0];
            }

            return Math.Atan2(pt2.Y - pt1.Y, pt2.X - pt1.X);
        }
Example #2
0
        // Get all the locations in the course exception controlView.
        private static PointF[] GetOtherLocations(EventDB eventDB, CourseView courseView, CourseView.ControlView controlViewExcept)
        {
            List<PointF> list = new List<PointF>();

            foreach (CourseView.ControlView controlView in courseView.ControlViews) {
                if (controlView != controlViewExcept)
                    list.Add(eventDB.GetControl(controlView.controlId).location);
            }

            return list.ToArray();
        }
Example #3
0
        // Create an filtered All Controls view -- show controls from the control collection, but only includes some.
        // excludedCourses contains an array of course ids to excluded from the contgrols.
        // kindFilter, if non-null, limits the controls to this kind of controls.
        public static CourseView CreateFilteredAllControlsView(EventDB eventDB, CourseDesignator[] excludedCourses, ControlPointKind kindFilter, bool addSpecials, bool addDescription)
        {
            CourseView courseView = new CourseView(eventDB, CourseDesignator.AllControls);

            courseView.courseName = MiscText.AllControls;
            courseView.scoreColumn = -1;

            // Add every control to the course view, subject to the filters.
            foreach (Id<ControlPoint> controlId in eventDB.AllControlPointIds) {
                ControlPoint control = eventDB.GetControl(controlId);

                // Check if the control is filtered out.

                if (excludedCourses != null) {
                    // Filter excluded courses.
                    foreach (CourseDesignator excludedCourseDesignator in excludedCourses) {
                        if (QueryEvent.CourseUsesControl(eventDB, excludedCourseDesignator, controlId))
                            goto SKIP;
                    }
                }

                if (kindFilter != ControlPointKind.None) {
                    // Filter on control type.
                    if (control.kind != kindFilter)
                        goto SKIP;
                }

                // We are going to include this control in the collection.

                ControlView controlView = new ControlView();

                controlView.courseControlIds = new[] { Id<CourseControl>.None };
                controlView.controlId = controlId;

                // All controls doesn't have ordinals.
                controlView.ordinal = -1;

                controlView.joinIndex = -1;

                courseView.controlViews.Add(controlView);

               SKIP:        ;
            }

            // Sort the control views: first by kind, then by code.
            courseView.controlViews.Sort((view1, view2) => QueryEvent.CompareControlIds(eventDB, view1.controlId, view2.controlId));

            courseView.Finish();

            if (addSpecials) {
                // Add every special, regardless of courses it is on, except for descriptions. Descriptions are added to all
                // controls only if they appear in all courses (or specifically for the all controls view), and if "addDescription" is true
                foreach (Id<Special> specialId in eventDB.AllSpecialIds) {
                    Special special = eventDB.GetSpecial(specialId);
                    if (special.kind == SpecialKind.Descriptions) {
                        if (addDescription && QueryEvent.CourseContainsSpecial(eventDB, CourseDesignator.AllControls, specialId))
                            courseView.descriptionViews.Add(new DescriptionView(specialId, CourseDesignator.AllControls));
                    }
                    else
                        courseView.specialIds.Add(specialId);
                }
            }

            return courseView;
        }
Example #4
0
        // Find the SymPath of the path between controls, taking any bends into account. If no bends, the path is just the
        // simple path between the controls.
        public static SymPath GetLegPath(EventDB eventDB, Id<ControlPoint> controlId1, Id<ControlPoint> controlId2, Id<Leg> legId)
        {
            PointF location1 = eventDB.GetControl(controlId1).location;
            PointF location2 = eventDB.GetControl(controlId2).location;

            if (legId.IsNotNone) {
                Leg leg = eventDB.GetLeg(legId);
                Debug.Assert(leg.controlId1 == controlId1 && leg.controlId2 == controlId2);

                if (leg.bends != null) {
                    List<PointF> points = new List<PointF>();
                    points.Add(location1);
                    points.AddRange(leg.bends);
                    points.Add(location2);
                    return new SymPath(points.ToArray());
                }
            }

            // No bends.
            return new SymPath(new PointF[] { location1, location2 });
        }
Example #5
0
        // Get the gaps in a control for a given scale.
        // Returns null if no gaps defined for that scale.
        public static CircleGap[] GetControlGaps(EventDB eventDB, Id<ControlPoint> controlId, float scale)
        {
            int scaleInt = (int)Math.Round(scale);

            ControlPoint control = eventDB.GetControl(controlId);
            if (control.gaps == null)
                return null;
            else if (!control.gaps.ContainsKey(scaleInt))
                return null;
            else {
                return control.gaps[scaleInt];
            }
        }
Example #6
0
        // Find the control with a code, and return its ID. Else return None.
        public static Id<ControlPoint> FindCode(EventDB eventDB, string code)
        {
            if (string.IsNullOrWhiteSpace(code))
                return Id<ControlPoint>.None;

            foreach (Id<ControlPoint> controlId in eventDB.AllControlPointIds) {
                if (eventDB.GetControl(controlId).code == code)
                    return controlId;
            }

            return Id<ControlPoint>.None;
        }
Example #7
0
        // Compute the length of a leg between two controls, in meters. The indicated leg id, if non-zero, is used
        // to get bend information. The event map scale converts between the map scale, in mm, which is used
        // for the coordinate information, to meters in the world scale.
        public static float ComputeLegLength(EventDB eventDB, Id<ControlPoint> controlId1, Id<ControlPoint> controlId2, Id<Leg> legId)
        {
            PointF location1 = eventDB.GetControl(controlId1).location;
            PointF location2 = eventDB.GetControl(controlId2).location;

            SymPath path = GetLegPath(eventDB, controlId1, controlId2, legId);
            return (float)((eventDB.GetEvent().mapScale * path.Length) / 1000.0);
        }
Example #8
0
        // Compare control ID by kind and code.
        public static int CompareControlIds(EventDB eventDB, Id<ControlPoint> controlId1, Id<ControlPoint> controlId2)
        {
            ControlPoint control1 = eventDB.GetControl(controlId1);
            ControlPoint control2 = eventDB.GetControl(controlId2);
            if (control1.kind < control2.kind)
                return -1;
            else if (control1.kind > control2.kind)
                return 1;

            int result = Util.CompareCodes(control1.code, control2.code);
            if (result != 0)
                return result;

            return controlId1.id.CompareTo(controlId2.id);
        }
Example #9
0
        // Get missing points.
        List<MissingThing> MissingScores(EventDB eventDB)
        {
            List<MissingThing> missingScores = new List<MissingThing>();

            foreach (Id<Course> courseId in QueryEvent.SortedCourseIds(eventDB)) {
                Course course = eventDB.GetCourse(courseId);
                bool anyScores = false;
                List<MissingThing> missingScoresThisCourse = new List<MissingThing>();

                if (course.kind == CourseKind.Score) {
                    for (Id<CourseControl> courseControlId = course.firstCourseControl;
                          courseControlId.IsNotNone;
                          courseControlId = eventDB.GetCourseControl(courseControlId).nextCourseControl)
                    {
                        CourseControl courseControl = eventDB.GetCourseControl(courseControlId);

                        if (eventDB.GetControl(courseControl.control).kind == ControlPointKind.Normal) {
                            if (courseControl.points <= 0)
                                missingScoresThisCourse.Add(new MissingThing(courseId, courseControl.control, ReportText.EventAudit_MissingScore));
                            else
                                anyScores = true;
                        }
                    }

                    if (anyScores)
                        missingScores.AddRange(missingScoresThisCourse);  // only report missing scores if some control in this course has a score.
                }
            }

            return missingScores;
        }
Example #10
0
        // Get missing punches.
        List<MissingThing> MissingPunches(EventDB eventDB, List<Id<ControlPoint>> unusedControls)
        {
            List<MissingThing> missingPunches = new List<MissingThing>();

            bool anyPunches = false;    // Keep track if any controls have non-empty punch pattersn.
            foreach (Id<ControlPoint> controlId in eventDB.AllControlPointIds) {
                if (unusedControls.Contains(controlId))
                    continue;

                ControlPoint control = eventDB.GetControl(controlId);
                if (control.kind != ControlPointKind.Normal)
                    continue;

                if (control.punches == null || control.punches.IsEmpty)
                    missingPunches.Add(new MissingThing(controlId, ReportText.EventAudit_MissingPunch));
                else
                    anyPunches = true;
            }

            if (anyPunches) {
                missingPunches.Sort((thing1, thing2) => QueryEvent.CompareControlIds(eventDB, thing1.controlId, thing2.controlId));
                return missingPunches;
            }
            else {
                // No controls had punch patterns defined. This event clearly is not using punches.
                return new List<MissingThing>();
            }
        }
Example #11
0
        // Get missing description boxes.
        List<MissingThing> MissingDescriptionBoxes(EventDB eventDB, List<Id<ControlPoint>> unusedControls)
        {
            List<MissingThing> missingBoxes = new List<MissingThing>();

            foreach (Id<ControlPoint> controlId in eventDB.AllControlPointIds) {
                // Go through all regular or start controls that are in use.
                if (unusedControls.Contains(controlId))
                    continue;

                ControlPoint control = eventDB.GetControl(controlId);
                if (control.kind != ControlPointKind.Normal && control.kind != ControlPointKind.Start)
                    continue;

                // If a start control is completely empty, don't process it.
                if (control.kind == ControlPointKind.Start) {
                    if (! Array.Exists(control.symbolIds, id => !string.IsNullOrEmpty(id)))
                        continue;
                }

                // Each start or normal control has 6 boxes. C==0, D==1, E==2, F==3, G==4, H==5
                Debug.Assert(control.symbolIds.Length == 6);

                if (string.IsNullOrEmpty(control.symbolIds[1])) {
                    missingBoxes.Add(new MissingThing(controlId, "D", ReportText.EventAudit_MissingD));
                }
                else if (! string.IsNullOrEmpty(control.symbolIds[3]) && string.IsNullOrEmpty(control.symbolIds[2])) {
                    missingBoxes.Add(new MissingThing(controlId, "E", ReportText.EventAudit_MissingEJunction));
                }
                else if (control.symbolIds[4] == "11.15" && string.IsNullOrEmpty(control.symbolIds[2])) {
                    missingBoxes.Add(new MissingThing(controlId, "E", ReportText.EventAudit_MissingEBetween));
                }
            }

            missingBoxes.Sort(((thing1, thing2) => QueryEvent.CompareControlIds(eventDB, thing1.controlId, thing2.controlId)));
            return missingBoxes;
        }
Example #12
0
        // Get all the control IDs to cross-ref, in the correct order.
        private Id<ControlPoint>[] GetControlIdsToXref(EventDB eventDB)
        {
            // Only cross-ref regular controls. Then sort by code.
            List<Id<ControlPoint>> list = new List<Id<ControlPoint>>();

            foreach (Id<ControlPoint> controlId in eventDB.AllControlPointIds) {
                if (eventDB.GetControl(controlId).kind == ControlPointKind.Normal)
                    list.Add(controlId);
            }

            list.Sort(delegate(Id<ControlPoint> id1, Id<ControlPoint> id2) {
                ControlPoint control1 = eventDB.GetControl(id1), control2 = eventDB.GetControl(id2);
                return Util.CompareCodes(control1.code, control2.code);
            });

            return list.ToArray();
        }
Example #13
0
        // Return a list of all controls that are nearby each other. It is sorted in order of distance.
        private List<NearbyControls> FindNearbyControls(EventDB eventDB, float distanceLimit)
        {
            ICollection<Id<ControlPoint>> allPoints = eventDB.AllControlPointIds;
            List<NearbyControls> list = new List<NearbyControls>();

            // Go through every pair of normal controls. If the distance between them is less than the distance limit, add to the list.
            foreach (Id<ControlPoint> controlId1 in allPoints) {
                ControlPoint control1 = eventDB.GetControl(controlId1);
                if (control1.kind != ControlPointKind.Normal)
                    continue;     // only deal with normal points.
                string symbol1 = SymbolOfControl(control1);

                // Check all other controls with greater ids (so each pair considered only once)
                foreach (Id<ControlPoint> controlId2 in allPoints) {
                    ControlPoint control2 = eventDB.GetControl(controlId2);
                    if (control2.kind != ControlPointKind.Normal || controlId2.id <= controlId1.id)
                        continue;     // only deal with normal points with greater id.
                    string symbol2 = SymbolOfControl(control2);

                    float distance = QueryEvent.ComputeStraightLineControlDistance(eventDB, controlId1, controlId2);

                    if (distance < distanceLimit) {
                        NearbyControls nearbyControls;
                        nearbyControls.controlId1 = controlId1;
                        nearbyControls.controlId2 = controlId2;
                        nearbyControls.distance = distance;
                        nearbyControls.sameSymbol = (symbol1 != null && symbol2 != null && symbol1 == symbol2); // only same symbol if both have symbols!
                        list.Add(nearbyControls);
                    }
                }
            }

            // Sort the list by distance.
            list.Sort((x1, x2) => x1.distance.CompareTo(x2.distance));

            return list;
        }
Example #14
0
        internal string CreateCrossReferenceReport(EventDB eventDB)
        {
            InitReport();

            // Header.
            WriteH1(string.Format(ReportText.CrossRef_Title, QueryEvent.GetEventTitle(eventDB, " ")));

            Id<ControlPoint>[] controlsToXref = GetControlIdsToXref(eventDB);
            Id<Course>[] coursesToXref = QueryEvent.SortedCourseIds(eventDB);
            string[,] xref = CreateXref(eventDB, controlsToXref, coursesToXref);

            string[] classes = new string[coursesToXref.Length + 1];
            classes[0] = "leftalign";
            for (int i = 1; i < classes.Length; ++i)
                classes[i] = "rightalign";

            BeginTable("", classes.Length, classes);

            // Write the header row.
            BeginTableRow();
            WriteTableHeaderCell(ReportText.ColumnHeader_Control);
            for (int i = 0; i < coursesToXref.Length; ++i)
                WriteTableHeaderCell(eventDB.GetCourse(coursesToXref[i]).name);
            EndTableRow();

            // Write the cross-reference rows. Table rule after every 3rd line
            for (int row = 0; row < controlsToXref.Length; ++row) {
                bool tablerule = (row % 3 == 2);
                BeginTableRow();
                WriteTableCell(tablerule ? "tablerule" : "", eventDB.GetControl(controlsToXref[row]).code);
                for (int col = 0; col < coursesToXref.Length; ++col)
                    WriteTableCell(tablerule ? "tablerule" : "", xref[row, col]);
                EndTableRow();
            }

            EndTable();

            return FinishReport();
        }
Example #15
0
        // Create a report showing missing things
        public string CreateEventAuditReport(EventDB eventDB)
        {
            bool problemFound = false;

            // Initialize the report
            InitReport();

            // Header.
            WriteH1(string.Format(ReportText.EventAudit_Title, QueryEvent.GetEventTitle(eventDB, " ")));

            // Courses missing things. Climb (not score course), start, finish (not score course), competitor load.
            List<MissingThing> missingCourseThings = MissingCourseThings(eventDB);
            if (missingCourseThings.Count > 0) {
                problemFound = true;

                WriteH2(ReportText.EventAudit_MissingItems);
                BeginTable("", 3, "leftalign", "leftalign", "leftalign");
                WriteTableHeaderRow(ReportText.ColumnHeader_Course, ReportText.ColumnHeader_Item, ReportText.ColumnHeader_Reason);
                foreach (MissingThing thing in missingCourseThings) {
                    WriteTableRow(eventDB.GetCourse(thing.courseId).name, thing.what, thing.why);
                }
                EndTable();
            }

            // Close together controls.
            float DISTANCE_LIMIT = 100.4999F;       // limit of distance for close controls (100m, when rounded).
            List<NearbyControls> nearbyList = FindNearbyControls(eventDB, DISTANCE_LIMIT);
            if (nearbyList.Count > 0) {
                problemFound = true;

                // Informational text.
                WriteH2(ReportText.EventAudit_CloseTogetherControls);
                StartPara();
                WriteText(string.Format(ReportText.EventAudit_CloseTogetherExplanation, Math.Round(DISTANCE_LIMIT)));
                EndPara();

                // The report.
                BeginTable("", 3, "leftalign", "rightalign", "leftalign");
                WriteTableHeaderRow(ReportText.ColumnHeader_ControlCodes, ReportText.ColumnHeader_Distance, ReportText.ColumnHeader_SameSymbol);

                foreach (NearbyControls nearby in nearbyList) {
                    string code1 = eventDB.GetControl(nearby.controlId1).code;
                    string code2 = eventDB.GetControl(nearby.controlId2).code;
                    if (Util.CompareCodes(code1, code2) > 0) {
                        // swap code1 and code 2 so they always appear in order.
                        string temp = code1;
                        code1 = code2;
                        code2 = temp;
                    }

                    WriteTableRow(string.Format("{0}, {1}", code1, code2), string.Format("{0} m", Math.Round(nearby.distance)), nearby.sameSymbol ? ReportText.EventAudit_Yes : ReportText.EventAudit_No);
                }

                EndTable();
            }

            // Unused controls.
            List<Id<ControlPoint>> unusedControls = SortedUnusedControls(eventDB);
            if (unusedControls.Count > 0) {
                problemFound = true;

                WriteH2(ReportText.EventAudit_UnusedControls);
                StartPara();
                WriteText(ReportText.EventAudit_UnusedControlsExplanation);
                EndPara();
                BeginTable("", 2, "leftalign", "leftalign");
                WriteTableHeaderRow(ReportText.ColumnHeader_Code, ReportText.ColumnHeader_Location);
                foreach (Id<ControlPoint> controlId in unusedControls) {
                    ControlPoint control = eventDB.GetControl(controlId);
                    WriteTableRow(Util.ControlPointName(eventDB, controlId, NameStyle.Medium), string.Format("({0}, {1})", Math.Round(control.location.X), Math.Round(control.location.Y)));
                }
                EndTable();
            }

            // Missing descriptions boxes (regular controls only). Missing column D. Missing column E when between/junction/crossing used. Missing between/junction/crossing when column E is a symbol.
            List<MissingThing> missingBoxes = MissingDescriptionBoxes(eventDB, unusedControls);
            if (missingBoxes.Count > 0) {
                problemFound = true;

                WriteH2(ReportText.EventAudit_MissingBoxes);
                BeginTable("", 3, "leftalign", "leftalign", "leftalign");
                WriteTableHeaderRow(ReportText.ColumnHeader_Code, ReportText.ColumnHeader_Column, ReportText.ColumnHeader_Reason);
                foreach (MissingThing thing in missingBoxes) {
                    WriteTableRow(Util.ControlPointName(eventDB, thing.controlId, NameStyle.Medium), thing.what, thing.why);
                }
                EndTable();
            }

            // Missing punches.
            List<MissingThing> missingPunches = MissingPunches(eventDB, unusedControls);
            if (missingPunches.Count > 0) {
                problemFound = true;

                WriteH2(ReportText.EventAudit_MissingPunchPatterns);
                BeginTable("", 2, "leftalign", "leftalign");
                WriteTableHeaderRow(ReportText.ColumnHeader_Code, ReportText.ColumnHeader_Reason);
                foreach (MissingThing thing in missingPunches) {
                    WriteTableRow(Util.ControlPointName(eventDB, thing.controlId, NameStyle.Medium), thing.what);
                }
                EndTable();
            }

            // Missing points (score course only)
            List<MissingThing> missingScores = MissingScores(eventDB);
            if (missingScores.Count > 0) {
                problemFound = true;

                WriteH2(ReportText.EventAudit_MissingScores);
                BeginTable("", 3, "leftalign", "leftalign", "leftalign");
                WriteTableHeaderRow(ReportText.ColumnHeader_Course, ReportText.ColumnHeader_Control, ReportText.ColumnHeader_Reason);
                foreach (MissingThing thing in missingScores) {
                    WriteTableRow(eventDB.GetCourse(thing.courseId).name, Util.ControlPointName(eventDB, thing.controlId, NameStyle.Medium), thing.what);
                }
                EndTable();
            }

            // If none of the above, then "no problems found".
            if (!problemFound) {
                StartPara();
                WriteText(ReportText.EventAudit_NoProblems);
                EndPara();
            }

            return FinishReport();
        }
Example #16
0
        // Get the last course control in a course. In dontReturnFinish is true, will never return a finish control, but
        // always the control before the finish. Returns None if the course has no controls (or only a finish control.)
        public static Id<CourseControl> LastCourseControl(EventDB eventDB, Id<Course> courseId, bool dontReturnFinish)
        {
            Id<CourseControl> last = Id<CourseControl>.None;

            foreach (Id<CourseControl> courseControlId in EnumCourseControlIds(eventDB, new CourseDesignator(courseId))) {
                if (!dontReturnFinish || eventDB.GetControl(eventDB.GetCourseControl(courseControlId).control).kind != ControlPointKind.Finish)
                    last = courseControlId;
            }

            return last;
        }
Example #17
0
        // Determine if you should warn about moving a shared course control. If a normal control is being
        // moved more than 75 meters, and is in other courses, then warn.
        // Returns null to not warn, or array of other courses to warn.
        public static Id<Course>[] ShouldWarnAboutMovingControl(EventDB eventDB, Id<Course> courseId, Id<CourseControl> courseControlId, PointF newLocation)
        {
            Id<ControlPoint> controlId = eventDB.GetCourseControl(courseControlId).control;

            Debug.Assert(CourseUsesControl(eventDB, new CourseDesignator(courseId), controlId));

            if (eventDB.GetControl(controlId).kind != ControlPointKind.Normal)
                return null;

            float distance = DistanceBetweenPointsInMeters(eventDB, eventDB.GetControl(controlId).location, newLocation);
            if (distance < MOVE_THRESHOLD)
                return null;

            List<Id<Course>> list = new List<Id<Course>>();

            foreach (Id<Course> containingCourseId in SortedCourseIds(eventDB)) {
                if (containingCourseId != courseId &&
                    CourseUsesControl(eventDB, new CourseDesignator(containingCourseId), controlId)) {
                    list.Add(containingCourseId);
                }
            }

            if (list.Count == 0)
                return null;
            else
                return list.ToArray();
        }
Example #18
0
        void WriteControlLoadSection(EventDB eventDB)
        {
            List<ControlLoadInfo> loadInfos = new List<ControlLoadInfo>();

            // Get load information about each control.
            foreach (Id<ControlPoint> controlId in eventDB.AllControlPointIds) {
                ControlPoint control = eventDB.GetControl(controlId);

                if (control.kind != ControlPointKind.Normal)
                    continue;     // only list normal controls.

                ControlLoadInfo loadInfo = new ControlLoadInfo();

                loadInfo.controlId = controlId;
                loadInfo.controlName = Util.ControlPointName(eventDB, controlId, NameStyle.Medium);
                loadInfo.numCourses = QueryEvent.CoursesUsingControl(eventDB, controlId).Length;
                loadInfo.load = QueryEvent.GetControlLoad(eventDB, controlId);

                loadInfos.Add(loadInfo);
            }

            // Sort the load information, first by load, then by number of courses, then by name.
            loadInfos.Sort(delegate(ControlLoadInfo loadInfo1, ControlLoadInfo loadInfo2) {
                if (loadInfo1.load < loadInfo2.load) return 1;
                else if (loadInfo1.load > loadInfo2.load) return -1;

                if (loadInfo1.numCourses < loadInfo2.numCourses) return 1;
                else if (loadInfo1.numCourses > loadInfo2.numCourses) return -1;

                int result = Util.CompareCodes(loadInfo1.controlName, loadInfo2.controlName);
                if (result != 0)
                    return result;

                return loadInfo1.controlId.id.CompareTo(loadInfo2.controlId.id);
            });

            // Write the table.
            BeginTable("", 3, "leftalign", "rightalign", "rightalign");
            WriteTableHeaderRow(ReportText.ColumnHeader_Control, ReportText.ColumnHeader_NumberOfCourses, ReportText.ColumnHeader_Load);

            foreach (ControlLoadInfo loadInfo in loadInfos) {
                WriteTableRow(loadInfo.controlName,
                                        Convert.ToString(loadInfo.numCourses),
                                        loadInfo.load >= 0 ? Convert.ToString(loadInfo.load) : "");
            }

            EndTable();
        }
Example #19
0
        // Similar to ComputeLegLength. However, if the leg is flagged partially, only the length of the flagged portion is returned.
        // Note: if the flagging is NONE, this still returns the length of the whole leg!
        public static float ComputeFlaggedLegLength(EventDB eventDB, Id<ControlPoint> controlId1, Id<ControlPoint> controlId2, Id<Leg> legId)
        {
            PointF location1 = eventDB.GetControl(controlId1).location;
            PointF location2 = eventDB.GetControl(controlId2).location;
            PointF[] bends = null;
            Leg leg = null;

            if (legId.IsNotNone) {
                leg = eventDB.GetLeg(legId);
                Debug.Assert(leg.controlId1 == controlId1 && leg.controlId2 == controlId2);
                bends = leg.bends;
            }

            if (bends == null) {
                return (float)((eventDB.GetEvent().mapScale * Geometry.Distance(location1, location2)) / 1000.0);
            }
            else {
                List<PointF> points = new List<PointF>();
                int bendIndexStart, bendIndexStop;

                points.Add(location1);
                points.AddRange(bends);
                points.Add(location2);

                // Which part is flagged?
                if (leg.flagging == FlaggingKind.Begin) {
                    bendIndexStart = 0; bendIndexStop = points.IndexOf(leg.flagStartStop);
                }
                else if (leg.flagging == FlaggingKind.End) {
                    bendIndexStart = points.IndexOf(leg.flagStartStop); bendIndexStop = points.Count - 1;
                }
                else {
                    bendIndexStart = 0; bendIndexStop = points.Count - 1;
                }

                double dist = 0;

                for (int i = bendIndexStart + 1; i <= bendIndexStop; ++i)
                    dist += Geometry.Distance(points[i - 1], points[i]);

                return (float)((eventDB.GetEvent().mapScale * dist) / 1000.0);
            }
        }
Example #20
0
        private void WriteLegLengthTable(EventDB eventDB, CourseView courseView)
        {
            BeginTable("", 3, "leftalign", "leftalign", "rightalign");
            WriteTableHeaderRow(ReportText.ColumnHeader_Leg, ReportText.ColumnHeader_Controls, ReportText.ColumnHeader_Length);

            // Go through the control views.
            int controlViewIndex = 0;
            float distanceThisLeg = 0;
            float totalLegs = 0;
            int legNumber = 1;
            Id<ControlPoint> controlIdPrev = Id<ControlPoint>.None;

            while (controlViewIndex >= 0 && controlViewIndex < courseView.ControlViews.Count) {
                CourseView.ControlView controlView = courseView.ControlViews[controlViewIndex];
                ControlPointKind kind = eventDB.GetControl(controlView.controlId).kind;

                // Don't report crossing points.
                if (kind != ControlPointKind.CrossingPoint) {
                    if (controlIdPrev.IsNotNone) {
                        string legText = string.Format("{0}\u2013{1}", Util.ControlPointName(eventDB, controlIdPrev, NameStyle.Medium), Util.ControlPointName(eventDB, controlView.controlId, NameStyle.Medium));
                        WriteTableRow(Convert.ToString(legNumber), legText, string.Format("{0} m", Math.Round(distanceThisLeg)));
                        totalLegs += distanceThisLeg;
                        legNumber += 1;
                    }

                    controlIdPrev = controlView.controlId;
                    distanceThisLeg = 0;
                }

                if (controlView.legLength != null)
                    distanceThisLeg += controlView.legLength[0];

                controlViewIndex = courseView.GetNextControl(controlViewIndex);
            }

            // Write average row
            if (legNumber > 1) {
                BeginTableRow("summaryrow");
                WriteSpannedTableCell(2, ReportText.LegLength_Average);
                WriteTableCell(string.Format("{0} m", Convert.ToString(Math.Round(totalLegs / (float) (legNumber - 1)))));
                EndTableRow();
            }

            EndTable();
        }
Example #21
0
        // Compute the distance between two control points, in meters. The controls need not be part of a leg, and if they are, bends
        // in the leg are NOT taken into account.
        public static float ComputeStraightLineControlDistance(EventDB eventDB, Id<ControlPoint> controlId1, Id<ControlPoint> controlId2)
        {
            PointF location1 = eventDB.GetControl(controlId1).location;
            PointF location2 = eventDB.GetControl(controlId2).location;

            return DistanceBetweenPointsInMeters(eventDB, location1, location2);
        }
Example #22
0
        // Create highlights to and from a point to course controls. If controlDrag is set (optional), it is
        // used to get the correct bends for legs.
        // Static because it is used from DragControlMode also.
        public static CourseObj[] CreateLegHighlights(EventDB eventDB, PointF newPoint, Id<ControlPoint>controlDrag, ControlPointKind controlKind, Id<CourseControl> courseControlId1, Id<CourseControl> courseControlId2, float scaleRatio, CourseAppearance appearance)
        {
            List<CourseObj> highlights = new List<CourseObj>();

            if (courseControlId1.IsNotNone) {
                Id<ControlPoint> controlId1 = eventDB.GetCourseControl(courseControlId1).control;
                ControlPoint control1 = eventDB.GetControl(controlId1);
                LegCourseObj highlight = CreateLegHighlight(eventDB, control1.location, control1.kind, controlId1, newPoint, controlKind, controlDrag, scaleRatio, appearance);
                if (highlight != null)
                    highlights.Add(highlight);
            }

            if (courseControlId2.IsNotNone) {
                Id<ControlPoint> controlId2 = eventDB.GetCourseControl(courseControlId2).control;
                ControlPoint control2 = eventDB.GetControl(controlId2);
                LegCourseObj highlight = CreateLegHighlight(eventDB, newPoint, controlKind, controlDrag, control2.location, control2.kind, controlId2, scaleRatio, appearance);
                if (highlight != null)
                    highlights.Add(highlight);
            }

            return highlights.ToArray();
        }
Example #23
0
        // Finds where a new regular control would be inserted into an existing course. courseControl1 and courseControl2 can either or both be none, to identify
        // a leg to insert into, a control to insert after, or no information about where to insert. Updates courseControl1 and courseControl2 to identify exactly
        // where on the course the control should be inserted as follows:
        //     If inserting between two course controls -- these are denoted by courseControl1 and courseControl2
        //     If inserting as last course control -- courseControl1 is the current last control and courseControl2 is None  (only occurs when there is no finish)
        //     If inserting as first course control -- courseControl2 is None and courseControl2 is current first control (only occurs when there is no start)
        //     If inserting as only course control -- both are none (only occurs if course is currently empty)
        public static void FindControlInsertionPoint(EventDB eventDB, CourseDesignator courseDesignator, ref Id<CourseControl> courseControl1, ref Id<CourseControl> courseControl2)
        {
            Id<Course> courseId = courseDesignator.CourseId;

            if (courseControl1.IsNotNone && courseControl2.IsNotNone) {
                CourseControl cc1 = eventDB.GetCourseControl(courseControl1);
                CourseControl cc2 = eventDB.GetCourseControl(courseControl2);

                if (cc1.nextCourseControl != courseControl2) {
                    Debug.Assert(cc2.split && cc2.splitCourseControls.Contains(courseControl2));
                    courseControl2 = cc1.nextCourseControl;
                }

                return;
            }
            else {
                // Adding after courseControl1. If none, or a finish control, add at end, before the finish control if any.
                if (courseControl1.IsNone || eventDB.GetControl(eventDB.GetCourseControl(courseControl1).control).kind == ControlPointKind.Finish)
                    courseControl1 = QueryEvent.LastCourseControl(eventDB, courseId, true);

                if (courseControl1.IsNone) {
                    // Empty course or adding at start.
                    courseControl2 = eventDB.GetCourse(courseId).firstCourseControl;
                    return;
                }
                else {
                    // Adding after courseControl1.
                    CourseControl before = (CourseControl)eventDB.GetCourseControl(courseControl1);
                    courseControl2 = before.nextCourseControl;
                    return;
                }
            }
        }
        // Describe a control point.
        private static TextPart[] DescribeControlPoint(SymbolDB symbolDB, EventDB eventDB, Id<ControlPoint> controlId, DescKind descKind)
        {
            Debug.Assert(descKind == DescKind.DescPane || descKind == DescKind.Tooltip);

            List<TextPart> list = new List<TextPart>();
            ControlPoint control = eventDB.GetControl(controlId);

            // Control name/code.
            list.Add(new TextPart(TextFormat.Title, Util.ControlPointName(eventDB, controlId, NameStyle.Long)));

            // Control location.
            if (descKind == DescKind.DescPane) {
                list.Add(new TextPart(TextFormat.Header, SelectionDescriptionText.Location + "  "));
                list.Add(new TextPart(TextFormat.SameLine, string.Format("({0:##0.0}, {1:##0.0})", control.location.X, control.location.Y)));
            }

            // Which courses is it used in?
            list.Add(new TextPart(TextFormat.Header, (descKind == DescKind.Tooltip ? SelectionDescriptionText.UsedIn : SelectionDescriptionText.UsedInCourses)));
            Id<Course>[] coursesUsingControl = QueryEvent.CoursesUsingControl(eventDB, controlId);
            list.Add(new TextPart(descKind == DescKind.Tooltip ? TextFormat.SameLine : TextFormat.NewLine, CourseListText(eventDB, coursesUsingControl)));

            // What is the competitor load?
            int load = QueryEvent.GetControlLoad(eventDB, controlId);
            if (load >= 0) {
                list.Add(new TextPart(TextFormat.Header, (descKind == DescKind.Tooltip ? SelectionDescriptionText.Load : SelectionDescriptionText.CompetitorLoad)));
                list.Add(new TextPart(TextFormat.SameLine, string.Format("{0}", load)));
            }

            // Text version of the descriptions
            if (descKind == DescKind.DescPane) {
                Textifier textifier = new Textifier(eventDB, symbolDB, QueryEvent.GetDescriptionLanguage(eventDB));
                string descText = textifier.CreateTextForControl(controlId, null);
                list.Add(new TextPart(TextFormat.Header, SelectionDescriptionText.TextDescription));
                list.Add(new TextPart(TextFormat.NewLine, descText));
            }

            return list.ToArray();
        }
Example #25
0
        // Find the kind of flagging for the leg from controlId1 to controlIs2. The legId, if not none, must be the correct leg id.
        public static FlaggingKind GetLegFlagging(EventDB eventDB, Id<ControlPoint> controlId1, Id<ControlPoint> controlId2, Id<Leg> legId)
        {
            FlaggingKind flagging = FlaggingKind.None;
            if (legId.IsNotNone) {
                Leg leg = eventDB.GetLeg(legId);
                Debug.Assert(leg.controlId1 == controlId1 && leg.controlId2 == controlId2);
                flagging = leg.flagging;
            }

            ControlPoint control2 = eventDB.GetControl(controlId2);
            if (control2.kind == ControlPointKind.Finish && control2.symbolIds[0] == "14.1")
                flagging = FlaggingKind.All;
            if (control2.kind == ControlPointKind.MapExchange)
                flagging = FlaggingKind.All;

            return flagging;
        }
        // Determine the type of flagging
        private static string FlaggingType(EventDB eventDB, Id<ControlPoint> controlId1, Id<ControlPoint> controlId2, Id<Leg> legId)
        {
            string flaggingType = SelectionDescriptionText.None;
            FlaggingKind kind = QueryEvent.GetLegFlagging(eventDB, controlId1, controlId2, legId);

            switch (kind) {
            case FlaggingKind.All: flaggingType = SelectionDescriptionText.EntireLeg; break;
            case FlaggingKind.Begin: flaggingType = SelectionDescriptionText.AwayFromControl; break;
            case FlaggingKind.End: flaggingType = SelectionDescriptionText.IntoControl; break;
            }

            // We use slightly different wording based on the finish control.
            ControlPoint ending = eventDB.GetControl(controlId2);
            if (ending.kind == ControlPointKind.Finish) {
                // finish control can influence flagging!
                if (ending.symbolIds[0] == "14.2" && kind == FlaggingKind.None)
                    flaggingType = SelectionDescriptionText.FinishFunnel;
                else if (ending.symbolIds[0] == "14.2" && kind == FlaggingKind.End)
                    flaggingType = SelectionDescriptionText.IntoFinishFunnel;
            }

            return flaggingType;
        }
Example #27
0
        // Create the standard view onto a regular course, or a single variation of a variation course.
        private static CourseView CreateStandardCourseView(EventDB eventDB, CourseDesignator courseDesignator)
        {
            Course course = eventDB.GetCourse(courseDesignator.CourseId);

            if (QueryEvent.HasVariations(eventDB, courseDesignator.CourseId) && courseDesignator.VariationInfo == null)
                throw new ApplicationException("Cannot create course view without specifying which variation");

            // Get sub-part of the course. firstCourseControls is the first control to process, lastCourseControl is the last one to
            // process, or None if process to the end of the course.
            Id<CourseControl> firstCourseControl, lastCourseControl;
            if (courseDesignator.AllParts) {
                firstCourseControl = course.firstCourseControl;
                lastCourseControl = Id<CourseControl>.None;
            }
            else {
                QueryEvent.GetCoursePartBounds(eventDB, courseDesignator, out firstCourseControl, out lastCourseControl);
            }

            CourseView courseView = new CourseView(eventDB, courseDesignator);
            int ordinal;

            courseView.courseName = course.name;
            courseView.scoreColumn = -1;

            ordinal = 1;
            ordinal = course.firstControlOrdinal;

            // To get the ordinals correct, we get the course control ids for all parts.
            List<Id<CourseControl>> courseControls = QueryEvent.EnumCourseControlIds(eventDB, courseDesignator.WithAllParts()).ToList();
            int index = 0;

            // Increase the ordinal value for each normal control before the first one we're considering.
            while (index < courseControls.Count && courseControls[index] != firstCourseControl) {
                CourseControl courseControl = eventDB.GetCourseControl(courseControls[index]);
                ControlPoint control = eventDB.GetControl(courseControl.control);
                if (control.kind == ControlPointKind.Normal)
                    ++ordinal;
                ++index;
            }

            for (; index < courseControls.Count; ++index) {
                Id<CourseControl> courseControlId = courseControls[index];

                ControlView controlView = new ControlView();
                CourseControl courseControl = eventDB.GetCourseControl(courseControlId);
                ControlPoint control = eventDB.GetControl(courseControl.control);

                controlView.courseControlIds = new[] { courseControlId };
                controlView.controlId = courseControl.control;

                // Set the ordinal number.
                if (control.kind == ControlPointKind.Normal)
                    controlView.ordinal = ordinal++;
                else if (control.kind == ControlPointKind.Start || control.kind == ControlPointKind.MapExchange)
                    controlView.ordinal = 0;
                else
                    controlView.ordinal = -1;

                controlView.joinIndex = -1;

                // Don't show the map exchange for the next part at the end of this part.
                if (courseControlId == lastCourseControl && !courseDesignator.AllParts && control.kind == ControlPointKind.MapExchange) {
                    controlView.hiddenControl = true;
                }

                // Set the legTo array with the next courseControlID. This is later updated
                // to the indices.
                if (index < courseControls.Count - 1 && courseControlId != lastCourseControl) {
                    Id<CourseControl> nextCourseControl = courseControls[index + 1];
                    controlView.legTo = new int[1] { nextCourseControl.id };   // legTo initially holds course control ids, later changed.
                }
                // Add the controlview.
                courseView.controlViews.Add(controlView);

                if (courseControlId == lastCourseControl)
                    break;
            }

            // If this is a part that should also have the finish on it, and it isn't the last part, then
            // add the finish.
            if (courseDesignator.IsNotAllControls && !courseDesignator.AllParts &&
                courseDesignator.Part != QueryEvent.CountCourseParts(eventDB, courseDesignator.CourseId) - 1 &&
                QueryEvent.GetPartOptions(eventDB, courseDesignator).ShowFinish)
            {
                if (QueryEvent.HasFinishControl(eventDB, courseDesignator.CourseId))
                    courseView.extraCourseControls.Add(QueryEvent.LastCourseControl(eventDB, courseDesignator.CourseId, false));
            }

            courseView.Finish();
            return courseView;
        }
Example #28
0
        // Does the course have a finish control?
        public static bool HasFinishControl(EventDB eventDB, Id<Course> courseId)
        {
            Id<CourseControl> lastId = QueryEvent.LastCourseControl(eventDB, courseId, false);

            if (lastId.IsNone || eventDB.GetControl(eventDB.GetCourseControl(lastId).control).kind != ControlPointKind.Finish)
                return false;
            else
                return true;
        }
Example #29
0
        // Create the normal view onto a score course
        private static CourseView CreateScoreCourseView(EventDB eventDB, CourseDesignator courseDesignator)
        {
            Course course = eventDB.GetCourse(courseDesignator.CourseId);
            CourseView courseView = new CourseView(eventDB, courseDesignator);
            Id<CourseControl> courseControlId;

            courseView.courseName = course.name;
            courseView.scoreColumn = course.scoreColumn;

            courseControlId = course.firstCourseControl;

            while (courseControlId.IsNotNone) {
                ControlView controlView = new ControlView();
                CourseControl courseControl = eventDB.GetCourseControl(courseControlId);

                controlView.courseControlIds = new[] { courseControlId };
                controlView.controlId = courseControl.control;

                // Ordinals assigned after sorting.
                controlView.ordinal = -1;

                controlView.joinIndex = -1;

                // Move to the next control.
                courseView.controlViews.Add(controlView);
                courseControlId = courseControl.nextCourseControl;
            }

            // Sort the control views: first by kind, then by score, then by code.
            courseView.controlViews.Sort(delegate(ControlView view1, ControlView view2) {
                ControlPoint control1 = eventDB.GetControl(view1.controlId);
                ControlPoint control2 = eventDB.GetControl(view2.controlId);
                CourseControl courseControl1 = eventDB.GetCourseControl(view1.courseControlIds[0]);
                CourseControl courseControl2 = eventDB.GetCourseControl(view2.courseControlIds[0]);

                if (control1.kind < control2.kind)
                    return -1;
                else if (control1.kind > control2.kind)
                    return 1;

                if (courseControl1.points != courseControl2.points)
                    return courseControl1.points.CompareTo(courseControl2.points);
                int result = Util.CompareCodes(control1.code, control2.code);
                if (result != 0)
                    return result;

                return view1.controlId.id.CompareTo(view2.controlId.id);
            });

            // Assign ordinals, if applicable. If scores in column A, then no ordinals will be assigned.
            if (courseView.scoreColumn != 0) {
                int ordinal = course.firstControlOrdinal;
                foreach (ControlView control in courseView.controlViews) {
                    if (eventDB.GetControl(control.controlId).kind == ControlPointKind.Normal)
                        control.ordinal = ordinal++;
                }
            }

            courseView.Finish();
            return courseView;
        }
Example #30
0
 // Does the course have a start control?
 public static bool HasStartControl(EventDB eventDB, Id<Course> courseId)
 {
     Id<CourseControl> firstId = eventDB.GetCourse(courseId).firstCourseControl;
     if (firstId.IsNone || eventDB.GetControl(eventDB.GetCourseControl(firstId).control).kind != ControlPointKind.Start)
         return false;
     else
         return true;
 }