// Create the highlight, and put it at the given location. // Set displayUpdateNeeded to true if the highlight was just created or was moved. void SetHighlightLocation(PointF highlightLocation, float pixelSize, ref bool displayUpdateNeeded) { if (highlight != null && highlight.location == highlightLocation) return; // Note, we cannot change this existing highlight because it is needed for erasing. switch (specialKind) { case SpecialKind.FirstAid: highlight = new FirstAidCourseObj(Id<Special>.None, scaleRatio, appearance, highlightLocation); break; case SpecialKind.Water: highlight = new WaterCourseObj(Id<Special>.None, scaleRatio, appearance, highlightLocation); break; case SpecialKind.OptCrossing: highlight = new CrossingCourseObj(Id<ControlPoint>.None, Id<CourseControl>.None, Id<Special>.None, scaleRatio, appearance, 0, highlightLocation); break; case SpecialKind.Forbidden: highlight = new ForbiddenCourseObj(Id<Special>.None, scaleRatio, appearance, highlightLocation); break; case SpecialKind.RegMark: highlight = new RegMarkCourseObj(Id<Special>.None, scaleRatio, appearance, highlightLocation); break; default: throw new Exception("bad special kind"); } highlight.location = highlightLocation; displayUpdateNeeded = true; }
// Cut the leg "legObj" with respect to "otherObj", if they overlap private static void CutLegWithRespectTo(EventDB eventDB, CourseAppearance appearance, CourseDesignator courseDesignator, LineCourseObj legObj, PointCourseObj otherObj) { float radiusOther = otherObj.ApparentRadius; PointF nearestPointOnLeg; float distance = legObj.path.DistanceFromPoint(otherObj.location, out nearestPointOnLeg); if (distance < radiusOther && Geometry.Distance(nearestPointOnLeg, legObj.path.FirstPoint) > 0.5 && Geometry.Distance(nearestPointOnLeg, legObj.path.LastPoint) > 0.5) { float gapRadius = (float) Math.Sqrt(radiusOther * radiusOther - distance * distance); // pythagorean theorem. gapRadius += appearance.autoLegGapSize / 2; CutLegAtPoint(legObj, nearestPointOnLeg, gapRadius); } }
// Create the highlight, and put it at the given location. // Set displayUpdateNeeded to true if the highlight was just created or was moved. void SetHighlightLocation(PointF highlightLocation, float pixelSize, ref bool displayUpdateNeeded) { if (highlight != null && highlight.location == highlightLocation) return; PointF unused; Id<ControlPoint> existingControl = HitTestPoint(highlightLocation, pixelSize, out unused); // Get where the control is being inserted. CourseDesignator courseDesignator; Id<CourseControl> courseControl1, courseControl2; GetControlInsertionPoint(highlightLocation, out courseDesignator, out courseControl1, out courseControl2); // Note, we cannot changed this existing highlight because it is needed for erasing. additionalHighlights = null; switch (controlKind) { case ControlPointKind.Normal: highlight = new ControlCourseObj(Id<ControlPoint>.None, Id<CourseControl>.None, scaleRatio, appearance, null, highlightLocation); if (courseDesignator.IsNotAllControls && !(exchangeAtControl && existingControl.IsNotNone && QueryEvent.CourseUsesControl(eventDB, courseDesignator, existingControl)) && eventDB.GetCourse(courseDesignator.CourseId).kind != CourseKind.Score) { // Show the legs to and from the control also as additional highlights. additionalHighlights = CreateLegHighlights(eventDB, highlightLocation, Id<ControlPoint>.None, controlKind, courseControl1, courseControl2, scaleRatio, appearance); } break; case ControlPointKind.Start: highlight = new StartCourseObj(Id<ControlPoint>.None, Id<CourseControl>.None, scaleRatio, appearance, 0, highlightLocation, CrossHairOptions.HighlightCrossHair); break; case ControlPointKind.MapExchange: highlight = new StartCourseObj(Id<ControlPoint>.None, Id<CourseControl>.None, scaleRatio, appearance, 0, highlightLocation, CrossHairOptions.HighlightCrossHair); if (courseDesignator.IsNotAllControls && eventDB.GetCourse(courseDesignator.CourseId).kind != CourseKind.Score) { // Show the legs to and from the control also as additional highlights. additionalHighlights = CreateLegHighlights(eventDB, highlightLocation, Id<ControlPoint>.None, controlKind, courseControl1, courseControl2, scaleRatio, appearance); } break; case ControlPointKind.Finish: highlight = new FinishCourseObj(Id<ControlPoint>.None, Id<CourseControl>.None, scaleRatio, appearance, null, highlightLocation, CrossHairOptions.HighlightCrossHair); break; case ControlPointKind.CrossingPoint: highlight = new CrossingCourseObj(Id<ControlPoint>.None, Id<CourseControl>.None, Id<Special>.None, scaleRatio, appearance, 0, highlightLocation); if (courseDesignator.IsNotAllControls && eventDB.GetCourse(courseDesignator.CourseId).kind != CourseKind.Score) { // Show the legs to and from the control also as additional highlights. additionalHighlights = CreateLegHighlights(eventDB, highlightLocation, Id<ControlPoint>.None, controlKind, courseControl1, courseControl2, scaleRatio, appearance); } break; default: throw new Exception("bad control kind"); } highlight.location = highlightLocation; displayUpdateNeeded = true; }
// Cut "controlObj" with respect to "courseObj", if courseObj is close enough to overlap. private static void CutControlWithRespectTo(PointCourseObj controlObj, PointCourseObj courseObj) { float radiusControl = controlObj.ApparentRadius; float radiusOther = courseObj.ApparentRadius; double distance = Geometry.Distance(controlObj.location, courseObj.location); if (distance < (radiusControl + radiusOther) * 0.9F && distance > (radiusControl + radiusOther) * 0.35F) { // The other object is close enough to the control to merit cutting, but not too close. (0.9 and 0.35 were just arrived by what looks good.) // Law of cosines... double arcCos = (radiusControl * radiusControl + distance * distance - radiusOther * radiusOther) / (2 * radiusControl * distance); float halfAngleGap = (float) (180 * Math.Acos(arcCos) / Math.PI); float angleGap = Geometry.Angle(controlObj.location, courseObj.location); controlObj.gaps = CircleGap.AddGap(controlObj.gaps, angleGap - halfAngleGap, angleGap + halfAngleGap); } }
// Check this control and add cuts to it if needed. private static void AutoCutControl(PointCourseObj controlObj, CourseLayout courseLayout) { foreach (CourseObj courseObj in courseLayout) { if (courseObj != controlObj && courseObj.layer == controlObj.layer && courseObj is PointCourseObj) CutControlWithRespectTo(controlObj, (PointCourseObj)courseObj); } }
public AddControlGapMode(Controller controller, PointCourseObj courseObj) { this.controller = controller; this.courseObjStart = (PointCourseObj) courseObj.Clone(); this.courseObjDrag = (PointCourseObj) courseObj.Clone(); }
PointCourseObj courseObj; // object to modify. #endregion Fields #region Constructors public RemoveControlGapMode(Controller controller, PointCourseObj courseObj) { this.controller = controller; this.courseObj = (PointCourseObj) courseObj.Clone(); }
public override void LeftButtonDrag(Pane pane, PointF location, PointF locationStart, float pixelSize, ref bool displayUpdateNeeded) { Debug.Assert(pane == Pane.Map); // Get the new set of gaps. CircleGap[] newGaps = CircleGap.AddGap(courseObjStart.location, courseObjStart.gaps, startDrag, location); CircleGap[] newMovableGaps = CircleGap.AddGap(courseObjStart.location, courseObjStart.movableGaps, startDrag, location); // Put the new gaps into the highlight. courseObjDrag = (PointCourseObj) courseObjStart.Clone(); courseObjDrag.gaps = newGaps; courseObjDrag.movableGaps = newMovableGaps; displayUpdateNeeded = true; }