private int CheckConstraint([NotNull] ZRangeFeature minFeature,
                                    [NotNull] ZRangeFeature maxFeature,
                                    [NotNull] IntersectionGeometryProvider geometryProvider,
                                    double zDifference)
        {
            string conditionMessage;
            bool   fulFilled = IsZRelationConditionFulfilled(
                maxFeature.Feature, maxFeature.TableIndex,
                minFeature.Feature, minFeature.TableIndex,
                zDifference,
                out conditionMessage);

            if (fulFilled)
            {
                return(NoError);
            }

            IGeometry errorGeometry = geometryProvider.Geometry;

            return(ErrorReporting.Report(conditionMessage, errorGeometry,
                                         Codes[Code.ConstraintNotFulfilled], null,
                                         maxFeature.Feature,
                                         minFeature.Feature));
        }
        protected override int ReportErrors(IFeature feature1, int tableIndex1,
                                            IFeature feature2, int tableIndex2)
        {
            var zRangeFeature1 =
                new ZRangeFeature(feature1, tableIndex1, _envelopeTemplate);
            var zRangeFeature2 =
                new ZRangeFeature(feature2, tableIndex2, _envelopeTemplate);

            var errorCount            = 0;
            int errorCountPreZNotNull = errorCount;

            errorCount += ValidateZNotNull(zRangeFeature1);
            errorCount += ValidateZNotNull(zRangeFeature2);

            if (errorCount != errorCountPreZNotNull)
            {
                // one or both Z values are NaN
                return(errorCount);
            }

            ZRangeFeature minFeature;
            ZRangeFeature maxFeature;

            if (zRangeFeature1.ZMin <= zRangeFeature2.ZMin)
            {
                minFeature = zRangeFeature1;
                maxFeature = zRangeFeature2;
            }
            else
            {
                minFeature = zRangeFeature2;
                maxFeature = zRangeFeature1;
            }

            double minimumZDifference =
                GetMinimumZDifference(minFeature.Feature, minFeature.TableIndex,
                                      maxFeature.Feature, maxFeature.TableIndex);
            double maximumZDifference =
                GetMaximumZDifference(minFeature.Feature, minFeature.TableIndex,
                                      maxFeature.Feature, maxFeature.TableIndex);

            double dz = maxFeature.ZMin - minFeature.ZMax;

            var geometryProvider =
                new IntersectionGeometryProvider(minFeature, maxFeature);

            if (minimumZDifference > 0 && dz < minimumZDifference)
            {
                string    description;
                IssueCode issueCode;
                if (dz > 0)
                {
                    issueCode   = Codes[Code.TooSmall];
                    description = string.Format(
                        "The Z distance between the feature Z ranges is too small ({0})",
                        FormatComparison(dz, minimumZDifference, "<"));
                }
                else
                {
                    double overlapDistance = Math.Min(minFeature.ZMax, maxFeature.ZMax) -
                                             Math.Max(minFeature.ZMin, maxFeature.ZMin);

                    issueCode   = Codes[Code.RangeOverlap];
                    description = $"The feature Z ranges overlap by {overlapDistance:N2}";
                }

                errorCount += ErrorReporting.Report(description,
                                                    geometryProvider.Geometry,
                                                    issueCode, null,
                                                    minFeature.Feature,
                                                    maxFeature.Feature);
            }

            if (maximumZDifference > 0 && dz > maximumZDifference)
            {
                // a z difference larger than maximum is always an error
                string description = string.Format(
                    "The Z distance between the feature Z ranges is too large ({0})",
                    FormatComparison(dz, maximumZDifference, ">"));

                errorCount += ErrorReporting.Report(
                    description,
                    geometryProvider.Geometry, Codes[Code.TooLarge],
                    TestUtils.GetShapeFieldName(feature1),
                    new object[] { dz },
                    feature1, feature2);
            }

            errorCount += CheckConstraint(minFeature, maxFeature, geometryProvider, dz);

            return(errorCount);
        }