/// <summary> /// Creates a new <c>SectionGeometry</c> /// </summary> /// <param name="baseLine">The line the section is based on (not null).</param> /// <param name="start">The point at the start of the section (coincident with /// the specified line)</param> /// <param name="end">The point at the end of the section (coincident with /// the specified line)</param> /// <exception cref="ArgumentNullException">If a null line was specified</exception> internal SectionGeometry(LineFeature baseLine, PointFeature start, PointFeature end) : base(start, end) { if (baseLine==null) throw new ArgumentNullException(); m_Base = baseLine; }
/// <summary> /// Initializes a new instance of the <see cref="SectionGeometry"/> class /// using the data read from persistent storage. /// </summary> /// <param name="editDeserializer">The mechanism for reading back content.</param> internal SectionGeometry(EditDeserializer editDeserializer) : base(editDeserializer) { m_Base = editDeserializer.ReadFeatureRef<LineFeature>(DataField.Base); if (m_Base == null) throw new ArgumentNullException(); }
/// <summary> /// Records information for a line split /// </summary> /// <param name="parentLine">The line that may be getting split</param> /// <param name="field">The tag of the item that should be attached to the line split info</param> /// <param name="dataId">The ID for the section (null if there is no split)</param> /// <returns>True if a line split was recorded, false if the <paramref name="splitSection"/> is null.</returns> internal bool AddLineSplit(LineFeature parentLine, DataField field, string dataId) { if (dataId == null) return false; InternalIdValue id = new InternalIdValue(dataId); AddFeatureDescription(field, new FeatureStub(Creator, id, parentLine.EntityType, null)); return true; }
/// <summary> /// Creates a new <c>SectionTopologyList</c> that relates to the specified line, /// and with the specified list of sections. /// </summary> /// <param name="line">The line that any topological sections relate to.</param> /// <param name="sections">The topological sections (must all refer to <paramref name="line"/>)</param> /// <exception cref="ArgumentException">If any of the specified sections do not /// relate to <paramref name="line"/> /// </exception> internal SectionTopologyList(LineFeature line, List<IDivider> sections) : base(line) { foreach (IDivider d in sections) { if (d.Line != line) throw new ArgumentException("Topological section refers to inconsistent line"); } m_Sections = sections; }
/// <summary> /// Creates a new <c>FindIntersectionsQuery</c> (and executes it). The result of the query /// can then be obtained through the <c>Result</c> property. /// <para/> /// Use this constructor when intersecting something that has already been added to /// the spatial index. This ensures that the line is not intersected with itself. /// </summary> /// <param name="index">The spatial index to search</param> /// <param name="line">The line feature to intersect.</param> /// <param name="wantEndEnd">Specify true if you want end-to-end intersections in the results.</param> internal FindIntersectionsQuery(ISpatialIndex index, LineFeature line, bool wantEndEnd) { if (index == null) throw new ArgumentNullException("FindIntersectionsQuery"); m_Feature = line; m_Geom = GetUnsectionedLineGeometry(line.LineGeometry); m_WantEndEnd = wantEndEnd; m_Result = new List<IntersectionResult>(100); FindIntersections(index); }
/// <summary> /// Creates a new <c>SectionDivider</c> that relates to the specified section of line, /// with undefined polygon rings on left and right. /// </summary> /// <param name="line">The line this topological section partially coincides with.</param> /// <param name="from">The start position for the topological section.</param> /// <param name="to">The end position for the topological section.</param> internal SectionDivider(LineFeature line, ITerminal from, ITerminal to) : base(line, from, to) { m_Left = m_Right = null; if (from is Intersection) (from as Intersection).Add(line); else if (from is PointFeature) (from as PointFeature).AddReference(line); if (to is Intersection) (to as Intersection).Add(line); else if (to is PointFeature) (to as PointFeature).AddReference(line); }
/// <summary> /// Creates a new <c>SectionTopologyList</c> that relates to the specified line, /// but with an empty list of sections. /// </summary> /// <param name="line">The line that any topological sections must relate to.</param> internal SectionTopologyList(LineFeature line) : base(line) { m_Sections = new List<IDivider>(); }
/// <summary> /// Reacts to the selection of a line feature. /// </summary> /// <param name="line">The line (if any) that has been selected.</param> internal override void OnSelectLine(LineFeature line) { }
/// <summary> /// Creates a new <c>LineTopology</c> that relates to a complete line. /// Base class for <see cref="LineDivider"/> and <see cref="LineOverlap"/>. /// </summary> /// <param name="line">The line the topology relates to.</param> /// <seealso cref="SectionTopology"/> protected LineTopology(LineFeature line) : base(line) { }
/// <summary> /// Creates a new <c>SectionOverlap</c> that relates to a section of the specified line. /// </summary> /// <param name="line">The line the overlap topology is for (this is <b>not</b> /// the line that is overlapped by this section)</param> /// <param name="from">The start position for the section.</param> /// <param name="to">The end position for the section.</param> internal SectionOverlap(LineFeature line, ITerminal from, ITerminal to) : base(line, from, to) { }
/// <summary> /// Creates a new <c>LineOverlap</c> that relates to the specified line. /// </summary> /// <param name="line">The line the overlap topology is for (<b>not</b> /// the line that is overlapped)</param> internal LineOverlap(LineFeature line) : base(line) { }
/// <summary> /// Creates a new <c>IntersectionFinder</c> for the specified line feature. /// Use this constructor when intersecting something that has already been added to /// the map model. This ensures that the line is not intersected with itself. /// </summary> /// <param name="line">The line feature to intersect.</param> /// <param name="wantEndEnd">Specify true if you want end-to-end intersections in the results.</param> internal IntersectionFinder(LineFeature line, bool wantEndEnd) { m_Line = line; ISpatialIndex index = CadastralMapModel.Current.Index; m_Intersects = new FindIntersectionsQuery(index, line, wantEndEnd).Result; }
/// <summary> /// Creates a new <c>Divider</c> that relates to the specified line. /// </summary> /// <param name="line">The line the topology relates to.</param> internal LineDivider(LineFeature line) : base(line) { m_Left = m_Right = null; }
private Feature ImportLine(ILength tol, Ntx.Line line, Operation creator) { // Circular arcs are handled elsewhere if (line.IsCurve) return null; IEntity what = GetEntityType(line, SpatialType.Line); PointGeometry[] pts = GetPositions(line); // Ignore zero-length lines if (HasZeroLength(pts)) return null; // Ensure point features exist at both ends of the line. PointFeature ps = EnsurePointExists(pts[0], tol, creator); PointFeature pe = EnsurePointExists(pts[pts.Length-1], tol, creator); // Force end positions to match pts[0] = ps.PointGeometry; pts[pts.Length-1] = pe.PointGeometry; // It's possible we've now produced a zero-length line if (Object.ReferenceEquals(ps, pe) && HasZeroLength(pts)) return null; // If we're dealing with a multi-segment, I have occasionally seen tiny glitches // at the end of the incoming lines (whether this is a real data problem, or an // imperfection in the import software is unknown). So double check now. // In the longer term, the import software should also check for more complex // issues, like missing intersections. In the meantime, I assume that incoming // topological data is generally clean. if (pts.Length > 2 && line.IsTopologicalArc) pts = CheckMultiSegmentEnds(pts); LineFeature result; InternalIdValue id = CadastralMapModel.Current.WorkingSession.AllocateNextId(); if (pts.Length==2) result = new LineFeature(creator, id, what, ps, pe); else result = new LineFeature(creator, id, what, ps, pe, pts); // The toological status of the incoming arc may override the status that the // constructor derived from the entity type result.SetTopology(line.IsTopologicalArc); return result; }
/// <summary> /// Creates a new <c>SectionTopology</c> /// </summary> /// <param name="line">The line this topological section partially coincides with.</param> /// <param name="from">The start position for the topological section.</param> /// <param name="to">The end position for the topological section.</param> protected SectionTopology(LineFeature line, ITerminal from, ITerminal to) { m_Line = line; m_From = from; m_To = to; }
/// <summary> /// Reacts to the selection of a line feature. /// </summary> /// <param name="line">The line (if any) that has been selected.</param> internal abstract void OnSelectLine(LineFeature line);
/// <summary> /// Mark this line as inactive. /// </summary> /// <param name="op">The operation that is doing this</param> /* internal void SetInactive(Operation op) { throw new NotImplementedException(); } */ /* // @mfunc Mark this arc as inactive. When you do this, any // system-defined split sections will be eliminated. // // @parm The operation that is doing this. This operation will // hold any sub-features that get created as a result of // de-activating this arc. Only SetDeleted is expected to // pass in a null value. // @parm Is the arc being de-activated in order to trim a // dangling system-generated arc section? If so, DON'T // undo any splits that are incident on this arc. A // TRUE value should be specified ONLY by <mf CeSplit:: // Trim>. Default=FALSE. // // @rdesc Any sub-feature that was created to represent the // layers that this feature was NOT de-activated on. CeFeature* CeArc::SetInactive ( CeOperation* pop , const LOGICAL isTrim ) { // Return if this arc is already inactive (or marked for deletion). if ( this->IsInactive() ) return 0; // De-activate the base class. CeFeature* pSub = CeFeature::SetInactive(pop); // Ensure polygons on the left and right have been marked // for deletion. SetPolDeleted(); // Get any split operation listing arc sections (only returns // something if FFL_SYSTOPOL is set). CeSplit* pSplit = GetpSplit(); if ( pSplit ) { // Return if the splits have been revealed. if ( pSplit->IsRevealed() ) return pSub; // Mark all splits for deletion. RemoveSplits(); // If we created a sub-arc to represent layers that are // not being de-activated, mark it as moved, to force // re-intersection. if ( pSub ) pSub->SetMoved(); } // Check for overlaps with the line's end locations. if ( !isTrim ) m_pLine->UndoEndOverlaps(*this); return pSub; } // end of SetInactive */ /// <summary> /// Make a new line that corresponds to a sub-section of this line. /// </summary> /// <param name="creator">The operation that should be noted as the creator of the new line.</param> /// <param name="id">The internal ID to assign to the sub-section.</param> /// <param name="section">The geometry for the new line.</param> /// <returns>The new line</returns> internal LineFeature MakeSubSection(Operation creator, InternalIdValue id, SectionGeometry section) { LineFeature result = new LineFeature(creator, id, section); //PointFeature start = (PointFeature)section.Start; //PointFeature end = (PointFeature)section.End; //LineFeature result = new LineFeature(this.EntityType, op, start, end, section); DefineFeature(result); // The resultant sub-section should always have the same topological status //if (result.IsTopological) // result.m_Topology = Topology.CreateTopology(result); result.SetTopology(this.IsTopological); return result; }
/// <summary> /// Intersect this line with another line. /// </summary> /// <param name="line">The line to intersect with (not equal to THIS line)</param> /// <param name="closeTo">The point that the intersection should be closest to. /// Specify null if you don't care. In that case, if there are multiple intersections, /// you get the intersection that is closest to one of 3 points: the start of the /// direction line, the start of the line, or the end of the line.</param> /// <param name="xsect">The position of the intersection (if any). Null if not found.</param> /// <param name="closest">The default point that is closest to the intersection. Null if /// intersection wasn't found.</param> /// <returns>True if intersection was found.</returns> internal bool Intersect( LineFeature line , PointFeature closeTo , out IPosition xsect , out PointFeature closest) { // Initialize results xsect = null; closest = null; // Don't intersect a line with itself. if (Object.ReferenceEquals(this, line)) throw new Exception("Cannot intersect a line with itself."); // Intersect this line with the other one. IntersectionResult xres = new IntersectionResult(this); uint nx = line.LineGeometry.Intersect(xres); if (nx==0) return false; // Determine which terminal point is the best. double mindsq = Double.MaxValue; if (xres.GetCloserPoint(this.StartPoint, ref mindsq, ref xsect)) closest = this.StartPoint; if (xres.GetCloserPoint(this.EndPoint, ref mindsq, ref xsect)) closest = this.EndPoint; if (xres.GetCloserPoint(line.StartPoint, ref mindsq, ref xsect)) closest = line.StartPoint; if (xres.GetCloserPoint(line.EndPoint, ref mindsq, ref xsect)) closest = line.EndPoint; // If a close-to point has been specified, that overrides // everything else (however, doing the above has the desired // effect of defining the best of the default points). In // this case, we allow an intersection that coincides with // the line being intersected. if (closeTo!=null) xres.GetClosest(closeTo, out xsect, 0.0); return (xsect!=null); }
/// <summary> /// Initializes a new instance of the <see cref="LineFeature"/> class that corresponds to /// a section of another line, and records it as part of the map model. /// </summary> /// <param name="f">Basic information about the feature (not null).</param> /// <param name="baseLine">The line that this section is part of</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> /// <exception cref="ArgumentNullException">If either <paramref name="ent"/> or /// <paramref name="creator"/> is null.</exception> internal LineFeature(IFeature f, LineFeature baseLine, PointFeature start, PointFeature end, bool isTopological) : this(f, start, end, new SectionGeometry(baseLine, start, end), isTopological) { }
/// <summary> /// Attempts to locate a superseded (inactive) line that was the parent of /// a specific line. /// </summary> /// <param name="line">The line of interest</param> /// <returns>A line that was superseded by this edit in order to produce /// the line of interest.</returns> internal abstract LineFeature GetPredecessor(LineFeature line);
/// <summary> /// Removes the specified line from this intersection. /// </summary> /// <param name="line">The line to remove</param> /// <returns>True if the line was removed. False if it was not associated /// with this intersection</returns> internal bool Remove(LineFeature line) { return m_Lines.Remove(line); }
/// <summary> /// Convenience method that marks a line as "moved" (first checks whether /// the specified line is null). This is normally called by implementations /// of the <c>Intersect</c> method. /// </summary> /// <param name="line">The line to mark as moved (may be null)</param> protected void SetMoved(LineFeature line) { if (line!=null) line.IsMoved = true; }
/// <summary> /// Highlights the specified line on the command's active display. /// </summary> /// <param name="line">The line to highlight (ignored if null)</param> protected void Highlight(LineFeature line) { if (line!=null) { IDrawStyle style = Controller.HighlightStyle; ISpatialDisplay display = ActiveDisplay; line.Render(display, style); } }
/// <summary> /// Creates a new <c>FindIntersectionsQuery</c> (and executes it). The result of the query /// can then be obtained through the <c>Result</c> property. /// <para/> /// Use this constructor when intersecting with geometry that has been created ad-hoc. /// Note that if you are looking to intersect a line feature (already part of /// the spatial index), you should use the constructor that accepts the <c>LineFeature</c>. /// </summary> /// <param name="index">The spatial index to search</param> /// <param name="geom">The geometry to intersect.</param> /// <param name="wantEndEnd">Specify true if you want end-to-end intersections in the results.</param> internal FindIntersectionsQuery(ISpatialIndex index, LineGeometry geom, bool wantEndEnd) { m_Feature = null; m_Geom = GetUnsectionedLineGeometry(geom); m_WantEndEnd = wantEndEnd; m_Result = new List<IntersectionResult>(100); FindIntersections(index); }
/// <summary> /// Associates this intersection with the specified line. /// </summary> /// <param name="line">The line that passes through this intersection (not null)</param> /// <exception cref="ArgumentNullException">If the specified line is null</exception> internal void Add(LineFeature line) { if (line == null) throw new ArgumentNullException(); if (!m_Lines.Contains(line)) m_Lines.Add(line); }
/// <summary> /// /// </summary> /// <param name="line"></param> internal void OnLineDeactivation(LineFeature line) { // Remove the reference the intersection has to the line Remove(line); // If the intersection now refers only to one line, it's no longer // an intersection, so remove it from the spatial index and merge // the sections incident on the intersection. if (m_Lines.Count<=1) { if (IsIndexed) { CadastralMapModel map = line.MapModel; EditingIndex index = map.EditingIndex; index.RemoveIntersection(this); } if (m_Lines.Count>0) { Topology t = m_Lines[0].Topology; if (t != null) { // Merge the two sections - if we end up with just one // section covering the whole line, replace list topology // with fresh topology for the whole line. if (t.MergeSections(this) == 1) { m_Lines[0].SetTopology(true); } } } } }
/// <summary> /// Creates a new line section /// </summary> /// <param name="itemName">The name for the item involved</param> /// <param name="baseLine">The line that this section is part of</param> /// <param name="from">The point at the start of the section</param> /// <param name="to">The point at the end of the section</param> /// <returns>The created section (never null)</returns> internal override LineFeature CreateSection(string itemName, LineFeature baseLine, PointFeature from, PointFeature to) { IFeature f = new FeatureStub(this.Creator, InternalIdValue.Empty, baseLine.EntityType, null); return new LineFeature(f, baseLine, from, to, baseLine.IsTopological); }