public void HitTest() { 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("courselayout\\marymoor1.coursescribe")); eventDB.Validate(); // Create the all controls course courseView = CourseView.CreateViewingCourseView(eventDB, CourseDesignator.AllControls); course = new CourseLayout(); CourseFormatter.FormatCourseToLayout(symbolDB, courseView, defaultCourseAppearance, course, 0); CheckHitTest(course, new PointF(9.0F, 12.4F), 0, null, "Water: special:1 scale:1 location:(7.996275,12.34392)"); CheckHitTest(course, new PointF(54.7F, 12.2F), 0, null, null); CheckHitTest(course, new PointF(0.5F, 9.0F), 0, null, "Control: control:72 scale:1 location:(-0.7,10.3) gaps:"); CheckHitTest(course, new PointF(58.5F, -9.2F), 0, null, "Start: control:1 scale:1 location:(56.8,-8.7) orientation:0"); CheckHitTest(course, new PointF(46.6F, -15.9F), 0, null, @"Code: control:52 scale:1 text:52 top-left:(45.56,-12.18) font-name:Roboto Condensed font-style:Bold font-height:4.18"); // Create course 3 courseView = CourseView.CreateViewingCourseView(eventDB, new CourseDesignator(CourseId(3))); course = new CourseLayout(); CourseFormatter.FormatCourseToLayout(symbolDB, courseView, defaultCourseAppearance, course, 0); CheckHitTest(course, new PointF(-3.5F, 10.3F), 0, null, "Control: control:72 course-control:305 scale:1 location:(-0.7,10.3) gaps:"); CheckHitTest(course, new PointF(35.6F, 17.7F), 0, null, null); CheckHitTest(course, new PointF(59.2F, 18.5F), 0, null, "Leg: control:71 course-control:307 scale:1 course-control2:308 path:N(42.92,17.55)--N(71.88,19.05)"); CheckHitTest(course, new PointF(72.1F, 33.5F), 0, null, @"ControlNumber: control:75 course-control:311 scale:1 text:10 top-left:(66.57,37.12) font-name:Roboto font-style:Regular font-height:5.57"); CheckHitTest(course, new PointF(50.2F, -2.9F), 0, null, @"Finish: control:2 course-control:315 scale:1 location:(53.2,-2.8) gaps:"); // Add in all controls. Test with true and false for all Layers. courseView = CourseView.CreateFilteredAllControlsView(eventDB, new CourseDesignator[] { Designator(3) }, ControlPointKind.Normal, new CourseViewOptions() { showNonDescriptionSpecials = false, showDescriptionSpecials = true }); CourseFormatter.FormatCourseToLayout(symbolDB, courseView, defaultCourseAppearance, course, CourseLayer.AllControls); CheckHitTest(course, new PointF(5.1F, -5.1F), CourseLayer.All, null, @"Control: layer:12 control:76 scale:1 location:(5.6,-5.7) gaps:"); CheckHitTest(course, new PointF(5.1F, -5.1F), CourseLayer.MainCourse, null, null); // Test the type filter CheckHitTest(course, new PointF(59.2F, 18.5F), CourseLayer.MainCourse, (co => co is LegCourseObj), "Leg: control:71 course-control:307 scale:1 course-control2:308 path:N(42.92,17.55)--N(71.88,19.05)"); CheckHitTest(course, new PointF(59.2F, 18.5F), CourseLayer.MainCourse, (co => co is PointCourseObj), null); CheckHitTest(course, new PointF(-3.5F, 10.3F), CourseLayer.MainCourse, (co => co is PointCourseObj), "Control: control:72 course-control:305 scale:1 location:(-0.7,10.3) gaps:"); CheckHitTest(course, new PointF(-3.5F, 10.3F), CourseLayer.MainCourse, (co => co is LineCourseObj), null); }
public AddTextMode(Controller controller, UndoMgr undoMgr, SelectionMgr selectionMgr, EventDB eventDB, string text, string fontName, bool fontBold, bool fontItalic, SpecialColor fontColor, float fontHeight) { this.controller = controller; this.undoMgr = undoMgr; this.selectionMgr = selectionMgr; this.eventDB = eventDB; this.text = text; this.fontName = fontName; this.fontBold = fontBold; this.fontItalic = fontItalic; this.fontColor = fontColor; this.fontHeight = fontHeight; this.displayText = CourseFormatter.ExpandText(eventDB, selectionMgr.ActiveCourseView, text); }
// Create a leg object from one point to another. Might return null. The controlIds can be None, but if they are supplied, then // they are used to handle bends. If either is null, the leg object is just straight. Gaps are never displayed. private static LegCourseObj CreateLegHighlight(EventDB eventDB, PointF pt1, ControlPointKind kind1, Id <ControlPoint> controlId1, PointF pt2, ControlPointKind kind2, Id <ControlPoint> controlId2, float courseObjRatio, CourseAppearance appearance) { LegGap[] gaps; SymPath path = CourseFormatter.GetLegPath(eventDB, pt1, kind1, controlId1, pt2, kind2, controlId2, float.NaN, courseObjRatio, appearance, out gaps); if (path != null) { return(new LegCourseObj(controlId1, Id <CourseControl> .None, Id <CourseControl> .None, courseObjRatio, appearance, path, null)); // We never display the gaps, because it looks dumb. } else { return(null); } }
public void BoundingRect() { 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("courselayout\\marymoor1.coursescribe")); eventDB.Validate(); // Create the all controls course courseView = CourseView.CreateViewingCourseView(eventDB, CourseDesignator.AllControls); course = new CourseLayout(); CourseFormatter.FormatCourseToLayout(symbolDB, courseView, defaultCourseAppearance, course, 0); RectangleF bounding = course.BoundingRect(); RectangleF expected = new RectangleF(-16.41F, -34.3F, 152.17F, 79.95F); TestUtil.AssertEqualRect(expected, bounding, 0.01F, "Bounding rect all controls"); // Try course 1 courseView = CourseView.CreateViewingCourseView(eventDB, new CourseDesignator(CourseId(1))); course = new CourseLayout(); CourseFormatter.FormatCourseToLayout(symbolDB, courseView, defaultCourseAppearance, course, 0); bounding = course.BoundingRect(); expected = new RectangleF(-2.11F, -32.9F, 64.73F, 60.43F); TestUtil.AssertEqualRect(expected, bounding, 0.1F, "Bounding rect course 1"); // Try course with control descriptions on it. courseView = CourseView.CreateViewingCourseView(eventDB, new CourseDesignator(CourseId(10))); course = new CourseLayout(); CourseFormatter.FormatCourseToLayout(symbolDB, courseView, defaultCourseAppearance, course, 0); bounding = course.BoundingRect(); expected = new RectangleF(6.0F, -40.1F, 121.94F, 77.22F); TestUtil.AssertEqualRect(expected, bounding, 0.1F, "Bounding rect course 10"); // Do an empty course courseView = CourseView.CreateViewingCourseView(eventDB, new CourseDesignator(CourseId(11))); course = new CourseLayout(); CourseFormatter.FormatCourseToLayout(symbolDB, courseView, defaultCourseAppearance, course, 0); bounding = course.BoundingRect(); expected = RectangleF.FromLTRB(0, 0, 0, 0); TestUtil.AssertEqualRect(expected, bounding, 0.001F, "Bounding rect blank course"); }
// The core printing routine. void DrawPage(IGraphicsTarget graphicsTarget, CoursePage page) { // Get the course view for the course we are printing. CourseView courseView = CourseView.CreatePrintingCourseView(eventDB, page.courseDesignator); // Get the correct purple color to print the course in. short ocadId; float purpleC, purpleM, purpleY, purpleK; bool purpleOverprint; FindPurple.GetPurpleColor(mapDisplay, appearance, out ocadId, out purpleC, out purpleM, out purpleY, out purpleK, out purpleOverprint); // Create a course layout from the view. CourseLayout layout = new CourseLayout(); layout.SetLayerColor(CourseLayer.Descriptions, NormalCourseAppearance.blackColorOcadId, NormalCourseAppearance.blackColorName, NormalCourseAppearance.blackColorC, NormalCourseAppearance.blackColorM, NormalCourseAppearance.blackColorY, NormalCourseAppearance.blackColorK, false); layout.SetLayerColor(CourseLayer.MainCourse, ocadId, NormalCourseAppearance.courseColorName, purpleC, purpleM, purpleY, purpleK, purpleOverprint); CourseFormatter.FormatCourseToLayout(symbolDB, courseView, appearance, layout, CourseLayer.MainCourse); // Set the course layout into the map display mapDisplay.SetCourse(layout); mapDisplay.SetPrintArea(null); // Set the transform, and the clip. Matrix transform = Geometry.CreateInvertedRectangleTransform(page.mapRectangle, page.printRectangle); PushRectangleClip(graphicsTarget, page.printRectangle); graphicsTarget.PushTransform(transform); // Determine the resolution in map coordinates. Matrix inverseTransform = transform.Clone(); inverseTransform.Invert(); float minResolutionPage = 100F / 2400F; // Assume 2400 DPI as the base resolution, to get very accurate print. float minResolutionMap = Geometry.TransformDistance(minResolutionPage, inverseTransform); // And draw. mapDisplay.Draw(graphicsTarget, page.mapRectangle, minResolutionMap); graphicsTarget.PopTransform(); graphicsTarget.PopClip(); }
// Udate the selected course objects in the course. void UpdateSelectedCourseObjects() { if (selectionKind == SelectionKind.None) { selectedCourseObjects = null; return; } List<CourseObj> list = new List<CourseObj>(); // Get through each object in the active course and find which ones match. Ignore stuff in the All Controls layer. foreach (CourseObj courseobj in activeCourse) { if (courseobj.layer != CourseLayer.AllControls) { if (selectionKind == SelectionKind.Control && !(courseobj is LineCourseObj) && // don't select legs courseobj.controlId == selectedControl && courseobj.courseControlId == selectedCourseControl) { list.Add(courseobj); } else if (selectionKind == SelectionKind.Leg && courseobj is LineCourseObj && courseobj.courseControlId == selectedCourseControl && ((LineCourseObj) courseobj).courseControlId2 == selectedCourseControl2) { // The leg may be made up of multiple parts due to flagging and gaps. Create a single course object for the whole thing. CourseObj legObject = CourseFormatter.CreateSimpleLeg(eventDB, activeCourseView, courseobj.courseObjRatio, courseobj.appearance, selectedCourseControl, selectedCourseControl2); if (legObject != null) list.Add(legObject); break; } else if (selectionKind == SelectionKind.Special && courseobj.specialId == selectedSpecial) { list.Add(courseobj); } } } selectedCourseObjects = list.ToArray(); }
// Update the course void UpdateCourse() { CourseAppearance appearance = controller.GetCourseAppearance(); // Get purple color. short purpleOcadId; float purpleC, purpleM, purpleY, purpleK; bool purpleOverprint; controller.GetPurpleColor(out purpleOcadId, out purpleC, out purpleM, out purpleY, out purpleK, out purpleOverprint); // Place the active course in the layout. activeCourse = new CourseLayout(); activeCourse.SetLayerColor(CourseLayer.Descriptions, NormalCourseAppearance.blackColorOcadId, NormalCourseAppearance.blackColorName, NormalCourseAppearance.blackColorC, NormalCourseAppearance.blackColorM, NormalCourseAppearance.blackColorY, NormalCourseAppearance.blackColorK, false); activeCourse.SetLayerColor(CourseLayer.MainCourse, NormalCourseAppearance.courseOcadId, NormalCourseAppearance.courseColorName, purpleC, purpleM, purpleY, purpleK, (purpleOverprint && (extraCourses == null || extraCourses.Count == 0))); CourseFormatter.FormatCourseToLayout(symbolDB, activeCourseView, appearance, activeCourse, CourseLayer.MainCourse); if (showAllControls && !activeCourseDesignator.IsAllControls) { // Create the all controls view. CourseView allControlsView = CourseView.CreateFilteredAllControlsView(eventDB, new CourseDesignator[] { activeCourseDesignator }, allControlsFilter, new CourseViewOptions() { showNonDescriptionSpecials = false, showDescriptionSpecials = false }); // Add it to the CourseLayout. activeCourse.SetLayerColor(CourseLayer.AllControls, NormalCourseAppearance.allControlsOcadId, NormalCourseAppearance.allControlsColorName, NormalCourseAppearance.allControlsColorC, NormalCourseAppearance.allControlsColorM, NormalCourseAppearance.allControlsColorY, NormalCourseAppearance.allControlsColorK, purpleOverprint); CourseFormatter.FormatCourseToLayout(symbolDB, allControlsView, appearance, activeCourse, CourseLayer.AllControls); } if (extraCourses != null && extraCourses.Count > 0) { for (int i = 0; i < extraCourses.Count; ++i) { Id<Course> courseId = extraCourses[i]; if (eventDB.IsCoursePresent(courseId)) { AddExtraCourseToLayout(activeCourse, courseId, i % CourseLayout.EXTRACOURSECOUNT); } } } }
// 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 }); }
// Get the area of the map we want to print, in map coordinates, and the print scale. // if the courseId is None, do all controls. // If asked for, crop to a single page size. RectangleF GetPrintAreaForCourse(CourseDesignator courseDesignator, out bool landscape, out PaperSize paperSize, out int margins, out float scaleRatio, out string description) { // Get the course view to get the scale ratio. CourseView courseView = CourseView.CreatePositioningCourseView(eventDB, courseDesignator); scaleRatio = courseView.ScaleRatio; description = courseView.CourseFullName; RectangleF printRectangle = controller.GetCurrentPrintAreaRectangle(courseDesignator); PrintArea printArea = controller.GetCurrentPrintArea(courseDesignator); landscape = printArea.pageLandscape; paperSize = new PaperSize("", printArea.pageWidth, printArea.pageHeight); margins = printArea.pageMargins; if (cropLargePrintArea) { // Crop the print area to a single page, portrait or landscape. // Try to keep CourseObjects in view as much as possible. CourseLayout layout = new CourseLayout(); CourseFormatter.FormatCourseToLayout(symbolDB, courseView, appearance, layout, 0); RectangleF courseObjectsArea = layout.BoundingRect(); courseObjectsArea.Intersect(printRectangle); // We may need to crop the print area to fit. float areaCovered; RectangleF printableArea = GetPrintablePageArea(landscape, paperSize, margins); RectangleF croppedRectangle = CropPrintArea(printRectangle, courseObjectsArea, GetScaledPrintableSizeInMapUnits(printableArea, scaleRatio), out areaCovered); return(croppedRectangle); } else { return(printRectangle); } }
// The core printing routine. The origin of the graphics is the upper-left of the margins, // and the printArea in the size to draw into (in hundreths of an inch). protected override void DrawPage(IGraphicsTarget graphicsTarget, int pageNumber, SizeF printArea, float dpi) { CoursePage page = pages[pageNumber]; // Get the course view for the course we are printing. CourseView courseView = CourseView.CreatePrintingCourseView(eventDB, page.courseDesignator); // Get the correct purple color to print the course in. short ocadId; float purpleC, purpleM, purpleY, purpleK; bool purpleOverprint; FindPurple.GetPurpleColor(mapDisplay, appearance, out ocadId, out purpleC, out purpleM, out purpleY, out purpleK, out purpleOverprint); // Create a course layout from the view. CourseLayout layout = new CourseLayout(); layout.SetLayerColor(CourseLayer.Descriptions, NormalCourseAppearance.blackColorOcadId, NormalCourseAppearance.blackColorName, NormalCourseAppearance.blackColorC, NormalCourseAppearance.blackColorM, NormalCourseAppearance.blackColorY, NormalCourseAppearance.blackColorK, false); layout.SetLayerColor(CourseLayer.MainCourse, ocadId, NormalCourseAppearance.courseColorName, purpleC, purpleM, purpleY, purpleK, purpleOverprint); CourseFormatter.FormatCourseToLayout(symbolDB, courseView, appearance, layout, CourseLayer.MainCourse); // Set the course layout into the map display mapDisplay.SetCourse(layout); this.mapDisplay.SetPrintArea(null); // Collecting garbage should make out of memory less common. GC.Collect(); if (graphicsTarget is GDIPlus_GraphicsTarget) { // We print to intermediate bands of bitmaps. This is the only way to get purple blending correct. // Other code ensure that if purple blending is on, we always take this code path. GDIPlus_GraphicsTarget gdiGraphicsTarget = ((GDIPlus_GraphicsTarget)graphicsTarget); Graphics g = gdiGraphicsTarget.Graphics; // Save and restore state so we can mess with stuff. GraphicsState graphicsState = g.Save(); // Printing via a bitmap. Works best with some print drivers. dpi = AdjustDpi(dpi); const long MAX_PIXELS_PER_BAND = 20000000; // 20M pixels = 60M bytes (3 bytes per pixel). List <CoursePage> bands = BandPageToLimitBitmapSize(page, dpi, MAX_PIXELS_PER_BAND); // Create the bitmap. Can do this once because each band is the same size. int bitmapWidth = (int)Math.Round(bands[0].printRectangle.Width * dpi / 100F); int bitmapHeight = (int)Math.Round(bands[0].printRectangle.Height * dpi / 100F); Bitmap bitmap = new Bitmap(bitmapWidth, bitmapHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb); foreach (CoursePage band in bands) { // Set the transform Matrix transform = Geometry.CreateInvertedRectangleTransform(band.mapRectangle, new RectangleF(0, 0, bitmapWidth, bitmapHeight)); mapDisplay.Draw(bitmap, transform); try { // Draw the bitmap on the printer. g.DrawImage(bitmap, band.printRectangle); } catch (Exception) { } } // restore state. g.Restore(graphicsState); bitmap.Dispose(); } else { // Print directly. Used only when prerasterization is off. // Set the transform, and the clip. Matrix transform = Geometry.CreateInvertedRectangleTransform(page.mapRectangle, page.printRectangle); PushRectangleClip(graphicsTarget, page.printRectangle); graphicsTarget.PushTransform(transform); // Determine the resolution in map coordinates. Matrix inverseTransform = transform.Clone(); inverseTransform.Invert(); float minResolutionPage = 100F / dpi; float minResolutionMap = Geometry.TransformDistance(minResolutionPage, inverseTransform); // And draw. mapDisplay.Draw(graphicsTarget, page.mapRectangle, minResolutionMap); graphicsTarget.PopTransform(); graphicsTarget.PopClip(); } }