/// <summary> /// Generate an excel output of all nodes with /// - their computed coordinates relative to entry /// - their distance from entry /// - their distance from the ground surface above them /// </summary> /// <param name="visualTopoFile"></param> /// <param name="dataSet"></param> private void Run_ExcelExport(string visualTopoFile, DEMDataSet dataSet) { try { StopwatchLog timeLog = StopwatchLog.StartNew(_logger); //======================= // Generation params // string outputDir = Directory.GetCurrentDirectory(); VisualTopoModel model = _visualTopoService.LoadFile(visualTopoFile, Encoding.GetEncoding("ISO-8859-1") , decimalDegrees: true , ignoreRadialBeams: true); // for debug, //var b = GetBranches(model); // graph list of all nodes //var lowestPoint = model.Sets.Min(s => s.Data.Min(d => d.GlobalGeoPoint?.Elevation ?? 0)); BoundingBox bbox = model.BoundingBox // relative coords .Translate(model.EntryPoint.Longitude, model.EntryPoint.Latitude, model.EntryPoint.Elevation ?? 0) // absolute coords .Pad(50) // margin around model .ReprojectTo(model.SRID, dataSet.SRID); _elevationService.DownloadMissingFiles(dataSet, bbox); timeLog.LogTime("Terrain height map"); //======================= // Get entry elevation (need to reproject to DEM coordinate system first) // and sections entry elevations // _visualTopoService.ComputeFullCavityElevations(model, dataSet); // will add TerrainElevationAbove and entry elevations // CSV string csvFileName = Path.GetFileName(Path.ChangeExtension(visualTopoFile, ".csv")); File.WriteAllBytes(csvFileName, _visualTopoService.ExportToCsv(model, "\t").ToArray()); // Excel string xlsFileName = Path.GetFileName(Path.ChangeExtension(visualTopoFile, ".xlsx")); using (MemoryStream ms = _visualTopoService.ExportToExcel(model, autoFitColumns: false)) { File.WriteAllBytes(xlsFileName, ms.ToArray()); } timeLog.LogTime("Cavity points elevation"); timeLog.LogTime("3D model"); } catch (Exception ex) { _logger.LogError("Error :" + ex.Message); } }
/// <summary> /// Generates a VisualTopo file 3D model /// </summary> /// <remarks>LT* (Lambert Carto) projections are not supported and could produce imprecise results (shifted by +10meters)</remarks> /// <param name="vtopoFile">VisualTopo .TRO file</param> /// <param name="imageryProvider">Imagery provider for terrain texture. Set to null for untextured model</param> /// <param name="bboxMarginMeters">Terrain margin (meters) around VisualTopo model</param> public void Run_3DModelGeneration(string vtopoFile, ImageryProvider imageryProvider, float bboxMarginMeters = 1000, bool generateTopoOnlyModel = false, float zFactor = 1f) { try { //======================= // Generation params // int outputSRID = 3857; // Output SRID float lineWidth = 1.0F; // Topo lines width (meters) var dataset = DEMDataSet.AW3D30; // DEM dataset for terrain and elevation int TEXTURE_TILES = 8; // Texture quality (number of tiles for bigger side) 4: med, 8: high, 12: ultra string outputDir = Directory.GetCurrentDirectory(); bool GENERATE_LINE3D = false; //======================= // Open and parse file // // model will have available properties // => Graph (nodes/arcs) // => BoundingBox // => Topology3D -> list of point-to-point lines // => SRID of model file StopwatchLog timeLog = StopwatchLog.StartNew(_logger); VisualTopoModel model = _visualTopoService.LoadFile(vtopoFile, Encoding.GetEncoding("ISO-8859-1") , decimalDegrees: true , ignoreRadialBeams: true , zFactor); timeLog.LogTime($"Loading {vtopoFile} model file"); // for debug, //var b = GetBranches(model); // graph list of all nodes //var lowestPoint = model.Sets.Min(s => s.Data.Min(d => d.GlobalGeoPoint?.Elevation ?? 0)); BoundingBox bbox = model.BoundingBox // relative coords .Translate(model.EntryPoint.Longitude, model.EntryPoint.Latitude, model.EntryPoint.Elevation ?? 0) // absolute coords .Pad(bboxMarginMeters) // margin around model .ReprojectTo(model.SRID, dataset.SRID); // DEM coords // Get height map // Note that ref Bbox means that the bbox will be adjusted to match DEM data var heightMap = _elevationService.GetHeightMap(ref bbox, dataset, downloadMissingFiles: true); var bboxTerrainSpace = bbox.ReprojectTo(dataset.SRID, outputSRID); // terrain coords timeLog.LogTime("Terrain height map"); //======================= // Get entry elevation (need to reproject to DEM coordinate system first) // and sections entry elevations // _visualTopoService.ComputeFullCavityElevations(model, dataset, zFactor); // will add TerrainElevationAbove and entry elevations _visualTopoService.Create3DTriangulation(model); timeLog.LogTime("Cavity points elevation"); // Model origin GeoPoint axisOriginWorldSpace = model.EntryPoint.ReprojectTo(model.SRID, outputSRID) .CenterOnOrigin(bboxTerrainSpace); Vector3 axisOriginModelSpace = model.EntryPoint.AsVector3(); //======================= // Local transform function from model coordinates (relative to entry, in meters) // and global coordinates absolute in final 3D model space // IEnumerable <GeoPoint> TransformLine(IEnumerable <GeoPoint> line) { var newLine = line.Translate(model.EntryPoint) // Translate to entry (=> global topo coord space) .ReprojectTo(model.SRID, outputSRID) // Reproject to terrain coord space .CenterOnOrigin(bboxTerrainSpace) // Center on terrain space origin .CenterOnOrigin(axisOriginWorldSpace); return(newLine); }; //======================= // 3D model // var gltfModel = _gltfService.CreateNewModel(); // Add X/Y/Z axis on entry point var axis = _meshService.CreateAxis(); _gltfService.AddMesh(gltfModel, "Axis", axis, doubleSided: false); int i = 0; var triangulation = model.TriangulationFull3D.Clone() .Translate(axisOriginModelSpace) // already zScaled if zFactor > 1 .ReprojectTo(model.SRID, outputSRID) .CenterOnOrigin(bboxTerrainSpace) .CenterOnOrigin(axisOriginWorldSpace.AsVector3()); gltfModel = _gltfService.AddMesh(gltfModel, "Cavite3D", model.TriangulationFull3D, VectorsExtensions.CreateColor(0, 255, 0), doubleSided: false); if (GENERATE_LINE3D) { foreach (var line in model.Topology3D) // model.Topology3D is the graph of topo paths { // Add line to model gltfModel = _gltfService.AddLine(gltfModel , string.Concat("GPX", i++) // name of 3D node , TransformLine(line) // call transform function , color: VectorsExtensions.CreateColor(255, 0, 0, 128) , lineWidth); } } timeLog.LogTime("Topo 3D model"); //axis = _meshService.CreateAxis(10,100); //_gltfService.AddMesh(gltfModel, "Axis", axis, doubleSided: false); if (generateTopoOnlyModel) { // Uncomment this to save 3D model for topo only (without terrain) gltfModel.SaveGLB(string.Concat(Path.GetFileNameWithoutExtension(vtopoFile) + $"Z{zFactor}_TopoOnly.glb")); } // Reproject and center height map coordinates heightMap = heightMap.ReprojectTo(dataset.SRID, outputSRID) .CenterOnOrigin(bboxTerrainSpace) .ZScale(zFactor) .CenterOnOrigin(axisOriginWorldSpace); //.BakeCoordinates(); timeLog.LogTime("Height map transform"); //======================= // Textures // PBRTexture pbrTexture = null; if (imageryProvider != null) { TileRange tiles = _imageryService.DownloadTiles(bbox, imageryProvider, TEXTURE_TILES); string fileName = Path.Combine(outputDir, "Texture.jpg"); timeLog.LogTime("Imagery download"); Console.WriteLine("Construct texture..."); //TextureInfo texInfo = _imageryService.ConstructTexture(tiles, bbox, fileName, TextureImageFormat.image_jpeg); var topoTexture = model.Topology3D.SelectMany(l => l).Translate(model.EntryPoint).ReprojectTo(model.SRID, 4326); TextureInfo texInfo = _imageryService.ConstructTextureWithGpxTrack(tiles, bbox, fileName, TextureImageFormat.image_jpeg , topoTexture, false); pbrTexture = PBRTexture.Create(texInfo, null); timeLog.LogTime("Texture creation"); } // //======================= // Triangulate height map _logger.LogInformation($"Triangulating height map and generating 3D mesh..."); gltfModel = _gltfService.AddTerrainMesh(gltfModel, heightMap, pbrTexture); gltfModel.SaveGLB(string.Concat(Path.GetFileNameWithoutExtension(vtopoFile) + $"Z{zFactor}.glb")); timeLog.LogTime("3D model"); } catch (Exception ex) { _logger.LogError("Error :" + ex.Message); } }
/// <summary> /// Compiles the given <paramref name="buddyText"/> into a TDIL file as string. /// </summary> /// <param name="buddyText">Buddy language text to compile</param> /// <returns>Compiled buddy text</returns> /// <exception cref="ArgumentNullException">If the given <paramref name="buddyText"/> is NULL or empty</exception> /// <exception cref="BuddyCompilerException">If something went wrong during the compilation process</exception> public virtual string Compile(string buddyText) { if (string.IsNullOrEmpty(buddyText)) { throw new ArgumentNullException(nameof(buddyText)); } StopwatchLog compilerStopwatch = StopwatchLog.StartNew(LogCompilerPerformance); TdilFileWriter tdilFileWriter = new TdilFileWriter("0.1.2"); try { // TODO Remove workaround add 'Vorbedingung' if (!buddyText.Contains("Vorbedingung: -") && buddyText.Contains("Anwendung: ")) { int insertPoint = buddyText.IndexOf("Schritte:"); buddyText = buddyText.Insert(insertPoint, "Vorbedingung: -\r\n\r\n"); } // TODO Remove workaround add final linefeeds if (!buddyText.EndsWith("\r\n")) { buddyText += "\r\n"; } // Process text StopwatchLog textProcessorStopwatch = StopwatchLog.StartNew(LogBuddyTextProcessorPerformance); BuddyTextInfo buddyTextInfo = _buddyTextProcessor.ProcessText(buddyText); textProcessorStopwatch.Dispose(buddyTextInfo); // In the case of an short form, create standard names if (buddyTextInfo.IsShortForm) { buddyTextInfo.ApplicationText = "untitled"; buddyTextInfo.UseCaseText = "untitled"; buddyTextInfo.ScenarioText = "untitled"; } // TODO Check if this is a workaround and remove it if (string.IsNullOrEmpty(buddyTextInfo.VersionText)) { buddyTextInfo.VersionText = "*"; } // Little verification ushort expectedNoOfSteps = CalculateNoOfSteps(buddyText); if (expectedNoOfSteps != buddyTextInfo.Steps.Length) { ThrowUncompilableDirectiveException(buddyText, expectedNoOfSteps, buddyTextInfo.Steps.Length); } string[] buddyTextSteps = buddyTextInfo.Steps; // Normalize directives string[] normalizedBuddyTextSteps; using (StopwatchLog.StartNew(LogNormalizingPerformance)) { normalizedBuddyTextSteps = NormalizeSteps(buddyTextSteps, buddyTextInfo.Parameters); } // Create unit name UnitName unitName = new UnitName(buddyTextInfo.ApplicationText, buddyTextInfo.VersionText, buddyTextInfo.UseCaseText, buddyTextInfo.ScenarioText); string qualifiedUnitName = unitName.ToQualifiedString(); using (CompilingContext compilingContext = new CompilingContext()) { // Compile directives string[] directiveSet = new string[1000]; int pr = 0; using (StopwatchLog.StartNew(LogInstructionTranslationPerformance)) { for (int i = -1; ++i != normalizedBuddyTextSteps.Length;) { string actionLine = normalizedBuddyTextSteps[i]; string directive = _instructionTranslator.ToDirective(actionLine); directiveSet[pr++] = directive; } Array.Resize(ref directiveSet, pr); } // Add alias references string[] aliasReferenceSet = compilingContext.AliasReferenceSet; tdilFileWriter.AddAlias(aliasReferenceSet); // Add unit references string[] unitReferenceSet = compilingContext.UnitReferenceSet; string[] qualifiedUnitNames = ToQualifiedUnitNames(unitReferenceSet); tdilFileWriter.AddImport(qualifiedUnitNames); // Write unit using (StopwatchLog.StartNew(LogTdilUnitWritingPerformance)) { using (TdilUnitWriter tdilUnitWriter = tdilFileWriter.CreateUnit(qualifiedUnitName)) { string executeSectionName = unitName.GetEncodedScenarioName(); BuddyTextParameter[] unitParameters = buddyTextInfo.Parameters; string[] parameterNames = new string[unitParameters.Length]; for (int l = -1; ++l != parameterNames.Length;) { parameterNames[l] = unitParameters[l].Name; } // Write main section using (TdilSectionWriter tdilSectionWriter = tdilUnitWriter.CreateSection("Main")) { // Declare parameters for (int i = -1; ++i != unitParameters.Length;) { BuddyTextParameter unitParameter = unitParameters[i]; tdilSectionWriter.AppendLine("{0} = {1}", unitParameter.Name, unitParameter.DefaultValue); } // Add start statement tdilSectionWriter.AppendLine("start(,, \"{{{0}}}\")", buddyTextInfo.ApplicationText); // Add argument invocation line if there are some string argInvLine = null; if (parameterNames.Length != 0) { string argSetLine = string.Join(", ", parameterNames); argInvLine = $"({argSetLine})"; } tdilSectionWriter.AppendLine("gosub {0}:{1}", executeSectionName, argInvLine); // Add close statement tdilSectionWriter.AppendLine("close(_Application,, Default)"); tdilSectionWriter.AppendLine("kill(_Application,, 3000)"); tdilSectionWriter.AppendLine("close(\"AcroRd32\",, Default)"); tdilSectionWriter.AppendLine("kill(\"AcroRd32\",, 3000)"); } // Write execute section using (TdilSectionWriter tdilSectionWriter = tdilUnitWriter.CreateSection(executeSectionName, parameterNames)) { for (int l = -1; ++l != directiveSet.Length;) { tdilSectionWriter.AppendLine(directiveSet[l]); } } } } } } catch (BuddyCompilerException) { throw; } catch (Exception ex) { throw new BuddyCompilerException("Error on compiling buddy language unit.", ex); } string tdilFileContent = tdilFileWriter.WriteToString(); compilerStopwatch.Dispose(); return(tdilFileContent); }