Image GetImage(Operation op, LineFeature line) { // If the creating op can't be updated, use a no-entry sign. if (!(op is IRevisable)) { return(smallImageList.Images["NoEntry"]); } // If the line is not a circular curve, use the line icon. ArcFeature arc = (line as ArcFeature); if (arc == null) { return(smallImageList.Images["Line"]); } // This leaves us with either a circle, or gray circle. if (arc.Circle.Creator == op) { return(smallImageList.Images["Circle"]); } else { return(smallImageList.Images["GrayCircle"]); } }
/// <summary> /// Performs data processing that involves creating or retiring spatial features. /// Newly created features will not have any definition for their geometry - a /// subsequent call to <see cref="CalculateGeometry"/> is needed to to that. /// </summary> /// <param name="ff">The factory class for generating any spatial features</param> internal override void ProcessFeatures(FeatureFactory ff) { // If the closing point does not already exist, create one at some unspecified position OffsetPoint offset = (m_Radius as OffsetPoint); PointFeature p = (offset == null ? null : offset.Point); if (p == null) { p = ff.CreatePointFeature(DataField.ClosingPoint); } // Form the construction line (there is no associated circle at this stage, because // geometry does not get created until CalculateGeometry) ArcFeature arc = ff.CreateArcFeature(DataField.Arc, p, p); // Attach a new circle with undefined radius (at this stage, we do NOT cross-reference // it to the center point or add it to the map model, since that should be left unti; // CalculateGeometry). // Note: Setting the arc geometry also updates the circle to refer back to the feature. var circle = new Circle(m_Center, 0.0); arc.Geometry = new ArcGeometry(circle, arc.StartPoint, arc.StartPoint, true); base.SetNewLine(arc); }
/// <summary> /// Performs the data processing associated with this editing operation. /// </summary> /// <param name="ctx">The context in which the geometry is being calculated.</param> internal override void CalculateGeometry(EditingContext ctx) { // Get the radius, in meters on the ground. double rad = m_Radius.GetDistance(m_Center).Meters; if (rad < Constants.TINY) { throw new Exception("NewCircleOperation.CalculateGeometry - Radius is too close to zero."); } // If the closing point was created by this edit, define it's position ArcFeature arc = (ArcFeature)this.Line; PointFeature p = arc.StartPoint; if (p.Creator == this) { PointGeometry pg = new PointGeometry(m_Center.X, m_Center.Y + rad); p.ApplyPointGeometry(ctx, pg); } // Define the radius of the circle and include in the map model Circle circle = arc.Circle; Debug.Assert(circle != null); circle.Radius = rad; // Refer the center point to the circle. circle.AddReferences(); }
/// <summary> /// Returns the offset for the parallel, in units on the mapping plane. In order /// for this to work, a prior call to Calculate must be made. /// </summary> /// <returns>The offset distance on the mapping plane (>= 0).</returns> internal double GetPlanarOffset() { // If the reference line or the parallel points are undefined, there's nothing we can do. if (m_Line == null || m_Par1 == null || m_Par2 == null) { return(0.0); } // If the reference line is a curve, get the curve info. ArcFeature arc = m_Line.GetArcBase(); if (arc != null) { // Get the (planar) radial offset from the circle to one of the parallel positions. double radius = arc.Circle.Radius; IPosition center = arc.Circle.Center; return(Math.Abs(Geom.Distance(center, m_Par1) - radius)); } // Get the ends of the reference line. IPosition spos = m_Line.StartPoint; IPosition epos = m_Line.EndPoint; // And its bearing. double bearing = Geom.BearingInRadians(spos, epos); // Get the perpendicular distance (signed) from one of the // parallel points to the reference line. double offdist = Geom.SignedDistance(spos.X, spos.Y, bearing, m_Par1.X, m_Par1.Y); return(Math.Abs(offdist)); }
/// <summary> /// Performs the data processing associated with this editing operation. /// </summary> /// <param name="ctx">The context in which the geometry is being calculated.</param> internal override void CalculateGeometry(EditingContext ctx) { IPosition p = Calculate(); PointGeometry pg = PointGeometry.Create(p); m_NewPoint.ApplyPointGeometry(ctx, pg); // If the extension line was a circular arc, we also need to define it's geometry. // This COULD have been defined at an earlier stage (e.g. as part of CreateFeature), // but it's more consistent to do it as part of this method. if (m_NewLine is ArcFeature) { ArcFeature arc = m_ExtendLine.GetArcBase(); Circle circle = arc.Circle; Debug.Assert(circle != null); bool iscw = arc.IsClockwise; if (!m_IsExtendFromEnd) { iscw = !iscw; } ArcGeometry geom = new ArcGeometry(circle, m_NewLine.StartPoint, m_NewLine.EndPoint, iscw); (m_NewLine as ArcFeature).Geometry = geom; } }
/// <summary> /// Initializes a new instance of the <see cref="NewArcOperation"/> class /// using the data read from persistent storage. /// </summary> /// <param name="editDeserializer">The mechanism for reading back content.</param> internal NewArcOperation(EditDeserializer editDeserializer) : base(editDeserializer) { // I originally let the base class do it, but it needs to be an instance // of ArcFeature. This is a bit rough - does NewArcOperation really need // to extend NewLineOperation? ArcFeature arc = editDeserializer.ReadPersistent <ArcFeature>(DataField.Line); SetNewLine(arc); }
/// <summary> /// Obtains the features that are referenced by this operation (including features /// that are indirectly referenced by observation classes). /// </summary> /// <returns> /// The referenced features (never null, but may be an empty array). /// </returns> public override Feature[] GetRequiredFeatures() { List <Feature> result = new List <Feature>(base.GetRequiredFeatures()); ArcFeature arc = (ArcFeature)this.Line; PointFeature center = arc.Circle.CenterPoint; if (center.Creator != this) { result.Add(center); } return(result.ToArray()); }
/// <summary> /// Calculates positions that are parallel to a line. /// </summary> /// <param name="line">The reference line.</param> /// <param name="offpoint">The point the parallel must pass through.</param> /// <param name="sres">The position of the start of the parallel.</param> /// <param name="eres">The position of the end of the parallel.</param> /// <returns>True if positions calculated ok</returns> internal static bool Calculate(LineFeature refline, PointFeature offpoint, out IPosition sres, out IPosition eres) { // No result positions so far. sres = eres = null; // Get the ends of the reference line. IPosition spos = refline.StartPoint; IPosition epos = refline.EndPoint; // If the reference line is a circular arc ArcFeature arc = refline.GetArcBase(); if (arc != null) { // Get the curve info Circle circle = arc.Circle; double radius = circle.Radius; IPosition centre = circle.Center; bool iscw = arc.IsClockwise; // Get the (planar) distance from the centre of the // circle to the offset point. double offdist = Geom.Distance(offpoint, centre); // Project the BC/EC radially. double sbear = Geom.BearingInRadians(centre, spos); sres = Geom.Polar(centre, sbear, offdist); double ebear = Geom.BearingInRadians(centre, epos); eres = Geom.Polar(centre, ebear, offdist); } else { double bearing = Geom.BearingInRadians(spos, epos); // Get the perpendicular distance (signed) from the offset point // to the reference line. double offdist = Geom.SignedDistance(spos.X, spos.Y, bearing, offpoint.X, offpoint.Y); // Calculate the parallel points. bearing += Constants.PIDIV2; sres = Geom.Polar(spos, bearing, offdist); eres = Geom.Polar(epos, bearing, offdist); } return(true); }
internal void Draw() // was Paint { // Nothing to do if parallel points undefined. if (m_South == null || m_North == null) { return; } Debug.Assert(m_Line != null); ISpatialDisplay draw = m_Cmd.ActiveDisplay; IDrawStyle solidStyle = EditingController.Current.Style(Color.Magenta); IDrawStyle dottedStyle = new DottedStyle(); ArcFeature arc = m_Line.GetArcBase(); if (arc != null) { // The parallel portion is solid, while the remaining portion of the circle is dotted. CircularArcGeometry cg = new CircularArcGeometry(arc.Circle.Center, m_South, m_North, arc.IsClockwise); solidStyle.Render(draw, cg); cg.IsClockwise = !cg.IsClockwise; dottedStyle.Render(draw, cg); } else { // What's the bearing from the start to the end of the parallel? double bearing = Geom.BearingInRadians(m_South, m_North); // What's the max length of a diagonal crossing the entire screen? double maxdiag = m_Cmd.MaxDiagonal; // Project to a point below the southern end of the parallel, as // well as a point above the northern end. IPosition below = Geom.Polar(m_South, bearing + Constants.PI, maxdiag); IPosition above = Geom.Polar(m_North, bearing, maxdiag); LineSegmentGeometry.Render(below, m_South, draw, dottedStyle); LineSegmentGeometry.Render(m_South, m_North, draw, solidStyle); LineSegmentGeometry.Render(m_North, above, draw, dottedStyle); // If we have an offset point, draw it in green. if (m_Point != null) { m_Point.Draw(draw, Color.Green); } } }
/// <summary> /// Performs the data processing associated with this editing operation. /// </summary> /// <param name="ctx">The context in which the geometry is being calculated.</param> internal override void CalculateGeometry(EditingContext ctx) { // Calculate the end positions IPosition spos, epos; if (!Calculate(out spos, out epos)) { throw new Exception("Failed to calculate parallel line positions"); } // Apply the calculated positions so long as the end points of the parallel line // were created by this edit if (m_ParLine.StartPoint.Creator == this) { m_ParLine.StartPoint.ApplyPointGeometry(ctx, PointGeometry.Create(spos)); } if (m_ParLine.EndPoint.Creator == this) { m_ParLine.EndPoint.ApplyPointGeometry(ctx, PointGeometry.Create(epos)); } // If the parallel is an arc, define the geometry if (m_ParLine is ArcFeature) { // Get the center of the reference line ArcFeature refArc = m_RefLine.GetArcBase(); PointFeature center = refArc.Circle.CenterPoint; // Obtain a circle for the parallel double radius = Geom.Distance(center, m_ParLine.StartPoint); Circle circle = MapModel.AddCircle(center, radius); // Define arc direction bool iscw = refArc.IsClockwise; if (IsArcReversed) { iscw = !iscw; } ArcGeometry geom = new ArcGeometry(circle, m_ParLine.StartPoint, m_ParLine.EndPoint, iscw); (m_ParLine as ArcFeature).Geometry = geom; } }
/// <summary> /// Creates any new spatial features (without any geometry) /// </summary> /// <param name="ff">The factory class for generating spatial features</param> internal override void ProcessFeatures(FeatureFactory ff) { m_NewPoint = ff.CreatePointFeature(DataField.NewPoint); if (ff.HasFeatureDescription(DataField.NewLine)) { PointFeature from = (m_IsExtendFromEnd ? m_ExtendLine.EndPoint : m_ExtendLine.StartPoint); ArcFeature arc = m_ExtendLine.GetArcBase(); if (arc == null) { m_NewLine = ff.CreateSegmentLineFeature(DataField.NewLine, from, m_NewPoint); } else { m_NewLine = ff.CreateArcFeature(DataField.NewLine, from, m_NewPoint); } m_NewLine.ObservedLength = m_Length; } }
/// <summary> /// Returns the intersection of the parallel with a line. A prior call to Calculate is required. /// </summary> /// <param name="line">The line to intersect with.</param> /// <param name="isEndParallel">Is the intersection biased towards the end of the parallel?</param> /// <returns>The intersection (if any). In cases where the line intersects the parallel /// more than once, you get an arbitrary intersection.</returns> internal IPosition GetIntersect(LineFeature line, bool isEndParallel) { // Make sure the intersection is undefined. IPosition result = null; // Return if the parallel points are undefined. if (m_Par1 == null || m_Par2 == null) { return(null); } // If the reference line is a circular arc, get the curve info. ArcFeature arc = m_Line.GetArcBase(); if (arc != null) { Circle circle = arc.Circle; double radius = circle.Radius; IPointGeometry centre = circle.Center; bool iscw = arc.IsClockwise; // Construct a circle that passes through // the parallel points (assumed to have the same distance // with respect to the centre of the circle). double parrad = Geom.Distance(centre, m_Par1); // Intersect the circle with the line to intersect with. IntersectionResult xres = new IntersectionResult(line); uint nx = xres.Intersect(centre, parrad); if (nx == 0) { return(null); } // If there is only one intersection, that's what we want. if (nx == 1) { return(xres.Intersections[0].P1); } // Get the intersection that is closest to the parallel point // that has the bias. if (isEndParallel) { xres.GetClosest(m_Par2, out result, 0.0); } else { xres.GetClosest(m_Par1, out result, 0.0); } } else { // Get the bearing from the start to the end of the parallel. double bearing = Geom.BearingInRadians(m_Par1, m_Par2); // Get the ground dimension of a line that crosses the // extent of the draw window. double dist = MaxDiagonal; // Project the parallel line to positions that are well // beyond the draw extent. IPosition start = Geom.Polar(m_Par1, bearing + Constants.PI, dist); IPosition end = Geom.Polar(m_Par2, bearing, dist); // Intersect the line segment with the line to intersect with. IntersectionResult xres = new IntersectionResult(line); IPointGeometry sg = PointGeometry.Create(start); IPointGeometry eg = PointGeometry.Create(end); uint nx = xres.Intersect(sg, eg); if (nx == 0) { return(null); } // If there is only one intersection, that's what we want. if (nx == 1) { return(xres.Intersections[0].P1); } // Get the intersection that is closest to the parallel point // that has the bias. if (isEndParallel) { xres.GetClosest(m_Par2, out result, 0.0); } else { xres.GetClosest(m_Par1, out result, 0.0); } } return(result); }
/// <summary> /// Calculates positions that are parallel to a line. /// </summary> /// <param name="line">The reference line.</param> /// <param name="offset">The offset to the parallel, in ground units. Signed to denote /// which side (less than zero means it's to the left of the reference line).</param> /// <param name="sres">The position of the start of the parallel.</param> /// <param name="eres">The position of the end of the parallel.</param> /// <returns>True if positions calculated ok</returns> static bool Calculate(LineFeature line, Distance offset, out IPosition sres, out IPosition eres) { // No result positions so far. sres = eres = null; // Get the ends of the reference line. IPosition spos = line.StartPoint; IPosition epos = line.EndPoint; ISpatialSystem sys = CadastralMapModel.Current.SpatialSystem; // If the reference line is a circular arc, get the curve info. ArcFeature arc = line.GetArcBase(); if (arc != null) { Circle circle = arc.Circle; double radius = circle.Radius; IPosition centre = circle.Center; bool iscw = arc.IsClockwise; // Get the midpoint of the curve. The reduction of the // ground distance will be along the line that goes // from the centre of the circle & through this position. ILength len = line.Length; ILength halfLen = new Length(len.Meters * 0.5); IPosition middle; line.LineGeometry.GetPosition(halfLen, out middle); // Get the bearing from the centre to the mid-position // and use that to reduce the offset to the mapping plane. double bearing = Geom.BearingInRadians(centre, middle); double offdist = offset.GetPlanarMetric(middle, bearing, sys); // No parallel if the offset exceeds the radius. // if ( offdist > radius ) return FALSE; // Calculate the parallel points. double sbear = Geom.BearingInRadians(centre, spos); sres = Geom.Polar(centre, sbear, offdist + radius); double ebear = Geom.BearingInRadians(centre, epos); eres = Geom.Polar(centre, ebear, offdist + radius); } else { // Get the bearing.of the line. double bearing = Geom.BearingInRadians(spos, epos); // Get the planar distance for a perpendicular line that passes // through the midpoint of the reference line. The planar distance // will have the same sign as the ground value. IPosition middle = Position.CreateMidpoint(spos, epos); bearing += Constants.PIDIV2; double offdist = offset.GetPlanarMetric(middle, bearing, sys); // Calculate the parallel points. sres = Geom.Polar(spos, bearing, offdist); eres = Geom.Polar(epos, bearing, offdist); } return(true); }
/// <summary> /// Draws the current state of the edit /// </summary> internal void Draw() { Debug.Assert(m_Line != null); ISpatialDisplay view = ActiveDisplay; // Figure out the positions for the ends of the parallel line (if any) ... // Assume we already know both terminals. IPosition start = m_Term1; IPosition end = m_Term2; // If either one is undefined, but a dialog for it is active, // try to get the terminal from there instead. if (m_TermDial1 != null && start == null) { start = m_TermDial1.TerminalPosition; } if (m_TermDial2 != null && end == null) { end = m_TermDial2.TerminalPosition; } // If they weren't actually defined, use the parallel points instead. if (start == null) { start = m_Par1; } if (end == null) { end = m_Par2; } // If those weren't defined either, try to calculate them now. if (end == null && Calculate()) { start = m_Par1; end = m_Par2; } // Any offset point if (m_OffsetPoint != null) { m_OffsetPoint.Draw(view, Color.Green); } // Everything else should draw in usual command-style colour. IDrawStyle style = EditingController.Current.Style(Color.Magenta); IDrawStyle dottedStyle = new DottedStyle(); // If the reference line is a curve, get the curve info. ArcFeature arc = m_Line.GetArcBase(); if (arc != null) { bool iscw = arc.IsClockwise; // Reverse the direction if necessary. if (m_IsReversed) { iscw = !iscw; } // Draw the parallel line (the rest of the circle being dotted). if (start != null) { CircularArcGeometry parArc = new CircularArcGeometry(arc.Circle, start, end, iscw); style.Render(view, parArc); parArc.IsClockwise = !parArc.IsClockwise; dottedStyle.Render(view, parArc); } } else { // PARALLEL IS STRAIGHT // If we've got something, figure out positions for dotted portion. if (start != null) { // What's the max length of a diagonal crossing the entire screen? double maxdiag = this.MaxDiagonal; // What's the bearing from the start to the end of the parallel? double bearing = Geom.BearingInRadians(start, end); // Project to a point before the start end of the parallel, as // well as a point after the end. IPosition before = Geom.Polar(start, bearing + Constants.PI, maxdiag); IPosition after = Geom.Polar(end, bearing, maxdiag); LineSegmentGeometry.Render(before, start, view, dottedStyle); LineSegmentGeometry.Render(start, end, view, style); LineSegmentGeometry.Render(end, after, view, dottedStyle); } } // Draw terminal positions (if defined). if (m_Term1 != null) { style.Render(view, m_Term1); } if (m_Term2 != null) { style.Render(view, m_Term2); } // The terminal lines. if (m_TermLine1 != null) { m_TermLine1.Render(view, style); } if (m_TermLine2 != null) { m_TermLine2.Render(view, style); } // Do the active dialog last so their stuff draws on top. if (m_ParDial != null) { m_ParDial.Draw(); } if (m_TermDial1 != null) { m_TermDial1.Draw(); } if (m_TermDial2 != null) { m_TermDial2.Draw(); } }
/// <summary> /// Returns the intersection of the parallel with a line. /// </summary> /// <param name="refline">The reference line.</param> /// <param name="parpos">Search position that coincides with the parallel.</param> /// <param name="line">The line to intersect with.</param> /// <returns>The intersection (if any). In cases where the line intersects the /// parallel more than once, you get the intersection that is closest to the /// search position.</returns> internal static IPosition GetIntersect(LineFeature refline, IPosition parpos, LineFeature line) { // Make sure the intersection is undefined. IPosition result = null; // Return if the parallel point is undefined. if (parpos == null) { return(null); } // If the reference line is a circular arc (or a section based on an arc), get the curve info. ArcFeature arc = refline.GetArcBase(); if (arc != null) { Circle circle = arc.Circle; double radius = circle.Radius; IPointGeometry centre = circle.Center; bool iscw = arc.IsClockwise; // Construct a circle that passes through the search position double parrad = Geom.Distance(centre, parpos); // Intersect the circle with the line to intersect with. IntersectionResult xres = new IntersectionResult(line); uint nx = xres.Intersect(centre, parrad); if (nx == 0) { return(null); } // If there is only one intersection, that's what we want. if (nx == 1) { return(xres.Intersections[0].P1); } // Get the intersection that is closest to the search position. xres.GetClosest(parpos, out result, 0.0); } else { // Get the bearing from the start to the end of the reference line. IPosition spos = refline.StartPoint; IPosition epos = refline.EndPoint; double bearing = Geom.BearingInRadians(spos, epos); // Project the parallel line to positions that are a long way away (but make sure we // don't end up with negative numbers). Window searchWindow = new Window(line.Extent); searchWindow.Union(refline.Extent); searchWindow.Union(parpos); double dist = Geom.Distance(searchWindow.Min, searchWindow.Max); IPosition start = Geom.Polar(parpos, bearing + Constants.PI, dist); IPosition end = Geom.Polar(parpos, bearing, dist); // Intersect the line segment with the line to intersect with. IntersectionResult xres = new IntersectionResult(line); IPointGeometry sg = new PointGeometry(start); IPointGeometry eg = new PointGeometry(end); uint nx = xres.Intersect(sg, eg); if (nx == 0) { return(null); } // If there is only one intersection, that's what we want. if (nx == 1) { return(xres.Intersections[0].P1); } // Get the intersection that is closest to the search position xres.GetClosest(parpos, out result, 0.0); } return(result); }
/// <summary> /// Calculates the start and end positions of an extension to a circular arc. /// </summary> /// <param name="extendLine">The line being extended.</param> /// <param name="isFromEnd">True if extending from the end of the line.</param> /// <param name="dist">The length of the extension.</param> /// <param name="start">The position of the start of the extension.</param> /// <param name="end">The position of the end of the extension.</param> /// <param name="center">The center of the circle on which the arc lies.</param> /// <param name="iscw">Is the circular arc directed clockwise?</param> /// <returns>True if position have been worked out. False if there is insufficient data, /// or the extension is not on a circular arc, or the length is more than the circumference /// of the circle (in those cases, the start and end positions come back as nulls)</returns> internal static bool Calculate(LineFeature extendLine, bool isFromEnd, Distance dist, out IPosition start, out IPosition end, out IPosition center, out bool iscw) { start = end = null; center = null; iscw = true; // Can't calculate if there is insufficient data. if (extendLine == null || dist == null) { return(false); } // The length must be defined. if (!dist.IsDefined) { return(false); } // The line that's being extended must be a circular arc. ArcFeature arc = (extendLine as ArcFeature); if (arc == null) { return(false); } center = arc.Circle.Center; double radius = arc.Circle.Radius; iscw = arc.IsClockwise; // Get the length of the arc extension, in meters on the ground. double arclen = dist.Meters; // If the arc length exceeds the length of the circumference, // the end point can't be calculated. double circumf = Constants.PIMUL2 * radius; if (arclen > circumf) { return(false); } // If we're extending from the start of the arc, the curve direction has // to be reversed too. if (!isFromEnd) { iscw = !iscw; } // Get the point we're extending from. start = (isFromEnd ? extendLine.EndPoint : extendLine.StartPoint); // Get the point we're extending to ... // Get the bearing from the center of the circle to the start of the arc. Turn turn = new Turn(center, start); double sbearing = turn.BearingInRadians; // Get the sector angle (in radians). double sector = arclen / radius; double ebearing = sbearing; if (iscw) { ebearing += sector; } else { ebearing -= sector; } end = Geom.Polar(center, ebearing, radius); // Re-calculate the arc length on the mapping plane, arclen = dist.GetPlanarMetric(start, end, extendLine.SpatialSystem); // And adjust the end position accordingly. sector = arclen / radius; if (iscw) { ebearing = sbearing + sector; } else { ebearing = sbearing - sector; } end = Geom.Polar(center, ebearing, radius); return(true); }