Пример #1
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);
                }
            }
        }
Пример #2
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;
        }