public static int ReportDuplicates(
            [NotNull] IRow row1, int tableIndex1,
            [NotNull] IRow row2, int tableIndex2,
            [NotNull] IErrorReporting errorReporting,
            [CanBeNull] IssueCode issueCode,
            [CanBeNull] IValidRelationConstraint validRelationConstraint)
        {
            Assert.ArgumentNotNull(row1, nameof(row1));
            Assert.ArgumentNotNull(row2, nameof(row2));
            Assert.ArgumentNotNull(errorReporting, nameof(errorReporting));

            string errorDescription;

            if (!AreDuplicates(row1, tableIndex1,
                               row2, tableIndex2,
                               validRelationConstraint,
                               out errorDescription))
            {
                return(_noError);
            }

            IGeometry errorGeometry = ((IFeature)row1).ShapeCopy;

            const bool reportIndividualParts = false;

            return(errorReporting.Report(errorDescription,
                                         errorGeometry, issueCode,
                                         reportIndividualParts,
                                         row1, row2));
        }
        public static int ReportIntersections(
            [NotNull] IRow row1, int tableIndex1,
            [NotNull] IRow row2, int tableIndex2,
            [NotNull] IErrorReporting errorReporting,
            [CanBeNull] IssueCode issueCode,
            [CanBeNull] IValidRelationConstraint validRelationConstraint,
            bool reportIndividualParts,
            [CanBeNull] GeometryConstraint validIntersectionGeometryConstraint = null,
            GeometryComponent geomComponent1 = GeometryComponent.EntireGeometry,
            GeometryComponent geomComponent2 = GeometryComponent.EntireGeometry)
        {
            Assert.ArgumentNotNull(row1, nameof(row1));
            Assert.ArgumentNotNull(row2, nameof(row2));
            Assert.ArgumentNotNull(errorReporting, nameof(errorReporting));

            if (row1 == row2)
            {
                return(_noError);
            }

            string errorDescription;

            if (HasFulfilledConstraint(row1, tableIndex1,
                                       row2, tableIndex2,
                                       validRelationConstraint, "Features intersect",
                                       out errorDescription))
            {
                return(_noError);
            }

            IGeometry shape1 = ((IFeature)row1).Shape;
            IGeometry shape2 = ((IFeature)row2).Shape;

            var g1 = GeometryComponentUtils.GetGeometryComponent(shape1, geomComponent1);
            var g2 = GeometryComponentUtils.GetGeometryComponent(shape2, geomComponent2);

            var errorCount = 0;

            if (g1 != null && g2 != null)
            {
                foreach (IGeometry errorGeometry in
                         IntersectionUtils.GetAllIntersections(g1, g2))
                {
                    if (validIntersectionGeometryConstraint == null ||
                        !validIntersectionGeometryConstraint.IsFulfilled(errorGeometry))
                    {
                        errorCount += errorReporting.Report(errorDescription,
                                                            errorGeometry,
                                                            issueCode, reportIndividualParts,
                                                            row1, row2);
                    }
                }
            }

            return(errorCount);
        }
        public static int ReportOverlaps(
            [NotNull] IRow row1, int tableIndex1,
            [NotNull] IRow row2, int tableIndex2,
            [NotNull] IErrorReporting errorReporting,
            [CanBeNull] IssueCode issueCode,
            [CanBeNull] IValidRelationConstraint validRelationConstraint,
            bool reportIndividualParts)
        {
            Assert.ArgumentNotNull(row1, nameof(row1));
            Assert.ArgumentNotNull(row2, nameof(row2));
            Assert.ArgumentNotNull(errorReporting, nameof(errorReporting));
            if (row1 == row2)
            {
                return(_noError);
            }

            IGeometry g1 = ((IFeature)row1).Shape;
            IGeometry g2 = ((IFeature)row2).Shape;

            string errorDescription;

            if (HasFulfilledConstraint(row1, tableIndex1,
                                       row2, tableIndex2,
                                       validRelationConstraint, "Features overlap",
                                       out errorDescription))
            {
                return(_noError);
            }

            IGeometry intersection = TestUtils.GetOverlap(g1, g2);

            if (intersection.IsEmpty)
            {
                Marshal.ReleaseComObject(intersection);
                return(_noError);
            }

            return(errorReporting.Report(errorDescription,
                                         intersection, issueCode,
                                         reportIndividualParts,
                                         row1, row2));
        }
        public int ReportErrors([NotNull] IFeature feature1, int tableIndex1,
                                [NotNull] IFeature feature2, int tableIndex2,
                                [NotNull] IErrorReporting reportError,
                                [CanBeNull] IssueCode issueCode,
                                bool reportIndividualErrors)
        {
            Assert.ArgumentNotNull(feature1, nameof(feature1));
            Assert.ArgumentNotNull(feature2, nameof(feature2));
            Assert.ArgumentNotNull(reportError, nameof(reportError));

            if (feature1 == feature2)
            {
                return(0);
            }

            string conditionMessage;

            if (IsFulfilled(feature1, tableIndex1,
                            feature2, tableIndex2,
                            out conditionMessage))
            {
                // currently: no error, even if intersection geometry constraint would be violated
                // (parameter for constraint combination operation could be added)
                return(0);
            }

            // geometries of multiple dimensions possible
            var errorCount = 0;

            foreach (IGeometry geometry in GetIntersections(feature1, feature2))
            {
                foreach (IGeometry reportableGeometry in GetGeometries(geometry,
                                                                       reportIndividualErrors))
                {
                    if (_validIntersectionDimensions != null &&
                        _validIntersectionDimensions.Contains(reportableGeometry.Dimension))
                    {
                        continue;
                    }

                    if (_intersectionGeometryConstraint != null)
                    {
                        if (_intersectionGeometryConstraint.IsFulfilled(reportableGeometry))
                        {
                            continue;
                        }

                        string displayValues =
                            _intersectionGeometryConstraint.FormatValues(reportableGeometry,
                                                                         CultureInfo.CurrentCulture)
                            .Replace("$", string.Empty);
                        string rawValues =
                            _intersectionGeometryConstraint.FormatValues(reportableGeometry,
                                                                         CultureInfo
                                                                         .InvariantCulture);

                        // format for display to the user (current culture)
                        string description = GetErrorDescription(
                            conditionMessage,
                            _intersectionGeometryConstraint.Constraint.Replace("$", string.Empty),
                            displayValues);

                        errorCount += reportError.Report(description, reportableGeometry,
                                                         issueCode, null,
                                                         new object[] { rawValues },
                                                         feature1, feature2);
                    }
                    else
                    {
                        string description = GetErrorDescription(conditionMessage);

                        errorCount += reportError.Report(description, reportableGeometry,
                                                         issueCode, null,
                                                         feature1, feature2);
                    }
                }
            }

            return(errorCount);
        }
        public static int ReportCrossings(
            [NotNull] IRow row1, int tableIndex1,
            [NotNull] IRow row2, int tableIndex2,
            [NotNull] IErrorReporting errorReporting,
            [CanBeNull] IssueCode issueCode,
            [CanBeNull] IValidRelationConstraint validRelationConstraint,
            bool reportIndividualParts)
        {
            Assert.ArgumentNotNull(row1, nameof(row1));
            Assert.ArgumentNotNull(row2, nameof(row2));
            Assert.ArgumentNotNull(errorReporting, nameof(errorReporting));

            if (row1 == row2)
            {
                return(_noError);
            }

            IGeometry g1 = ((IFeature)row1).Shape;
            IGeometry g2 = ((IFeature)row2).Shape;

            string errorDescription;

            if (HasFulfilledConstraint(row1, tableIndex1,
                                       row2, tableIndex2,
                                       validRelationConstraint, "Features cross",
                                       out errorDescription))
            {
                return(_noError);
            }

            var errorCount = 0;

            foreach (IGeometry errorGeometry in GetCrossings(g1, g2))
            {
                if (errorGeometry.IsEmpty)
                {
                    continue;
                }

                errorCount += errorReporting.Report(errorDescription,
                                                    errorGeometry, issueCode,
                                                    reportIndividualParts,
                                                    row1, row2);
            }

            return(errorCount);

            //const bool overlap = false;
            //IGeometry intersection = TestUtils.GetIntersection(g1, g2, overlap);

            //// TODO remove boundary

            //try
            //{
            //    if (intersection.IsEmpty)
            //    {
            //        return _noError;
            //    }

            //    return errorReporting.Report("Features cross",
            //                                 intersection, reportIndividualParts,
            //                                 row1, row2);
            //}
            //finally
            //{
            //    Marshal.ReleaseComObject(intersection);
            //}
        }
        public static int ReportTouches(
            [NotNull] IRow row1, int tableIndex1,
            [NotNull] IRow row2, int tableIndex2,
            [NotNull] IErrorReporting errorReporting,
            [CanBeNull] IssueCode issueCode,
            [CanBeNull] IValidRelationConstraint validRelationConstraint,
            [CanBeNull] GeometryConstraint validTouchGeometryConstraint,
            bool reportIndividualParts = false)
        {
            Assert.ArgumentNotNull(row1, nameof(row1));
            Assert.ArgumentNotNull(row2, nameof(row2));
            Assert.ArgumentNotNull(errorReporting, nameof(errorReporting));

            if (row1 == row2)
            {
                return(_noError);
            }

            IGeometry g1 = ((IFeature)row1).Shape;
            IGeometry g2 = ((IFeature)row2).Shape;

            string errorDescription;

            if (HasFulfilledConstraint(row1, tableIndex1,
                                       row2, tableIndex2,
                                       validRelationConstraint, "Geometries touch",
                                       out errorDescription))
            {
                return(_noError);
            }

            var errorCount = 0;

            foreach (IGeometry geometry in GetTouches(g1, g2))
            {
                if (geometry.IsEmpty)
                {
                    continue;
                }

                if (reportIndividualParts)
                {
                    foreach (IGeometry part in GeometryUtils.Explode(geometry))
                    {
                        if (part.IsEmpty ||
                            validTouchGeometryConstraint != null &&
                            validTouchGeometryConstraint.IsFulfilled(part))
                        {
                            continue;
                        }

                        errorCount += errorReporting.Report(errorDescription,
                                                            part, issueCode,
                                                            false,                         // already exploded
                                                            row1, row2);
                    }
                }
                else
                {
                    if (validTouchGeometryConstraint != null &&
                        validTouchGeometryConstraint.IsFulfilled(geometry))
                    {
                        continue;
                    }

                    errorCount += errorReporting.Report(errorDescription,
                                                        geometry, issueCode,
                                                        false,
                                                        row1, row2);
                }
            }

            return(errorCount);
        }