/// <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; }
internal HorizontalRay(IPosition start, double distance) { if (distance < 0.0) { throw new ArgumentOutOfRangeException(); } m_Start = PointGeometry.Create(start); m_EndX = start.X + distance; }
/// <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> /// 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); }
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); }
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> /// Obtains the geometry for spans along this leg. /// </summary> /// <param name="bc">The position for the start of the leg. /// <param name="bcBearing">The bearing on entry into the leg.</param> /// <param name="sfac">Scale factor to apply to distances.</param> /// <param name="spans">Information for the spans coinciding with this leg.</param> /// <returns>The sections along this leg</returns> internal override ILineGeometry[] GetSpanSections(IPosition bc, double bcBearing, double sfac, SpanInfo[] spans) { // Can't do anything if the leg radius isn't defined if (m_Metrics.ObservedRadius == null) { throw new InvalidOperationException("Cannot create sections for circular leg with undefined radius"); } var result = new ILineGeometry[spans.Length]; // Use supplied stuff to derive info on the center and EC. IPosition center; IPosition ec; double bearingToBC; double ecBearing; GetPositions(bc, bcBearing, sfac, out center, out bearingToBC, out ec, out ecBearing); // Define the underlying circle ICircleGeometry circle = new CircleGeometry(PointGeometry.Create(center), BasicGeom.Distance(center, bc)); // Handle case where the leg is a cul-de-sac with no observed spans if (spans.Length == 1 && spans[0].ObservedDistance == null) { result[0] = new CircularArcGeometry(circle, bc, ec, m_Metrics.IsClockwise); return(result); } /// Initialize scaling factor for distances in cul-de-sacs (ratio of the length calculated from /// the CA & Radius, versus the observed distances that were actually specified). For curves that /// are not cul-de-sacs, this will be 1.0 double culFactor = 1.0; if (m_Metrics.IsCulDeSac) { double obsv = PrimaryFace.GetTotal(); if (obsv > MathConstants.TINY) { culFactor = Length.Meters / obsv; } } IPosition sPos = bc; IPosition ePos = null; bool isClockwise = m_Metrics.IsClockwise; double radius = RadiusInMeters; double edist = 0.0; for (int i = 0; i < result.Length; i++, sPos = ePos) { // Add on the unscaled distance edist += spans[i].ObservedDistance.Meters; // Get the angle subtended at the center of the circle. We use // unscaled values here, since the scale factors would cancel out. // However, we DO apply any cul-de-sac scaling factor, to account // for the fact that the distance may be inconsistent with the // curve length derived from the CA and radius. For example, it // is possible that the calculated curve length=200, although the // total of the observed spans is somehow only 100. In that case, // if the supplied distance is 50, we actually want to use a // value of 50 * (200/100) = 100. double angle = (edist * culFactor) / radius; // Get the bearing of the point with respect to the center of the circle. double bearing; if (isClockwise) { bearing = bearingToBC + angle; } else { bearing = bearingToBC - angle; } // Calculate the position using the scaled radius. ePos = Geom.Polar(center, bearing, radius * sfac); result[i] = new CircularArcGeometry(circle, sPos, ePos, isClockwise); } return(result); }
/// <summary> /// Assigns sort values to the supplied intersections (each sort value /// indicates the distance from the start of this line). /// </summary> /// <param name="data">The intersection data to update</param> internal override void SetSortValues(List <IntersectionData> dataList) { // Get an array of cumulative distances for each segment. IPointGeometry[] data = this.Data; double[] cumdist = GetCumDist(data); foreach (IntersectionData xd in dataList) { // Get the first intersection IPointGeometry pos = PointGeometry.Create(xd.P1); double xi = pos.X; double yi = pos.Y; // Find the segment number // @devnote -- we may need to use a different function at // this point, because FindSegment currently assumes that // the intersection must lie within the window of the segment. int segnum = FindSegment(data, true, 0, pos); if (segnum < 0) { throw new Exception("MultiSegmentGeometry.SetSortValues - intersection not on line"); } // Get position of the start of segment double xs = data[segnum].X; double ys = data[segnum].Y; // Get the distance squared to the start of segment double dx = xi - xs; double dy = yi - ys; double dsq = (dx * dx + dy * dy); // If we have a graze, process the 2nd intersection too // (it MUST lie on the same segment, given that multisegments // are intersected by processing each segment in turn). // If it's closer than the distance we already have, use // the second intersection as the sort value, and treat // it subsequently as the first intersection. if (xd.IsGraze) { xi = xd.P2.X; yi = xd.P2.Y; dx = xi - xs; dy = yi - ys; double dsq2 = (dx * dx + dy * dy); if (dsq2 < dsq) { xd.Reverse(); dsq = dsq2; } } // Set the sort value double dset = cumdist[segnum] + Math.Sqrt(dsq); xd.SortValue = dset; } }