public List<RelatedCurve> GetTangentCurveMatchFeatures(IFeatureClass FeatureClass, IFeature inFeature, IPolycurve inPolycurve, string WhereClause,
                                                int idxRadius, int idxCenterPointID,
                                                double SegementLength, out List<RelatedLine> tangentLines)
            //double AngleToleranceTangentCompareInDegrees, double StraightLinesBreakLessThanInDegrees, 
            //double MaximumDeltaInDegrees, double ExcludeTangentsShorterThan,
            //                                     out int outFoundTangentCurvesCount, ref List<RelatedCurve> CurveInfoFromNeighbours)
        {
            List<RelatedCurve> CurveInfoFromNeighbours = new List<RelatedCurve>();
            tangentLines = new List<RelatedLine>();

            ILine pOriginalChord = (ILine)new Line();
            pOriginalChord.PutCoords(inPolycurve.FromPoint, inPolycurve.ToPoint);
            IVector3D vecOriginalSelected = (IVector3D)new Vector3D();
            vecOriginalSelected.PolarSet(pOriginalChord.Angle, 0, 1);

            IGeometryBag pGeomBag = (IGeometryBag)new GeometryBag();
            IGeometryCollection pGeomColl = (IGeometryCollection)pGeomBag;

            IGeometry MultiPartPolyLine = (IGeometry)new Polyline(); //qi
            IGeoDataset pGeoDS = (IGeoDataset)FeatureClass;
            ISpatialReference spatialRef = pGeoDS.SpatialReference;
            MultiPartPolyLine.SpatialReference = spatialRef;

            IGeometryCollection geometryCollection2 = MultiPartPolyLine as IGeometryCollection;

            ILine inGeomTangentLineAtEnd = new Line(); //new
            ILine inGeomTangentLineAtStart = new Line(); //new
            object objMissing = Type.Missing;

            for (int i = 0; i < 2; i++)
            {
                ILine pThisLine = null;
                if (i == 0)
                {
                    //Add line tangent at end point
                    inPolycurve.QueryTangent(esriSegmentExtension.esriExtendAtTo, 1.0, true, CurveByInferenceSettings.Instance.TangentQueryLength, inGeomTangentLineAtEnd);
                    pThisLine = new Line();
                    pThisLine.PutCoords(inGeomTangentLineAtEnd.FromPoint, inGeomTangentLineAtEnd.ToPoint);
                    pGeomColl.AddGeometry(pThisLine);
                }
                else
                {
                    //Add line tangent at start point
                    inPolycurve.QueryTangent(esriSegmentExtension.esriExtendAtFrom, 0.0, true, CurveByInferenceSettings.Instance.TangentQueryLength, inGeomTangentLineAtStart);
                    pThisLine = new Line();
                    pThisLine.PutCoords(inGeomTangentLineAtStart.FromPoint, inGeomTangentLineAtStart.ToPoint);
                    pGeomColl.AddGeometry(pThisLine);
                }
                //Create a new path for each line.

                ISegmentCollection newPath = (ISegmentCollection)new Path();
                newPath.AddSegment((ISegment)pThisLine, ref objMissing, ref objMissing);
                //The spatial reference associated with geometryCollection will be assigned to all incoming paths and segments.
                geometryCollection2.AddGeometry(newPath as IGeometry, ref objMissing, ref objMissing);
            }

            //now buffer the tangent lines
            IGeometryCollection outBufferedGeometryCol = (IGeometryCollection)new GeometryBag();
            for (int jj = 0; jj < geometryCollection2.GeometryCount; jj++)
            {
                IPath pPath = geometryCollection2.get_Geometry(jj) as IPath;
                IGeometryCollection pPolyL = (IGeometryCollection)new Polyline();
                pPolyL.AddGeometry((IGeometry)pPath);

                ITopologicalOperator topologicalOperator = (ITopologicalOperator)pPolyL;
                IPolygon pBuffer = topologicalOperator.Buffer(CurveByInferenceSettings.Instance.TangentQueryBuffer) as IPolygon;
                outBufferedGeometryCol.AddGeometry(pBuffer, ref objMissing, ref objMissing);
            }
            ITopologicalOperator pUnionedBuffers = null;
            pUnionedBuffers = new Polygon() as ITopologicalOperator;
            pUnionedBuffers.ConstructUnion((IEnumGeometry)outBufferedGeometryCol);

            ISpatialFilter pSpatFilt = new SpatialFilter();
            pSpatFilt.WhereClause = WhereClause;
            pSpatFilt.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;
            pSpatFilt.SearchOrder = esriSearchOrder.esriSearchOrderSpatial;

            pSpatFilt.Geometry = (IGeometry)pUnionedBuffers;

            IFeatureCursor pFeatCursLines = null;
            try
            {
                pFeatCursLines = FeatureClass.Search(pSpatFilt, false);
            }
            catch (Exception ex)
            {
                messageBox.Show(ex.Message);
                return CurveInfoFromNeighbours;
            }
            IVector3D foundGeomVector = (IVector3D)new Vector3D();
            IFeature foundFeature = null;
            bool bHasTangentStraightLineAtJunction = false;

            //A list of relative orientation values that have large breaks
            List<RelativeOrientation> lstLargeBreak = new List<RelativeOrientation>();

            while ((foundFeature = pFeatCursLines.NextFeature()) != null)
            {
                if (inFeature.OID == foundFeature.OID)
                {
                    Marshal.ReleaseComObject(foundFeature);
                    continue;
                }

                IGeometry foundLineGeom = foundFeature.ShapeCopy;
                IPolyline foundPolyLine = foundLineGeom as IPolyline4;
                IPolycurve foundPolyCurve = foundLineGeom as IPolycurve;
                RelativeOrientation iRelativeOrientation = GetRelativeOrientation(foundPolyCurve, inPolycurve);
                //iRelativeOrientation == 1 --> closest points are original TO and found TO
                //iRelativeOrientation == 2 --> closest points are original TO and found FROM
                //iRelativeOrientation == 3 --> closest points are original FROM and found TO
                //iRelativeOrientation == 4 --> closest points are original FROM and found FROM

                double foundRadius = (foundFeature.get_Value(idxRadius) is DBNull) ? 0 : (double)foundFeature.get_Value(idxRadius);
                int? foundCentriodID = (foundFeature.get_Value(idxCenterPointID) is DBNull) ? null : (int?)foundFeature.get_Value(idxCenterPointID);

                //if the found feature has the same start and endpoints, assume that the feature is the same.  If that feature has radius and centerpoint information
                //assume that feature is unchanged and update the current feature with the found feature.
                if (iRelativeOrientation == RelativeOrientation.Same || iRelativeOrientation == RelativeOrientation.Reverse)
                {
                    if (foundRadius > 0 && foundCentriodID.HasValue)
                    {
                        //Curved line
                        double adjustedRadius = iRelativeOrientation == RelativeOrientation.Same ? foundRadius : -1 * foundRadius;

                        CurveInfoFromNeighbours.Clear();
                        CurveInfoFromNeighbours.Add(new RelatedCurve(foundFeature.OID, adjustedRadius, foundCentriodID.Value, iRelativeOrientation));
                        Marshal.ReleaseComObject(foundFeature);
                        Marshal.FinalReleaseComObject(pFeatCursLines);
                        return CurveInfoFromNeighbours;
                    }
                    else if (foundPolyLine.Length > inPolycurve.Length * CurveByInferenceSettings.Instance.TangentOverlapScaleFactor)
                    {
                        //straight line
                        CurveInfoFromNeighbours.Clear();

                        Marshal.ReleaseComObject(foundFeature);
                        Marshal.FinalReleaseComObject(pFeatCursLines);
                        return CurveInfoFromNeighbours;

                    }
                    Marshal.ReleaseComObject(foundFeature);
                    continue;
                }

                /******************************
                 * 
                 *   Compare chord of the in geometry vs the found geometry
                 * 
                 * ****************************/


                ILine foundChord = new Line();
                foundChord.PutCoords(foundPolyCurve.FromPoint, foundPolyCurve.ToPoint);

                //Not sure about this, but it looks like this may be sensitive to the order in which the records are returned

                //first check for likelihood that subject line is supposed to stay straight, by geometry chord bearing angle break test
                //compare the in geometries chord with the found geometries chord
                foundGeomVector.PolarSet(foundChord.Angle, 0, 1);
                double chordsAngleDelta = Math.Abs(Math.Acos(foundGeomVector.DotProduct(vecOriginalSelected)) * 180 / Math.PI); //in degrees

                //large angle break non-tangent, greater than 3 degrees
                if (chordsAngleDelta > CurveByInferenceSettings.Instance.dLargeAngleBreakInDegrees && chordsAngleDelta < (180 - CurveByInferenceSettings.Instance.dLargeAngleBreakInDegrees))
                {
                    if (!lstLargeBreak.Contains(iRelativeOrientation))
                    {
                        lstLargeBreak.Add(iRelativeOrientation);

                        //check to see if there is already a related curve for the current relative orientation
                        //if(CurveInfoFromNeighbours.Any(w=>w.Orientation == iRelativeOrientation))
                        //{
                        //    bHasTangentStraightLineAtJunction = true;
                        //}
                    }

                }

                double ExcludeTangentsShorterThan = SegementLength * CurveByInferenceSettings.Instance.ExcludeTangentsShorterThanScaler;
                
                /*
                if(foundPolyCurve.Length < ExcludeTangentsShorterThan)
                {
                    //exclude short segements
                    Marshal.ReleaseComObject(foundFeature);
                    continue;
                }
                else if (!foundCentriodID.HasValue && foundRadius == 0)
                {
                    //attribute straight line, check the geometry to see if it is tangent at the endpoint
                    if (chordsAngleDelta <= CurveByInferenceSettings.Instance.StraightLinesBreakLessThanInDegrees || (180 - chordsAngleDelta) < CurveByInferenceSettings.Instance.StraightLinesBreakLessThanInDegrees)
                    {
                        if (lstLargeBreak.Contains(iRelativeOrientation))
                            bHasTangentStraightLineAtJunction = true;
                    }
                }
                else if (foundCentriodID.HasValue && foundRadius != 0)
                {
                    //attribute curved line
                    if ((inPolycurve.Length / foundRadius * 180 / Math.PI) > CurveByInferenceSettings.Instance.MaximumDeltaInDegrees)
                    {
                        //if the resulting curve ('in feature' length with 'found feature' radius) would have a central angle more than MaximumDeltaInDegrees degrees then skip
                        Marshal.ReleaseComObject(foundFeature);
                        continue;
                    }
                }
                else
                {
                    //invalid state, curves should have both centriod and radius, straigh lines should have niether.
                    Marshal.ReleaseComObject(foundFeature);
                    throw new Exception(string.Format("Invalid attribute state")); 
                }
                 */

                if ((chordsAngleDelta <= CurveByInferenceSettings.Instance.StraightLinesBreakLessThanInDegrees || (180 - chordsAngleDelta) < CurveByInferenceSettings.Instance.StraightLinesBreakLessThanInDegrees)
                    && !foundCentriodID.HasValue && foundRadius == 0 && !(foundPolyCurve.Length < ExcludeTangentsShorterThan))
                {
                    if (lstLargeBreak.Contains(iRelativeOrientation))
                        bHasTangentStraightLineAtJunction = true;
                }

                if (!foundCentriodID.HasValue || foundRadius == 0 || foundPolyCurve.Length < ExcludeTangentsShorterThan)
                {
                    //staight line
                    if (foundPolyCurve.Length > ExcludeTangentsShorterThan)
                    {
                        //vecOriginalSelected

                        //ISegmentCollection collection = (ISegmentCollection)polyline;
                        //ISegment segement = collection.get_Segment(collection.SegmentCount - 1);
                        ILine line = new Line();

                        double Angle = 0.0;
                        switch (iRelativeOrientation)
                        {
                            case RelativeOrientation.To_From:
                                foundPolyLine.QueryTangent(esriSegmentExtension.esriExtendAtFrom, 0.0, true, 1.0, line);
                                Angle = line.Angle;
                                break;
                            case RelativeOrientation.From_From:
                                foundPolyLine.QueryTangent(esriSegmentExtension.esriExtendAtFrom, 0.0, true, 1.0, line);
                                Angle = (line.Angle > 0) ? line.Angle - Math.PI : line.Angle + Math.PI;
                                break;
                            case RelativeOrientation.To_To:
                                foundPolyLine.QueryTangent(esriSegmentExtension.esriExtendAtTo, 1.0, true, 1.0, line);
                                Angle = (line.Angle > 0) ? line.Angle - Math.PI : line.Angle + Math.PI;
                                break;
                            case RelativeOrientation.From_To:
                                foundPolyLine.QueryTangent(esriSegmentExtension.esriExtendAtTo, 1.0, true, 1.0, line);
                                Angle = line.Angle;
                                break;
                        }

                        IVector3D foundVector = new Vector3D() as IVector3D;
                        foundVector.PolarSet(Angle, 0, 1);
                        double dVectDiff = Math.Acos(vecOriginalSelected.DotProduct(foundVector));

                        //Console.WriteLine("Add Straight Line: {0}, {1} -> {2}", foundFeature.OID, line.Angle, ((ILine)segement).Angle);
                        tangentLines.Add(new RelatedLine(foundFeature.OID, toDegrees(Angle), toDegrees(dVectDiff), iRelativeOrientation));
                    }
                    //if the feature has a null centrpointID then skip.
                    Marshal.ReleaseComObject(foundFeature);
                    continue;
                }

                if (Math.Abs(inPolycurve.Length / foundRadius * 180 / Math.PI) > CurveByInferenceSettings.Instance.MaximumDeltaInDegrees)
                {
                    //if the resulting curve ('in feature' length with 'found feature' radius) would have a central angle more than MaximumDeltaInDegrees degrees then skip
                    Marshal.ReleaseComObject(foundFeature);
                    continue;
                }

                /******************************
                 * 
                 *   Compare two lines, one from each in geometry and found geometry taken at the closes ends of the lines
                 *   Ie, compare the slopes of the two lines where they touch (or at least where they closest).
                 * 
                 * ****************************/

                //if geometry of curve neighbor curves have been cracked then there can be more than one segment
                //however since all segments would be circular arcs, just need to test the first segment
                ISegmentCollection pFoundLineGeomSegs = foundLineGeom as ISegmentCollection;
                ISegment pSeg = pFoundLineGeomSegs.get_Segment(0);
                if (!(pSeg is ICircularArc))
                {
                    Marshal.ReleaseComObject(foundFeature);
                    continue;
                }

                IVector3D vect1 = (IVector3D)new Vector3D();
                IVector3D vect2 = (IVector3D)new Vector3D();
                ILine tang = new Line();
                double dUnitSignChange = 1;
                if (iRelativeOrientation == RelativeOrientation.To_To) //closest points are original TO and found TO
                {
                    dUnitSignChange = -1;
                    vect1.PolarSet(inGeomTangentLineAtEnd.Angle, 0, 1);
                    foundPolyCurve.QueryTangent(esriSegmentExtension.esriExtendAtTo, 1.0, true, 1, tang);
                    vect2.PolarSet(tang.Angle, 0, 1);
                }
                else if (iRelativeOrientation == RelativeOrientation.To_From)//closest points are original TO and found FROM
                {
                    vect1.PolarSet(inGeomTangentLineAtEnd.Angle, 0, 1);
                    foundPolyCurve.QueryTangent(esriSegmentExtension.esriExtendAtFrom, 0.0, true, 1, tang);
                    vect2.PolarSet(tang.Angle, 0, 1);
                }
                else if (iRelativeOrientation == RelativeOrientation.From_To)//closest points are original FROM and found TO
                {
                    vect1.PolarSet(inGeomTangentLineAtStart.Angle, 0, 1);
                    foundPolyCurve.QueryTangent(esriSegmentExtension.esriExtendAtTo, 1.0, true, 1, tang);
                    vect2.PolarSet(tang.Angle, 0, 1);
                }
                else if (iRelativeOrientation == RelativeOrientation.From_From)//closest points are original FROM and found FROM
                {
                    dUnitSignChange = -1;
                    vect1.PolarSet(inGeomTangentLineAtStart.Angle, 0, 1);
                    foundPolyCurve.QueryTangent(esriSegmentExtension.esriExtendAtFrom, 0.0, true, 1, tang);
                    vect2.PolarSet(tang.Angle, 0, 1);
                }

                double tangentAngleDelta = Math.Abs(Math.Acos(vect1.DotProduct(vect2)) * 180 / Math.PI); //in degrees
                if (tangentAngleDelta < CurveByInferenceSettings.Instance.AngleToleranceTangentCompareInDegrees || (180 - tangentAngleDelta) < CurveByInferenceSettings.Instance.AngleToleranceTangentCompareInDegrees)
                {

                    double inferredRadius = foundRadius * dUnitSignChange;
                    CurveInfoFromNeighbours.Add(new RelatedCurve(foundFeature.OID, inferredRadius, foundCentriodID.Value, iRelativeOrientation));
                }
                Marshal.ReleaseComObject(foundFeature);
            }
            Marshal.FinalReleaseComObject(pFeatCursLines);

            if (bHasTangentStraightLineAtJunction)
                CurveInfoFromNeighbours.Clear(); //open to logic change to be less conservative

            //Original source didn't clear the list before, returing all the found records by reference.
            //calling procedure didn't do anything with those features though, only consumed the features if true was returned

            return CurveInfoFromNeighbours;
        }
Ejemplo n.º 2
0
        public bool HasTangentCurveMatchFeatures(IFeatureClass FeatureClass, IPolycurve inPolycurve, string WhereClause,
  double AngleToleranceTangentCompareInDegrees, double StraightLinesBreakLessThanInDegrees, double MaximumDeltaInDegrees, double ExcludeTangentsShorterThan, 
      out int outFoundTangentCurvesCount, ref List<string> CurveInfoFromNeighbours)
        {
            outFoundTangentCurvesCount = 0;

              ILine pOriginalChord = new Line();
              pOriginalChord.PutCoords(inPolycurve.FromPoint, inPolycurve.ToPoint);
              IVector3D vecOriginalSelected = new Vector3DClass();
              vecOriginalSelected.PolarSet(pOriginalChord.Angle, 0, 1);

              int idxRadius = FeatureClass.FindField("RADIUS");
              if (idxRadius == -1)
            return false;

              int idxCenterPointID = FeatureClass.FindField("CENTERPOINTID");
              if (idxCenterPointID == -1)
            return false;

              object val = null;

              IGeometryBag pGeomBag = new GeometryBagClass();
              IGeometryCollection pGeomColl = (IGeometryCollection)pGeomBag;

              IGeometry MultiPartPolyLine = new PolylineClass(); //qi
              IGeoDataset pGeoDS = (IGeoDataset)FeatureClass;
              ISpatialReference spatialRef = pGeoDS.SpatialReference;
              MultiPartPolyLine.SpatialReference = spatialRef;

              IGeometryCollection geometryCollection2 = MultiPartPolyLine as IGeometryCollection;

              ILine pTangentLineAtEnd = new Line(); //new
              ILine pTangentLineAtStart = new Line(); //new
              object objMissing = Type.Missing;

              for (int i = 0; i < 2; i++)
              {
            ILine pThisLine = null;
            if (i == 0)
            {
              inPolycurve.QueryTangent(esriSegmentExtension.esriExtendAtTo, 1.0, true, 0.2, pTangentLineAtEnd);
              pThisLine = new Line();
              pThisLine.PutCoords(pTangentLineAtEnd.FromPoint, pTangentLineAtEnd.ToPoint);
              pGeomColl.AddGeometry(pThisLine);
            }
            else
            {
              inPolycurve.QueryTangent(esriSegmentExtension.esriExtendAtFrom, 0.0, true, 0.2, pTangentLineAtStart);
              pThisLine = new Line();
              pThisLine.PutCoords(pTangentLineAtStart.FromPoint, pTangentLineAtStart.ToPoint);
              pGeomColl.AddGeometry(pThisLine);
            }
            //Create a new path for each line.

            ISegmentCollection newPath = new PathClass();
            newPath.AddSegment((ISegment)pThisLine, ref objMissing, ref objMissing);
            //The spatial reference associated with geometryCollection will be assigned to all incoming paths and segments.
            geometryCollection2.AddGeometry(newPath as IGeometry, ref objMissing, ref objMissing);
              }

              //now buffer the lines
              IGeometryCollection outBufferedGeometryCol = new GeometryBagClass();
              for (int jj = 0; jj < geometryCollection2.GeometryCount; jj++)
              {
            IPath pPath = geometryCollection2.get_Geometry(jj) as IPath;
            IGeometryCollection pPolyL = new PolylineClass();
            pPolyL.AddGeometry((IGeometry)pPath);

            ITopologicalOperator topologicalOperator = (ITopologicalOperator)pPolyL;
            IPolygon pBuffer = topologicalOperator.Buffer(0.1) as IPolygon;
            outBufferedGeometryCol.AddGeometry(pBuffer, ref objMissing, ref objMissing);
              }
              ITopologicalOperator pUnionedBuffers = null;
              pUnionedBuffers = new PolygonClass() as ITopologicalOperator;
              pUnionedBuffers.ConstructUnion((IEnumGeometry)outBufferedGeometryCol);

              ISpatialFilter pSpatFilt = new SpatialFilter();
              pSpatFilt.WhereClause = WhereClause;
              pSpatFilt.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;
              pSpatFilt.SearchOrder = esriSearchOrder.esriSearchOrderSpatial;

              pSpatFilt.Geometry = (IGeometry)pUnionedBuffers;

              IFeatureCursor pFeatCursLines = null;
              try
              {
            pFeatCursLines = FeatureClass.Search(pSpatFilt, false);
              }
              catch (Exception ex)
              {
            MessageBox.Show(ex.Message);
            return false;
              }
              IVector3D vecFoundGeom = new Vector3DClass();
              IFeature pFeat = pFeatCursLines.NextFeature();
              bool bHasTangentStraightLineAtJunction = false;
              List<int> lstLargeBreak = new List<int>();

              while (pFeat != null)
              {
            IGeometry pFoundLineGeom = pFeat.ShapeCopy;
            IPolycurve pFoundLineAsPolyCurve = pFoundLineGeom as IPolycurve;
            int iRelativeOrientation = GetRelativeOrientation(pFoundLineAsPolyCurve, inPolycurve);
            //iRelativeOrientation == 1 --> closest points are original TO and found TO
            //iRelativeOrientation == 2 --> closest points are original TO and found FROM
            //iRelativeOrientation == 3 --> closest points are original FROM and found TO
            //iRelativeOrientation == 4 --> closest points are original FROM and found FROM

            //if the feature has no radius attribute, skip.
            double dRadius = 0;
            int iCtrPoint = -1;
            val = pFeat.get_Value(idxRadius);
            if (val == DBNull.Value)
              dRadius = 0;
            else
              dRadius = (double)val;

            val = pFeat.get_Value(idxCenterPointID);

            IPolycurve pPolyCurve = pFoundLineGeom as IPolycurve;

            ILine pFoundChordCandidate = new LineClass();
            pFoundChordCandidate.PutCoords(pPolyCurve.FromPoint, pPolyCurve.ToPoint);
            //first check for liklihood that subject line is supposed to stay straight, by
            //geometry chord bearing angle break test
            vecFoundGeom.PolarSet(pFoundChordCandidate.Angle, 0, 1);
            double dDotProd = vecFoundGeom.DotProduct(vecOriginalSelected);
            double dAngleCheck = Math.Acos(dDotProd) * 180 / Math.PI; //in degrees
            dAngleCheck = Math.Abs(dAngleCheck);
            double dLargeAngleBreakInDegrees = 3;
            if (dAngleCheck > dLargeAngleBreakInDegrees && dAngleCheck < (180 - dLargeAngleBreakInDegrees)) //large angle break non-tangent, greater than 3 degrees
            {
              if (!lstLargeBreak.Contains(iRelativeOrientation))
            lstLargeBreak.Add(iRelativeOrientation);
            }

            if ((dAngleCheck <= StraightLinesBreakLessThanInDegrees || (180 - dAngleCheck) < StraightLinesBreakLessThanInDegrees)
            && val == DBNull.Value && dRadius == 0 && !(pPolyCurve.Length< ExcludeTangentsShorterThan))
            {
              if (lstLargeBreak.Contains(iRelativeOrientation))
            bHasTangentStraightLineAtJunction = true;
            }

            if (val == DBNull.Value || dRadius == 0 || pPolyCurve.Length< ExcludeTangentsShorterThan)
            {//if the feature has a null centrpointID then skip.
              Marshal.ReleaseComObject(pFeat);
              pFeat = pFeatCursLines.NextFeature();
              continue;
            }

            if (Math.Abs(inPolycurve.Length / dRadius * 180 / Math.PI) > MaximumDeltaInDegrees)
            {
              //if the resulting curve would have a central angle more than MaximumDeltaInDegrees degrees then skip
              Marshal.ReleaseComObject(pFeat);
              pFeat = pFeatCursLines.NextFeature();
              continue;
            }

            iCtrPoint = (int)val;

            //if geometry of curve neighbour curves have been cracked then there can be more than one segment
            //however since all segments would be circular arcs, just need to test the first segment
            ISegmentCollection pFoundLineGeomSegs = pFoundLineGeom as ISegmentCollection;
            ISegment pSeg = pFoundLineGeomSegs.get_Segment(0);
            if (!(pSeg is ICircularArc))
            {
              Marshal.ReleaseComObject(pFeat);
              pFeat = pFeatCursLines.NextFeature();
              continue;
            }

            dRadius = (double)pFeat.get_Value(idxRadius);

            IVector3D vect1 = new Vector3DClass();
            IVector3D vect2 = new Vector3DClass();
            ILine tang = new Line();
            double dUnitSignChange = 1;
            if (iRelativeOrientation == 1) //closest points are original TO and found TO
            {
              dUnitSignChange = -1;
              vect1.PolarSet(pTangentLineAtEnd.Angle, 0, 1);
              pFoundLineAsPolyCurve.QueryTangent(esriSegmentExtension.esriExtendAtTo, 1.0, true, 1, tang);
              vect2.PolarSet(tang.Angle, 0, 1);
            }
            else if (iRelativeOrientation == 2)//closest points are original TO and found FROM
            {
              vect1.PolarSet(pTangentLineAtEnd.Angle, 0, 1);
              pFoundLineAsPolyCurve.QueryTangent(esriSegmentExtension.esriExtendAtFrom, 0.0, true, 1, tang);
              vect2.PolarSet(tang.Angle, 0, 1);
            }
            else if (iRelativeOrientation == 3)//closest points are original FROM and found TO
            {
              vect1.PolarSet(pTangentLineAtStart.Angle, 0, 1);
              pFoundLineAsPolyCurve.QueryTangent(esriSegmentExtension.esriExtendAtTo, 1.0, true, 1, tang);
              vect2.PolarSet(tang.Angle, 0, 1);
            }
            else if (iRelativeOrientation == 4)//closest points are original FROM and found FROM
            {
              dUnitSignChange = -1;
              vect1.PolarSet(pTangentLineAtStart.Angle, 0, 1);
              pFoundLineAsPolyCurve.QueryTangent(esriSegmentExtension.esriExtendAtFrom, 0.0, true, 1, tang);
              vect2.PolarSet(tang.Angle, 0, 1);
            }

            dDotProd = vect1.DotProduct(vect2);
            dAngleCheck = Math.Acos(dDotProd) * 180 / Math.PI; //in degrees
            dAngleCheck = Math.Abs(dAngleCheck);
            if (dAngleCheck < AngleToleranceTangentCompareInDegrees || (180 - dAngleCheck) < AngleToleranceTangentCompareInDegrees)
            {

              double dDerivedRadius = dRadius * dUnitSignChange;

              string sHarvestedCurveInfo = pFeat.OID.ToString() + "," + dDerivedRadius.ToString("#.000") + "," +
            iCtrPoint.ToString() + "," + "t";
              CurveInfoFromNeighbours.Add(sHarvestedCurveInfo);

              outFoundTangentCurvesCount++;
            }

            Marshal.ReleaseComObject(pFeat);
            pFeat = pFeatCursLines.NextFeature();
              }
              Marshal.FinalReleaseComObject(pFeatCursLines);

              if (bHasTangentStraightLineAtJunction)
            return false; //open to logic change to be less conservative

              bool bHasParallelCurveFeaturesNearby = (outFoundTangentCurvesCount > 0);

              return bHasParallelCurveFeaturesNearby;
        }