|
| 1 | +/// <reference path="C:\Program Files\Leica Geosystems\Cyclone 3DR 19.1\Script\JsDoc\Reshaper.d.ts"/> |
| 2 | + |
| 3 | +// ------------------------ HOW TO USE IT -------------------------------------------- |
| 4 | +// This algoritm is a modification of the TreeMeshing.js. The algorithm uses the selected clouds to mesh them using this trunk meshing strategy! => Make sure to select the clouds firts |
| 5 | +// |
| 6 | +// ------------------------ ALGORITHM USED -------------------------------------------- |
| 7 | +// 1. The algorithm creates slices of defined depth in the point cloud at regular steps in Z |
| 8 | +// 2. A section of each slice is created using the convex hull algorithm |
| 9 | +// 3. The sections are joined in order to create a watertight mesh |
| 10 | +// 4. MODIFICATION - it also calculates the total volume |
| 11 | +// |
| 12 | +// ------------------------ PARAMETERS -------------------------------------------- |
| 13 | +// Parameter explanations: |
| 14 | +// 1. Slice step: distance between the sections that have to be created |
| 15 | +// 2. Slice depth: depth of each section for creating the convex hull |
| 16 | +// |
| 17 | + |
| 18 | + |
| 19 | +function ErrorMessage(_iMessage // [in] the error message |
| 20 | + , _iThrowError = true // [in] should we throw an error (default value: true) |
| 21 | +) { |
| 22 | + var _iThrowError = (typeof _iThrowError !== 'undefined') ? _iThrowError : true; |
| 23 | + |
| 24 | + var myDlg = SDialog.New("Error Message"); |
| 25 | + myDlg.AddLine(_iMessage, false, {}, 1); |
| 26 | + myDlg.Execute(); |
| 27 | + if (_iThrowError) |
| 28 | + throw new Error(_iMessage); |
| 29 | +} |
| 30 | + |
| 31 | + |
| 32 | +function mainTreeMeshing() { |
| 33 | + // Total Volume |
| 34 | + var VolumeTotal = 0 |
| 35 | + // retrieving the cloud to mesh with this approach |
| 36 | + var selClouds = SCloud.FromSel(); |
| 37 | + if (selClouds.length == 0) |
| 38 | + ErrorMessage("Esqueceu de selecionar as nuvens de pontos!") |
| 39 | + for (let i = 0; i<selClouds.length; i++) { |
| 40 | + var theCloud = selClouds[i]; |
| 41 | + |
| 42 | + |
| 43 | + |
| 44 | + //Enter the input data |
| 45 | + //var theDialog = SDialog.New('Tree meshing parameters'); |
| 46 | + //theDialog.AddLine("Slice step: ", true, {}, 1); |
| 47 | + //theDialog.AddLine("Slice depth: ", true, {}, 0.5); |
| 48 | + |
| 49 | + //var result = theDialog.Execute(); |
| 50 | + //if (result.ErrorCode != 0)// result == 0 means the user click //on the "OK" button |
| 51 | + //ErrorMessage("Operation canceled"); |
| 52 | + |
| 53 | + var Param_Slice_Step = 1 //parseFloat(result.InputTbl[0]); |
| 54 | + var Param_Slice_Depth = 0.5 //parseFloat(result.InputTbl[1]); |
| 55 | + |
| 56 | + // looking for the different heights at which we will create the mesh |
| 57 | + var ZVect = SVector.New(0, 0, 1); |
| 58 | + var centroid = theCloud.GetCentroid().Point; |
| 59 | + var LPt = theCloud.GetLowestPoint(ZVect).Point.GetZ(); |
| 60 | + var UPt = theCloud.GetHighestPoint(SVector.New(0, 0, 1)).Point.GetZ(); |
| 61 | + try{ |
| 62 | + if (UPt - LPt < 2 * Param_Slice_Step) |
| 63 | + console.error('Too few steps will be created to mesh') |
| 64 | + //ErrorMessage("Too few steps will be created to mesh") |
| 65 | + } catch (error) { |
| 66 | + //console.error('An error occurred:', error); |
| 67 | + continue; |
| 68 | + } |
| 69 | + |
| 70 | + var NStep = Math.round((UPt - LPt) / Param_Slice_Step); |
| 71 | + |
| 72 | + // looping on each height to create the convex contours |
| 73 | + var allMultis = new Array; |
| 74 | + for (var iHeight = 0; iHeight < NStep; iHeight++) { |
| 75 | + var curZ = LPt + iHeight * Param_Slice_Step; |
| 76 | + var locPoint = SPoint.New(centroid.GetX(), centroid.GetY(), curZ); |
| 77 | + var curPlane = SPlane.New(locPoint, ZVect, SVector.New(1, 0, 0), 1, 1); |
| 78 | + |
| 79 | + var localCloud = theCloud.SeparateFeature(curPlane, Param_Slice_Depth, SCloud.FILL_IN_ONLY).InCloud; |
| 80 | + |
| 81 | + try{ |
| 82 | + var convContRes = localCloud.GetConvexContour(ZVect, locPoint, false); |
| 83 | + |
| 84 | + if (convContRes.ErrorCode != 0) |
| 85 | + console.error("Error when extracting convex contours") |
| 86 | + } catch (error) { |
| 87 | + continue; |
| 88 | + //ErrorMessage("Error when extracting convex contours") |
| 89 | + } |
| 90 | + allMultis.push(convContRes.Multi) |
| 91 | + } |
| 92 | + |
| 93 | + // creating the meshes at each heights |
| 94 | + |
| 95 | + var allPolys = new Array; |
| 96 | + // adding bottom |
| 97 | + try{ |
| 98 | + var bottomRes = SPoly.ConstraintMesh2D(null, [allMultis[0]], ZVect, 0, 0); |
| 99 | + |
| 100 | + if (bottomRes.ErrorCode != 0 || bottomRes.PolyTbl.length != 1) |
| 101 | + console.error('Error when creating bottom') |
| 102 | + //ErrorMessage("Too few steps will be created to mesh") |
| 103 | + } catch (error) { |
| 104 | + //console.error('An error occurred:', error); |
| 105 | + continue; |
| 106 | + } |
| 107 | + //ErrorMessage("Error when creating bottom") |
| 108 | + allPolys.push(bottomRes.PolyTbl[0]) |
| 109 | + |
| 110 | + // looping on each height |
| 111 | + for (var iHeight = 0; iHeight < NStep - 1; iHeight++) { |
| 112 | + var locLMultis = new Array; |
| 113 | + locLMultis.push(allMultis[iHeight]) |
| 114 | + locLMultis.push(allMultis[iHeight + 1]) |
| 115 | + |
| 116 | + try { |
| 117 | + |
| 118 | + var meshRes = SPoly.JoinContour(locLMultis, [], 0, 0, 0, false, 0); |
| 119 | + |
| 120 | + if (meshRes.ErrorCode != 0) |
| 121 | + console.error("Error when joining contours") |
| 122 | + } catch (error) { |
| 123 | + continue; |
| 124 | + //ErrorMessage("Error when joining contours") |
| 125 | + } |
| 126 | + allPolys.push(meshRes.Poly) |
| 127 | + } |
| 128 | + |
| 129 | + // adding top |
| 130 | + try { |
| 131 | + |
| 132 | + var topRes = SPoly.ConstraintMesh2D(null, [allMultis[allMultis.length - 1]], ZVect, 0, 0); |
| 133 | + |
| 134 | + if (topRes.ErrorCode != 0 || topRes.PolyTbl.length != 1) |
| 135 | + console.error("Error when creating top") |
| 136 | + } catch (error) { |
| 137 | + //ErrorMessage("Error when creating top") |
| 138 | + continue; |
| 139 | + } |
| 140 | + allPolys.push(topRes.PolyTbl[0]) |
| 141 | + |
| 142 | + // merging the results (final should be only 1 filled mesh) |
| 143 | + try { |
| 144 | + |
| 145 | + var resMerge = SPoly.MergeCommonBorders(allPolys, SPoly.SIMPLE); |
| 146 | + |
| 147 | + if (resMerge.ErrorCode != 0) |
| 148 | + console.error("Error when mergin meshes") |
| 149 | + } catch (error) { |
| 150 | + continue; |
| 151 | + //ErrorMessage("Error when mergin meshes") |
| 152 | + } |
| 153 | + |
| 154 | + var finalMeshes = resMerge.PolyTbl; |
| 155 | + for (var iMesh = 0; iMesh < finalMeshes.length; iMesh++) { |
| 156 | + finalMeshes[iMesh].SetName(theCloud.GetName()) |
| 157 | + finalMeshes[iMesh].AddToDoc(); |
| 158 | + } |
| 159 | + //print()) |
| 160 | + VolumeTotal = VolumeTotal + finalMeshes[0].GetVolume().Volume; |
| 161 | + |
| 162 | + console.log("Done", i) |
| 163 | + |
| 164 | + } |
| 165 | + print((`O Volume Total é: ${VolumeTotal} unidades de volume`)) |
| 166 | +} |
| 167 | + |
| 168 | +mainTreeMeshing() |
0 commit comments