public void CanFormatRowWithFieldNameContainedInOtherField() { // TOP-5056: Field PLZ_ZZ and PLZ are both present in the feature class: const string name = "TESTCLASS"; const string aliasName = "Test FeatureClass"; var featureClassMock = new FeatureClassMock( 1, name, aliasName, esriGeometryType.esriGeometryPolyline); featureClassMock.AddField("NAME", esriFieldType.esriFieldTypeString); featureClassMock.AddField("PLZ", esriFieldType.esriFieldTypeInteger); featureClassMock.AddField("PLZ_ZZ", esriFieldType.esriFieldTypeInteger); IFeature feature = featureClassMock.CreateFeature(); var plz = 5023; var zz = 2; feature.Value[feature.Fields.FindField("PLZ")] = plz; feature.Value[feature.Fields.FindField("PLZ_ZZ")] = zz; Assert.AreEqual($"{plz}_{zz}", RowFormat.Format(@"{PLZ}_{PLZ_ZZ}", feature)); }
public void CanFormatRow() { const string name = "TESTCLASS"; const string aliasName = "Test FeatureClass"; var featureClassMock = new FeatureClassMock( 1, name, aliasName, esriGeometryType.esriGeometryPolyline); featureClassMock.AddField("NAME", esriFieldType.esriFieldTypeString); featureClassMock.AddField("PLZ", esriFieldType.esriFieldTypeInteger); IFeature feature = featureClassMock.CreateFeature(); Assert.AreEqual($"{feature.OID}", RowFormat.Format(feature)); Assert.AreEqual($"{aliasName} - {feature.OID}", RowFormat.Format(feature, true)); var plz = 5023; feature.Value[feature.Fields.FindField("PLZ")] = plz; Assert.AreEqual($": {plz}", RowFormat.Format(@"{NAME}: {PLZ}", feature)); Assert.AreEqual($"<null>: {plz}", RowFormat.Format(@"{NAME}: {PLZ}", feature, "<null>")); }
public static IEnumerable <IGeometry> GetSelectableOverlaps( [NotNull] IFeature sourceFeature, [NotNull] SpatialHashSearcher <IFeature> overlappingFeatures, [CanBeNull] NotificationCollection notifications = null, [CanBeNull] ITrackCancel trackCancel = null) { IGeometry sourceGeometry = sourceFeature.Shape; if (sourceGeometry == null || sourceGeometry.IsEmpty) { yield break; } IEnvelope sourceEnvelope = sourceGeometry.Envelope; double tolerance = GeometryUtils.GetXyTolerance(sourceGeometry); foreach (IFeature targetFeature in overlappingFeatures.Search( sourceEnvelope.XMin, sourceEnvelope.YMin, sourceEnvelope.XMax, sourceEnvelope.YMax, tolerance)) { if (trackCancel != null && !trackCancel.Continue()) { yield break; } _msg.VerboseDebugFormat("Calculating overlap from {0}", GdbObjectUtils.ToString(targetFeature)); IGeometry targetGeometry = targetFeature.Shape; if (GeometryUtils.Disjoint(targetGeometry, sourceGeometry)) { continue; } if (GeometryUtils.Contains(targetGeometry, sourceGeometry)) { // Idea for the future: Optionally allow also deleting features (probably using a black display feedback) NotificationUtils.Add(notifications, "Source feature {0} is completely within target {1} and would become empty if the overlap was removed. The overlap is supressed.", RowFormat.Format(sourceFeature), RowFormat.Format(targetFeature)); continue; } if (sourceGeometry.GeometryType == esriGeometryType.esriGeometryMultiPatch) { sourceGeometry = GeometryFactory.CreatePolygon(sourceGeometry); } IGeometry intersection = TryGetIntersection(sourceGeometry, targetGeometry); if (intersection == null) { continue; } if (GeometryUtils.GetPartCount(intersection) > 1) { foreach (var part in GeometryUtils.Explode(intersection)) { yield return(part); } } else { yield return(intersection); } } }
/// <summary> /// Gets points weeded at the specified tolerance and under consideration of shared vertices if required. /// </summary> /// <param name="forFeatureVertexInfos"></param> /// <param name="weedTolerance"></param> /// <param name="only2D"></param> /// <param name="inPerimeter"></param> /// <param name="trackCancel"></param> /// <returns></returns> public static void CalculateWeedPoints( [NotNull] IEnumerable <FeatureVertexInfo> forFeatureVertexInfos, double weedTolerance, bool only2D, [CanBeNull] IGeometry inPerimeter, [CanBeNull] ITrackCancel trackCancel) { foreach (FeatureVertexInfo featureVertexInfo in forFeatureVertexInfos) { if (trackCancel != null && !trackCancel.Continue()) { return; } IFeature feature = featureVertexInfo.Feature; _msg.DebugFormat("Calculating weed points for {0}", GdbObjectUtils.ToString(feature)); try { // intersect on perimeter and cut into separate paths at protected points IPolycurve originalGeometry = GetOriginalGeometry(feature, featureVertexInfo); IPointCollection weededPoints; try { weededPoints = CrackUtils.GetWeedPoints( originalGeometry, weedTolerance, only2D, inPerimeter); } catch (Exception e) { _msg.Debug("Generalisation error.", e); _msg.WarnFormat("Cannot generalize {0}: {1}", RowFormat.Format(feature), e.Message); continue; } // NOTE: At least in advanced generalize consider only showing those crack points that // actually protect an existing vertex (i.e. only those on an existing vertex) // -> could be done in RemovableSegments // In theory it would also be nice to see the points that would be weeded if they were not protected // however this means double the processing and the result is not always consistent because // if an otherwise protected point is weeded some other point would probably remain (problem // of different start point). // It might be helpful if only those crack points would be shown that are // actual vertices but again in case of un-selected neighbour it nicely shows the cut points // of the weeding and makes the weed points more plausible in certain cases. // -> consider making the symbol slightly bigger for real-vertex crack points (or square) // this is good for protecting shared vertices between selected and unselected features // for guaranteed identical generalization of shared edges between selected features // build topology graph! // NOTE: in theory this is only necessary if the input is not cut into separate paths at all protected points // -> consider only cutting at intersection points between sources (shared line end points) // NOTE: sometimes the intersection is rather inaccurate -> this still reduces points! featureVertexInfo.NonDeletablePoints = RemoveProtectedPoints(weededPoints, featureVertexInfo); featureVertexInfo.PointsToDelete = weededPoints; } catch (Exception) { _msg.ErrorFormat("Error calculating generalized points for {0}", GdbObjectUtils.ToString(feature)); throw; } } }
public void AddCrackPoints([NotNull] IFeature targetFeature, [NotNull] CrackPointCalculator crackPointCalculator) { // TODO: consider moving this to CrackUtils Stopwatch watch = _msg.DebugStartTiming("Calculating intersection points between {0} and {1}", GdbObjectUtils.ToString(Feature), GdbObjectUtils.ToString(targetFeature)); IPointCollection intersectionPoints = null; try { IGeometry targetGeometry = targetFeature.ShapeCopy; IGeometry originalGeometry = Feature.Shape; IPolyline clippedSource = OriginalClippedPolyline; GeometryUtils.EnsureSpatialReference(targetGeometry, clippedSource.SpatialReference); crackPointCalculator.SetDataResolution(Feature); IGeometry intersectionTarget; intersectionPoints = crackPointCalculator.GetIntersectionPoints( clippedSource, targetGeometry, out intersectionTarget); // TODO: if the target has a vertex closish (wrt tolerance) to the actual intersection point // the intersection point is somewhere in between. Consider snapping intersection points // to target vertices (this might be the start of clustering!) or use minimal tolerance! AddIntersectionPoints(intersectionPoints); IList <CrackPoint> crackPoints = crackPointCalculator.DetermineCrackPoints( intersectionPoints, originalGeometry, clippedSource, intersectionTarget); // TODO: rename to AddNonCrackablePoints / sort out whether drawing can happen straight from List<CrackPoint> AddCrackPoints(crackPoints); if (intersectionTarget != null && intersectionTarget != targetGeometry) { Marshal.ReleaseComObject(intersectionTarget); } Marshal.ReleaseComObject(targetGeometry); } catch (Exception e) { string message = $"Error calculationg crack points with target feature {RowFormat.Format(targetFeature)}: {e.Message}"; _msg.Debug(message, e); if (crackPointCalculator.ContinueOnException) { crackPointCalculator.FailedOperations.Add(Feature.OID, message); } else { throw; } } _msg.DebugStopTiming(watch, "Calculated and processed {0} intersection points", intersectionPoints?.PointCount); }