static void CreateGrid(TileInfo tiles, int level, IFeatureWorkspace destination, String name) { ISpatialReferenceFactory2 sEnv = new SpatialReferenceEnvironment() as ISpatialReferenceFactory2; ISpatialReference sr = sEnv.CreateSpatialReference((int)tiles.spatialReference); sr.SetMDomain(-137434824702, 0); IFeatureClass fc = CreateFeatureClass(destination, name, sr); LOD lod = tiles.lods[level]; double width = tiles.width * lod.resolution; double height = tiles.height * lod.resolution; double y = tiles.originY; long row = 0; double maxX = -(tiles.originX + width); double minY = -(tiles.originY - height); while (y > minY) { double x = tiles.originX; long col = 0; while (x < maxX) { RingClass ring = new RingClass(); IPoint tl = new PointClass(); tl.PutCoords(x, y); tl.M = -(((col & 0xFFFF) << 16) + (row & 0xFFFF)); ring.AddPoint(tl); IPoint tr = new PointClass(); tr.PutCoords(x + width, y); tr.M = -((((col + 1) & 0xFFFF) << 16) + (row & 0xFFFF)); ring.AddPoint(tr); IPoint br = new PointClass(); br.PutCoords(x + width, y - width); br.M = -((((col + 1) & 0xFFFF) << 16) + ((row + 1) & 0xFFFF)); ring.AddPoint(br); IPoint bl = new PointClass(); bl.PutCoords(x, y - width); bl.M = -(((col & 0xFFFF) << 16) + ((row + 1) & 0xFFFF)); ring.AddPoint(bl); ring.AddPoint(tl); ring.Close(); PolygonClass polygon = new PolygonClass(); polygon.AddGeometry(ring); IFeature polyFeature = fc.CreateFeature(); polyFeature.Shape = polygon; polyFeature.Store(); x += width; col += 1; } row += 1; y -= height; } IFeatureClassDescriptor fd = new FeatureClassDescriptorClass(); fd.Create(fc, null, "OBJECTID"); }
private byte[] ExtractByPolygonHandler(NameValueCollection boundVariables, JsonObject operationInput, string outputFormat, string requestProperties, out string responseProperties) { string search_id; bool found = operationInput.TryGetString("search_id", out search_id); if (!found || string.IsNullOrEmpty(search_id)) { throw new ArgumentNullException("search_id"); } // input polygon - REQUIRED - the polygon to summarise data within JsonObject jsonPolygon; found = operationInput.TryGetJsonObject("polygon", out jsonPolygon); if (!found) { throw new ArgumentNullException("polygon"); } IPolygon extractionPolygon = Conversion.ToGeometry(jsonPolygon, esriGeometryType.esriGeometryPolygon) as IPolygon; long? jsonWkid; found = operationInput.TryGetAsLong("input_wkid", out jsonWkid); if (!found) { throw new ArgumentNullException("input_wkid", "WKID numeric value for spatial reference of input point must be provided"); } if (jsonWkid.HasValue) { int wkid = (int)jsonWkid.Value; ISpatialReferenceFactory2 tInSRFac = new SpatialReferenceEnvironment() as ISpatialReferenceFactory2; ISpatialReference tInSR = tInSRFac.CreateSpatialReference(wkid); extractionPolygon.SpatialReference = tInSR; } else { // we won't get here extractionPolygon.SpatialReference = new UnknownCoordinateSystemClass(); } bool? reqReturnAsAttributes; bool returnAsAttributes = false; found = operationInput.TryGetAsBoolean("extractToPolygonAttributes", out reqReturnAsAttributes); if (found && reqReturnAsAttributes.HasValue) { returnAsAttributes = (bool)reqReturnAsAttributes; } List<ExtractionLayerConfig> extractionRequests = new List<ExtractionLayerConfig>(); foreach (ExtractionLayerConfig tExtLayerInfo in m_ExtractableParams) { string jsonParam = tExtLayerInfo.ParamName; bool? wasRequested; found = operationInput.TryGetAsBoolean(jsonParam, out wasRequested); if (found && wasRequested.HasValue && (bool)wasRequested) { extractionRequests.Add(tExtLayerInfo); } } logger.LogMessage(ServerLogger.msgType.debug, "ExtractByPolygonHandler", 99, "Processed inputs, attempting " + extractionRequests.Count.ToString() + " extractions"); // now need to convert the IPolygon to a geodataset, (a polygon one) for feature // extractions. IWorkspace inMemWksp = CreateInMemoryWorkspace() as IWorkspace; IFeatureWorkspace inMemFeatWksp = inMemWksp as IFeatureWorkspace; IFeatureClass tPolyAsFC = CreateFeatureClassFromGeometry(extractionPolygon, inMemFeatWksp, extractionPolygon.SpatialReference.FactoryCode); IArea tArea = extractionPolygon as IArea; if (AddAField(tPolyAsFC,"Total_Area",esriFieldType.esriFieldTypeDouble)) { IFeatureCursor tFCursor = tPolyAsFC.Search(null,false); IFeature tPolyAsFeature = tFCursor.NextFeature(); tPolyAsFeature.set_Value(tPolyAsFC.FindField("Total_Area"),tArea.Area); tPolyAsFeature.Store(); } IGeoDataset tPolygonGDS = tPolyAsFC as IGeoDataset; // now do the extractions from it ExtractionResultCollection tExtractionResults = ProcessExtractions(search_id,tPolygonGDS, null, extractionRequests); // Warning! Don't go assuming that the suggestively-named responseProperties can be set to anything // helpful to describe, say, response properties. Try setting it to anything other than null // (that I have tried) and you get "500 Unexpected Error" message and lose the best part of an // afternoon working out why! //responseProperties = "Extractions processed successfully"; responseProperties = null; logger.LogMessage(ServerLogger.msgType.debug, "ExtractByPolygonHandler", 99, "Extractions complete, returning feature"); if (returnAsAttributes) { IRecordSetInit returnRecSet = new RecordSetClass(); IGeoDataset tFinalGDS = tExtractionResults.ResultsAsAttributedGeodataset; returnRecSet.SetSourceTable(tFinalGDS as ITable, null); IRecordSet recset = returnRecSet as IRecordSet; byte[] jsonFeature = Conversion.ToJson(recset); return jsonFeature; } else { JsonObject tResultsAsJson = tExtractionResults.ResultsAsJson; byte[] jsonFeatures = System.Text.Encoding.UTF8.GetBytes(tResultsAsJson.ToJson()); return jsonFeatures; } }
private byte[] CreateWatershedHandler(NameValueCollection boundVariables, JsonObject operationInput, string outputFormat, string requestProperties, out string responseProperties) { responseProperties = null; #region Process the REST arguments // hydroshed_id - REQUIRED - to identify the overall result string search_id; bool found = operationInput.TryGetString("search_id", out search_id); if (!found || string.IsNullOrEmpty(search_id)) { throw new ArgumentNullException("search_id"); } // input point - REQUIRED - the search location JsonObject jsonPoint; found = operationInput.TryGetJsonObject("location", out jsonPoint); if (!found) { throw new ArgumentNullException("location"); } IPoint locationpoint = Conversion.ToGeometry(jsonPoint, esriGeometryType.esriGeometryPoint) as IPoint; long? jsonWkid; found = operationInput.TryGetAsLong("input_wkid", out jsonWkid); if (!found) { throw new ArgumentNullException("input_wkid", "WKID numeric value for spatial reference of input point must be provided"); } if (jsonWkid.HasValue) { int wkid = (int)jsonWkid.Value; ISpatialReferenceFactory2 tInSRFac = new SpatialReferenceEnvironment() as ISpatialReferenceFactory2; ISpatialReference tInSR = tInSRFac.CreateSpatialReference(wkid); locationpoint.SpatialReference = tInSR; } // extent - OPTIONAL - we will use full extent if not provided but this is slow!! // TODO maybe preferable to have the extent looked up in the SOE rather than expecting it as a parameter JsonObject jsonExtent; found = operationInput.TryGetJsonObject("extent", out jsonExtent); IGeometry tAnalysisEnvelope; if (found && jsonExtent != null) { logger.LogMessage(ServerLogger.msgType.debug, "process input params", 8000, "Found input extent json object "); tAnalysisEnvelope = convertAnyJsonGeometry(jsonExtent); logger.LogMessage(ServerLogger.msgType.debug, "process input params", 8000, "Input extent processed ok "); try { logger.LogMessage(ServerLogger.msgType.debug, "process input params", 8000, "Input extent height*width are: " + tAnalysisEnvelope.Envelope.Height.ToString() + " * " + tAnalysisEnvelope.Envelope.Width.ToString()); } catch (NullReferenceException nre) { logger.LogMessage(ServerLogger.msgType.debug, "Processing parameters", 8000, "Problem reading input extent, exception was " + nre.Message + " at " + nre.StackTrace); } } else { tAnalysisEnvelope = null; logger.LogMessage(ServerLogger.msgType.debug, "process input params", 8000, "No input extent parameter requested "); } List<ExtractionLayerConfig> extractionRequests = new List<ExtractionLayerConfig>(); foreach (ExtractionLayerConfig tExtLayerInfo in m_ExtractableParams) { string jsonParam = tExtLayerInfo.ParamName; bool? wasRequested; found = operationInput.TryGetAsBoolean(jsonParam, out wasRequested); if (found && wasRequested.HasValue && (bool)wasRequested) { extractionRequests.Add(tExtLayerInfo); } } // check whether to return as json structured object or all flattened onto attributes of the // polygon bool returnAsPolygonAttributes=false; if (extractionRequests.Count > 0) { bool? nullableBool; found = operationInput.TryGetAsBoolean("extractToPolygonAttributes", out nullableBool); if (found && nullableBool.HasValue) { returnAsPolygonAttributes = (bool)nullableBool; } } #endregion #region Do the actual watershed extraction // Modified the computeWatershed method to return both the raster and converted polygon versions of the // watershed. Because the polygon version, if made by unioning separate polygons, is multipart, and // although this is what we want to return to the user, the raster extraction operations can't handle // that so we run them with a raster mask input instead. Returning both here saves the extraction methods // from converting back to a raster. IGeoDataset tWatershedPolyGDS; IGeoDataset tWatershedRasterGDS; if (tAnalysisEnvelope != null) { KeyValuePair<IGeoDataset, IGeoDataset> tPair = computeWatershed(locationpoint, tAnalysisEnvelope.Envelope); tWatershedPolyGDS = tPair.Value; tWatershedRasterGDS = tPair.Key; } else { try { IEnvelope tAnalysisActuallyAnEnvelope = GetAnalysisEnvelope(locationpoint); KeyValuePair<IGeoDataset, IGeoDataset> tPair = computeWatershed(locationpoint, tAnalysisActuallyAnEnvelope); tWatershedPolyGDS = tPair.Value; tWatershedRasterGDS = tPair.Key; } catch { // error getting the extent. Compute watershed without one (will be slow). KeyValuePair<IGeoDataset, IGeoDataset> tPair = computeWatershed(locationpoint, null); tWatershedPolyGDS = tPair.Value; tWatershedRasterGDS = tPair.Key; } } #endregion #region Modify the default fields in polygon catchment // raster-to-poly conversion adds some fields we don't want - remove them // also we will return the search id, and the corresponding outlet coordinates as // attributes on the catchment try { IFeatureClass tPolygonAsFC = (IFeatureClass)tWatershedPolyGDS; // these get made by raster-poly conversion and they're boring TryDeleteAField(tPolygonAsFC, "GRIDCODE"); TryDeleteAField(tPolygonAsFC, "ID"); // Now then now then. After an irritating Thursday afternoon i've discovered that we can't use // tPolygonAsFC.GetFeature(1). Because 1 doesn't mean the first one in the FC, but the one with // OID = 1. If there were multiple polygons that got deleted and replaced by a single unioned one, then // the unioned one won't have OID = 1, as OIDs aren't reused. So we have to use a cursor to get the // feature instead. Add all the fields first, to save having to redo the feature retrieval from the // cursor, then set them if they added ok. bool addedSearchId = AddAField(tPolygonAsFC, "search_id", esriFieldType.esriFieldTypeString, search_id.Length); bool addedOutletX = AddAField(tPolygonAsFC, "outlet_x", esriFieldType.esriFieldTypeDouble); bool addedOutletY = AddAField(tPolygonAsFC, "outlet_y", esriFieldType.esriFieldTypeDouble); IFeature tCatchmentFeature; IFeatureCursor tFeatureCursor = tPolygonAsFC.Search(null, false); tCatchmentFeature = tFeatureCursor.NextFeature(); // there will only be one, not bothering with loop if (addedSearchId) { try { tCatchmentFeature.set_Value(tCatchmentFeature.Fields.FindField("search_id"), search_id); tCatchmentFeature.Store(); } catch (Exception ex) { logger.LogMessage(ServerLogger.msgType.debug, "create watershed handler", 99, "error setting search id field with value " + search_id + ". Detail: " + ex.StackTrace + " " + ex.Message); } } if (addedOutletX) { try { tCatchmentFeature.set_Value(tCatchmentFeature.Fields.FindField("outlet_x"), locationpoint.X); tCatchmentFeature.Store(); } catch (Exception ex) { logger.LogMessage(ServerLogger.msgType.debug, "create watershed handler", 99, "error setting outlet x field with value " + locationpoint.X + ". Detail: " + ex.StackTrace + " " + ex.Message); } } if (addedOutletY) { try { tCatchmentFeature.set_Value(tCatchmentFeature.Fields.FindField("outlet_y"), locationpoint.Y); tCatchmentFeature.Store(); } catch (Exception ex) { logger.LogMessage(ServerLogger.msgType.debug, "create watershed handler", 99, "error setting outlet y field with value " + locationpoint.Y + ". Detail: " + ex.StackTrace + " " + ex.Message); } } } catch (Exception ex) { logger.LogMessage(ServerLogger.msgType.debug, "create watershed handler", 99, "some weird problem setting fields in output polygon" + ex.Message + ex.TargetSite.Name + ex.StackTrace + ex.InnerException.Message); } #endregion bool tPolygonIsMultipart = false; { IFeatureClass tPolygonAsFC = (IFeatureClass)tWatershedPolyGDS; IFeatureCursor tFeatureCursor = tPolygonAsFC.Search(null, false); IFeature tCatchmentFeature = tFeatureCursor.NextFeature(); IPolygon tCatchmentPolygon = (IPolygon)tCatchmentFeature.ShapeCopy; tPolygonIsMultipart = tCatchmentPolygon.ExteriorRingCount > 1; } logger.LogMessage(ServerLogger.msgType.debug, "create watershed handler", 99, "created watershed polygon, proceeding with extractions"); #region Do the catchment characteristic extractions, if any // Use the catchment feature (both vector and original raster versions) as input into the generic // extraction method // will return one with nothing in if there are no extraction requests ExtractionResultCollection tExtractionResults = ProcessExtractions(search_id, tWatershedPolyGDS, tWatershedRasterGDS, extractionRequests); //IGeoDataset tFinalPolygonGDS = ProcessExtractions(tWatershedPolyGDS, tWatershedRasterGDS, extractionRequests); #endregion // The catchment feature now exists and we also have all the attributes requested. Ready to go. // Return either as attributes on the feature itself or as a structured JSON object if (returnAsPolygonAttributes) { IRecordSetInit returnRecSet = new RecordSetClass(); IGeoDataset tFinalPolygonGDS = tExtractionResults.ResultsAsAttributedGeodataset; returnRecSet.SetSourceTable(tFinalPolygonGDS as ITable, null); IRecordSet recset = returnRecSet as IRecordSet; byte[] jsonFeatures = Conversion.ToJson(recset); return jsonFeatures; } else { JsonObject tResultsAsJson = tExtractionResults.ResultsAsJson; byte[] jsonFeatures = System.Text.Encoding.UTF8.GetBytes(tResultsAsJson.ToJson()); return jsonFeatures; } }
private IFeatureClass CreateFeatureClassFromGeometry(IGeometry pGeometry, IFeatureWorkspace pOutFeatWorkspace, int wkid) { // thanks to http://bcdcspatial.blogspot.co.uk/2011/12/some-random-arcobjects-that-make.html // which was the only place i could find an answer to the problem I was having - the last // argument to createfeatureclass is null NOT an empty string try { IFields tFields = new FieldsClass() as IFields; IFieldsEdit tFieldsEdit = (IFieldsEdit)tFields; IField tShpFld = new Field(); IFieldEdit tShpEd = (IFieldEdit)tShpFld; tShpEd.Type_2 = esriFieldType.esriFieldTypeGeometry; tShpEd.Name_2 = "Shape"; IGeometryDef tGeomDef = new GeometryDef(); IGeometryDefEdit tGdEdit = (IGeometryDefEdit)tGeomDef; tGdEdit.GeometryType_2 = pGeometry.GeometryType; ISpatialReferenceFactory2 tSRFac = new SpatialReferenceEnvironment() as ISpatialReferenceFactory2; ISpatialReference tSpatRef = tSRFac.CreateSpatialReference(wkid); ISpatialReferenceResolution tSpatRefRes = (ISpatialReferenceResolution)tSpatRef; tSpatRefRes.ConstructFromHorizon(); tGdEdit.SpatialReference_2 = tSpatRef; tShpEd.GeometryDef_2 = tGeomDef; tFieldsEdit.AddField(tShpFld); IObjectClassDescription tOCDesc = new FeatureClassDescription(); for (int i = 0; i < tOCDesc.RequiredFields.FieldCount; i++) { IField tField = tOCDesc.RequiredFields.get_Field(i); if (tFieldsEdit.FindField(tField.Name) == -1) { tFieldsEdit.AddField(tField); } } string tFCName = "tmp" + Guid.NewGuid().ToString("N"); IFeatureClass tFC = pOutFeatWorkspace.CreateFeatureClass( tFCName, tFields, null, null, esriFeatureType.esriFTSimple, "Shape", null); IFeature tGeomAsFeature = tFC.CreateFeature(); tGeomAsFeature.Shape = pGeometry; tGeomAsFeature.Store(); return tFC; } catch (Exception e) { Console.WriteLine(e.Message); logger.LogMessage(ServerLogger.msgType.error, "CreateFeatureClassFromGeometry", 99, "Could not create feature class " + e.Message + e.Source + e.StackTrace); throw e; } }