Example #1
0
        /// <summary>
        /// Sets the environment for raster analysis.
        /// </summary>
        /// <param name="pWS"></param>
        /// <param name="pEnv"></param>
        /// <param name="pSR"></param>
        /// <param name="dCellSize"></param>
        /// <param name="pMask"></param>
        private void SetRasterAnalysisEnvironment(IWorkspace pWS, IEnvelope pEnv, ISpatialReference pSR, Double dCellSize, IGeoDataset pMask)
        {
            IRasterAnalysisEnvironment pRAE = new RasterAnalysisClass();
            object oEnv      = pEnv;
            object oCellSize = dCellSize;
            object oBool     = true;

            try
            {
                if (pWS != null)
                {
                    pRAE.OutWorkspace = pWS;
                }
                if (pEnv != null)
                {
                    pRAE.SetExtent(esriRasterEnvSettingEnum.esriRasterEnvValue, ref oEnv, ref oBool);
                }
                if (pSR != null)
                {
                    pRAE.OutSpatialReference = pSR;
                }
                if (dCellSize > 0)
                {
                    pRAE.SetCellSize(esriRasterEnvSettingEnum.esriRasterEnvValue, ref oCellSize);
                }
                if (pMask != null)
                {
                    pRAE.Mask = pMask;
                }
                pRAE.VerifyType = esriRasterVerifyEnum.esriRasterVerifyOff;
                //TIM: we need to make sure this gets set back at some point
                pRAE.SetAsNewDefaultEnvironment();
            }
            catch (Exception ex)
            {
                clsStatic.ShowErrorMessage(ex.ToString());
            }
        }
Example #2
0
        internal static RasterExtractionResult SummariseRaster(IGeoDataset pClippingPolygon, ExtractionLayerConfig pExtractionLayerConfig)
        {
            // set the analysis extent to be that of the polygon
            ServerLogger logger = new ServerLogger();

            logger.LogMessage(ServerLogger.msgType.debug, "SummariseCategoricalRaster", 99, "Categorical raster clip beginning..");
            IEnvelope tAnalysisExtent = pClippingPolygon.Extent;

            bool        pCategoricalSummary = pExtractionLayerConfig.ExtractionType == ExtractionTypes.CategoricalRaster;
            IGeoDataset pRasterToClip       = pExtractionLayerConfig.LayerDataset;

            IRasterAnalysisEnvironment tRasterAnalysisEnvironment = new RasterAnalysisClass();
            object tAnalysisEnvelopeCastToObject = (System.Object)tAnalysisExtent;
            // object tAnotherBizarreMissingObject = Type.Missing;
            object tSnapObject = (System.Object)pRasterToClip;

            tRasterAnalysisEnvironment.SetExtent(esriRasterEnvSettingEnum.esriRasterEnvValue,
                                                 ref tAnalysisEnvelopeCastToObject, ref tSnapObject);
            tRasterAnalysisEnvironment.SetAsNewDefaultEnvironment();
            // extract the subset of the raster
            IExtractionOp2 tExtractionOp = new RasterExtractionOpClass();
            // note we want to base the extraction on a raster (in an IGeoDataset) rather than an IPolygon.
            // That's because the catchment polygon may be multipart, and the operation doesn't work with multipart.
            // Also the polygon has a max of 1000 vertices.
            // And raster mask extraction is probably faster since the
            // polygon is converted internally to a grid anyway.
            IGeoDataset tClipped;

            if (pRasterToClip as IRaster != null)
            {
                logger.LogMessage(ServerLogger.msgType.debug, "SummariseRaster", 99,
                                  "Input was in raster form, using directly to clip...");
                tClipped = tExtractionOp.Raster(pRasterToClip, pClippingPolygon);
            }
            else
            {
                // POLYGON VERSION: tExtractionOp.Polygon(pClipRaster,pPolygon,true)
                // sometimes we need to be able to pass in a polygon but rather than using the polygon
                // method we'll manually convert to a mask raster to avoid the issues above
                // It would save work to do this once for each request rather than repeat the conversion
                // for each layer - but we might want a different environment (snap extent etc) for each.
                logger.LogMessage(ServerLogger.msgType.debug, "SummariseCategoricalRaster", 99,
                                  "Converting input polygon to mask raster for clip...");
                IRasterConvertHelper tConvertPolygonToRaster = new RasterConvertHelperClass();
                // convert it to a raster with the same cell size as the input
                IRasterProps tRst         = pRasterToClip as IRasterProps;
                IPnt         tRstCellSize = tRst.MeanCellSize();
                double       x            = tRstCellSize.X;
                double       y            = tRstCellSize.Y;
                double       cellSize     = Math.Round(Math.Min(x, y), 0);
                object       tCellSizeAsObjectForNoGoodReason = (System.Object)cellSize;
                tRasterAnalysisEnvironment.SetCellSize(esriRasterEnvSettingEnum.esriRasterEnvValue,
                                                       ref tCellSizeAsObjectForNoGoodReason);
                IGeoDataset tPolyAsRast =
                    tConvertPolygonToRaster.ToRaster1(pRasterToClip, "GRID", tRasterAnalysisEnvironment)
                    as IGeoDataset;
                logger.LogMessage(ServerLogger.msgType.debug, "SummariseCategoricalRaster", 99,
                                  "...done, proceeding with clip");
                tClipped = tExtractionOp.Raster(pRasterToClip, tPolyAsRast);
            }
            // now we have the clipped raster we need to summarise it differently depending on whether
            // we want a summary by category/value (for categorical rasters) or by stats (for float rasters)
            Dictionary <string, double> tResults;

            if (pCategoricalSummary)
            {
                tResults = WatershedDetailExtraction.SummariseRasterCategorically(tClipped);
                if (tResults.Count > 100)
                {
                    // sanity check: don't sum up more than 100 different values
                    tResults            = WatershedDetailExtraction.SummariseRasterStatistically(tClipped);
                    pCategoricalSummary = false;
                }
            }
            else
            {
                tResults = WatershedDetailExtraction.SummariseRasterStatistically(tClipped);
            }
            tRasterAnalysisEnvironment.RestoreToPreviousDefaultEnvironment();
            return(new RasterExtractionResult(pExtractionLayerConfig.ParamName, pCategoricalSummary, tResults));
            //return tResults;
        }
        /// <summary>
        /// return operation watershed handler
        /// </summary>
        /// <param name="boundVariables">>bound Variables</param>
        /// <param name="operationInput">operation Input</param>
        /// <param name="outputFormat">output Format</param>
        /// <param name="requestProperties">request Properties</param>
        /// <param name="responseProperties">response Properties</param>
        /// <returns>operation watershed handler</returns>
        private byte[] OperationWatershedHandler(NameValueCollection boundVariables, JsonObject operationInput, string outputFormat, string requestProperties, out string responseProperties)
        {
            responseProperties = null;

            long?idWatershed;

            if (operationInput.Exists("idWatershed"))
            {
                if (!operationInput.TryGetAsLong("idWatershed", out idWatershed))
                {
                    throw new ArgumentNullException("idWatershed");
                }
            }
            else
            {
                idWatershed = 0;
            }

            JsonObject jsonObjectPoint;

            if (!operationInput.TryGetJsonObject("location", out jsonObjectPoint))
            {
                throw new ArgumentNullException("location");
            }

            IPoint location = Conversion.ToGeometry(jsonObjectPoint, esriGeometryType.esriGeometryPoint) as IPoint;

            if (location == null)
            {
                throw new ArgumentException("Invalid location", "location");
            }

            double?snapDistance;

            if (!operationInput.TryGetAsDouble("snapDistance", out snapDistance))
            {
                throw new ArgumentNullException("snapDistance");
            }

            snapDistance = snapDistance ?? 0.0;

            long?idAccumulation;

            if (!operationInput.TryGetAsLong("idAccumulation", out idAccumulation) || !idAccumulation.HasValue)
            {
                throw new ArgumentNullException("idAccumulation");
            }

            long?idDirection;

            if (!operationInput.TryGetAsLong("idDirection", out idDirection) || !idDirection.HasValue)
            {
                throw new ArgumentNullException("idDirection");
            }

            string methodName = MethodBase.GetCurrentMethod().Name;

            try
            {
                IFeatureWorkspace featureWorkspace = Helper.CreateInMemoryWorkspace() as IFeatureWorkspace;
                IFeatureClass     featureClass     = this.CreateFeatureClass(location, featureWorkspace);

                IFeature feature = featureClass.CreateFeature();
                feature.Shape = location;
                feature.set_Value(featureClass.FindField(SAUtility.FieldNameIdWatershed), (int)idWatershed.Value);
                feature.Store();

                IHydrologyOp hydrologyOp = new RasterHydrologyOp() as IHydrologyOp;

                IGeoDataset accumulation = this.GetGeodataset((int)idAccumulation.Value);
                IGeoDataset direction    = this.GetGeodataset((int)idDirection.Value);

                IFeatureClassDescriptor featureClassDescriptor = new FeatureClassDescriptorClass();
                featureClassDescriptor.Create(featureClass, null, SAUtility.FieldNameIdWatershed);
                IGeoDataset pourPoint = featureClassDescriptor as IGeoDataset;

                IRasterAnalysisEnvironment rasterAnalysisEnvironment = new RasterAnalysisClass();
                object extentProvider = Type.Missing;
                object snapRasterData = Type.Missing;
                rasterAnalysisEnvironment.SetExtent(esriRasterEnvSettingEnum.esriRasterEnvMaxOf, ref extentProvider, ref snapRasterData);

                IGeoDataset snapRaster = hydrologyOp.SnapPourPoint(pourPoint, accumulation, snapDistance.Value);

                IGeoDataset watershed = hydrologyOp.Watershed(direction, snapRaster);

                IConversionOp conversionOp          = new RasterConversionOpClass() as IConversionOp;
                IGeoDataset   featureClassWatershed = conversionOp.RasterDataToPolygonFeatureData(watershed, featureWorkspace as IWorkspace, "WatershedPolygon", true);

                IRecordSetInit recordset = new RecordSetClass();
                recordset.SetSourceTable(featureClassWatershed as ITable, null);

                byte[] recorset = Conversion.ToJson(recordset as IRecordSet);
                this.logger.LogMessage(ServerLogger.msgType.infoDetailed, methodName, SAUtility.MessageCodeSOE, string.Format("Watershed created with succcess. IdWatershed {0}", (int)idWatershed.Value));
                return(recorset);
            }
            catch (Exception ex)
            {
                this.logger.LogMessage(ServerLogger.msgType.error, methodName, SAUtility.MessageCodeSOE, ex.Message);
                return(new ObjectError("error create watershed").ToJsonObject().JsonByte());
            }
        }
        private KeyValuePair<IGeoDataset, IGeoDataset> computeWatershed(IPoint pour_point, IEnvelope analysisExtent)
        {
            try
            {
                //bodge the input point into its nasty shell of arcobjects junk for analysis
                IHydrologyOp pHydrologyOp = new RasterHydrologyOp() as IHydrologyOp;
                IPointCollection3 tPointCollection = new MultipointClass();
                object tPointlessMissingObject = Type.Missing;
                tPointCollection.AddPoint(pour_point, ref tPointlessMissingObject, ref tPointlessMissingObject);

                // open the accumulation and direction datasets, hardcoded
                //IGeoDataset tAccum = OpenRasterDataset(data_path, accum_name) as IGeoDataset;
                //IGeoDataset tDirection = OpenRasterDataset(data_path, dir_name) as IGeoDataset;
                //bodge the input extent into its nasty shell of arcobjects junk
                IRasterAnalysisEnvironment tRasterAnalysisEnvironment = new RasterAnalysisClass();
                if (analysisExtent != null)
                {
                    IRelationalOperator tCheckRequestedExtent = analysisExtent as IRelationalOperator;
                    if (tCheckRequestedExtent != null && tCheckRequestedExtent.Contains(pour_point))
                    {
                        // can anyone explain why these things have to be objects? Why can't there be interfaces
                        // for AnalysisExtentProvider and SnapObject that the datasets implement?
                        object tAnalysisEnvelopePointlesslyCastedToObject = (System.Object)analysisExtent;
                        object tAnotherPointlessMissingObject = Type.Missing;
                        //object tSnapObject = (System.Object)tDirection;
                        object tSnapObject = (System.Object)m_FlowDirDataset;
                        tRasterAnalysisEnvironment.SetExtent(esriRasterEnvSettingEnum.esriRasterEnvValue,
                            ref tAnalysisEnvelopePointlesslyCastedToObject, ref tSnapObject);
                        tRasterAnalysisEnvironment.SetAsNewDefaultEnvironment();
                    }
                    else
                    {
                        logger.LogMessage(ServerLogger.msgType.warning, "create watershed", 8000,
                            "Input point was not within requested analysis extent. Analysis extent will be ignored (may be slow)!");
                    }
                }
                else
                {
                    logger.LogMessage(ServerLogger.msgType.warning, "create watershed", 8000,
                        "No analysis extent requested. Full extent will be used (may be slow)!");

                }
                IExtractionOp tExtractionOp = new RasterExtractionOpClass();

                // Do the work: snap the point to a snapped-pour-point grid and use it to calcualte the watershed
                //IGeoDataset tPourPointGrid = tExtractionOp.Points(tDirection, tPointCollection, true);
                IGeoDataset tPourPointGrid = tExtractionOp.Points(m_FlowDirDataset, tPointCollection, true);
                //IGeoDataset snapRaster = pHydrologyOp.SnapPourPoint(tPourPointGrid, tAccum, 100);
                IGeoDataset snapRaster = pHydrologyOp.SnapPourPoint(tPourPointGrid, m_FlowAccDataset, 100);
                // check the snapping worked..?
                // calculate the watershed!
                //IGeoDataset watershedRaster = pHydrologyOp.Watershed(tDirection, snapRaster);
                IGeoDataset watershedRaster = pHydrologyOp.Watershed(m_FlowDirDataset, snapRaster);
                //  restore previous default analysis extent if we changed it (should = whole dataset)
                if (analysisExtent != null)
                {
                    tRasterAnalysisEnvironment.RestoreToPreviousDefaultEnvironment();
                }
                // change it to a polygon feature (will have the area added) and return it
                IGeoDataset tWatershedPolygonGDS = ConvertAndUnionWatershed(watershedRaster);
                KeyValuePair<IGeoDataset, IGeoDataset> tRasterPolyPair = new KeyValuePair<IGeoDataset, IGeoDataset>(watershedRaster, tWatershedPolygonGDS);
                return tRasterPolyPair;
            }
            catch (Exception e)
            {
                logger.LogMessage(ServerLogger.msgType.infoStandard, "Compute watershed error: ", 8000, e.Message);
                logger.LogMessage(ServerLogger.msgType.infoStandard, "Compute watershed error: ", 8000, e.ToString());
                logger.LogMessage(ServerLogger.msgType.infoStandard, "Compute watershed error: ", 8000, e.TargetSite.Name);
                logger.LogMessage(ServerLogger.msgType.infoStandard, "Compute watershed error: ", 8000, e.StackTrace);
            }
            return new KeyValuePair<IGeoDataset, IGeoDataset>();
        }
        internal static RasterExtractionResult SummariseRaster(IGeoDataset pClippingPolygon, ExtractionLayerConfig pExtractionLayerConfig)
        {
            // set the analysis extent to be that of the polygon
            ServerLogger logger = new ServerLogger();
            logger.LogMessage(ServerLogger.msgType.debug, "SummariseCategoricalRaster", 99, "Categorical raster clip beginning..");
            IEnvelope tAnalysisExtent = pClippingPolygon.Extent;

            bool pCategoricalSummary = pExtractionLayerConfig.ExtractionType==ExtractionTypes.CategoricalRaster;
            IGeoDataset pRasterToClip = pExtractionLayerConfig.LayerDataset;

            IRasterAnalysisEnvironment tRasterAnalysisEnvironment = new RasterAnalysisClass();
            object tAnalysisEnvelopeCastToObject = (System.Object)tAnalysisExtent;
               // object tAnotherBizarreMissingObject = Type.Missing;
            object tSnapObject = (System.Object)pRasterToClip;
            tRasterAnalysisEnvironment.SetExtent(esriRasterEnvSettingEnum.esriRasterEnvValue,
                ref tAnalysisEnvelopeCastToObject, ref tSnapObject);
            tRasterAnalysisEnvironment.SetAsNewDefaultEnvironment();
            // extract the subset of the raster
            IExtractionOp2 tExtractionOp = new RasterExtractionOpClass();
            // note we want to base the extraction on a raster (in an IGeoDataset) rather than an IPolygon.
            // That's because the catchment polygon may be multipart, and the operation doesn't work with multipart.
            // Also the polygon has a max of 1000 vertices.
            // And raster mask extraction is probably faster since the
            // polygon is converted internally to a grid anyway.
            IGeoDataset tClipped;
            if (pRasterToClip as IRaster != null)
            {
                logger.LogMessage(ServerLogger.msgType.debug, "SummariseRaster", 99,
                    "Input was in raster form, using directly to clip...");
                tClipped = tExtractionOp.Raster(pRasterToClip, pClippingPolygon);
            }
            else
            {
                // POLYGON VERSION: tExtractionOp.Polygon(pClipRaster,pPolygon,true)
                // sometimes we need to be able to pass in a polygon but rather than using the polygon
                // method we'll manually convert to a mask raster to avoid the issues above
                // It would save work to do this once for each request rather than repeat the conversion
                // for each layer - but we might want a different environment (snap extent etc) for each.
                logger.LogMessage(ServerLogger.msgType.debug, "SummariseCategoricalRaster", 99,
                    "Converting input polygon to mask raster for clip...");
                IRasterConvertHelper tConvertPolygonToRaster = new RasterConvertHelperClass();
                // convert it to a raster with the same cell size as the input
                IRasterProps tRst = pRasterToClip as IRasterProps;
                IPnt tRstCellSize = tRst.MeanCellSize();
                double x = tRstCellSize.X;
                double y = tRstCellSize.Y;
                double cellSize = Math.Round(Math.Min(x, y), 0);
                object tCellSizeAsObjectForNoGoodReason = (System.Object)cellSize;
                tRasterAnalysisEnvironment.SetCellSize(esriRasterEnvSettingEnum.esriRasterEnvValue,
                    ref tCellSizeAsObjectForNoGoodReason);
                IGeoDataset tPolyAsRast =
                    tConvertPolygonToRaster.ToRaster1(pRasterToClip, "GRID", tRasterAnalysisEnvironment)
                as IGeoDataset;
                logger.LogMessage(ServerLogger.msgType.debug, "SummariseCategoricalRaster", 99,
                    "...done, proceeding with clip");
                tClipped = tExtractionOp.Raster(pRasterToClip, tPolyAsRast);
            }
            // now we have the clipped raster we need to summarise it differently depending on whether
            // we want a summary by category/value (for categorical rasters) or by stats (for float rasters)
            Dictionary<string, double> tResults;
            if (pCategoricalSummary)
            {
                tResults = WatershedDetailExtraction.SummariseRasterCategorically(tClipped);
                if (tResults.Count > 100)
                {
                    // sanity check: don't sum up more than 100 different values
                    tResults = WatershedDetailExtraction.SummariseRasterStatistically(tClipped);
                    pCategoricalSummary = false;
                }
            }
            else
            {
                tResults = WatershedDetailExtraction.SummariseRasterStatistically(tClipped);
            }
            tRasterAnalysisEnvironment.RestoreToPreviousDefaultEnvironment();
            return new RasterExtractionResult(pExtractionLayerConfig.ParamName, pCategoricalSummary, tResults);
            //return tResults;
        }