Esempio n. 1
0
 public void SetMostRecentMeterValue(WorkingData meter, RepresentationValue value)
 {
     if (_meterToPreviousValue.ContainsKey(meter))
     {
         _meterToPreviousValue[meter] = value;
     }
     else
     {
         _meterToPreviousValue.Add(meter, value);
     }
 }
        public static void DescribeSpatialData(Catalog catalog, LoggedData loggedData)
        {
            //Coincident Operations
            DescribeCoincidentOperations(loggedData);

            Console.WriteLine();
            Console.WriteLine("-----------------------");
            Console.WriteLine("Spatial Data");
            Console.WriteLine("-----------------------");
            Console.WriteLine();

            foreach (OperationData operationData in loggedData.OperationData)
            {
                //1.  Create some collections for tracking high-level/header information on the implement devices and sensors.
                List <WorkingData>    operationDataWorkingDatas       = new List <WorkingData>();
                Dictionary <int, int> useToDeviceConfigurationMapping = new Dictionary <int, int>();

                //ADAPT models spatial data in multiple depths according to a virtual hierarchy describing the data as it relates to the physical layout of the implement.
                //In the 2020 implementation,
                //  depth 0 refers to a single device representing the entire width of the implement and any sensors reporting data across the implement.
                //  depth 1 generally refers to row-by-row data, where multiple DeviceElements representing individual rows contain one or more sensors
                //  depth 2 is present on planting data where there are multiple varieties configured in specific parts of the implement.  In that case
                //depth 1 contains a description of the varieties
                //depth 2 contains the row-level data
                for (int depth = 0; depth <= operationData.MaxDepth; depth++)  //MaxDepth defines the maximum depth of data on an OperationData
                {
                    //A DeviceElementUse is an instance of a DeviceElement/DeviceElementConfiguration within a specific OperationData.
                    //It contains the collection of all data elements (WorkingData objects) reported on that DeviceElement during the Operation.
                    IEnumerable <DeviceElementUse> deviceElementUses = operationData.GetDeviceElementUses(depth);
                    foreach (DeviceElementUse deviceElementUse in deviceElementUses)
                    {
                        //Track the DeviceConfiguration that this DeviceElementUse relates to for reconciling data values to implement offsets for precise location
                        useToDeviceConfigurationMapping.Add(deviceElementUse.Id.ReferenceId, deviceElementUse.DeviceConfigurationId);

                        //A WorkingData is essentially a Sensor.   It is the definition of some object that will report data per spatial point.
                        //List all such sensors on this DeviceElementUse within this Operation
                        IEnumerable <WorkingData> workingDatas = deviceElementUse.GetWorkingDatas();

                        //Track these in the comprehensive list
                        operationDataWorkingDatas.AddRange(workingDatas);
                    }
                }

                //2. Illustrate any multivariety data present here.
                //If an OperationData from the 2020 plugin contains a maxdepth of 2, then level 1 describes parts of the planter with specific varieties
                if (operationData.OperationType == OperationTypeEnum.SowingAndPlanting &&
                    operationData.MaxDepth == 2)
                {
                    //------------------
                    //Split Planter data
                    //-------------------
                    Console.WriteLine($"OperationData {operationData.Id.ReferenceId} is planter data containing multiple varieties assigned to specific rows:");
                    IEnumerable <DeviceElementUse> levelOneDeviceElementUses = operationData.GetDeviceElementUses(1);
                    foreach (DeviceElementUse use in levelOneDeviceElementUses)
                    {
                        //Retrieve the DeviceElementConfiguration object that matches the DeviceElementUse on this specific operation
                        DeviceElementConfiguration deviceElementConfig = catalog.DeviceElementConfigurations.First(d => d.Id.ReferenceId == use.DeviceConfigurationId);

                        //We've named the Level 1 device elements with the varieties in this situation
                        Console.WriteLine(deviceElementConfig.Description);

                        //All rows planting that variety will be children of this device element,
                        //and the level 1 DeviceElementUse will have a WorkingData called "vrProductIndex" that will map to the variety
                    }
                    Console.WriteLine();
                }
                else if (operationData.OperationType == OperationTypeEnum.SowingAndPlanting &&
                         operationData.MaxDepth == 1 &&
                         operationDataWorkingDatas.Select(w => w.Representation.Code).Any(c => c == "vrProductIndex"))
                {
                    //------------------------------------------------------
                    //vSetSelect & mSet data (variable multi-hybrid planting)
                    //------------------------------------------------------
                    Console.WriteLine($"OperationData {operationData.Id.ReferenceId} is planter data containing multiple varieties dynamically assigned to each row.");

                    //Make a dictionary of product names
                    Dictionary <int, string> productNames = new Dictionary <int, string>();
                    foreach (int productID in operationData.ProductIds)
                    {
                        List <DeviceElementUse> productDeviceElementUses = new List <DeviceElementUse>();
                        Product product = catalog.Products.First(p => p.Id.ReferenceId == productID);
                        productNames.Add(productID, product.Description);
                    }

                    Console.WriteLine($"The following varieties are planted at various points in the field: {string.Join(", ", productNames.Values)}");

                    SpatialRecord firstPoint = operationData.GetSpatialRecords().First();
                    Console.WriteLine("For example, on the first point...");

                    //Examine the content of each DeviceElementUse at the row level with a product index working data
                    foreach (DeviceElementUse deviceElementUse in operationData.GetDeviceElementUses(1)) //1 is the row level where OperationData.MaxDepth == 1.
                    {
                        foreach (WorkingData productIndexWorkingData in deviceElementUse.GetWorkingDatas().Where(w => w.Representation.Code == "vrProductIndex"))
                        {
                            NumericRepresentationValue productValue = firstPoint.GetMeterValue(productIndexWorkingData) as NumericRepresentationValue;
                            int productIndex = (int)productValue.Value.Value;
                            DeviceElementConfiguration deviceElementConfiguration = catalog.DeviceElementConfigurations.First(d => d.Id.ReferenceId == deviceElementUse.DeviceConfigurationId);
                            Console.WriteLine($"{deviceElementConfiguration.Description} planted {productNames[productIndex]}.");
                        }
                    }

                    Console.WriteLine();
                }


                //3. Read the point-by-point data
                //With the data definition of the OperationData now in-hand, we can iterate the collection of physical points on the field to read the data.
                //Rather than writing out each data value to the screen, we will assemble them into collections to summarize after iterating all data
                Dictionary <WorkingData, List <object> > operationSpatialDataValues = new Dictionary <WorkingData, List <object> >();
                Dictionary <WorkingData, string>         numericDataUnitsOfMeasure  = new Dictionary <WorkingData, string>();

                //Similarly, we will track the geospatial envelope of the data to illustrate lat/lon data present
                double maxLat = Double.MinValue;
                double minLat = Double.MaxValue;
                double maxLon = Double.MinValue;
                double minLon = Double.MaxValue;

                Console.WriteLine("Reading point-by-point data...");
                Console.WriteLine();

                //IMPORTANT
                //To effectively manage memory usage, avoid invoking the iterator multiple times or iterate the entire list in a Linq expression.
                //The linq expressions below do not necessarily take this advice as the focus here is illustrative.
                foreach (SpatialRecord spatialRecord in operationData.GetSpatialRecords())
                {
                    //2020 data will always be in point form
                    Point point = spatialRecord.Geometry as Point;

                    //Track the lat/lon to illustrate the envelope of the dataset
                    double latitude  = point.Y;
                    double longitude = point.X;
                    if (latitude < minLat)
                    {
                        minLat = latitude;
                    }
                    if (latitude > maxLat)
                    {
                        maxLat = latitude;
                    }
                    if (longitude < minLon)
                    {
                        minLon = longitude;
                    }
                    if (longitude > maxLon)
                    {
                        maxLon = longitude;
                    }

                    //Examine the actual data on the points
                    foreach (WorkingData operationWorkingData in operationDataWorkingDatas)
                    {
                        //Create a List for data values on the first encounter with this WorkingData
                        if (!operationSpatialDataValues.ContainsKey(operationWorkingData))
                        {
                            operationSpatialDataValues.Add(operationWorkingData, new List <object>());
                        }

                        //---------------
                        //Representations
                        //---------------
                        //ADAPT publishes standard representations that often equate to ISO11783-11 Data Dictionary Identifiers (DDIs)
                        //These representations define a common type of agricultural measurement.
                        //Where Precision Planting has implemented representations that are not published with ADAPT, they are marked as UserDefined
                        //and the Name describes what each is.

                        //--------------------
                        //RepresentationValues
                        //--------------------
                        //A Representation Value is a complex type that allows the value to
                        //be augmented the full representation, the unit of measure and other data.

                        RepresentationValue representationValue = spatialRecord.GetMeterValue(operationWorkingData);

                        //Values reported may be of type Numeric or Enumerated
                        if (representationValue is NumericRepresentationValue)
                        {
                            NumericRepresentationValue numericRepresentationValue = representationValue as NumericRepresentationValue;
                            operationSpatialDataValues[operationWorkingData].Add(numericRepresentationValue.Value.Value); //Value is a double

                            //--------------------
                            //Units of Measure
                            //--------------------
                            //Store the UOM on the first encounter
                            if (!numericDataUnitsOfMeasure.ContainsKey(operationWorkingData))
                            {
                                numericDataUnitsOfMeasure.Add(operationWorkingData, numericRepresentationValue.Value.UnitOfMeasure.Code);

                                //ADAPT units of measure are documented in the Resources/UnitSystem.xml that is installed in any ADAPT project
                                //They take the form of unitCode[postive exponent]unitcode[negative exponent]
                                //Where the exponents allow for complex units.   E.g.s,
                                //lb = pounds
                                //ac = acres
                                //lb1ac-1 = pounds per acre
                                //mm3m-2 = cubic millimeters per square meter
                            }
                        }
                        else if (representationValue is EnumeratedValue)
                        {
                            EnumeratedValue enumeratedValue = representationValue as EnumeratedValue;
                            operationSpatialDataValues[operationWorkingData].Add(enumeratedValue.Value.Value); //Value is a string
                        }
                    }
                }

                Console.WriteLine();
                Console.WriteLine("-----------------------");
                Console.WriteLine($"{Enum.GetName(typeof(OperationTypeEnum), operationData.OperationType)} data");
                Console.WriteLine("-----------------------");
                Console.WriteLine();

                Console.WriteLine($"Data logged within envelope bounded by {minLat},{minLon} and {maxLat},{maxLon}.");
                Console.WriteLine();

                foreach (WorkingData workingData in operationSpatialDataValues.Keys)
                {
                    //We can obtain a reference to the part of the machine that logged the data via the DeviceConfigurationId property.
                    DeviceElementConfiguration deviceElementConfig = catalog.DeviceElementConfigurations.FirstOrDefault(d => d.Id.ReferenceId == useToDeviceConfigurationMapping[workingData.DeviceElementUseId]);
                    string deviceElementName = deviceElementConfig.Description;

                    if (operationSpatialDataValues[workingData].Any())
                    {
                        if (workingData is NumericWorkingData)
                        {
                            double max     = operationSpatialDataValues[workingData].Cast <double>().Max();
                            double average = operationSpatialDataValues[workingData].Cast <double>().Average();
                            double min     = operationSpatialDataValues[workingData].Cast <double>().Min();
                            string uom     = numericDataUnitsOfMeasure[workingData];
                            Console.WriteLine($"Numeric Working Data {deviceElementConfig.Description}-{workingData.Representation.Description} had a minimum value of {min}, and average of {average} and a maximum value of {max} {uom}.");
                            Console.WriteLine();
                        }
                        else if (workingData is EnumeratedWorkingData)
                        {
                            EnumeratedWorkingData    enumeratedWorkingData    = workingData as EnumeratedWorkingData;
                            EnumeratedRepresentation enumeratedRepresentation = enumeratedWorkingData.Representation as EnumeratedRepresentation;
                            IEnumerable <string>     enumerationValues        = enumeratedRepresentation.EnumeratedMembers.Select(e => e.Value);

                            foreach (string enumerationValue in enumerationValues)
                            {
                                int count = operationSpatialDataValues[workingData].Cast <string>().Count(v => v == enumerationValue);
                                Console.WriteLine($"Enumerated Working Data {deviceElementConfig.Description}-{workingData.Representation.Description} had {count} values of {enumerationValue}.");
                                Console.WriteLine();
                            }
                        }
                    }
                }
            }
        }
Esempio n. 3
0
 public void SetMeterValue(WorkingData workingData, RepresentationValue value)
 {
     _meterValues.Add(workingData.Id.ReferenceId, value);
 }
        /// <summary>
        /// Draws a Red polygon if all values 0, a DarkMagenta polygon if all values the same non-zero value, or else themes Red/DarkOrange/Gold/YellowGreen/LawnGreen/LimeGreen/ForestGreen/DarkGreen.
        /// </summary>
        /// <param name="operation"></param>
        /// <param name="workingDataKey"></param>
        public void ThemeMap(string workingDataKey)
        {
            using (var graphics = _spatialViewer.CreateGraphics())
            {
                graphics.Clear(System.Drawing.Color.White);
                _drawingUtil = new DrawingUtil(_spatialViewer.Width, _spatialViewer.Height, graphics);

                List <Point>  projectedPoints = new List <Point>();
                List <double> doubleValues    = null;
                foreach (SpatialRecord record in _spatialRecords)
                {
                    Point point = record.Geometry as Point;
                    projectedPoints.Add(point.ToUtm());

                    if (_workingDataDictionary.ContainsKey(workingDataKey))
                    {
                        WorkingData         workingData = _workingDataDictionary[workingDataKey];
                        RepresentationValue repValue    = record.GetMeterValue(workingData);
                        if (repValue is NumericRepresentationValue)
                        {
                            NumericRepresentationValue numericValue = repValue as NumericRepresentationValue;
                            if (doubleValues == null)
                            {
                                doubleValues = new List <double>();
                            }
                            doubleValues.Add(numericValue.Value.Value);
                        }
                        else if (repValue is EnumeratedValue)
                        {
                            EnumeratedValue enumValue = repValue as EnumeratedValue;
                            if (enumValue.Representation.Code == "dtRecordingStatus")
                            {
                                if (doubleValues == null)
                                {
                                    doubleValues = new List <double>();
                                }
                                doubleValues.Add(enumValue.Value.Value == "On" ? 1d : -1d);
                            }
                        }
                    }
                }

                if (!projectedPoints.Any())
                {
                    return;
                }

                _drawingUtil.SetMinMax(projectedPoints);
                var screenPolygon = projectedPoints.Select(point => point.ToXy(_drawingUtil.MinX, _drawingUtil.MinY, _drawingUtil.GetDelta())).ToArray();

                if (screenPolygon.All(p => !double.IsNaN(p.X) && !double.IsNaN(p.Y)))
                {
                    if (doubleValues == null)
                    {
                        //WorkingData is not numeric
                        graphics.DrawPolygon(DrawingUtil.B_Black, screenPolygon);
                    }
                    else
                    {
                        if (doubleValues.Max() == doubleValues.Min())
                        {
                            //All values are the same
                            if (doubleValues.Max() <= 0d)
                            {
                                //Zero values
                                graphics.DrawPolygon(DrawingUtil.E_Red, screenPolygon);
                            }
                            else
                            {
                                //Non-zero values
                                graphics.DrawPolygon(DrawingUtil.L_DarkGreen, screenPolygon);
                            }
                        }
                        else
                        {
                            double        max                  = doubleValues.Max();
                            double        min                  = doubleValues.Min();
                            double        average              = doubleValues.Average();
                            List <double> removedZeroValues    = doubleValues.Where(dv => dv != 0).ToList();
                            double        avarageWithoutZeroes = removedZeroValues.Average();
                            if (average != avarageWithoutZeroes)
                            {
                                min = removedZeroValues.Min();
                            }


                            int    i     = 0;
                            double range = (max - min) / 7.0;
                            double e7th  = min;
                            double f7th  = e7th + range;
                            double g7th  = f7th + range;
                            double h7th  = g7th + range;
                            double i7th  = h7th + range;
                            double j7th  = i7th + range;
                            double k7th  = j7th + range;
                            double l7th  = max;

                            foreach (System.Drawing.PointF f in screenPolygon)
                            {
                                double             dbl = i < doubleValues.Count ? doubleValues[i] : 0d; //Values will be in same order as points
                                System.Drawing.Pen pen = DrawingUtil.B_Black;

                                if (dbl <= e7th)
                                {
                                    pen = DrawingUtil.E_Red;
                                }
                                else if (dbl <= f7th)
                                {
                                    pen = DrawingUtil.F_DarkOrange;
                                }
                                else if (dbl <= g7th)
                                {
                                    pen = DrawingUtil.G_Gold;
                                }
                                else if (dbl <= h7th)
                                {
                                    pen = DrawingUtil.H_YellowGreen;
                                }
                                else if (dbl <= i7th)
                                {
                                    pen = DrawingUtil.I_LawnGreen;
                                }
                                else if (dbl <= j7th)
                                {
                                    pen = DrawingUtil.J_LimeGreen;
                                }
                                else if (dbl <= k7th)
                                {
                                    pen = DrawingUtil.K_ForestGreen;
                                }
                                else if (dbl <= l7th)
                                {
                                    pen = DrawingUtil.L_DarkGreen;
                                }

                                graphics.DrawEllipse(pen, new System.Drawing.RectangleF(f.X, f.Y, 2, 2));
                                i++;
                            }
                        }
                    }
                }
            }
        }
Esempio n. 5
0
 public void SetMeterValue(Meter meter, RepresentationValue value)
 {
     _meterValues.Add(meter.Id.ReferenceId, value);
 }