private Feature Map(FieldBoundary fieldBoundary) { GeoJSON.Net.Geometry.MultiPolygon multiPolygon = MultiPolygonMapper.Map(fieldBoundary.SpatialData, _properties.AffineTransformation); if (multiPolygon == null) { return(null); } Dictionary <string, object> properties = new Dictionary <string, object>(); properties.Add("Guid", UniqueIdMapper.GetUniqueGuid(fieldBoundary.Id, UniqueIdSourceCNH)); if (_properties.Anonymise) { properties.Add("Description", "Field boundary " + fieldBoundary.Id.ReferenceId); } else { properties.Add("Description", fieldBoundary.Description); } // GpsSource var gpsSource = fieldBoundary.GpsSource; properties.Add("GpsSource", null); if (gpsSource != null) { properties["GpsSource"] = fieldBoundary.GpsSource.ToString(); } // Created time var creationTime = fieldBoundary.TimeScopes.Where(ts => ts.DateContext == DateContextEnum.Creation).FirstOrDefault(); properties.Add("CreationTime", null); if (creationTime != null) { if (creationTime.TimeStamp1 != null) { properties["CreationTime"] = ((DateTime)creationTime.TimeStamp1).ToString("O", CultureInfo.InvariantCulture); } } // Modified time var modifiedTime = fieldBoundary.TimeScopes.Where(ts => ts.DateContext == DateContextEnum.Modification).FirstOrDefault(); properties.Add("ModifiedTime", null); if (modifiedTime != null) { if (modifiedTime.TimeStamp1 != null) { properties["ModifiedTime"] = ((DateTime)modifiedTime.TimeStamp1).ToString("O", CultureInfo.InvariantCulture); } } Feature fieldBoundaryDto = new Feature(multiPolygon, properties); return(fieldBoundaryDto); }
public Field ImportField(ISOPartfield isoPartfield) { Field field = new Field(); //Field ID ImportIDs(field.Id, isoPartfield.PartfieldID); //Farm ID field.FarmId = TaskDataMapper.InstanceIDMap.GetADAPTID(isoPartfield.FarmIdRef); //Area var numericValue = new NumericValue(new CompositeUnitOfMeasure("m2").ToModelUom(), (double)(isoPartfield.PartfieldArea)); field.Area = new NumericRepresentationValue(RepresentationInstanceList.vrReportedFieldArea.ToModelRepresentation(), numericValue.UnitOfMeasure, numericValue); //Name field.Description = isoPartfield.PartfieldDesignator; //Boundary PolygonMapper polygonMapper = new PolygonMapper(TaskDataMapper); IEnumerable <Polygon> boundaryPolygons = polygonMapper.ImportPolygons(isoPartfield.Polygons).ToList(); if (boundaryPolygons.Any()) { MultiPolygon boundary = new MultiPolygon(); boundary.Polygons = boundaryPolygons.ToList(); FieldBoundary fieldBoundary = new FieldBoundary { FieldId = field.Id.ReferenceId, SpatialData = boundary, }; //Add the boundary to the Catalog if (DataModel.Catalog.FieldBoundaries == null) { DataModel.Catalog.FieldBoundaries = new List <FieldBoundary>(); } DataModel.Catalog.FieldBoundaries.Add(fieldBoundary); field.ActiveBoundaryId = fieldBoundary.Id.ReferenceId; } //Guidance GuidanceGroupMapper guidanceGroupMapper = new GuidanceGroupMapper(TaskDataMapper); IEnumerable <GuidanceGroup> groups = guidanceGroupMapper.ImportGuidanceGroups(isoPartfield.GuidanceGroups); if (groups.Any()) { field.GuidanceGroupIds = groups.Select(g => g.Id.ReferenceId).ToList(); } //TODO any obstacle, flag, entry, etc. data //TODO store Partfield Code as ContextItem return(field); }
public ISOPartfield ExportField(Field adaptField) { ISOPartfield isoField = new ISOPartfield(); //Field ID string fieldID = adaptField.Id.FindIsoId() ?? GenerateId(); isoField.PartfieldID = fieldID; ExportIDs(adaptField.Id, fieldID); ExportContextItems(adaptField.ContextItems, fieldID, "ADAPT_Context_Items:Field"); //Customer & Farm ID ExportFarmAndGrower(adaptField, isoField); //isoField.PartfieldCode = ? //TODO ContextItem? //Area if (adaptField.Area != null) { isoField.PartfieldArea = (uint)(adaptField.Area.Value.ConvertToUnit(new CompositeUnitOfMeasure("m2"))); } //Name isoField.PartfieldDesignator = adaptField.Description; //Boundary PolygonMapper polygonMapper = new PolygonMapper(TaskDataMapper); FieldBoundary boundary = DataModel.Catalog.FieldBoundaries.SingleOrDefault(b => b.FieldId == adaptField.Id.ReferenceId); if (boundary != null) { IEnumerable <ISOPolygon> isoPolygons = polygonMapper.ExportPolygons(boundary.SpatialData.Polygons, ISOEnumerations.ISOPolygonType.PartfieldBoundary); isoField.Polygons.AddRange(isoPolygons); } //Guidance if (DataModel.Catalog.GuidanceGroups != null) { List <GuidanceGroup> groups = new List <GuidanceGroup>(); foreach (int groupID in adaptField.GuidanceGroupIds) { GuidanceGroup group = DataModel.Catalog.GuidanceGroups.SingleOrDefault(g => g.Id.ReferenceId == groupID); if (group != null) { groups.Add(group); } } GuidanceGroupMapper ggpMapper = TaskDataMapper.GuidanceGroupMapper; isoField.GuidanceGroups = ggpMapper.ExportGuidanceGroups(groups).ToList(); } //TODO any obstacle, flag, entry, etc. data pending fixes to InteriorBoundaryAttribute class return(isoField); }
public Feature MapAsSingleFeature(FieldBoundary fieldBoundary) { if (_dataModel == null) { return(null); } Feature fieldBoundaryFeature = Map(fieldBoundary); if (fieldBoundaryFeature == null) { return(null); } Field adaptField = _dataModel.Catalog.Fields.Where(f => f.Id.ReferenceId == fieldBoundary.FieldId).FirstOrDefault(); if (adaptField != null) { fieldBoundaryFeature.Properties.Add("Field", adaptField.Description); //Guid fieldguid = UniqueIdMapper.GetUniqueGuid(adaptField.Id, UniqueIdSourceCNH); //fieldBoundaryFeature.Properties.Add("FieldId", fieldguid); fieldBoundaryFeature.Properties.Add("FieldId", adaptField.Id.ReferenceId); Farm adaptFarm = _dataModel.Catalog.Farms.Where(f => f.Id.ReferenceId == adaptField.FarmId).FirstOrDefault(); if (adaptFarm != null) { fieldBoundaryFeature.Properties.Add("Farm", adaptFarm.Description); Grower adaptGrower = _dataModel.Catalog.Growers.Where(f => f.Id.ReferenceId == adaptFarm.GrowerId).FirstOrDefault(); if (adaptGrower != null) { fieldBoundaryFeature.Properties.Add("Grower", adaptGrower.Name); } } if (adaptField.GrowerId != null && !fieldBoundaryFeature.Properties.ContainsKey("Grower")) { Grower adaptGrower = _dataModel.Catalog.Growers.Where(f => f.Id.ReferenceId == adaptFarm.GrowerId).FirstOrDefault(); if (adaptGrower != null) { fieldBoundaryFeature.Properties.Add("Grower", adaptGrower.Name); } } } return(fieldBoundaryFeature); }
public void ProcessBoundary(FieldBoundary fieldBoundary) { using (var graphics = _spatialViewer.CreateGraphics()) { _drawingUtil = new DrawingUtil(_spatialViewer.Width, _spatialViewer.Height, graphics); foreach (var polygon in fieldBoundary.SpatialData.Polygons) { var projectedPoints = polygon.ExteriorRing.Points.Select(point => point.ToUtm()).ToList(); _drawingUtil.SetMinMax(projectedPoints); var screenPolygon = projectedPoints.Select(point => point.ToXy(_drawingUtil.MinX, _drawingUtil.MinY, _drawingUtil.GetDelta())).ToArray(); graphics.DrawPolygon(DrawingUtil.B_Black, screenPolygon); } } }
public void AddBoundary(Field field, Catalog adaptCatalog) { var fieldBoundary = new FieldBoundary { FieldId = field.Id.ReferenceId, Description = "Boundary Name", SpatialData = new MultiPolygon() }; // It is possible for a field boundary to contain multiple polygons (e.g., multiple exteriors). // Older Deere displays require a single exterior ring - however, given multiple exterior rings the Deere // plugins will automatically add land bridges as needed to ensure compatibility. var polygon = new Polygon { ExteriorRing = new LinearRing { Points = new List <Point> { // Spatial coordinates go here. Coordinates must use a WGS84 spatial projection. } }, }; fieldBoundary.SpatialData.Polygons.Add(polygon); var interior = new LinearRing { Id = 1, Points = new List <Point> { // Spatial coordinates go here. Coordinates must use a WGS84 spatial projection. } }; polygon.InteriorRings.Add(interior); // InteriorBoundaryAttributes provide metadata about an interior ring. var interiorAttributes = new InteriorBoundaryAttribute { Description = "Interior Name", // IsPassable indicates whether it is safe to drive through an interior. IsPassable = false, // This should match the Id value of the corresponding interior ring. ShapeIdRef = 1 }; fieldBoundary.InteriorBoundaryAttributes.Add(interiorAttributes); adaptCatalog.FieldBoundaries.Add(fieldBoundary); }
public ModelEnvelope <FieldBoundary> Convert(FieldBoundaryDto fieldBoundaryDto) { var fieldBoundary = new FieldBoundary { TimeScopes = new List <TimeScope>() { new TimeScope { TimeStamp1 = new DateTime(fieldBoundaryDto.CropYear, 1, 1), TimeStamp2 = new DateTime(fieldBoundaryDto.CropYear, 12, 31) } }, Description = $"{fieldBoundaryDto.CropYear} Boundary" }; var fieldBoundaryUniqueId = fieldBoundary.Id; var boundaryUniqueId = _uniqueIdFactory.CreateInt(fieldBoundaryDto.Id); fieldBoundaryUniqueId.UniqueIds.Add(boundaryUniqueId); var selfLink = new ReferenceLink { Id = fieldBoundaryUniqueId, Rel = Relationships.Self, Link = $"/FieldBoundaries/{boundaryUniqueId.Source}/{boundaryUniqueId.Id}" }; var fieldUniqueId = _uniqueIdFactory.CreateGuid(fieldBoundaryDto.FieldUid); var fieldCompoundId = fieldUniqueId.ToCompoundIdentifier(); fieldBoundary.FieldId = fieldCompoundId.ReferenceId; var fieldLink = new ReferenceLink { Id = fieldCompoundId, Rel = typeof(Field).ObjectRel(), Link = $"/Fields/{fieldUniqueId.Source}/{fieldUniqueId.Id}" }; // NOTE: Skipped SpatialData to not introduce Spatial Dependencies in conversion. var fieldBoundaryEnvelope = new ModelEnvelope <FieldBoundary>(fieldBoundary); fieldBoundaryEnvelope.Links.Add(selfLink); fieldBoundaryEnvelope.Links.Add(fieldLink); return(fieldBoundaryEnvelope); }
private void LoadFieldBoundary(XmlNode inputNode, Field field) { var polygon = ShapeLoader.LoadPolygon(inputNode.SelectNodes("PLN")); if (polygon != null) { var fieldBoundary = new FieldBoundary { FieldId = field.Id.ReferenceId, SpatialData = polygon, }; _taskDocument.FieldBoundaries.Add(fieldBoundary); field.ActiveBoundaryId = fieldBoundary.Id.ReferenceId; } }
private void UpdateInvalidFieldBoundaries(GridPoint center) { BimaruValue centerValue = GetFieldValueNoCheck(center); foreach (Direction direction in Directions.GetAllDirections()) { BimaruValue neighbourValue = this[center.GetNextPoint(direction)]; FieldBoundary boundary = center.GetBoundary(direction); if (centerValue.IsCompatibleWith(direction, neighbourValue)) { invalidFieldBoundaries.Remove(boundary); } else { invalidFieldBoundaries.Add(boundary); } } }
private void WriteBoundary(XmlWriter writer, int?boundaryId) { if (!boundaryId.HasValue) { return; } FieldBoundary fieldBoundary = null; foreach (var boundary in TaskWriter.DataModel.Catalog.FieldBoundaries) { if (boundary.Id.ReferenceId == boundaryId) { fieldBoundary = boundary; break; } } if (fieldBoundary == null || fieldBoundary.SpatialData == null) { return; } ShapeWriter.WritePolygon(writer, fieldBoundary.SpatialData); }
static void Main(string[] args) { // Load up the sample farm/field/cropzone information var treeData = (JArray)(JObject.Parse(File.ReadAllText("tree.json"))["Results"]); // Load up the field/cropzone boundaries var boundaryData = (JArray)(JObject.Parse(File.ReadAllText("boundaries.json"))["Results"]); // Initialize a Well-Known-Text (WKT) reader for handling the sample boundary data GeometryFactory geometryFactory = new GeometryFactory(); NetTopologySuite.IO.WKTReader wktReader = new NetTopologySuite.IO.WKTReader(geometryFactory); // In this console app the ADMPlugin is included as a NuGet package so the ADMPlugin.dll is always // copied directly in to the executable directory. That's why we tell the PluginFactory to look there // for the ADMPlugin. string applicationPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location); // The PluginFactory looks at all the DLLs in the target directory to find any that implement the IPlugin interface. var pluginFactory = new PluginFactory(applicationPath); // We're only interested in the ADMPlugin here, so I address it directly instead of looking through all the // available plugins that the PluginFactory found. var admPlugin = pluginFactory.GetPlugin("ADMPlugin"); // The ADMPlugin doesn't require any initialization parameters. admPlugin.Initialize(); // The ApplicationDataModel is the root object in ADAPT ApplicationDataModel export = new ApplicationDataModel(); // The Catalog object (inside the ApplicationDataModel) holds all the items you would expect to find in a "pick list". // Alternatively, you could think of it as the place you put everything used "by reference" in any of the Documents // you are trying to send. export.Catalog = new Catalog(); // The Documents object (inside the ApplicationDataModel) holds all the Plans, Recommendations, WorkOrders, and // WorkRecords (and their component parts). We won't be using this in this example. export.Documents = new Documents(); // Create a "crop year" TimeScope to tag objects with. TimeScope cropYear = new TimeScope(); cropYear.Description = "2017"; cropYear.DateContext = DateContextEnum.CropSeason; export.Catalog.TimeScopes.Add(cropYear); // Create the Grower object. The constructor will automatically create the Id property and assign the // next available ReferenceId integer. Grower adaptGrower = new Grower(); // Associate your internal, unique identifier to the Grower object by creating a UniqueId object // and adding it to the Grower object's CompoundIdentifier. UniqueId ourId = new UniqueId(); ourId.Id = "7d2253f0-fce6-4740-b3c3-f9c8ab92bfaa"; // Notice the available IdTypeEnum choices. Not everybody uses the same way of identifying things in their // system. As a result, we must support a number of identification schemes. ourId.IdType = IdTypeEnum.UUID; // Almost as important as the identifier is knowing who created it (or where it came from). ourId.Source = "www.agconnections.com"; ourId.SourceType = IdSourceTypeEnum.URI; // Each CompoundIdentifier that is used in ADAPT can have multiple unique identifiers associated with it. // Consider the possibilites here, not only can your identifier for something be peristed but also the // identifiers that your trading partner assigns to the same object. PLEASE CONSIDER PERSISTING AND RETURNING // IDENTIFIERS PASSED TO YOU IN THIS FASHION. This has the potential to result in a "frictionless" conversation // once the initial mapping is done, buy this benefit will only emerge if we all are "good neighbors". adaptGrower.Id.UniqueIds.Add(ourId); // You may notice that many of the objects in ADAPT have a minimal number of properties. Don't panic if you // can't find a place to put all your data. It may be in an associated object or intended to be expressed // as a ContextItem. adaptGrower.Name = "Ponderosa Farms"; // Add the Grower object to the Catalog. export.Catalog.Growers.Add(adaptGrower); // Pull the farm objects out of the sample JSON test data var farms = (from c in treeData where ((string)c["type"] == "farm") select c).ToList(); // Iterate over each farm foreach (var farm in farms) { // Create the Farm object. The constructor will automatically create the Id property and assign the // next available ReferenceId integer. Farm adaptFarm = new Farm(); ourId = new UniqueId(); ourId.Id = (string)farm["id"]; ourId.IdType = IdTypeEnum.UUID; ourId.Source = "www.agconnections.com"; ourId.SourceType = IdSourceTypeEnum.URI; adaptFarm.Id.UniqueIds.Add(ourId); adaptFarm.Description = (string)farm["text"]; // Here we link this farm object to the grower. Note that this is the integer (ReferenceId) in the // Grower's CompountIdentifier object. adaptFarm.GrowerId = adaptGrower.Id.ReferenceId; // Add the Farm object to the Catalog. export.Catalog.Farms.Add(adaptFarm); // Pull the field objects out of the sample JSON test data that are part of this iteration's farm var fields = (from c in treeData where (((string)c["type"] == "field") && ((string)c["parent"] == (string)farm["id"])) select c).ToList(); // Iterate over each field foreach (var field in fields) { // Create the Field object. The constructor will automatically create the Id property and assign the // next available ReferenceId integer. Field adaptField = new Field(); ourId = new UniqueId(); ourId.Id = (string)field["id"]; ourId.IdType = IdTypeEnum.UUID; ourId.Source = "www.agconnections.com"; ourId.SourceType = IdSourceTypeEnum.URI; adaptField.Id.UniqueIds.Add(ourId); adaptField.Description = (string)field["text"]; // Here we link this field object to the farm. Note that this is the integer (ReferenceId) in the // Farm's CompountIdentifier object. adaptField.FarmId = adaptFarm.Id.ReferenceId; // Pull the boundary object out of the sample JSON test data (if it exists) var fieldBoundary = (from c in boundaryData where (((string)c["FieldId"] == (string)field["id"]) && ((string)c["CropZoneId"] == null)) select c).FirstOrDefault(); if (fieldBoundary != null) { // This sample data has boundaries expressed as MultiPolygons in WKT so we need to transform that into the correlary ADAPT objects. // Your data may use a different geometry (instead of MultiPolygon) to describe your boundaries so your code may differ at this point. var boundary = wktReader.Read((string)fieldBoundary["MapData"]) as NetTopologySuite.Geometries.MultiPolygon; AgGateway.ADAPT.ApplicationDataModel.Shapes.MultiPolygon adaptMultiPolygon = new AgGateway.ADAPT.ApplicationDataModel.Shapes.MultiPolygon(); adaptMultiPolygon.Polygons = new List <AgGateway.ADAPT.ApplicationDataModel.Shapes.Polygon>(); foreach (var geometry in boundary.Geometries) { var polygon = geometry as NetTopologySuite.Geometries.Polygon; AgGateway.ADAPT.ApplicationDataModel.Shapes.Polygon adaptPolygon = new AgGateway.ADAPT.ApplicationDataModel.Shapes.Polygon(); adaptPolygon.ExteriorRing = new AgGateway.ADAPT.ApplicationDataModel.Shapes.LinearRing(); adaptPolygon.InteriorRings = new List <AgGateway.ADAPT.ApplicationDataModel.Shapes.LinearRing>(); foreach (var coordinate in polygon.ExteriorRing.Coordinates) { var adaptPoint = new AgGateway.ADAPT.ApplicationDataModel.Shapes.Point(); adaptPoint.X = coordinate.X; adaptPoint.Y = coordinate.Y; adaptPolygon.ExteriorRing.Points.Add(adaptPoint); } foreach (var ring in polygon.InteriorRings) { var adaptRing = new AgGateway.ADAPT.ApplicationDataModel.Shapes.LinearRing(); adaptRing.Points = new List <AgGateway.ADAPT.ApplicationDataModel.Shapes.Point>(); foreach (var coordinate in ring.Coordinates) { var adaptPoint = new AgGateway.ADAPT.ApplicationDataModel.Shapes.Point(); adaptPoint.X = coordinate.X; adaptPoint.Y = coordinate.Y; adaptRing.Points.Add(adaptPoint); } adaptPolygon.InteriorRings.Add(adaptRing); } adaptMultiPolygon.Polygons.Add(adaptPolygon); } // Unlike the CropZone object (which holds its geomertry internally) a Field's boundary is held in a separate FieldBoundary object. // Create the FieldBoundary object. The constructor will automatically create the Id property and assign the // next available ReferenceId integer. FieldBoundary adaptBoundary = new FieldBoundary(); // The FieldBoundary.SpatialData property is an ADAPT Shape object (which is an abastract class). What you actually attach here // is one of the child classes of Shape (Polygon, MultiPolygon, etc.). adaptBoundary.SpatialData = adaptMultiPolygon; // Here we link this field boundary object to the field. Note that this is the integer (ReferenceId) in the // Field's CompountIdentifier object. adaptBoundary.FieldId = adaptField.Id.ReferenceId; // Add the FieldBoundary object to the Catalog. export.Catalog.FieldBoundaries.Add(adaptBoundary); // It is possible for a given Field to have multiple FieldBounday objects associated with it, but we need to be able // to indicate which one should be used by "default". adaptField.ActiveBoundaryId = adaptBoundary.Id.ReferenceId; } // Add the Field object to the Catalog. *Note: We are adding this to the Catalog here so that we don't have to go // back and fetch the object to set the ActiveBoundaryId property. Not required, just convenient. export.Catalog.Fields.Add(adaptField); // We're defining a CropZone as a spatial area within a field grown to a crop during a specific window of time. // This is fundamentally different from the concept of a management zone (that might vary by plant population or soil type). // Pull the cropzone objects out of the sample JSON test data that are part of this iteration's field var cropzones = (from c in treeData where (((string)c["type"] == "cropzone") && ((string)c["parent"] == (string)field["id"])) select c).ToList(); // Iterate over each cropzone foreach (var cropzone in cropzones) { // It's entirely possible that we have already added this Crop to the Catalog during a previous iteration. We need to check // the Crop list in Catalog first and reuse that object if it exists. Crop adaptCrop = null; var crops = export.Catalog.Crops.Where(x => (x.Name == (string)cropzone["li_attr"]["CropName"])).ToList(); if (crops.Count > 0) { adaptCrop = crops[0]; } else { // Create the Crop object. The constructor will automatically create the Id property and assign the // next available ReferenceId integer. adaptCrop = new Crop(); ourId = new UniqueId(); ourId.Id = (string)cropzone["li_attr"]["CropId"]; ourId.IdType = IdTypeEnum.UUID; ourId.Source = "www.agconnections.com"; ourId.SourceType = IdSourceTypeEnum.URI; adaptCrop.Id.UniqueIds.Add(ourId); adaptCrop.Name = (string)cropzone["li_attr"]["CropName"]; // Add EPPO code as ContextItem at some point in the future // Add the Crop object to the Catalog. export.Catalog.Crops.Add(adaptCrop); } // Create the CropZone object. The constructor will automatically create the Id property and assign the // next available ReferenceId integer. CropZone adaptCropZone = new CropZone(); ourId = new UniqueId(); ourId.Id = (string)cropzone["id"]; ourId.IdType = IdTypeEnum.UUID; ourId.Source = "www.agconnections.com"; ourId.SourceType = IdSourceTypeEnum.URI; adaptCropZone.Id.UniqueIds.Add(ourId); adaptCropZone.Description = (string)cropzone["text"]; // Here we link this cropzone object to the field. Note that this is the integer (ReferenceId) in the // Field's CompountIdentifier object. adaptCropZone.FieldId = adaptField.Id.ReferenceId; // Here we link this cropzone object to the crop. Note that this is the integer (ReferenceId) in the // Crop's CompountIdentifier object. adaptCropZone.CropId = adaptCrop.Id.ReferenceId; // Here we link this cropzone object to the crop year TimeScope. Note that the TimeScope is used BY VALUE // instead of BY REFERENCE (like the field and crop above). adaptCropZone.TimeScopes.Add(cropYear); string areaString = (string)cropzone["li_attr"]["AreaValue"]; if (!string.IsNullOrEmpty(areaString)) { double area = Convert.ToDouble(areaString); adaptCropZone.Area = new NumericRepresentationValue(RepresentationInstanceList.vrReportedFieldArea.ToModelRepresentation(), new NumericValue(UnitSystemManager.GetUnitOfMeasure("ac1"), area)); } // As mentioned before, the CropZone (unlike Field) holds its boundary internally. Also unlike field, a CropZone is only expected // to have a single boundary due to its scope in crop & time. var czBoundary = (from c in boundaryData where ((string)c["CropZoneId"] == (string)cropzone["id"]) select c).FirstOrDefault(); if (czBoundary != null) { var boundary = wktReader.Read((string)czBoundary["MapData"]) as NetTopologySuite.Geometries.MultiPolygon; AgGateway.ADAPT.ApplicationDataModel.Shapes.MultiPolygon adaptMultiPolygon = new AgGateway.ADAPT.ApplicationDataModel.Shapes.MultiPolygon(); adaptMultiPolygon.Polygons = new List <AgGateway.ADAPT.ApplicationDataModel.Shapes.Polygon>(); foreach (var geometry in boundary.Geometries) { var polygon = geometry as NetTopologySuite.Geometries.Polygon; AgGateway.ADAPT.ApplicationDataModel.Shapes.Polygon adaptPolygon = new AgGateway.ADAPT.ApplicationDataModel.Shapes.Polygon(); adaptPolygon.ExteriorRing = new AgGateway.ADAPT.ApplicationDataModel.Shapes.LinearRing(); adaptPolygon.InteriorRings = new List <AgGateway.ADAPT.ApplicationDataModel.Shapes.LinearRing>(); foreach (var coordinate in polygon.ExteriorRing.Coordinates) { var adaptPoint = new AgGateway.ADAPT.ApplicationDataModel.Shapes.Point(); adaptPoint.X = coordinate.X; adaptPoint.Y = coordinate.Y; adaptPolygon.ExteriorRing.Points.Add(adaptPoint); } foreach (var ring in polygon.InteriorRings) { var adaptRing = new AgGateway.ADAPT.ApplicationDataModel.Shapes.LinearRing(); adaptRing.Points = new List <AgGateway.ADAPT.ApplicationDataModel.Shapes.Point>(); foreach (var coordinate in ring.Coordinates) { var adaptPoint = new AgGateway.ADAPT.ApplicationDataModel.Shapes.Point(); adaptPoint.X = coordinate.X; adaptPoint.Y = coordinate.Y; adaptRing.Points.Add(adaptPoint); } adaptPolygon.InteriorRings.Add(adaptRing); } adaptMultiPolygon.Polygons.Add(adaptPolygon); } adaptCropZone.BoundingRegion = adaptMultiPolygon; } // Add the CropZone object to the Catalog. export.Catalog.CropZones.Add(adaptCropZone); } } } // At this point we have added all the Grower/Farm/Field objects to the Catalog and are ready to export. // Create an output path string outputPath = applicationPath + @"\Output"; if (Directory.Exists(outputPath)) { Directory.Delete(outputPath, true); } if (!Directory.Exists(outputPath)) { Directory.CreateDirectory(outputPath); } // Export to a local directory using the ADMPlugin admPlugin.Export(export, outputPath); // The ADMPlugin creates an "adm" subdirectory in the indicated local directory that contains the following items: // An additional "documents" subdirectory that contains the protobuf-encoded document files. // An AdmVersion.info file that contains version information. // A ProprietaryValues.adm file // A Catalog.adm file that contains the zipped JSON serialization of the ApplicationDataModel.Catalog object. // We've added logic here to zip that "adm" subdirectory into a single file, in case you want to email it to someone. string zipPath = applicationPath + @"\Zip"; if (Directory.Exists(zipPath)) { Directory.Delete(zipPath, true); } if (!Directory.Exists(zipPath)) { Directory.CreateDirectory(zipPath); } // Delete the file if it already exists string zipFile = zipPath + @"\tree.zip"; if (File.Exists(zipFile)) { File.Delete(zipFile); } ZipFile.CreateFromDirectory(outputPath, zipFile); // This is logic to import the same data from the "adm" subdirectory we just created so you can compare it // in the debugger if you want. var pluginFactory2 = new PluginFactory(applicationPath); var admPlugin2 = pluginFactory.GetPlugin("ADMPlugin"); admPlugin2.Initialize(); // Note that when a plugin imports, the returned object is a list of ApplicationDataModel objects. var imports = admPlugin2.Import(outputPath); }
public static void Export(string path) { ApplicationDataModel adm = new ApplicationDataModel(); adm.Catalog = new Catalog(); adm.Documents = new Documents(); //-------------------------- //Setup information //-------------------------- //Add a crop Crop corn = new Crop() { Name = "Corn" }; adm.Catalog.Crops.Add(corn); //Add some seed varieties CropVarietyProduct seedVariety1 = new CropVarietyProduct() { CropId = corn.Id.ReferenceId, Description = "Variety 1" }; CropVarietyProduct seedVariety2 = new CropVarietyProduct() { CropId = corn.Id.ReferenceId, Description = "Variety 2" }; adm.Catalog.Products.Add(seedVariety1); adm.Catalog.Products.Add(seedVariety2); //Add a liquid product CropNutritionProduct fertilizer = new CropNutritionProduct() { Description = "Starter", Form = ProductFormEnum.Liquid }; fertilizer.ProductType = ProductTypeEnum.Fertilizer; adm.Catalog.Products.Add(fertilizer); //Add a granular product CropProtectionProduct insecticide = new CropProtectionProduct() { Description = "Insecticide", Form = ProductFormEnum.Solid }; insecticide.ProductType = ProductTypeEnum.Chemical; adm.Catalog.Products.Add(insecticide); //GFF Grower grower = new Grower() { Name = "Example Grower" }; adm.Catalog.Growers.Add(grower); Farm farm = new Farm() { Description = "Example Farm", GrowerId = grower.Id.ReferenceId }; adm.Catalog.Farms.Add(farm); Field field = new Field() { Description = "Example Field", FarmId = farm.Id.ReferenceId, GrowerId = grower.Id.ReferenceId }; field.Area = GetNumericRepresentationValue(23d, "ha", "vrReportedFieldArea"); adm.Catalog.Fields.Add(field); //Crop zone TimeScope season = new TimeScope() { DateContext = DateContextEnum.CropSeason, TimeStamp1 = new DateTime(2021, 1, 1) }; CropZone cropZone = new CropZone() { CropId = corn.Id.ReferenceId, FieldId = field.Id.ReferenceId, TimeScopes = new List <TimeScope>() { season } }; adm.Catalog.CropZones.Add(cropZone); //Field boundary FieldBoundary boundary = new FieldBoundary() { SpatialData = new MultiPolygon() { Polygons = new List <Polygon>() { new Polygon() { ExteriorRing = new LinearRing() { Points = new List <Point>() { new Point() { X = -89.488565, Y = 40.478304 }, new Point() { X = -89.485439, Y = 40.478304 }, new Point() { X = -89.485439, Y = 40.475010 }, new Point() { X = -89.488565, Y = 40.475010 } } }, InteriorRings = new List <LinearRing>() { new LinearRing() { Points = new List <Point>() { new Point() { X = -89.487719, Y = 40.478091 }, new Point() { X = -89.487536, Y = 40.478091 }, new Point() { X = -89.487536, Y = 40.477960 }, new Point() { X = -89.487719, Y = 40.477960 }, new Point() { X = -89.487719, Y = 40.478091 } } }, new LinearRing() { Points = new List <Point>() { new Point() { X = -89.486732, Y = 40.478172 }, new Point() { X = -89.486453, Y = 40.478172 }, new Point() { X = -89.486453, Y = 40.478082 }, new Point() { X = -89.486732, Y = 40.478082 }, new Point() { X = -89.486732, Y = 40.478172 } } } } } } }, FieldId = field.Id.ReferenceId }; adm.Catalog.FieldBoundaries.Add(boundary); field.ActiveBoundaryId = boundary.Id.ReferenceId; //-------------------------- //Prescription //-------------------------- //Prescription setup data //Setup the representation and units for seed rate & seed depth prescriptions NumericRepresentation seedRate = GetNumericRepresentation("vrSeedRateSeedsTarget"); UnitOfMeasure seedUOM = UnitInstance.UnitSystemManager.GetUnitOfMeasure("seeds1ac-1"); RxProductLookup seedVariety1RateLookup = new RxProductLookup() { ProductId = seedVariety1.Id.ReferenceId, Representation = seedRate, UnitOfMeasure = seedUOM }; RxProductLookup seedVariety2RateLookup = new RxProductLookup() { ProductId = seedVariety2.Id.ReferenceId, Representation = seedRate, UnitOfMeasure = seedUOM }; NumericRepresentation seedDepth = GetNumericRepresentation("vrSeedDepthTarget"); UnitOfMeasure depthUOM = UnitInstance.UnitSystemManager.GetUnitOfMeasure("cm"); RxProductLookup seedVariety1DepthLookup = new RxProductLookup() { ProductId = seedVariety1.Id.ReferenceId, Representation = seedDepth, UnitOfMeasure = depthUOM }; RxProductLookup seedVariety2DepthLookup = new RxProductLookup() { ProductId = seedVariety2.Id.ReferenceId, Representation = seedDepth, UnitOfMeasure = depthUOM }; //Setup liquid rx representation/units NumericRepresentation fertilizerRate = GetNumericRepresentation("vrAppRateVolumeTarget"); UnitOfMeasure fertilizerUOM = UnitInstance.UnitSystemManager.GetUnitOfMeasure("gal1ac-1"); RxProductLookup fertilizerRateLookup = new RxProductLookup() { ProductId = fertilizer.Id.ReferenceId, Representation = fertilizerRate, UnitOfMeasure = fertilizerUOM }; //Setup granular rx representation/units NumericRepresentation insecticideRate = GetNumericRepresentation("vrAppRateMassTarget"); UnitOfMeasure insecticideUOM = UnitInstance.UnitSystemManager.GetUnitOfMeasure("lb1ac-1"); RxProductLookup insecticideRateLookup = new RxProductLookup() { ProductId = insecticide.Id.ReferenceId, Representation = insecticideRate, UnitOfMeasure = insecticideUOM }; //Prescription zones //Zone 1 - Variety 1 at 32000 seeds/acre, 4 cm depth target; Starter at 7 gal/ac; Insecticide at 5 lb/ac RxShapeLookup zone1 = new RxShapeLookup() { Rates = new List <RxRate>() { new RxRate() { Rate = 32000d, RxProductLookupId = seedVariety1RateLookup.Id.ReferenceId }, new RxRate() { Rate = 4d, RxProductLookupId = seedVariety1DepthLookup.Id.ReferenceId }, new RxRate() { Rate = 7d, RxProductLookupId = fertilizerRateLookup.Id.ReferenceId }, new RxRate() { Rate = 5d, RxProductLookupId = insecticideRateLookup.Id.ReferenceId } }, Shape = new MultiPolygon() { Polygons = new List <Polygon>() { new Polygon() { ExteriorRing = new LinearRing() { Points = new List <Point>() { new Point() { X = -89.488565, Y = 40.478304 }, new Point() { X = -89.485439, Y = 40.478304 }, new Point() { X = -89.485439, Y = 40.477404 }, new Point() { X = -89.488565, Y = 40.477756 }, new Point() { X = -89.488565, Y = 40.478304 } } }, InteriorRings = new List <LinearRing>() { new LinearRing() { Points = new List <Point>() { new Point() { X = -89.487719, Y = 40.478091 }, new Point() { X = -89.487536, Y = 40.478091 }, new Point() { X = -89.487536, Y = 40.477960 }, new Point() { X = -89.487719, Y = 40.477960 }, new Point() { X = -89.487719, Y = 40.478091 } } }, new LinearRing() { Points = new List <Point>() { new Point() { X = -89.486732, Y = 40.478172 }, new Point() { X = -89.486453, Y = 40.478172 }, new Point() { X = -89.486453, Y = 40.478082 }, new Point() { X = -89.486732, Y = 40.478082 }, new Point() { X = -89.486732, Y = 40.478172 } } } } } } } }; //Zone 2 - Variety 1 at 34000 seeds/acre, depth target 5cm; Starter at 4 gal/ac; Insecticide at 2.5 lb/ac RxShapeLookup zone2 = new RxShapeLookup() { Rates = new List <RxRate>() { new RxRate() { Rate = 34000d, RxProductLookupId = seedVariety1RateLookup.Id.ReferenceId }, new RxRate() { Rate = 5d, RxProductLookupId = seedVariety1DepthLookup.Id.ReferenceId }, new RxRate() { Rate = 4d, RxProductLookupId = fertilizerRateLookup.Id.ReferenceId }, new RxRate() { Rate = 2.5, RxProductLookupId = insecticideRateLookup.Id.ReferenceId } }, Shape = new MultiPolygon() { Polygons = new List <Polygon>() { new Polygon() { ExteriorRing = new LinearRing() { Points = new List <Point>() { new Point() { X = -89.488565, Y = 40.477756 }, new Point() { X = -89.485439, Y = 40.477404 }, new Point() { X = -89.485439, Y = 40.476688 }, new Point() { X = -89.488565, Y = 40.476688 }, new Point() { X = -89.488565, Y = 40.477756 } } } } } } }; //Zone 3 - Variety 2 at 29000 seeds/acre, depth target 6 cm; Starter at 6 gal/ac ; Insecticide at 2.75 lb/ac RxShapeLookup zone3 = new RxShapeLookup() { Rates = new List <RxRate>() { new RxRate() { Rate = 29000d, RxProductLookupId = seedVariety2RateLookup.Id.ReferenceId }, new RxRate() { Rate = 6d, RxProductLookupId = seedVariety2DepthLookup.Id.ReferenceId }, new RxRate() { Rate = 6d, RxProductLookupId = fertilizerRateLookup.Id.ReferenceId }, new RxRate() { Rate = 2.75, RxProductLookupId = insecticideRateLookup.Id.ReferenceId } }, Shape = new MultiPolygon() { Polygons = new List <Polygon>() { new Polygon() { ExteriorRing = new LinearRing() { Points = new List <Point>() { new Point() { X = -89.488565, Y = 40.476688 }, new Point() { X = -89.485439, Y = 40.476688 }, new Point() { X = -89.485439, Y = 40.475010 }, new Point() { X = -89.488565, Y = 40.475010 }, new Point() { X = -89.488565, Y = 40.476688 } } } } } } }; //Assembled Rx VectorPrescription vectorPrescription = new VectorPrescription() { Description = "Test Prescription", RxProductLookups = new List <RxProductLookup>() { seedVariety1RateLookup, seedVariety2RateLookup, fertilizerRateLookup, seedVariety1DepthLookup, seedVariety2DepthLookup, insecticideRateLookup }, RxShapeLookups = new List <RxShapeLookup>() { zone1, zone2, zone3 }, CropZoneId = cropZone.Id.ReferenceId, FieldId = field.Id.ReferenceId }; (adm.Catalog.Prescriptions as List <Prescription>).Add(vectorPrescription); //-------------------------- //Export data to file via the Plugin //-------------------------- PrecisionPlanting.ADAPT._2020.Plugin plugin = new Plugin(); plugin.Export(adm, path); }
public Field ImportField(ISOPartfield isoPartfield) { Field field = new Field(); //Field ID ImportIDs(field.Id, isoPartfield.PartfieldID); field.ContextItems = ImportContextItems(isoPartfield.PartfieldID, "ADAPT_Context_Items:Field"); //Farm ID field.FarmId = TaskDataMapper.InstanceIDMap.GetADAPTID(isoPartfield.FarmIdRef); //Area var numericValue = new NumericValue(new CompositeUnitOfMeasure("m2").ToModelUom(), (double)(isoPartfield.PartfieldArea)); field.Area = new NumericRepresentationValue(RepresentationInstanceList.vrReportedFieldArea.ToModelRepresentation(), numericValue.UnitOfMeasure, numericValue); //Name field.Description = isoPartfield.PartfieldDesignator; //Boundary FieldBoundary fieldBoundary = null; PolygonMapper polygonMapper = new PolygonMapper(TaskDataMapper); IEnumerable <Polygon> boundaryPolygons = polygonMapper.ImportBoundaryPolygons(isoPartfield.Polygons); if (boundaryPolygons.Any()) { MultiPolygon boundary = new MultiPolygon(); boundary.Polygons = boundaryPolygons.ToList(); fieldBoundary = new FieldBoundary { FieldId = field.Id.ReferenceId, SpatialData = boundary, }; //Add the boundary to the Catalog if (DataModel.Catalog.FieldBoundaries == null) { DataModel.Catalog.FieldBoundaries = new List <FieldBoundary>(); } DataModel.Catalog.FieldBoundaries.Add(fieldBoundary); field.ActiveBoundaryId = fieldBoundary.Id.ReferenceId; } //Guidance GuidanceGroupMapper guidanceGroupMapper = new GuidanceGroupMapper(TaskDataMapper); IEnumerable <GuidanceGroup> groups = guidanceGroupMapper.ImportGuidanceGroups(isoPartfield.GuidanceGroups); if (groups.Any()) { field.GuidanceGroupIds = groups.Select(g => g.Id.ReferenceId).ToList(); } //Obstacles, flags, etc. if (fieldBoundary != null) { foreach (AttributeShape attributePolygon in polygonMapper.ImportAttributePolygons(isoPartfield.Polygons)) { fieldBoundary.InteriorBoundaryAttributes.Add( new InteriorBoundaryAttribute() { Description = attributePolygon.Name, ContextItems = new List <ContextItem>() { new ContextItem() { Code = "Pr_ISOXML_Attribute_Type", Value = attributePolygon.TypeName } }, Shape = attributePolygon.Shape }); } if (isoPartfield.LineStrings.Any()) { LineStringMapper lsgMapper = new LineStringMapper(TaskDataMapper); foreach (AttributeShape attributeLsg in lsgMapper.ImportAttributeLineStrings(isoPartfield.LineStrings)) { fieldBoundary.InteriorBoundaryAttributes.Add( new InteriorBoundaryAttribute() { Description = attributeLsg.Name, ContextItems = new List <ContextItem>() { new ContextItem() { Code = "Pr_ISOXML_Attribute_Type", Value = attributeLsg.TypeName } }, Shape = attributeLsg.Shape }); } } if (isoPartfield.Points.Any()) { PointMapper pointMapper = new PointMapper(TaskDataMapper); foreach (AttributeShape attributePoint in pointMapper.ImportAttributePoints(isoPartfield.Points)) { fieldBoundary.InteriorBoundaryAttributes.Add( new InteriorBoundaryAttribute() { Description = attributePoint.Name, ContextItems = new List <ContextItem>() { new ContextItem() { Code = "Pr_ISOXML_Attribute_Type", Value = attributePoint.TypeName } }, Shape = attributePoint.Shape }); } } } //TODO store Partfield Code as ContextItem return(field); }
public static IEnumerable <Polygon> GetPolygons(this FieldBoundary fieldBoundary) { return(fieldBoundary.SpatialData?.Polygons ?? Enumerable.Empty <Polygon>()); }