// Format the given CourseView into a bunch of course objects, and add it to the given course Layout
        public RectangleF FormatCourseToLayout(SymbolDB symbolDB, CourseView courseViewAllVariations, CourseView specificVariation, CourseLayout courseLayout, CourseLayer layerAllVariations, CourseLayer layerSpecificVariation)
        {
            this.eventDB = courseViewAllVariations.EventDB;
            this.symbolDB = symbolDB;
            this.courseLayout = courseLayout;
            this.courseLayerAllVariationsAndParts = layerAllVariations;
            this.courseLayerSpecificVariation = layerSpecificVariation;
            this.controlViewsAllVariationsAndParts = courseViewAllVariations.ControlViews;
            this.controlViewsSpecificVariation = specificVariation.ControlViews;
            this.controlPositions = new ControlPosition[controlViewsAllVariationsAndParts.Count];
            this.courseControlIdsSpecificVariation = QueryEvent.EnumCourseControlIds(eventDB, specificVariation.CourseDesignator).ToArray();
            this.variationMap = QueryEvent.GetVariantCodeMapping(eventDB, courseViewAllVariations.CourseDesignator);

            SizeF totalAbstractSize = AssignControlPositions(0, controlViewsAllVariationsAndParts.Count, 0, 0);

            // Now create objects now that the positions have been created.
            scaleRatio = 1.0F;
            appearance = new CourseAppearance();

            for (int index = 0; index < controlViewsAllVariationsAndParts.Count; ++index) {
                CreateObjectsForControlView(controlViewsAllVariationsAndParts[index], controlPositions[index]);
            }

            PointF bottomCenter = LocationFromAbstractPosition(0, 0);
            SizeF size = SizeFromAbstractSize(totalAbstractSize);
            RectangleF rect = new RectangleF(bottomCenter.X - size.Width / 2, bottomCenter.Y - size.Height, size.Width, size.Height);
            rect.Inflate(widthUnit, heightUnit);
            return rect;
        }
Beispiel #2
0
        // Format the given CourseView into a bunch of course objects, and add it to the given course Layout
        public RectangleF FormatCourseToLayout(SymbolDB symbolDB, CourseView courseViewAllVariations, CourseView specificVariation, CourseLayout courseLayout,
                                               Id <CourseControl> ccSelection1, Id <CourseControl> ccSelection2, CourseLayer layerAllVariations, CourseLayer layerSpecificVariation)
        {
            this.eventDB      = courseViewAllVariations.EventDB;
            this.symbolDB     = symbolDB;
            this.courseLayout = courseLayout;
            this.courseLayerAllVariationsAndParts  = layerAllVariations;
            this.courseLayerSpecificVariation      = layerSpecificVariation;
            this.controlViewsAllVariationsAndParts = courseViewAllVariations.ControlViews;
            this.controlViewsSpecificVariation     = specificVariation.ControlViews;
            this.controlPositions = new ControlPosition[controlViewsAllVariationsAndParts.Count];
            this.courseControlIdsSpecificVariation = QueryEvent.EnumCourseControlIds(eventDB, specificVariation.CourseDesignator).ToArray();
            this.courseControlIdSelection1         = ccSelection1;
            this.courseControlIdSelection2         = ccSelection2;
            this.variationMap = QueryEvent.GetVariantCodeMapping(eventDB, courseViewAllVariations.CourseDesignator);

            SizeF totalAbstractSize = AssignControlPositions(0, controlViewsAllVariationsAndParts.Count, 0, 0);

            // Now create objects now that the positions have been created.
            courseObjRatio = 1.0F;
            appearance     = new CourseAppearance();

            for (int index = 0; index < controlViewsAllVariationsAndParts.Count; ++index)
            {
                CreateObjectsForControlView(controlViewsAllVariationsAndParts[index], controlPositions[index]);
            }

            PointF     bottomCenter = LocationFromAbstractPosition(0, 0);
            SizeF      size         = SizeFromAbstractSize(totalAbstractSize);
            RectangleF rect         = new RectangleF(bottomCenter.X - size.Width / 2, bottomCenter.Y - size.Height, size.Width, size.Height);

            rect.Inflate(widthUnit, heightUnit);
            return(rect);
        }
Beispiel #3
0
        public static readonly object KeyLayout   = "LayoutKey";   // key to get the "layout" symdef.

        // Set the color of a particular layer. Layer 0 is black, layer 1 is the primary course, layer 2 all other controls,
        // and layers 3 and above for other courses.
        public void SetLayerColor(CourseLayer layer, short ocadColorId, string colorName, float colorC, float colorM, float colorY, float colorK, bool overprint)
        {
            this.ocadColorId[(int)layer]    = ocadColorId;
            this.colorName[(int)layer]      = colorName;
            this.colorC[(int)layer]         = colorC;
            this.colorM[(int)layer]         = colorM;
            this.colorY[(int)layer]         = colorY;
            this.colorK[(int)layer]         = colorK;
            this.colorOverprint[(int)layer] = overprint;
        }
        void CheckHitTest(CourseLayout course, PointF point, CourseLayer layerFilter, Predicate <CourseObj> filter, string expectedObject)
        {
            CourseObj courseobj = course.HitTest(point, 0.1F, layerFilter, filter);

            if (courseobj == null)
            {
                Assert.IsNull(expectedObject);
            }
            else
            {
                Console.WriteLine(courseobj);
                Assert.AreEqual(expectedObject, courseobj.ToString());
            }
        }
Beispiel #5
0
        public override bool GetToolTip(Pane pane, PointF location, float pixelSize, out string tipText, out string titleText)
        {
            CourseLayout activeCourse;
            CourseView   courseView = selectionMgr.ActiveCourseView;

            if (pane == Pane.Map)
            {
                activeCourse = controller.GetCourseLayout();
            }
            else
            {
                activeCourse = controller.GetTopologyLayout();
            }

            CourseObj touchedObject = null;

            for (CourseLayer layer = CourseLayer.MainCourse; layer <= CourseLayer.AllControls; ++layer)
            {
                if (touchedObject == null)
                {
                    touchedObject = activeCourse.HitTest(location, pixelSize, layer, co => !(co is TopologyDropTargetCourseObj));
                }
            }

            if (touchedObject != null)
            {
                TextPart[] textParts = SelectionDescriber.DescribeCourseObject(symbolDB, eventDB, touchedObject, courseView.ScaleRatio);
                if (textParts != null)
                {
                    ConvertTextPartsToToolTip(textParts, out tipText, out titleText);
                    return(true);
                }
            }

            tipText = titleText = "";
            return(false);
        }
Beispiel #6
0
        // extraCourseIndex indicates the color/layer.
        private void AddExtraCourseToLayout(CourseLayout courseLayout, Id<Course> courseId, int extraCourseIndex)
        {
            if (extraCourseIndex >= CourseLayout.EXTRACOURSECOUNT)
                return;

            CourseAppearance appearance = controller.GetCourseAppearance();
            CourseLayer layer = CourseLayer.OtherCourse1 + extraCourseIndex;

            // Create the course view.
            CourseView courseView = CourseView.CreateCourseView(eventDB, new CourseDesignator(courseId),
                new CourseViewOptions() { showNonDescriptionSpecials = false, showDescriptionSpecials = false, showControlNumbers = false });

            // Add it to the CourseLayout.
            courseLayout.SetLayerColor(layer, (short) (NormalCourseAppearance.extraCourseOcadId + extraCourseIndex), 
                                              string.Format(NormalCourseAppearance.allControlsColorName, extraCourseIndex + 1),
                                              NormalCourseAppearance.extraCourseC[extraCourseIndex],
                                              NormalCourseAppearance.extraCourseM[extraCourseIndex],
                                              NormalCourseAppearance.extraCourseY[extraCourseIndex],
                                              NormalCourseAppearance.extraCourseK[extraCourseIndex],
                                              false);

            CourseFormatter.FormatCourseToLayout(symbolDB, courseView, appearance, courseLayout, layer,
                new CourseFormatterOptions() { showControlNumbers = false });
        }
        void CheckCourse(string testfileName, Id<Course> courseId, CourseLayer layer, string expected)
        {
            SymbolDB symbolDB = new SymbolDB(Util.GetFileInAppDirectory("symbols.xml"));
            UndoMgr undomgr = new UndoMgr(5);
            EventDB eventDB = new EventDB(undomgr);
            CourseView courseView;
            CourseLayout course;

            eventDB.Load(TestUtil.GetTestFile(testfileName));
            eventDB.Validate();

            // Create the course
            courseView = CourseView.CreateViewingCourseView(eventDB, new CourseDesignator(courseId));
            course = new CourseLayout();
            CourseFormatter.FormatCourseToLayout(symbolDB, courseView, defaultCourseAppearance, course, layer);

            // Dump it to a string.
            StringWriter writer = new StringWriter();
            course.Dump(writer);

            // Check that the string is correct.
            string actual = writer.ToString();
            if (expected != actual) {
                for (int i = 0; i < Math.Min(expected.Length, actual.Length); ++i)
                    if (actual[i] != expected[i]) {
                        Console.WriteLine("Difference at -->{0}", actual.Substring(i, 30));
                        break;
                    }
            }

            Assert.AreEqual(expected, writer.ToString());
        }
 void CheckHitTest(CourseLayout course, PointF point, CourseLayer layerFilter, Predicate<CourseObj> filter, string expectedObject)
 {
     CourseObj courseobj = course.HitTest(point, 0.1F, layerFilter, filter);
     if (courseobj == null) {
         Assert.IsNull(expectedObject);
     }
     else {
         Console.WriteLine(courseobj);
         Assert.AreEqual(expectedObject, courseobj.ToString());
     }
 }
Beispiel #9
0
        // Check a point against a set of course objects.
        // The layerFilter, if >= 0, limits the objects consider to those in the given layer.
        // The filter, if non-null, is an additional filter (return true to consider)
        public static CourseObj HitTestCollection(IEnumerable <CourseObj> courseObjects, PointF point, float pixelSize, CourseLayer layerFilter, Predicate <CourseObj> filter)
        {
            // We need to hit within 3 pixels of an object to select it.
            double    distanceLimit = pixelSize * 3;
            double    bestDistance  = distanceLimit;
            int       bestPriority  = -1;
            CourseObj bestObject    = null;

            foreach (CourseObj courseObject in courseObjects)
            {
                if (layerFilter >= 0 && courseObject.layer != layerFilter)
                {
                    continue;
                }
                if (filter != null && !filter(courseObject))
                {
                    continue;
                }

                double dist     = courseObject.DistanceFromPoint(point);
                int    priority = courseObject.SelectionPriority();
                if (dist < distanceLimit)
                {
                    // Could be selected. Check if other object is better.
                    if (priority > bestPriority || (priority == bestPriority && dist < bestDistance))
                    {
                        bestDistance = dist;
                        bestObject   = courseObject;
                        bestPriority = priority;
                    }
                }
            }

            return(bestObject);
        }
Beispiel #10
0
 // Find a course object from a point, and a "pixelsize" that says how big one pixel is.
 // If no course object is hit, then we return null.
 // The layerFilter, if >= 0, limits the objects consider to those in the given layer.
 // The filter, if non-null, is an additional filter (return true to consider)
 public CourseObj HitTest(PointF point, float pixelSize, CourseLayer layerFilter, Predicate <CourseObj> filter)
 {
     return(HitTestCollection(this, point, pixelSize, layerFilter, filter));
 }
Beispiel #11
0
        // Create the course objects associated with this special. Assign the given layer to it.
        static CourseObj CreateSpecial(EventDB eventDB, CourseView courseView, float scaleRatio, CourseAppearance appearance, Id<Special> specialId, CourseLayer normalLayer)
        {
            Special special = eventDB.GetSpecial(specialId);
            CourseObj courseObj = null;

            switch (special.kind) {
            case SpecialKind.FirstAid:
                courseObj = new FirstAidCourseObj(specialId, scaleRatio, appearance, special.locations[0]); break;
            case SpecialKind.Water:
                courseObj = new WaterCourseObj(specialId, scaleRatio, appearance, special.locations[0]); break;
            case SpecialKind.OptCrossing:
                courseObj = new CrossingCourseObj(Id<ControlPoint>.None, Id<CourseControl>.None, specialId, scaleRatio, appearance, special.orientation, special.locations[0]); break;
            case SpecialKind.Forbidden:
                courseObj = new ForbiddenCourseObj(specialId, scaleRatio, appearance, special.locations[0]); break;
            case SpecialKind.RegMark:
                courseObj = new RegMarkCourseObj(specialId, scaleRatio, appearance, special.locations[0]); break;
            case SpecialKind.Boundary:
                courseObj = new BoundaryCourseObj(specialId, scaleRatio, appearance, new SymPath(special.locations)); break;
            case SpecialKind.Rectangle:
                courseObj = new RectSpecialCourseObj(specialId, appearance, special.color, special.lineKind, special.lineWidth, special.cornerRadius, special.gapSize, special.dashSize, Geometry.RectFromPoints(special.locations[0], special.locations[1])); break;
            case SpecialKind.Line:
                courseObj = new LineSpecialCourseObj(specialId, appearance, special.color, special.lineKind, special.lineWidth, special.gapSize, special.dashSize, new SymPath(special.locations)); break;
            case SpecialKind.OOB:
                courseObj = new OOBCourseObj(specialId, scaleRatio, appearance, special.locations); break;
            case SpecialKind.Dangerous:
                courseObj = new DangerousCourseObj(specialId, scaleRatio, appearance, special.locations); break;
            case SpecialKind.WhiteOut:
                courseObj = new WhiteOutCourseObj(specialId, scaleRatio, appearance, special.locations); break;

            case SpecialKind.Image:
                Special imageSpecial = eventDB.GetSpecial(specialId);
                courseObj = new ImageCourseObj(specialId, scaleRatio, appearance, special.locations, imageSpecial.text, imageSpecial.imageBitmap);
                break;

            case SpecialKind.Text:
                string text = ExpandText(eventDB, courseView, special.text);
                FontStyle fontStyle = Util.GetFontStyle(special.fontBold, special.fontItalic);
                RectangleF boundingRect = RectangleF.FromLTRB((float)Math.Min(special.locations[0].X, special.locations[1].X), (float)Math.Min(special.locations[0].Y, special.locations[1].Y),
                                                                                              (float)Math.Max(special.locations[0].X, special.locations[1].X), (float)Math.Max(special.locations[0].Y, special.locations[1].Y));
                courseObj = new BasicTextCourseObj(specialId, text, boundingRect, special.fontName, fontStyle, special.color);
                break;
            case SpecialKind.Descriptions:
                Debug.Fail("description specials should not be passed to this function");
                return null;
            default:
                Debug.Fail("bad special kind");
                return null;
            }

            courseObj.layer = normalLayer;

            return courseObj;
        }
Beispiel #12
0
        // Create the course objects associated with this special. Assign the given layer to it.
        static CourseObj CreateDescriptionSpecial(EventDB eventDB, SymbolDB symbolDB, CourseView.DescriptionView descriptionView, CourseLayer layer)
        {
            Special special = eventDB.GetSpecial(descriptionView.SpecialId);
            Debug.Assert(special.kind == SpecialKind.Descriptions);

            DescriptionKind descKind;
            DescriptionLine[] description = GetCourseDescription(eventDB, symbolDB, descriptionView.CourseDesignator, out descKind);
            CourseObj courseObj = new DescriptionCourseObj(descriptionView.SpecialId, special.locations[0], (float)Geometry.Distance(special.locations[0], special.locations[1]), symbolDB, description, descKind, special.numColumns);
            courseObj.layer = layer;
            return courseObj;
        }
Beispiel #13
0
        // Cut any overlapping legs in the given layer.
        private static void AutoCutLegs(EventDB eventDB, CourseAppearance appearance, CourseDesignator courseDesignator, CourseLayout courseLayout, CourseLayer layer)
        {
            if (appearance.autoLegGapSize <= 0)
                return;     // No cutting requested.

            foreach (CourseObj courseObj in courseLayout) {
                if (courseObj.layer == layer && (courseObj is LegCourseObj || courseObj is FlaggedLegCourseObj))
                    AutoCutLeg(eventDB, appearance, courseDesignator, (LineCourseObj)courseObj, courseLayout);
            }
        }
Beispiel #14
0
 // Cut any overlapping control circles in the given layer.
 private static void AutoCutCircles(CourseLayout courseLayout, CourseLayer layer)
 {
     foreach (CourseObj courseObj in courseLayout) {
         if (courseObj.layer == layer && (courseObj is ControlCourseObj || courseObj is FinishCourseObj))
             AutoCutControl((PointCourseObj) courseObj, courseLayout);
     }
 }
Beispiel #15
0
        // Format the given CourseView into a bunch of course objects, and add it to the given course Layout
        public static void FormatCourseToLayout(SymbolDB symbolDB, CourseView courseView, CourseAppearance appearance, CourseLayout courseLayout, CourseLayer layer)
        {
            EventDB eventDB = courseView.EventDB;
            CourseView.CourseViewKind kind = courseView.Kind;
            ControlLabelKind labelKind = courseView.ControlLabelKind;
            float scaleRatio = courseView.ScaleRatio;
            List<CourseView.ControlView> controlViews = courseView.ControlViews;
            CourseObj courseObj;

            // Go through all the specials in the view and process them to create course objects
            foreach(Id<Special> specialId in courseView.SpecialIds) {
                courseObj = CreateSpecial(eventDB, courseView, scaleRatio, appearance, specialId, layer);
                if (courseObj != null)
                    courseLayout.AddCourseObject(courseObj);
            }

            // Go through all the descriptions in the view and process them to create course objects
            foreach (CourseView.DescriptionView descriptionView in courseView.DescriptionViews) {
                // The layer depends on "descriptions in purple" setting in the course appearance.
                courseObj = CreateDescriptionSpecial(eventDB, symbolDB, descriptionView, appearance.descriptionsPurple ? layer : CourseLayer.Descriptions);
                if (courseObj != null)
                    courseLayout.AddCourseObject(courseObj);
            }

            // Go through all the controls in the view and process them to create controls and legs.
            for (int controlIndex = 0; controlIndex < controlViews.Count; ++controlIndex) {
                CourseView.ControlView controlView = controlViews[controlIndex];

                if (!controlView.hiddenControl) {

                    // Get the angles of the legs into and out of this control, in radians.
                    double angleOut = ComputeAngleOut(eventDB, courseView, controlIndex);

                    // Get the normal course object associated with this control.
                    courseObj = CreateCourseObject(eventDB, scaleRatio, appearance, courseView.PrintScale, controlView, angleOut);
                    if (courseObj != null) {
                        courseObj.layer = layer;
                        courseLayout.AddCourseObject(courseObj);
                    }

                    // If this course-control indicates custom placement, place the number/code now (so it influences auto-placed numbers).
                    if (CustomPlaceNumber(eventDB, controlView)) {
                        if (kind == CourseView.CourseViewKind.AllControls)
                            courseObj = CreateCode(eventDB, scaleRatio, appearance, controlView, courseLayout);
                        else if (kind == CourseView.CourseViewKind.AllVariations)
                            courseObj = CreateControlNumber(eventDB, scaleRatio, appearance, ControlLabelKind.Code, controlView, courseView, courseLayout);
                        else
                            courseObj = CreateControlNumber(eventDB, scaleRatio, appearance, labelKind, controlView, courseView, courseLayout);

                        if (courseObj != null) {
                            courseObj.layer = layer;
                            courseLayout.AddCourseObject(courseObj);
                        }
                    }
                }

                if (kind == CourseView.CourseViewKind.Normal || kind == CourseView.CourseViewKind.AllVariations) {
                    // Get the object(s) associated with the leg(s) to the next control.
                    if (controlView.legTo != null) {
                        for (int leg = 0; leg < controlView.legTo.Length; ++leg) {
                            CourseObj[] courseObjs = CreateLeg(eventDB, scaleRatio, appearance, controlView.courseControlIds[leg], controlView, controlViews[controlView.legTo[leg]], controlView.legId[leg]);
                            if (courseObjs != null) {
                                foreach (CourseObj o in courseObjs) {
                                    o.layer = layer;
                                    courseLayout.AddCourseObject(o);
                                }
                            }
                        }
                    }
                }
            }

            // Add any additional controls
            foreach (Id<CourseControl> extraCourseControl in courseView.ExtraCourseControls) {
                courseLayout.AddCourseObject(CreateCourseObject(eventDB, scaleRatio, appearance, courseView.PrintScale,
                                                                eventDB.GetCourseControl(extraCourseControl).control, extraCourseControl, double.NaN));
            }

            // No go through each control again and add an automatically placed number/code to each. We do this last so that the placement
            // of all fixed-position objects influences the auto-positioned numbers so that they don't interfere.
            for (int controlIndex = 0; controlIndex < controlViews.Count; ++controlIndex) {
                CourseView.ControlView controlView = controlViews[controlIndex];

                // Only place numbers WITHOUT custom number placement. Those with custom placement were done previously above.
                if (!controlView.hiddenControl && ! CustomPlaceNumber(eventDB, controlView)) {
                    if (kind == CourseView.CourseViewKind.AllControls)
                        courseObj = CreateCode(eventDB, scaleRatio, appearance, controlView, courseLayout);
                    else if (kind == CourseView.CourseViewKind.AllVariations)
                        courseObj = CreateControlNumber(eventDB, scaleRatio, appearance, ControlLabelKind.Code, controlView, courseView, courseLayout);
                    else
                        courseObj = CreateControlNumber(eventDB, scaleRatio, appearance, labelKind, controlView, courseView, courseLayout);

                    if (courseObj != null) {
                        courseObj.layer = layer;
                        courseLayout.AddCourseObject(courseObj);
                    }
                }
            }

            // Automatically add cuts to close control circles in the layout.
            if (courseView.Kind != CourseView.CourseViewKind.AllControls) {
                AutoCutCircles(courseLayout, layer);
                AutoCutLegs(eventDB, appearance, courseView.CourseDesignator, courseLayout, layer);
            }
        }