private static (Operation operation, OperationMxProcessing operationPrescription) BuildTheGeoJsonOutput(RuleResult collectRuleResult, List <Value> values, Operation buildGeoJsonOperation = null) { var cityCount = values.Count; // Build the Javascript template for creating the entire GeoJSON Value var valueBody = "{\"type\":\"FeatureCollection\",\"features\":["; for (var ix = 0; ix < cityCount; ix++) { if (ix > 0) { valueBody += ","; } valueBody += $"${{{ix}}}"; } valueBody += "]}"; var valueTemplate = $"{{JSON.parse('{valueBody}')}}"; // Add an Operation to reference the collect Rule and merge all of the results into one GeoJSON if (buildGeoJsonOperation == null) { var opKey = values.OperandKey(EntityType.Value); buildGeoJsonOperation = collectRuleResult.CreateUpdateOperation(new[] { opKey }, GuidHelpers.NewTimeUuid(), valueTemplate); } else { var opKey = values.OperandKey(EntityType.Value, buildGeoJsonOperation.Operands[0].EntityId); buildGeoJsonOperation = buildGeoJsonOperation.RecreateUpdateOperation(collectRuleResult, new[] { opKey }, valueTemplate); } var buildGeoJsonPrescription = buildGeoJsonOperation.AddUpdate(); return(buildGeoJsonOperation, buildGeoJsonPrescription); }
private static (List <Operation> operations, List <OperationMxProcessing> operationPrescriptions) BuildTheCityDistances(RuleResult cityRuleResults, List <Value> values) { var operations = new List <Operation>(); var operationPrescriptions = new List <OperationMxProcessing>(); // Build the Javascript template for calculating the length of each connecting GeoJSON line // Concept - Id of this city, then formula to calculate each distance and output the result as a sorted list. const string cityATempl = "{{'cityAId':'{0}','destinations':["; const string lonTempl = "JSON.parse('${{{0}}}')['geometry']['coordinates'][0]"; const string latTempl = "JSON.parse('${{{0}}}')['geometry']['coordinates'][1]"; const string getDistTempl = "{{'cityBId':'{0}','distance':Math.pow(Math.pow({1} - {2}, 2) + Math.pow({3} - {4}, 2), 0.5),'usage':'not set'}}"; for (var ix = 0; ix < values.Count; ix++) { var jTemplate = new StringBuilder(); jTemplate.AppendLine("["); jTemplate.AppendFormat(cityATempl, values[ix].EntityId); jTemplate.AppendLine(); var cityALonTempl = string.Format(lonTempl, ix); var cityALatTempl = string.Format(latTempl, ix); var needsComma = false; for (var jx = 0; jx < values.Count; jx++) { if (ix == jx) { continue; } var cityBLonTempl = string.Format(lonTempl, jx); var cityBLatTempl = string.Format(latTempl, jx); var cityAtoBDistTempl = string.Format(getDistTempl, values[jx].EntityId, cityALonTempl, cityBLonTempl, cityALatTempl, cityBLatTempl); if (needsComma) { jTemplate.AppendLine(","); } jTemplate.Append(cityAtoBDistTempl); if (!needsComma) { needsComma = true; } } jTemplate.AppendLine(); jTemplate.AppendLine("].sort(function(a, b) {return a.distance - b.distance;})"); // Adding a slice at the end (for the 10 shortest paths) reduce the overall file size but did not seem to reduce processing time // jTemplate.AppendLine("].sort(function(a, b) {return a.distance - b.distance;}).slice(0, 10)"); jTemplate.AppendLine("}"); jTemplate.AppendLine("]"); var jTempl = jTemplate.ToString(); // Although the source values are always the same we need a new OperandKey each time // for each new Value to be generated var opKeys = new[] { values.OperandKey(EntityType.Value) }; // Add an Operation to reference the collect Rule and merge all of the results into one GeoJSON var buildCityDistancesOperation = cityRuleResults.CreateUpdateOperation(opKeys, GuidHelpers.NewTimeUuid(), jTempl); var buildCityDistancesPrescription = buildCityDistancesOperation.AddUpdate(); operations.Add(buildCityDistancesOperation); operationPrescriptions.Add(buildCityDistancesPrescription); } return(operations, operationPrescriptions); }