GetCourseControl() public method

public GetCourseControl ( Id courseControlId ) : CourseControl
courseControlId Id
return CourseControl
コード例 #1
0
        // Create a single object associated with the leg from courseControlId1 to courseControlId2. Does not consider
        // flagging (but does consider bends and gaps.) Used for highlighting on the map.
        public static CourseObj CreateSimpleLeg(EventDB eventDB, float scaleRatio, CourseAppearance appearance, Id<CourseControl> courseControlId1, Id<CourseControl> courseControlId2)
        {
            Id<ControlPoint> controlId1 = eventDB.GetCourseControl(courseControlId1).control;
            Id<ControlPoint> controlId2 = eventDB.GetCourseControl(courseControlId2).control;
            ControlPoint control1 = eventDB.GetControl(controlId1);
            ControlPoint control2 = eventDB.GetControl(controlId2);
            LegGap[] gaps;

            SymPath legPath = GetLegPath(eventDB, control1.location, control1.kind, controlId1, control2.location, control2.kind, controlId2, scaleRatio, appearance, out gaps);
            if (legPath == null)
                return null;

            return new LegCourseObj(controlId1, courseControlId1, courseControlId2, scaleRatio, appearance, legPath, gaps);
        }
コード例 #2
0
ファイル: QueryEvent.cs プロジェクト: petergolde/PurplePen
 // If a course control is the beginning of a variation split, return all course controls assigned to that variation split.
 // Otherwise, return just that course control.
 public static IEnumerable<Id<CourseControl>> AllVariationsOfCourseControl(EventDB eventDB, Id<CourseControl> courseControlId)
 {
     CourseControl courseControl = eventDB.GetCourseControl(courseControlId);
     if (courseControl.split) {
         return courseControl.splitCourseControls;
     }
     else {
         return new[] { courseControlId };
     }
 }
コード例 #3
0
        // Get the text for a control lable
        private static string GetControlLabelText(EventDB eventDB, ControlLabelKind labelKind, CourseView.ControlView controlView, CourseView courseView)
        {
            string text = "";

            List<CourseView.ControlView> repeatedControlViews = FindControlViewsWithControlId(courseView, controlView.controlId);

            if (repeatedControlViews.Count > 1 && repeatedControlViews[0] != controlView) {
                // This control is repeated (e.g., like a butterfly course) and is not the first use of this control. Don't put any text.
                return "";
            }

            if (labelKind == ControlLabelKind.Sequence || labelKind == ControlLabelKind.SequenceAndCode || labelKind == ControlLabelKind.SequenceAndScore) {
                text += controlView.ordinal.ToString();

                // Add in numbers for repeated controls.
                for (int i = 1; i < repeatedControlViews.Count; ++i) {
                    text += "/";
                    text += repeatedControlViews[i].ordinal.ToString();
                }
            }
            if (labelKind == ControlLabelKind.SequenceAndCode)
                text += "-";
            if (labelKind == ControlLabelKind.SequenceAndCode || labelKind == ControlLabelKind.Code || labelKind == ControlLabelKind.CodeAndScore) {
                ControlPoint control = eventDB.GetControl(controlView.controlId);
                text += control.code;
            }

            if (labelKind == ControlLabelKind.CodeAndScore || labelKind == ControlLabelKind.SequenceAndScore) {
                int points = eventDB.GetCourseControl(controlView.courseControlIds[0]).points;
                if (points > 0) {
                    text += "(" + points.ToString() + ")";
                }
            }

            return text;
        }
コード例 #4
0
ファイル: CourseView.cs プロジェクト: petergolde/PurplePen
        // Create the view of all variations of a course with variations. Cannot be a single part of a multi-part course.
        // Does not contain ordinals.
        private static CourseView CreateAllVariationsCourseView(EventDB eventDB, CourseDesignator courseDesignator)
        {
            Course course = eventDB.GetCourse(courseDesignator.CourseId);

            if (!courseDesignator.AllParts)
                throw new ApplicationException("Cannot create all variations of a single part");

            CourseView courseView = new CourseView(eventDB, courseDesignator);

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

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

            for (int index = 0; index < courseControls.Count; ++index) {
                Id<CourseControl> courseControlId = courseControls[index];
                CourseControl courseControl = eventDB.GetCourseControl(courseControlId);

                // We add each split control only once, even though it has multiple variations. Check to see if we have already
                // handled it.
                bool alreadyHandled = false;
                if (courseControl.split) {
                    foreach (ControlView cv in courseView.controlViews) {
                        if (cv.courseControlIds.Contains(courseControlId))
                            alreadyHandled = true;
                    }
                }

                if (!alreadyHandled) {
                    ControlView controlView = new ControlView();

                    controlView.controlId = courseControl.control;

                    // Set the ordinal number. All variations does not include an ordinal.
                    controlView.ordinal = -1;

                    // Set all course control ids associated with split control, or a single one for a non-split control.
                    // Set the legTo array with the next courseControlID(s). This is later updated
                    // to the indices.
                    if (courseControl.split) {
                        controlView.courseControlIds = QueryEvent.AllVariationsOfCourseControl(eventDB, courseControlId).ToArray();
                        if (courseControl.nextCourseControl.IsNotNone) {
                            controlView.legTo = new int[controlView.courseControlIds.Length];
                            for (int i = 0; i < controlView.legTo.Length; ++i) {
                                controlView.legTo[i] = eventDB.GetCourseControl(controlView.courseControlIds[i]).nextCourseControl.id;
                            }
                        }
                        if (courseControl.loop)
                            controlView.joinIndex = courseControlId.id;
                        else
                            controlView.joinIndex = courseControl.splitEnd.id;
                    }
                    else {
                        controlView.courseControlIds = new[] { courseControlId };
                        if (courseControl.nextCourseControl.IsNotNone)
                            controlView.legTo = new int[1] { courseControl.nextCourseControl.id };   // legTo initially holds course control ids, later changed.
                        controlView.joinIndex = -1;
                    }

                    // Add the controlview.
                    courseView.controlViews.Add(controlView);
                }
            }

            courseView.Finish();
            return courseView;
        }
コード例 #5
0
ファイル: QueryEvent.cs プロジェクト: petergolde/PurplePen
        // Get the mapping from split course control to letter.
        public static Dictionary<Id<CourseControl>, char> GetVariantCodeMapping(EventDB eventDB, CourseDesignator courseDesignator)
        {
            Debug.Assert(!courseDesignator.IsVariation);

            char nextLetter = 'A';
            Dictionary<Id<CourseControl>, char> result = new Dictionary<Id<CourseControl>, char>();

            foreach (Id<CourseControl> courseControlId in EnumCourseControlIds(eventDB, courseDesignator)) {
                CourseControl courseControl = eventDB.GetCourseControl(courseControlId);
                if (courseControl.split) {
                    foreach (Id<CourseControl> splitId in courseControl.splitCourseControls) {
                        // The loop escape path doesn't get a letter.
                        if (!(courseControl.loop && courseControl.splitCourseControls[0] == splitId)) {
                            if (!result.ContainsKey(splitId)) {
                                result.Add(splitId, nextLetter);
                                if (nextLetter == 'Z')
                                    nextLetter = 'a';
                                else
                                    ++nextLetter;
                            }
                        }
                    }
                }
            }

            return result;
        }
コード例 #6
0
ファイル: QueryEvent.cs プロジェクト: petergolde/PurplePen
        // Find all the course controls for a particular control in a particular course. If the course
        // doesn't contain the given controlId, an empty array is returned.
        public static Id<CourseControl>[] GetCourseControlsInCourse(EventDB eventDB, CourseDesignator courseDesignator, Id<ControlPoint> controlId)
        {
            List<Id<CourseControl>> list = new List<Id<CourseControl>>();

            foreach (Id<CourseControl> courseControlId in EnumCourseControlIds(eventDB, courseDesignator)) {
                if (eventDB.GetCourseControl(courseControlId).control == controlId)
                    list.Add(courseControlId);
            }

            return list.ToArray();
        }
コード例 #7
0
ファイル: QueryEvent.cs プロジェクト: petergolde/PurplePen
        // Find the closest leg to a given point on a course. The leg might be None/None if the course has no legs.
        public static LegInfo FindClosestLeg(EventDB eventDB, CourseDesignator courseDesignator, PointF pt)
        {
            LegInfo closestLegSoFar = new LegInfo();
            float closestSoFar = 1E10F;

            foreach (LegInfo leg in EnumLegs(eventDB, courseDesignator)) {
                PointF temp;
                SymPath legPath = GetLegPath(eventDB, eventDB.GetCourseControl(leg.courseControlId1).control, eventDB.GetCourseControl(leg.courseControlId2).control);
                float distance = legPath.DistanceFromPoint(pt, out temp);
                if (distance < closestSoFar) {
                    closestSoFar = distance;
                    closestLegSoFar = leg;
                }
                else if (distance == closestSoFar) {
                    // Distances are equal. Use leg with the largest angle between the end points.
                    SymPath closestLegPath = GetLegPath(eventDB, eventDB.GetCourseControl(closestLegSoFar.courseControlId1).control, eventDB.GetCourseControl(closestLegSoFar.courseControlId2).control);
                    if (Geometry.Angle(legPath.FirstPoint, pt, legPath.LastPoint) >  Geometry.Angle(closestLegPath.FirstPoint, pt, closestLegPath.LastPoint)) {
                        closestSoFar = distance;
                        closestLegSoFar = leg;
                    }
                }
            }

            return closestLegSoFar;
        }
コード例 #8
0
ファイル: QueryEvent.cs プロジェクト: petergolde/PurplePen
        // Return if a give course uses a given control.
        public static bool CourseUsesControl(EventDB eventDB, CourseDesignator courseDesignator, Id<ControlPoint> controlId)
        {
            eventDB.CheckControlId(controlId);

            foreach (Id<CourseControl> courseControlId in EnumCourseControlIds(eventDB, courseDesignator)) {
                if (eventDB.GetCourseControl(courseControlId).control == controlId)
                    return true;
            }

            return false;
        }
コード例 #9
0
ファイル: QueryEvent.cs プロジェクト: petergolde/PurplePen
        public static bool CourseIsForked(EventDB eventDB, CourseDesignator courseDesignator)
        {
            foreach (Id<CourseControl> courseControlId in EnumCourseControlIds(eventDB, courseDesignator)) {
                if (eventDB.GetCourseControl(courseControlId).split)
                    return true;
            }

            return false;
        }
コード例 #10
0
ファイル: QueryEvent.cs プロジェクト: petergolde/PurplePen
 // 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;
 }
コード例 #11
0
ファイル: QueryEvent.cs プロジェクト: petergolde/PurplePen
        // 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;
        }
コード例 #12
0
        // Describe a leg.
        private static TextPart[] DescribeLeg(EventDB eventDB, Id<CourseControl> courseControlId1, Id<CourseControl> courseControlId2, DescKind descKind)
        {
            Debug.Assert(descKind == DescKind.Tooltip || descKind == DescKind.DescPane);

            Id<ControlPoint> controlId1 = eventDB.GetCourseControl(courseControlId1).control;
            Id<ControlPoint> controlId2 = eventDB.GetCourseControl(courseControlId2).control;
            Id<Leg> legId = QueryEvent.FindLeg(eventDB, controlId1, controlId2);

            List<TextPart> list = new List<TextPart>();

            // Course name
            list.Add(new TextPart(TextFormat.Title, string.Format("{0} \u2013 {1}", Util.ControlPointName(eventDB, controlId1, NameStyle.Long), Util.ControlPointName(eventDB, controlId2, NameStyle.Long))));

            // Course length
            list.Add(new TextPart(TextFormat.Header, SelectionDescriptionText.Length));
            list.Add(new TextPart(TextFormat.SameLine,
                string.Format("{0:#,###} m", QueryEvent.ComputeLegLength(eventDB, controlId1, controlId2, legId))));

            // Which courses
            list.Add(new TextPart(TextFormat.Header, (descKind == DescKind.Tooltip ? SelectionDescriptionText.UsedIn : SelectionDescriptionText.UsedInCourses)));
            Id<Course>[] coursesUsingControl = QueryEvent.CoursesUsingLeg(eventDB, controlId1, controlId2);
            list.Add(new TextPart(descKind == DescKind.Tooltip ? TextFormat.SameLine : TextFormat.NewLine, CourseListText(eventDB, coursesUsingControl)));

            // What is the competitor load?
            int load = QueryEvent.GetLegLoad(eventDB, controlId1, controlId2);
            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)));
            }

            if (descKind == DescKind.DescPane) {
                // Flagging
                list.Add(new TextPart(TextFormat.Header, SelectionDescriptionText.Flagging + "  "));
                list.Add(new TextPart(TextFormat.SameLine, FlaggingType(eventDB, controlId1, controlId2, legId)));
            }

            return list.ToArray();
        }
コード例 #13
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();
        }
コード例 #14
0
ファイル: Reports.cs プロジェクト: petergolde/PurplePen
        void WriteLegLoadSection(EventDB eventDB)
        {
            // Maps legs to load infos, so we only process each leg once.
            Dictionary<Pair<Id<ControlPoint>, Id<ControlPoint>>, LegLoadInfo> loadInfos = new Dictionary<Pair<Id<ControlPoint>, Id<ControlPoint>>, LegLoadInfo>();

            // Get load information about each leg. To enumerate all legs, just enumerate all courses and all legs on each course.
            foreach (Id<Course> courseId in eventDB.AllCourseIds) {
                foreach (QueryEvent.LegInfo leg in QueryEvent.EnumLegs(eventDB, new CourseDesignator(courseId))) {
                    Id<ControlPoint> controlId1 = eventDB.GetCourseControl(leg.courseControlId1).control;
                    Id<ControlPoint> controlId2 = eventDB.GetCourseControl(leg.courseControlId2).control;
                    Pair<Id<ControlPoint>, Id<ControlPoint>> key = new Pair<Id<ControlPoint>, Id<ControlPoint>>(controlId1, controlId2);

                    if (!loadInfos.ContainsKey(key)) {
                        // This leg hasn't been processed yet. Process it.
                        LegLoadInfo loadInfo = new LegLoadInfo();
                        loadInfo.controlId1 = controlId1;
                        loadInfo.controlId2 = controlId2;
                        loadInfo.text = string.Format("{0}\u2013{1}", Util.ControlPointName(eventDB, controlId1, NameStyle.Medium), Util.ControlPointName(eventDB, controlId2, NameStyle.Medium));
                        loadInfo.numCourses = QueryEvent.CoursesUsingLeg(eventDB, controlId1, controlId2).Length;
                        loadInfo.load = QueryEvent.GetLegLoad(eventDB, controlId1, controlId2);

                        loadInfos.Add(key, loadInfo);
                    }
                }
            }

            // Remove legs used only once.
            List<LegLoadInfo> loadInfoList = new List<LegLoadInfo>(loadInfos.Values);
            loadInfoList = loadInfoList.FindAll(delegate(LegLoadInfo loadInfo) { return loadInfo.numCourses > 1; });

            // Sort the list of legs, first by load, then by number of courses
            loadInfoList.Sort(delegate(LegLoadInfo loadInfo1, LegLoadInfo 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;

                return 0;
            });

            // Write the table.
            WritePara(ReportText.Load_OnlyLegsMoreThanOnce);

            BeginTable("", 3, "leftalign", "rightalign", "rightalign");
            WriteTableHeaderRow(ReportText.ColumnHeader_Leg, ReportText.ColumnHeader_NumberOfCourses, ReportText.ColumnHeader_Load);

            foreach (LegLoadInfo loadInfo in loadInfoList) {
                WriteTableRow(loadInfo.text,
                                        Convert.ToString(loadInfo.numCourses),
                                        loadInfo.load >= 0 ? Convert.ToString(loadInfo.load) : "");
            }

            EndTable();
        }
コード例 #15
0
ファイル: Reports.cs プロジェクト: petergolde/PurplePen
        // 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;
        }
コード例 #16
0
ファイル: QueryEvent.cs プロジェクト: petergolde/PurplePen
        private static List<List<Id<CourseControl>>> GetVariations(EventDB eventDB, CourseDesignator courseDesignator, Id<CourseControl> start, HashSet<Id<CourseControl>> alreadyVisited)
        {
            List<List<Id<CourseControl>>> result = new List<List<Id<CourseControl>>>();
            Id<CourseControl> nextCourseControlId = start;

            // Traverse the course control links.
            while (nextCourseControlId.IsNotNone) {
                CourseControl courseCtl = eventDB.GetCourseControl(nextCourseControlId);

                if (courseCtl.split) {

                    // If its a loop, we can only continue on the loop skipping path if all other loop
                    // paths have been visited.
                    bool allLoopsVisited = true; // true if all loops in this loop are visited, or its a fork.
                    if (courseCtl.loop) {
                        for (int i = 1; i < courseCtl.splitCourseControls.Length; ++i) {
                            if (!alreadyVisited.Contains(courseCtl.splitCourseControls[i]))
                                allLoopsVisited = false;
                        }
                    }

                    for (int i = (allLoopsVisited ? 0 : 1); i < courseCtl.splitCourseControls.Length; ++i) {
                        Id<CourseControl> split = courseCtl.splitCourseControls[i];
                        Id<CourseControl> afterSplit = eventDB.GetCourseControl(split).nextCourseControl;

                        if (afterSplit.IsNotNone && !alreadyVisited.Contains(split)) {
                            // Mark this path as visited so if its part of a loop, we don't visit it again.
                            alreadyVisited.Add(split);
                            List<List<Id<CourseControl>>> tailVariants = GetVariations(eventDB, courseDesignator, afterSplit, alreadyVisited);
                            alreadyVisited.Remove(split);

                            foreach (List<Id<CourseControl>> v in tailVariants) {
                                List<Id<CourseControl>> l = new List<PurplePen.Id<PurplePen.CourseControl>>(v.Count + 1);
                                l.Add(courseCtl.splitCourseControls[i]);
                                l.AddRange(v);
                                result.Add(l);
                            }
                        }
                    }

                    break;
                }

                nextCourseControlId = courseCtl.nextCourseControl;
            }

            // If no variations found, there is one way to go.
            if (result.Count == 0)
                result.Add(new List<Id<CourseControl>>());

            return result;
        }
コード例 #17
0
ファイル: QueryEvent.cs プロジェクト: petergolde/PurplePen
        // Get the number of parts that this course has.  A course with no map exchanges has 1 part, with one
        // map exchange has 2 parts, etc.
        public static int CountCourseParts(EventDB eventDB, CourseDesignator courseDesignator)
        {
            Debug.Assert(courseDesignator.AllParts);

            int currentPart = 0;

            foreach (Id<CourseControl> courseControlId in EnumCourseControlIds(eventDB, courseDesignator)) {
                if (eventDB.GetCourseControl(courseControlId).exchange)
                    ++currentPart;
            }

            return currentPart + 1;
        }
コード例 #18
0
ファイル: QueryEvent.cs プロジェクト: petergolde/PurplePen
        // See if course has any variations.
        public static bool HasVariations(EventDB eventDB, Id<Course> courseId)
        {
            if (courseId.IsNone)
                return false;  // All Control has no variations.
            Course course = eventDB.GetCourse(courseId);
            if (course.kind == CourseKind.Score)
                return false;  // Score courses don't have variations.

            return EnumCourseControlIds(eventDB, new CourseDesignator(courseId)).Any(courseControlId => eventDB.GetCourseControl(courseControlId).split);
        }
コード例 #19
0
ファイル: QueryEvent.cs プロジェクト: petergolde/PurplePen
        // Find which courses are using a particular leg. If none, return an
        // empty array.
        public static Id<Course>[] CoursesUsingLeg(EventDB eventDB, Id<ControlPoint> control1, Id<ControlPoint> control2)
        {
            List<Id<Course>> list = new List<Id<Course>>();

            foreach (Id<Course> courseId in SortedCourseIds(eventDB)) {
                foreach (LegInfo leg in EnumLegs(eventDB, new CourseDesignator(courseId))) {
                    if (eventDB.GetCourseControl(leg.courseControlId1).control == control1 &&
                        eventDB.GetCourseControl(leg.courseControlId2).control == control2) {
                        list.Add(courseId);
                        break;
                    }
                }
            }

            return list.ToArray();
        }
コード例 #20
0
ファイル: QueryEvent.cs プロジェクト: petergolde/PurplePen
        public static bool CanAddVariation(EventDB eventDB, CourseDesignator courseDesignator, Id<CourseControl> courseControlId)
        {
            // Can't be all controls or score course.
            if (courseDesignator.IsAllControls)
                return false;
            Id<Course> courseId = courseDesignator.CourseId;
            if (eventDB.GetCourse(courseId).kind == CourseKind.Score)
                return false;

            if (courseControlId.IsNone)
                return false;

            // Must not be the last control in the course.
            if (QueryEvent.LastCourseControl(eventDB, courseId, false) == courseControlId)
                return false;

            // Can't already have a variation there.
            CourseControl courseControl = eventDB.GetCourseControl(courseControlId);
            if (courseControl.split)
                return false;

            return true;
        }
コード例 #21
0
ファイル: QueryEvent.cs プロジェクト: petergolde/PurplePen
        public static IEnumerable<LegInfo> EnumLegs(EventDB eventDB, CourseDesignator courseDesignator)
        {
            if (courseDesignator.IsAllControls)
                yield break;

            Id<Course> courseId = courseDesignator.CourseId;

            // Score courses, by definition, have no legs.
            if (eventDB.GetCourse(courseId).kind == CourseKind.Score)
                yield break;

            bool first = true;
            foreach (Id<CourseControl> courseControlId in EnumCourseControlIds(eventDB, courseDesignator)) {
                CourseControl courseControl = eventDB.GetCourseControl(courseControlId);
                if (first || courseDesignator.AllParts || !courseControl.exchange) {
                    Id<CourseControl> nextCourseControlId = GetNextControl(eventDB, courseDesignator, courseControlId);
                    if (nextCourseControlId.IsNotNone) {
                        yield return new LegInfo(courseControlId, nextCourseControlId);
                    }
                }
                first = false;
            }
        }
コード例 #22
0
ファイル: QueryEvent.cs プロジェクト: petergolde/PurplePen
        // 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;
        }
コード例 #23
0
ファイル: QueryEvent.cs プロジェクト: petergolde/PurplePen
        // 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;
                }
            }
        }
コード例 #24
0
ファイル: QueryEvent.cs プロジェクト: petergolde/PurplePen
        // 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();
        }
コード例 #25
0
ファイル: QueryEvent.cs プロジェクト: petergolde/PurplePen
        private static List<CourseControlAndSplitStart> EnumCourseControlsAndSplitStartsToJoin(EventDB eventDB, Id<Course> courseId, Id<CourseControl> begin, Id<CourseControl> join, Id<CourseControl> splitStart)
        {
            List<CourseControlAndSplitStart> result = new List<CourseControlAndSplitStart>();

            Id<CourseControl> nextCourseControlId = begin;

            // Traverse the course control links.
            while (nextCourseControlId.IsNotNone && nextCourseControlId != join) {
                CourseControl courseCtl = eventDB.GetCourseControl(nextCourseControlId);

                if (courseCtl.split) {
                    // Follow all of the alternate paths
                    for (int i = 0; i < courseCtl.splitCourseControls.Length; ++i) {
                        if (! (courseCtl.loop && i == 0)) {
                            Id<CourseControl> forkStart = courseCtl.splitCourseControls[i];
                            result.Add(new CourseControlAndSplitStart(forkStart, forkStart));
                            var splitControls = EnumCourseControlsAndSplitStartsToJoin(eventDB, courseId, eventDB.GetCourseControl(forkStart).nextCourseControl, courseCtl.splitEnd, forkStart);
                            result.AddRange(splitControls);
                        }
                    }

                    if (!courseCtl.loop) {
                        nextCourseControlId = courseCtl.splitEnd;
                    }
                    else {
                        nextCourseControlId = courseCtl.nextCourseControl;
                    }
                }
                else {
                    result.Add(new CourseControlAndSplitStart(nextCourseControlId, splitStart));
                    nextCourseControlId = courseCtl.nextCourseControl;
                }
            }

            return result;
        }
コード例 #26
0
ファイル: QueryEvent.cs プロジェクト: petergolde/PurplePen
        private static List<Id<CourseControl>> EnumCourseControlsToJoin(EventDB eventDB, CourseDesignator courseDesignator, Id<CourseControl> start, Id<CourseControl> join,
            IEnumerable<Id<CourseControl>> variationChoices, bool ignoreFirstSplit, int currentPart)
        {
            List<Id<CourseControl>> result = new List<Id<CourseControl>>();

            int part = courseDesignator.Part;
            Id<CourseControl> nextCourseControlId = start;
            bool first = true;

            // Traverse the course control links.
            while (nextCourseControlId.IsNotNone && nextCourseControlId != join) {
                CourseControl courseCtl = eventDB.GetCourseControl(nextCourseControlId);

                if (courseCtl.split && !(first && ignoreFirstSplit)) {
                    if (variationChoices != null && variationChoices.Any()) {
                        // Follow the path given by the variantChoices. May be the same as this control.
                        Id<CourseControl> choice = variationChoices.First();
                        Debug.Assert(courseCtl.splitCourseControls.Contains(choice));

                        variationChoices = variationChoices.Skip(1);

                        nextCourseControlId = choice;
                        courseCtl = eventDB.GetCourseControl(nextCourseControlId);
                    }
                    else {
                        // Follow all of the alternate paths except the current one.
                        for (int i = 0; i < courseCtl.splitCourseControls.Length; ++i) {
                            if (courseCtl.splitCourseControls[i] != nextCourseControlId) {
                                var splitControls = EnumCourseControlsToJoin(eventDB, courseDesignator, courseCtl.splitCourseControls[i], courseCtl.splitEnd, variationChoices, true, currentPart);
                                result.AddRange(splitControls);
                            }
                        }
                    }
                }

                if (courseDesignator.AllParts || currentPart == part)
                    result.Add(nextCourseControlId);

                if (courseCtl.exchange) {
                    ++currentPart;
                    if (!courseDesignator.AllParts && currentPart == part)
                        result.Add(nextCourseControlId);
                }

                nextCourseControlId = courseCtl.nextCourseControl;
                first = false;
            }

            return result;
        }
コード例 #27
0
ファイル: CourseView.cs プロジェクト: petergolde/PurplePen
        // 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;
        }
コード例 #28
0
ファイル: QueryEvent.cs プロジェクト: petergolde/PurplePen
        // Get the next course control
        private static Id<CourseControl> GetNextControl(EventDB eventDB, CourseDesignator courseDesignator, Id<CourseControl> courseControlId)
        {
            Id<CourseControl> next = eventDB.GetCourseControl(courseControlId).nextCourseControl;

            // Simple case, the next control is not starting a split.
            if (next.IsNone || !eventDB.GetCourseControl(next).split)
                return next;

            // If it does, then we have to do the complex thing.
            List<Id<CourseControl>> allCourseControls = EnumCourseControlIds(eventDB, courseDesignator).ToList();
            for (int i = 0; i < allCourseControls.Count; ++i) {
                if (allCourseControls[i] == courseControlId) {
                    if (i < allCourseControls.Count - 1)
                        return allCourseControls[i + 1];
                    else
                        return Id<CourseControl>.None;
                }
            }

            throw new Exception("Course does not contain give course control");
        }
コード例 #29
0
ファイル: CourseView.cs プロジェクト: petergolde/PurplePen
        // 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;
        }
コード例 #30
0
 // Does this control view have a custom number placement?
 private static bool CustomPlaceNumber(EventDB eventDB, CourseView.ControlView controlView)
 {
     return ((controlView.courseControlIds[0].IsNotNone && eventDB.GetCourseControl(controlView.courseControlIds[0]).customNumberPlacement) ||
                 (controlView.courseControlIds[0].IsNone && eventDB.GetControl(controlView.controlId).customCodeLocation));
 }