예제 #1
0
        /// <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));
        }
예제 #2
0
        /// <summary>
        /// Returns the point feature that is at the end of this leg.
        /// </summary>
        /// <param name="op">The operation that is expected to have created the end point.</param>
        /// <returns>The point object at the end. Null if the leg ends with an "OmitPoint", or
        /// the leg ends at a point that was not created by the specified operation (in the latter
        /// case, the leg might end at the very end of a connection path).</returns>
        internal PointFeature GetEndPoint(Operation op)
        {
            // If the very last feature for this leg is a point, that's the thing we want.
            Feature      feat  = m_Spans[NumSpan - 1].CreatedFeature;
            PointFeature point = (feat as PointFeature);

            if (point != null)
            {
                return(point);
            }

            // Otherwise the last feature should be a line object, so
            // we want IT'S end point (either active or inactive).
            LineFeature line = (feat as LineFeature);

            if (line != null)
            {
                point = line.EndPoint;
                if (Object.ReferenceEquals(point.Creator, op))
                {
                    return(point);
                }
            }

            return(null);
        }
예제 #3
0
        /// <summary>
        /// Initializes a new instance of the <see cref="ArcGeometry"/> class
        /// using the data read from persistent storage.
        /// </summary>
        /// <param name="editDeserializer">The mechanism for reading back content.</param>
        internal ArcGeometry(EditDeserializer editDeserializer)
            : base(editDeserializer)
        {
            m_IsClockwise = editDeserializer.ReadBool(DataField.Clockwise);

            if (editDeserializer.IsNextField(DataField.Center))
            {
                PointFeature center = editDeserializer.ReadFeatureRef <PointFeature>(this, DataField.Center);

                // The arc is the first arc attached to the circle. However, we cannot
                // calculate the radius just yet because the bc/ec points are not persisted
                // as part of the ArcGeometry definition (they are defined as part of the
                // LineFeature object that utilizes the ArcGeometry).

                // Even if we did have the bc/ec points at this stage, their positions will
                // only be available if the data came from an import (they will still be
                // undefined if the geometry is calculated, since calculation only occurs
                // after deserialization has been completed).

                if (center != null)
                {
                    ApplyFeatureRef(DataField.Center, center);
                }
            }
            else
            {
                ArcFeature firstArc = editDeserializer.ReadFeatureRef <ArcFeature>(this, DataField.FirstArc);
                if (firstArc != null)
                {
                    ApplyFeatureRef(DataField.FirstArc, firstArc);
                }
            }
        }
예제 #4
0
        /*
         * /// <summary>
         * /// Updates the definition of this circle.
         * /// </summary>
         * /// <param name="center">The point at the center of the circle.</param>
         * /// <param name="radius">The radius of the circle, on the ground, in meters</param>
         * internal void MoveCircle(PointFeature center, double radius)
         * {
         *  // Remove this circle (and attached arcs) from the spatial index
         *  foreach (ArcFeature a in m_Arcs)
         *      a.PreMove();
         *
         *  m_Center.MapModel.EditingIndex.RemoveCircle(this);
         *
         *  // If the center location is changing then ensure that
         *  // the old location no longer refers to this circle,
         *  // and ensure the new one does.
         *
         *  // 08-DEC-99: Note that there appears to be inconsistency
         *  // in the cross-referencing of the center location to the
         *  // circle. Some places seem to do it, while other don't.
         *  // The extra reference shouldn't hurt, and at some stage
         *  // in the future, it would be good to enforce this.
         *
         *  if (!Object.ReferenceEquals(m_Center, center))
         *  {
         *      m_Center.CutReference(this);
         *      m_Center = center;
         *      m_Center.AddReference(this);
         *  }
         *
         *  // Change the radius
         *  m_Radius = radius;
         *
         *  // Re-index this circle and any attached arcs (this should also
         *  // mark the operations that created the arcs for rollforward).
         *  m_Center.MapModel.EditingIndex.AddCircle(this);
         *  foreach (ArcFeature a in m_Arcs)
         *      a.PostMove();
         * }
         */

        /// <summary>
        /// Checks whether this circle is referenced to arcs that terminaye at
        /// a specific point. This excludes arcs that correspond to the whole circle.
        /// </summary>
        /// <param name="p">The point to look for</param>
        /// <returns>True if an incident arc was found.</returns>
        internal bool HasArcsAt(PointFeature p)
        {
            // A location to check has to be specified!
            if (p == null)
            {
                return(false);
            }

            // Loop through each arc (including inactive ones).
            foreach (ArcFeature a in m_Arcs)
            {
                // Skip if the arc represents the whole circle.
                if (a.Geometry.IsCircle)
                {
                    continue;
                }

                // Check whether either end of the arc coincides with
                // the check location.
                if (p.IsCoincident(a.StartPoint) || p.IsCoincident(a.EndPoint))
                {
                    return(true);
                }
            }

            return(false);
        }
예제 #5
0
 /// <summary>
 /// Creates a new <c>FindPointQuery</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="point">The position of interest</param>
 internal FindPointQuery(ISpatialIndex index, IPointGeometry p)
 {
     m_Point = p;
     m_Result = null;
     IWindow w = new Window(p, p);
     index.QueryWindow(w, SpatialType.Point, OnQueryHit);
 }
예제 #6
0
        /// <summary>
        /// Performs processing when a point is about to be moved.
        /// </summary>
        /// <param name="point">The point that is about to move</param>
        void HandlePointMoving(PointFeature point)
        {
            // Remove the point from the spatial index.
            point.RemoveIndex();

            // Remove all dependent spatial objects from the index as well (usually
            // incident lines, but could also be circles)

            // Convert the supplied List to an array, since we may cut refs in
            // the loop below.
            if (point.Dependents != null)
            {
                IFeatureDependent[] deps = point.Dependents.ToArray();

                if (deps != null)
                {
                    // IFeatureDependent is implemented by Feature, Circle, and Operation.
                    // For features and circles, this will remove them from the spatial index (for
                    // line features, any polygon topology will also be marked for a rebuild).
                    // For operations, OnFeatureMoving does nothing.

                    foreach (IFeatureDependent fd in deps)
                    {
                        fd.OnFeatureMoving(point, this);
                    }
                }
            }
        }
예제 #7
0
        /// <summary>
        /// Defines geometry for this link (and undefines everything else). For use by <c>PolygonFace</c>.
        /// </summary>
        /// <param name="point">The point that coincides with this link position (may be null at
        /// system-generated split location)</param>
        /// <param name="isCurveEnd">Does the link location coincide with the BC/EC of a circular
        /// arc? If the link is regarded as a radial position, this must be false.</param>
        /// <param name="isRadial">Does the link fall somewhere along a circular curve?</param>
        /// <param name="bearing">The bearing of the bisector of the angle formed with adjacent
        /// link objects</param>
        /// <param name="angle">The clockwise angle formed with adjacent link positions (irrelevant
        /// if the link is a radial).</param>
        internal void Define(PointFeature point, bool isCurveEnd, bool isRadial, double bearing, double angle)
        {
            // Ensure everything is in it's default state
            ResetContent();

            // Assign the supplied values
            m_Point      = point;
            m_IsCurveEnd = isCurveEnd;
            m_IsRadial   = isRadial;

            // If we're dealing with a radial, the angle is n/a. Otherwise
            // pick up a value that's less than 180 degrees (this simplifies
            // the test to see if we're dealing with a corner)
            if (m_IsRadial)
            {
                m_Angle = 0.0;
            }
            else
            {
                m_Angle = angle;
                if (m_Angle > Constants.PI)
                {
                    m_Angle -= Constants.PI;
                }
            }

            // Important that the bearing is in range [0,PIMUL2), for use with Turn.GetAngle
            m_Bearing = bearing;
            if (m_Bearing >= Constants.PIMUL2)
            {
                m_Bearing -= Constants.PIMUL2;
            }
        }
예제 #8
0
        /// <summary>
        /// Remembers a point that is about to be moved
        /// </summary>
        /// <param name="p">The point that is about to move</param>
        internal void AddMove(PointFeature p)
        {
            UpdateUndoMarker um = m_Moves.Peek();

            Debug.Assert(um != null);
            um.AddMove(p);
        }
예제 #9
0
        /// <summary>
        /// Tries to get a link between two points.

        /// </summary>
        /// <remarks>
        /// You can cycle through the links as soon as the constructor has been called, using
        /// a loop like:
        /// <code>
        ///
        ///   PolygonSub sub = new PolygonSub(pol);
        ///   PointFeature ps, pe;
        ///   for (int i=0; sub.GetLink(i,out ps, out pe); i++);
        ///
        /// </code>
        /// </remarks>
        /// <param name="index">The index number of the link you want.</param>
        /// <param name="start">The point at the start of the link.</param>
        /// <param name="end">The point at the end of the link.</param>
        /// <returns>True if a link was returned</returns>
        internal bool GetLink(int index, out PointFeature start, out PointFeature end)
        {
            // Initialize return variables.
            start = end = null;

            // Loop through each point, checking to see whether it has a link. If so,
            // check if we have reached the desired index, and increment link count. This
            // may not be particularly efficient, but there shouldn't be that many links.

            PointFeature s, e;      // Start and end of link
            int          nLink = 0; // No links so far

            for (int i = 0; i < m_Links.Length; i++)
            {
                if (m_Links[i].GetLink(out s, out e))
                {
                    if (nLink == index)
                    {
                        start = s;
                        end   = e;
                        return(true);
                    }
                    nLink++;
                }
            }

            // Specified index is greater than the number of links we actually have.
            return(false);
        }
예제 #10
0
        void ExportPoint(PointFeature p)
        {
            IDirectPosition dp = new DirectPositionImpl(p.X, p.Y);
            IGeometry       g  = m_Factory.CreatePoint(dp);

            ExportGeometry(g);
        }
예제 #11
0
        /// <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)));
        }
예제 #12
0
 /// <summary>
 /// Creates a new <c>Circle</c> with the specified center and radius.
 /// </summary>
 /// <param name="center">The point at the center of the circle.</param>
 /// <param name="radius">The radius of the circle, in meters</param>
 internal Circle(PointFeature center, double radius)
 {
     m_Center  = center;
     m_Radius  = radius;
     m_Arcs    = new List <ArcFeature>();
     IsIndexed = false;
 }
예제 #13
0
        /// <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;
        }
예제 #14
0
        /// <summary>
        /// Creates a new <c>FindPointQuery</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="point">The position of interest</param>
        internal FindPointQuery(ISpatialIndex index, IPointGeometry p)
        {
            m_Point  = p;
            m_Result = null;
            IWindow w = new Window(p, p);

            index.QueryWindow(w, SpatialType.Point, OnQueryHit);
        }
예제 #15
0
파일: Node.cs 프로젝트: 15831944/backsight
        /// <summary>
        /// Associates this node with an additional feature
        /// </summary>
        /// <param name="p">The point making use of this node</param>
        /// <exception cref="ArgumentException">If the supplied point has a geometry that
        /// doesn't refer to this node</exception>
        internal void AttachPoint(PointFeature p)
        {
            if (!Object.ReferenceEquals(p.Geometry, this))
            {
                throw new ArgumentException();
            }

            m_Points.Add(p);
        }
예제 #16
0
        /// <summary>
        /// Defines the attributes of this content
        /// </summary>
        /// <param name="reader">The reading tool</param>
        /// <remarks>Implements IXmlContent</remarks>
        public override void ReadAttributes(XmlContentReader reader)
        {
            m_Point = new PointFeature();
            m_Point.ReadFeatureAttributes(reader);

            PointFeature p = reader.ReadFeatureByReference<PointFeature>("FirstPoint");
            m_Point.Node = p.Node;
            p.Node.AttachPoint(m_Point);
        }
예제 #17
0
        /// <summary>
        /// Creates any circle that's required for arcs that sit on this leg. This method must
        /// be called before making any calls to <see cref="CreateLine"/>.
        /// </summary>
        /// <param name="ff">The factory for creating new spatial features</param>
        /// <param name="itemName">The name for the item that represents the point at the center of the circle</param>
        /// <returns>The created circle (with an undefined radius)</returns>
        internal Circle CreateCircle(FeatureFactory ff, string itemName)
        {
            // Create a center point, and cross-reference to a new circle (with undefined radius)
            PointFeature center = ff.CreatePointFeature(itemName);

            m_Circle = new Circle(center, 0.0);
            m_Circle.AddReferences();
            return(m_Circle);
        }
예제 #18
0
        /// <summary>
        /// Defines the attributes of this content
        /// </summary>
        /// <param name="reader">The reading tool</param>
        /// <remarks>Implements IXmlContent</remarks>
        public override void ReadAttributes(XmlContentReader reader)
        {
            m_Point = new PointFeature();
            m_Point.ReadFeatureAttributes(reader);

            PointFeature p = reader.ReadFeatureByReference <PointFeature>("FirstPoint");

            m_Point.Node = p.Node;
            p.Node.AttachPoint(m_Point);
        }
예제 #19
0
        /// <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;
        }
예제 #20
0
        /// <summary>
        /// Creates a new <c>PathInfo</c> object
        /// </summary>
        /// <param name="from">The point where the path starts.</param>
        /// <param name="to">The point where the path ends.</param>
        internal PathInfo(PointFeature from, PointFeature to, Leg[] legs)
        {
            m_From = from;
            m_To   = to;
            m_Legs = legs;

            m_IsAdjusted  = false;
            m_Rotation    = 0.0;
            m_ScaleFactor = 0.0;
        }
예제 #21
0
        /// <summary>
        /// Creates a new <c>PathInfo</c> object
        /// </summary>
        /// <param name="from">The point where the path starts.</param>
        /// <param name="to">The point where the path ends.</param>
        internal PathInfo(PointFeature from, PointFeature to, Leg[] legs)
        {
            m_From = from;
            m_To = to;
            m_Legs = legs;

            m_IsAdjusted = false;
            m_Rotation = 0.0;
            m_ScaleFactor = 0.0;
        }
예제 #22
0
        /// <summary>
        /// Create a new <c>PathInfo</c> object that corresponds to a previously
        /// saved connection path. For consistency with the other constructor, this
        /// does not attempt to adjust the path (the Rotation and ScaleFactory properties
        /// will retain zero values unless a call is made to Adjust).
        /// </summary>
        /// <param name="pop">The saved connection path</param>
        internal PathInfo(PathOperation pop)
        {
            m_From = pop.StartPoint;
            m_To   = pop.EndPoint;
            m_Legs = pop.GetLegs();

            m_IsAdjusted  = false;
            m_Rotation    = 0.0;
            m_ScaleFactor = 0.0;
            m_Precision   = 0.0;
        }
예제 #23
0
        /// <summary>
        /// Delegate that's called whenever the index finds a point that's inside the query window
        /// </summary>
        /// <param name="item">The item to process (expected to be some sort of <c>PointFeature</c>)</param>
        /// <returns>True (always), indicating that the query should continue.</returns>
        private bool OnPointFound(ISpatialObject item)
        {
            PointFeature p = (PointFeature)item;

            if (m_ClosedShape.IsOverlap(p))
            {
                m_Points.Add(p);
            }

            return(true);
        }
예제 #24
0
        /// <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);
        }
예제 #25
0
        /// <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);
        }
예제 #26
0
        /// <summary>
        /// Attempts to find a location that can act as a terminal for a polygon boundary.
        /// This either refers to a user-perceived point feature, or an intersection
        /// point (as added via a prior call to <see cref="AddIntersection"/>).
        /// </summary>
        /// <param name="p">The position of interest</param>
        /// <remarks>The corresponding terminal (null if nothing found). This should either
        /// be an instance of <see cref="PointFeature"/> or <see cref="Intersection"/>.</remarks>
        internal ITerminal FindTerminal(IPointGeometry p)
        {
            // Search the base index for a real point feature
            PointFeature pf = (base.QueryClosest(p, Length.Zero, SpatialType.Point) as PointFeature);

            if (pf != null)
            {
                return(pf);
            }

            // Search for an intersection
            return(m_ExtraData.QueryClosest(p, Length.Zero, SpatialType.Point) as Intersection);
        }
예제 #27
0
        /// <summary>
        /// Creates a new <see cref="LineFeature"/> (with <see cref="SegmentGeometry"/>) using the feature
        /// stub with the specified name.
        /// </summary>
        /// <param name="itemName">The name for the item involved</param>
        /// <param name="from">The point at the start of the line (not null).</param>
        /// <param name="to">The point at the end of the line (not null).</param>
        /// <returns>The created feature (null if there is no feature stub)</returns>
        internal override LineFeature CreateSegmentLineFeature(string itemName, PointFeature from, PointFeature to)
        {
            IFeature f = FindFeatureDescription(itemName);

            if (f == null)
            {
                return(null);
            }
            else
            {
                return(new LineFeature(f, from, to));
            }
        }
예제 #28
0
        /// <summary>
        /// Creates a new <see cref="LineFeature"/> using the session sequence number
        /// that was previously recorded via a call to <see cref="AddFeatureDescription"/>.
        /// <para/>
        /// Only the session sequence number will be used when creating the section (any
        /// entity type and feature ID that may have been presented through <see cref="AddFeatureDescription"/>
        /// will be ignored - the values from the parent line will be applied instead).
        /// </summary>
        /// <param name="field">The name for the item involved (must refer to information
        /// previously attached via a call to <see cref="AddFeatureDescription"/>)</param>
        /// <param name="baseLine">The line that's being subdivided</param>
        /// <param name="from">The point at the start of the section (not null).</param>
        /// <param name="to">The point at the end of the section (not null).</param>
        /// <returns>The created feature (null if a feature description was not previously added)</returns>
        /// <exception cref="InvalidOperationException">If information for the item has not been
        /// attached to this factory.</exception>
        LineFeature MakeSection(DataField field, LineFeature baseLine, PointFeature from, PointFeature to)
        {
            IFeature f = FindFeatureDescription(field.ToString());

            if (f == null)
            {
                throw new InvalidOperationException();
            }

            SectionGeometry section = new SectionGeometry(baseLine, from, to);

            return(baseLine.MakeSubSection(m_Operation, f.InternalId, section));
        }
예제 #29
0
 /// <summary>
 /// Assigns initial values to everything
 /// </summary>
 void ResetContent()
 {
     m_Point        = null;
     m_Link         = null;
     m_SideNumber   = 0;
     m_Angle        = 0.0;
     m_Bearing      = 0.0;
     m_IsCurveEnd   = false;
     m_IsEnd        = false;
     m_IsRadial     = false;
     m_LinkAngle    = Constants.PIMUL2;
     m_NumIntersect = 0;
 }
예제 #30
0
        /// <summary>
        /// Delegate that's called whenever the index finds an object with an extent that
        /// overlaps the query window.
        /// </summary>
        /// <param name="item">The item to process (expected to be some sort of <c>PointFeature</c>)</param>
        /// <returns>True if the query should continue. False if a coincident point has been found.</returns>
        private bool OnQueryHit(ISpatialObject item)
        {
            Debug.Assert(item is PointFeature);

            PointFeature p = (PointFeature)item;

            if (p.Geometry.IsCoincident(m_Point))
            {
                m_Result = p;
                return(false);
            }

            return(true);
        }
예제 #31
0
 /// <summary>
 /// Returns any link information.
 /// </summary>
 /// <param name="from">The point where the link starts.</param>
 /// <param name="to">The point where the link ends.</param>
 /// <returns>True if a link has been returned. False if no link (in that case,
 /// the 2 return parameters come back as nulls).</returns>
 internal bool GetLink(out PointFeature from, out PointFeature to)
 {
     if (m_Link != null && !m_IsEnd)
     {
         from = m_Point;
         to   = m_Link.Point;
         return(true);
     }
     else
     {
         from = to = null;
         return(false);
     }
 }
예제 #32
0
        /// <summary>
        /// Splits a line into two sections, using the session sequence number
        /// that was previously recorded via a call to <see cref="AddFeatureDescription"/>.
        /// The original line will then be deactivated.
        /// <para/>
        /// Only the session sequence number will be used when creating the section (any
        /// entity type and feature ID that may have been presented through <see cref="AddFeatureDescription"/>
        /// will be ignored - the values from the parent line will be applied instead).
        /// </summary>
        /// <param name="baseLine">The line to split.</param>
        /// <param name="itemBefore">The name of the item for the section preceding the split.</param>
        /// <param name="x">The point that is common to the two sections</param>
        /// <param name="itemAfter">The name of the item for the section after the splot.</param>
        /// <param name="lineBefore">The created section prior to the split point (corresponding to <paramref name="itemBefore"/>)</param>
        /// <param name="lineAfter">The created section after the split point (corresponding to <paramref name="itemAfter"/>)</param>
        /// <exception cref="InvalidOperationException">If information for either item has not been
        /// attached to this factory.</exception>
        internal void MakeSections(LineFeature baseLine, DataField itemBefore, PointFeature x, DataField itemAfter,
                                   out LineFeature lineBefore, out LineFeature lineAfter)
        {
            lineBefore = lineAfter = null;

            // Split the line (the sections should get an undefined creation sequence). Note that
            // you cannot use the SplitLine method at this stage, because that requires defined
            // geometry.

            lineBefore = MakeSection(itemBefore, baseLine, baseLine.StartPoint, x);
            lineAfter  = MakeSection(itemAfter, baseLine, x, baseLine.EndPoint);

            Deactivate(baseLine);
        }
예제 #33
0
파일: Node.cs 프로젝트: 15831944/backsight
        /// <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);
        }
예제 #34
0
        /// <summary>
        /// Creates a new <see cref="ArcFeature"/> using information previously
        /// recorded via a call to <see cref="AddFeatureDescription"/>.
        /// </summary>
        /// <param name="itemName">The name for the item involved</param>
        /// <param name="from">The point at the start of the line (not null).</param>
        /// <param name="to">The point at the end of the line (not null).</param>
        /// <returns>The new feature (null if a feature description was not previously added)</returns>
        internal override ArcFeature CreateArcFeature(string itemName, PointFeature from, PointFeature to)
        {
            IFeature f = FindFeatureDescription(itemName);

            if (f == null)
            {
                return(null);
            }

            // Circle construction lines may not have an entity type
            bool isPolBoundary = (f.EntityType == null ? false : f.EntityType.IsPolygonBoundaryValid);

            return(new ArcFeature(f, from, to, null, isPolBoundary));
        }
예제 #35
0
        /// <summary>
        /// Delegate that's called whenever the index finds an object with an extent that
        /// overlaps the query window.
        /// </summary>
        /// <param name="item">The item to process (expected to be some sort of <c>PointFeature</c>)</param>
        /// <returns>True if the query should continue. False if a matching point has been found.</returns>
        private bool OnQueryHit(ISpatialObject item)
        {
            Debug.Assert(item is PointFeature);

            PointFeature p = (PointFeature)item;

            if (p.FormattedKey == m_Key)
            {
                m_Result = p;
                return(false);
            }

            return(true);
        }
예제 #36
0
        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);
        }
예제 #37
0
        /// <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>
        /// Creates a new <see cref="ArcFeature"/> using information previously
        /// recorded via a call to <see cref="AddFeatureDescription"/>.
        /// </summary>
        /// <param name="itemName">The name for the item involved</param>
        /// <param name="from">The point at the start of the line (not null).</param>
        /// <param name="to">The point at the end of the line (not null).</param>
        /// <returns>The new feature (null if a feature description was not previously added)</returns>
        internal override ArcFeature CreateArcFeature(string itemName, PointFeature from, PointFeature to)
        {
            IFeature f = FindFeatureDescription(itemName);

            if (f == null)
                return null;

            // Circle construction lines may not have an entity type
            bool isPolBoundary = (f.EntityType == null ? false : f.EntityType.IsPolygonBoundaryValid);
            return new ArcFeature(f, from, to, null, isPolBoundary);
        }
        /// <summary>
        /// Creates a new <see cref="LineFeature"/> (with <see cref="SegmentGeometry"/>) using the feature
        /// stub with the specified name.
        /// </summary>
        /// <param name="itemName">The name for the item involved</param>
        /// <param name="from">The point at the start of the line (not null).</param>
        /// <param name="to">The point at the end of the line (not null).</param>
        /// <returns>The created feature (null if there is no feature stub)</returns>
        internal override LineFeature CreateSegmentLineFeature(string itemName, PointFeature from, PointFeature to)
        {
            IFeature f = FindFeatureDescription(itemName);

            if (f == null)
                return null;
            else
                return new LineFeature(f, from, to);
        }
예제 #40
0
 internal abstract void Paint(PointFeature point);
예제 #41
0
        /// <summary>
        /// Delegate that's called whenever the index finds an object with an extent that
        /// overlaps the query window.
        /// </summary>
        /// <param name="item">The item to process (expected to be some sort of <c>PointFeature</c>)</param>
        /// <returns>True if the query should continue. False if a matching point has been found.</returns>
        private bool OnQueryHit(ISpatialObject item)
        {
            Debug.Assert(item is PointFeature);

            PointFeature p = (PointFeature)item;
            if (p.FormattedKey == m_Key)
            {
                m_Result = p;
                return false;
            }

            return true;
        }
예제 #42
0
 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;
 }
예제 #43
0
        private Circle EnsureCircleExists(PointFeature center, double radius, ILength tol, Operation creator)
        {
            // The index refers to the data loaded from the current NTX file. It holds only
            // information for points & circles, so we should only find circles at this stage.

            Position p = new Position(center.X, center.Y+radius);
            ISpatialObject so = m_Index.QueryClosest(p, tol, SpatialType.Line);
            if (so==null)
            {
                so = new Circle(center, radius);
                m_Index.Add(so);
            }

            Debug.Assert(so is Circle);
            return (Circle)so;
        }
예제 #44
0
        /// <summary>
        /// Creates spatial features (points and lines) for this face. The created
        /// features don't have any geometry.
        /// </summary>
        /// <param name="ff">The factory for creating new spatial features</param>
        /// <param name="startPoint">The point (if any) at the start of this leg. May be
        /// null in a situation where the preceding leg ended with an "omit point" directive.</param>
        /// <param name="lastPoint">The point that should be used for the very end
        /// of the leg (specify null if a point should be created at the end of the leg).</param>
        internal void CreateFeatures(FeatureFactory ff, PointFeature startPoint, PointFeature lastPoint)
        {
            PointFeature from = startPoint;
            PointFeature to = null;

            // The initial item sequence relates to the face itself. The first feature along the face will
            // have a sequence number one higher.
            uint maxSequence = this.Sequence.ItemSequence;

            int nSpan = m_Spans.Length;
            for (int i = 0; i < nSpan; i++, from = to)
            {
                SpanInfo span = GetSpanData(i);

                // If we have an end point, add it (so long as this span is not
                // at the very end of the connection path).

                to = null;
                maxSequence++;

                if (span.HasEndPoint)
                {
                    if (i == (nSpan - 1))
                        to = lastPoint;

                    if (to == null)
                        to = ff.CreatePointFeature(maxSequence.ToString());

                    Debug.Assert(to != null);
                }

                // A line can only exist if both end points are defined (the "omit point"
                // directive may well be used to finish a leg without a point, so the first
                // span in the next leg can't have a line).

                maxSequence++;
                if (span.HasLine && from != null)
                {
                    LineFeature line = this.Leg.CreateLine(ff, maxSequence.ToString(), from, to);
                    line.ObservedLength = span.ObservedDistance;

                    // Alternate faces should by non-topological. And mark as "void" so that it can be
                    // skipped on export to AutoCad.
                    if (FaceNumber == 2)
                    {
                        line.SetTopology(false); // should probably be false already
                        line.IsVoid = true;
                    }

                    span.CreatedFeature = line;
                }
                else
                {
                    span.CreatedFeature = to;
                }
            }
        }
예제 #45
0
        /// <summary>
        /// Creates a new <c>LineFeature</c>
        /// </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 defining the shape of the line (not null)</param>
        /// <note>To ensure that the start and end of all lines are instances of <see cref="PointFeature"/>,
        /// this constructor should always remain private.</note>
        protected LineFeature(Operation creator, InternalIdValue id, IEntity e, PointFeature start, PointFeature end, LineGeometry g)
            : base(creator, id, e, null)
        {
            if (g==null)
                throw new ArgumentNullException();

            m_From = start;
            m_To = end;
            m_Geom = g;
            m_Topology = null;
            AddReferences();

            // If the entity type denotes a topological boundary, initialize the topology.
            if (e.IsPolygonBoundaryValid)
                SetTopology(true);
        }
예제 #46
0
 /// <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)
 {
 }
예제 #47
0
        /// <summary>
        /// Reads data that was previously written using <see cref="WriteData"/>
        /// </summary>
        /// <param name="editDeserializer">The mechanism for reading back content.</param>
        /// <param name="from">The point at the start of the line</param>
        /// <param name="to">The point at the end of the line</param>
        /// <param name="isTopological">Does the line act as a polygon boundary </param>
        /// <param name="geom">The geometry for the line.</param>
        static void ReadData(EditDeserializer editDeserializer, out PointFeature from, out PointFeature to, out bool isTopological,
            out LineGeometry geom)
        {
            from = editDeserializer.ReadFeatureRef<PointFeature>(DataField.From);
            to = editDeserializer.ReadFeatureRef<PointFeature>(DataField.To);
            isTopological = editDeserializer.ReadBool(DataField.Topological);

            if (editDeserializer.IsNextField(DataField.Type))
            {
                geom = editDeserializer.ReadPersistent<LineGeometry>(DataField.Type);

                // Ensure terminals have been defined (since there was no easy way to pass them
                // through to the LineGeometry constructor).
                geom.StartTerminal = from;
                geom.EndTerminal = to;

                // If we're dealing with a circular arc, and the bc/ec points have defined
                // positions (e.g. coming from an import), we can calculate the radius now.
                // Otherwise we'll need to wait until geometry has been calculated.

                // The radius is defined here only because it's consistent with older code.
                // It may well be better to leave the definition of circle radius till later
                // (i.e. do all circles after geometry has been calculated).

                ArcGeometry arc = (geom as ArcGeometry);
                if (arc != null)
                {
                    Circle c = (Circle)arc.Circle;
                    PointFeature center = c.CenterPoint;

                    if (center.PointGeometry != null && from.PointGeometry != null)
                        c.Radius = Geom.Distance(center.PointGeometry, from.PointGeometry);
                }

            }
            else
            {
                geom = new SegmentGeometry(from, to);
            }
        }
예제 #48
0
 /// <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]));
 }
예제 #49
0
 /// <summary>
 /// Remembers a point that is about to be moved
 /// </summary>
 /// <param name="p">The point that is about to move</param>
 internal void AddMove(PointFeature p)
 {
     Move m = new Move(p);
     m_Moves.Add(m);
 }
예제 #50
0
 /// <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);
 }
예제 #51
0
        /// <summary>
        /// Ensures a point is visible on the active display (expands the draw window
        /// if necessary), and optionally selects it.
        /// </summary>
        /// <param name="p">The point that needs to be shown.</param>
        /// <param name="select">Specify true if the point should be selected.</param>
        internal void EnsureVisible(PointFeature p, bool select)
        {
            // Ensure the draw window shows the point.
            ISpatialDisplay display = ActiveDisplay;
            IWindow drawExtent = display.Extent;

            if (drawExtent==null || drawExtent.IsEmpty)
                display.DrawOverview();
            else if (!drawExtent.IsOverlap(p))
                display.Center = p;

            // Select the point if requested
            if (select)
                SetSelection(new Selection(p, p));
        }
예제 #52
0
 /// <summary>
 /// Initializes a new instance of the <see cref="LineFeature"/> class, and records it
 /// as part of the map model.
 /// </summary>
 /// <param name="f">Basic information about the feature (not null).</param>
 /// <param name="start">The point at the start of the line (not null).</param>
 /// <param name="end">The point at the end of the line (not null).</param>
 /// <exception cref="ArgumentNullException">If any parameter is null.</exception>
 internal LineFeature(IFeature f, PointFeature start, PointFeature end)
     : this(f, start, end, f.EntityType.IsPolygonBoundaryValid)
 {
 }
예제 #53
0
 /// <summary>
 /// Creates a new <c>FindPointByIdQuery</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="key">The ID of interest.</param>
 internal FindPointByIdQuery(ISpatialIndex index, string key)
 {
     m_Key = key;
     m_Result = null;
     index.QueryWindow(null, SpatialType.Point, OnQueryHit);
 }
예제 #54
0
 /// <summary>
 /// Initializes a new instance of the <see cref="LineFeature"/> class, and records it
 /// as part of the map model.
 /// </summary>
 /// <param name="f">Basic information about the feature (not null).</param>
 /// <param name="start">The point at the start of the line (not null).</param>
 /// <param name="end">The point at the end of the line (not null).</param>
 /// <param name="isTopological">Should the line be tagged as a polygon boundary?</param>
 /// <exception cref="ArgumentNullException">If any parameter is null.</exception>
 internal LineFeature(IFeature f, PointFeature start, PointFeature end, bool isTopological)
     : this(f, start, end, new SegmentGeometry(start, end), isTopological)
 {
 }
예제 #55
0
        /// <summary>
        /// Initializes a new instance of the <see cref="LineFeature"/> class, and records it
        /// as part of the map model.
        /// </summary>
        /// <param name="iid">The internal ID for the feature.</param>
        /// <param name="fid">The (optional) user-perceived ID for the feature. If not null,
        /// this will be modified by cross-referencing it to the newly created feature.</param>
        /// <param name="ent">The entity type for the feature (not null)</param>
        /// <param name="creator">The operation creating the feature (not null). Expected to
        /// refer to an editing session that is consistent with the session ID that is part
        /// of the feature's internal ID.</param>
        /// <param name="start">The point at the start of the line (not null)</param>
        /// <param name="end">The point at the end of the line (not null)</param>
        /// <param name="g">The geometry for the line (could be null, although this is only really
        /// expected during deserialization)</param>
        /// <param name="isTopological">Does the line form part of a polygon boundary?</param>
        /// <exception cref="ArgumentNullException">If either <paramref name="ent"/> or
        /// <paramref name="creator"/> or <paramref name="start"/> or <paramref name="end"/> is null.
        /// </exception>
        protected LineFeature(IFeature f, PointFeature start, PointFeature end, LineGeometry g, bool isTopological)
            : base(f)
        {
            if (start == null || end == null)
                throw new ArgumentNullException();

            m_From = start;
            m_To = end;
            m_Geom = g;
            m_Topology = null;

            // Don't cross-reference if we're dealing with a temporary feature
            if (!f.InternalId.IsEmpty)
                AddReferences();

            if (isTopological)
                SetTopology(true);
        }
예제 #56
0
        /// <summary>
        /// Delegate that's called whenever the index finds an object with an extent that
        /// overlaps the query window.
        /// </summary>
        /// <param name="item">The item to process (expected to be some sort of <c>PointFeature</c>)</param>
        /// <returns>True if the query should continue. False if a coincident point has been found.</returns>
        private bool OnQueryHit(ISpatialObject item)
        {
            Debug.Assert(item is PointFeature);

            PointFeature p = (PointFeature)item;
            if (p.Geometry.IsCoincident(m_Point))
            {
                m_Result = p;
                return false;
            }

            return true;
        }
예제 #57
0
        /// <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);
        }
예제 #58
0
 /// <summary>
 /// Creates a <c>LineFeature</c> consisting of a simple line segment.
 /// </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>
 internal LineFeature(Operation creator, InternalIdValue id, IEntity e, PointFeature start, PointFeature end)
     : this(creator, id, e, start, end, new SegmentGeometry(start, end))
 {
 }
예제 #59
0
 void ExportPoint(PointFeature p)
 {
     IDirectPosition dp = new DirectPositionImpl(p.X, p.Y);
     IGeometry g = m_Factory.CreatePoint(dp);
     ExportGeometry(g);
 }
예제 #60
0
        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;
        }