/// <summary> /// Attempts to make a distance out of this observation and a from-point. /// </summary> /// <param name="from">The point the distance was measured from.</param> /// <returns> /// The distance, in metres on the ground. If a distance cannot be deduced, /// this will be 0.0. NOTE: may actually be a distance on the mapping plane if this /// observation is an offset point. The caller needs to check.</returns> /// <devnote> /// This function was written to assist in the implementation of the /// Intersect Direction & Distance command, which allows a distance to be specified /// using an offset point. Since offsets and distance object do not inherit from some /// place where we could define a pure virtual, this function exists to make explicit /// checks on the sort of distance we have (I don't want to define stubs for all the /// other objects which won't be able to return a distance). Re-arranging the class /// hierarchy would be better. /// </devnote> internal ILength GetDistance(PointFeature from) { // It's easy if the observation is a distance object. Distance dist = (this as Distance); if (dist != null) { return(dist); } // Can't do anything if the from point is undefined. if (from == null) { return(Length.Zero); } // See if we have an offset point. If so, the distance is the // distance from the from-point to the offset-point. OffsetPoint offset = (OffsetPoint)this; if (offset == null) { return(Length.Zero); } return(new Length(Geom.Distance(offset.Point, from))); }
/// <summary> /// Calculates the distance from the start of this line to a specific position (on the map projection) /// </summary> /// <param name="asFarAs">Position on the line that you want the length to. Specify /// null for the length of the whole line.</param> /// <returns>The length. Less than zero if a position was specified and it is /// not on the line.</returns> internal override ILength GetLength(IPosition asFarAs) { if (asFarAs == null) { return(Length); } else { // assume it's on the line return(new Length(Geom.Distance(Start, asFarAs))); } }
/// <summary> /// Delegate that's called whenever the index finds a line with an extent that /// overlaps the query window. /// </summary> /// <param name="item">The item to process (expected to be some sort of <c>IFeature</c>)</param> /// <returns>True (always), meaning the query should continue.</returns> private bool OnQueryHit(ISpatialObject item) { if (item is Circle) { // Confirm the circle is truly within tolerance Circle c = (item as Circle); double rad = c.Radius; double dist = Geom.Distance(c.Center, m_Position); if (Math.Abs(rad - dist) < m_Tolerance) { m_Result.Add(c); } } return(true); }
/// <summary> /// Gets the point on this line that is closest to a specified position. /// </summary> /// <param name="p">The position to search from.</param> /// <param name="tol">Maximum distance from line to the search position</param> /// <returns>The closest position (null if the line is further away than the specified /// max distance)</returns> internal override IPosition GetClosest(IPointGeometry p, ILength tol) { // Get the distance from the centre of the circle to the search point. IPointGeometry center = m_Circle.Center; double dist = Geom.Distance(center, p); // Return if the search point is beyond tolerance. double radius = m_Circle.Radius; double diff = Math.Abs(dist - radius); if (diff > tol.Meters) { return(null); } // If the vertex lies in the curve sector, the closest position // is along the bearing from the centre through the search // position. Otherwise the closest position is the end of // the curve that's closest (given that it's within tolerance). if (CircularArcGeometry.IsInSector(this, p, 0.0)) { double bearing = Geom.BearingInRadians(center, p); return(Geom.Polar(center, bearing, radius)); } double d1 = Geom.DistanceSquared(p, BC); double d2 = Geom.DistanceSquared(p, EC); double t = tol.Meters; if (Math.Min(d1, d2) < (t * t)) { if (d1 < d2) { return(BC); } else { return(EC); } } return(null); }
/// <summary> /// Obtains the geometry for spans along an alternate face attached to this leg. /// </summary> /// <param name="start">The position for the start of the leg. /// <param name="end">The position for the end of the leg.</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 start, IPosition end, SpanInfo[] spans) { Debug.Assert(AlternateFace != null); // Get the desired length (in meters on the ground) double len = Geom.Distance(start, end); // Get the observed length (in meters on the ground) double obs = AlternateFace.GetTotal(); // Get the adjustment factor for stretching-compressing the observed distances. double factor = len / obs; // Get the bearing of the line. double bearing = Geom.BearingInRadians(start, end); return(GetSpanSections(start, bearing, factor, spans)); }
static bool GetPosition(IPosition[] line, double d, out IPosition result) { if (line.Length < 2) { throw new Exception("Line contains fewer than 2 positions"); } // Check for invalid distance if (d < 0.0) { result = line[0]; return(false); } double walked = 0.0; // Distance walked so far // Loop through the segments until we get to a distance that // exceeds the required distance. for (int i = 1; i < line.Length; i++) { // Update total length walked to end of segment double seglen = Geom.Distance(line[i - 1], line[i]); walked += seglen; // If the accumulated distance exceeds the required distance, // the point we want is somewhere in the current segment. if (walked >= d) { double ratio = (walked - d) / seglen; // Check whether the ratio yields a length that matches segment length to within // the order of the data precision (1 micron). If so, return the start of the segment. // If you don't do this, minute shifts occur when points are inserted into the // multisegment. This means that if you repeat the GetPosition call with the SAME distance, // you may actually get a point that is fractionally different from the initially returned // point. if ((seglen - ratio * seglen) < 0.000002) { result = line[i - 1]; } else { // Make damn sure! double xs = line[i - 1].X; double ys = line[i - 1].Y; double xe = line[i].X; double ye = line[i].Y; double dx = xe - xs; double dy = ye - ys; double xres = xe - ratio * dx; double yres = ye - ratio * dy; if (Math.Abs(xres - xe) < 0.000002 && Math.Abs(yres - ye) < 0.000002) { result = line[i]; } else { result = new Position(xres, yres); } } return(true); } } // Got to the end, so the distance is too much result = line[line.Length - 1]; return(false); }
void CheckPts(string ptsFileName, CadastralMapModel mm) { if (!File.Exists(ptsFileName)) { return; } var badList = new List <CheckData>(); foreach (string s in File.ReadAllLines(ptsFileName)) { string[] items = s.Split(','); uint id = UInt32.Parse(items[0]); double x = Double.Parse(items[1]); double y = Double.Parse(items[2]); Position a = new Position(x, y); PointFeature p = mm.Find <PointFeature>(new InternalIdValue(id)); if (p != null) { double delta = Geom.Distance(a, p); if (delta > 0.001) { badList.Add(new CheckData() { Point = p, Delta = delta }); } } } // Obtain the calculation sequence Operation[] calcs = mm.GetCalculationSequence(); var editOrder = new Dictionary <uint, uint>(); for (int i = 0; i < calcs.Length; i++) { editOrder.Add(calcs[i].EditSequence, (uint)i); } foreach (CheckData cd in badList) { cd.CalculationOrder = editOrder[cd.Point.Creator.EditSequence]; } badList.Sort((A, B) => A.CalculationOrder.CompareTo(B.CalculationOrder)); using (StreamWriter sw = File.CreateText(ptsFileName + ".check")) { // Dump out the calc order //foreach (Operation op in calcs) // sw.WriteLine(String.Format("Edit={0} Order={1} Type={2}", op.EditSequence, editOrder[op.EditSequence], op.EditId)); sw.WriteLine("Number of points>0.001 = " + badList.Count); foreach (CheckData cd in badList) { sw.WriteLine(String.Format("Order={0} Id={1} Delta={2:0.000}", cd.CalculationOrder, cd.Point.InternalId.ItemSequence, cd.Delta)); } } }
/// <summary> /// Adjusts the path (Helmert adjustment). /// </summary> /// <param name="dN">Misclosure in northing.</param> /// <param name="dE">Misclosure in easting.</param> /// <param name="precision">Precision denominator (zero if no adjustment needed).</param> /// <param name="length">Total observed length.</param> /// <param name="rotation">The clockwise rotation to apply (in radians).</param> /// <param name="sfac">The scaling factor to apply.</param> void Adjust(out double dN, out double dE, out double precision, out double length, out double rotation, out double sfac) { dN = dE = precision = length = rotation = 0.0; sfac = 1.0; // Initialize position to the start of the path, corresponding to the initial // un-adjusted end point. IPosition start = m_From; IPosition gotend = new Position(m_From); // Initial bearing is due north. double bearing = 0.0; // Go through each leg, updating the end position, and getting // the total path length. foreach (Leg leg in m_Legs) { length += leg.Length.Meters; leg.Project(ref gotend, ref bearing, sfac); } // Get the bearing and distance of the end point we ended up with. double gotbear = Geom.BearingInRadians(m_From, gotend); double gotdist = Geom.Distance(m_From, gotend); // Get the bearing and distance we want. double wantbear = Geom.BearingInRadians(m_From, m_To); double wantdist = Geom.Distance(m_From, m_To); // Figure out the rotation. rotation = wantbear - gotbear; // Rotate the end point we got. gotend = Geom.Rotate(m_From, gotend, new RadianValue(rotation)); // Calculate the line scale factor. double linefac = m_From.MapModel.SpatialSystem.GetLineScaleFactor(m_From, gotend); // Figure out where the rotated end point ends up when we apply the line scale factor. gotend = Geom.Polar(m_From, wantbear, gotdist * linefac); // What misclosure do we have? dN = gotend.Y - m_To.Y; dE = gotend.X - m_To.X; double delta = Math.Sqrt(dN * dN + dE * dE); // What's the precision denominator (use a value of 0 to denote an exact match). if (delta > MathConstants.TINY) { precision = wantdist / delta; } else { precision = 0.0; } // Figure out the scale factor for the adjustment (use a value of 0 if the start and end // points are coincident). The distances here have NOT been adjusted for the line scale factor. if (gotdist > MathConstants.TINY) { sfac = wantdist / gotdist; } else { sfac = 0.0; } // Remember the rotation and scaling factor m_IsAdjusted = true; m_Rotation = rotation; m_ScaleFactor = sfac; m_Precision = precision; }