List<RelatedCurve> GetParallelCurveMatchFeatures(IFeatureClass FeatureClass, IFeature inFeature, IPolycurve inPolycurve, string WhereClause) //double AngleToleranceTangentCompareInDegrees, double OrthogonalSearchDistance, // out int outFoundLinesCount, out int outFoundParallelCurvesCount, ref List<RelatedCurve> CurveInfoFromNeighbours) { List<RelatedCurve> CurveInfoFromNeighbours = new List<RelatedCurve>(); ILine inGeomChord = (ILine)new Line(); inGeomChord.PutCoords(inPolycurve.FromPoint, inPolycurve.ToPoint); IVector3D inGeomVector = (IVector3D)new Vector3D(); inGeomVector.PolarSet(inGeomChord.Angle, 0, 1); //generate line segments that are perpendicular to the in feature at half way IGeometryBag queryGeomBag = (IGeometryBag)new GeometryBag(); IGeometryCollection queryGeomPartCollection = (IGeometryCollection)queryGeomBag; IGeometry queryMultiPartPolyLine = (IGeometry)new Polyline(); //qi IGeoDataset pGeoDS = (IGeoDataset)FeatureClass; ISpatialReference spatialRef = pGeoDS.SpatialReference; queryMultiPartPolyLine.SpatialReference = spatialRef; IGeometryCollection queryGeomCollection = queryMultiPartPolyLine as IGeometryCollection; ILine pNormalLine = (ILine)new Line(); //new for (int i = -1; i < 2; i = i + 2) { double dOffset = CurveByInferenceSettings.Instance.OrthogonalSearchDistance * i; inPolycurve.QueryNormal(esriSegmentExtension.esriNoExtension, 0.5, true, dOffset, pNormalLine); ILine pThisLine = (ILine)new Line(); pThisLine.PutCoords(pNormalLine.FromPoint, pNormalLine.ToPoint); queryGeomPartCollection.AddGeometry(pThisLine); //Although each line is connected to the other, create a new path for each line //this allows for future changes in case the input needs to be altered to separate paths. ISegmentCollection newPath = (ISegmentCollection)new Path(); object obj = Type.Missing; newPath.AddSegment((ISegment)pThisLine, ref obj, ref obj); //The spatial reference associated with geometryCollection will be assigned to all incoming paths and segments. queryGeomCollection.AddGeometry(newPath as IGeometry, ref obj, ref obj); } //search for records that intersect these perpendicular geometries IQueryFilter filter = new SpatialFilter(); filter.SubFields = String.Format("{0}, {1}, {2}, {3}", FeatureClass.OIDFieldName, CurveByInferenceSettings.Instance.RadiusFieldName, CurveByInferenceSettings.Instance.CenterpointIDFieldName, FeatureClass.ShapeFieldName); ISpatialFilter spatialFilter = (ISpatialFilter)filter; //Can't add any additional filtering on centerpointid and radius field because the straight lines are needed spatialFilter.WhereClause = WhereClause; spatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects; spatialFilter.SearchOrder = esriSearchOrder.esriSearchOrderSpatial; spatialFilter.Geometry = queryGeomBag; IFeatureCursor pFeatCursLines = null; try { pFeatCursLines = FeatureClass.Search(spatialFilter, false); } catch (Exception ex) { messageBox.Show(ex.Message); return CurveInfoFromNeighbours; } int idxCenterPointID = pFeatCursLines.Fields.FindField(CurveByInferenceSettings.Instance.CenterpointIDFieldName); int idxRadius = pFeatCursLines.Fields.FindField(CurveByInferenceSettings.Instance.RadiusFieldName); IPoint midpoint = new Point(); inPolycurve.QueryPoint(esriSegmentExtension.esriNoExtension, 0.5, true, midpoint); double lengthFiler = inPolycurve.Length * 3; double closestStraighLine = Double.MaxValue; IFeature pFeat = null; while ((pFeat = pFeatCursLines.NextFeature()) != null) { if (inFeature.OID == pFeat.OID) continue; IGeometry pFoundLineGeom = pFeat.ShapeCopy; IPolyline pFoundPolyline = pFoundLineGeom as IPolyline; ITopologicalOperator6 pTopoOp6 = (ITopologicalOperator6)queryMultiPartPolyLine; IGeometry intersectionPoint = pTopoOp6.IntersectEx(pFoundLineGeom, false, esriGeometryDimension.esriGeometry0Dimension); if (intersectionPoint == null || intersectionPoint.IsEmpty) { // there isn't actually an intersection between the features Marshal.ReleaseComObject(pFeat); continue; } //distance from intersection of tangent line and found feature to the start point of the tangent line double distanceToLine = ((IProximityOperator)intersectionPoint).ReturnDistance(midpoint); //if the feature has no radius attribute, skip. double dRadius = pFeat.get_Value(idxRadius) is DBNull ? 0 : (double)pFeat.get_Value(idxRadius); int? centerpointID = pFeat.get_Value(idxCenterPointID) is DBNull ? null : (int?)pFeat.get_Value(idxCenterPointID); if (dRadius == 0 || centerpointID == null) {//null centrpointID so skip. if (closestStraighLine > distanceToLine && pFoundPolyline.Length > lengthFiler) { closestStraighLine = distanceToLine; CurveInfoFromNeighbours.RemoveAll(w=>w.DistanceToLine > closestStraighLine); } Marshal.ReleaseComObject(pFeat); continue; } //out past a straight line if (closestStraighLine < distanceToLine) continue; ISegmentCollection pFoundLineGeomSegs = pFoundLineGeom as ISegmentCollection; bool bHasCurves = false; pFoundLineGeomSegs.HasNonLinearSegments(ref bHasCurves); if (!bHasCurves) { Marshal.ReleaseComObject(pFeat); continue; } IPointCollection5 PtColl = (IPointCollection5)intersectionPoint; if (PtColl.PointCount > 1) { // the intersection isn't a point Marshal.ReleaseComObject(pFeat); continue; } IPolycurve pPolyCurve4Tangent = pFoundLineGeom as IPolycurve; for (int j = 0; j < PtColl.PointCount; j++) { IPoint p = PtColl.get_Point(j); IPoint outPoint = (IPoint)new Point(); double dDistanceAlong = 0; double dDistanceFromCurve = 0; bool bOffsetRight = true; //work out if the point is to the left or right of the original inPolycurve.QueryPointAndDistance(esriSegmentExtension.esriNoExtension, p, false, outPoint, ref dDistanceAlong, ref dDistanceFromCurve, ref bOffsetRight); ILine pTangent = (ILine)new Line(); dDistanceAlong = 0; dDistanceFromCurve = 0; bool bOnRight = true; pPolyCurve4Tangent.QueryPointAndDistance(esriSegmentExtension.esriNoExtension, p, false, outPoint, ref dDistanceAlong, ref dDistanceFromCurve, ref bOnRight); pPolyCurve4Tangent.QueryTangent(esriSegmentExtension.esriNoExtension, dDistanceAlong, false, 100, pTangent); //compare the tangent bearing with the normal to check for orthogonality IVector3D vecTangent = (IVector3D)new Vector3D(); vecTangent.PolarSet(pTangent.Angle, 0, 1); IVector3D vecNormal = (IVector3D)new Vector3D(); vecNormal.PolarSet(pNormalLine.Angle, 0, 1); ILine pHitDistanceForRadiusDifference = (ILine)new Line(); pHitDistanceForRadiusDifference.PutCoords(pNormalLine.FromPoint, outPoint); double dRadiusDiff = pHitDistanceForRadiusDifference.Length; double dDotProd = vecTangent.DotProduct(vecNormal); double dAngleCheck = Math.Acos(dDotProd) * 180 / Math.PI; //in degrees dAngleCheck = Math.Abs(dAngleCheck - 90); if (dAngleCheck < CurveByInferenceSettings.Instance.AngleToleranceTangentCompareInDegrees) { //work out concavity orientation with respect to the original line using the radius sign and dot product dDotProd = inGeomVector.DotProduct(vecTangent); double dTangentCheck = Math.Acos(dDotProd) * 180 / Math.PI; // in degrees //dTangentCheck at this point should be close to 0 or 180 degrees. bool bIsConvex = ((dTangentCheck < 90 && dRadius < 0 && !bOffsetRight) || (dTangentCheck > 90 && dRadius > 0 && !bOffsetRight) || (dTangentCheck < 90 && dRadius > 0 && bOffsetRight) || (dTangentCheck > 90 && dRadius < 0 && bOffsetRight)); double dUnitSignChange = 1; if (!bIsConvex) dUnitSignChange = -1; double dDerivedRadius = (Math.Abs(dRadius)) + dRadiusDiff * dUnitSignChange; dUnitSignChange = 1; //now compute inferred left/right for candidate if (bIsConvex && !bOffsetRight) dUnitSignChange = -1; if (!bIsConvex && bOffsetRight) dUnitSignChange = -1; dDerivedRadius = dDerivedRadius * dUnitSignChange; //string sHarvestedCurveInfo = pFeat.OID.ToString() + "," + dDerivedRadius.ToString("#.000") + "," + centerpointID.ToString() + "," + dRadiusDiff.ToString("#.000"); CurveInfoFromNeighbours.Add(new RelatedCurve(pFeat.OID, dDerivedRadius, centerpointID.Value, distanceToLine, RelativeOrientation.Parallel)); } } Marshal.ReleaseComObject(pFeat); } Marshal.FinalReleaseComObject(pFeatCursLines); return CurveInfoFromNeighbours; }
public bool HasParallelCurveMatchFeatures(IFeatureClass FeatureClass, IPolycurve inPolycurve, string WhereClause, double AngleToleranceTangentCompareInDegrees, double OrthogonalSearchDistance, out int outFoundLinesCount, out int outFoundParallelCurvesCount, ref List<string> CurveInfoFromNeighbours) { outFoundLinesCount = 0; outFoundParallelCurvesCount = 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 pNormalLine = new Line(); //new for (int i = -1; i < 2; i = i + 2) { double dOffset = OrthogonalSearchDistance * i; inPolycurve.QueryNormal(esriSegmentExtension.esriNoExtension, 0.5, true, dOffset, pNormalLine); ILine pThisLine = new Line(); pThisLine.PutCoords(pNormalLine.FromPoint, pNormalLine.ToPoint); pGeomColl.AddGeometry(pThisLine); //Although each line is connected to the other, create a new path for each line //this allows for future changes in case the input needs to be altered to separate paths. ISegmentCollection newPath = new PathClass(); object obj = Type.Missing; newPath.AddSegment((ISegment)pThisLine, ref obj, ref obj); //The spatial reference associated with geometryCollection will be assigned to all incoming paths and segments. geometryCollection2.AddGeometry(newPath as IGeometry, ref obj, ref obj); } ISpatialFilter pSpatFilt = new SpatialFilter(); pSpatFilt.WhereClause = WhereClause; pSpatFilt.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects; pSpatFilt.SearchOrder = esriSearchOrder.esriSearchOrderSpatial; pSpatFilt.Geometry = pGeomBag; IFeatureCursor pFeatCursLines = null; try { pFeatCursLines = FeatureClass.Search(pSpatFilt, false); } catch (Exception ex) { MessageBox.Show(ex.Message); return false; } IFeature pFeat = pFeatCursLines.NextFeature(); while (pFeat != null) { IGeometry pFoundLineGeom = pFeat.ShapeCopy; //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; if (dRadius == 0) {//null or zero radius so skip. Marshal.ReleaseComObject(pFeat); pFeat = pFeatCursLines.NextFeature(); continue; } val = pFeat.get_Value(idxCenterPointID); if (val == DBNull.Value) {//null centrpointID so skip. Marshal.ReleaseComObject(pFeat); pFeat = pFeatCursLines.NextFeature(); continue; } iCtrPoint = (int)val; ITopologicalOperator6 pTopoOp6 = (ITopologicalOperator6)MultiPartPolyLine; IGeometry pResultGeom = pTopoOp6.IntersectEx(pFoundLineGeom, false, esriGeometryDimension.esriGeometry0Dimension); if (pResultGeom == null) { Marshal.ReleaseComObject(pFeat); pFeat = pFeatCursLines.NextFeature(); continue; } if (pResultGeom.IsEmpty) { Marshal.ReleaseComObject(pFeat); pFeat = pFeatCursLines.NextFeature(); continue; } ISegmentCollection pFoundLineGeomSegs = pFoundLineGeom as ISegmentCollection; bool bHasCurves = false; pFoundLineGeomSegs.HasNonLinearSegments(ref bHasCurves); if (!bHasCurves) { Marshal.ReleaseComObject(pFeat); pFeat = pFeatCursLines.NextFeature(); continue; } IPointCollection5 PtColl = (IPointCollection5)pResultGeom; if (PtColl.PointCount > 1) { Marshal.ReleaseComObject(pFeat); pFeat = pFeatCursLines.NextFeature(); continue; } IPolycurve pPolyCurve4Tangent = pFoundLineGeom as IPolycurve; for (int j = 0; j < PtColl.PointCount; j++) { IPoint p = PtColl.get_Point(j); IPoint outPoint = new Point(); double dDistanceAlong = 0; double dDistanceFromCurve = 0; bool bOffsetRight = true; //work out if the point is to the left or right of the original inPolycurve.QueryPointAndDistance(esriSegmentExtension.esriNoExtension, p, false, outPoint, ref dDistanceAlong, ref dDistanceFromCurve, ref bOffsetRight); ILine pTangent = new Line(); dDistanceAlong = 0; dDistanceFromCurve = 0; bool bOnRight = true; pPolyCurve4Tangent.QueryPointAndDistance(esriSegmentExtension.esriNoExtension, p, false, outPoint, ref dDistanceAlong, ref dDistanceFromCurve, ref bOnRight); pPolyCurve4Tangent.QueryTangent(esriSegmentExtension.esriNoExtension, dDistanceAlong, false, 100, pTangent); //compare the tangent bearing with the normal to check for orthogonality IVector3D vecTangent = new Vector3DClass(); vecTangent.PolarSet(pTangent.Angle, 0, 1); IVector3D vecNormal = new Vector3DClass(); vecNormal.PolarSet(pNormalLine.Angle, 0, 1); ILine pHitDistanceForRadiusDifference = new Line(); pHitDistanceForRadiusDifference.PutCoords(pNormalLine.FromPoint, outPoint); double dRadiusDiff = pHitDistanceForRadiusDifference.Length; double dDotProd = vecTangent.DotProduct(vecNormal); double dAngleCheck = Math.Acos(dDotProd) * 180 / Math.PI; //in degrees dAngleCheck = Math.Abs(dAngleCheck - 90); if (dAngleCheck < AngleToleranceTangentCompareInDegrees) { //work out concavity orientation with respect to the original line using the radius sign and dot product dDotProd = vecOriginalSelected.DotProduct(vecTangent); double dTangentCheck = Math.Acos(dDotProd) * 180 / Math.PI; // in degrees //dTangentCheck at this point should be close to 0 or 180 degrees. outFoundLinesCount++; bool bIsConvex = ((dTangentCheck < 90 && dRadius < 0 && !bOffsetRight) || (dTangentCheck > 90 && dRadius > 0 && !bOffsetRight) || (dTangentCheck < 90 && dRadius > 0 && bOffsetRight) || (dTangentCheck > 90 && dRadius < 0 && bOffsetRight)); double dUnitSignChange = 1; if (!bIsConvex) dUnitSignChange = -1; double dDerivedRadius = (Math.Abs(dRadius)) + dRadiusDiff * dUnitSignChange; dUnitSignChange = 1; //now compute inferred left/right for candidate if (bIsConvex && !bOffsetRight) dUnitSignChange = -1; if (!bIsConvex && bOffsetRight) dUnitSignChange = -1; dDerivedRadius = dDerivedRadius * dUnitSignChange; string sHarvestedCurveInfo = pFeat.OID.ToString() + "," + dDerivedRadius.ToString("#.000") + "," + iCtrPoint.ToString() + "," + dRadiusDiff.ToString("#.000"); CurveInfoFromNeighbours.Add(sHarvestedCurveInfo); } } Marshal.ReleaseComObject(pFeat); pFeat = pFeatCursLines.NextFeature(); } Marshal.FinalReleaseComObject(pFeatCursLines); bool bHasParallelCurveFeaturesNearby = (outFoundLinesCount > 0); return bHasParallelCurveFeaturesNearby; }