/// <summary> /// Checks whether any intersections occur at positions that do not coincide /// with the end points of a line. /// </summary> /// <param name="line">The line to check. This should be the same line that /// was supplied to the <c>IntersectionFinder</c> constructor that created THIS results /// object (doing otherwise doesn't make any sense).</param> /// <returns>TRUE if any intersection does not coincide with the end points /// of the specified line.</returns> internal bool IsSplitOn(ILineGeometry line) { // Get the locations of the line end points. IPointGeometry start = line.Start; IPointGeometry end = line.End; // Go through each intersection, looking for one that does // not correspond to the line ends. foreach (IntersectionData d in m_Data) { IPointGeometry loc1 = new PointGeometry(d.P1); if (!start.IsCoincident(loc1) && !end.IsCoincident(loc1)) { return(true); } if (d.IsGraze) { /* * Huh? This was the original, but it always ended up returning true. * * IPointGeometry loc2 = PointGeometry.New(d.P2); * if (!start.IsCoincident(loc2) && !end.IsCoincident(loc2)) * return true; * * return true; */ return(true); } } return(false); }
/// <summary> /// Initializes a new instance of the <see cref="TextFeature"/> class, and records it /// as part of the map model. /// </summary> /// <param name="f">Basic information about the feature (not null).</param> /// <param name="geom">The metrics for the text (including the text itself).</param> /// <param name="isTopological">Is the new feature expected to act as a polygon label?</param> /// <param name="polPosition">The position of the polygon reference position (specify null /// if the feature is not a polygon label)</param> /// <exception cref="ArgumentNullException">If <paramref name="f"/> is null.</exception> protected TextFeature(IFeature f, TextGeometry geom, bool isTopological, PointGeometry polPosition) : base(f) { m_Geom = geom; SetTopology(isTopological); m_PolygonPosition = polPosition; }
/// <summary> /// Initializes a new instance of the <see cref="MultiSegmentGeometry"/> class /// using the data read from persistent storage. /// </summary> /// <param name="editDeserializer">The mechanism for reading back content.</param> internal MultiSegmentGeometry(EditDeserializer editDeserializer) : base(editDeserializer) { // LineString assumes 2D, with X preceding Y. Each coordinate pair is separated // with a comma, with a space between each X and Y (e.g. "123 345,124 349,129 341") string s = editDeserializer.ReadString(DataField.LineString); string[] xys = s.Split(','); m_Data = new IPointGeometry[xys.Length]; for (int i = 0; i < xys.Length; i++) { string xy = xys[i].Trim(); int blankPos = xy.IndexOf(' '); if (blankPos <= 0) { throw new FormatException(); } double x = Double.Parse(xy.Substring(0, blankPos)); double y = Double.Parse(xy.Substring(blankPos + 1)); m_Data[i] = new PointGeometry(x, y); } m_Extent = LineStringGeometry.GetExtent(this); }
internal RowTextContent(int tableId, ITemplate template, PointGeometry pos, IFont font, double height, double width, float rotation) : base(pos, font, height, width, rotation) { m_TableId = tableId; m_TemplateId = 0; }
/// <summary> /// Initializes a new instance of the <see cref="PointFeature"/> class (with geometry that /// isn't shared with any other point), and records it as part of the map model. /// </summary> /// <param name="f">Basic information about the feature.</param> /// <param name="g">The geometry for the point (may be null)</param> internal PointFeature(IFeature f, PointGeometry g) : base(f) { if (g == null) m_Geom = null; else m_Geom = new Node(this, g); }
/// <summary> /// Creates a new <c>PointFeature</c> with geometry that isn't shared /// with any other point. /// </summary> /// <param name="creator">The operation that created the feature (not null)</param> /// <param name="id">The internal ID of this feature within the project that created it.</param> /// <param name="e">The entity type for the feature (not null)</param> /// <param name="g">The geometry for the point (may be null)</param> internal PointFeature(Operation creator, InternalIdValue id, IEntity e, PointGeometry g) : base(creator, id, e, null) { if (g == null) m_Geom = null; else m_Geom = new Node(this, g); }
/// <summary> /// Creates a new <c>TextGeometry</c> /// </summary> /// <param name="pos">Position of the text's reference point (always the top left corner of the string).</param> /// <param name="font">The text style (defines the type-face and the height of the text).</param> /// <param name="height">The height of the text, in meters on the ground.</param> /// <param name="width">The total width of the text, in meters on the ground.</param> /// <param name="rotation">Clockwise rotation from horizontal</param> protected TextGeometry(PointGeometry pos, IFont font, double height, double width, float rotation) { m_Font = font; m_Position = pos; m_Height = (float)height; m_Width = (float)width; m_Rotation = new RadianValue((double)rotation); }
/// <summary> /// Copy constructor (for use by the <see cref="RowTextContent"/> class) /// </summary> /// <param name="copy">The geometry to copy</param> protected TextGeometry(TextGeometry copy) { m_Font = copy.m_Font; m_Position = copy.m_Position; m_Height = copy.m_Height; m_Width = copy.m_Width; m_Rotation = copy.m_Rotation; }
/// <summary> /// Initializes a new instance of the <see cref="Annotation"/> class with the /// <see cref="FontStyle"/> property set to <see cref="System.Drawing.FontStyle.Regular"/>. /// </summary> /// <param name="text">The annotation text.</param> /// <param name="position">The position for the text (center-baseline aligned).</param> /// <param name="height">The height of the text (in meters on the ground).</param> /// <param name="rotation">The rotation (in radians clockwise from horizontal).</param> internal Annotation(string text, IPosition position, double height, double rotation) { m_Text = text; m_Position = PointGeometry.Create(position); m_Height = height; m_Rotation = new RadianValue(rotation); m_FontStyle = FontStyle.Regular; }
/// <summary> /// Cuts back a horizontal line segment to the closest intersection with this line. /// Used in point in polygon. /// </summary> /// <param name="s">Start of horizontal segment.</param> /// <param name="e">End of segment (will be modified if segment intersects this line)</param> /// <param name="status">Return code indicating whether an error has arisen (returned /// as 0 if no error).</param> /// <returns>True if the horizontal line was cut back.</returns> internal override bool GetCloser(IPointGeometry s, ref PointGeometry e, out uint status) { status = 0; // Remember the initial end of segment PointGeometry initEnd = new PointGeometry(e); // Represent the horizontal segment in a class of its own HorizontalRay hseg = new HorizontalRay(s, e.X - s.X); if (!hseg.IsValid) { status = 1; return(false); } IPointGeometry[] data = this.Data; // Get relative position code for the start of the line. If it's // somewhere on the horizontal segment, cut the line back. byte scode = Geom.GetPositionCode(data[0], s, e); if (scode == 0) { e = new PointGeometry(Start); } // Loop through each line segment, testing the end of each segment // against the horizontal segment. byte ecode; for (int i = 1; i < data.Length; scode = ecode, i++) { // Get the position code for the end of the line segment ecode = Geom.GetPositionCode(data[i], s, e); // If it's coincident with the horizontal segment, cut the // line back. Otherwise see whether there is any potential // intersection to cut back to. if (ecode == 0) { e = new PointGeometry(data[i]); } else if ((scode & ecode) == 0) { IPosition x = null; if (hseg.Intersect(data[i - 1], data[i], ref x)) { e = new PointGeometry(x); } } } // Return flag to indicate whether we got closer or not. return(!e.IsCoincident(initEnd)); }
internal HorizontalRay(IPosition start, double distance) { if (distance < 0.0) { throw new ArgumentOutOfRangeException(); } m_Start = PointGeometry.Create(start); m_EndX = start.X + distance; }
private PointGeometry[] GetPositions(Ntx.Line line) { PointGeometry[] pts = new PointGeometry[line.NumPosition]; for (int i = 0; i < line.NumPosition; i++) { Ntx.Position xp = line.Position(i); pts[i] = new PointGeometry(xp.Easting, xp.Northing); } return(pts); }
/// <summary> /// Initializes a new instance of the <see cref="PointFeature"/> class (with geometry that /// isn't shared with any other point), and records it as part of the map model. /// </summary> /// <param name="f">Basic information about the feature.</param> /// <param name="g">The geometry for the point (may be null)</param> internal PointFeature(IFeature f, PointGeometry g) : base(f) { if (g == null) { m_Geom = null; } else { m_Geom = new Node(this, g); } }
/// <summary> /// Initializes a new instance of the <see cref="Node"/> class that refers to /// a specific point, with the specified location. /// </summary> /// <param name="p">The point that will be assigned this geometry (not null). /// Modified by referring its geometry to <c>this</c> node.</param> /// <param name="g">The geometry for the point (not null)</param> internal Node(PointFeature p, PointGeometry g) : base(g) { if (p==null) throw new ArgumentNullException(); m_Points = new List<PointFeature>(1); m_Points.Add(p); // Ensure the point is associated with this node p.SetNode(this); }
/// <summary> /// Initializes a new instance of the <see cref="Node"/> class that refers to /// the supplied array of points, all associated with the specified location. /// </summary> /// <param name="pts">The points that will be assigned this geometry (not null). /// Each point will be modified by referring its geometry to <c>this</c> node.</param> /// <param name="g">The geometry for the point (not null)</param> internal Node(PointFeature[] pts, PointGeometry g) : base(g) { if (pts==null) throw new ArgumentNullException(); m_Points = new List<PointFeature>(pts); // Ensure every point is associated with this node foreach (PointFeature p in pts) p.SetNode(this); }
/// <summary> /// Creates a new <c>PointFeature</c> with geometry that isn't shared /// with any other point. /// </summary> /// <param name="creator">The operation that created the feature (not null)</param> /// <param name="id">The internal ID of this feature within the project that created it.</param> /// <param name="e">The entity type for the feature (not null)</param> /// <param name="g">The geometry for the point (may be null)</param> internal PointFeature(Operation creator, InternalIdValue id, IEntity e, PointGeometry g) : base(creator, id, e, null) { if (g == null) { m_Geom = null; } else { m_Geom = new Node(this, g); } }
private PointGeometry[] CheckMultiSegmentEnds(PointGeometry[] pts) { if (pts.Length <= 2) { return(pts); } //double tol = (Constants.XYRES * Constants.XYRES); double tol = (0.001 * 0.001); PointGeometry[] res = pts; bool doCheck = true; while (doCheck && res.Length > 2) { doCheck = false; // If the start position coincides with the second segment, strip out // the second position. if (BasicGeom.DistanceSquared(res[0].X, res[0].Y, res[1].X, res[1].Y, res[2].X, res[2].Y) < tol) { PointGeometry[] tmp = new PointGeometry[res.Length - 1]; tmp[0] = res[0]; Array.Copy(res, 2, tmp, 1, res.Length - 2); res = tmp; doCheck = true; } } // If the end position coincides with the second last segment, strip out // the second last position. doCheck = true; while (doCheck && res.Length > 2) { doCheck = false; int last = res.Length - 1; if (BasicGeom.DistanceSquared(res[last].X, res[last].Y, res[last - 1].X, res[last - 1].Y, res[last - 2].X, res[last - 2].Y) < tol) { PointGeometry[] tmp = new PointGeometry[res.Length - 1]; Array.Copy(res, 0, tmp, 0, res.Length - 2); tmp[tmp.Length - 1] = res[last]; res = tmp; doCheck = true; } } return(res); }
/// <summary> /// Defines the position of this point as a new un-shared position. /// </summary> /// <param name="ctx">The context in which the assignment is being made. May be null, but do /// so with care - an editing context is vital when dealing with the propagation of updates. /// </param> /// <param name="value">The position to assign (not null).</param> internal void ApplyPointGeometry(EditingContext ctx, PointGeometry value) { if (value == null) { throw new ArgumentNullException(); } if (ctx != null) { ctx.RegisterChange(this); } m_Geom = new Node(this, value); }
/// <summary> /// Initializes a new instance of the <see cref="Node"/> class that refers to /// a specific point, with the specified location. /// </summary> /// <param name="p">The point that will be assigned this geometry (not null). /// Modified by referring its geometry to <c>this</c> node.</param> /// <param name="g">The geometry for the point (not null)</param> internal Node(PointFeature p, PointGeometry g) : base(g) { if (p == null) { throw new ArgumentNullException(); } m_Points = new List <PointFeature>(1); m_Points.Add(p); // Ensure the point is associated with this node p.SetNode(this); }
private PointFeature EnsurePointExists(PointGeometry p, ILength tol, Operation creator) { PointFeature result = (PointFeature)m_Index.QueryClosest(p, tol, SpatialType.Point); if (result == null) { IEntity e = creator.MapModel.DefaultPointType; InternalIdValue id = CadastralMapModel.Current.WorkingSession.AllocateNextId(); result = new PointFeature(creator, id, e, p); m_Index.Add(result); m_Result.Add(result); } return(result); }
/// <summary> /// Initializes a new instance of the <see cref="RowTextGeometry"/> class. /// </summary> /// <param name="row">The row that contains the information to format</param> /// <param name="template">How to form the text string out of the data in the row</param> /// <param name="pos">Position of the text's reference point (always the top left corner of the string).</param> /// <param name="font">The text style (defines the type-face and the height of the text).</param> /// <param name="height">The height of the text, in meters on the ground.</param> /// <param name="width">The total width of the text, in meters on the ground.</param> /// <param name="rotation">Clockwise rotation from horizontal</param> internal RowTextGeometry(Row row, ITemplate template, PointGeometry pos, IFont font, double height, double width, float rotation) : base(pos, font, height, width, rotation) { // The row may be null during deserialization (attributes only get loaded after // all spatial featues have been deserialized). if (template == null) { throw new ArgumentNullException(); } m_Row = row; m_Template = template; }
/// <summary> /// Remembers a new polygon reference position for this label. /// </summary> /// <param name="p">The reference position. Specify null if the default reference /// position should be used (the position associated with the text geometry).</param> internal void SetPolPosition(IPointGeometry p) { if (p == null) { m_PolygonPosition = null; } else { m_PolygonPosition = PointGeometry.Create(p); } // If the label was previously "built", re-calculate the relationship to any // enclosing polygon RecalculateEnclosingPolygon(); }
/// <summary> /// Constructor for a grazing intersection. If the supplied positions are /// actually closer than the coordinate resolution (1 micron), a simple /// intersection will be defined. /// </summary> /// <param name="x1">X-value of 1st intersection.</param> /// <param name="y1">Y-value of 1st intersection.</param> /// <param name="x2">X-value of 2nd intersection.</param> /// <param name="y2">Y-value of 2nd intersection.</param> internal IntersectionData(double x1, double y1, double x2, double y2) { IPointGeometry p1 = new PointGeometry(x1, y1); IPointGeometry p2 = new PointGeometry(x2, y2); m_X1 = p1; if (!p1.IsCoincident(p2)) { m_X2 = p2; } m_SortValue = 0.0; m_Context1 = 0; m_Context2 = 0; }
/// <summary> /// Cuts back a horizontal line segment to the closest intersection with this line. /// Used in point in polygon. /// </summary> /// <param name="s">Start of horizontal segment.</param> /// <param name="e">End of segment (will be modified if segment intersects this line)</param> /// <param name="status">Return code indicating whether an error has arisen (returned /// as 0 if no error).</param> /// <returns>True if the horizontal line was cut back.</returns> internal override bool GetCloser(IPointGeometry s, ref PointGeometry e, out uint status) { status = 0; // Remember the initial end of segment PointGeometry initEnd = new PointGeometry(e); // Represent the horizontal segment in a class of its own HorizontalRay hseg = new HorizontalRay(s, e.X - s.X); if (!hseg.IsValid) { status = 1; return(false); } // Get relative position code for the start of the line. If it's // somewhere on the horizontal segment, cut the line back. byte scode = Geom.GetPositionCode(Start, s, e); if (scode == 0) { e = new PointGeometry(Start); } // Get the position code for the end of the line segment byte ecode = Geom.GetPositionCode(End, s, e); // If it's coincident with the horizontal segment, cut the // line back. Otherwise see whether there is any potential // intersection to cut back to. if (ecode == 0) { e = new PointGeometry(End); } else if ((scode & ecode) == 0) { IPosition x = null; if (hseg.Intersect(Start, End, ref x)) { e = new PointGeometry(x); } } // Return flag to indicate whether we got closer or not. return(!e.IsCoincident(initEnd)); }
/// <summary> /// Initializes a new instance of the <see cref="Node"/> class that refers to /// the supplied array of points, all associated with the specified location. /// </summary> /// <param name="pts">The points that will be assigned this geometry (not null). /// Each point will be modified by referring its geometry to <c>this</c> node.</param> /// <param name="g">The geometry for the point (not null)</param> internal Node(PointFeature[] pts, PointGeometry g) : base(g) { if (pts == null) { throw new ArgumentNullException(); } m_Points = new List <PointFeature>(pts); // Ensure every point is associated with this node foreach (PointFeature p in pts) { p.SetNode(this); } }
/// <summary> /// Creates a new <c>FindIslandContainerQuery</c> (and executes it). The result of the query /// can then be obtained through the <c>Result</c> property. /// </summary> /// <param name="index">The spatial index to search</param> /// <param name="island">The island you want the container for</param> internal FindIslandContainerQuery(ISpatialIndex index, Island island) { m_Island = island; m_Result = null; // Get the most easterly point in the island. IPosition ep = m_Island.GetEastPoint(); // Shift the east point ONE MICRON further to the east, to ensure // we don't pick up the interior of the island! PointGeometry eg = PointGeometry.Create(ep); m_EastPoint = new PointGeometry(eg.Easting.Microns + 1, eg.Northing.Microns); IWindow w = new Window(m_EastPoint, m_EastPoint); index.QueryWindow(w, SpatialType.Polygon, OnQueryHit); }
/// <summary> /// Reads data that was previously written using <see cref="WriteData"/> /// </summary> /// <param name="editDeserializer">The mechanism for reading back content.</param> /// <param name="font">The text style</param> /// <param name="position">Position of the text's reference point</param> /// <param name="height">The height of the text, in meters on the ground.</param> /// <param name="width">The total width of the text, in meters on the ground.</param> /// <param name="rotation">Clockwise rotation from horizontal</param> static void ReadData(EditDeserializer editDeserializer, out IFont font, out PointGeometry position, out float height, out float width, out IAngle rotation) { if (editDeserializer.IsNextField(DataField.Font)) { int fontId = editDeserializer.ReadInt32(DataField.Font); font = EnvironmentContainer.FindFontById(fontId); } else { font = null; } position = editDeserializer.ReadPointGeometry(DataField.X, DataField.Y); width = (float)editDeserializer.ReadDouble(DataField.Width); height = (float)editDeserializer.ReadDouble(DataField.Height); rotation = editDeserializer.ReadRadians(DataField.Rotation); }
/// <summary> /// Moves this text to a new position /// </summary> /// <param name="to">The new position for the text</param> /// <returns>True if the text was moved. False if the specified position is /// coincident with the current position.</returns> internal bool Move(PointGeometry to) { // Just return if the new location is at the same position // as the old location. if (m_Geom.Position.IsCoincident(to)) { return(false); } // Remove this feature from spatial index, move the text (and null the // polygon reference position), add back into the spatial index RemoveIndex(); m_Geom.Position = to; m_PolygonPosition = null; AddToIndex(); return(true); }
/// <summary> /// Define the relationship that this intersection has to a pair of lines. /// </summary> /// <param name="line1">The 1st line.</param> /// <param name="line2">The 2nd line.</param> internal void SetContext(ILineGeometry line1, ILineGeometry line2) { m_Context1 = 0; m_Context2 = 0; if (this.IsGraze) { IPointGeometry loc1 = new PointGeometry(m_X1); IPointGeometry loc2 = new PointGeometry(m_X2); m_Context1 = GetContext(loc1, loc2, line1); m_Context2 = GetContext(loc1, loc2, line2); } else { IPointGeometry loc = new PointGeometry(m_X1); m_Context1 = GetContext(loc, line1); m_Context2 = GetContext(loc, line2); } }
/// <summary> /// Checks whether the supplied positions define a zero-length line /// </summary> /// <param name="pts">The positions for a line</param> /// <returns>True if the supplied array contains fewer than 2 points, or all the points /// are exactly coincident.</returns> private bool HasZeroLength(PointGeometry[] pts) { if (pts.Length < 2) { return(true); } PointGeometry start = pts[0]; for (int i = 1; i < pts.Length; i++) { if (!pts[i].IsCoincident(start)) { return(false); } } return(true); }
PointFeature GetArcEndPoint(PointGeometry g, ILength tol, Operation creator) { // Ensure we've got a point at the required position PointFeature pt = EnsurePointExists(g, tol, creator); // If it's not exactly coincident, we've picked up a previously loaded point // that happens to be within tolerance. If it's not already connected to any // lines, shift it to where we want it. if (!pt.IsCoincident(g)) { if (!pt.HasDependents) { m_Index.Remove(pt); PointFeature[] pts = pt.Node.Points; pt.SetNode(new Node(pts, g)); m_Index.Add(pt); } } return(pt); }
/// <summary> /// Reads data that was previously written using <see cref="WriteData"/> /// </summary> /// <param name="editDeserializer">The mechanism for reading back content.</param> /// <param name="isTopological">Are we dealing with a polygon label</param> /// <param name="polPos">The label reference point (usually applies onlt to polygon labels). Null if it's /// identical to the position recorded via the geometry object.</param> /// <param name="geom">The geometry for the text.</param> static void ReadData(EditDeserializer editDeserializer, out bool isTopological, out PointGeometry polPos, out TextGeometry geom) { isTopological = editDeserializer.ReadBool(DataField.Topological); if (editDeserializer.IsNextField(DataField.PolygonX)) polPos = editDeserializer.ReadPointGeometry(DataField.PolygonX, DataField.PolygonY); else polPos = null; geom = editDeserializer.ReadPersistent<TextGeometry>(DataField.Type); }
/// <summary> /// Creates a new <c>Intersection</c> at the specified position. /// </summary> /// <param name="p">The position of the intersection</param> internal Intersection(PointGeometry p) : base(p) { m_Lines = new List<LineFeature>(2); m_Flag = 0; }
private PointGeometry[] CheckMultiSegmentEnds(PointGeometry[] pts) { if (pts.Length<=2) return pts; //double tol = (Constants.XYRES * Constants.XYRES); double tol = (0.001 * 0.001); PointGeometry[] res = pts; bool doCheck = true; while (doCheck && res.Length>2) { doCheck = false; // If the start position coincides with the second segment, strip out // the second position. if (BasicGeom.DistanceSquared(res[0].X, res[0].Y, res[1].X, res[1].Y, res[2].X, res[2].Y) < tol) { PointGeometry[] tmp = new PointGeometry[res.Length-1]; tmp[0] = res[0]; Array.Copy(res, 2, tmp, 1, res.Length-2); res = tmp; doCheck = true; } } // If the end position coincides with the second last segment, strip out // the second last position. doCheck = true; while (doCheck && res.Length>2) { doCheck = false; int last = res.Length-1; if (BasicGeom.DistanceSquared(res[last].X, res[last].Y, res[last-1].X, res[last-1].Y, res[last-2].X, res[last-2].Y) < tol) { PointGeometry[] tmp = new PointGeometry[res.Length-1]; Array.Copy(res, 0, tmp, 0, res.Length-2); tmp[tmp.Length-1] = res[last]; res = tmp; doCheck = true; } } return res; }
/// <summary> /// Cuts back a horizontal line segment to the closest intersection with this line. /// Used in point in polygon. /// </summary> /// <param name="s">Start of horizontal segment.</param> /// <param name="e">End of segment (will be modified if segment intersects this line)</param> /// <param name="status">Return code indicating whether an error has arisen (returned /// as 0 if no error).</param> /// <returns>True if the horizontal line was cut back.</returns> internal abstract bool GetCloser(IPointGeometry s, ref PointGeometry e, out uint status);
/// <summary> /// Checks whether any intersections occur at positions that do not coincide /// with the end points of a line. /// </summary> /// <param name="line">The line to check. This should be the same line that /// was supplied to the <c>IntersectionFinder</c> constructor that created THIS results /// object (doing otherwise doesn't make any sense).</param> /// <returns>TRUE if any intersection does not coincide with the end points /// of the specified line.</returns> internal bool IsSplitOn(ILineGeometry line) { // Get the locations of the line end points. IPointGeometry start = line.Start; IPointGeometry end = line.End; // Go through each intersection, looking for one that does // not correspond to the line ends. foreach (IntersectionData d in m_Data) { IPointGeometry loc1 = new PointGeometry(d.P1); if (!start.IsCoincident(loc1) && !end.IsCoincident(loc1)) return true; if (d.IsGraze) { /* * Huh? This was the original, but it always ended up returning true. * IPointGeometry loc2 = PointGeometry.New(d.P2); if (!start.IsCoincident(loc2) && !end.IsCoincident(loc2)) return true; return true; */ return true; } } return false; }
/// <summary> /// Moves this text to a new position /// </summary> /// <param name="to">The new position for the text</param> /// <returns>True if the text was moved. False if the specified position is /// coincident with the current position.</returns> internal bool Move(PointGeometry to) { // Just return if the new location is at the same position // as the old location. if (m_Geom.Position.IsCoincident(to)) return false; // Remove this feature from spatial index, move the text (and null the // polygon reference position), add back into the spatial index RemoveIndex(); m_Geom.Position = to; m_PolygonPosition = null; AddToIndex(); return true; }
private ArcFeature ImportArc(Ntx.Line line, Operation creator, ILength tol) { Debug.Assert(line.IsCurve); IEntity what = GetEntityType(line, SpatialType.Line); // Get positions defining the arc PointGeometry[] pts = GetPositions(line); // Ignore zero-length lines if (HasZeroLength(pts)) return null; // Add a point at the center of the circle Ntx.Position pos = line.Center; PointGeometry pc = new PointGeometry(pos.Easting, pos.Northing); PointFeature center = EnsurePointExists(pc, tol, creator); // Calculate exact positions for the arc endpoints double radius = line.Radius; ICircleGeometry cg = new CircleGeometry(pc, radius); IPosition bc = CircleGeometry.GetClosestPosition(cg, pts[0]); IPosition ec = CircleGeometry.GetClosestPosition(cg, pts[pts.Length-1]); // Round off to nearest micron PointGeometry bcg = PointGeometry.Create(bc); PointGeometry ecg = PointGeometry.Create(ec); // Ensure point features exist at both ends of the line. PointFeature ps = GetArcEndPoint(bcg, tol, creator); PointFeature pe = GetArcEndPoint(ecg, tol, creator); // Try to find a circle that's already been added by this import. Circle c = EnsureCircleExists(center, radius, tol, creator); // Determine which way the arc is directed bool iscw = LineStringGeometry.IsClockwise(pts, center); InternalIdValue id = CadastralMapModel.Current.WorkingSession.AllocateNextId(); ArcFeature arc = new ArcFeature(creator, id, what, c, ps, pe, iscw); // The toological status of the incoming arc may override the status that the // constructor derived from the entity type arc.SetTopology(line.IsTopologicalArc); #if DEBUG // Confirm the NTX data was valid (ensure it's consistent with what we've imported)... double readRad = c.Radius; double calcRad = BasicGeom.Distance(c.Center, ps); Debug.Assert(Math.Abs(readRad-calcRad) < tol.Meters); foreach (IPointGeometry pg in pts) { ILength check = arc.Geometry.Distance(pg); Debug.Assert(check.Meters < tol.Meters); } #endif return arc; }
/// <summary> /// Cuts back a horizontal line segment to the closest intersection with this line. /// Used in point in polygon. /// </summary> /// <param name="s">Start of horizontal segment.</param> /// <param name="e">End of segment (will be modified if segment intersects this line)</param> /// <param name="status">Return code indicating whether an error has arisen (returned /// as 0 if no error).</param> /// <returns>True if the horizontal line was cut back.</returns> internal override bool GetCloser(IPointGeometry s, ref PointGeometry e, out uint status) { status = 0; // Remember the initial end of segment PointGeometry initEnd = new PointGeometry(e); // Represent the horizontal segment in a class of its own HorizontalRay hseg = new HorizontalRay(s, e.X-s.X); if (!hseg.IsValid) { status = 1; return false; } // Get relative position code for the start of the line. If it's // somewhere on the horizontal segment, cut the line back. byte scode = Geom.GetPositionCode(Start, s, e); if (scode==0) e = new PointGeometry(Start); // Get the position code for the end of the line segment byte ecode = Geom.GetPositionCode(End, s, e); // If it's coincident with the horizontal segment, cut the // line back. Otherwise see whether there is any potential // intersection to cut back to. if (ecode==0) e = new PointGeometry(End); else if ((scode & ecode)==0) { IPosition x = null; if (hseg.Intersect(Start, End, ref x)) e = new PointGeometry(x); } // Return flag to indicate whether we got closer or not. return (!e.IsCoincident(initEnd)); }
/// <summary> /// Cuts back a horizontal line segment to the closest intersection with this line. /// Used in point in polygon. /// </summary> /// <param name="s">Start of horizontal segment.</param> /// <param name="e">End of segment (will be modified if segment intersects this line)</param> /// <param name="status">Return code indicating whether an error has arisen (returned /// as 0 if no error).</param> /// <returns>True if the horizontal line was cut back.</returns> internal override bool GetCloser(IPointGeometry s, ref PointGeometry e, out uint status) { return Make().GetCloser(s, ref e, out status); }
/// <summary> /// Creates a <c>LineFeature</c> consisting of a series of connected line segments. /// </summary> /// <param name="creator">The operation that created the feature (not null)</param> /// <param name="id">The internal ID of this feature within the project that created it.</param> /// <param name="e">The entity type for the feature.</param> /// <param name="start">The point at the start of the line</param> /// <param name="end">The point at the end of the line</param> /// <param name="data">The positions defining the shape of the line. The first position must /// coincide precisely with the supplied <paramref name="start"/>, and the last position /// must coincide precisely with <paramref name="end"/>. Expected to be more than two positions.</param> internal LineFeature(Operation creator, InternalIdValue id, IEntity e, PointFeature start, PointFeature end, PointGeometry[] data) : this(creator, id, e, start, end, new MultiSegmentGeometry(start, end, data)) { Debug.Assert(data.Length>2); Debug.Assert(start.Geometry.IsCoincident(data[0])); Debug.Assert(end.Geometry.IsCoincident(data[data.Length-1])); }
PointFeature GetArcEndPoint(PointGeometry g, ILength tol, Operation creator) { // Ensure we've got a point at the required position PointFeature pt = EnsurePointExists(g, tol, creator); // If it's not exactly coincident, we've picked up a previously loaded point // that happens to be within tolerance. If it's not already connected to any // lines, shift it to where we want it. if (!pt.IsCoincident(g)) { if (!pt.HasDependents) { m_Index.Remove(pt); PointFeature[] pts = pt.Node.Points; pt.SetNode(new Node(pts, g)); m_Index.Add(pt); } } return pt; }
private PointGeometry[] GetPositions(Ntx.Line line) { PointGeometry[] pts = new PointGeometry[line.NumPosition]; for (int i=0; i<line.NumPosition; i++) { Ntx.Position xp = line.Position(i); pts[i] = new PointGeometry(xp.Easting, xp.Northing); } return pts; }
/// <summary> /// Creates a new <c>KeyTextGeometry</c> that isn't associated with a text feature. There is a chicken and egg /// problem here - an instance of KeyTextGeometry is expected to refer to a TextFeature, but the feature cannot /// be created until the geometry has been created. So after creating the KeyTextGeometry, you are expected to /// create the corresponding feature, then assign the feature to this geometry using the <see cref="Label"/> /// property. /// </summary> /// <param name="pos">Position of the text's reference point (always the top left corner of the string).</param> /// <param name="font">The text style (defines the type-face and the height of the text).</param> /// <param name="height">The height of the text, in meters on the ground.</param> /// <param name="width">The total width of the text, in meters on the ground.</param> /// <param name="rotation">Clockwise rotation from horizontal</param> internal KeyTextGeometry(PointGeometry pos, IFont font, double height, double width, float rotation) : base(pos, font, height, width, rotation) { m_Feature = null; }
private Feature ImportName(Ntx.Name name, Operation creator) { /* * // Get pointer to the applicable map theme * CeTheme theme(Name.GetTheme()); * CeTheme* pTheme = theme.AddTheme(); * * // Get pointer to the entity type. * GRAPHICSTYPE geom = ANNOTATION; * if ( Name.IsLabel() ) geom = POLYGON; * CeEntity* pEntity = AddEntity(Name.GetpFeatureCode(),pTheme,geom); */ IEntity entity = GetEntityType(name, SpatialType.Text); // Get the text string string text = name.Text; // Get the position of the centre of the 1st character Ntx.Position pos = name.Position(0); IPosition vcentre = new Position(pos.Easting, pos.Northing); // Get text metrics float height = name.Height; float spacing = name.Spacing; float rotation = name.Rotation; // Calculate the top left corner of the first character using // the text metrics we just got ... // Get the width of the first character. For names that contain // only one character, the spacing we have will be zero, so in // that case, deduce the width of the character via the covering // rectangle. float charwidth = spacing; if (charwidth < Constants.TINY) { // Get the covering rectangle. Ntx.Position nw = name.NorthWest; Ntx.Position se = name.SouthEast; // And get the dimensions. double dx = se.Easting - nw.Easting; double dy = nw.Northing - se.Northing; // If the cover is screwed up, assume the width is 80% of the text height. if (dy < Constants.TINY) { charwidth = (float)(height * 0.8); } else { charwidth = (float)(height * (dx / dy)); } } // Define the bearing from bottom to top of the text. double vbear = (double)rotation; // Get position directly above the centre of the 1st char. IPosition above = Geom.Polar(vcentre, vbear, 0.5 * (double)height); // Define the bearing from the point we just got to the // start of the text string. double hbear = vbear - Constants.PIDIV2; // Back up half a character to get the initial corner. PointGeometry topleft = new PointGeometry(Geom.Polar(above, hbear, 0.5 * (double)charwidth)); IFont font = null; double width = (double)text.Length * charwidth; TextFeature result = null; if (name.IsLabel) { // Create key text string keystr = name.Text; KeyTextGeometry kt = new KeyTextGeometry(topleft, font, height, width, rotation); InternalIdValue id = CadastralMapModel.Current.WorkingSession.AllocateNextId(); result = new TextFeature(creator, id, entity, kt); kt.Label = result; result.SetTopology(true); // Define the label's foreign ID and form a two-way association ForeignId fid = GetFeatureId(keystr); Debug.Assert(fid != null); fid.Add(result); // Remember the reference position of the label. Ntx.Position xp = name.RefPosition; IPointGeometry pp = new PointGeometry(xp.Easting, xp.Northing); result.SetPolPosition(pp); } else { // Create a miscellaneous text label. MiscTextGeometry mt = new MiscTextGeometry(text, topleft, font, height, width, rotation); InternalIdValue id = CadastralMapModel.Current.WorkingSession.AllocateNextId(); result = new TextFeature(creator, id, entity, mt); result.SetTopology(false); } return(result); }
/// <summary> /// Remembers a new polygon reference position for this label. /// </summary> /// <param name="p">The reference position. Specify null if the default reference /// position should be used (the position associated with the text geometry).</param> internal void SetPolPosition(IPointGeometry p) { if (p == null) m_PolygonPosition = null; else m_PolygonPosition = PointGeometry.Create(p); // If the label was previously "built", re-calculate the relationship to any // enclosing polygon RecalculateEnclosingPolygon(); }
/// <summary> /// Checks whether the supplied positions define a zero-length line /// </summary> /// <param name="pts">The positions for a line</param> /// <returns>True if the supplied array contains fewer than 2 points, or all the points /// are exactly coincident.</returns> private bool HasZeroLength(PointGeometry[] pts) { if (pts.Length<2) return true; PointGeometry start = pts[0]; for (int i=1; i<pts.Length; i++) { if (!pts[i].IsCoincident(start)) return false; } return true; }
/// <summary> /// Initializes a new instance of the <see cref="Node"/> class, with sufficient space /// to reference a single point feature. Make a subsequent call to <see cref="AttachPoint"/> /// to associate the new node with the point. /// </summary> /// <param name="g">The position of the node</param> internal Node(PointGeometry g) : base(g) { m_Points = new List<PointFeature>(1); }
private Feature ImportName(Ntx.Name name, Operation creator) { /* // Get pointer to the applicable map theme CeTheme theme(Name.GetTheme()); CeTheme* pTheme = theme.AddTheme(); // Get pointer to the entity type. GRAPHICSTYPE geom = ANNOTATION; if ( Name.IsLabel() ) geom = POLYGON; CeEntity* pEntity = AddEntity(Name.GetpFeatureCode(),pTheme,geom); */ IEntity entity = GetEntityType(name, SpatialType.Text); // Get the text string string text = name.Text; // Get the position of the centre of the 1st character Ntx.Position pos = name.Position(0); IPosition vcentre = new Position(pos.Easting, pos.Northing); // Get text metrics float height = name.Height; float spacing = name.Spacing; float rotation = name.Rotation; // Calculate the top left corner of the first character using // the text metrics we just got ... // Get the width of the first character. For names that contain // only one character, the spacing we have will be zero, so in // that case, deduce the width of the character via the covering // rectangle. float charwidth = spacing; if (charwidth < Constants.TINY) { // Get the covering rectangle. Ntx.Position nw = name.NorthWest; Ntx.Position se = name.SouthEast; // And get the dimensions. double dx = se.Easting - nw.Easting; double dy = nw.Northing - se.Northing; // If the cover is screwed up, assume the width is 80% of the text height. if (dy < Constants.TINY) charwidth = (float)(height * 0.8); else charwidth = (float)(height * (dx/dy)); } // Define the bearing from bottom to top of the text. double vbear = (double)rotation; // Get position directly above the centre of the 1st char. IPosition above = Geom.Polar(vcentre, vbear, 0.5 * (double)height); // Define the bearing from the point we just got to the // start of the text string. double hbear = vbear - Constants.PIDIV2; // Back up half a character to get the initial corner. PointGeometry topleft = new PointGeometry(Geom.Polar(above, hbear, 0.5 * (double)charwidth)); IFont font = null; double width = (double)text.Length * charwidth; TextFeature result = null; if (name.IsLabel) { // Create key text string keystr = name.Text; KeyTextGeometry kt = new KeyTextGeometry(topleft, font, height, width, rotation); InternalIdValue id = CadastralMapModel.Current.WorkingSession.AllocateNextId(); result = new TextFeature(creator, id, entity, kt); kt.Label = result; result.SetTopology(true); // Define the label's foreign ID and form a two-way association ForeignId fid = GetFeatureId(keystr); Debug.Assert(fid != null); fid.Add(result); // Remember the reference position of the label. Ntx.Position xp = name.RefPosition; IPointGeometry pp = new PointGeometry(xp.Easting, xp.Northing); result.SetPolPosition(pp); } else { // Create a miscellaneous text label. MiscTextGeometry mt = new MiscTextGeometry(text, topleft, font, height, width, rotation); InternalIdValue id = CadastralMapModel.Current.WorkingSession.AllocateNextId(); result = new TextFeature(creator, id, entity, mt); result.SetTopology(false); } return result; }
/// <summary> /// Defines the position of this point as a new un-shared position. /// </summary> /// <param name="ctx">The context in which the assignment is being made. May be null, but do /// so with care - an editing context is vital when dealing with the propagation of updates. /// </param> /// <param name="value">The position to assign (not null).</param> internal void ApplyPointGeometry(EditingContext ctx, PointGeometry value) { if (value == null) throw new ArgumentNullException(); if (ctx != null) ctx.RegisterChange(this); m_Geom = new Node(this, value); }
private PointFeature EnsurePointExists(PointGeometry p, ILength tol, Operation creator) { PointFeature result = (PointFeature)m_Index.QueryClosest(p, tol, SpatialType.Point); if (result==null) { IEntity e = creator.MapModel.DefaultPointType; InternalIdValue id = CadastralMapModel.Current.WorkingSession.AllocateNextId(); result = new PointFeature(creator, id, e, p); m_Index.Add(result); m_Result.Add(result); } return result; }
/// <summary> /// Initializes a new instance of the <see cref="Move"/> class, with an "old" position that /// corresponds to it's current position. /// </summary> /// <param name="feature">The point feature that is being moved.</param> internal Move(PointFeature feature) { m_Feature = feature; m_OldPosition = new PointGeometry(feature.PointGeometry); }
private Feature ImportSymbol(Ntx.Symbol symbol, Operation creator) { IEntity what = GetEntityType(symbol, SpatialType.Point); // Get the position Ntx.Position pos = symbol.Position; PointGeometry g = new PointGeometry(pos.Easting, pos.Northing); // Ignore positions at 0,0! if (g.Easting.Microns==0 && g.Northing.Microns==0) return null; InternalIdValue id = CadastralMapModel.Current.WorkingSession.AllocateNextId(); PointFeature p = new PointFeature(creator, id, what, g); /* static LOGICAL warned=FALSE; // debug // Get pointer to the map theme CeTheme theme(Symbol.GetTheme()); const CeTheme* const pTheme = theme.AddTheme(); // Get pointer to the entity CeEntity* pEntity = AddEntity(Symbol.GetpFeatureCode(),pTheme,VERTEX); // Get the position const CxPosition& pos = Symbol.GetPosition(); // For the time being ... if ( !warned && pos.Is3D() ) { AfxMessageBox("Elevation data is being stripped."); warned = TRUE; } // Add the position of the symbol. CeVertex vtx(pos.GetEasting(),pos.GetNorthing()) ; const CeLocation* pLoc = pMap->AddLocation(vtx); // If the location does not already have an associated point // feature, add one now (the location may have been previously // added via the import of a line). // Note that this version of AddPoint will always add a duplicate // point at the specified location. CePoint* pPoint = pMap->AddPoint((CeLocation* const)pLoc,pEntity); */ // Define foreign ID (if any) ... string keystr = symbol.Key; ForeignId fid = GetFeatureId(keystr); if (fid != null) fid.Add(p); return p; }
private Feature ImportSymbol(Ntx.Symbol symbol, Operation creator) { IEntity what = GetEntityType(symbol, SpatialType.Point); // Get the position Ntx.Position pos = symbol.Position; PointGeometry g = new PointGeometry(pos.Easting, pos.Northing); // Ignore positions at 0,0! if (g.Easting.Microns == 0 && g.Northing.Microns == 0) { return(null); } InternalIdValue id = CadastralMapModel.Current.WorkingSession.AllocateNextId(); PointFeature p = new PointFeature(creator, id, what, g); /* * * static LOGICAL warned=FALSE; // debug * * // Get pointer to the map theme * CeTheme theme(Symbol.GetTheme()); * const CeTheme* const pTheme = theme.AddTheme(); * * // Get pointer to the entity * CeEntity* pEntity = AddEntity(Symbol.GetpFeatureCode(),pTheme,VERTEX); * * // Get the position * const CxPosition& pos = Symbol.GetPosition(); * * // For the time being ... * if ( !warned && pos.Is3D() ) { * AfxMessageBox("Elevation data is being stripped."); * warned = TRUE; * } * * // Add the position of the symbol. * CeVertex vtx(pos.GetEasting(),pos.GetNorthing()) ; * const CeLocation* pLoc = pMap->AddLocation(vtx); * * // If the location does not already have an associated point * // feature, add one now (the location may have been previously * // added via the import of a line). * * // Note that this version of AddPoint will always add a duplicate * // point at the specified location. * * CePoint* pPoint = pMap->AddPoint((CeLocation* const)pLoc,pEntity); */ // Define foreign ID (if any) ... string keystr = symbol.Key; ForeignId fid = GetFeatureId(keystr); if (fid != null) { fid.Add(p); } return(p); }
private ISpatialObject SelectObject(ISpatialDisplay display, IPosition p, SpatialType spatialType) { ProjectSettings ps = m_Project.Settings; CadastralMapModel cmm = this.CadastralMapModel; ISpatialSelection currentSel = this.SpatialSelection; ISpatialObject oldItem = currentSel.Item; ISpatialObject newItem; // Try to find a point feature if points are drawn. if ((spatialType & SpatialType.Point) != 0 && display.MapScale <= ps.ShowPointScale) { ILength size = new Length(ps.PointHeight * 0.5); newItem = cmm.QueryClosest(p, size, SpatialType.Point); if (newItem != null) { return(newItem); } } // If we are adding a line, don't bother trying to select // lines or polygons or text. /* * if (m_Op==ID_LINE_NEW || m_Op==ID_LINE_CURVE) * return 0; */ ILength tol = new Length(0.001 * display.MapScale); // Try to find a line, using a tolerance of 1mm at the draw scale. if ((spatialType & SpatialType.Line) != 0) { // If we previously selected something, see if the search point // lies within tolerance. If so, just return with what we've already got // ...just make the query (the issue here has to do with special highlighting // for topological sections -- if you point at another section of a line, the // highlighting doesn't move). // if (oldItem!=null && oldItem.SpatialType==SpatialType.Line) // { // ILength dist = oldItem.Distance(p); // if (dist.Meters < tol.Meters) // return; // } newItem = cmm.QueryClosest(p, tol, SpatialType.Line); if (newItem != null) { return(newItem); } } // Try for a text string if text is drawn. // The old software handles text by checking that the point is inside // the outline, not sure whether the new index provides acceptable alternative. if ((spatialType & SpatialType.Text) != 0 && display.MapScale <= ps.ShowLabelScale) { newItem = cmm.QueryClosest(p, tol, SpatialType.Text); if (newItem != null) { return(newItem); } } // Just return if a command dialog is up, // since selecting a polygon is distracting at that stage // (really, this applies to things like intersect commands). // There MIGHT be cases at some later date where we really // do want to select pols... // For updates, allow polygon selection if (IsCommandRunning && !(m_Command is UpdateUI)) { return(null); } if ((spatialType & SpatialType.Polygon) != 0) { // If we currently have a selected polygon, see if we're still inside it. /* * if (oldItem is Polygon) * { * Polygon oldPol = (oldItem is Polygon); * if (oldPol.IsEnclosing(p)) * * } */ IPointGeometry pg = PointGeometry.Create(p); ISpatialIndex index = cmm.Index; Polygon pol = new FindPointContainerQuery(index, pg).Result; if (pol != null) { return(pol); } } return(null); }