import { cloneDeep } from "lodash"; import { pond } from "protobuf-ts/pond"; import { or } from "utils/types"; import area from "@turf/area"; import { Feature } from "geojson"; import { GeometryMapping } from "./GeometryMapping"; import GrainDescriber from "grain/GrainDescriber"; export class Field { public settings: pond.FieldSettings = pond.FieldSettings.create(); public status: pond.FieldStatus = pond.FieldStatus.create(); public permissions: pond.Permission[] = []; public static create(pf?: pond.Field): Field { let my = new Field(); if (pf) { my.settings = pond.FieldSettings.fromObject(cloneDeep(or(pf.settings, {}))); my.status = pond.FieldStatus.fromObject(cloneDeep(or(pf.status, {}))); my.permissions = pf.fieldPermissions; } return my; } public static clone(other?: Field): Field { if (other) { return Field.create( pond.Field.fromObject({ settings: cloneDeep(other.settings), status: cloneDeep(other.status), permissions: cloneDeep(other.permissions) }) ); } return Field.create(); } public calculateAcres(): number { let totalAcres = 0; const metersToAcresConversionValue = 0.00024710538146717; let geoData = this.settings.fieldGeoData; if (geoData) { //round to 2 decimal places totalAcres = Math.round( area( GeometryMapping.geoJSON(geoData.geoShape, geoData.shapes, geoData.holes) as Feature ) * metersToAcresConversionValue * 100 ) / 100; } return totalAcres; } public static any(data: any): Field { return Field.create(pond.Field.fromObject(cloneDeep(data))); } public key(): string { return this.settings.key; } public fieldName(): string { return this.settings.fieldName; } public landLoc(): string { return this.settings.landLocation; } public crop(): pond.Grain { return this.settings.crop; } public name(): string { return this.settings.fieldName; } public objectType(): pond.ObjectType { return pond.ObjectType.OBJECT_TYPE_FIELD; } public objectTypeString(): string { return "Field"; } public grain(): pond.Grain { return this.settings.crop; } public subtype(): string { return this.settings.grainSubtype; } public customType(): string { let c = ""; if (this.settings) { c = this.settings.customGrain; } return c; } public acres(): number { if (this.settings.acres > 0) { return this.settings.acres; } else { return this.calculateAcres(); } } //these are for when using the field as a source for a grain transaction to compare if the destination matches public storage(): pond.BinStorage { let storage = pond.BinStorage.BIN_STORAGE_SUPPORTED_GRAIN; if (this.settings.crop === pond.Grain.GRAIN_CUSTOM) { storage = pond.BinStorage.BIN_STORAGE_UNSUPPORTED_GRAIN; } return storage; } /** * returns the bushels per tonne set in the bins settings, if not set will return 1 * @returns 1 or bushels per tonne */ public bushelsPerTonne(): number { //trying to avoid a divide by 0 error by only returning a value greater than 0 //since to get the weight you divide the current bushels by the bushels per tonne let bpt = 1; if (this.settings.bushelsPerTonne > 0) { bpt = this.settings.bushelsPerTonne; } return bpt; } public center(): pond.Coordinates { let coords = pond.Coordinates.create(); if (this.settings.fieldGeoData) { let minLong = 0; let minLat = 0; let maxLong = 0; let maxLat = 0; this.settings.fieldGeoData.shapes.forEach(shape => { shape.points.forEach(pair => { if (pair.longitude < minLong || minLong === 0) minLong = pair.longitude; if (pair.longitude > maxLong || maxLong === 0) maxLong = pair.longitude; if (pair.latitude < minLat || minLat === 0) minLat = pair.latitude; if (pair.latitude > maxLat || maxLat === 0) maxLat = pair.latitude; }); }); coords.longitude = (maxLong + minLong) / 2; coords.latitude = (maxLat + minLat) / 2; } return coords; } public grainName(): string { if (this.grain() !== pond.Grain.GRAIN_INVALID) { if (this.grain() === pond.Grain.GRAIN_CUSTOM) { return this.customType(); } else { return GrainDescriber(this.grain()).name; } } else { return "None"; } } }