Пример #1
0
        private void CreateMissingPKError(IFeature theEditIndicator, string[] pks, string editType)
        {
            IPoint theErrorPoint = this.get_ErrorPoint(theEditIndicator.Shape);
            theErrorPoint.Project(SpatialReferenceHelper.GeographicReference);

            DataQualityError theError = new DataQualityError(this.Name, false, false);
            theError.Location = theErrorPoint;

            theError.Severity = 1;

            if (editType == "insert")
                theError.Description = "Inserted shape has null primary key information";
            else if (editType == "delete")
                theError.Description = "Deleted feature has null primary key information";
            else
                theError.Description = "Edited shape has null primary key information";

            ExtendedInfo theInfo = new ExtendedInfo();

            string theSourceDSName = "";
            IDataset theSourceDS = (IDataset)theEditIndicator.Table;
            theSourceDSName = theSourceDS.Name;

            theInfo.AddProperty("Feature class", theSourceDSName);
            theInfo.AddProperty("Feature ID: ", theEditIndicator.OID.ToString());

            theError.ExtendedData = theInfo.WriteXML();
            //this.LogMessage(theError.ExtendedData);
            this._errors.Add(theError);
        }
Пример #2
0
        private void EvaluateEditInSee(
			IFeature workingFeature,
			IFeature pristineFeature,
			IPolygon seeBounds,
			string seeID,
			string pkWhereClause,
			double shiftLimit)
        {
            bool bWorkingFeatureOutside = false;
            bool bPristineFeatureOutside = false;
            bool bUpdateOutOfBounds = false;

            HashSet<IPoint> theOffendingVertices = null;

            IRelationalOperator theRelOp = (IRelationalOperator)seeBounds;
            IGeometry theWorkingShape = null;
            IGeometry thePristineShape = null;

            try
            {
                if (workingFeature != null)
                {
                    theWorkingShape = this.ShapeCopy(workingFeature);
                    if (theRelOp.Contains(theWorkingShape) == false)
                    {
                        bWorkingFeatureOutside = true;
                    }
                }

                if (pristineFeature != null)
                {
                    thePristineShape = this.ShapeCopy(pristineFeature);
                    if (theRelOp.Contains(thePristineShape) == false)
                    {
                        bPristineFeatureOutside = true;
                    }
                }

                bUpdateOutOfBounds = bWorkingFeatureOutside || bPristineFeatureOutside;

                if (bUpdateOutOfBounds && theWorkingShape != null && thePristineShape != null)
                {
                    IGeometry theWorkingShapeOutsideSee = ((ITopologicalOperator)theWorkingShape).Difference(seeBounds);
                    IGeometry thePristineShapeOutsideSee = ((ITopologicalOperator)thePristineShape).Difference(seeBounds);

                    if (theWorkingShapeOutsideSee == null
                        || theWorkingShapeOutsideSee.IsEmpty)
                    {
                        bUpdateOutOfBounds = false;
                    }
                    else if (((IRelationalOperator)theWorkingShapeOutsideSee).Equals(thePristineShapeOutsideSee))
                    {
                        // shape unchanged
                        bUpdateOutOfBounds = false;
                    }
                    else if (!((IRelationalOperator)theWorkingShapeOutsideSee).Equals(thePristineShapeOutsideSee))
                    {
                        IGeometry pristineClone = pristineFeature.ShapeCopy;
                        IGeometry workingClone = workingFeature.ShapeCopy;

                        string theTxID = this.TxID;
                        IQueryFilter theQF = new QueryFilterClass();
                        theQF.WhereClause = SEE_ID_FIELD_NAME + " = '" + theTxID + "'";
                        IFeatureCursor theFCursor = this.SEELayer.Search(theQF, false);
                        IFeature theSee = theFCursor.NextFeature();
                        Marshal.ReleaseComObject(theFCursor);
                        theFCursor = null;

                        IGeometry seeClone = theSee.ShapeCopy;

                        // simplify the clones (see SEE.cs line 92?)
                        ITopologicalOperator2 simplifyPristineTo = (ITopologicalOperator2)pristineClone;
                        simplifyPristineTo.IsKnownSimple_2 = false;
                        simplifyPristineTo.Simplify();

                        ITopologicalOperator2 simplifyWorkingTo = (ITopologicalOperator2)workingClone;
                        simplifyWorkingTo.IsKnownSimple_2 = false;
                        simplifyWorkingTo.Simplify();

                        // clone the SEE. Reproject the SEE to the pristines projection
                        ITopologicalOperator2 simplifySeeTo = (ITopologicalOperator2)seeClone;
                        simplifySeeTo.IsKnownSimple_2 = false;
                        simplifySeeTo.Simplify();
                        seeClone.Project(pristineClone.SpatialReference);

                        ITopologicalOperator baseWorkingTo = (ITopologicalOperator)workingClone;
                        IGeometry bufferWorkingShape = baseWorkingTo.Buffer(shiftLimit);
                        ITopologicalOperator pristineTo = (ITopologicalOperator)pristineClone;
                        IGeometry diffedGeom = pristineTo.Difference(bufferWorkingShape);
                        diffedGeom.SpatialReference = workingClone.SpatialReference;

                        ITopologicalOperator basePristineTo = (ITopologicalOperator)pristineClone;
                        IGeometry bufferPristineShape = basePristineTo.Buffer(shiftLimit);
                        ITopologicalOperator workingTo = (ITopologicalOperator)workingClone;
                        IGeometry secondDiffedGeom = workingTo.Difference(bufferPristineShape);
                        secondDiffedGeom.SpatialReference = pristineClone.SpatialReference;

                        theOffendingVertices = new HashSet<IPoint>();

                        GetOffendingVertices(diffedGeom, seeClone, theOffendingVertices);
                        GetOffendingVertices(secondDiffedGeom, seeClone, theOffendingVertices);

                        if(theOffendingVertices.Count == 0) bUpdateOutOfBounds = false;

                        while (Marshal.ReleaseComObject(baseWorkingTo) > 0) { }
                        while (Marshal.ReleaseComObject(bufferWorkingShape) > 0) { }
                        while (Marshal.ReleaseComObject(pristineTo) > 0) { }
                        while (Marshal.ReleaseComObject(diffedGeom) > 0) { }

                        while (Marshal.ReleaseComObject(basePristineTo) > 0) { }
                        while (Marshal.ReleaseComObject(bufferPristineShape) > 0) { }
                        while (Marshal.ReleaseComObject(workingTo) > 0) { }
                        while (Marshal.ReleaseComObject(secondDiffedGeom) > 0) { }

                        while (Marshal.ReleaseComObject(pristineClone) > 0) { }
                        while (Marshal.ReleaseComObject(workingClone) > 0) { }

                        diffedGeom = null;
                        pristineTo = null;
                        bufferWorkingShape = null;
                        baseWorkingTo = null;

                        secondDiffedGeom = null;
                        workingTo = null;
                        bufferPristineShape = null;
                        basePristineTo = null;

                        pristineClone = null;
                        workingClone = null;
                    }
                    else
                    {
                        // TODO: This index is causing errors on rebuild geometries using
                        // TODO: topology tools. Verify vertext and shape match, not using an index

                        // Evaluate if this is a real edit or just vertex shifting

                        // Build point collection index for the pristine shape
                        // cellsize: average of thePristineShapeOutsideSee width and height divided by 10
                        PointCollectionIndex theIndex = new PointCollectionIndex(thePristineShapeOutsideSee.Envelope.Width + thePristineShapeOutsideSee.Envelope.Height / 2 / 10);
                        IPointCollection thePtColl = (IPointCollection)thePristineShapeOutsideSee;
                        for (int i = 0; i < thePtColl.PointCount; i++)
                            theIndex.AddPoint(new IndexPoint(pristineFeature.OID, i, thePtColl.get_Point(i)));

                        // Check each working vertex to see if there is a vertex within the shift limit
                        // If not, this vertex needs flagging
                        theOffendingVertices = new HashSet<IPoint>();
                        thePtColl = (IPointCollection)theWorkingShapeOutsideSee;
                        for (int i = 0; i < thePtColl.PointCount; i++)
                        {
                            IPoint theWorkingPoint = thePtColl.get_Point(i);
                            IndexPoint thePristinePoint = theIndex.get_ClosestPointWithinLimits(theWorkingPoint.X, theWorkingPoint.Y, -1, shiftLimit);

                            if (thePristinePoint == null)
                            {
                                theOffendingVertices.Add(this.get_ErrorPoint(theWorkingPoint));
                            }

                        }

                        if (theOffendingVertices.Count == 0)
                            bUpdateOutOfBounds = false;
                    }

                    while (Marshal.ReleaseComObject(theWorkingShapeOutsideSee) > 0){}
                    while (Marshal.ReleaseComObject(thePristineShapeOutsideSee) > 0) { }

                    theWorkingShapeOutsideSee = null;
                    thePristineShapeOutsideSee = null;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }

            if (bUpdateOutOfBounds)
            {
                // This needs to be flagged. The only exceptions are:
                // - a spatial update where the difference between the working and pristine shapes falls within the SEE
                // - an attribute-only update
                if (theOffendingVertices == null)
                {
                    theOffendingVertices = new HashSet<IPoint>();
                    if (theWorkingShape != null)
                        theOffendingVertices.Add(this.get_ErrorPoint(theWorkingShape));
                    else
                        theOffendingVertices.Add(this.get_ErrorPoint(thePristineShape));
                }

                foreach (IPoint theErrorPoint in theOffendingVertices)
                {
                    theErrorPoint.Project(SpatialReferenceHelper.GeographicReference);

                    DataQualityError theError = new DataQualityError(this.Name, false, false);
                    theError.Location = theErrorPoint;

                    theError.Severity = 1;

                    if (thePristineShape == null)
                        theError.Description = "Inserted shape extends outside of the SEE area";
                    else if (theWorkingShape == null)
                        theError.Description = "Deleted feature extends outside of the SEE area";
                    else
                        theError.Description = "Edited shape extends outside of the SEE area";

                    ExtendedInfo theInfo = new ExtendedInfo();

                    string theSourceDSName = "";
                    if (workingFeature != null)
                    {
                        IDataset theSourceDS = (IDataset)workingFeature.Table;
                        theSourceDSName = theSourceDS.Name;
                    }
                    else
                    {
                        IDataset theSourceDS = (IDataset)pristineFeature.Table;
                        theSourceDSName = "P_" + theSourceDS.Name;
                    }
                    theInfo.AddProperty("Feature class", theSourceDSName);
                    theInfo.AddProperty("Business ID: ", pkWhereClause);
                    if (workingFeature != null)
                        theInfo.AddProperty("Working Feature ID", workingFeature.OID.ToString());
                    theInfo.AddProperty("SEE ID", seeID.ToString());

                    theError.ExtendedData = theInfo.WriteXML();
                    //this.LogMessage(theError.ExtendedData);
                    this._errors.Add(theError);
                }
            }
        }
Пример #3
0
        private int AnalyzePair(IFeatureClass fcWork, IFeatureClass fcOsdb, 
			string fieldName, string fkey,
			int idxWork, int idxOsdb, int idxFKey,
			bool canDefer, bool canExcept)
        {
            // First check that the working fc is self-consistent
            int errCount = AnalyzeSingle(fcWork, idxWork, canDefer, canExcept);

            if (errCount != 0)
                return errCount; // -1 if error, > 0 is a count of errors

            /*
             * We know that all of the values in the working layer are unique within
             * the working layer. Now we need to determine if any working values
             * line up with multiple osdb records
             */
            IDataset dsWork = (IDataset)fcWork;
            IDataset dsOsdb = (IDataset)fcOsdb;

            IQueryDef theQDef = ((IFeatureWorkspace)dsOsdb.Workspace).CreateQueryDef();
            theQDef.Tables = dsOsdb.Name;
            theQDef.SubFields = "count(*)";

            IField theField = fcWork.Fields.get_Field(idxWork);
            string q = "";
            if (theField.Type == esriFieldType.esriFieldTypeString)
                q = "'";
            else if (theField.Type == esriFieldType.esriFieldTypeBlob
                || theField.Type == esriFieldType.esriFieldTypeGeometry
                || theField.Type == esriFieldType.esriFieldTypeRaster)
            {
                this.LogMessage("Fields of type " + theField.Type + " can't be evaluated by " + this.Name);
                return -1;
            }

            IFeatureCursor checkCursor = null;
            ICursor theCountCursor = null;
            try
            {
                checkCursor = fcWork.Search(null, true);
                IFeature theFeature = checkCursor.NextFeature();
                while (theFeature != null)
                {
                    theQDef.WhereClause = fieldName + "=" + q + Convert.ToString(theFeature.get_Value(idxWork)) + q
                        + " and " + fkey + "<>" + q + Convert.ToString(theFeature.get_Value(idxFKey)) + q;

                    theCountCursor = theQDef.Evaluate();

                    IRow theCountRow = theCountCursor.NextRow();
                    int theCount = Convert.ToInt32(theCountRow.get_Value(0));
                    Marshal.ReleaseComObject(theCountCursor);
                    theCountCursor = null;

                    if (theCount > 0)
                    {
                        // Error
                        IPoint theErrorPoint = this.get_ErrorPoint(theFeature.Shape);

                        DataQualityError theError = new DataQualityError(this.Name, canDefer, canExcept);
                        theError.Location = theErrorPoint;
                        theError.Severity = 1;

                        theError.Description = "Non-unique value in unique-constrained field";

                        ExtendedInfo theInfo = new ExtendedInfo();

                        theInfo.AddProperty("Working feature class", dsWork.Name);
                        theInfo.AddProperty("OSDB feature class", dsOsdb.Name);
                        theInfo.AddProperty("Feature ID", theFeature.OID.ToString());

                        object theValue = theFeature.get_Value(idxWork);
                        theInfo.AddProperty("Value", theValue.ToString());
                        object theFKey = theFeature.get_Value(idxFKey);
                        theInfo.AddProperty("FKey", theFKey.ToString());

                        theError.ExtendedData = theInfo.WriteXML();
                        //this.LogMessage(theError.ExtendedData);
                        this._errors.Add(theError);

                        errCount++;
                    }

                    theFeature = checkCursor.NextFeature();
                }
            }
            catch (Exception ex)
            {
                this.LogMessage("Error looking for OSDB records:" + Environment.NewLine
                    + ex.Message + Environment.NewLine + ex.StackTrace);
                return -1;
            }
            finally
            {
                if (checkCursor != null)
                    Marshal.ReleaseComObject(checkCursor);
                if (theCountCursor != null)
                    Marshal.ReleaseComObject(theCountCursor);
            }

            return errCount;
        }
Пример #4
0
        private int AnalyzeSingle(IFeatureClass fc, int fieldIdx, bool canDefer, bool canExcept)
        {
            int errCount = 0;
            Hashtable theLookup = new Hashtable();
            IDataset theDataset = (IDataset)fc;
            IFeatureCursor checkCursor = fc.Search(null, true);

            try
            {
                IFeature theFeature = checkCursor.NextFeature();
                while (theFeature != null)
                {
                    object theValue = theFeature.get_Value(fieldIdx);
                    if (theValue == null || Convert.IsDBNull(theValue))
                    {
                        // Error
                        IPoint theErrorPoint = this.get_ErrorPoint(theFeature.Shape);

                        DataQualityError theError = new DataQualityError(this.Name, canDefer, canExcept);
                        theError.Location = theErrorPoint;
                        theError.Severity = 1;

                        theError.Description = "Null value in unique-constrained field";

                        ExtendedInfo theInfo = new ExtendedInfo();

                        theInfo.AddProperty("Feature class", theDataset.Name);
                        theInfo.AddProperty("Feature ID", theFeature.OID.ToString());

                        theError.ExtendedData = theInfo.WriteXML();
                        //this.LogMessage(theError.ExtendedData);
                        this._errors.Add(theError);

                        errCount++;
                    }
                    else if (theLookup.ContainsKey(theValue))
                    {
                        // Error
                        IPoint theErrorPoint = this.get_ErrorPoint(theFeature.Shape);

                        DataQualityError theError = new DataQualityError(this.Name, canDefer, canExcept);
                        theError.Location = theErrorPoint;
                        theError.Severity = 1;

                        theError.Description = "Non-unique value in unique-constrained field";

                        ExtendedInfo theInfo = new ExtendedInfo();

                        theInfo.AddProperty("Feature class", theDataset.Name);
                        theInfo.AddProperty("Feature ID", theFeature.OID.ToString());
                        theInfo.AddProperty("Value", theValue.ToString());

                        theError.ExtendedData = theInfo.WriteXML();
                        //this.LogMessage(theError.ExtendedData);
                        this._errors.Add(theError);

                        errCount++;
                    }
                    else
                    {
                        theLookup.Add(theValue, theValue);
                    }

                    theFeature = checkCursor.NextFeature();
                }
            }
            catch (Exception ex)
            {
                this.LogMessage("Error checking unique values:" + Environment.NewLine
                    + ex.Message + Environment.NewLine + ex.StackTrace);
                return -1;
            }
            finally
            {
                Marshal.ReleaseComObject(checkCursor);
            }
            return errCount;
        }
Пример #5
0
        private ArrayList ProcessFeature(IFeature test, ISpatialReference referenceSR, double precision)
        {
            if (test == null || test.Shape == null || test.Shape.IsEmpty)
                return null;

            ArrayList theReturn = new ArrayList();
            string polygonError = "";   // test feb 21

            int index = this.FindParameter("minimum-arc-proportional");
            double proportion = Math.Abs((double)((ParameterInfo)this._params[index]).ParamValue);
            index = this.FindParameter(ParameterInfo.PARAM_CANDEFER);
            bool canDefer = (bool)((ParameterInfo)this._params[index]).ParamValue;
            index = this.FindParameter(ParameterInfo.PARAM_CANEXCEPT);
            bool canExcept = (bool)((ParameterInfo)this._params[index]).ParamValue;

            IGeometry theGeometry = test.ShapeCopy;
            theGeometry.Project(referenceSR);

            ISegmentCollection theGeomColl = (ISegmentCollection)test.Shape;
            for (int i = 0; i < theGeomColl.SegmentCount; i++)
            {
                IGeometry theGeometryPart = theGeomColl.get_Segment(i);
                ISegment theCurve = (ISegment)theGeomColl.get_Segment(i);

                if (theCurve.Length < precision * proportion)
                {
                    IPoint theErrorPoint = theCurve.FromPoint;
                    theErrorPoint.Project(SpatialReferenceHelper.GeographicReference);

                    DataQualityError theError = new DataQualityError(this.Name, canDefer, canExcept);
                    theError.Location = theErrorPoint;

                    if (theCurve.Length == 0)
                        theError.Severity = 1;
                    else if (theCurve.Length <= precision)
                        theError.Severity = 2;
                    else
                        theError.Severity = 3;

                    theError.Description = "Arc too short";

                    // Feb 15, 2008 Testing
                    System.Diagnostics.Debug.WriteLine(string.Format("({0},{1}) - ({2},{3}) {4} {5}",
                        theCurve.FromPoint.X.ToString(),
                        theCurve.FromPoint.Y.ToString(),
                        theCurve.ToPoint.X.ToString(),
                        theCurve.ToPoint.Y.ToString(),
                        theCurve.IsClosed.ToString(),
                        theCurve.Length.ToString()));

                    ExtendedInfo theInfo = new ExtendedInfo();
                    IDataset theDataset = (IDataset)test.Table;

                    theInfo.AddProperty("Feature class", theDataset.Name);
                    theInfo.AddProperty("Feature ID", test.OID.ToString());
                    theInfo.AddProperty("Arc length", theCurve.Length.ToString());

                    theError.ExtendedData = theInfo.WriteXML();
                    //this.LogMessage(theError.ExtendedData);
                    theReturn.Add(theError);
                }
            }
            // If a polygon check the geometry type using IsSimpleEx
            if (test.ShapeCopy.GeometryType == esriGeometryType.esriGeometryPolygon)
            {
                IPoint theErrorPoint = this.get_ErrorPoint(theGeometry);
                theErrorPoint.Project(SpatialReferenceHelper.GeographicReference);

                DataQualityError theError = new DataQualityError(this.Name, canDefer, canExcept);
                theError.Location = theErrorPoint;

                ITopologicalOperator4 pTopo4 = test.ShapeCopy as ITopologicalOperator4;
                esriNonSimpleReasonEnum myReason = esriNonSimpleReasonEnum.esriNonSimpleOK; // Initialize myReason
                pTopo4.IsKnownSimple_2 = false;
                bool isSimple = pTopo4.get_IsSimpleEx(out myReason);

                if (!isSimple)
                {
                    switch (myReason.ToString())
                    {
                        case "esriNonSimpleOK":
                            theError.Description = "The geometry is simple.";
                            break;
                        case "esriNonSimpleRingOrientation":
                            theError.Description = "A polygon is topologically simple, but its rings may not be oriented correctly (outer rings - cw, inner rings - ccw).";
                            break;
                        case "esriNonSimpleSegmentOrientation":
                            theError.Description = "Individual segments are not consistantly oriented. The 'to' point of seg i should be incident on the 'from' point of seg i+1.";
                            break;
                        case "esriNonSimpleShortSegments":
                            theError.Description = "Some segments are shorter than allowed by the system units of the spatial reference associated with the geometry.";
                            break;
                        case "esriNonSimpleSelfIntersections":
                            theError.Description = "The interior of each part (rings, planar paths) must not intersect itself or other parts.";
                            break;
                        case "esriNonSimpleUnclosedRing":
                            theError.Description = "The last segment in a ring must have its 'to' point incident on the 'from' point of the first segment.";
                            break;
                        case "esriNonSimpleEmptyPart":
                            theError.Description = "The geometry contains an empty part.";
                            break;
                        default:
                            theError.Description = "Do not understand problem definition code: " + myReason.ToString();
                            break;
                    }
                    theReturn.Add(theError);
                }
            }
            return theReturn;
        }
Пример #6
0
        public override int Execute(string logfileName)
        {
            this.InitLogging(logfileName);
            this.LogMessage(this.Name + " QA test execution started.");

            try
            {
                this.LogMessage(this.Name + " Parameters:");
                for (int i = 0; i < this.ParameterCount; i++)
                    this.LogMessage(this.get_ParameterText(i) + ": " + this.get_ParameterValue(i));

                this.ClearErrors();

                bool bProblemsRunning = false;

                int index = this.FindParameter(ParameterInfo.PARAM_CANDEFER);
                bool canDefer = (bool)((ParameterInfo)this._params[index]).ParamValue;
                index = this.FindParameter(ParameterInfo.PARAM_CANEXCEPT);
                bool canExcept = (bool)((ParameterInfo)this._params[index]).ParamValue;

                // Compare the shape type of the odd layers with the evens.
                // If the user has used the magic wand tool, this should be right
                for (int layerIdx = 0; layerIdx < this.LayerCount; layerIdx+=2)
                {
                    IFeatureLayer theFLayer1 = this.get_Layer(layerIdx);
                    IFeatureLayer theFLayer2 = this.get_Layer(layerIdx + 1);

                    if (theFLayer1 == null || theFLayer2 == null
                        || theFLayer1.Valid == false || theFLayer2.Valid == false)
                    {
                        bProblemsRunning = true;
                        break;
                    }

                    IFeatureClass theFClass1 = theFLayer1.FeatureClass;
                    IFeatureClass theFClass2 = theFLayer2.FeatureClass;

                    IDataset theDataset1 = (IDataset)theFClass1;
                    IDataset theDataset2 = (IDataset)theFClass2;

                    this.LogMessage("Comparing the shape type of featureclass " + theDataset1.Name + " vs. " + theDataset2.Name);

                    if (theFClass1.ShapeType != theFClass2.ShapeType)
                    {
                        IPoint theErrorPoint = ((IArea)theFLayer1.AreaOfInterest).Centroid;
                        theErrorPoint.Project(SpatialReferenceHelper.GeographicReference);

                        DataQualityError theError = new DataQualityError(this.Name, canDefer, canExcept);
                        theError.Location = theErrorPoint;

                        theError.Severity = 1;

                        theError.Description = "Wrong shape type";

                        ExtendedInfo theInfo = new ExtendedInfo();

                        theInfo.AddProperty("Feature class 1", theDataset1.Name);
                        theInfo.AddProperty("Feature class 2", theDataset2.Name);
                        theInfo.AddProperty("Shape type 1", theFClass1.ShapeType.ToString());
                        theInfo.AddProperty("Shape type 2", theFClass2.ShapeType.ToString());

                        theError.ExtendedData = theInfo.WriteXML();

                        this._errors.Add(theError);
                    }
                }

                this.LogMessage("Number of errors found: " + this.ErrorCount);

                if (bProblemsRunning)
                    return -1;
                else
                    this.LogMessage("Test " + this.Name + " successful.");
            }
            catch (Exception ex)
            {
                this.LogMessage("Exception caught: \n" + ex.Message + "\n" + ex.StackTrace.ToString());
                return -1;
            }
            finally
            {
                this.StopLogging();
            }

            return this.ErrorCount;
        }
Пример #7
0
        private void CompareSIDs(IFeatureClass workingFeatureClass, IFeatureCursor checkCursor, ITable osdbBizTable, string sidFieldName,
			bool canDefer, bool canExcept)
        {
            IDataset theDS1 = (IDataset)osdbBizTable;
            IDataset theDS2 = (IDataset)workingFeatureClass;

            IRelationshipClass theRC = null;
            try
            {
                // Create relationshipclass backwards to normal, b/c we're checking
                // that the SIDs that exist in the FC exist in the biz table
                IMemoryRelationshipClassFactory theFactory = new MemoryRelationshipClassFactoryClass();
                theRC = theFactory.Open(
                    theDS2.Name + "_to_" + theDS1.Name,
                    (IObjectClass)workingFeatureClass,
                    sidFieldName,
                    (IObjectClass)osdbBizTable,
                    sidFieldName,
                    "forward",
                    "backward",
                    esriRelCardinality.esriRelCardinalityOneToOne);
            }
            catch (Exception ex)
            {
                this.LogMessage("Error creating memory relationship class between " + theDS2.Name + " and " + theDS1.Name + ":" +Environment.NewLine
                    + ex.Message + Environment.NewLine + ex.StackTrace);
                return;
            }

            try
            {
                int sidIndex = workingFeatureClass.FindField(sidFieldName);

                IFeature theFeature = checkCursor.NextFeature();
                while (theFeature != null)
                {
                    ISet theSet = theRC.GetObjectsRelatedToObject((IObject)theFeature);
                    if (theSet.Count == 0)
                    {
                        // Error
                        IPoint theErrorPoint = this.get_ErrorPoint(theFeature.Shape);

                        DataQualityError theError = new DataQualityError(this.Name, canDefer, canExcept);
                        theError.Location = theErrorPoint;
                        theError.Severity = 1;

                        theError.Description = "No corresponding OSDB record";

                        ExtendedInfo theInfo = new ExtendedInfo();

                        theInfo.AddProperty("Feature class", theDS2.Name);
                        theInfo.AddProperty("OSDB table", theDS1.Name);
                        theInfo.AddProperty("Feature ID", theFeature.OID.ToString());

                        object sidValue = theFeature.get_Value(sidIndex);
                        theInfo.AddProperty("SID value", sidValue == null ? "NULL" : sidValue.ToString());

                        theError.ExtendedData = theInfo.WriteXML();
                        //this.LogMessage(theError.ExtendedData);
                        this._errors.Add(theError);

                    }

                    theFeature = checkCursor.NextFeature();
                }
            }
            catch (Exception ex)
            {
                this.LogMessage("Error looking for OSDB records:" + Environment.NewLine
                    + ex.Message + Environment.NewLine + ex.StackTrace);
            }
        }
Пример #8
0
        private void CompareAreas(IFeatureClass workingFeatureClass, IFeatureCursor checkCursor,
			ITable relatedTable, string relateFieldName,
			string areaFieldName, double conversionFactor, double tolerance,
			bool canDefer, bool canExcept)
        {
            IDataset theDS1 = (IDataset)relatedTable;
            IDataset theDS2 = (IDataset)workingFeatureClass;

            IRelationshipClass theRC = null;
            if (relatedTable != null && relateFieldName != null && relateFieldName.Length > 0)
            {
                try
                {
                    // Create relationshipclass backwards to normal, b/c we're checking
                    // that the SIDs that exist in the FC exist in the biz table
                    IMemoryRelationshipClassFactory theFactory = new MemoryRelationshipClassFactoryClass();
                    IObjectClass bob = (IObjectClass)workingFeatureClass;
                    IObjectClass sam = (IObjectClass)relatedTable;
                    theRC = theFactory.Open(
                        theDS2.Name + "_to_" + theDS1.Name,
                        bob,
                        relateFieldName,
                        sam,
                        relateFieldName,
                        "forward",
                        "backward",
                        esriRelCardinality.esriRelCardinalityOneToOne);
                }
                catch (Exception ex)
                {
                    this.LogMessage("Error creating memory relationship class between " + theDS2.Name + " and " + theDS1.Name + ":" +Environment.NewLine
                        + ex.Message + Environment.NewLine + ex.StackTrace);
                    return;
                }
            }

            try
            {
                int areaFieldIndex = -1;
                int fkIndex = -1;

                if (theRC == null)
                {
                    // Area field is on the feature
                    areaFieldIndex = workingFeatureClass.FindField(areaFieldName);
                }
                else
                {
                    // Area field is on the related table
                    areaFieldIndex = relatedTable.FindField(areaFieldName);
                    fkIndex = workingFeatureClass.FindField(relateFieldName);
                }

                IFeature theFeature = checkCursor.NextFeature();
                while (theFeature != null)
                {
                    double areaDbValue = double.NaN;
                    double areaGeoValue = double.NaN;

                    // Get the geographic area in sq. metres
                    if (theFeature.Shape != null && theFeature.Shape.IsEmpty == false)
                    {
                        IGeometry theGeometry = theFeature.ShapeCopy;
                        theGeometry.Project(SpatialReferenceHelper.BCAlbersSpatialReference);
                        areaGeoValue = ((IArea)theGeometry).Area;
                    }

                    if (theRC == null)
                    {
                        // Db Area is on the feature
                        areaDbValue = Convert.ToDouble(theFeature.get_Value(areaFieldIndex));
                        areaDbValue *= conversionFactor;
                    }
                    else
                    {
                        // Db Area is on related feature
                        // Only valid if there is exactly one related record
                        // and it has a real area (not zero or null)
                        ISet theSet = theRC.GetObjectsRelatedToObject((IObject)theFeature);
                        if (theSet.Count == 1)
                        {
                            IObject theRelatedObject = (IObject)theSet.Next();
                            if (theRelatedObject != null)
                            {
                                object theValue = theRelatedObject.get_Value(areaFieldIndex);
                                if (Convert.IsDBNull(theValue) == false)
                                {
                                    double theDValue = Convert.ToDouble(theValue);
                                    if (theDValue > 0)
                                    {
                                        areaDbValue = theDValue;
                                        areaDbValue *= conversionFactor;
                                    }
                                }
                            }
                        }
                    }

                    if (double.IsNaN(areaDbValue))
                    {
                        /*
                        IPoint theErrorPoint = this.get_ErrorPoint(theFeature.Shape);

                        DataQualityError theError = new DataQualityError(this.Name, canDefer, canExcept);
                        theError.Location = theErrorPoint;
                        theError.Severity = 1;
                        theError.Description = "Null database area";

                        ExtendedInfo theInfo = new ExtendedInfo();

                        theInfo.AddProperty("Feature class", theDS2.Name);
                        theInfo.AddProperty("Feature ID", theFeature.OID.ToString());

                        if (theRC != null)
                        {
                            theInfo.AddProperty("Related table", theDS1.Name);
                            object fkValue = theFeature.get_Value(fkIndex);
                            theInfo.AddProperty("FK value", fkValue == null ? "NULL" : fkValue.ToString());
                        }

                        theError.ExtendedData = theInfo.WriteXML();
                        this._errors.Add(theError);
                        */
                    }
                    else if (double.IsNaN(areaGeoValue))
                    {
                        IPoint theErrorPoint = this.get_ErrorPoint(null);

                        DataQualityError theError = new DataQualityError(this.Name, canDefer, canExcept);
                        theError.Location = theErrorPoint;
                        theError.Severity = 1;
                        theError.Description = "Null geographic area";

                        ExtendedInfo theInfo = new ExtendedInfo();

                        theInfo.AddProperty("Feature class", theDS2.Name);
                        theInfo.AddProperty("Feature ID", theFeature.OID.ToString());

                        if (theRC != null)
                        {
                            theInfo.AddProperty("Related table", theDS1.Name);
                            object fkValue = theFeature.get_Value(fkIndex);
                            theInfo.AddProperty("SID", fkValue == null ? "NULL" : fkValue.ToString());
                        }

                        theError.ExtendedData = theInfo.WriteXML();
                        this._errors.Add(theError);
                    }
                    else
                    {

                        double difference = Math.Abs(areaDbValue - areaGeoValue);
                        if (difference > tolerance)
                        {
                            // Error
                            IPoint theErrorPoint = this.get_ErrorPoint(theFeature.Shape);

                            DataQualityError theError = new DataQualityError(this.Name, canDefer, canExcept);
                            theError.Location = theErrorPoint;

                            if (difference < tolerance * 2)
                                theError.Severity = 3;
                            else if (difference < tolerance * 10)
                                theError.Severity = 2;
                            else
                                theError.Severity = 1;

                            theError.Description = "Stored area different from geographic area";

                            ExtendedInfo theInfo = new ExtendedInfo();

                            theInfo.AddProperty("Feature class", theDS2.Name);
                            theInfo.AddProperty("Feature ID", theFeature.OID.ToString());

                            theInfo.AddProperty("Geographic area (sq. metres)", areaGeoValue.ToString());
                            theInfo.AddProperty("Database area (sq. metres)", areaDbValue.ToString());

                            if (theRC != null)
                            {
                                theInfo.AddProperty("Related table", theDS1.Name);
                                object fkValue = theFeature.get_Value(fkIndex);
                                theInfo.AddProperty("SID", fkValue == null ? "NULL" : fkValue.ToString());
                            }

                            theError.ExtendedData = theInfo.WriteXML();
                            //this.LogMessage(theError.ExtendedData);
                            this._errors.Add(theError);

                        }
                    }

                    theFeature = checkCursor.NextFeature();
                }
            }
            catch (Exception ex)
            {
                this.LogMessage("Error comparing areas:" + Environment.NewLine
                    + ex.Message + Environment.NewLine + ex.StackTrace);
            }
        }
Пример #9
0
        public override int Execute(string logfileName)
        {
            this.InitLogging(logfileName);
            this.LogMessage(this.Name + " QA test execution started.");

            int currentOid = -1;

            try
            {
                this.LogMessage(this.Name + " Parameters:");
                for (int i = 0; i < this.ParameterCount; i++)
                    this.LogMessage(this.get_ParameterText(i) + ": " + this.get_ParameterValue(i));

                this.ClearErrors();

                // Check the search radius
                int idx = this.FindParameter("search-radius");
                DoubleParameterInfo theInfo = (DoubleParameterInfo)this._params[idx];
                double theSearchRadius = (double)theInfo.ParamValue;

                if (theSearchRadius <= 0)
                {
                    this.LogMessage("Zero or negative value passed as search radius for " + this.Name + ". Stopping.");
                    return -1;
                }

                // Check the cluster tolerance
                idx = this.FindParameter("cluster-tolerance");
                theInfo = (DoubleParameterInfo)this._params[idx];
                double theCluster = (double)theInfo.ParamValue;

                if (theCluster >= theSearchRadius)
                {
                    this.LogMessage("Cluster tolerance equal to or larger than search radius for " + this.Name + ". Stopping.");
                    return -1;
                }

                // Convert them to metres
                idx = this.FindParameter("search-units");
                UnitsParameterInfo theUnitsParam = (UnitsParameterInfo)this._params[idx];
                esriUnits theUnits = theUnitsParam.ParamValueInUnits;
                IUnitConverter theConverter = new UnitConverterClass();
                theSearchRadius = theConverter.ConvertUnits(theSearchRadius, theUnits, esriUnits.esriMeters);
                theCluster = theConverter.ConvertUnits(theCluster, theUnits, esriUnits.esriMeters);

                // Get the canDefer/canExcept params
                idx = this.FindParameter(ParameterInfo.PARAM_CANDEFER);
                bool canDefer = (bool)((ParameterInfo)this._params[idx]).ParamValue;
                idx = this.FindParameter(ParameterInfo.PARAM_CANEXCEPT);
                bool canExcept = (bool)((ParameterInfo)this._params[idx]).ParamValue;

                // Loop through the layers
                for (int i = 0; i < this.LayerCount - 1; i++)
                {
                    IFeatureLayer theLayer1 = this.get_Layer(i);
                    if (this.SupportsGeometryType(theLayer1.FeatureClass.ShapeType) == false)
                        continue;

                    // Index the points in theLayer1
                    IDataset theDataset1 = (IDataset)theLayer1.FeatureClass;
                    IGeoDataset theGeoDS = (IGeoDataset)theDataset1;
                    IEnvelope theAOI = theGeoDS.Extent;
                    if (theAOI == null || theAOI.IsEmpty)
                        continue;

                    theAOI.Project(SpatialReferenceHelper.BCAlbersSpatialReference);
                    double theCellsize = theAOI.Width / 100;
                    this.LogMessage("Indexing features in " + theDataset1.Name + ". Cellsize (m): " + theCellsize);
                    PointCollectionIndex theIndex = new PointCollectionIndex(theCellsize);

                    IFeatureCursor theFCursor1 = null;
                    if (this.ConstrainToSelection)
                    {
                        ICursor theCursor = null;
                        IFeatureSelection theFSel = (IFeatureSelection)theLayer1;
                        theFSel.SelectionSet.Search(null, true, out theCursor);
                        theFCursor1 = (IFeatureCursor)theCursor;
                    }
                    else
                    {
                        theFCursor1 = theLayer1.Search(null, true);
                    }

                    IFeature theFeature1 = theFCursor1.NextFeature();
                    while (theFeature1 != null)
                    {
                        if (theFeature1.Shape != null && theFeature1.Shape.IsEmpty == false)
                        {
                            IPointCollection thePtColl = (IPointCollection)theFeature1.Shape;
                            for (int k = 0; k < thePtColl.PointCount; k++)
                            {
                                theIndex.AddPoint(new IndexPoint(theFeature1.OID, k, thePtColl.get_Point(k)));
                            }
                        }

                        theFeature1 = theFCursor1.NextFeature();
                    }

                    // Release the cursor
                    Marshal.ReleaseComObject(theFCursor1);
                    theFCursor1 = null;

                    if (theIndex.PointCount > 0)
                    {
                        // Use the index to analyze the other layers
                        for (int j = i+1; j < this.LayerCount; j++)
                        {
                            IFeatureLayer theLayer2 = this.get_Layer(j);
                            if (this.SupportsGeometryType(theLayer2.FeatureClass.ShapeType) == false)
                                continue;

                            IDataset theDataset2 = (IDataset)theLayer2.FeatureClass;
                            IFeatureCursor theFCursor2 = null;
                            if (this.ConstrainToSelection)
                            {
                                ICursor theCursor = null;
                                IFeatureSelection theFSel = (IFeatureSelection)theLayer2;
                                theFSel.SelectionSet.Search(null, true, out theCursor);
                                theFCursor2 = (IFeatureCursor)theCursor;
                            }
                            else
                            {
                                theFCursor2 = theLayer2.Search(null, true);
                            }

                            IFeature theFeature2 = theFCursor2.NextFeature();
                            while (theFeature2 != null)
                            {
                                if (theFeature2.Shape != null && theFeature2.Shape.IsEmpty == false)
                                {
                                    IGeometry theCopy = theFeature2.ShapeCopy;
                                    theCopy.Project(SpatialReferenceHelper.BCAlbersSpatialReference);
                                    IPointCollection thePtColl = (IPointCollection)theCopy;
                                    for (int k = 0; k < thePtColl.PointCount; k++)
                                    {
                                        // Find the closest point in the index. If it's less than
                                        // the search radius and larger than the cluster tolerance,
                                        // log as an error
                                        IPoint thePoint = thePtColl.get_Point(k);
                                        IndexPoint theIdxPoint = theIndex.get_ClosestPointWithinLimits(
                                            thePoint.X,
                                            thePoint.Y,
                                            theCluster,
                                            theSearchRadius);

                                        if (theIdxPoint != null)
                                        {
                                            // Build a straight line between the offending points
                                            IPolyline thePolyline = new PolylineClass();
                                            thePolyline.Project(SpatialReferenceHelper.BCAlbersSpatialReference);
                                            ((IPointCollection)thePolyline).AddPoint(thePoint, ref this._missing, ref this._missing);
                                            IPoint theOtherPoint = new PointClass();
                                            theOtherPoint.Project(SpatialReferenceHelper.BCAlbersSpatialReference);
                                            theOtherPoint.PutCoords(theIdxPoint.X, theIdxPoint.Y);
                                            ((IPointCollection)thePolyline).AddPoint(theOtherPoint, ref this._missing, ref this._missing);

                                            // Get the distance
                                            double dist = PointCollectionIndex.get_Distance(thePoint.X, thePoint.Y, theOtherPoint.X, theOtherPoint.Y);

                                            // Project to geographics for error reporting
                                            thePolyline.Project(SpatialReferenceHelper.GeographicReference);

                                            // Error point will be 1/2 way along line between points
                                            IPoint theErrorPoint = new PointClass();
                                            thePolyline.QueryPoint(esriSegmentExtension.esriNoExtension, 0.5, true, theErrorPoint);

                                            DataQualityError theError = new DataQualityError(this.Name, canDefer, canExcept);
                                            theError.Location = theErrorPoint;

                                            // If it's in the smallest 10% of the search radius, mark high severity
                                            // 50%, medium
                                            if (dist <= theSearchRadius / 10)
                                                theError.Severity = 1;
                                            else if (dist <= theSearchRadius / 2)
                                                theError.Severity = 2;
                                            else
                                                theError.Severity = 3;

                                            theError.Description = "Points almost but not quite co-located";

                                            ExtendedInfo theExtInfo = new ExtendedInfo();

                                            theExtInfo.AddProperty("Feature class 1", theDataset1.Name);
                                            theExtInfo.AddProperty("Feature class 2", theDataset2.Name);
                                            if (theLayer1.FeatureClass.HasOID)
                                                theExtInfo.AddProperty("Feature ID 1", theIdxPoint.SourceFeatureID.ToString());
                                            if (theLayer2.FeatureClass.HasOID)
                                                theExtInfo.AddProperty("Feature ID 2", theFeature2.OID.ToString());
                                            theExtInfo.AddProperty("Distance", String.Format("{0:0.## metres}", dist));
                                            theExtInfo.AddProperty("From point x", thePolyline.FromPoint.X.ToString());
                                            theExtInfo.AddProperty("From point y", thePolyline.FromPoint.Y.ToString());
                                            theExtInfo.AddProperty("To point x", thePolyline.ToPoint.X.ToString());
                                            theExtInfo.AddProperty("To point y", thePolyline.ToPoint.Y.ToString());

                                            theError.ExtendedData = theExtInfo.WriteXML();
                                            //this.LogMessage(theError.ExtendedData);
                                            this._errors.Add(theError);
                                        }
                                    }
                                }

                                theFeature2 = theFCursor2.NextFeature();
                            }
                        }
                    }
                }

                this.LogMessage("Number of errors found: " + this.ErrorCount);
                this.LogMessage("Test " + this.Name + " successful.");
            }
            catch (Exception ex)
            {
                this.LogMessage("Exception caught: \n" + ex.Message + "\n" + ex.StackTrace.ToString());
                this.LogMessage("id of the current polygon: " + currentOid);
                return -1;
            }
            finally
            {
                this.StopLogging();
            }

            return this.ErrorCount;
        }
Пример #10
0
        private void CheckSIDs(IFeatureClass workingFeatureClass, IFeatureCursor checkCursor, string sidFieldName,
			bool canDefer, bool canExcept)
        {
            IDataset theDS2 = (IDataset)workingFeatureClass;
            Hashtable theLookup = new Hashtable();

            try
            {
                int sidIndex = workingFeatureClass.FindField(sidFieldName);

                IFeature theFeature = checkCursor.NextFeature();
                while (theFeature != null)
                {
                    object theSID = theFeature.get_Value(sidIndex);
                    if (theSID == null || Convert.IsDBNull(theSID))
                    {
                        // Error
                        IPoint theErrorPoint = this.get_ErrorPoint(theFeature.Shape);

                        DataQualityError theError = new DataQualityError(this.Name, canDefer, canExcept);
                        theError.Location = theErrorPoint;
                        theError.Severity = 1;

                        theError.Description = "Null SID";

                        ExtendedInfo theInfo = new ExtendedInfo();

                        theInfo.AddProperty("Feature class", theDS2.Name);
                        theInfo.AddProperty("Feature ID", theFeature.OID.ToString());

                        theError.ExtendedData = theInfo.WriteXML();
                        //this.LogMessage(theError.ExtendedData);
                        this._errors.Add(theError);
                    }
                    else if (theLookup.ContainsKey(theSID))
                    {
                        // Error
                        IPoint theErrorPoint = this.get_ErrorPoint(theFeature.Shape);

                        DataQualityError theError = new DataQualityError(this.Name, canDefer, canExcept);
                        theError.Location = theErrorPoint;
                        theError.Severity = 1;

                        theError.Description = "Non-unique SID";

                        ExtendedInfo theInfo = new ExtendedInfo();

                        theInfo.AddProperty("Feature class", theDS2.Name);
                        theInfo.AddProperty("Feature ID", theFeature.OID.ToString());

                        object sidValue = theFeature.get_Value(sidIndex);
                        theInfo.AddProperty("SID value", sidValue.ToString());

                        theError.ExtendedData = theInfo.WriteXML();
                        //this.LogMessage(theError.ExtendedData);
                        this._errors.Add(theError);
                    }
                    else
                    {
                        theLookup.Add(theSID, theSID);
                    }

                    theFeature = checkCursor.NextFeature();
                }
            }
            catch (Exception ex)
            {
                this.LogMessage("Error checking SID uniqueness and completeness:" + Environment.NewLine
                    + ex.Message + Environment.NewLine + ex.StackTrace);
            }
        }
Пример #11
0
        private ArrayList ProcessFeature(IFeature test, SegmentCollectionIndex index,
			double searchRadius, double aspectRatio, bool canDefer, bool canExcept)
        {
            if (test == null || test.Shape == null || test.Shape.IsEmpty)
                return null;

            ArrayList theReturn = new ArrayList();

            IDataset theDataset = (IDataset)test.Table;

            IGeometry theTestShape = test.ShapeCopy;
            theTestShape.Project(SpatialReferenceHelper.BCAlbersSpatialReference);
            ISegmentCollection theSegColl = (ISegmentCollection)theTestShape;
            ISegment theSegment;

            for (int i = 0; i < theSegColl.SegmentCount; i++)
            {
                theSegment = theSegColl.get_Segment(i);
                int theNeatlineOID;
                double dist1 = index.get_MinimumDistance(theSegment.FromPoint, out theNeatlineOID);
                if (dist1 <= searchRadius)
                {
                    double dist2 = index.get_MinimumDistance(theSegment.ToPoint, out theNeatlineOID);
                    if (dist2 <= searchRadius)
                    {
                        if (Math.Abs(dist1 - dist2) < theSegment.Length / aspectRatio)
                        {
                            // Error point will be 1/2 way along segment
                            IPolyline thePolyline = new PolylineClass();
                            thePolyline.Project(SpatialReferenceHelper.BCAlbersSpatialReference);
                            ((ISegmentCollection)thePolyline).AddSegment(theSegment, ref this._missing, ref this._missing);
                            thePolyline.Project(SpatialReferenceHelper.GeographicReference);

                            IPoint theErrorPoint = new PointClass();
                            thePolyline.QueryPoint(esriSegmentExtension.esriNoExtension, 0.5, true, theErrorPoint);

                            DataQualityError theError = new DataQualityError(this.Name, canDefer, canExcept);
                            theError.Location = theErrorPoint;

                            // If it's in the smallest 10% of the search radius, mark high severity
                            // 50%, medium
                            double avgDist = (dist1 + dist2) / 2;
                            if (avgDist <= searchRadius / 10)
                                theError.Severity = 1;
                            else if (avgDist <= searchRadius / 2)
                                theError.Severity = 2;
                            else
                                theError.Severity = 3;

                            theError.Description = "Line segment co-linear with neatline";

                            ExtendedInfo theInfo = new ExtendedInfo();

                            theInfo.AddProperty("Feature class", theDataset.Name);
                            if (test.HasOID)
                                theInfo.AddProperty("Feature ID", test.OID.ToString());
                            theInfo.AddProperty("Neatline Feature ID", theNeatlineOID.ToString());
                            theInfo.AddProperty("Distance", String.Format("{0:0.## metres}", avgDist));
                            theInfo.AddProperty("From point x", thePolyline.FromPoint.X.ToString());
                            theInfo.AddProperty("From point y", thePolyline.FromPoint.Y.ToString());
                            theInfo.AddProperty("To point x", thePolyline.ToPoint.X.ToString());
                            theInfo.AddProperty("To point y", thePolyline.ToPoint.Y.ToString());

                            theError.ExtendedData = theInfo.WriteXML();
                            //this.LogMessage(theError.ExtendedData);
                            theReturn.Add(theError);
                        }
                    }
                }
            }
            return theReturn;
        }
Пример #12
0
        private ArrayList WeedErrors(ArrayList potentialList, bool canDefer, bool canExcept, double minGap, double maxGap)
        {
            /*
             * Finds the smallest gap between a given source feature vertex and another feature
             * This cuts down on the noise considerably. Without this, a source vertex could show
             * gap errors to multiple vertices on another feature if those vertices were closer
             * than the maxGap
             */
            ArrayList theReturn = new ArrayList();

            // Organize the errors by key
            // Key is defined as source oid + source vertex # + other oid
            Hashtable theHash = new Hashtable();
            foreach (object obj in potentialList)
            {
                PotentialError thePError = (PotentialError)obj;
                string key = thePError.Key;
                ArrayList theErrorsWithSameKey;
                if (theHash.ContainsKey(key) == false)
                {
                    theErrorsWithSameKey = new ArrayList(2);
                    theHash.Add(key, theErrorsWithSameKey);
                }
                else
                {
                    theErrorsWithSameKey = (ArrayList)theHash[key];
                }
                theErrorsWithSameKey.Add(thePError);
            }

            // Get the PotentialError with the smallest GapSize
            foreach (object key in theHash.Keys)
            {
                ArrayList theErrorsWithSameKey = (ArrayList)theHash[key];
                PotentialError theSmallest = null;

                foreach (object obj in theErrorsWithSameKey)
                {
                    PotentialError thePError = (PotentialError)obj;
                    if (theSmallest == null || thePError.GapSize < theSmallest.GapSize)
                        theSmallest = thePError;
                }

                if (theSmallest != null)
                {
                    DataQualityError theError = new DataQualityError(this.Name, canDefer, canExcept);
                    theError.Location = theSmallest.ErrorPoint;

                    // If it's in the smallest 10% of the gap range, mark high severity
                    if (theSmallest.GapSize < (minGap + ((maxGap - minGap) / 10)))
                        theError.Severity = 1;
                    else
                        theError.Severity = 2;

                    theError.Description = "Gap between polygons";

                    ExtendedInfo theInfo = new ExtendedInfo();

                    theInfo.AddProperty("Feature class", theSmallest.FeatureClassName);
                    theInfo.AddProperty("Gap size", String.Format("{0:0.## metres}", theSmallest.GapSize));
                    theInfo.AddProperty("Angle", String.Format("{0:0.## degrees}", theSmallest.AngleDegrees));
                    theInfo.AddProperty("From point x", theSmallest.FromPoint.X.ToString());
                    theInfo.AddProperty("From point y", theSmallest.FromPoint.Y.ToString());
                    theInfo.AddProperty("To point x", theSmallest.ToPoint.X.ToString());
                    theInfo.AddProperty("To point y", theSmallest.ToPoint.Y.ToString());

                    theError.ExtendedData = theInfo.WriteXML();
                    //this.LogMessage(theError.ExtendedData);
                    theReturn.Add(theError);
                }
            }

            return theReturn;
        }
Пример #13
0
        private ArrayList ProcessFeature(IFeature test)
        {
            if (test == null || test.Shape == null || test.Shape.IsEmpty)
                return null;

            ArrayList theReturn = new ArrayList();

            int index = this.FindParameter("minimum-allowable-ap-ratio");
            double apRatio = Math.Abs((double)((ParameterInfo)this._params[index]).ParamValue);
            index = this.FindParameter(ParameterInfo.PARAM_CANDEFER);
            bool canDefer = (bool)((ParameterInfo)this._params[index]).ParamValue;
            index = this.FindParameter(ParameterInfo.PARAM_CANEXCEPT);
            bool canExcept = (bool)((ParameterInfo)this._params[index]).ParamValue;

            IGeometry theGeometry = test.Shape;
            bool bNeedProjection = !SpatialReferenceHelper.IsBCAlbers(theGeometry.SpatialReference);
            if (bNeedProjection)
                theGeometry.Project(SpatialReferenceHelper.BCAlbersSpatialReference);

            IGeometryCollection theGeomColl = (IGeometryCollection)test.Shape;
            for (int i = 0; i < theGeomColl.GeometryCount; i++)
            {
                IGeometry theGeometryPart = theGeomColl.get_Geometry(i);
                IArea theArea = (IArea)theGeometryPart;

                if (theArea.Area > 0)
                {
                    ICurve theCurve = (ICurve)theGeometryPart;
                    double calculatedAP = theArea.Area / theCurve.Length;

                    if (calculatedAP < apRatio)
                    {
                        IPoint theErrorPoint = this.get_ErrorPoint(theGeometryPart);
                        theErrorPoint.Project(SpatialReferenceHelper.GeographicReference);

                        DataQualityError theError = new DataQualityError(this.Name, canDefer, canExcept);
                        theError.Location = theErrorPoint;

                        if (calculatedAP < apRatio / 10)
                            theError.Severity = 1;
                        else if (calculatedAP < apRatio / 2)
                            theError.Severity = 2;
                        else
                            theError.Severity = 3;

                        theError.Description = "Sliver polygon";

                        ExtendedInfo theInfo = new ExtendedInfo();
                        IDataset theDataset = (IDataset)test.Table;

                        theInfo.AddProperty("Feature class", theDataset.Name);
                        theInfo.AddProperty("Feature ID", test.OID.ToString());
                        theInfo.AddProperty("Part area", String.Format("{0:0.##}", theArea.Area) + " sq. metres");
                        theInfo.AddProperty("Area/Perimeter ratio", String.Format("{0:0.##}", calculatedAP));

                        theError.ExtendedData = theInfo.WriteXML();
                        //this.LogMessage(theError.ExtendedData);
                        theReturn.Add(theError);
                    }
                }
            }

            return theReturn;
        }
Пример #14
0
        private ArrayList ProcessFeature(ITopologyErrorFeature test, IDataset source, string subtypeName,
			double maxOverlap, double minOverlap)
        {
            if (test == null)
                return null;

            IFeature theTestFeature = (IFeature)test;
            if (theTestFeature.Shape == null || theTestFeature.Shape.IsEmpty)
                return null;

            if (test.ShapeType != esriGeometryType.esriGeometryPolygon)
                return null;

            ArrayList theReturn = new ArrayList();

            int index = this.FindParameter(ParameterInfo.PARAM_CANDEFER);
            bool canDefer = (bool)((ParameterInfo)this._params[index]).ParamValue;
            index = this.FindParameter(ParameterInfo.PARAM_CANEXCEPT);
            bool canExcept = (bool)((ParameterInfo)this._params[index]).ParamValue;

            IGeometry theGeometry = theTestFeature.ShapeCopy;
            theGeometry.Project(SpatialReferenceHelper.BCAlbersSpatialReference);

            // Is/isn't an error based on the full area of the error
            IArea theArea = (IArea)theGeometry;
            bool isError = (theArea.Area > minOverlap && theArea.Area < maxOverlap);

            if (isError)
            {
                // Severity is based on parts
                IGeometryCollection theGeomColl = (IGeometryCollection)theGeometry;
                for (int i = 0; i < theGeomColl.GeometryCount; i++)
                {
                    IGeometry theGeometryPart = theGeomColl.get_Geometry(i);
                    IArea thePartArea = (IArea)theGeometryPart;

                    if (thePartArea.Area > 0)
                    {
                        IPoint theErrorPoint = this.get_ErrorPoint(theGeometryPart);
                        theErrorPoint.Project(SpatialReferenceHelper.GeographicReference);

                        DataQualityError theError = new DataQualityError(this.Name, canDefer, canExcept);
                        theError.Location = theErrorPoint;

                        if (thePartArea.Area > minOverlap && thePartArea.Area < maxOverlap)
                            theError.Severity = 1;
                        else
                            theError.Severity = 2;

                        theError.Description = "Polygons overlap";

                        ExtendedInfo theInfo = new ExtendedInfo();

                        theInfo.AddProperty("Feature class", source.Name);
                        theInfo.AddProperty("Feature subtype", subtypeName);
                        theInfo.AddProperty("Feature ID #1", test.OriginOID.ToString());
                        theInfo.AddProperty("Feature ID #2", test.DestinationOID.ToString());
                        theInfo.AddProperty("Area", thePartArea.Area.ToString());

                        theError.ExtendedData = theInfo.WriteXML();
                        //this.LogMessage(theError.ExtendedData);
                        theReturn.Add(theError);
                    }
                }
            }

            return theReturn;
        }
Пример #15
0
        private ArrayList CheckFeatureTypes(
			IFeatureClass workingFeatureClass,
			string unqualifiedFClassName,
			IFeatureCursor checkCursor,
			string ftFieldName,
			Hashtable featureTypeData,
			bool canDefer,
			bool canExcept)
        {
            ArrayList theReturn = new ArrayList();

            IDataset theDS2 = (IDataset)workingFeatureClass;

            int ftIndex = workingFeatureClass.FindField(ftFieldName);

            int stIndex = -1;
            if (workingFeatureClass is ISubtypes && ((ISubtypes)workingFeatureClass).HasSubtype)
            {
                ISubtypes theST = (ISubtypes)workingFeatureClass;
                stIndex = theST.SubtypeFieldIndex;
            }

            try
            {
                IFeature theFeature = checkCursor.NextFeature();
                while (theFeature != null)
                {
                    object theFCode = theFeature.get_Value(ftIndex);
                    if (theFCode == null || Convert.IsDBNull(theFCode))
                    {
                        // Null FCode Error
                        IPoint theErrorPoint = this.get_ErrorPoint(theFeature.Shape);

                        DataQualityError theError = new DataQualityError(this.Name, canDefer, canExcept);
                        theError.Location = theErrorPoint;
                        theError.Severity = 1;

                        theError.Description = "Null Feature Code";

                        ExtendedInfo theInfo = new ExtendedInfo();

                        theInfo.AddProperty("Feature class", theDS2.Name);
                        theInfo.AddProperty("Feature ID", theFeature.OID.ToString());

                        theError.ExtendedData = theInfo.WriteXML();
                        //this.LogMessage(theError.ExtendedData);
                        theReturn.Add(theError);
                    }
                    else
                    {
                        // Determine the featureclass/subtype
                        theFCode = theFCode.ToString();
                        string theKey = unqualifiedFClassName;
                        if (stIndex >= 0)
                            theKey += ":" + theFeature.get_Value(stIndex);

                        // Get the allowed set of feature codes
                        Hashtable theAllowedCodes = null;
                        if (featureTypeData.ContainsKey(theKey))
                            theAllowedCodes = (Hashtable)featureTypeData[theKey];

                        if (theAllowedCodes == null)
                        {
                            // Unknown subtype error
                            IPoint theErrorPoint = this.get_ErrorPoint(theFeature.Shape);

                            DataQualityError theError = new DataQualityError(this.Name, canDefer, canExcept);
                            theError.Location = theErrorPoint;
                            theError.Severity = 1;

                            theError.Description = "Unknown Subtype Code";

                            ExtendedInfo theInfo = new ExtendedInfo();

                            theInfo.AddProperty("Feature class", theDS2.Name);
                            theInfo.AddProperty("Feature ID", theFeature.OID.ToString());
                            theInfo.AddProperty("Subtype", theFeature.get_Value(stIndex).ToString());

                            theError.ExtendedData = theInfo.WriteXML();
                            //this.LogMessage(theError.ExtendedData);
                            theReturn.Add(theError);
                        }
                        else if (theAllowedCodes.ContainsKey(theFCode) == false)
                        {
                            // Invalid FCode Error
                            IPoint theErrorPoint = this.get_ErrorPoint(theFeature.Shape);

                            DataQualityError theError = new DataQualityError(this.Name, canDefer, canExcept);
                            theError.Location = theErrorPoint;
                            theError.Severity = 1;

                            theError.Description = "Invalid Feature Type";

                            ExtendedInfo theInfo = new ExtendedInfo();

                            theInfo.AddProperty("Feature class", theDS2.Name);
                            theInfo.AddProperty("Feature ID", theFeature.OID.ToString());
                            if (stIndex >= 0)
                                theInfo.AddProperty("Subtype", theFeature.get_Value(stIndex).ToString());

                            string theCodes = "";
                            string theDescs = "";
                            foreach (object key in theAllowedCodes.Keys)
                            {
                                if (theCodes.Length > 0)
                                {
                                    theCodes += ", ";
                                    theDescs += ", ";
                                }
                                theCodes += key;
                                theDescs += theAllowedCodes[key];
                            }
                            theInfo.AddProperty("Allowed feature codes", theCodes);
                            theInfo.AddProperty("Allowed feature types", theDescs);
                            theInfo.AddProperty("Feature type", theFCode.ToString());

                            theError.ExtendedData = theInfo.WriteXML();
                            //this.LogMessage(theError.ExtendedData);
                            theReturn.Add(theError);
                        }
                    }

                    theFeature = checkCursor.NextFeature();
                }
            }
            catch (Exception ex)
            {
                this.LogMessage("Error checking feature codes:" + Environment.NewLine
                    + ex.Message + Environment.NewLine + ex.StackTrace);
            }

            return theReturn;
        }