diff --git a/CMakeLists.txt b/CMakeLists.txt index 2977cf82..bc311683 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -116,6 +116,8 @@ if(RF_BUILD_BINDINGS) add_subdirectory(rooferpy) endif() +add_subdirectory(roofersharp/cpp) + # EXECUTABLES if(RF_BUILD_APPS OR RF_BUILD_DOC_HELPER) add_subdirectory(apps) diff --git a/roofersharp/.gitignore b/roofersharp/.gitignore new file mode 100644 index 00000000..eb68c9db --- /dev/null +++ b/roofersharp/.gitignore @@ -0,0 +1,3 @@ +.vs/* +.idea/* +lib/* \ No newline at end of file diff --git a/roofersharp/RooferSharp.Test/.gitignore b/roofersharp/RooferSharp.Test/.gitignore new file mode 100644 index 00000000..ac1a68c9 --- /dev/null +++ b/roofersharp/RooferSharp.Test/.gitignore @@ -0,0 +1,3 @@ +bin/* +obj/* +.idea/* \ No newline at end of file diff --git a/roofersharp/RooferSharp.Test/Model/GeometryPayload.cs b/roofersharp/RooferSharp.Test/Model/GeometryPayload.cs new file mode 100644 index 00000000..f434f0e3 --- /dev/null +++ b/roofersharp/RooferSharp.Test/Model/GeometryPayload.cs @@ -0,0 +1,26 @@ +using System.Text.Json.Serialization; + +namespace RooferSharp.Test.Model; + +public sealed class GeometryPayload +{ + [JsonPropertyName("pointsRoof")] + public List PointsRoof { get; set; } + + [JsonPropertyName("pointsGround")] + public List PointsGround { get; set; } + + [JsonPropertyName("footprintExterior")] + public List FootprintExterior { get; set; } + + [JsonPropertyName("footprintInteriors")] + public List> FootprintInteriors { get; set; } // null => omitted if you want + + public GeometryPayload() + { + PointsRoof = new List(); + PointsGround = new List(); + FootprintExterior = new List(); + FootprintInteriors = null; // keep optional + } +} \ No newline at end of file diff --git a/roofersharp/RooferSharp.Test/Model/TestPayloadExtensions.cs b/roofersharp/RooferSharp.Test/Model/TestPayloadExtensions.cs new file mode 100644 index 00000000..f4f637cb --- /dev/null +++ b/roofersharp/RooferSharp.Test/Model/TestPayloadExtensions.cs @@ -0,0 +1,11 @@ +using System.Numerics; + +namespace RooferSharp.Test.Model; + +public static class TestPayloadExtensions +{ + public static List ToVector3List(this List vec3List) + { + return vec3List.Select(v => new Vector3(v.X, v.Y, v.Z)).ToList(); + } +} \ No newline at end of file diff --git a/roofersharp/RooferSharp.Test/Model/Vec3.cs b/roofersharp/RooferSharp.Test/Model/Vec3.cs new file mode 100644 index 00000000..1dea4346 --- /dev/null +++ b/roofersharp/RooferSharp.Test/Model/Vec3.cs @@ -0,0 +1,28 @@ +using System.Numerics; +using System.Text.Json.Serialization; + +namespace RooferSharp.Test.Model; + +public sealed class Vec3 +{ + [JsonPropertyName("x")] + public float X { get; set; } + + [JsonPropertyName("y")] + public float Y { get; set; } + + [JsonPropertyName("z")] + public float Z { get; set; } + + public Vec3() { } // for deserialization + + public Vec3(float x, float y, float z) + { + X = x; Y = y; Z = z; + } + + public Vector3 ToVector3() + { + return new Vector3(X, Y, Z); + } +} \ No newline at end of file diff --git a/roofersharp/RooferSharp.Test/Properties/launchSettings.json b/roofersharp/RooferSharp.Test/Properties/launchSettings.json new file mode 100644 index 00000000..44702fef --- /dev/null +++ b/roofersharp/RooferSharp.Test/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "RooferSharp.Test": { + "commandName": "Project", + "nativeDebugging": true + } + } +} \ No newline at end of file diff --git a/roofersharp/RooferSharp.Test/RooferSharp.Test.csproj b/roofersharp/RooferSharp.Test/RooferSharp.Test.csproj new file mode 100644 index 00000000..f71a998e --- /dev/null +++ b/roofersharp/RooferSharp.Test/RooferSharp.Test.csproj @@ -0,0 +1,43 @@ + + + + net8.0 + latest + enable + enable + false + x64 + x64 + x64 + + + + x64 + + + + + + + + + + + + + + + + + + + + + Always + + + PreserveNewest + + + + diff --git a/roofersharp/RooferSharp.Test/UnitTest1.cs b/roofersharp/RooferSharp.Test/UnitTest1.cs new file mode 100644 index 00000000..20ac12d9 --- /dev/null +++ b/roofersharp/RooferSharp.Test/UnitTest1.cs @@ -0,0 +1,33 @@ +using System.Numerics; +using RooferSharp.Test.Model; + +namespace RooferSharp.Test; + +public class Tests +{ + [SetUp] + public void Setup() + { + + + } + + [Test] + public void Test1() + { + var config = new ReconstructionConfig(); + config.ClipGround = false; + // example file containing roof points and ground points + var file = File.ReadAllText("testdata/slantedroof.json"); + var payload = System.Text.Json.JsonSerializer.Deserialize(file); + + Assert.That(payload != null); + var result = RooferSharp.Reconstructor.ReconstructWithGround(config, + payload!.PointsRoof.ToVector3List(), + payload.PointsGround.ToVector3List(), + payload.FootprintExterior.ToVector3List()); + var data = result[0]; + var polygons = data.GetPolygons(); + Assert.That(polygons.Count, Is.GreaterThan(0)); + } +} \ No newline at end of file diff --git a/roofersharp/RooferSharp.Test/testdata/boxBuilding.json b/roofersharp/RooferSharp.Test/testdata/boxBuilding.json new file mode 100644 index 00000000..bf7ffcaa --- /dev/null +++ b/roofersharp/RooferSharp.Test/testdata/boxBuilding.json @@ -0,0 +1,2443 @@ +{ + "pointsRoof": [ + { + "x": -9.976671256004733, + "y": -5.30890270328791, + "z": 15.771093898346226 + }, + { + "x": -9.278618475051266, + "y": -5.30890270328791, + "z": 15.404162594771087 + }, + { + "x": -8.580565694097793, + "y": -5.308902703287913, + "z": 15.16599867034983 + }, + { + "x": -7.8825129131443274, + "y": -5.308902703287916, + "z": 15.985047052607428 + }, + { + "x": -7.184460132190858, + "y": -5.308902703287913, + "z": 15.109004633551931 + }, + { + "x": -6.48640735123739, + "y": -5.308902703287913, + "z": 15.306680407983565 + }, + { + "x": -5.7883545702839205, + "y": -5.308902703287913, + "z": 15.802140461188806 + }, + { + "x": -5.090301789330451, + "y": -5.30890270328791, + "z": 15.445546678940554 + }, + { + "x": -4.392249008376982, + "y": -5.3089027032879095, + "z": 15.224983153969506 + }, + { + "x": -3.6941962274235127, + "y": -5.308902703287911, + "z": 15.01120665297434 + }, + { + "x": -2.9961434464700436, + "y": -5.308902703287913, + "z": 15.765367340652908 + }, + { + "x": -2.2980906655165754, + "y": -5.308902703287913, + "z": 15.028743590707306 + }, + { + "x": -1.600037884563104, + "y": -5.30890270328791, + "z": 15.007561190523003 + }, + { + "x": -0.9019851036096371, + "y": -5.308902703287913, + "z": 15.51002241694835 + }, + { + "x": -0.20393232265616767, + "y": -5.308902703287913, + "z": 15.382094984586395 + }, + { + "x": 0.49412045829730206, + "y": -5.3089027032879095, + "z": 15.279408783316336 + }, + { + "x": 1.19217323925077, + "y": -5.308902703287913, + "z": 15.703088294110767 + }, + { + "x": 1.8902260202042398, + "y": -5.308902703287908, + "z": 15.235345735324241 + }, + { + "x": 2.5882788011577094, + "y": -5.3089027032879095, + "z": 15.731321921912636 + }, + { + "x": -9.976671256004733, + "y": -4.192014835575289, + "z": 15.089001557831187 + }, + { + "x": -9.278618475051267, + "y": -4.192014835575289, + "z": 15.082648985126358 + }, + { + "x": -8.580565694097796, + "y": -4.192014835575288, + "z": 15.33872517819457 + }, + { + "x": -7.882512913144327, + "y": -4.192014835575284, + "z": 15.32991219606712 + }, + { + "x": -7.184460132190853, + "y": -4.192014835575281, + "z": 15.73131695703199 + }, + { + "x": -6.486407351237388, + "y": -4.192014835575284, + "z": 15.895953410722296 + }, + { + "x": -5.788354570283919, + "y": -4.192014835575287, + "z": 15.812650163570721 + }, + { + "x": -5.090301789330452, + "y": -4.192014835575284, + "z": 15.653548586486629 + }, + { + "x": -4.39224900837698, + "y": -4.192014835575286, + "z": 15.926836201887037 + }, + { + "x": -3.6941962274235127, + "y": -4.192014835575284, + "z": 15.09924142626079 + }, + { + "x": -2.9961434464700427, + "y": -4.192014835575287, + "z": 15.691829131307001 + }, + { + "x": -2.298090665516573, + "y": -4.19201483557528, + "z": 15.9254800574507 + }, + { + "x": -1.600037884563104, + "y": -4.192014835575284, + "z": 15.980140829449585 + }, + { + "x": -0.9019851036096374, + "y": -4.192014835575287, + "z": 15.101419798611392 + }, + { + "x": -0.2039323226561677, + "y": -4.192014835575284, + "z": 15.038685026130958 + }, + { + "x": 0.4941204582973021, + "y": -4.192014835575284, + "z": 15.341054720031588 + }, + { + "x": 1.1921732392507702, + "y": -4.192014835575287, + "z": 15.849639621493239 + }, + { + "x": 1.8902260202042382, + "y": -4.1920148355752875, + "z": 15.687092905252749 + }, + { + "x": 2.5882788011577045, + "y": -4.192014835575286, + "z": 15.74400214280188 + }, + { + "x": -9.976671256004733, + "y": -3.0751269678626616, + "z": 15.685645662567412 + }, + { + "x": -9.278618475051266, + "y": -3.0751269678626594, + "z": 15.093061322855325 + }, + { + "x": -8.580565694097794, + "y": -3.075126967862659, + "z": 15.040521103907617 + }, + { + "x": -7.8825129131443274, + "y": -3.0751269678626594, + "z": 15.271620187569233 + }, + { + "x": -7.184460132190858, + "y": -3.0751269678626594, + "z": 15.263251126400778 + }, + { + "x": -6.486407351237388, + "y": -3.0751269678626603, + "z": 15.49977948493314 + }, + { + "x": -5.788354570283919, + "y": -3.0751269678626567, + "z": 15.961569905263172 + }, + { + "x": -5.090301789330451, + "y": -3.07512696786266, + "z": 15.55604546636159 + }, + { + "x": -4.3922490083769805, + "y": -3.0751269678626576, + "z": 15.017603008084745 + }, + { + "x": -3.6941962274235127, + "y": -3.0751269678626625, + "z": 15.488540577464057 + }, + { + "x": -2.996143446470043, + "y": -3.0751269678626603, + "z": 15.342212458766165 + }, + { + "x": -2.2980906655165763, + "y": -3.075126967862662, + "z": 15.485653481672356 + }, + { + "x": -1.6000378845631056, + "y": -3.0751269678626594, + "z": 15.642432012894393 + }, + { + "x": -0.9019851036096371, + "y": -3.0751269678626603, + "z": 15.620127741070524 + }, + { + "x": -0.20393232265616784, + "y": -3.0751269678626594, + "z": 15.073345340822518 + }, + { + "x": 0.49412045829730233, + "y": -3.0751269678626603, + "z": 15.895421876523375 + }, + { + "x": 1.1921732392507698, + "y": -3.075126967862659, + "z": 15.595372762808282 + }, + { + "x": 1.8902260202042385, + "y": -3.0751269678626594, + "z": 15.432368720151656 + }, + { + "x": 2.58827880115771, + "y": -3.0751269678626594, + "z": 15.074250398703967 + }, + { + "x": -9.97667125600473, + "y": -1.9582391001500303, + "z": 15.434681713317836 + }, + { + "x": -9.278618475051264, + "y": -1.9582391001500339, + "z": 15.089093641885134 + }, + { + "x": -8.580565694097796, + "y": -1.958239100150033, + "z": 15.29635446998121 + }, + { + "x": -7.882512913144328, + "y": -1.958239100150036, + "z": 15.653131821496938 + }, + { + "x": -7.184460132190858, + "y": -1.9582391001500357, + "z": 15.875304259301773 + }, + { + "x": -6.486407351237387, + "y": -1.9582391001500352, + "z": 15.346305252679764 + }, + { + "x": -5.7883545702839205, + "y": -1.9582391001500354, + "z": 15.533154022662504 + }, + { + "x": -5.09030178933045, + "y": -1.958239100150033, + "z": 15.085726595523642 + }, + { + "x": -4.392249008376982, + "y": -1.9582391001500357, + "z": 15.785226511203321 + }, + { + "x": -3.694196227423513, + "y": -1.9582391001500357, + "z": 15.927323792095912 + }, + { + "x": -2.996143446470044, + "y": -1.9582391001500357, + "z": 15.968876164392045 + }, + { + "x": -2.2980906655165736, + "y": -1.9582391001500359, + "z": 15.168967696916763 + }, + { + "x": -1.6000378845631038, + "y": -1.9582391001500365, + "z": 15.532455363093156 + }, + { + "x": -0.9019851036096374, + "y": -1.9582391001500352, + "z": 15.592315878063586 + }, + { + "x": -0.2039323226561673, + "y": -1.9582391001500357, + "z": 15.959086151308888 + }, + { + "x": 0.4941204582973021, + "y": -1.958239100150036, + "z": 15.54970007275683 + }, + { + "x": 1.192173239250769, + "y": -1.9582391001500357, + "z": 15.638260599057311 + }, + { + "x": 1.89022602020424, + "y": -1.958239100150036, + "z": 15.048480453923569 + }, + { + "x": 2.588278801157708, + "y": -1.958239100150036, + "z": 15.811028797557125 + }, + { + "x": -9.976671256004733, + "y": -0.8413512324374118, + "z": 15.075474051793792 + }, + { + "x": -9.278618475051264, + "y": -0.8413512324374097, + "z": 15.830132711133981 + }, + { + "x": -8.580565694097798, + "y": -0.8413512324374111, + "z": 15.769747051768823 + }, + { + "x": -7.882512913144327, + "y": -0.8413512324374067, + "z": 15.339907944360705 + }, + { + "x": -7.184460132190858, + "y": -0.8413512324374088, + "z": 15.795047155485976 + }, + { + "x": -6.486407351237391, + "y": -0.8413512324374097, + "z": 15.165008009022573 + }, + { + "x": -5.78835457028392, + "y": -0.84135123243741, + "z": 15.584623743120872 + }, + { + "x": -5.090301789330451, + "y": -0.8413512324374073, + "z": 15.613587944588431 + }, + { + "x": -4.392249008376982, + "y": -0.8413512324374095, + "z": 15.049397118412609 + }, + { + "x": -3.6941962274235123, + "y": -0.8413512324374093, + "z": 15.305352316380176 + }, + { + "x": -2.9961434464700427, + "y": -0.8413512324374097, + "z": 15.906795488627067 + }, + { + "x": -2.298090665516575, + "y": -0.8413512324374093, + "z": 15.205997922088018 + }, + { + "x": -1.600037884563104, + "y": -0.8413512324374097, + "z": 15.443312263322674 + }, + { + "x": -0.9019851036096375, + "y": -0.8413512324374088, + "z": 15.908685999879934 + }, + { + "x": -0.20393232265616945, + "y": -0.8413512324374088, + "z": 15.775389222789272 + }, + { + "x": 0.49412045829730233, + "y": -0.8413512324374093, + "z": 15.252411191934911 + }, + { + "x": 1.1921732392507716, + "y": -0.8413512324374093, + "z": 15.654908500916747 + }, + { + "x": 1.8902260202042398, + "y": -0.8413512324374102, + "z": 15.389291192586203 + }, + { + "x": 2.5882788011577076, + "y": -0.8413512324374084, + "z": 15.439929501358385 + }, + { + "x": -9.976671256004735, + "y": 0.2755366352752151, + "z": 15.165216844605848 + }, + { + "x": -9.278618475051266, + "y": 0.27553663527521777, + "z": 15.925314934889466 + }, + { + "x": -8.580565694097796, + "y": 0.2755366352752149, + "z": 15.73009710373827 + }, + { + "x": -7.8825129131443274, + "y": 0.275536635275217, + "z": 15.414052889409497 + }, + { + "x": -7.184460132190856, + "y": 0.2755366352752173, + "z": 15.176343394059847 + }, + { + "x": -6.486407351237389, + "y": 0.2755366352752171, + "z": 15.628721674265677 + }, + { + "x": -5.78835457028392, + "y": 0.27553663527521755, + "z": 15.0487268436927 + }, + { + "x": -5.090301789330449, + "y": 0.2755366352752169, + "z": 15.319572880547295 + }, + { + "x": -4.392249008376982, + "y": 0.27553663527521755, + "z": 15.809757095673008 + }, + { + "x": -3.6941962274235123, + "y": 0.2755366352752171, + "z": 15.893337603608769 + }, + { + "x": -2.9961434464700436, + "y": 0.27553663527521755, + "z": 15.683345861585506 + }, + { + "x": -2.2980906655165745, + "y": 0.2755366352752171, + "z": 15.070427668313695 + }, + { + "x": -1.600037884563104, + "y": 0.27553663527521755, + "z": 15.435084741765207 + }, + { + "x": -0.9019851036096377, + "y": 0.2755366352752171, + "z": 15.846941422599807 + }, + { + "x": -0.2039323226561679, + "y": 0.27553663527521755, + "z": 15.784343965251157 + }, + { + "x": 0.49412045829730356, + "y": 0.2755366352752171, + "z": 15.356894668357864 + }, + { + "x": 1.19217323925077, + "y": 0.27553663527521666, + "z": 15.244117687569986 + }, + { + "x": 1.8902260202042402, + "y": 0.275536635275218, + "z": 15.66493466154902 + }, + { + "x": 2.58827880115771, + "y": 0.275536635275218, + "z": 15.74918569752443 + }, + { + "x": -9.976671256004732, + "y": 1.3924245029878408, + "z": 15.501307314495236 + }, + { + "x": -9.278618475051266, + "y": 1.3924245029878408, + "z": 15.488123812474369 + }, + { + "x": -8.580565694097796, + "y": 1.3924245029878415, + "z": 15.290680516180899 + }, + { + "x": -7.882512913144325, + "y": 1.3924245029878377, + "z": 15.732717308091335 + }, + { + "x": -7.184460132190858, + "y": 1.3924245029878384, + "z": 15.483756904249898 + }, + { + "x": -6.486407351237387, + "y": 1.3924245029878417, + "z": 15.780374279143462 + }, + { + "x": -5.788354570283921, + "y": 1.392424502987839, + "z": 15.878431022576256 + }, + { + "x": -5.090301789330451, + "y": 1.392424502987841, + "z": 15.721325870007893 + }, + { + "x": -4.392249008376982, + "y": 1.3924245029878388, + "z": 15.525563901069368 + }, + { + "x": -3.694196227423513, + "y": 1.392424502987839, + "z": 15.26028169703683 + }, + { + "x": -2.996143446470044, + "y": 1.3924245029878388, + "z": 15.757066140303884 + }, + { + "x": -2.298090665516573, + "y": 1.3924245029878435, + "z": 15.339904686128676 + }, + { + "x": -1.600037884563104, + "y": 1.392424502987839, + "z": 15.304177650392138 + }, + { + "x": -0.9019851036096376, + "y": 1.392424502987844, + "z": 15.160408880170625 + }, + { + "x": -0.20393232265616745, + "y": 1.3924245029878435, + "z": 15.198331097698924 + }, + { + "x": 0.4941204582973021, + "y": 1.3924245029878382, + "z": 15.88326360931772 + }, + { + "x": 1.1921732392507702, + "y": 1.3924245029878417, + "z": 15.885713862667659 + }, + { + "x": 1.89022602020424, + "y": 1.3924245029878408, + "z": 15.34537694805552 + }, + { + "x": 2.5882788011577045, + "y": 1.392424502987839, + "z": 15.416079821724482 + }, + { + "x": -9.976671256004732, + "y": 2.509312370700465, + "z": 15.593403657708969 + }, + { + "x": -9.27861847505127, + "y": 2.509312370700465, + "z": 15.711186270095029 + }, + { + "x": -8.580565694097798, + "y": 2.509312370700466, + "z": 15.746320311793275 + }, + { + "x": -7.882512913144327, + "y": 2.5093123707004654, + "z": 15.845435128475277 + }, + { + "x": -7.18446013219086, + "y": 2.509312370700467, + "z": 15.774866647447864 + }, + { + "x": -6.486407351237388, + "y": 2.509312370700467, + "z": 15.720250340979662 + }, + { + "x": -5.78835457028392, + "y": 2.509312370700465, + "z": 15.366051256827102 + }, + { + "x": -5.090301789330453, + "y": 2.5093123707004654, + "z": 15.23492464806648 + }, + { + "x": -4.3922490083769805, + "y": 2.5093123707004654, + "z": 15.47171074686186 + }, + { + "x": -3.6941962274235123, + "y": 2.5093123707004654, + "z": 15.359056499488212 + }, + { + "x": -2.9961434464700427, + "y": 2.5093123707004676, + "z": 15.658968298071516 + }, + { + "x": -2.2980906655165736, + "y": 2.5093123707004703, + "z": 15.55179133152207 + }, + { + "x": -1.6000378845631038, + "y": 2.509312370700467, + "z": 15.531271535219286 + }, + { + "x": -0.9019851036096372, + "y": 2.509312370700467, + "z": 15.58747653038589 + }, + { + "x": -0.20393232265616756, + "y": 2.5093123707004703, + "z": 15.905722803392319 + }, + { + "x": 0.4941204582973051, + "y": 2.5093123707004708, + "z": 15.88798387809097 + }, + { + "x": 1.1921732392507685, + "y": 2.509312370700471, + "z": 15.951805688884019 + }, + { + "x": 1.89022602020424, + "y": 2.509312370700467, + "z": 15.87453632842495 + }, + { + "x": 2.5882788011577063, + "y": 2.5093123707004676, + "z": 15.19259762679813 + }, + { + "x": -9.976671256004732, + "y": 3.6262002384130914, + "z": 15.246340199488372 + }, + { + "x": -9.278618475051266, + "y": 3.626200238413092, + "z": 15.633678610266037 + }, + { + "x": -8.580565694097794, + "y": 3.6262002384130945, + "z": 15.29791237148359 + }, + { + "x": -7.8825129131443274, + "y": 3.6262002384130914, + "z": 15.907395804257781 + }, + { + "x": -7.184460132190858, + "y": 3.626200238413092, + "z": 15.52316294262333 + }, + { + "x": -6.486407351237389, + "y": 3.626200238413092, + "z": 15.059291183510467 + }, + { + "x": -5.788354570283918, + "y": 3.626200238413093, + "z": 15.052690955369124 + }, + { + "x": -5.090301789330451, + "y": 3.6262002384130945, + "z": 15.553432917480094 + }, + { + "x": -4.392249008376981, + "y": 3.626200238413092, + "z": 15.379168211193369 + }, + { + "x": -3.6941962274235127, + "y": 3.626200238413092, + "z": 15.91001878814307 + }, + { + "x": -2.996143446470043, + "y": 3.6262002384130945, + "z": 15.236753644066281 + }, + { + "x": -2.2980906655165745, + "y": 3.626200238413092, + "z": 15.963677813282086 + }, + { + "x": -1.6000378845631056, + "y": 3.626200238413091, + "z": 15.8986301025835 + }, + { + "x": -0.9019851036096371, + "y": 3.626200238413092, + "z": 15.011517720302344 + }, + { + "x": -0.20393232265616756, + "y": 3.626200238413092, + "z": 15.828037865845504 + }, + { + "x": 0.4941204582973022, + "y": 3.6262002384130945, + "z": 15.071531003840049 + }, + { + "x": 1.1921732392507687, + "y": 3.626200238413092, + "z": 15.0379994274294 + }, + { + "x": 1.8902260202042398, + "y": 3.626200238413092, + "z": 15.754987002701958 + }, + { + "x": 2.588278801157708, + "y": 3.6262002384130914, + "z": 15.642688683999092 + }, + { + "x": -9.976671256004733, + "y": 4.743088106125716, + "z": 15.515813868733037 + }, + { + "x": -9.278618475051264, + "y": 4.743088106125718, + "z": 15.01246696711167 + }, + { + "x": -8.580565694097793, + "y": 4.743088106125721, + "z": 15.117705647422797 + }, + { + "x": -7.8825129131443274, + "y": 4.743088106125718, + "z": 15.545449631076979 + }, + { + "x": -7.184460132190859, + "y": 4.743088106125718, + "z": 15.406720275714397 + }, + { + "x": -6.486407351237388, + "y": 4.743088106125718, + "z": 15.362269370519682 + }, + { + "x": -5.788354570283919, + "y": 4.743088106125716, + "z": 15.866595602997856 + }, + { + "x": -5.09030178933045, + "y": 4.743088106125718, + "z": 15.70849036551476 + }, + { + "x": -4.392249008376983, + "y": 4.743088106125718, + "z": 15.2257946050846 + }, + { + "x": -3.6941962274235127, + "y": 4.743088106125718, + "z": 15.752428155742784 + }, + { + "x": -2.9961434464700423, + "y": 4.743088106125718, + "z": 15.39845484699982 + }, + { + "x": -2.2980906655165745, + "y": 4.743088106125718, + "z": 15.272425002079656 + }, + { + "x": -1.6000378845631038, + "y": 4.743088106125718, + "z": 15.246525408814906 + }, + { + "x": -0.9019851036096374, + "y": 4.743088106125718, + "z": 15.00872728089277 + }, + { + "x": -0.20393232265616756, + "y": 4.743088106125718, + "z": 15.693116235869525 + }, + { + "x": 0.494120458297302, + "y": 4.743088106125718, + "z": 15.099036748567148 + }, + { + "x": 1.192173239250769, + "y": 4.743088106125718, + "z": 15.782401211458446 + }, + { + "x": 1.89022602020424, + "y": 4.743088106125718, + "z": 15.29549128622538 + }, + { + "x": 2.588278801157708, + "y": 4.743088106125718, + "z": 15.803790465837247 + }, + { + "x": -9.976671256004733, + "y": 5.859975973838343, + "z": 15.223157369169945 + }, + { + "x": -9.27861847505127, + "y": 5.859975973838339, + "z": 15.786143944964811 + }, + { + "x": -8.580565694097796, + "y": 5.859975973838345, + "z": 15.72217569207874 + }, + { + "x": -7.882512913144327, + "y": 5.8599759738383455, + "z": 15.16681742349957 + }, + { + "x": -7.184460132190858, + "y": 5.859975973838344, + "z": 15.986883045633736 + }, + { + "x": -6.486407351237389, + "y": 5.859975973838345, + "z": 15.324905859923412 + }, + { + "x": -5.788354570283919, + "y": 5.8599759738383455, + "z": 15.23495710279558 + }, + { + "x": -5.090301789330448, + "y": 5.859975973838345, + "z": 15.395378686206126 + }, + { + "x": -4.392249008376982, + "y": 5.859975973838342, + "z": 15.760338195488012 + }, + { + "x": -3.6941962274235127, + "y": 5.859975973838344, + "z": 15.540273611219728 + }, + { + "x": -2.9961434464700436, + "y": 5.859975973838345, + "z": 15.70323366937378 + }, + { + "x": -2.2980906655165745, + "y": 5.859975973838345, + "z": 15.515945526545842 + }, + { + "x": -1.6000378845631034, + "y": 5.8599759738383455, + "z": 15.867723375962917 + }, + { + "x": -0.9019851036096371, + "y": 5.859975973838345, + "z": 15.132996875389013 + }, + { + "x": -0.20393232265616756, + "y": 5.859975973838346, + "z": 15.309117004884927 + }, + { + "x": 0.4941204582973022, + "y": 5.859975973838342, + "z": 15.358722459691913 + }, + { + "x": 1.1921732392507687, + "y": 5.859975973838345, + "z": 15.180130659686462 + }, + { + "x": 1.8902260202042398, + "y": 5.859975973838344, + "z": 15.128634552065579 + }, + { + "x": 2.588278801157708, + "y": 5.859975973838344, + "z": 15.088228979189056 + }, + { + "x": -9.976671256004732, + "y": 6.976863841550967, + "z": 15.891192095769192 + }, + { + "x": -9.278618475051267, + "y": 6.976863841550969, + "z": 15.545126433738103 + }, + { + "x": -8.580565694097798, + "y": 6.976863841550968, + "z": 15.656567339625475 + }, + { + "x": -7.882512913144327, + "y": 6.976863841550968, + "z": 15.350800817995703 + }, + { + "x": -7.184460132190858, + "y": 6.976863841550967, + "z": 15.826896350284525 + }, + { + "x": -6.486407351237388, + "y": 6.976863841550969, + "z": 15.801004761737309 + }, + { + "x": -5.78835457028392, + "y": 6.976863841550971, + "z": 15.980713364193548 + }, + { + "x": -5.09030178933045, + "y": 6.976863841550967, + "z": 15.637593786063414 + }, + { + "x": -4.392249008376981, + "y": 6.976863841550968, + "z": 15.990228235251376 + }, + { + "x": -3.694196227423513, + "y": 6.976863841550971, + "z": 15.954950532389317 + }, + { + "x": -2.996143446470044, + "y": 6.976863841550971, + "z": 15.205513866713977 + }, + { + "x": -2.2980906655165736, + "y": 6.976863841550971, + "z": 15.912480971735194 + }, + { + "x": -1.6000378845631058, + "y": 6.976863841550972, + "z": 15.045636654387058 + }, + { + "x": -0.9019851036096374, + "y": 6.9768638415509665, + "z": 15.776039717614669 + }, + { + "x": -0.20393232265616756, + "y": 6.976863841550968, + "z": 15.234208961592152 + }, + { + "x": 0.494120458297302, + "y": 6.976863841550967, + "z": 15.531829633532013 + }, + { + "x": 1.1921732392507685, + "y": 6.9768638415509665, + "z": 15.85654473903428 + }, + { + "x": 1.890226020204243, + "y": 6.9768638415509665, + "z": 15.793638176654298 + }, + { + "x": 2.588278801157708, + "y": 6.976863841550969, + "z": 15.845649543612101 + }, + { + "x": -9.976671256004733, + "y": 8.093751709263598, + "z": 15.13082260178906 + }, + { + "x": -9.278618475051266, + "y": 8.093751709263595, + "z": 15.220543771153569 + }, + { + "x": -8.580565694097796, + "y": 8.093751709263595, + "z": 15.171763172918821 + }, + { + "x": -7.8825129131443274, + "y": 8.093751709263591, + "z": 15.966890684313556 + }, + { + "x": -7.184460132190858, + "y": 8.093751709263596, + "z": 15.106257407509842 + }, + { + "x": -6.486407351237388, + "y": 8.093751709263598, + "z": 15.168216754295033 + }, + { + "x": -5.788354570283922, + "y": 8.093751709263593, + "z": 15.522560935710818 + }, + { + "x": -5.090301789330449, + "y": 8.093751709263598, + "z": 15.236482629196942 + }, + { + "x": -4.392249008376982, + "y": 8.093751709263593, + "z": 15.530731471036901 + }, + { + "x": -3.694196227423512, + "y": 8.093751709263593, + "z": 15.139428126690643 + }, + { + "x": -2.996143446470043, + "y": 8.093751709263593, + "z": 15.937408403929979 + }, + { + "x": -2.298090665516577, + "y": 8.093751709263595, + "z": 15.650004821200858 + }, + { + "x": -1.600037884563104, + "y": 8.093751709263598, + "z": 15.512985576183063 + }, + { + "x": -0.9019851036096376, + "y": 8.093751709263593, + "z": 15.970402196501569 + }, + { + "x": -0.20393232265616756, + "y": 8.093751709263598, + "z": 15.69417223226939 + }, + { + "x": 0.494120458297302, + "y": 8.093751709263595, + "z": 15.404299190456188 + }, + { + "x": 1.1921732392507702, + "y": 8.093751709263595, + "z": 15.258664032099146 + }, + { + "x": 1.89022602020424, + "y": 8.093751709263595, + "z": 15.566590029544471 + }, + { + "x": 2.588278801157711, + "y": 8.093751709263598, + "z": 15.435343126969109 + }, + { + "x": -9.976671256004737, + "y": 9.210639576976218, + "z": 15.895279341794216 + }, + { + "x": -9.278618475051266, + "y": 9.210639576976217, + "z": 15.365812661762261 + }, + { + "x": -8.580565694097796, + "y": 9.210639576976218, + "z": 15.006169681440184 + }, + { + "x": -7.8825129131443274, + "y": 9.21063957697622, + "z": 15.687312073859998 + }, + { + "x": -7.184460132190856, + "y": 9.210639576976222, + "z": 15.2447288675442 + }, + { + "x": -6.486407351237389, + "y": 9.21063957697622, + "z": 15.44042815381681 + }, + { + "x": -5.78835457028392, + "y": 9.21063957697622, + "z": 15.554824328774037 + }, + { + "x": -5.090301789330451, + "y": 9.21063957697622, + "z": 15.627792639484532 + }, + { + "x": -4.392249008376982, + "y": 9.21063957697622, + "z": 15.657597014986722 + }, + { + "x": -3.6941962274235127, + "y": 9.21063957697622, + "z": 15.739905808931173 + }, + { + "x": -2.9961434464700414, + "y": 9.210639576976218, + "z": 15.633514414370765 + }, + { + "x": -2.2980906655165745, + "y": 9.21063957697622, + "z": 15.601167241856999 + }, + { + "x": -1.600037884563104, + "y": 9.21063957697622, + "z": 15.452572265850646 + }, + { + "x": -0.9019851036096378, + "y": 9.21063957697622, + "z": 15.565084283037615 + }, + { + "x": -0.20393232265616779, + "y": 9.21063957697622, + "z": 15.334481116074361 + }, + { + "x": 0.494120458297302, + "y": 9.210639576976224, + "z": 15.997811950276517 + }, + { + "x": 1.1921732392507702, + "y": 9.210639576976222, + "z": 15.867685208035486 + }, + { + "x": 1.8902260202042402, + "y": 9.21063957697622, + "z": 15.719428922850373 + }, + { + "x": 2.5882788011577076, + "y": 9.210639576976218, + "z": 15.578235749424545 + }, + { + "x": -9.976671256004732, + "y": 10.32752744468885, + "z": 15.550309932115631 + }, + { + "x": -9.278618475051267, + "y": 10.327527444688846, + "z": 15.18258406370067 + }, + { + "x": -8.580565694097798, + "y": 10.327527444688846, + "z": 15.304335414573709 + }, + { + "x": -7.882512913144327, + "y": 10.327527444688846, + "z": 15.564522132540366 + }, + { + "x": -7.184460132190858, + "y": 10.32752744468885, + "z": 15.449981893156647 + }, + { + "x": -6.486407351237388, + "y": 10.327527444688851, + "z": 15.498165659372773 + }, + { + "x": -5.78835457028392, + "y": 10.327527444688847, + "z": 15.052819831321397 + }, + { + "x": -5.09030178933045, + "y": 10.327527444688847, + "z": 15.30494571118846 + }, + { + "x": -4.392249008376982, + "y": 10.327527444688846, + "z": 15.692528290530912 + }, + { + "x": -3.694196227423513, + "y": 10.327527444688847, + "z": 15.942078775233625 + }, + { + "x": -2.9961434464700436, + "y": 10.327527444688847, + "z": 15.351464422117669 + }, + { + "x": -2.2980906655165745, + "y": 10.327527444688847, + "z": 15.371740527158483 + }, + { + "x": -1.6000378845631051, + "y": 10.327527444688846, + "z": 15.975544929493006 + }, + { + "x": -0.9019851036096374, + "y": 10.327527444688844, + "z": 15.965239603987541 + }, + { + "x": -0.20393232265616734, + "y": 10.327527444688847, + "z": 15.421201612065174 + }, + { + "x": 0.494120458297302, + "y": 10.327527444688851, + "z": 15.898358834860082 + }, + { + "x": 1.1921732392507698, + "y": 10.327527444688844, + "z": 15.479836881849838 + }, + { + "x": 1.8902260202042411, + "y": 10.327527444688846, + "z": 15.124652920348872 + }, + { + "x": 2.588278801157708, + "y": 10.327527444688847, + "z": 15.533231697293573 + }, + { + "x": -9.976671256004732, + "y": 11.44441531240147, + "z": 15.927034305374619 + }, + { + "x": -9.278618475051266, + "y": 11.444415312401473, + "z": 15.526462530496746 + }, + { + "x": -8.580565694097798, + "y": 11.444415312401473, + "z": 15.551433078735805 + }, + { + "x": -7.882512913144328, + "y": 11.444415312401475, + "z": 15.5404241148105 + }, + { + "x": -7.184460132190858, + "y": 11.444415312401471, + "z": 15.864963920724097 + }, + { + "x": -6.486407351237387, + "y": 11.444415312401473, + "z": 15.496576820265771 + }, + { + "x": -5.7883545702839205, + "y": 11.44441531240147, + "z": 15.897217056666138 + }, + { + "x": -5.09030178933045, + "y": 11.444415312401471, + "z": 15.538260884833642 + }, + { + "x": -4.392249008376982, + "y": 11.444415312401471, + "z": 15.484836138079332 + }, + { + "x": -3.6941962274235127, + "y": 11.444415312401471, + "z": 15.08492053816324 + }, + { + "x": -2.9961434464700414, + "y": 11.444415312401471, + "z": 15.178504460108702 + }, + { + "x": -2.2980906655165736, + "y": 11.444415312401471, + "z": 15.972590246225051 + }, + { + "x": -1.6000378845631036, + "y": 11.444415312401471, + "z": 15.826487024233904 + }, + { + "x": -0.9019851036096374, + "y": 11.444415312401471, + "z": 15.684870267605813 + }, + { + "x": -0.20393232265616734, + "y": 11.444415312401473, + "z": 15.680428282674603 + }, + { + "x": 0.49412045829730045, + "y": 11.44441531240147, + "z": 15.01628009742884 + }, + { + "x": 1.192173239250769, + "y": 11.444415312401473, + "z": 15.252759063268433 + }, + { + "x": 1.8902260202042416, + "y": 11.444415312401473, + "z": 15.590943927220508 + }, + { + "x": 2.5882788011577063, + "y": 11.444415312401471, + "z": 15.801290529221898 + }, + { + "x": -9.976671256004733, + "y": 12.561303180114097, + "z": 15.556187788283541 + }, + { + "x": -9.278618475051266, + "y": 12.561303180114097, + "z": 15.189146414487226 + }, + { + "x": -8.580565694097793, + "y": 12.561303180114098, + "z": 15.191909036222803 + }, + { + "x": -7.8825129131443274, + "y": 12.561303180114097, + "z": 15.135482442628351 + }, + { + "x": -7.184460132190859, + "y": 12.561303180114097, + "z": 15.862296038243127 + }, + { + "x": -6.486407351237388, + "y": 12.561303180114095, + "z": 15.685713864250907 + }, + { + "x": -5.78835457028392, + "y": 12.561303180114097, + "z": 15.306132592869053 + }, + { + "x": -5.09030178933045, + "y": 12.561303180114098, + "z": 15.36816528177269 + }, + { + "x": -4.392249008376982, + "y": 12.561303180114095, + "z": 15.657969484877757 + }, + { + "x": -3.6941962274235127, + "y": 12.561303180114098, + "z": 15.63592763786946 + }, + { + "x": -2.996143446470043, + "y": 12.561303180114095, + "z": 15.031370653785473 + }, + { + "x": -2.2980906655165745, + "y": 12.561303180114098, + "z": 15.666725448177536 + }, + { + "x": -1.6000378845631056, + "y": 12.561303180114097, + "z": 15.854644234224523 + }, + { + "x": -0.9019851036096371, + "y": 12.561303180114098, + "z": 15.873159029927642 + }, + { + "x": -0.20393232265616756, + "y": 12.561303180114098, + "z": 15.334453510741914 + }, + { + "x": 0.49412045829730245, + "y": 12.561303180114098, + "z": 15.792394617475754 + }, + { + "x": 1.1921732392507698, + "y": 12.561303180114095, + "z": 15.051773218927798 + }, + { + "x": 1.8902260202042402, + "y": 12.561303180114097, + "z": 15.99887685337983 + }, + { + "x": 2.588278801157708, + "y": 12.561303180114097, + "z": 15.642159948890173 + }, + { + "x": -9.976671256004735, + "y": 13.67819104782672, + "z": 15.43937149384961 + }, + { + "x": -9.278618475051264, + "y": 13.678191047826722, + "z": 15.067945312274594 + }, + { + "x": -8.580565694097796, + "y": 13.678191047826724, + "z": 15.55276483649051 + }, + { + "x": -7.8825129131443274, + "y": 13.678191047826722, + "z": 15.959904774539128 + }, + { + "x": -7.184460132190855, + "y": 13.678191047826727, + "z": 15.567983693242066 + }, + { + "x": -6.486407351237389, + "y": 13.678191047826722, + "z": 15.220025173025215 + }, + { + "x": -5.788354570283919, + "y": 13.678191047826722, + "z": 15.514023830422211 + }, + { + "x": -5.090301789330453, + "y": 13.678191047826726, + "z": 15.969488529008576 + }, + { + "x": -4.392249008376982, + "y": 13.678191047826722, + "z": 15.524977397883767 + }, + { + "x": -3.6941962274235127, + "y": 13.678191047826722, + "z": 15.686870259552668 + }, + { + "x": -2.996143446470045, + "y": 13.678191047826719, + "z": 15.295116646818405 + }, + { + "x": -2.2980906655165736, + "y": 13.67819104782672, + "z": 15.948959506558703 + }, + { + "x": -1.6000378845631038, + "y": 13.678191047826722, + "z": 15.16844254879674 + }, + { + "x": -0.9019851036096371, + "y": 13.678191047826724, + "z": 15.307414907639574 + }, + { + "x": -0.20393232265616756, + "y": 13.67819104782672, + "z": 15.678546352627942 + }, + { + "x": 0.4941204582973022, + "y": 13.678191047826722, + "z": 15.568465132065334 + }, + { + "x": 1.1921732392507702, + "y": 13.678191047826724, + "z": 15.344085282806347 + }, + { + "x": 1.8902260202042416, + "y": 13.678191047826726, + "z": 15.735125269151817 + }, + { + "x": 2.5882788011577063, + "y": 13.678191047826722, + "z": 15.390980087868394 + }, + { + "x": -9.976671256004733, + "y": 14.795078915539348, + "z": 15.689137040492676 + }, + { + "x": -9.278618475051266, + "y": 14.795078915539351, + "z": 15.854710250559593 + }, + { + "x": -8.580565694097794, + "y": 14.795078915539348, + "z": 15.558831327855046 + }, + { + "x": -7.882512913144327, + "y": 14.79507891553935, + "z": 15.128411538493081 + }, + { + "x": -7.184460132190856, + "y": 14.795078915539346, + "z": 15.239247571788376 + }, + { + "x": -6.486407351237389, + "y": 14.79507891553935, + "z": 15.902333246964185 + }, + { + "x": -5.78835457028392, + "y": 14.795078915539346, + "z": 15.45346548429386 + }, + { + "x": -5.09030178933045, + "y": 14.79507891553935, + "z": 15.418195089985707 + }, + { + "x": -4.392249008376982, + "y": 14.795078915539346, + "z": 15.323860225884179 + }, + { + "x": -3.6941962274235127, + "y": 14.795078915539348, + "z": 15.099431216297406 + }, + { + "x": -2.996143446470043, + "y": 14.795078915539346, + "z": 15.49203351349199 + }, + { + "x": -2.2980906655165736, + "y": 14.79507891553935, + "z": 15.892475650130061 + }, + { + "x": -1.6000378845631071, + "y": 14.795078915539342, + "z": 15.628655063746802 + }, + { + "x": -0.9019851036096371, + "y": 14.795078915539346, + "z": 15.01740324404901 + }, + { + "x": -0.203932322656168, + "y": 14.795078915539346, + "z": 15.61059911437826 + }, + { + "x": 0.494120458297302, + "y": 14.795078915539346, + "z": 15.151572433370898 + }, + { + "x": 1.19217323925077, + "y": 14.795078915539348, + "z": 15.733345216947303 + }, + { + "x": 1.8902260202042398, + "y": 14.795078915539346, + "z": 15.003422951793029 + }, + { + "x": 2.588278801157708, + "y": 14.795078915539346, + "z": 15.229241639948096 + } + ], + "pointsGround": [ + { + "x": -30.674724036958203, + "y": -26.425790571000537, + "z": 0.7710938983462257 + }, + { + "x": -25.278618475051264, + "y": -26.425790571000537, + "z": 0.4041625947710884 + }, + { + "x": -19.882512913144325, + "y": -26.425790571000537, + "z": 0.1659986703498283 + }, + { + "x": -14.48640735123739, + "y": -26.425790571000537, + "z": 0.9850470526074279 + }, + { + "x": -9.09030178933045, + "y": -26.425790571000537, + "z": 0.10900463355193131 + }, + { + "x": -3.6941962274235127, + "y": -26.425790571000537, + "z": 0.30668040798356777 + }, + { + "x": 1.7019093344834246, + "y": -26.425790571000537, + "z": 0.8021404611888064 + }, + { + "x": 7.098014896390362, + "y": -26.425790571000537, + "z": 0.44554667894055444 + }, + { + "x": 12.494120458297305, + "y": -26.425790571000537, + "z": 0.22498315396950727 + }, + { + "x": 17.89022602020424, + "y": -26.425790571000537, + "z": 0.011206652974340437 + }, + { + "x": 23.286331582111178, + "y": -26.425790571000537, + "z": 0.7653673406529088 + }, + { + "x": -30.674724036958203, + "y": -20.192014835575286, + "z": 0.028743590707305627 + }, + { + "x": -25.278618475051264, + "y": -20.192014835575286, + "z": 0.007561190523002851 + }, + { + "x": -19.882512913144325, + "y": -20.192014835575286, + "z": 0.5100224169483513 + }, + { + "x": -14.48640735123739, + "y": -20.192014835575286, + "z": 0.38209498458639485 + }, + { + "x": -9.09030178933045, + "y": -20.192014835575286, + "z": 0.27940878331633695 + }, + { + "x": -3.6941962274235127, + "y": -20.192014835575286, + "z": 0.7030882941107677 + }, + { + "x": 1.7019093344834246, + "y": -20.192014835575286, + "z": 0.23534573532424202 + }, + { + "x": 7.098014896390362, + "y": -20.192014835575286, + "z": 0.7313219219126375 + }, + { + "x": 12.494120458297305, + "y": -20.192014835575286, + "z": 0.08900155783118753 + }, + { + "x": 17.89022602020424, + "y": -20.192014835575286, + "z": 0.08264898512635799 + }, + { + "x": 23.286331582111178, + "y": -20.192014835575286, + "z": 0.33872517819457 + }, + { + "x": -30.674724036958203, + "y": -13.958239100150038, + "z": 0.32991219606712097 + }, + { + "x": -25.278618475051264, + "y": -13.958239100150038, + "z": 0.73131695703199 + }, + { + "x": -19.882512913144325, + "y": -13.958239100150038, + "z": 0.8959534107222936 + }, + { + "x": -14.48640735123739, + "y": -13.958239100150038, + "z": 0.8126501635707217 + }, + { + "x": -9.09030178933045, + "y": -13.958239100150038, + "z": 0.6535485864866285 + }, + { + "x": -3.6941962274235127, + "y": -13.958239100150038, + "z": 0.9268362018870359 + }, + { + "x": 1.7019093344834246, + "y": -13.958239100150038, + "z": 0.09924142626078866 + }, + { + "x": 7.098014896390362, + "y": -13.958239100150038, + "z": 0.6918291313070009 + }, + { + "x": 12.494120458297305, + "y": -13.958239100150038, + "z": 0.9254800574507006 + }, + { + "x": 17.89022602020424, + "y": -13.958239100150038, + "z": 0.9801408294495851 + }, + { + "x": 23.286331582111178, + "y": -13.958239100150038, + "z": 0.10141979861139311 + }, + { + "x": -30.674724036958203, + "y": -7.724463364724784, + "z": 0.038685026130958006 + }, + { + "x": -25.278618475051264, + "y": -7.724463364724784, + "z": 0.34105472003158865 + }, + { + "x": -19.882512913144325, + "y": -7.724463364724784, + "z": 0.8496396214932388 + }, + { + "x": -14.48640735123739, + "y": -7.724463364724784, + "z": 0.6870929052527496 + }, + { + "x": -9.09030178933045, + "y": -7.724463364724784, + "z": 0.7440021428018818 + }, + { + "x": -3.6941962274235127, + "y": -7.724463364724784, + "z": 0.6856456625674132 + }, + { + "x": 1.7019093344834246, + "y": -7.724463364724784, + "z": 0.09306132285532603 + }, + { + "x": 7.098014896390362, + "y": -7.724463364724784, + "z": 0.040521103907619184 + }, + { + "x": 12.494120458297305, + "y": -7.724463364724784, + "z": 0.27162018756923273 + }, + { + "x": 17.89022602020424, + "y": -7.724463364724784, + "z": 0.2632511264007777 + }, + { + "x": 23.286331582111178, + "y": -7.724463364724784, + "z": 0.4997794849331395 + }, + { + "x": -30.674724036958203, + "y": -1.4906876292995328, + "z": 0.9615699052631714 + }, + { + "x": -25.278618475051264, + "y": -1.4906876292995328, + "z": 0.5560454663615886 + }, + { + "x": -19.882512913144325, + "y": -1.4906876292995328, + "z": 0.017603008084745617 + }, + { + "x": -14.48640735123739, + "y": -1.4906876292995328, + "z": 0.4885405774640574 + }, + { + "x": -9.09030178933045, + "y": -1.4906876292995328, + "z": 0.34221245876616446 + }, + { + "x": -3.6941962274235127, + "y": -1.4906876292995328, + "z": 0.4856534816723566 + }, + { + "x": 1.7019093344834246, + "y": -1.4906876292995328, + "z": 0.642432012894392 + }, + { + "x": 7.098014896390362, + "y": -1.4906876292995328, + "z": 0.6201277410705237 + }, + { + "x": 12.494120458297305, + "y": -1.4906876292995328, + "z": 0.07334534082251849 + }, + { + "x": 17.89022602020424, + "y": -1.4906876292995328, + "z": 0.8954218765233746 + }, + { + "x": 23.286331582111178, + "y": -1.4906876292995328, + "z": 0.5953727628082841 + }, + { + "x": -30.674724036958203, + "y": 4.743088106125716, + "z": 0.4323687201516557 + }, + { + "x": -25.278618475051264, + "y": 4.743088106125716, + "z": 0.07425039870396741 + }, + { + "x": -19.882512913144325, + "y": 4.743088106125716, + "z": 0.43468171331783834 + }, + { + "x": -14.48640735123739, + "y": 4.743088106125716, + "z": 0.08909364188513423 + }, + { + "x": -9.09030178933045, + "y": 4.743088106125716, + "z": 0.29635446998120957 + }, + { + "x": -3.6941962274235127, + "y": 4.743088106125716, + "z": 0.6531318214969392 + }, + { + "x": 1.7019093344834246, + "y": 4.743088106125716, + "z": 0.8753042593017706 + }, + { + "x": 7.098014896390362, + "y": 4.743088106125716, + "z": 0.3463052526797658 + }, + { + "x": 12.494120458297305, + "y": 4.743088106125716, + "z": 0.5331540226625064 + }, + { + "x": 17.89022602020424, + "y": 4.743088106125716, + "z": 0.08572659552363986 + }, + { + "x": 23.286331582111178, + "y": 4.743088106125716, + "z": 0.7852265112033238 + }, + { + "x": -30.674724036958203, + "y": 10.976863841550966, + "z": 0.9273237920959125 + }, + { + "x": -25.278618475051264, + "y": 10.976863841550966, + "z": 0.9688761643920448 + }, + { + "x": -19.882512913144325, + "y": 10.976863841550966, + "z": 0.1689676969167626 + }, + { + "x": -14.48640735123739, + "y": 10.976863841550966, + "z": 0.5324553630931561 + }, + { + "x": -9.09030178933045, + "y": 10.976863841550966, + "z": 0.5923158780635874 + }, + { + "x": -3.6941962274235127, + "y": 10.976863841550966, + "z": 0.9590861513088859 + }, + { + "x": 1.7019093344834246, + "y": 10.976863841550966, + "z": 0.5497000727568288 + }, + { + "x": 7.098014896390362, + "y": 10.976863841550966, + "z": 0.6382605990573115 + }, + { + "x": 12.494120458297305, + "y": 10.976863841550966, + "z": 0.04848045392356834 + }, + { + "x": 17.89022602020424, + "y": 10.976863841550966, + "z": 0.8110287975571252 + }, + { + "x": 23.286331582111178, + "y": 10.976863841550966, + "z": 0.07547405179379231 + }, + { + "x": -30.674724036958203, + "y": 17.210639576976217, + "z": 0.8301327111339815 + }, + { + "x": -25.278618475051264, + "y": 17.210639576976217, + "z": 0.7697470517688184 + }, + { + "x": -19.882512913144325, + "y": 17.210639576976217, + "z": 0.33990794436070504 + }, + { + "x": -14.48640735123739, + "y": 17.210639576976217, + "z": 0.795047155485976 + }, + { + "x": -9.09030178933045, + "y": 17.210639576976217, + "z": 0.16500800902257115 + }, + { + "x": -3.6941962274235127, + "y": 17.210639576976217, + "z": 0.5846237431208714 + }, + { + "x": 1.7019093344834246, + "y": 17.210639576976217, + "z": 0.613587944588432 + }, + { + "x": 7.098014896390362, + "y": 17.210639576976217, + "z": 0.0493971184126088 + }, + { + "x": 12.494120458297305, + "y": 17.210639576976217, + "z": 0.30535231638017685 + }, + { + "x": 17.89022602020424, + "y": 17.210639576976217, + "z": 0.9067954886270666 + }, + { + "x": 23.286331582111178, + "y": 17.210639576976217, + "z": 0.2059979220880186 + }, + { + "x": -30.674724036958203, + "y": 23.444415312401468, + "z": 0.44331226332267387 + }, + { + "x": -25.278618475051264, + "y": 23.444415312401468, + "z": 0.9086859998799329 + }, + { + "x": -19.882512913144325, + "y": 23.444415312401468, + "z": 0.7753892227892714 + }, + { + "x": -14.48640735123739, + "y": 23.444415312401468, + "z": 0.2524111919349112 + }, + { + "x": -9.09030178933045, + "y": 23.444415312401468, + "z": 0.6549085009167476 + }, + { + "x": -3.6941962274235127, + "y": 23.444415312401468, + "z": 0.38929119258620365 + }, + { + "x": 1.7019093344834246, + "y": 23.444415312401468, + "z": 0.4399295013583868 + }, + { + "x": 7.098014896390362, + "y": 23.444415312401468, + "z": 0.1652168446058486 + }, + { + "x": 12.494120458297305, + "y": 23.444415312401468, + "z": 0.9253149348894669 + }, + { + "x": 17.89022602020424, + "y": 23.444415312401468, + "z": 0.7300971037382712 + }, + { + "x": 23.286331582111178, + "y": 23.444415312401468, + "z": 0.41405288940949964 + }, + { + "x": -30.674724036958203, + "y": 29.67819104782672, + "z": 0.17634339405984775 + }, + { + "x": -25.278618475051264, + "y": 29.67819104782672, + "z": 0.628721674265676 + }, + { + "x": -19.882512913144325, + "y": 29.67819104782672, + "z": 0.04872684369270077 + }, + { + "x": -14.48640735123739, + "y": 29.67819104782672, + "z": 0.3195728805472948 + }, + { + "x": -9.09030178933045, + "y": 29.67819104782672, + "z": 0.8097570956730084 + }, + { + "x": -3.6941962274235127, + "y": 29.67819104782672, + "z": 0.8933376036087691 + }, + { + "x": 1.7019093344834246, + "y": 29.67819104782672, + "z": 0.6833458615855061 + }, + { + "x": 7.098014896390362, + "y": 29.67819104782672, + "z": 0.07042766831369496 + }, + { + "x": 12.494120458297305, + "y": 29.67819104782672, + "z": 0.435084741765207 + }, + { + "x": 17.89022602020424, + "y": 29.67819104782672, + "z": 0.8469414225998062 + }, + { + "x": 23.286331582111178, + "y": 29.67819104782672, + "z": 0.7843439652511589 + }, + { + "x": -30.674724036958203, + "y": 35.91196678325197, + "z": 0.3568946683578634 + }, + { + "x": -25.278618475051264, + "y": 35.91196678325197, + "z": 0.24411768756998595 + }, + { + "x": -19.882512913144325, + "y": 35.91196678325197, + "z": 0.6649346615490199 + }, + { + "x": -14.48640735123739, + "y": 35.91196678325197, + "z": 0.7491856975244292 + }, + { + "x": -9.09030178933045, + "y": 35.91196678325197, + "z": 0.5013073144952335 + }, + { + "x": -3.6941962274235127, + "y": 35.91196678325197, + "z": 0.48812381247436804 + }, + { + "x": 1.7019093344834246, + "y": 35.91196678325197, + "z": 0.29068051618089924 + }, + { + "x": 7.098014896390362, + "y": 35.91196678325197, + "z": 0.7327173080913337 + }, + { + "x": 12.494120458297305, + "y": 35.91196678325197, + "z": 0.48375690424989765 + }, + { + "x": 17.89022602020424, + "y": 35.91196678325197, + "z": 0.780374279143463 + }, + { + "x": 23.286331582111178, + "y": 35.91196678325197, + "z": 0.8784310225762572 + } + ], + "footprintExterior": [ + { + "x": 3.2863315821111776, + "y": -6.425790571000537, + "z": 0 + }, + { + "x": 3.2863315821111776, + "y": 15.911966783251973, + "z": 0 + }, + { + "x": -10.674724036958203, + "y": 15.911966783251973, + "z": 0 + }, + { + "x": -10.674724036958203, + "y": -6.425790571000537, + "z": 0 + }, + { + "x": 3.2863315821111776, + "y": -6.425790571000537, + "z": 0 + } + ] +} diff --git a/roofersharp/RooferSharp.Test/testdata/slantedroof.json b/roofersharp/RooferSharp.Test/testdata/slantedroof.json new file mode 100644 index 00000000..e1a9eb35 --- /dev/null +++ b/roofersharp/RooferSharp.Test/testdata/slantedroof.json @@ -0,0 +1,4698 @@ +{ + "pointsRoof": [ + { + "x": 15.814964664370011, + "y": -7.026570386323232, + "z": 14.792621720619398 + }, + { + "x": 16.304218114163053, + "y": -7.026570386323229, + "z": 14.4622317502685 + }, + { + "x": 16.793471563956086, + "y": -7.0265703863232245, + "z": 14.144718517833 + }, + { + "x": 17.282725013749133, + "y": -7.026570386323228, + "z": 13.932926516065375 + }, + { + "x": 17.771978463542162, + "y": -7.026570386323229, + "z": 13.551625434166453 + }, + { + "x": 18.26123191333519, + "y": -7.026570386323226, + "z": 13.27769617161624 + }, + { + "x": 18.750485363128238, + "y": -7.026570386323228, + "z": 13.03354533694338 + }, + { + "x": 19.239738812921278, + "y": -7.026570386323228, + "z": 12.704189118725179 + }, + { + "x": 19.72899226271431, + "y": -7.026570386323228, + "z": 12.388435926234692 + }, + { + "x": 20.21824571250734, + "y": -7.026570386323227, + "z": 12.073361436141804 + }, + { + "x": 20.70749916230039, + "y": -7.026570386323229, + "z": 11.855080664916276 + }, + { + "x": 21.19675261209342, + "y": -7.026570386323229, + "z": 11.487721449928339 + }, + { + "x": 21.686006061886467, + "y": -7.02657038632323, + "z": 11.191906369916525 + }, + { + "x": 22.1752595116795, + "y": -7.026570386323229, + "z": 10.948455652565682 + }, + { + "x": 22.66451296147254, + "y": -7.026570386323228, + "z": 10.64196606933611 + }, + { + "x": 23.153766411265583, + "y": -7.026570386323228, + "z": 10.338000609215722 + }, + { + "x": 23.643019861058605, + "y": -7.026570386323229, + "z": 10.086671720301794 + }, + { + "x": 24.132273310851648, + "y": -7.026570386323231, + "z": 9.746200624429758 + }, + { + "x": 24.62152676064469, + "y": -7.026570386323229, + "z": 9.502101403095216 + }, + { + "x": 25.11078021043773, + "y": -7.02657038632323, + "z": 9.14417252669369 + }, + { + "x": 25.600033660230768, + "y": -7.026570386323229, + "z": 8.849840429429829 + }, + { + "x": 26.089287110023804, + "y": -7.026570386323229, + "z": 8.581751208743272 + }, + { + "x": 26.57854055981684, + "y": -7.02657038632323, + "z": 8.287173070537145 + }, + { + "x": 27.06779400960988, + "y": -7.026570386323229, + "z": 8.033616706640256 + }, + { + "x": 27.557047459402916, + "y": -7.026570386323228, + "z": 7.756383512015908 + }, + { + "x": 28.04630090919596, + "y": -7.026570386323226, + "z": 7.454356347307368 + }, + { + "x": 28.535554358989, + "y": -7.026570386323227, + "z": 7.14474934960558 + }, + { + "x": 29.024807808782036, + "y": -7.02657038632323, + "z": 6.878381271152242 + }, + { + "x": 15.814964664370008, + "y": -6.211174823707086, + "z": 14.725436473410856 + }, + { + "x": 16.30421811416305, + "y": -6.2111748237070925, + "z": 14.490998403922093 + }, + { + "x": 16.793471563956086, + "y": -6.211174823707089, + "z": 14.220666656543088 + }, + { + "x": 17.282725013749126, + "y": -6.211174823707088, + "z": 13.932435893749593 + }, + { + "x": 17.771978463542162, + "y": -6.211174823707087, + "z": 13.550866950672399 + }, + { + "x": 18.261231913335195, + "y": -6.211174823707089, + "z": 13.250896633430978 + }, + { + "x": 18.75048536312824, + "y": -6.211174823707089, + "z": 12.987436762827658 + }, + { + "x": 19.23973881292127, + "y": -6.211174823707088, + "z": 12.744598412980446 + }, + { + "x": 19.728992262714318, + "y": -6.21117482370709, + "z": 12.434646901363017 + }, + { + "x": 20.218245712507347, + "y": -6.211174823707089, + "z": 12.146640985124552 + }, + { + "x": 20.707499162300383, + "y": -6.211174823707088, + "z": 11.847108497107728 + }, + { + "x": 21.196752612093427, + "y": -6.211174823707087, + "z": 11.494153223143135 + }, + { + "x": 21.686006061886463, + "y": -6.211174823707089, + "z": 11.195202361254987 + }, + { + "x": 22.175259511679503, + "y": -6.211174823707091, + "z": 10.92461542962777 + }, + { + "x": 22.66451296147254, + "y": -6.211174823707087, + "z": 10.630081683517547 + }, + { + "x": 23.15376641126558, + "y": -6.21117482370709, + "z": 10.360037679377402 + }, + { + "x": 23.64301986105861, + "y": -6.211174823707092, + "z": 10.11251988141703 + }, + { + "x": 24.13227331085166, + "y": -6.211174823707092, + "z": 9.77827059753349 + }, + { + "x": 24.62152676064469, + "y": -6.211174823707089, + "z": 9.430729511712427 + }, + { + "x": 25.11078021043773, + "y": -6.211174823707089, + "z": 9.184126428656977 + }, + { + "x": 25.600033660230775, + "y": -6.211174823707089, + "z": 8.875796776793806 + }, + { + "x": 26.0892871100238, + "y": -6.211174823707089, + "z": 8.59644403909105 + }, + { + "x": 26.578540559816844, + "y": -6.21117482370709, + "z": 8.318425052219876 + }, + { + "x": 27.067794009609887, + "y": -6.211174823707093, + "z": 8.022497785044106 + }, + { + "x": 27.55704745940291, + "y": -6.211174823707091, + "z": 7.674122705025932 + }, + { + "x": 28.04630090919596, + "y": -6.211174823707085, + "z": 7.462633518602633 + }, + { + "x": 28.535554358988996, + "y": -6.211174823707089, + "z": 7.138931767237747 + }, + { + "x": 29.024807808782032, + "y": -6.211174823707088, + "z": 6.828934522978705 + }, + { + "x": 15.81496466437001, + "y": -5.395779261090943, + "z": 14.72293737065517 + }, + { + "x": 16.304218114163053, + "y": -5.395779261090947, + "z": 14.465283662123177 + }, + { + "x": 16.79347156395609, + "y": -5.395779261090948, + "z": 14.13702801498653 + }, + { + "x": 17.28272501374913, + "y": -5.395779261090951, + "z": 13.864057257802761 + }, + { + "x": 17.771978463542162, + "y": -5.395779261090948, + "z": 13.606038152960954 + }, + { + "x": 18.261231913335195, + "y": -5.395779261090946, + "z": 13.334558556748059 + }, + { + "x": 18.750485363128238, + "y": -5.395779261090948, + "z": 12.987961816092477 + }, + { + "x": 19.23973881292127, + "y": -5.395779261090948, + "z": 12.712949853097374 + }, + { + "x": 19.728992262714314, + "y": -5.39577926109095, + "z": 12.374510270390106 + }, + { + "x": 20.218245712507354, + "y": -5.395779261090947, + "z": 12.150763421964696 + }, + { + "x": 20.70749916230039, + "y": -5.395779261090948, + "z": 11.87127631006058 + }, + { + "x": 21.196752612093427, + "y": -5.395779261090948, + "z": 11.581734707296809 + }, + { + "x": 21.686006061886467, + "y": -5.395779261090948, + "z": 11.2080470205559 + }, + { + "x": 22.175259511679503, + "y": -5.395779261090947, + "z": 10.950698947180163 + }, + { + "x": 22.664512961472536, + "y": -5.395779261090949, + "z": 10.662988158683829 + }, + { + "x": 23.15376641126558, + "y": -5.395779261090948, + "z": 10.405968346014978 + }, + { + "x": 23.64301986105861, + "y": -5.395779261090948, + "z": 10.071332898166393 + }, + { + "x": 24.132273310851655, + "y": -5.395779261090948, + "z": 9.786492110803065 + }, + { + "x": 24.62152676064469, + "y": -5.395779261090948, + "z": 9.43381725629631 + }, + { + "x": 25.11078021043773, + "y": -5.395779261090949, + "z": 9.216375250666287 + }, + { + "x": 25.60003366023077, + "y": -5.395779261090947, + "z": 8.84912293609657 + }, + { + "x": 26.089287110023804, + "y": -5.395779261090948, + "z": 8.630891962037213 + }, + { + "x": 26.578540559816844, + "y": -5.395779261090947, + "z": 8.331156556107318 + }, + { + "x": 27.067794009609887, + "y": -5.395779261090948, + "z": 7.994475805373124 + }, + { + "x": 27.557047459402916, + "y": -5.395779261090936, + "z": 7.746292886492276 + }, + { + "x": 28.04630090919596, + "y": -5.395779261090943, + "z": 7.389592131852557 + }, + { + "x": 28.535554358988993, + "y": -5.39577926109095, + "z": 7.137856865269007 + }, + { + "x": 29.02480780878203, + "y": -5.395779261090948, + "z": 6.847056445422385 + }, + { + "x": 15.814964664370008, + "y": -4.580383698474801, + "z": 14.720452042626038 + }, + { + "x": 16.304218114163046, + "y": -4.580383698474797, + "z": 14.452350722429415 + }, + { + "x": 16.79347156395608, + "y": -4.580383698474803, + "z": 14.218798199660728 + }, + { + "x": 17.282725013749126, + "y": -4.580383698474808, + "z": 13.855021603013439 + }, + { + "x": 17.77197846354216, + "y": -4.580383698474806, + "z": 13.585056197143526 + }, + { + "x": 18.26123191333519, + "y": -4.58038369847481, + "z": 13.337896730805879 + }, + { + "x": 18.75048536312824, + "y": -4.580383698474807, + "z": 13.030870213103425 + }, + { + "x": 19.23973881292127, + "y": -4.580383698474808, + "z": 12.684875570024614 + }, + { + "x": 19.728992262714314, + "y": -4.580383698474807, + "z": 12.431428460929418 + }, + { + "x": 20.218245712507354, + "y": -4.580383698474807, + "z": 12.111169890102978 + }, + { + "x": 20.707499162300387, + "y": -4.580383698474808, + "z": 11.82253688098682 + }, + { + "x": 21.196752612093427, + "y": -4.580383698474808, + "z": 11.50136877531819 + }, + { + "x": 21.686006061886467, + "y": -4.580383698474808, + "z": 11.283681744353173 + }, + { + "x": 22.175259511679503, + "y": -4.580383698474808, + "z": 10.970463121244672 + }, + { + "x": 22.66451296147254, + "y": -4.580383698474808, + "z": 10.645161859818419 + }, + { + "x": 23.153766411265583, + "y": -4.580383698474809, + "z": 10.327694070290075 + }, + { + "x": 23.64301986105862, + "y": -4.580383698474808, + "z": 10.079235058317275 + }, + { + "x": 24.13227331085165, + "y": -4.580383698474809, + "z": 9.7275387352666 + }, + { + "x": 24.62152676064469, + "y": -4.580383698474808, + "z": 9.460926498958676 + }, + { + "x": 25.11078021043773, + "y": -4.580383698474809, + "z": 9.216248080477872 + }, + { + "x": 25.600033660230768, + "y": -4.580383698474807, + "z": 8.93090929127807 + }, + { + "x": 26.0892871100238, + "y": -4.580383698474817, + "z": 8.61621327708237 + }, + { + "x": 26.57854055981684, + "y": -4.580383698474808, + "z": 8.261224617761806 + }, + { + "x": 27.067794009609884, + "y": -4.58038369847481, + "z": 8.003993485113579 + }, + { + "x": 27.55704745940292, + "y": -4.580383698474809, + "z": 7.751482313203658 + }, + { + "x": 28.046300909195963, + "y": -4.5803836984748045, + "z": 7.451525727475411 + }, + { + "x": 28.535554358988996, + "y": -4.580383698474812, + "z": 7.115083957792706 + }, + { + "x": 29.024807808782036, + "y": -4.58038369847481, + "z": 6.81010941972054 + }, + { + "x": 15.814964664370008, + "y": -3.764988135858656, + "z": 14.78200579693968 + }, + { + "x": 16.30421811416305, + "y": -3.7649881358586668, + "z": 14.496734060543838 + }, + { + "x": 16.793471563956082, + "y": -3.7649881358586694, + "z": 14.178249382247541 + }, + { + "x": 17.28272501374913, + "y": -3.7649881358586668, + "z": 13.883234192052072 + }, + { + "x": 17.771978463542162, + "y": -3.7649881358586694, + "z": 13.569793022429348 + }, + { + "x": 18.261231913335198, + "y": -3.764988135858667, + "z": 13.320299861627015 + }, + { + "x": 18.750485363128238, + "y": -3.7649881358586685, + "z": 13.001706981249487 + }, + { + "x": 19.239738812921274, + "y": -3.764988135858668, + "z": 12.737671878745468 + }, + { + "x": 19.728992262714314, + "y": -3.764988135858669, + "z": 12.45378071309537 + }, + { + "x": 20.21824571250735, + "y": -3.7649881358586685, + "z": 12.144373357845154 + }, + { + "x": 20.707499162300387, + "y": -3.7649881358586703, + "z": 11.831100320957924 + }, + { + "x": 21.196752612093427, + "y": -3.764988135858669, + "z": 11.510875260561289 + }, + { + "x": 21.686006061886467, + "y": -3.764988135858669, + "z": 11.266856864894615 + }, + { + "x": 22.175259511679503, + "y": -3.764988135858668, + "z": 10.931443879483712 + }, + { + "x": 22.664512961472536, + "y": -3.7649881358586663, + "z": 10.634174335916683 + }, + { + "x": 23.153766411265575, + "y": -3.7649881358586677, + "z": 10.326100618901151 + }, + { + "x": 23.643019861058608, + "y": -3.764988135858668, + "z": 10.036196000660604 + }, + { + "x": 24.13227331085165, + "y": -3.764988135858668, + "z": 9.810992411829105 + }, + { + "x": 24.62152676064469, + "y": -3.7649881358586694, + "z": 9.517540597170719 + }, + { + "x": 25.110780210437724, + "y": -3.764988135858666, + "z": 9.169810065716124 + }, + { + "x": 25.600033660230764, + "y": -3.764988135858669, + "z": 8.88318351308964 + }, + { + "x": 26.089287110023804, + "y": -3.764988135858669, + "z": 8.607219056694714 + }, + { + "x": 26.578540559816844, + "y": -3.764988135858668, + "z": 8.325300477939937 + }, + { + "x": 27.06779400960988, + "y": -3.764988135858662, + "z": 8.035117042116383 + }, + { + "x": 27.557047459402924, + "y": -3.7649881358586748, + "z": 7.7513316837912045 + }, + { + "x": 28.04630090919596, + "y": -3.7649881358586548, + "z": 7.450577995695086 + }, + { + "x": 28.535554358988993, + "y": -3.7649881358586588, + "z": 7.1514195250548855 + }, + { + "x": 29.024807808782032, + "y": -3.7649881358586703, + "z": 6.822302776646252 + }, + { + "x": 15.814964664370006, + "y": -2.94959257324252, + "z": 14.739004795591425 + }, + { + "x": 16.304218114163046, + "y": -2.949592573242525, + "z": 14.468986565477584 + }, + { + "x": 16.79347156395609, + "y": -2.9495925732425285, + "z": 14.164024300746838 + }, + { + "x": 17.282725013749136, + "y": -2.949592573242521, + "z": 13.900318640611784 + }, + { + "x": 17.771978463542165, + "y": -2.949592573242528, + "z": 13.595904103963468 + }, + { + "x": 18.261231913335198, + "y": -2.949592573242528, + "z": 13.300155284339809 + }, + { + "x": 18.75048536312824, + "y": -2.949592573242528, + "z": 13.01207894386309 + }, + { + "x": 19.239738812921278, + "y": -2.949592573242529, + "z": 12.750206731170353 + }, + { + "x": 19.72899226271431, + "y": -2.9495925732425263, + "z": 12.45473599864684 + }, + { + "x": 20.21824571250735, + "y": -2.9495925732425285, + "z": 12.167421339732767 + }, + { + "x": 20.707499162300387, + "y": -2.949592573242528, + "z": 11.865997563693481 + }, + { + "x": 21.196752612093423, + "y": -2.949592573242527, + "z": 11.504106853537419 + }, + { + "x": 21.68600606188647, + "y": -2.949592573242528, + "z": 11.215784270813062 + }, + { + "x": 22.1752595116795, + "y": -2.9495925732425263, + "z": 10.960821271897451 + }, + { + "x": 22.66451296147254, + "y": -2.949592573242528, + "z": 10.63354780802583 + }, + { + "x": 23.15376641126558, + "y": -2.949592573242528, + "z": 10.400799311309866 + }, + { + "x": 23.64301986105861, + "y": -2.949592573242528, + "z": 10.068679185153044 + }, + { + "x": 24.132273310851655, + "y": -2.949592573242527, + "z": 9.728595169248377 + }, + { + "x": 24.62152676064469, + "y": -2.949592573242527, + "z": 9.434238306440863 + }, + { + "x": 25.11078021043773, + "y": -2.9495925732425277, + "z": 9.19061566265858 + }, + { + "x": 25.600033660230768, + "y": -2.9495925732425277, + "z": 8.87949235203653 + }, + { + "x": 26.089287110023804, + "y": -2.9495925732425285, + "z": 8.638880569738124 + }, + { + "x": 26.57854055981684, + "y": -2.949592573242527, + "z": 8.277857215337065 + }, + { + "x": 27.067794009609884, + "y": -2.9495925732425277, + "z": 8.05685279226526 + }, + { + "x": 27.55704745940292, + "y": -2.949592573242541, + "z": 7.756651181202026 + }, + { + "x": 28.046300909195956, + "y": -2.949592573242523, + "z": 7.374243102980534 + }, + { + "x": 28.535554358988996, + "y": -2.9495925732425405, + "z": 7.162198277541469 + }, + { + "x": 29.024807808782032, + "y": -2.949592573242529, + "z": 6.792850751347547 + }, + { + "x": 15.814964664370004, + "y": -2.134197010626398, + "z": 14.719312273527716 + }, + { + "x": 16.30421811416305, + "y": -2.1341970106263863, + "z": 14.49731419106159 + }, + { + "x": 16.793471563956086, + "y": -2.1341970106263872, + "z": 14.192387519197926 + }, + { + "x": 17.282725013749126, + "y": -2.134197010626388, + "z": 13.886003197677939 + }, + { + "x": 17.771978463542162, + "y": -2.1341970106263877, + "z": 13.541971667522427 + }, + { + "x": 18.261231913335198, + "y": -2.1341970106263872, + "z": 13.258798695560161 + }, + { + "x": 18.750485363128238, + "y": -2.1341970106263877, + "z": 13.007876253932196 + }, + { + "x": 19.239738812921274, + "y": -2.134197010626388, + "z": 12.700306478402563 + }, + { + "x": 19.728992262714314, + "y": -2.1341970106263872, + "z": 12.402164547889708 + }, + { + "x": 20.218245712507354, + "y": -2.1341970106263872, + "z": 12.15890033114415 + }, + { + "x": 20.70749916230039, + "y": -2.134197010626388, + "z": 11.84939296740246 + }, + { + "x": 21.196752612093423, + "y": -2.134197010626387, + "z": 11.507426551366065 + }, + { + "x": 21.686006061886467, + "y": -2.134197010626388, + "z": 11.266393066438505 + }, + { + "x": 22.175259511679506, + "y": -2.1341970106263872, + "z": 10.937298895570827 + }, + { + "x": 22.66451296147254, + "y": -2.1341970106263872, + "z": 10.630999071085434 + }, + { + "x": 23.15376641126558, + "y": -2.134197010626388, + "z": 10.334712271765579 + }, + { + "x": 23.64301986105862, + "y": -2.1341970106263872, + "z": 10.017235618979987 + }, + { + "x": 24.132273310851655, + "y": -2.134197010626388, + "z": 9.791977674484286 + }, + { + "x": 24.62152676064469, + "y": -2.1341970106263877, + "z": 9.438872885760667 + }, + { + "x": 25.110780210437735, + "y": -2.1341970106263872, + "z": 9.213512492056415 + }, + { + "x": 25.60003366023077, + "y": -2.1341970106263886, + "z": 8.87112465953973 + }, + { + "x": 26.089287110023804, + "y": -2.134197010626388, + "z": 8.628257737507539 + }, + { + "x": 26.578540559816844, + "y": -2.1341970106263872, + "z": 8.27649758784743 + }, + { + "x": 27.06779400960988, + "y": -2.1341970106263886, + "z": 8.03909940543354 + }, + { + "x": 27.557047459402916, + "y": -2.1341970106263886, + "z": 7.739005740151553 + }, + { + "x": 28.046300909195963, + "y": -2.1341970106263877, + "z": 7.389773073300252 + }, + { + "x": 28.535554358988996, + "y": -2.134197010626387, + "z": 7.178082795520292 + }, + { + "x": 29.024807808782032, + "y": -2.1341970106263877, + "z": 6.818188236955881 + }, + { + "x": 15.814964664370013, + "y": -1.3188014480102546, + "z": 14.739008041064332 + }, + { + "x": 16.304218114163053, + "y": -1.3188014480102466, + "z": 14.461353359412007 + }, + { + "x": 16.79347156395609, + "y": -1.3188014480102468, + "z": 14.204152470346818 + }, + { + "x": 17.282725013749126, + "y": -1.3188014480102477, + "z": 13.888449171926611 + }, + { + "x": 17.771978463542162, + "y": -1.318801448010249, + "z": 13.611048337748638 + }, + { + "x": 18.2612319133352, + "y": -1.3188014480102472, + "z": 13.298622683472464 + }, + { + "x": 18.750485363128238, + "y": -1.3188014480102472, + "z": 13.040103628420795 + }, + { + "x": 19.239738812921274, + "y": -1.3188014480102466, + "z": 12.672934138370021 + }, + { + "x": 19.728992262714314, + "y": -1.3188014480102466, + "z": 12.396849311326235 + }, + { + "x": 20.21824571250735, + "y": -1.3188014480102466, + "z": 12.108113016813556 + }, + { + "x": 20.70749916230039, + "y": -1.318801448010249, + "z": 11.796556996819632 + }, + { + "x": 21.196752612093423, + "y": -1.318801448010247, + "z": 11.497710546064164 + }, + { + "x": 21.68600606188647, + "y": -1.3188014480102486, + "z": 11.199973148783133 + }, + { + "x": 22.175259511679506, + "y": -1.3188014480102468, + "z": 10.986572620447765 + }, + { + "x": 22.66451296147254, + "y": -1.3188014480102468, + "z": 10.65826921425128 + }, + { + "x": 23.15376641126558, + "y": -1.3188014480102468, + "z": 10.375716464846636 + }, + { + "x": 23.643019861058615, + "y": -1.3188014480102486, + "z": 10.051442972690282 + }, + { + "x": 24.13227331085165, + "y": -1.318801448010249, + "z": 9.805355685925786 + }, + { + "x": 24.62152676064469, + "y": -1.3188014480102481, + "z": 9.509069687077684 + }, + { + "x": 25.110780210437728, + "y": -1.3188014480102472, + "z": 9.23334370732993 + }, + { + "x": 25.600033660230775, + "y": -1.3188014480102486, + "z": 8.905334909523532 + }, + { + "x": 26.089287110023804, + "y": -1.3188014480102477, + "z": 8.646901514448952 + }, + { + "x": 26.57854055981685, + "y": -1.318801448010249, + "z": 8.349676904169364 + }, + { + "x": 27.067794009609884, + "y": -1.3188014480102472, + "z": 7.981036397608455 + }, + { + "x": 27.557047459402913, + "y": -1.31880144801023, + "z": 7.7580362681172 + }, + { + "x": 28.046300909195963, + "y": -1.318801448010249, + "z": 7.377654996389003 + }, + { + "x": 28.535554358988996, + "y": -1.3188014480102468, + "z": 7.156998462718386 + }, + { + "x": 29.02480780878203, + "y": -1.31880144801025, + "z": 6.809118547122758 + }, + { + "x": 15.81496466437001, + "y": -0.5034058853941035, + "z": 14.768695294137975 + }, + { + "x": 16.30421811416305, + "y": -0.503405885394108, + "z": 14.507469964694828 + }, + { + "x": 16.79347156395609, + "y": -0.5034058853941071, + "z": 14.207482468463448 + }, + { + "x": 17.282725013749126, + "y": -0.5034058853941084, + "z": 13.91898676516585 + }, + { + "x": 17.771978463542165, + "y": -0.5034058853941075, + "z": 13.553807230990165 + }, + { + "x": 18.261231913335198, + "y": -0.5034058853941064, + "z": 13.269082507933236 + }, + { + "x": 18.750485363128238, + "y": -0.5034058853941077, + "z": 12.970507608116385 + }, + { + "x": 19.239738812921274, + "y": -0.5034058853941072, + "z": 12.75632351926248 + }, + { + "x": 19.728992262714318, + "y": -0.5034058853941081, + "z": 12.376563351588725 + }, + { + "x": 20.218245712507354, + "y": -0.5034058853941079, + "z": 12.089062446273868 + }, + { + "x": 20.707499162300387, + "y": -0.5034058853941079, + "z": 11.830800024422068 + }, + { + "x": 21.19675261209343, + "y": -0.5034058853941079, + "z": 11.5084953537773 + }, + { + "x": 21.686006061886467, + "y": -0.5034058853941081, + "z": 11.244223397967914 + }, + { + "x": 22.1752595116795, + "y": -0.5034058853941077, + "z": 10.911396223539912 + }, + { + "x": 22.664512961472546, + "y": -0.5034058853941081, + "z": 10.697497411270465 + }, + { + "x": 23.15376641126558, + "y": -0.5034058853941064, + "z": 10.375060213004174 + }, + { + "x": 23.64301986105861, + "y": -0.5034058853941081, + "z": 10.06766144850902 + }, + { + "x": 24.13227331085165, + "y": -0.5034058853941077, + "z": 9.819706270547492 + }, + { + "x": 24.621526760644695, + "y": -0.5034058853941077, + "z": 9.49838643413089 + }, + { + "x": 25.11078021043773, + "y": -0.5034058853941064, + "z": 9.17570228995619 + }, + { + "x": 25.600033660230768, + "y": -0.5034058853941077, + "z": 8.867441934127108 + }, + { + "x": 26.089287110023804, + "y": -0.5034058853941059, + "z": 8.604537693878262 + }, + { + "x": 26.578540559816844, + "y": -0.5034058853941064, + "z": 8.297716163627346 + }, + { + "x": 27.06779400960988, + "y": -0.5034058853941077, + "z": 8.05001294511648 + }, + { + "x": 27.557047459402916, + "y": -0.5034058853941081, + "z": 7.703369437119905 + }, + { + "x": 28.046300909195956, + "y": -0.5034058853941064, + "z": 7.373708299094316 + }, + { + "x": 28.535554358989, + "y": -0.5034058853941143, + "z": 7.148125698342916 + }, + { + "x": 29.02480780878203, + "y": -0.5034058853941064, + "z": 6.810170537717964 + }, + { + "x": 15.814964664370011, + "y": 0.31198967722203663, + "z": 14.759555146166456 + }, + { + "x": 16.304218114163046, + "y": 0.3119896772220344, + "z": 14.477297923668802 + }, + { + "x": 16.79347156395609, + "y": 0.3119896772220341, + "z": 14.19089791474647 + }, + { + "x": 17.282725013749126, + "y": 0.3119896772220335, + "z": 13.90018151230331 + }, + { + "x": 17.77197846354216, + "y": 0.31198967722203463, + "z": 13.614715551704377 + }, + { + "x": 18.261231913335198, + "y": 0.31198967722203275, + "z": 13.310379572254957 + }, + { + "x": 18.75048536312824, + "y": 0.31198967722203275, + "z": 13.0134480150102 + }, + { + "x": 19.239738812921278, + "y": 0.3119896772220332, + "z": 12.704891677416187 + }, + { + "x": 19.72899226271431, + "y": 0.3119896772220332, + "z": 12.422446039141503 + }, + { + "x": 20.218245712507347, + "y": 0.31198967722203275, + "z": 12.105688882451803 + }, + { + "x": 20.707499162300383, + "y": 0.31198967722203297, + "z": 11.87832512587864 + }, + { + "x": 21.19675261209343, + "y": 0.31198967722203275, + "z": 11.571615611661153 + }, + { + "x": 21.686006061886467, + "y": 0.3119896772220332, + "z": 11.263093143149264 + }, + { + "x": 22.1752595116795, + "y": 0.3119896772220323, + "z": 10.9552769858133 + }, + { + "x": 22.66451296147254, + "y": 0.31198967722203275, + "z": 10.658787564089033 + }, + { + "x": 23.153766411265583, + "y": 0.31198967722203275, + "z": 10.328318137254156 + }, + { + "x": 23.643019861058615, + "y": 0.3119896772220332, + "z": 10.046796432348081 + }, + { + "x": 24.132273310851655, + "y": 0.31198967722203275, + "z": 9.77911826415137 + }, + { + "x": 24.62152676064469, + "y": 0.3119896772220332, + "z": 9.473967400219617 + }, + { + "x": 25.110780210437735, + "y": 0.31198967722203275, + "z": 9.18508893684785 + }, + { + "x": 25.60003366023077, + "y": 0.31198967722203363, + "z": 8.846857514049331 + }, + { + "x": 26.08928711002381, + "y": 0.3119896772220332, + "z": 8.578373262042662 + }, + { + "x": 26.57854055981685, + "y": 0.31198967722203363, + "z": 8.323434679983526 + }, + { + "x": 27.06779400960988, + "y": 0.31198967722203363, + "z": 8.054692888460423 + }, + { + "x": 27.557047459402924, + "y": 0.31198967722203275, + "z": 7.701934613155445 + }, + { + "x": 28.046300909195956, + "y": 0.3119896772220425, + "z": 7.410265383666147 + }, + { + "x": 28.535554358988996, + "y": 0.3119896772220372, + "z": 7.176948983906217 + }, + { + "x": 29.02480780878203, + "y": 0.31198967722203186, + "z": 6.882221611362295 + }, + { + "x": 15.814964664370006, + "y": 1.12738523983817, + "z": 14.757632491991295 + }, + { + "x": 16.304218114163053, + "y": 1.1273852398381752, + "z": 14.511651374277404 + }, + { + "x": 16.79347156395609, + "y": 1.1273852398381732, + "z": 14.176102338983004 + }, + { + "x": 17.282725013749136, + "y": 1.127385239838178, + "z": 13.84688710283952 + }, + { + "x": 17.771978463542162, + "y": 1.127385239838175, + "z": 13.594048140540615 + }, + { + "x": 18.261231913335195, + "y": 1.1273852398381752, + "z": 13.339731561355341 + }, + { + "x": 18.750485363128238, + "y": 1.1273852398381732, + "z": 13.005977543874177 + }, + { + "x": 19.239738812921274, + "y": 1.127385239838175, + "z": 12.7147777587047 + }, + { + "x": 19.728992262714314, + "y": 1.127385239838173, + "z": 12.419980022318793 + }, + { + "x": 20.21824571250735, + "y": 1.1273852398381754, + "z": 12.158737162916772 + }, + { + "x": 20.707499162300383, + "y": 1.127385239838175, + "z": 11.828201612877562 + }, + { + "x": 21.196752612093427, + "y": 1.1273852398381736, + "z": 11.574568796524218 + }, + { + "x": 21.686006061886467, + "y": 1.1273852398381754, + "z": 11.24497633934759 + }, + { + "x": 22.175259511679506, + "y": 1.127385239838175, + "z": 10.945937024678779 + }, + { + "x": 22.66451296147254, + "y": 1.1273852398381754, + "z": 10.612248624693793 + }, + { + "x": 23.15376641126558, + "y": 1.1273852398381732, + "z": 10.32791017689496 + }, + { + "x": 23.64301986105862, + "y": 1.127385239838175, + "z": 10.113621915513212 + }, + { + "x": 24.13227331085165, + "y": 1.127385239838174, + "z": 9.805314753320722 + }, + { + "x": 24.62152676064469, + "y": 1.1273852398381732, + "z": 9.497456237664535 + }, + { + "x": 25.11078021043773, + "y": 1.1273852398381754, + "z": 9.203315199178032 + }, + { + "x": 25.600033660230764, + "y": 1.1273852398381758, + "z": 8.84320354066008 + }, + { + "x": 26.089287110023804, + "y": 1.1273852398381758, + "z": 8.573154597250658 + }, + { + "x": 26.578540559816844, + "y": 1.127385239838174, + "z": 8.313276243652485 + }, + { + "x": 27.067794009609884, + "y": 1.127385239838174, + "z": 8.040614063859245 + }, + { + "x": 27.557047459402924, + "y": 1.1273852398381736, + "z": 7.722406949772033 + }, + { + "x": 28.046300909195963, + "y": 1.1273852398381754, + "z": 7.392005972399019 + }, + { + "x": 28.535554358988996, + "y": 1.1273852398381727, + "z": 7.098585394579198 + }, + { + "x": 29.024807808782036, + "y": 1.127385239838178, + "z": 6.799245895226374 + }, + { + "x": 15.81496466437001, + "y": 1.9427808024543132, + "z": 14.80174193460909 + }, + { + "x": 16.30421811416305, + "y": 1.9427808024543138, + "z": 14.490386877216487 + }, + { + "x": 16.793471563956082, + "y": 1.9427808024543127, + "z": 14.158731910084924 + }, + { + "x": 17.282725013749126, + "y": 1.9427808024543132, + "z": 13.871238338981907 + }, + { + "x": 17.771978463542162, + "y": 1.9427808024543143, + "z": 13.606521919299034 + }, + { + "x": 18.2612319133352, + "y": 1.9427808024543132, + "z": 13.310620894604826 + }, + { + "x": 18.750485363128234, + "y": 1.9427808024543127, + "z": 12.956468356203048 + }, + { + "x": 19.23973881292127, + "y": 1.9427808024543127, + "z": 12.726306995648873 + }, + { + "x": 19.728992262714314, + "y": 1.9427808024543138, + "z": 12.451402034260195 + }, + { + "x": 20.218245712507347, + "y": 1.9427808024543125, + "z": 12.15955667383713 + }, + { + "x": 20.707499162300387, + "y": 1.9427808024543125, + "z": 11.811989281925174 + }, + { + "x": 21.196752612093427, + "y": 1.9427808024543118, + "z": 11.564086552605179 + }, + { + "x": 21.686006061886467, + "y": 1.942780802454313, + "z": 11.196327572757006 + }, + { + "x": 22.175259511679503, + "y": 1.9427808024543123, + "z": 10.997341096208828 + }, + { + "x": 22.66451296147254, + "y": 1.9427808024543123, + "z": 10.667972565766483 + }, + { + "x": 23.153766411265572, + "y": 1.9427808024543125, + "z": 10.353996880269051 + }, + { + "x": 23.643019861058608, + "y": 1.9427808024543125, + "z": 10.023157422118171 + }, + { + "x": 24.13227331085165, + "y": 1.9427808024543136, + "z": 9.777942534546382 + }, + { + "x": 24.62152676064469, + "y": 1.9427808024543127, + "z": 9.524959688357866 + }, + { + "x": 25.11078021043773, + "y": 1.9427808024543118, + "z": 9.19207074023478 + }, + { + "x": 25.600033660230768, + "y": 1.9427808024543123, + "z": 8.863578048219715 + }, + { + "x": 26.089287110023804, + "y": 1.9427808024543127, + "z": 8.599281073966036 + }, + { + "x": 26.57854055981684, + "y": 1.9427808024543127, + "z": 8.351130703831291 + }, + { + "x": 27.067794009609884, + "y": 1.9427808024543132, + "z": 8.012982750725435 + }, + { + "x": 27.55704745940291, + "y": 1.9427808024543123, + "z": 7.735475196898947 + }, + { + "x": 28.046300909195963, + "y": 1.9427808024543136, + "z": 7.402602995632136 + }, + { + "x": 28.535554358988996, + "y": 1.9427808024543127, + "z": 7.174290441612786 + }, + { + "x": 29.02480780878203, + "y": 1.94278080245431, + "z": 6.802541905843215 + }, + { + "x": 15.814964664370011, + "y": 2.7581763650704434, + "z": 14.746253821548732 + }, + { + "x": 16.30421811416305, + "y": 2.7581763650704545, + "z": 14.48967012605419 + }, + { + "x": 16.793471563956082, + "y": 2.7581763650704527, + "z": 14.184965164004549 + }, + { + "x": 17.282725013749126, + "y": 2.7581763650704536, + "z": 13.868830339085271 + }, + { + "x": 17.771978463542162, + "y": 2.7581763650704527, + "z": 13.614237497726439 + }, + { + "x": 18.2612319133352, + "y": 2.7581763650704536, + "z": 13.28612613960472 + }, + { + "x": 18.750485363128238, + "y": 2.7581763650704545, + "z": 13.02224499487377 + }, + { + "x": 19.23973881292127, + "y": 2.7581763650704536, + "z": 12.745105475887081 + }, + { + "x": 19.728992262714314, + "y": 2.7581763650704527, + "z": 12.421820743623245 + }, + { + "x": 20.218245712507354, + "y": 2.758176365070453, + "z": 12.08508192469367 + }, + { + "x": 20.707499162300387, + "y": 2.7581763650704536, + "z": 11.802468688029823 + }, + { + "x": 21.196752612093427, + "y": 2.758176365070444, + "z": 11.575080415554025 + }, + { + "x": 21.686006061886467, + "y": 2.7581763650704545, + "z": 11.236496799293612 + }, + { + "x": 22.1752595116795, + "y": 2.758176365070453, + "z": 10.939272919869419 + }, + { + "x": 22.66451296147254, + "y": 2.7581763650704536, + "z": 10.636142593465884 + }, + { + "x": 23.15376641126558, + "y": 2.7581763650704545, + "z": 10.32000285251383 + }, + { + "x": 23.64301986105861, + "y": 2.758176365070453, + "z": 10.065566242239909 + }, + { + "x": 24.13227331085165, + "y": 2.7581763650704536, + "z": 9.811913615910338 + }, + { + "x": 24.62152676064469, + "y": 2.758176365070454, + "z": 9.491834717278634 + }, + { + "x": 25.11078021043774, + "y": 2.758176365070451, + "z": 9.137012695315468 + }, + { + "x": 25.60003366023077, + "y": 2.7581763650704527, + "z": 8.902635442355017 + }, + { + "x": 26.089287110023804, + "y": 2.7581763650704536, + "z": 8.563035934260906 + }, + { + "x": 26.578540559816847, + "y": 2.758176365070455, + "z": 8.327516372625166 + }, + { + "x": 27.067794009609884, + "y": 2.7581763650704536, + "z": 7.96082730611636 + }, + { + "x": 27.557047459402913, + "y": 2.7581763650704527, + "z": 7.689712334938489 + }, + { + "x": 28.04630090919596, + "y": 2.7581763650704545, + "z": 7.43548386524837 + }, + { + "x": 28.535554358988996, + "y": 2.758176365070465, + "z": 7.170940217917232 + }, + { + "x": 29.02480780878203, + "y": 2.7581763650704536, + "z": 6.820524871745632 + }, + { + "x": 15.81496466437001, + "y": 3.5735719276865936, + "z": 14.787134864309008 + }, + { + "x": 16.30421811416305, + "y": 3.573571927686593, + "z": 14.499931010289924 + }, + { + "x": 16.793471563956082, + "y": 3.5735719276865936, + "z": 14.196248153020017 + }, + { + "x": 17.282725013749126, + "y": 3.5735719276865945, + "z": 13.870707094610573 + }, + { + "x": 17.771978463542165, + "y": 3.5735719276865945, + "z": 13.609421783942334 + }, + { + "x": 18.2612319133352, + "y": 3.5735719276865945, + "z": 13.333320941316753 + }, + { + "x": 18.750485363128234, + "y": 3.5735719276865936, + "z": 12.989262344878295 + }, + { + "x": 19.239738812921274, + "y": 3.5735719276865936, + "z": 12.67724423899078 + }, + { + "x": 19.728992262714314, + "y": 3.5735719276865945, + "z": 12.396407000623975 + }, + { + "x": 20.21824571250735, + "y": 3.5735719276865954, + "z": 12.171277593637921 + }, + { + "x": 20.707499162300383, + "y": 3.5735719276865936, + "z": 11.784270865683379 + }, + { + "x": 21.196752612093427, + "y": 3.5735719276865945, + "z": 11.550926403963546 + }, + { + "x": 21.68600606188647, + "y": 3.5735719276865954, + "z": 11.222124232152941 + }, + { + "x": 22.175259511679503, + "y": 3.5735719276865936, + "z": 10.976198380703906 + }, + { + "x": 22.66451296147254, + "y": 3.5735719276865945, + "z": 10.691810587476926 + }, + { + "x": 23.15376641126558, + "y": 3.573571927686594, + "z": 10.40401310826224 + }, + { + "x": 23.64301986105861, + "y": 3.5735719276865945, + "z": 10.047714617360924 + }, + { + "x": 24.13227331085165, + "y": 3.5735719276865954, + "z": 9.72842320365483 + }, + { + "x": 24.62152676064469, + "y": 3.5735719276865936, + "z": 9.44042103179877 + }, + { + "x": 25.11078021043773, + "y": 3.5735719276865936, + "z": 9.215455379214523 + }, + { + "x": 25.60003366023077, + "y": 3.5735719276865954, + "z": 8.860591891370994 + }, + { + "x": 26.089287110023804, + "y": 3.5735719276865945, + "z": 8.634884422194931 + }, + { + "x": 26.578540559816844, + "y": 3.5735719276865945, + "z": 8.257476239369613 + }, + { + "x": 27.06779400960988, + "y": 3.5735719276865945, + "z": 8.039924471879315 + }, + { + "x": 27.557047459402916, + "y": 3.5735719276865954, + "z": 7.73343432925084 + }, + { + "x": 28.046300909195956, + "y": 3.5735719276865936, + "z": 7.4662469572012675 + }, + { + "x": 28.535554358988996, + "y": 3.5735719276866, + "z": 7.135178834398765 + }, + { + "x": 29.024807808782032, + "y": 3.5735719276865954, + "z": 6.801281898390408 + }, + { + "x": 15.81496466437001, + "y": 4.388967490302735, + "z": 14.81003244435284 + }, + { + "x": 16.30421811416305, + "y": 4.388967490302735, + "z": 14.478319708818626 + }, + { + "x": 16.793471563956086, + "y": 4.3889674903027345, + "z": 14.139603015083841 + }, + { + "x": 17.282725013749122, + "y": 4.3889674903027345, + "z": 13.845541803421746 + }, + { + "x": 17.771978463542162, + "y": 4.3889674903027345, + "z": 13.588277252637786 + }, + { + "x": 18.261231913335195, + "y": 4.3889674903027345, + "z": 13.281114614085055 + }, + { + "x": 18.750485363128234, + "y": 4.3889674903027345, + "z": 12.967179782356226 + }, + { + "x": 19.239738812921274, + "y": 4.3889674903027345, + "z": 12.737402064118099 + }, + { + "x": 19.728992262714314, + "y": 4.388967490302734, + "z": 12.410649262465046 + }, + { + "x": 20.21824571250735, + "y": 4.388967490302736, + "z": 12.159880244217268 + }, + { + "x": 20.707499162300387, + "y": 4.3889674903027345, + "z": 11.800080442416329 + }, + { + "x": 21.196752612093423, + "y": 4.3889674903027345, + "z": 11.543900828788118 + }, + { + "x": 21.686006061886467, + "y": 4.3889674903027345, + "z": 11.197038705808998 + }, + { + "x": 22.1752595116795, + "y": 4.3889674903027345, + "z": 10.91222964529961 + }, + { + "x": 22.66451296147254, + "y": 4.388967490302735, + "z": 10.683230302720979 + }, + { + "x": 23.15376641126558, + "y": 4.3889674903027345, + "z": 10.360226259439731 + }, + { + "x": 23.643019861058615, + "y": 4.388967490302735, + "z": 10.099883521071321 + }, + { + "x": 24.13227331085165, + "y": 4.3889674903027345, + "z": 9.81945224416607 + }, + { + "x": 24.62152676064469, + "y": 4.3889674903027345, + "z": 9.499735554020136 + }, + { + "x": 25.11078021043773, + "y": 4.3889674903027345, + "z": 9.217587312515338 + }, + { + "x": 25.60003366023077, + "y": 4.388967490302736, + "z": 8.868678757654825 + }, + { + "x": 26.089287110023804, + "y": 4.3889674903027345, + "z": 8.627259835240395 + }, + { + "x": 26.578540559816844, + "y": 4.3889674903027345, + "z": 8.323172419639524 + }, + { + "x": 27.06779400960988, + "y": 4.3889674903027345, + "z": 7.97765202217437 + }, + { + "x": 27.557047459402916, + "y": 4.3889674903027345, + "z": 7.717728884346933 + }, + { + "x": 28.04630090919596, + "y": 4.3889674903027345, + "z": 7.384454049606657 + }, + { + "x": 28.535554358988996, + "y": 4.388967490302735, + "z": 7.095205351285206 + }, + { + "x": 29.024807808782032, + "y": 4.388967490302735, + "z": 6.870314453216656 + }, + { + "x": 15.814964664370011, + "y": 5.204363052918876, + "z": 14.790333461844126 + }, + { + "x": 16.30421811416305, + "y": 5.2043630529188745, + "z": 14.510505532071141 + }, + { + "x": 16.79347156395609, + "y": 5.204363052918876, + "z": 14.197757776296791 + }, + { + "x": 17.282725013749126, + "y": 5.204363052918876, + "z": 13.909962997684744 + }, + { + "x": 17.771978463542162, + "y": 5.204363052918875, + "z": 13.571233437868283 + }, + { + "x": 18.261231913335198, + "y": 5.204363052918874, + "z": 13.267374937444808 + }, + { + "x": 18.750485363128238, + "y": 5.204363052918876, + "z": 12.976420965416095 + }, + { + "x": 19.239738812921274, + "y": 5.204363052918877, + "z": 12.733599622590123 + }, + { + "x": 19.728992262714314, + "y": 5.204363052918877, + "z": 12.453490069345472 + }, + { + "x": 20.21824571250735, + "y": 5.204363052918874, + "z": 12.16684771305965 + }, + { + "x": 20.707499162300383, + "y": 5.204363052918875, + "z": 11.797070962130402 + }, + { + "x": 21.196752612093427, + "y": 5.204363052918874, + "z": 11.581734588879144 + }, + { + "x": 21.686006061886467, + "y": 5.2043630529188745, + "z": 11.25604672916556 + }, + { + "x": 22.175259511679506, + "y": 5.204363052918876, + "z": 10.907739814183328 + }, + { + "x": 22.664512961472536, + "y": 5.204363052918875, + "z": 10.652998296628317 + }, + { + "x": 23.15376641126558, + "y": 5.204363052918876, + "z": 10.353771983981398 + }, + { + "x": 23.64301986105862, + "y": 5.204363052918876, + "z": 10.10058353208286 + }, + { + "x": 24.13227331085165, + "y": 5.204363052918876, + "z": 9.775064133861639 + }, + { + "x": 24.62152676064469, + "y": 5.204363052918874, + "z": 9.503263764263128 + }, + { + "x": 25.11078021043773, + "y": 5.204363052918877, + "z": 9.139512496935616 + }, + { + "x": 25.600033660230764, + "y": 5.204363052918877, + "z": 8.849107530344801 + }, + { + "x": 26.089287110023804, + "y": 5.204363052918875, + "z": 8.60100655080735 + }, + { + "x": 26.578540559816844, + "y": 5.204363052918876, + "z": 8.350100681692084 + }, + { + "x": 27.067794009609877, + "y": 5.204363052918875, + "z": 8.03034497597548 + }, + { + "x": 27.557047459402916, + "y": 5.204363052918876, + "z": 7.689177454078461 + }, + { + "x": 28.046300909195963, + "y": 5.204363052918876, + "z": 7.446560732787375 + }, + { + "x": 28.535554358988996, + "y": 5.204363052918874, + "z": 7.167875511646153 + }, + { + "x": 29.02480780878203, + "y": 5.204363052918879, + "z": 6.8008366202150246 + }, + { + "x": 15.814964664370011, + "y": 6.019758615535015, + "z": 14.803025980102912 + }, + { + "x": 16.30421811416305, + "y": 6.0197586155350145, + "z": 14.516132843839904 + }, + { + "x": 16.79347156395609, + "y": 6.0197586155350145, + "z": 14.188297930011869 + }, + { + "x": 17.282725013749126, + "y": 6.019758615535015, + "z": 13.8706113739748 + }, + { + "x": 17.771978463542162, + "y": 6.0197586155350145, + "z": 13.559000593750149 + }, + { + "x": 18.261231913335195, + "y": 6.019758615535014, + "z": 13.276259820096492 + }, + { + "x": 18.750485363128238, + "y": 6.0197586155350145, + "z": 12.956277773052125 + }, + { + "x": 19.239738812921274, + "y": 6.019758615535014, + "z": 12.715656061178686 + }, + { + "x": 19.728992262714314, + "y": 6.0197586155350145, + "z": 12.383937958711867 + }, + { + "x": 20.21824571250735, + "y": 6.0197586155350145, + "z": 12.1182360955296 + }, + { + "x": 20.707499162300387, + "y": 6.0197586155350145, + "z": 11.807089201724475 + }, + { + "x": 21.196752612093427, + "y": 6.0197586155350145, + "z": 11.57038873917545 + }, + { + "x": 21.686006061886467, + "y": 6.0197586155350145, + "z": 11.282836810701392 + }, + { + "x": 22.175259511679506, + "y": 6.0197586155350145, + "z": 10.902961970955355 + }, + { + "x": 22.66451296147254, + "y": 6.0197586155350145, + "z": 10.666370640925381 + }, + { + "x": 23.15376641126558, + "y": 6.0197586155350145, + "z": 10.398973418849415 + }, + { + "x": 23.64301986105861, + "y": 6.0197586155350145, + "z": 10.09462205288004 + }, + { + "x": 24.13227331085165, + "y": 6.0197586155350145, + "z": 9.796544895991978 + }, + { + "x": 24.62152676064469, + "y": 6.019758615535018, + "z": 9.44638767420739 + }, + { + "x": 25.11078021043773, + "y": 6.019758615535016, + "z": 9.152089194335725 + }, + { + "x": 25.600033660230768, + "y": 6.019758615535013, + "z": 8.871714949482927 + }, + { + "x": 26.089287110023804, + "y": 6.0197586155350145, + "z": 8.573157006535595 + }, + { + "x": 26.578540559816844, + "y": 6.019758615535014, + "z": 8.2871282209756 + }, + { + "x": 27.06779400960988, + "y": 6.019758615535014, + "z": 8.059027641376002 + }, + { + "x": 27.557047459402916, + "y": 6.0197586155350145, + "z": 7.703856336240866 + }, + { + "x": 28.046300909195956, + "y": 6.019758615535013, + "z": 7.384662065253542 + }, + { + "x": 28.535554358989, + "y": 6.01975861553503, + "z": 7.156479293782426 + }, + { + "x": 29.02480780878203, + "y": 6.0197586155350145, + "z": 6.807390922139357 + }, + { + "x": 15.814964664370011, + "y": 6.835154178151153, + "z": 14.808283541302865 + }, + { + "x": 16.304218114163046, + "y": 6.835154178151154, + "z": 14.521594651251748 + }, + { + "x": 16.793471563956086, + "y": 6.835154178151152, + "z": 14.18127055454334 + }, + { + "x": 17.282725013749126, + "y": 6.835154178151152, + "z": 13.891460876024583 + }, + { + "x": 17.771978463542165, + "y": 6.835154178151153, + "z": 13.572590756748951 + }, + { + "x": 18.2612319133352, + "y": 6.835154178151154, + "z": 13.25497883615799 + }, + { + "x": 18.750485363128234, + "y": 6.835154178151153, + "z": 13.039782813265361 + }, + { + "x": 19.239738812921274, + "y": 6.835154178151155, + "z": 12.752869556290344 + }, + { + "x": 19.72899226271431, + "y": 6.835154178151153, + "z": 12.400365273839174 + }, + { + "x": 20.21824571250735, + "y": 6.835154178151155, + "z": 12.154578238953615 + }, + { + "x": 20.707499162300387, + "y": 6.835154178151155, + "z": 11.857155805933635 + }, + { + "x": 21.196752612093427, + "y": 6.835154178151155, + "z": 11.520511879880328 + }, + { + "x": 21.686006061886467, + "y": 6.835154178151152, + "z": 11.198490171949079 + }, + { + "x": 22.175259511679506, + "y": 6.835154178151154, + "z": 10.990673526274131 + }, + { + "x": 22.66451296147254, + "y": 6.835154178151155, + "z": 10.629468476100651 + }, + { + "x": 23.15376641126558, + "y": 6.835154178151153, + "z": 10.348285047391002 + }, + { + "x": 23.643019861058615, + "y": 6.835154178151152, + "z": 10.040215702981529 + }, + { + "x": 24.13227331085165, + "y": 6.8351541781511544, + "z": 9.811418955938661 + }, + { + "x": 24.62152676064469, + "y": 6.835154178151152, + "z": 9.44152277709183 + }, + { + "x": 25.11078021043773, + "y": 6.835154178151154, + "z": 9.137295810253669 + }, + { + "x": 25.600033660230764, + "y": 6.835154178151154, + "z": 8.93208932075282 + }, + { + "x": 26.089287110023804, + "y": 6.835154178151155, + "z": 8.554883833720138 + }, + { + "x": 26.578540559816844, + "y": 6.835154178151153, + "z": 8.345782653979532 + }, + { + "x": 27.06779400960988, + "y": 6.835154178151152, + "z": 8.008995448977194 + }, + { + "x": 27.557047459402913, + "y": 6.835154178151154, + "z": 7.722839109477322 + }, + { + "x": 28.04630090919596, + "y": 6.835154178151153, + "z": 7.444755528214378 + }, + { + "x": 28.535554358989, + "y": 6.835154178151154, + "z": 7.16439404164267 + }, + { + "x": 29.024807808782032, + "y": 6.835154178151154, + "z": 6.847932984669901 + }, + { + "x": 15.81496466437001, + "y": 7.650549740767298, + "z": 14.776883313788122 + }, + { + "x": 16.30421811416305, + "y": 7.650549740767294, + "z": 14.483452139566305 + }, + { + "x": 16.793471563956086, + "y": 7.650549740767295, + "z": 14.227240048670994 + }, + { + "x": 17.282725013749122, + "y": 7.6505497407673, + "z": 13.84112669944028 + }, + { + "x": 17.771978463542165, + "y": 7.650549740767297, + "z": 13.59287185726436 + }, + { + "x": 18.261231913335198, + "y": 7.650549740767295, + "z": 13.32828134186969 + }, + { + "x": 18.750485363128238, + "y": 7.650549740767295, + "z": 13.016581690653972 + }, + { + "x": 19.239738812921274, + "y": 7.650549740767294, + "z": 12.677855638244896 + }, + { + "x": 19.728992262714314, + "y": 7.650549740767295, + "z": 12.458781031777654 + }, + { + "x": 20.218245712507354, + "y": 7.650549740767296, + "z": 12.143746976497905 + }, + { + "x": 20.707499162300387, + "y": 7.650549740767296, + "z": 11.832219793231138 + }, + { + "x": 21.196752612093427, + "y": 7.650549740767297, + "z": 11.568582945354663 + }, + { + "x": 21.686006061886467, + "y": 7.650549740767296, + "z": 11.210207288507872 + }, + { + "x": 22.1752595116795, + "y": 7.650549740767296, + "z": 10.966832375459537 + }, + { + "x": 22.66451296147254, + "y": 7.650549740767295, + "z": 10.658242595841365 + }, + { + "x": 23.15376641126558, + "y": 7.650549740767296, + "z": 10.40598142476416 + }, + { + "x": 23.64301986105862, + "y": 7.650549740767294, + "z": 10.111629860902703 + }, + { + "x": 24.13227331085165, + "y": 7.650549740767296, + "z": 9.804419725178048 + }, + { + "x": 24.62152676064469, + "y": 7.650549740767296, + "z": 9.438446113244247 + }, + { + "x": 25.11078021043773, + "y": 7.650549740767296, + "z": 9.172191674073025 + }, + { + "x": 25.600033660230768, + "y": 7.650549740767295, + "z": 8.941141941305789 + }, + { + "x": 26.089287110023804, + "y": 7.650549740767296, + "z": 8.642599744462066 + }, + { + "x": 26.578540559816844, + "y": 7.650549740767299, + "z": 8.32887166927856 + }, + { + "x": 27.067794009609877, + "y": 7.650549740767296, + "z": 8.008800271192916 + }, + { + "x": 27.557047459402924, + "y": 7.650549740767289, + "z": 7.765805339059042 + }, + { + "x": 28.046300909195956, + "y": 7.650549740767298, + "z": 7.448152694432708 + }, + { + "x": 28.535554358988996, + "y": 7.650549740767303, + "z": 7.110573972297109 + }, + { + "x": 29.024807808782025, + "y": 7.650549740767296, + "z": 6.871463718685315 + }, + { + "x": 15.81496466437001, + "y": 8.465945303383437, + "z": 14.723690688196033 + }, + { + "x": 16.30421811416305, + "y": 8.465945303383437, + "z": 14.426456956496583 + }, + { + "x": 16.79347156395609, + "y": 8.465945303383437, + "z": 14.129106777484322 + }, + { + "x": 17.282725013749126, + "y": 8.465945303383437, + "z": 13.894623399478247 + }, + { + "x": 17.771978463542162, + "y": 8.465945303383439, + "z": 13.563676125465616 + }, + { + "x": 18.261231913335198, + "y": 8.465945303383439, + "z": 13.271244319552377 + }, + { + "x": 18.750485363128238, + "y": 8.465945303383439, + "z": 12.98519541328038 + }, + { + "x": 19.239738812921274, + "y": 8.465945303383435, + "z": 12.732425465057647 + }, + { + "x": 19.728992262714314, + "y": 8.465945303383435, + "z": 12.449153681074016 + }, + { + "x": 20.218245712507347, + "y": 8.465945303383435, + "z": 12.144147757291371 + }, + { + "x": 20.707499162300387, + "y": 8.465945303383439, + "z": 11.862061833420608 + }, + { + "x": 21.196752612093427, + "y": 8.465945303383435, + "z": 11.510933800890653 + }, + { + "x": 21.686006061886467, + "y": 8.465945303383435, + "z": 11.221119966438033 + }, + { + "x": 22.1752595116795, + "y": 8.465945303383439, + "z": 10.90494412868026 + }, + { + "x": 22.66451296147254, + "y": 8.465945303383439, + "z": 10.649138466444471 + }, + { + "x": 23.15376641126558, + "y": 8.465945303383435, + "z": 10.362406337321367 + }, + { + "x": 23.643019861058615, + "y": 8.465945303383435, + "z": 10.051439933551885 + }, + { + "x": 24.13227331085165, + "y": 8.465945303383439, + "z": 9.751483762588155 + }, + { + "x": 24.62152676064469, + "y": 8.465945303383435, + "z": 9.5119356126034 + }, + { + "x": 25.11078021043773, + "y": 8.465945303383435, + "z": 9.156407196157508 + }, + { + "x": 25.600033660230764, + "y": 8.465945303383435, + "z": 8.894094648749618 + }, + { + "x": 26.089287110023804, + "y": 8.465945303383439, + "z": 8.643557800092838 + }, + { + "x": 26.578540559816844, + "y": 8.465945303383439, + "z": 8.307425318958577 + }, + { + "x": 27.067794009609884, + "y": 8.465945303383439, + "z": 8.034782275189984 + }, + { + "x": 27.557047459402916, + "y": 8.465945303383437, + "z": 7.728975465867468 + }, + { + "x": 28.04630090919596, + "y": 8.465945303383437, + "z": 7.421171578473598 + }, + { + "x": 28.535554358988993, + "y": 8.46594530338345, + "z": 7.142063414274686 + }, + { + "x": 29.024807808782036, + "y": 8.465945303383439, + "z": 6.852347580428636 + }, + { + "x": 15.814964664370011, + "y": 9.281340865999567, + "z": 14.80245916121156 + }, + { + "x": 16.30421811416305, + "y": 9.281340865999574, + "z": 14.472621628408517 + }, + { + "x": 16.793471563956086, + "y": 9.281340865999578, + "z": 14.135806371318294 + }, + { + "x": 17.282725013749122, + "y": 9.281340865999578, + "z": 13.91150733377533 + }, + { + "x": 17.771978463542162, + "y": 9.281340865999574, + "z": 13.59079870052288 + }, + { + "x": 18.2612319133352, + "y": 9.281340865999578, + "z": 13.324512462925581 + }, + { + "x": 18.75048536312824, + "y": 9.281340865999576, + "z": 12.963374120827014 + }, + { + "x": 19.239738812921274, + "y": 9.281340865999578, + "z": 12.74783640606585 + }, + { + "x": 19.728992262714314, + "y": 9.281340865999576, + "z": 12.436455689804983 + }, + { + "x": 20.21824571250735, + "y": 9.281340865999578, + "z": 12.165715044550904 + }, + { + "x": 20.707499162300387, + "y": 9.281340865999574, + "z": 11.839328630693684 + }, + { + "x": 21.196752612093427, + "y": 9.281340865999574, + "z": 11.579687939766755 + }, + { + "x": 21.686006061886467, + "y": 9.281340865999578, + "z": 11.228665092997039 + }, + { + "x": 22.1752595116795, + "y": 9.281340865999576, + "z": 10.979148421608222 + }, + { + "x": 22.66451296147254, + "y": 9.281340865999574, + "z": 10.61646219452127 + }, + { + "x": 23.15376641126558, + "y": 9.281340865999576, + "z": 10.333419714449075 + }, + { + "x": 23.64301986105861, + "y": 9.281340865999576, + "z": 10.114598662601805 + }, + { + "x": 24.13227331085165, + "y": 9.281340865999578, + "z": 9.80605624320458 + }, + { + "x": 24.621526760644684, + "y": 9.281340865999578, + "z": 9.435918798492596 + }, + { + "x": 25.110780210437735, + "y": 9.281340865999578, + "z": 9.227348063489757 + }, + { + "x": 25.60003366023077, + "y": 9.281340865999576, + "z": 8.890914688888438 + }, + { + "x": 26.0892871100238, + "y": 9.281340865999576, + "z": 8.570221902834662 + }, + { + "x": 26.578540559816844, + "y": 9.281340865999578, + "z": 8.267420068525116 + }, + { + "x": 27.067794009609884, + "y": 9.281340865999578, + "z": 8.0306844673616 + }, + { + "x": 27.557047459402916, + "y": 9.281340865999576, + "z": 7.758883132726639 + }, + { + "x": 28.04630090919596, + "y": 9.281340865999576, + "z": 7.38313598704355 + }, + { + "x": 28.535554358988996, + "y": 9.281340865999578, + "z": 7.112641440846267 + }, + { + "x": 29.024807808782032, + "y": 9.281340865999576, + "z": 6.798196899205778 + }, + { + "x": 15.814964664370017, + "y": 10.09673642861572, + "z": 14.76691032846182 + }, + { + "x": 16.30421811416305, + "y": 10.096736428615714, + "z": 14.448506353224769 + }, + { + "x": 16.793471563956086, + "y": 10.096736428615717, + "z": 14.22613294454784 + }, + { + "x": 17.282725013749133, + "y": 10.096736428615726, + "z": 13.90929271793569 + }, + { + "x": 17.771978463542165, + "y": 10.096736428615717, + "z": 13.60227223622799 + }, + { + "x": 18.261231913335195, + "y": 10.096736428615717, + "z": 13.312242323808661 + }, + { + "x": 18.750485363128238, + "y": 10.096736428615717, + "z": 13.039175474624237 + }, + { + "x": 19.239738812921274, + "y": 10.096736428615719, + "z": 12.692044383450275 + }, + { + "x": 19.728992262714314, + "y": 10.096736428615714, + "z": 12.430156876764471 + }, + { + "x": 20.218245712507347, + "y": 10.096736428615717, + "z": 12.078673150443297 + }, + { + "x": 20.707499162300383, + "y": 10.096736428615715, + "z": 11.854556911172413 + }, + { + "x": 21.196752612093427, + "y": 10.096736428615717, + "z": 11.53733247432372 + }, + { + "x": 21.686006061886467, + "y": 10.096736428615717, + "z": 11.28859813867112 + }, + { + "x": 22.1752595116795, + "y": 10.096736428615719, + "z": 10.954633351203126 + }, + { + "x": 22.664512961472536, + "y": 10.096736428615717, + "z": 10.68558509834751 + }, + { + "x": 23.15376641126558, + "y": 10.096736428615717, + "z": 10.351662499838724 + }, + { + "x": 23.64301986105861, + "y": 10.096736428615719, + "z": 10.084395902738832 + }, + { + "x": 24.13227331085165, + "y": 10.096736428615717, + "z": 9.81079160368763 + }, + { + "x": 24.62152676064469, + "y": 10.096736428615715, + "z": 9.512589194018078 + }, + { + "x": 25.11078021043773, + "y": 10.096736428615714, + "z": 9.206096478005625 + }, + { + "x": 25.600033660230764, + "y": 10.096736428615717, + "z": 8.924549016442414 + }, + { + "x": 26.089287110023804, + "y": 10.096736428615717, + "z": 8.57776217538697 + }, + { + "x": 26.578540559816844, + "y": 10.096736428615717, + "z": 8.33024334347227 + }, + { + "x": 27.06779400960988, + "y": 10.096736428615717, + "z": 8.039282113553599 + }, + { + "x": 27.557047459402916, + "y": 10.096736428615719, + "z": 7.707918830878339 + }, + { + "x": 28.046300909195963, + "y": 10.096736428615719, + "z": 7.443684561688874 + }, + { + "x": 28.535554358988996, + "y": 10.096736428615712, + "z": 7.09670526245077 + }, + { + "x": 29.02480780878203, + "y": 10.096736428615715, + "z": 6.850301269479479 + }, + { + "x": 15.814964664370013, + "y": 10.912131991231865, + "z": 14.75308025080722 + }, + { + "x": 16.30421811416305, + "y": 10.91213199123186, + "z": 14.459303754887127 + }, + { + "x": 16.793471563956086, + "y": 10.912131991231856, + "z": 14.213109211985746 + }, + { + "x": 17.282725013749126, + "y": 10.912131991231856, + "z": 13.874450884423 + }, + { + "x": 17.771978463542162, + "y": 10.912131991231856, + "z": 13.58496235302961 + }, + { + "x": 18.261231913335195, + "y": 10.912131991231853, + "z": 13.344571712578157 + }, + { + "x": 18.750485363128238, + "y": 10.912131991231856, + "z": 12.990135248382181 + }, + { + "x": 19.239738812921274, + "y": 10.912131991231856, + "z": 12.703461667364985 + }, + { + "x": 19.728992262714318, + "y": 10.912131991231856, + "z": 12.46139759079446 + }, + { + "x": 20.218245712507347, + "y": 10.91213199123186, + "z": 12.158154563556005 + }, + { + "x": 20.707499162300387, + "y": 10.912131991231856, + "z": 11.811837514343406 + }, + { + "x": 21.196752612093427, + "y": 10.912131991231856, + "z": 11.557147739999639 + }, + { + "x": 21.686006061886467, + "y": 10.912131991231853, + "z": 11.287001077801863 + }, + { + "x": 22.175259511679506, + "y": 10.912131991231856, + "z": 10.977749101895498 + }, + { + "x": 22.66451296147254, + "y": 10.912131991231858, + "z": 10.662897288515724 + }, + { + "x": 23.15376641126558, + "y": 10.912131991231856, + "z": 10.401863122996252 + }, + { + "x": 23.643019861058615, + "y": 10.912131991231856, + "z": 10.023740102876529 + }, + { + "x": 24.13227331085165, + "y": 10.912131991231856, + "z": 9.77713025501986 + }, + { + "x": 24.62152676064469, + "y": 10.912131991231856, + "z": 9.523597015676241 + }, + { + "x": 25.11078021043773, + "y": 10.912131991231856, + "z": 9.227431588549543 + }, + { + "x": 25.600033660230768, + "y": 10.912131991231856, + "z": 8.882090215358001 + }, + { + "x": 26.089287110023804, + "y": 10.912131991231856, + "z": 8.619514139563856 + }, + { + "x": 26.578540559816844, + "y": 10.912131991231856, + "z": 8.256348295506857 + }, + { + "x": 27.06779400960988, + "y": 10.912131991231858, + "z": 7.964454419929721 + }, + { + "x": 27.557047459402916, + "y": 10.912131991231854, + "z": 7.693212843922807 + }, + { + "x": 28.046300909195956, + "y": 10.912131991231853, + "z": 7.4355141737445924 + }, + { + "x": 28.535554358988996, + "y": 10.912131991231847, + "z": 7.108920253673937 + }, + { + "x": 29.024807808782032, + "y": 10.912131991231856, + "z": 6.807212164177432 + }, + { + "x": 15.81496466437001, + "y": 11.727527553848002, + "z": 14.766141700676318 + }, + { + "x": 16.304218114163056, + "y": 11.727527553847992, + "z": 14.441032681924675 + }, + { + "x": 16.793471563956086, + "y": 11.727527553847992, + "z": 14.161858897994414 + }, + { + "x": 17.282725013749126, + "y": 11.727527553847994, + "z": 13.925375845482785 + }, + { + "x": 17.771978463542162, + "y": 11.727527553847994, + "z": 13.588628392308188 + }, + { + "x": 18.261231913335198, + "y": 11.727527553847997, + "z": 13.268268696101678 + }, + { + "x": 18.75048536312824, + "y": 11.727527553847997, + "z": 13.048173303421208 + }, + { + "x": 19.239738812921274, + "y": 11.727527553847995, + "z": 12.686365452662123 + }, + { + "x": 19.728992262714314, + "y": 11.727527553847992, + "z": 12.387379429248943 + }, + { + "x": 20.21824571250735, + "y": 11.727527553847992, + "z": 12.108224677547426 + }, + { + "x": 20.70749916230039, + "y": 11.727527553847995, + "z": 11.786791932098746 + }, + { + "x": 21.196752612093427, + "y": 11.727527553847995, + "z": 11.584751396904226 + }, + { + "x": 21.686006061886467, + "y": 11.727527553847995, + "z": 11.211526233638823 + }, + { + "x": 22.175259511679506, + "y": 11.727527553847997, + "z": 10.935454721807025 + }, + { + "x": 22.66451296147254, + "y": 11.727527553847995, + "z": 10.649899359875386 + }, + { + "x": 23.15376641126558, + "y": 11.727527553847994, + "z": 10.392178950020568 + }, + { + "x": 23.64301986105862, + "y": 11.727527553847995, + "z": 10.071194860188585 + }, + { + "x": 24.132273310851655, + "y": 11.727527553847997, + "z": 9.733985384869424 + }, + { + "x": 24.62152676064469, + "y": 11.727527553847995, + "z": 9.503942491061368 + }, + { + "x": 25.11078021043773, + "y": 11.727527553847995, + "z": 9.137950165411143 + }, + { + "x": 25.600033660230764, + "y": 11.727527553847994, + "z": 8.912318297742091 + }, + { + "x": 26.0892871100238, + "y": 11.727527553847995, + "z": 8.632136791353487 + }, + { + "x": 26.578540559816844, + "y": 11.727527553847995, + "z": 8.325601741561153 + }, + { + "x": 27.067794009609877, + "y": 11.727527553847995, + "z": 8.04715146674919 + }, + { + "x": 27.557047459402916, + "y": 11.727527553847995, + "z": 7.742753596909971 + }, + { + "x": 28.046300909195953, + "y": 11.727527553847986, + "z": 7.398242884805183 + }, + { + "x": 28.535554358988996, + "y": 11.727527553847992, + "z": 7.1034834250320475 + }, + { + "x": 29.024807808782036, + "y": 11.727527553847995, + "z": 6.85163012234594 + }, + { + "x": 15.81496466437001, + "y": 12.542923116464127, + "z": 14.750834150304085 + }, + { + "x": 16.30421811416305, + "y": 12.542923116464134, + "z": 14.502836642986459 + }, + { + "x": 16.793471563956086, + "y": 12.542923116464138, + "z": 14.141723051437253 + }, + { + "x": 17.282725013749126, + "y": 12.542923116464136, + "z": 13.916236350228695 + }, + { + "x": 17.771978463542162, + "y": 12.542923116464134, + "z": 13.608742789854515 + }, + { + "x": 18.261231913335198, + "y": 12.542923116464133, + "z": 13.262317575161669 + }, + { + "x": 18.750485363128238, + "y": 12.542923116464134, + "z": 13.046529137466823 + }, + { + "x": 19.239738812921274, + "y": 12.542923116464138, + "z": 12.735877239654556 + }, + { + "x": 19.728992262714314, + "y": 12.542923116464138, + "z": 12.418111156352985 + }, + { + "x": 20.218245712507354, + "y": 12.542923116464136, + "z": 12.114580319658634 + }, + { + "x": 20.707499162300387, + "y": 12.542923116464134, + "z": 11.802941158496091 + }, + { + "x": 21.196752612093427, + "y": 12.542923116464134, + "z": 11.559457352511439 + }, + { + "x": 21.686006061886467, + "y": 12.542923116464138, + "z": 11.276603929292163 + }, + { + "x": 22.1752595116795, + "y": 12.542923116464138, + "z": 10.929863126678105 + }, + { + "x": 22.66451296147254, + "y": 12.542923116464138, + "z": 10.67411814457843 + }, + { + "x": 23.15376641126558, + "y": 12.542923116464133, + "z": 10.381453036166846 + }, + { + "x": 23.64301986105861, + "y": 12.542923116464141, + "z": 10.06257909376548 + }, + { + "x": 24.132273310851648, + "y": 12.542923116464124, + "z": 9.817389549623005 + }, + { + "x": 24.62152676064469, + "y": 12.542923116464134, + "z": 9.50075244576833 + }, + { + "x": 25.110780210437735, + "y": 12.542923116464138, + "z": 9.137785744415204 + }, + { + "x": 25.600033660230764, + "y": 12.542923116464138, + "z": 8.867068190559323 + }, + { + "x": 26.0892871100238, + "y": 12.542923116464136, + "z": 8.567925916363759 + }, + { + "x": 26.578540559816837, + "y": 12.542923116464127, + "z": 8.303319290625225 + }, + { + "x": 27.067794009609877, + "y": 12.542923116464138, + "z": 7.975590349944093 + }, + { + "x": 27.557047459402913, + "y": 12.542923116464134, + "z": 7.75423773358056 + }, + { + "x": 28.046300909195956, + "y": 12.542923116464122, + "z": 7.399939299166748 + }, + { + "x": 28.535554358988993, + "y": 12.542923116464133, + "z": 7.1301662373459145 + }, + { + "x": 29.02480780878203, + "y": 12.542923116464133, + "z": 6.852068920425415 + }, + { + "x": 15.81496466437001, + "y": 13.358318679080282, + "z": 14.763309631287342 + }, + { + "x": 16.304218114163053, + "y": 13.35831867908028, + "z": 14.468889282175661 + }, + { + "x": 16.793471563956082, + "y": 13.358318679080288, + "z": 14.143107259509879 + }, + { + "x": 17.28272501374913, + "y": 13.35831867908028, + "z": 13.857173678446681 + }, + { + "x": 17.771978463542165, + "y": 13.358318679080279, + "z": 13.637876602019931 + }, + { + "x": 18.2612319133352, + "y": 13.358318679080277, + "z": 13.275937672032187 + }, + { + "x": 18.750485363128234, + "y": 13.358318679080265, + "z": 13.044740473136194 + }, + { + "x": 19.239738812921274, + "y": 13.358318679080277, + "z": 12.70005511704726 + }, + { + "x": 19.728992262714314, + "y": 13.358318679080277, + "z": 12.388317116901566 + }, + { + "x": 20.218245712507354, + "y": 13.358318679080279, + "z": 12.098674232668065 + }, + { + "x": 20.707499162300387, + "y": 13.358318679080279, + "z": 11.810430417854349 + }, + { + "x": 21.196752612093427, + "y": 13.358318679080275, + "z": 11.489933629288416 + }, + { + "x": 21.686006061886467, + "y": 13.358318679080279, + "z": 11.23595371515808 + }, + { + "x": 22.1752595116795, + "y": 13.358318679080279, + "z": 10.967353411045332 + }, + { + "x": 22.66451296147254, + "y": 13.35831867908028, + "z": 10.633702244498703 + }, + { + "x": 23.15376641126558, + "y": 13.358318679080277, + "z": 10.322552151367699 + }, + { + "x": 23.643019861058615, + "y": 13.358318679080277, + "z": 10.103284997217699 + }, + { + "x": 24.132273310851655, + "y": 13.35831867908028, + "z": 9.723029069400912 + }, + { + "x": 24.62152676064469, + "y": 13.35831867908028, + "z": 9.446193326976582 + }, + { + "x": 25.110780210437728, + "y": 13.358318679080275, + "z": 9.173605421928213 + }, + { + "x": 25.600033660230768, + "y": 13.358318679080279, + "z": 8.855472057645901 + }, + { + "x": 26.089287110023804, + "y": 13.358318679080275, + "z": 8.547905276271779 + }, + { + "x": 26.578540559816844, + "y": 13.35831867908027, + "z": 8.2946321038678 + }, + { + "x": 27.06779400960988, + "y": 13.358318679080277, + "z": 8.041726938177678 + }, + { + "x": 27.557047459402913, + "y": 13.35831867908028, + "z": 7.720156489934193 + }, + { + "x": 28.046300909195953, + "y": 13.358318679080268, + "z": 7.394666891520797 + }, + { + "x": 28.535554358988996, + "y": 13.358318679080275, + "z": 7.119834302697194 + }, + { + "x": 29.02480780878203, + "y": 13.358318679080275, + "z": 6.8009722450429075 + }, + { + "x": 15.814964664370011, + "y": 14.173714241696416, + "z": 14.747396043285056 + }, + { + "x": 16.30421811416305, + "y": 14.173714241696418, + "z": 14.520314552423596 + }, + { + "x": 16.79347156395609, + "y": 14.173714241696423, + "z": 14.222483627585193 + }, + { + "x": 17.282725013749115, + "y": 14.173714241696409, + "z": 13.875591661631452 + }, + { + "x": 17.77197846354217, + "y": 14.17371424169642, + "z": 13.605242668766046 + }, + { + "x": 18.261231913335198, + "y": 14.173714241696418, + "z": 13.273854707998328 + }, + { + "x": 18.750485363128238, + "y": 14.173714241696418, + "z": 12.981776779145372 + }, + { + "x": 19.239738812921274, + "y": 14.173714241696416, + "z": 12.6647342049621 + }, + { + "x": 19.728992262714314, + "y": 14.173714241696416, + "z": 12.39328855094015 + }, + { + "x": 20.218245712507347, + "y": 14.173714241696416, + "z": 12.073886130847423 + }, + { + "x": 20.707499162300387, + "y": 14.173714241696416, + "z": 11.856002561296147 + }, + { + "x": 21.19675261209343, + "y": 14.173714241696418, + "z": 11.541391228071237 + }, + { + "x": 21.686006061886467, + "y": 14.173714241696418, + "z": 11.23215078435979 + }, + { + "x": 22.1752595116795, + "y": 14.173714241696416, + "z": 10.927394318355674 + }, + { + "x": 22.66451296147254, + "y": 14.17371424169642, + "z": 10.652770370096402 + }, + { + "x": 23.15376641126558, + "y": 14.17371424169642, + "z": 10.329842471935157 + }, + { + "x": 23.643019861058615, + "y": 14.173714241696413, + "z": 10.079199902613018 + }, + { + "x": 24.13227331085165, + "y": 14.173714241696416, + "z": 9.789362747330896 + }, + { + "x": 24.62152676064469, + "y": 14.173714241696421, + "z": 9.486679120114731 + }, + { + "x": 25.11078021043773, + "y": 14.173714241696421, + "z": 9.190865030378216 + }, + { + "x": 25.600033660230768, + "y": 14.173714241696434, + "z": 8.931677082735904 + }, + { + "x": 26.0892871100238, + "y": 14.173714241696418, + "z": 8.584523710134992 + }, + { + "x": 26.578540559816844, + "y": 14.17371424169642, + "z": 8.282365083610484 + }, + { + "x": 27.067794009609877, + "y": 14.173714241696416, + "z": 8.047571555070357 + }, + { + "x": 27.557047459402924, + "y": 14.173714241696418, + "z": 7.676412023087492 + }, + { + "x": 28.046300909195956, + "y": 14.173714241696418, + "z": 7.3855300263216535 + }, + { + "x": 28.535554358989003, + "y": 14.173714241696427, + "z": 7.131869233690081 + }, + { + "x": 29.024807808782036, + "y": 14.173714241696421, + "z": 6.833468366118136 + }, + { + "x": 15.814964664370006, + "y": 14.989109804312555, + "z": 14.722135869231678 + }, + { + "x": 16.304218114163056, + "y": 14.989109804312552, + "z": 14.45556217226263 + }, + { + "x": 16.79347156395609, + "y": 14.989109804312553, + "z": 14.19750219944955 + }, + { + "x": 17.28272501374912, + "y": 14.989109804312566, + "z": 13.90999788144282 + }, + { + "x": 17.771978463542162, + "y": 14.989109804312557, + "z": 13.629194700285291 + }, + { + "x": 18.2612319133352, + "y": 14.989109804312571, + "z": 13.323162719050208 + }, + { + "x": 18.750485363128238, + "y": 14.989109804312557, + "z": 12.961868244540355 + }, + { + "x": 19.239738812921278, + "y": 14.989109804312562, + "z": 12.683514895262745 + }, + { + "x": 19.728992262714318, + "y": 14.989109804312555, + "z": 12.398006095874264 + }, + { + "x": 20.218245712507354, + "y": 14.989109804312557, + "z": 12.162957407020919 + }, + { + "x": 20.707499162300383, + "y": 14.989109804312557, + "z": 11.819112771327006 + }, + { + "x": 21.196752612093427, + "y": 14.989109804312559, + "z": 11.502823977971014 + }, + { + "x": 21.686006061886463, + "y": 14.989109804312555, + "z": 11.232604762717838 + }, + { + "x": 22.175259511679506, + "y": 14.989109804312559, + "z": 10.9222993303611 + }, + { + "x": 22.66451296147254, + "y": 14.989109804312559, + "z": 10.688898051258672 + }, + { + "x": 23.15376641126558, + "y": 14.989109804312559, + "z": 10.395336477208017 + }, + { + "x": 23.643019861058615, + "y": 14.989109804312557, + "z": 10.03926727894913 + }, + { + "x": 24.132273310851655, + "y": 14.989109804312557, + "z": 9.783346029756327 + }, + { + "x": 24.62152676064469, + "y": 14.989109804312559, + "z": 9.526301728426027 + }, + { + "x": 25.110780210437735, + "y": 14.989109804312559, + "z": 9.219227990154456 + }, + { + "x": 25.60003366023076, + "y": 14.989109804312559, + "z": 8.892588317046227 + }, + { + "x": 26.089287110023808, + "y": 14.989109804312557, + "z": 8.568546202810111 + }, + { + "x": 26.578540559816844, + "y": 14.989109804312543, + "z": 8.27258676644875 + }, + { + "x": 27.067794009609877, + "y": 14.989109804312555, + "z": 8.047156633494005 + }, + { + "x": 27.55704745940292, + "y": 14.989109804312575, + "z": 7.730653822303397 + }, + { + "x": 28.04630090919597, + "y": 14.989109804312568, + "z": 7.457938483222923 + }, + { + "x": 28.535554358988996, + "y": 14.989109804312557, + "z": 7.104567533217575 + }, + { + "x": 29.024807808782032, + "y": 14.989109804312553, + "z": 6.880936344252645 + }, + { + "x": 15.81496466437001, + "y": 15.804505366928694, + "z": 14.78582815973693 + }, + { + "x": 16.304218114163053, + "y": 15.804505366928694, + "z": 14.429093923445272 + }, + { + "x": 16.79347156395608, + "y": 15.804505366928696, + "z": 14.159664649481007 + }, + { + "x": 17.28272501374914, + "y": 15.804505366928698, + "z": 13.886500813388064 + }, + { + "x": 17.771978463542162, + "y": 15.804505366928698, + "z": 13.615076805258544 + }, + { + "x": 18.261231913335198, + "y": 15.804505366928698, + "z": 13.327702903984152 + }, + { + "x": 18.750485363128234, + "y": 15.804505366928698, + "z": 13.051807506508577 + }, + { + "x": 19.239738812921274, + "y": 15.804505366928694, + "z": 12.753238709462295 + }, + { + "x": 19.728992262714314, + "y": 15.804505366928698, + "z": 12.398199422189267 + }, + { + "x": 20.218245712507354, + "y": 15.804505366928698, + "z": 12.07412333065135 + }, + { + "x": 20.707499162300387, + "y": 15.804505366928698, + "z": 11.846618338590586 + }, + { + "x": 21.196752612093427, + "y": 15.804505366928698, + "z": 11.549713036120844 + }, + { + "x": 21.686006061886474, + "y": 15.804505366928703, + "z": 11.212554204633186 + }, + { + "x": 22.1752595116795, + "y": 15.804505366928698, + "z": 10.922586765658158 + }, + { + "x": 22.66451296147254, + "y": 15.804505366928696, + "z": 10.69147082689201 + }, + { + "x": 23.15376641126558, + "y": 15.804505366928696, + "z": 10.382180106429837 + }, + { + "x": 23.64301986105861, + "y": 15.804505366928698, + "z": 10.042490746848259 + }, + { + "x": 24.13227331085165, + "y": 15.804505366928701, + "z": 9.762399072994707 + }, + { + "x": 24.621526760644695, + "y": 15.804505366928698, + "z": 9.443107358517981 + }, + { + "x": 25.11078021043773, + "y": 15.804505366928698, + "z": 9.200528003239029 + }, + { + "x": 25.600033660230764, + "y": 15.804505366928698, + "z": 8.893079069747168 + }, + { + "x": 26.089287110023804, + "y": 15.804505366928698, + "z": 8.590785177279937 + }, + { + "x": 26.57854055981685, + "y": 15.8045053669287, + "z": 8.318364007005307 + }, + { + "x": 27.067794009609877, + "y": 15.804505366928701, + "z": 8.009428884221883 + }, + { + "x": 27.557047459402916, + "y": 15.8045053669287, + "z": 7.681894348792958 + }, + { + "x": 28.046300909195963, + "y": 15.804505366928696, + "z": 7.44161045443957 + }, + { + "x": 28.535554358988996, + "y": 15.804505366928696, + "z": 7.176152419982489 + }, + { + "x": 29.024807808782036, + "y": 15.804505366928698, + "z": 6.871653677524145 + } + ], + "pointsGround": [ + { + "x": -4.658947733156184, + "y": -27.033603990313544, + "z": 0.19277347458655641 + }, + { + "x": 0.7123332072046829, + "y": -27.033603990313544, + "z": 0.1010406486927721 + }, + { + "x": 6.08361414756555, + "y": -27.033603990313544, + "z": 0.04149966758745707 + }, + { + "x": 11.454895087926417, + "y": -27.033603990313544, + "z": 0.24626176315185697 + }, + { + "x": 16.826176028287286, + "y": -27.033603990313544, + "z": 0.027251158387982827 + }, + { + "x": 22.19745696864815, + "y": -27.033603990313544, + "z": 0.07667010199589194 + }, + { + "x": 27.568737909009016, + "y": -27.033603990313544, + "z": 0.2005351152972016 + }, + { + "x": 32.940018849369885, + "y": -27.033603990313544, + "z": 0.11138666973513861 + }, + { + "x": 38.311299789730754, + "y": -27.033603990313544, + "z": 0.05624578849237682 + }, + { + "x": 43.682580730091615, + "y": -27.033603990313544, + "z": 0.0028016632435851094 + }, + { + "x": 49.053861670452484, + "y": -27.033603990313544, + "z": 0.1913418351632272 + }, + { + "x": -4.658947733156184, + "y": -20.748211022020058, + "z": 0.007185897676826407 + }, + { + "x": 0.7123332072046829, + "y": -20.748211022020058, + "z": 0.0018902976307507127 + }, + { + "x": 6.08361414756555, + "y": -20.748211022020058, + "z": 0.12750560423708782 + }, + { + "x": 11.454895087926417, + "y": -20.748211022020058, + "z": 0.09552374614659871 + }, + { + "x": 16.826176028287286, + "y": -20.748211022020058, + "z": 0.06985219582908424 + }, + { + "x": 22.19745696864815, + "y": -20.748211022020058, + "z": 0.17577207352769192 + }, + { + "x": 27.568737909009016, + "y": -20.748211022020058, + "z": 0.058836433831060506 + }, + { + "x": 32.940018849369885, + "y": -20.748211022020058, + "z": 0.18283048047815936 + }, + { + "x": 38.311299789730754, + "y": -20.748211022020058, + "z": 0.022250389457796883 + }, + { + "x": 43.682580730091615, + "y": -20.748211022020058, + "z": 0.020662246281589497 + }, + { + "x": 49.053861670452484, + "y": -20.748211022020058, + "z": 0.0846812945486425 + }, + { + "x": -4.658947733156184, + "y": -14.462818053726572, + "z": 0.08247804901678024 + }, + { + "x": 0.7123332072046829, + "y": -14.462818053726572, + "z": 0.1828292392579975 + }, + { + "x": 6.08361414756555, + "y": -14.462818053726572, + "z": 0.2239883526805734 + }, + { + "x": 11.454895087926417, + "y": -14.462818053726572, + "z": 0.20316254089268043 + }, + { + "x": 16.826176028287286, + "y": -14.462818053726572, + "z": 0.16338714662165713 + }, + { + "x": 22.19745696864815, + "y": -14.462818053726572, + "z": 0.23170905047175896 + }, + { + "x": 27.568737909009016, + "y": -14.462818053726572, + "z": 0.024810356565197166 + }, + { + "x": 32.940018849369885, + "y": -14.462818053726572, + "z": 0.1729572828267502 + }, + { + "x": 38.311299789730754, + "y": -14.462818053726572, + "z": 0.23137001436267515 + }, + { + "x": 43.682580730091615, + "y": -14.462818053726572, + "z": 0.24503520736239628 + }, + { + "x": 49.053861670452484, + "y": -14.462818053726572, + "z": 0.025354949652848277 + }, + { + "x": -4.658947733156184, + "y": -8.177425085433084, + "z": 0.009671256532739501 + }, + { + "x": 0.7123332072046829, + "y": -8.177425085433084, + "z": 0.08526368000789716 + }, + { + "x": 6.08361414756555, + "y": -8.177425085433084, + "z": 0.2124099053733097 + }, + { + "x": 11.454895087926417, + "y": -8.177425085433084, + "z": 0.1717732263131874 + }, + { + "x": 16.826176028287286, + "y": -8.177425085433084, + "z": 0.18600053570047045 + }, + { + "x": 22.19745696864815, + "y": -8.177425085433084, + "z": 0.1714114156418533 + }, + { + "x": 27.568737909009016, + "y": -8.177425085433084, + "z": 0.02326533071383151 + }, + { + "x": 32.940018849369885, + "y": -8.177425085433084, + "z": 0.010130275976904796 + }, + { + "x": 38.311299789730754, + "y": -8.177425085433084, + "z": 0.06790504689230818 + }, + { + "x": 43.682580730091615, + "y": -8.177425085433084, + "z": 0.06581278160019442 + }, + { + "x": 49.053861670452484, + "y": -8.177425085433084, + "z": 0.12494487123328488 + }, + { + "x": -4.658947733156184, + "y": -1.892032117139598, + "z": 0.24039247631579286 + }, + { + "x": 0.7123332072046829, + "y": -1.892032117139598, + "z": 0.13901136659039715 + }, + { + "x": 6.08361414756555, + "y": -1.892032117139598, + "z": 0.004400752021186404 + }, + { + "x": 11.454895087926417, + "y": -1.892032117139598, + "z": 0.12213514436601434 + }, + { + "x": 16.826176028287286, + "y": -1.892032117139598, + "z": 0.08555311469154112 + }, + { + "x": 22.19745696864815, + "y": -1.892032117139598, + "z": 0.12141337041808915 + }, + { + "x": 27.568737909009016, + "y": -1.892032117139598, + "z": 0.160608003223598 + }, + { + "x": 32.940018849369885, + "y": -1.892032117139598, + "z": 0.15503193526763093 + }, + { + "x": 38.311299789730754, + "y": -1.892032117139598, + "z": 0.018336335205629623 + }, + { + "x": 43.682580730091615, + "y": -1.892032117139598, + "z": 0.22385546913084364 + }, + { + "x": 49.053861670452484, + "y": -1.892032117139598, + "z": 0.14884319070207103 + }, + { + "x": -4.658947733156184, + "y": 4.393360851153886, + "z": 0.10809218003791393 + }, + { + "x": 0.7123332072046829, + "y": 4.393360851153886, + "z": 0.018562599675991852 + }, + { + "x": 6.08361414756555, + "y": 4.393360851153886, + "z": 0.10867042832945958 + }, + { + "x": 11.454895087926417, + "y": 4.393360851153886, + "z": 0.022273410471283558 + }, + { + "x": 16.826176028287286, + "y": 4.393360851153886, + "z": 0.07408861749530239 + }, + { + "x": 22.19745696864815, + "y": 4.393360851153886, + "z": 0.1632829553742348 + }, + { + "x": 27.568737909009016, + "y": 4.393360851153886, + "z": 0.21882606482544265 + }, + { + "x": 32.940018849369885, + "y": 4.393360851153886, + "z": 0.08657631316994145 + }, + { + "x": 38.311299789730754, + "y": 4.393360851153886, + "z": 0.1332885056656266 + }, + { + "x": 43.682580730091615, + "y": 4.393360851153886, + "z": 0.021431648880909964 + }, + { + "x": 49.053861670452484, + "y": 4.393360851153886, + "z": 0.19630662780083094 + }, + { + "x": -4.658947733156184, + "y": 10.678753819447373, + "z": 0.23183094802397813 + }, + { + "x": 0.7123332072046829, + "y": 10.678753819447373, + "z": 0.2422190410980112 + }, + { + "x": 6.08361414756555, + "y": 10.678753819447373, + "z": 0.04224192422919065 + }, + { + "x": 11.454895087926417, + "y": 10.678753819447373, + "z": 0.13311384077328903 + }, + { + "x": 16.826176028287286, + "y": 10.678753819447373, + "z": 0.14807896951589686 + }, + { + "x": 22.19745696864815, + "y": 10.678753819447373, + "z": 0.23977153782722146 + }, + { + "x": 27.568737909009016, + "y": 10.678753819447373, + "z": 0.1374250181892072 + }, + { + "x": 32.940018849369885, + "y": 10.678753819447373, + "z": 0.15956514976432787 + }, + { + "x": 38.311299789730754, + "y": 10.678753819447373, + "z": 0.012120113480892085 + }, + { + "x": 43.682580730091615, + "y": 10.678753819447373, + "z": 0.2027571993892813 + }, + { + "x": 49.053861670452484, + "y": 10.678753819447373, + "z": 0.018868512948448077 + }, + { + "x": -4.658947733156184, + "y": 16.964146787740855, + "z": 0.20753317778349537 + }, + { + "x": 0.7123332072046829, + "y": 16.964146787740855, + "z": 0.1924367629422046 + }, + { + "x": 6.08361414756555, + "y": 16.964146787740855, + "z": 0.08497698609017626 + }, + { + "x": 11.454895087926417, + "y": 16.964146787740855, + "z": 0.198761788871494 + }, + { + "x": 16.826176028287286, + "y": 16.964146787740855, + "z": 0.04125200225564279 + }, + { + "x": 22.19745696864815, + "y": 16.964146787740855, + "z": 0.14615593578021785 + }, + { + "x": 27.568737909009016, + "y": 16.964146787740855, + "z": 0.153396986147108 + }, + { + "x": 32.940018849369885, + "y": 16.964146787740855, + "z": 0.0123492796031522 + }, + { + "x": 38.311299789730754, + "y": 16.964146787740855, + "z": 0.07633807909504421 + }, + { + "x": 43.682580730091615, + "y": 16.964146787740855, + "z": 0.22669887215676665 + }, + { + "x": 49.053861670452484, + "y": 16.964146787740855, + "z": 0.05149948052200465 + }, + { + "x": -4.658947733156184, + "y": 23.24953975603435, + "z": 0.11082806583066847 + }, + { + "x": 0.7123332072046829, + "y": 23.24953975603435, + "z": 0.22717149996998323 + }, + { + "x": 6.08361414756555, + "y": 23.24953975603435, + "z": 0.19384730569731784 + }, + { + "x": 11.454895087926417, + "y": 23.24953975603435, + "z": 0.0631027979837278 + }, + { + "x": 16.826176028287286, + "y": 23.24953975603435, + "z": 0.1637271252291869 + }, + { + "x": 22.19745696864815, + "y": 23.24953975603435, + "z": 0.09732279814655091 + }, + { + "x": 27.568737909009016, + "y": 23.24953975603435, + "z": 0.1099823753395967 + }, + { + "x": 32.940018849369885, + "y": 23.24953975603435, + "z": 0.04130421115146215 + }, + { + "x": 38.311299789730754, + "y": 23.24953975603435, + "z": 0.23132873372236673 + }, + { + "x": 43.682580730091615, + "y": 23.24953975603435, + "z": 0.1825242759345678 + }, + { + "x": 49.053861670452484, + "y": 23.24953975603435, + "z": 0.10351322235237491 + }, + { + "x": -4.658947733156184, + "y": 29.53493272432783, + "z": 0.04408584851496194 + }, + { + "x": 0.7123332072046829, + "y": 29.53493272432783, + "z": 0.157180418566419 + }, + { + "x": 6.08361414756555, + "y": 29.53493272432783, + "z": 0.012181710923175193 + }, + { + "x": 11.454895087926417, + "y": 29.53493272432783, + "z": 0.0798932201368237 + }, + { + "x": 16.826176028287286, + "y": 29.53493272432783, + "z": 0.2024392739182521 + }, + { + "x": 22.19745696864815, + "y": 29.53493272432783, + "z": 0.22333440090219228 + }, + { + "x": 27.568737909009016, + "y": 29.53493272432783, + "z": 0.17083646539637654 + }, + { + "x": 32.940018849369885, + "y": 29.53493272432783, + "z": 0.01760691707842374 + }, + { + "x": 38.311299789730754, + "y": 29.53493272432783, + "z": 0.10877118544130175 + }, + { + "x": 43.682580730091615, + "y": 29.53493272432783, + "z": 0.21173535564995155 + }, + { + "x": 49.053861670452484, + "y": 29.53493272432783, + "z": 0.19608599131278973 + }, + { + "x": -4.658947733156184, + "y": 35.82032569262132, + "z": 0.08922366708946584 + }, + { + "x": 0.7123332072046829, + "y": 35.82032569262132, + "z": 0.06102942189249649 + }, + { + "x": 6.08361414756555, + "y": 35.82032569262132, + "z": 0.16623366538725498 + }, + { + "x": 11.454895087926417, + "y": 35.82032569262132, + "z": 0.1872964243811073 + }, + { + "x": 16.826176028287286, + "y": 35.82032569262132, + "z": 0.12532682862380837 + }, + { + "x": 22.19745696864815, + "y": 35.82032569262132, + "z": 0.12203095311859201 + }, + { + "x": 27.568737909009016, + "y": 35.82032569262132, + "z": 0.07267012904522481 + }, + { + "x": 32.940018849369885, + "y": 35.82032569262132, + "z": 0.18317932702283343 + }, + { + "x": 38.311299789730754, + "y": 35.82032569262132, + "z": 0.12093922606247441 + }, + { + "x": 43.682580730091615, + "y": 35.82032569262132, + "z": 0.19509356978586576 + }, + { + "x": 49.053861670452484, + "y": 35.82032569262132, + "z": 0.2196077556440643 + } + ], + "footprintExterior": [ + { + "x": 15.341052266843816, + "y": -7.0336039903135426, + "z": 0 + }, + { + "x": 29.05386167045248, + "y": -7.0336039903135426, + "z": 0 + }, + { + "x": 29.05386167045248, + "y": 15.820325692621319, + "z": 0 + }, + { + "x": 15.341052266843816, + "y": 15.820325692621319, + "z": 0 + }, + { + "x": 15.341052266843816, + "y": -7.0336039903135426, + "z": 0 + } + ] +} diff --git a/roofersharp/RooferSharp.sln.DotSettings.user b/roofersharp/RooferSharp.sln.DotSettings.user new file mode 100644 index 00000000..94a98755 --- /dev/null +++ b/roofersharp/RooferSharp.sln.DotSettings.user @@ -0,0 +1,16 @@ + + ForceIncluded + ForceIncluded + <AssemblyExplorer> + <Assembly Path="C:\development\_PLAYGROUND\roofer\roofersharp\RooferSharp\mpfr-6.dll" /> +</AssemblyExplorer> + <SessionState ContinuousTestingMode="0" Name="Test1" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> + <TestAncestor> + <TestId>NUnit3x::F362C030-4F30-1131-E1ED-B0D3DC9F80E9::net10.0::RooferSharp.Test.Tests.Test1</TestId> + </TestAncestor> +</SessionState> + <SessionState ContinuousTestingMode="0" IsActive="True" Name="Test1 #2" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> + <TestAncestor> + <TestId>NUnit3x::F362C030-4F30-1131-E1ED-B0D3DC9F80E9::net10.0::RooferSharp.Test.Tests.Test1</TestId> + </TestAncestor> +</SessionState> \ No newline at end of file diff --git a/roofersharp/RooferSharp.slnx b/roofersharp/RooferSharp.slnx new file mode 100644 index 00000000..1545e45a --- /dev/null +++ b/roofersharp/RooferSharp.slnx @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/roofersharp/RooferSharp/.gitignore b/roofersharp/RooferSharp/.gitignore new file mode 100644 index 00000000..9117bc5b --- /dev/null +++ b/roofersharp/RooferSharp/.gitignore @@ -0,0 +1,4 @@ +bin/* +obj/* +.idea/* +.vs/* \ No newline at end of file diff --git a/roofersharp/RooferSharp/LinearRing.cs b/roofersharp/RooferSharp/LinearRing.cs new file mode 100644 index 00000000..54d76fcd --- /dev/null +++ b/roofersharp/RooferSharp/LinearRing.cs @@ -0,0 +1,17 @@ +// Copyright (c) 2018-2024 TU Delft 3D geoinformation group, Ravi Peters (3DGI), +// and Balazs Dukai (3DGI) +// C# P/Invoke wrapper for roofer library + +using System.Numerics; + +namespace RooferSharp +{ + + /// + /// Linear ring (exterior or interior ring of a polygon) + /// + public class LinearRing + { + public List Points { get; set; } = new List(); + } +} diff --git a/roofersharp/RooferSharp/NativeMethods.cs b/roofersharp/RooferSharp/NativeMethods.cs new file mode 100644 index 00000000..57619d2f --- /dev/null +++ b/roofersharp/RooferSharp/NativeMethods.cs @@ -0,0 +1,116 @@ +using System.Runtime.InteropServices; + +// ReSharper disable InconsistentNaming +// naming is based on underlying C++ methods. + +namespace RooferSharp; + +/// +/// Native method declarations +/// +internal static class NativeMethods +{ + private const string LibName = "roofer"; + + [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr roofer_config_create(); + + [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void roofer_config_destroy(IntPtr handle); + + [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void roofer_config_set_complexity_factor(IntPtr handle, float value); + + [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void roofer_config_set_clip_ground(IntPtr handle, int value); + + [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void roofer_config_set_lod(IntPtr handle, int value); + + [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void roofer_config_set_lod13_step_height(IntPtr handle, float value); + + [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void roofer_config_set_floor_elevation(IntPtr handle, float value); + + [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void roofer_config_set_override_with_floor_elevation(IntPtr handle, int value); + + [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void roofer_config_set_plane_detect_k(IntPtr handle, int value); + + [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void roofer_config_set_plane_detect_min_points(IntPtr handle, int value); + + [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void roofer_config_set_plane_detect_epsilon(IntPtr handle, float value); + + [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void roofer_config_set_plane_detect_normal_angle(IntPtr handle, float value); + + [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void roofer_config_set_line_detect_epsilon(IntPtr handle, float value); + + [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void roofer_config_set_thres_alpha(IntPtr handle, float value); + + [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void roofer_config_set_thres_reg_line_dist(IntPtr handle, float value); + + [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void roofer_config_set_thres_reg_line_ext(IntPtr handle, float value); + + [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] + internal static extern int roofer_config_is_valid(IntPtr handle); + + [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr roofer_reconstruct_with_ground( + [In] float[] points_roof, UIntPtr points_roof_count, + [In] float[] points_ground, UIntPtr points_ground_count, + [In] float[] footprint_exterior, UIntPtr footprint_exterior_count, + [In] float[] footprint_interiors, [In] UIntPtr[] interior_counts, UIntPtr interior_ring_count, + IntPtr config); + + [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr roofer_reconstruct( + [In] float[] points_roof, UIntPtr points_roof_count, + [In] float[] footprint_exterior, UIntPtr footprint_exterior_count, + [In] float[] footprint_interiors, [In] UIntPtr[] interior_counts, UIntPtr interior_ring_count, + IntPtr config); + + [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] + internal static extern UIntPtr roofer_mesh_array_size(IntPtr handle); + + [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr roofer_mesh_array_get(IntPtr handle, UIntPtr index); + + [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void roofer_mesh_array_destroy(IntPtr handle); + + [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] + internal static extern UIntPtr roofer_mesh_polygon_count(IntPtr handle); + + [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] + internal static extern UIntPtr roofer_mesh_get_polygon_exterior_size(IntPtr handle, UIntPtr poly_index); + + [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void roofer_mesh_get_polygon_exterior(IntPtr handle, UIntPtr poly_index, [Out] float[] points); + + [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] + internal static extern UIntPtr roofer_mesh_get_polygon_interior_count(IntPtr handle, UIntPtr poly_index); + + [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] + internal static extern UIntPtr roofer_mesh_get_polygon_interior_size(IntPtr handle, UIntPtr poly_index, UIntPtr interior_index); + + [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void roofer_mesh_get_polygon_interior(IntPtr handle, UIntPtr poly_index, UIntPtr interior_index, [Out] float[] points); + + [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] + internal static extern int roofer_triangulate_mesh( + IntPtr mesh_handle, + out IntPtr out_vertices, out UIntPtr out_vertex_count, + out IntPtr out_faces, out UIntPtr out_face_count); + + [DllImport(LibName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void roofer_free_triangulation(IntPtr vertices, IntPtr faces); +} \ No newline at end of file diff --git a/roofersharp/RooferSharp/Polygon.cs b/roofersharp/RooferSharp/Polygon.cs new file mode 100644 index 00000000..d4245988 --- /dev/null +++ b/roofersharp/RooferSharp/Polygon.cs @@ -0,0 +1,10 @@ +namespace RooferSharp; + +/// +/// Polygon with optional interior rings (holes) +/// +public class Polygon +{ + public LinearRing Exterior { get; set; } = new LinearRing(); + public List Interiors { get; set; } = new List(); +} \ No newline at end of file diff --git a/roofersharp/RooferSharp/Properties/launchSettings.json b/roofersharp/RooferSharp/Properties/launchSettings.json new file mode 100644 index 00000000..b715b229 --- /dev/null +++ b/roofersharp/RooferSharp/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "RooferSharp": { + "commandName": "Project", + "nativeDebugging": true + } + } +} \ No newline at end of file diff --git a/roofersharp/RooferSharp/ReconstructionConfig.cs b/roofersharp/RooferSharp/ReconstructionConfig.cs new file mode 100644 index 00000000..db6fc2b9 --- /dev/null +++ b/roofersharp/RooferSharp/ReconstructionConfig.cs @@ -0,0 +1,111 @@ +namespace RooferSharp; + +/// +/// Configuration for reconstruction +/// +public class ReconstructionConfig +{ + /** + * Complexity factor for building model geometry. + * + * A number between `0.0` and `1.0`. Higher values lead to + * more detailed building models, lower values to simpler models. + */ + public float ComplexityFactor { get; set; } = 0.888f; + + /** + * Set to true to activate the procedure that + * clips parts from the input footprint wherever patches of ground points + * are detected. May cause irregular outlines in reconstruction result. + */ + public bool ClipGround { get; set; } = true; + + /** + * - 12: LoD 1.2 + * - 13: LoD 1.3 + * - 22: LoD 2.2 + */ + public LevelOfDetail Lod { get; set; } = LevelOfDetail.Lod22; + + /** + * Step height used for LoD13 generalisation, i.e. roofparts with a + * height discontinuity that is smaller than this value are merged. Only + * affects LoD 1.3 reconstructions. Unit: meters. + */ + public float Lod13StepHeight { get; set; } = 3f; + + public float FloorElevation { get; set; } = 0f; + + /** + * @brief Force flat floor instead of using the + * elevation of the footprint (API only). + */ + public bool OverrideWithFloorElevation { get; set; } = false; + + /** + * @brief Number of points used in nearest neighbour queries + * during plane detection. + */ + public int PlaneDetectK { get; set; } = 15; + + /** + * Minimum number of points required to + * detect a plane. + */ + public int PlaneDetectMinPoints { get; set; } = 15; + + /** + * @brief Maximum allowed angle between points inside the same + * detected plane. This value is compared to the dot product between two + * unit normals. Eg. 0 means 90 degrees (orthogonal normals), and 1.0 means + * 0 degrees (parallel normals) + */ + public float PlaneDetectEpsilon { get; set; } = 0.3f; + /** + * @brief Maximum distance from candidate points to line during line + * fitting procedure. Higher values offer more robustness against irregular + * lines, lower values give more accurate lines (ie. more closely wrapping + * around point cloud). Unit: meters. + */ + public float PlaneDetectNormalAngle { get; set; } =0.75f; + + /** + * @brief Distance used in computing alpha-shape of detected plane + * segments prior to line detection. Higher values offer more robustness + * against irregular lines, lower values give more accurate lines (ie. more + * closely wrapping around point cloud). Unit: meters. + */ + public float LineDetectEpsilon { get; set; } = 1.0f; + /** + * @brief Distance used in computing alpha-shape of detected plane + * segments prior to line detection. Higher values offer more robustness + * against irregular lines, lower values give more accurate lines (ie. more + * closely wrapping around point cloud). Unit: meters. + */ + public float ThresAlpha { get; set; } = 0.25f; + + /** + * @brief Maximum distance to merge lines during line regularisation + * (after line detection). Approximately parallel lines that are closer to + * each other than this threshold are merged. Higher values yield more + * regularisation, lower values preserve more finer details. Unit: meters. + */ + public float ThresRegLineDist { get; set; } = 3.0f; + + /** + * @brief Extension of regularised lines prior to optimisation. Used + * to compensate for undetected parts in the roofpart boundaries. Use higher + * values when the input pointcloud is less dense. However, setting this too + * high can lead to unrealistic reconstruction results. Unit: meters. + */ + public float ThresRegLineExt { get; set; } = 3.0f; + + public bool IsValid => (ComplexityFactor >= 0 && ComplexityFactor <= 1.0) && Lod13StepHeight > 0; +} + +public enum LevelOfDetail +{ + Lod12 = 12, + Lod13 = 13, + Lod22 = 22 +} \ No newline at end of file diff --git a/roofersharp/RooferSharp/Reconstructor.cs b/roofersharp/RooferSharp/Reconstructor.cs new file mode 100644 index 00000000..76ed7ec7 --- /dev/null +++ b/roofersharp/RooferSharp/Reconstructor.cs @@ -0,0 +1,261 @@ +using System.Drawing; +using System.Numerics; + +namespace RooferSharp; + +/// +/// Main Roofer API +/// +public static class Reconstructor +{ + /// + /// Reconstructs a single instance of a building from a point cloud + /// + /// Reconstruction configuration + /// List of points for the roof + /// List of points for the ground, also for interior curves + /// Polyline representing the ground (should be ordered) + /// Polylines representing interior curves + /// + /// + + public static List ReconstructWithGround( + ReconstructionConfig config, + List pointsRoof, + List pointsGround, + List footprintExterior, + List>? footprintInteriors = null + ) + { + if (pointsRoof == null || pointsRoof.Count == 0) + throw new ArgumentException("Roof points cannot be null or empty", nameof(pointsRoof)); + if (pointsGround == null || pointsGround.Count == 0) + throw new ArgumentException("Ground points cannot be null or empty", nameof(pointsGround)); + if (footprintExterior == null || footprintExterior.Count < 3) + throw new ArgumentException("Footprint exterior must have at least 3 points", nameof(footprintExterior)); + + // Flatten points + var roofArray = FlattenPoints(pointsRoof); + var groundArray = FlattenPoints(pointsGround); + var footprintArray = FlattenPoints(footprintExterior); + + // Handle interior rings - pre-calculate total size + float[]? interiorsArray = null; + UIntPtr[]? interiorCounts = null; + var interiorRingCount = UIntPtr.Zero; + + if (footprintInteriors != null && footprintInteriors.Count > 0) + { + // Pre-calculate total points + var totalPoints = footprintInteriors.Sum(interior => interior.Count); + + interiorsArray = new float[totalPoints * 3]; + interiorCounts = new UIntPtr[footprintInteriors.Count]; + + var offset = 0; + for (var i = 0; i < footprintInteriors.Count; i++) + { + var interior = footprintInteriors[i]; + interiorCounts[i] = (UIntPtr)interior.Count; + + foreach (var pt in interior) + { + interiorsArray[offset++] = pt.X; + interiorsArray[offset++] = pt.Y; + interiorsArray[offset++] = pt.Z; + } + } + + interiorRingCount = (UIntPtr)footprintInteriors.Count; + } + + // Create and populate native config + var nativeConfig = CreateAndValidateNativeConfig(config); + + try + { + var meshArrayHandle = NativeMethods.roofer_reconstruct_with_ground( + roofArray, (UIntPtr)pointsRoof.Count, + groundArray, (UIntPtr)pointsGround.Count, + footprintArray, (UIntPtr)footprintExterior.Count, + interiorsArray ?? [], interiorCounts ?? [], interiorRingCount, + nativeConfig); + + return ExtractShapes(meshArrayHandle); + } + finally + { + if (nativeConfig != IntPtr.Zero) + { + NativeMethods.roofer_config_destroy(nativeConfig); + } + } + } + + /// + /// Reconstruct building from point cloud without ground points + /// + /// Reconstruction configuration + /// List of points for the roof + /// Polyline representing the ground (should be ordered) + /// Polylines representing interior curves (optional) + /// + /// + public static List ReconstructWithoutGround( + ReconstructionConfig config, + List pointsRoof, + List footprintExterior, + List>? footprintInteriors = null) + { + if (pointsRoof == null || pointsRoof.Count == 0) + throw new ArgumentException("Roof points cannot be null or empty", nameof(pointsRoof)); + if (footprintExterior == null || footprintExterior.Count < 3) + throw new ArgumentException("Footprint exterior must have at least 3 points", nameof(footprintExterior)); + + var roofArray = FlattenPoints(pointsRoof); + var footprintArray = FlattenPoints(footprintExterior); + + // Handle interior rings - pre-calculate total size + float[]? interiorsArray = null; + UIntPtr[]? interiorCounts = null; + var interiorRingCount = UIntPtr.Zero; + + if (footprintInteriors != null && footprintInteriors.Count > 0) + { + // Pre-calculate total points + var totalPoints = footprintInteriors.Sum(interior => interior.Count); + + interiorsArray = new float[totalPoints * 3]; + interiorCounts = new UIntPtr[footprintInteriors.Count]; + + var offset = 0; + for (var i = 0; i < footprintInteriors.Count; i++) + { + var interior = footprintInteriors[i]; + interiorCounts[i] = (UIntPtr)interior.Count; + + foreach (var pt in interior) + { + interiorsArray[offset++] = pt.X; + interiorsArray[offset++] = pt.Y; + interiorsArray[offset++] = pt.Z; + } + } + + interiorRingCount = (UIntPtr)footprintInteriors.Count; + } + + // Create and populate native config + var nativeConfig = CreateAndValidateNativeConfig(config); + + try + { + var meshArrayHandle = NativeMethods.roofer_reconstruct( + roofArray, (UIntPtr)pointsRoof.Count, + footprintArray, (UIntPtr)footprintExterior.Count, + interiorsArray ?? [], interiorCounts ?? [], interiorRingCount, + nativeConfig); + + return ExtractShapes(meshArrayHandle); + } + finally + { + if (nativeConfig != IntPtr.Zero) + { + NativeMethods.roofer_config_destroy(nativeConfig); + } + } + } + + /// + /// Triangulate a mesh + /// + public static TriangulatedShape TriangulateMesh(Shape shape) + { + if (shape == null) + throw new ArgumentNullException(nameof(shape)); + + var result = NativeMethods.roofer_triangulate_mesh( + shape.Handle, + out var vertices, out var vertexCount, + out var faces, out var faceCount); + + return result == 0 ? throw new InvalidOperationException("Triangulation failed") + : new TriangulatedShape(vertices, vertexCount, faces, faceCount); + } + + private static IntPtr CreateAndValidateNativeConfig(ReconstructionConfig config) + { + if (!config.IsValid) + { + throw new ArgumentException("Invalid reconstruction configuration. Please check parameter values.", nameof(config)); + } + var nativeConfig = NativeMethods.roofer_config_create(); + if (nativeConfig == IntPtr.Zero) + { + throw new InvalidOperationException("Failed to create native configuration"); + } + + try + { + // Set all config values + NativeMethods.roofer_config_set_complexity_factor(nativeConfig, config.ComplexityFactor); + NativeMethods.roofer_config_set_clip_ground(nativeConfig, config.ClipGround ? 1 : 0); + NativeMethods.roofer_config_set_lod(nativeConfig, (int)config.Lod); + NativeMethods.roofer_config_set_lod13_step_height(nativeConfig, config.Lod13StepHeight); + NativeMethods.roofer_config_set_floor_elevation(nativeConfig, config.FloorElevation); + NativeMethods.roofer_config_set_override_with_floor_elevation(nativeConfig, config.OverrideWithFloorElevation ? 1 : 0); + NativeMethods.roofer_config_set_plane_detect_k(nativeConfig, config.PlaneDetectK); + NativeMethods.roofer_config_set_plane_detect_min_points(nativeConfig, config.PlaneDetectMinPoints); + NativeMethods.roofer_config_set_plane_detect_epsilon(nativeConfig, config.PlaneDetectEpsilon); + NativeMethods.roofer_config_set_plane_detect_normal_angle(nativeConfig, config.PlaneDetectNormalAngle); + NativeMethods.roofer_config_set_line_detect_epsilon(nativeConfig, config.LineDetectEpsilon); + NativeMethods.roofer_config_set_thres_alpha(nativeConfig, config.ThresAlpha); + NativeMethods.roofer_config_set_thres_reg_line_dist(nativeConfig, config.ThresRegLineDist); + NativeMethods.roofer_config_set_thres_reg_line_ext(nativeConfig, config.ThresRegLineExt); + + // Validate the config + if (NativeMethods.roofer_config_is_valid(nativeConfig) != 0) return nativeConfig; + + NativeMethods.roofer_config_destroy(nativeConfig); + throw new ArgumentException("Invalid reconstruction configuration. Please check parameter values.", nameof(config)); + } + catch + { + // Cleanup on error + if (nativeConfig != IntPtr.Zero) + { + NativeMethods.roofer_config_destroy(nativeConfig); + } + throw; + } + } + + private static float[] FlattenPoints(List points) + { + var array = new float[points.Count * 3]; + for (var i = 0; i < points.Count; i++) + { + var p = points[i]; + array[i * 3] = p.X; + array[i * 3 + 1] = p.Y; + array[i * 3 + 2] = p.Z; + } + return array; + } + + private static List ExtractShapes(IntPtr meshArrayHandle) + { + var count = (int)NativeMethods.roofer_mesh_array_size(meshArrayHandle); + var meshes = new List(count); + + for (var i = 0; i < count; i++) + { + var meshHandle = NativeMethods.roofer_mesh_array_get(meshArrayHandle, (UIntPtr)i); + meshes.Add(new Shape(meshHandle)); + } + + NativeMethods.roofer_mesh_array_destroy(meshArrayHandle); + return meshes; + } +} \ No newline at end of file diff --git a/roofersharp/RooferSharp/RooferSharp.csproj b/roofersharp/RooferSharp/RooferSharp.csproj new file mode 100644 index 00000000..e58e301a --- /dev/null +++ b/roofersharp/RooferSharp/RooferSharp.csproj @@ -0,0 +1,37 @@ + + + + netstandard2.0 + enable + enable + latest + x64 + x64 + + + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + diff --git a/roofersharp/RooferSharp/Shape.cs b/roofersharp/RooferSharp/Shape.cs new file mode 100644 index 00000000..0dc75ef6 --- /dev/null +++ b/roofersharp/RooferSharp/Shape.cs @@ -0,0 +1,88 @@ +using System.Numerics; + +namespace RooferSharp; + +/// +/// Mesh consisting of multiple polygons +/// +public class Shape : IDisposable +{ + internal IntPtr Handle { get; set; } + private bool _disposed = false; + + internal Shape(IntPtr handle) + { + Handle = handle; + } + + public List GetPolygons() + { + var polygons = new List(); + var count = (int)NativeMethods.roofer_mesh_polygon_count(Handle); + + for (int i = 0; i < count; i++) + { + var polygon = new Polygon(); + + // Get exterior ring + var exteriorSize = (int)NativeMethods.roofer_mesh_get_polygon_exterior_size(Handle, (UIntPtr)i); + var exteriorPoints = new float[exteriorSize * 3]; + NativeMethods.roofer_mesh_get_polygon_exterior(Handle, (UIntPtr)i, exteriorPoints); + + polygon.Exterior.Points.Capacity = exteriorSize; + for (int j = 0; j < exteriorSize; j++) + { + polygon.Exterior.Points.Add(new Vector3( + exteriorPoints[j * 3], + exteriorPoints[j * 3 + 1], + exteriorPoints[j * 3 + 2] + )); + } + + // Get interior rings + var interiorCount = (int)NativeMethods.roofer_mesh_get_polygon_interior_count(Handle, (UIntPtr)i); + for (int k = 0; k < interiorCount; k++) + { + var interior = new LinearRing(); + var interiorSize = (int)NativeMethods.roofer_mesh_get_polygon_interior_size(Handle, (UIntPtr)i, (UIntPtr)k); + var interiorPoints = new float[interiorSize * 3]; + NativeMethods.roofer_mesh_get_polygon_interior(Handle, (UIntPtr)i, (UIntPtr)k, interiorPoints); + + interior.Points.Capacity = interiorSize; + for (int j = 0; j < interiorSize; j++) + { + interior.Points.Add(new Vector3( + interiorPoints[j * 3], + interiorPoints[j * 3 + 1], + interiorPoints[j * 3 + 2] + )); + } + polygon.Interiors.Add(interior); + } + + polygons.Add(polygon); + } + + return polygons; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!_disposed) + { + // Note: Mesh handles from array are not separately freed + _disposed = true; + } + } + + ~Shape() + { + Dispose(false); + } +} \ No newline at end of file diff --git a/roofersharp/RooferSharp/TriangulatedShape.cs b/roofersharp/RooferSharp/TriangulatedShape.cs new file mode 100644 index 00000000..ff34359b --- /dev/null +++ b/roofersharp/RooferSharp/TriangulatedShape.cs @@ -0,0 +1,76 @@ +using System.Numerics; +using System.Runtime.InteropServices; + +namespace RooferSharp; + +/// +/// Triangulated mesh with vertices and faces +/// +public class TriangulatedShape : IDisposable +{ + public Vector3[] Vertices { get; private set; } + public int[] Faces { get; private set; } + + private IntPtr _vertexPtr; + private IntPtr _facePtr; + private bool _disposed = false; + + internal TriangulatedShape(IntPtr vertexPtr, UIntPtr vertexCount, IntPtr facePtr, UIntPtr faceCount) + { + _vertexPtr = vertexPtr; + _facePtr = facePtr; + + var vCount = (int)vertexCount; + var fCount = (int)faceCount; + + // Copy vertices + Vertices = new Vector3[vCount]; + var vertexArray = new float[vCount * 3]; + Marshal.Copy(_vertexPtr, vertexArray, 0, vCount * 3); + + for (int i = 0; i < vCount; i++) + { + Vertices[i] = new Vector3( + vertexArray[i * 3], + vertexArray[i * 3 + 1], + vertexArray[i * 3 + 2] + ); + } + + // Copy faces (convert size_t to int) + Faces = new int[fCount * 3]; + if (UIntPtr.Size == 8) // 64-bit + { + var faceArray = new long[fCount * 3]; + Marshal.Copy(_facePtr, faceArray, 0, fCount * 3); + for (int i = 0; i < faceArray.Length; i++) + { + Faces[i] = (int)faceArray[i]; + } + } + else // 32-bit + { + Marshal.Copy(_facePtr, Faces, 0, fCount * 3); + } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!_disposed) + { + NativeMethods.roofer_free_triangulation(_vertexPtr, _facePtr); + _disposed = true; + } + } + + ~TriangulatedShape() + { + Dispose(false); + } +} \ No newline at end of file diff --git a/roofersharp/RooferSharp/gmp-10.dll b/roofersharp/RooferSharp/gmp-10.dll new file mode 100644 index 00000000..25f7ffb9 Binary files /dev/null and b/roofersharp/RooferSharp/gmp-10.dll differ diff --git a/roofersharp/RooferSharp/mpfr-6.dll b/roofersharp/RooferSharp/mpfr-6.dll new file mode 100644 index 00000000..a84fd243 Binary files /dev/null and b/roofersharp/RooferSharp/mpfr-6.dll differ diff --git a/roofersharp/RooferSharp/roofer.dll b/roofersharp/RooferSharp/roofer.dll new file mode 100644 index 00000000..00211c04 Binary files /dev/null and b/roofersharp/RooferSharp/roofer.dll differ diff --git a/roofersharp/cpp/CMakeLists.txt b/roofersharp/cpp/CMakeLists.txt new file mode 100644 index 00000000..65e98d43 --- /dev/null +++ b/roofersharp/cpp/CMakeLists.txt @@ -0,0 +1,81 @@ +# CMakeLists.txt for C# bindings +# Place in roofer/bindings/csharp/ or adjust paths accordingly + +cmake_minimum_required(VERSION 3.21) + +# If this is the top-level CMakeLists, define project +if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + project(roofer-csharp VERSION 1.0.0) + + # Set C++ standard + set(CMAKE_CXX_STANDARD 17) + set(CMAKE_CXX_STANDARD_REQUIRED ON) + + # Add roofer core - adjust path as needed + # If in bindings/csharp: ../../src/core + # If standalone: point to roofer source + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../../src/core") + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../src/core ${CMAKE_BINARY_DIR}/core) + else() + message(FATAL_ERROR "Cannot find roofer core library. Set roofer source path or build as subdirectory.") + endif() +endif() + +# C# wrapper sources +set(CSHARP_WRAPPER_SOURCES + "${CMAKE_CURRENT_SOURCE_DIR}/roofer_wrapper.cpp" +) + +# Create shared library for C# P/Invoke +add_library(roofer-csharp SHARED ${CSHARP_WRAPPER_SOURCES}) + +# Link to roofer core +target_link_libraries(roofer-csharp + PRIVATE roofer-core +) + +# Set output name (roofer.dll on Windows, roofer.so on Linux) +set_target_properties(roofer-csharp PROPERTIES + OUTPUT_NAME "roofer" + PREFIX "" # Remove 'lib' prefix on Unix +) + +# Platform-specific settings +if(WIN32) + target_compile_definitions(roofer-csharp PRIVATE ROOFER_EXPORTS) + # Output to bin/ for easy access + set_target_properties(roofer-csharp PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/$" + ) +elseif(UNIX AND NOT APPLE) + set_target_properties(roofer-csharp PROPERTIES + VERSION 1.0.0 + SOVERSION 1 + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" + ) +endif() + +# Include directories +target_include_directories(roofer-csharp + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} +) + +# Install +install(TARGETS roofer-csharp + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin +) + +install(FILES + "${CMAKE_CURRENT_SOURCE_DIR}/roofer_wrapper.h" + "${CMAKE_CURRENT_SOURCE_DIR}/Roofer.cs" + DESTINATION include +) + +# Print helpful info +if(WIN32) + message(STATUS "C# DLL will be built: build/bin/Release/roofer.dll") +else() + message(STATUS "C# library will be built: build/lib/roofer.so") +endif() +message(STATUS "Copy Roofer.cs to your C# project and reference the built DLL") \ No newline at end of file diff --git a/roofersharp/cpp/roofer_wrapper.cpp b/roofersharp/cpp/roofer_wrapper.cpp new file mode 100644 index 00000000..e70a955a --- /dev/null +++ b/roofersharp/cpp/roofer_wrapper.cpp @@ -0,0 +1,309 @@ +// Copyright (c) 2018-2024 TU Delft 3D geoinformation group, Ravi Peters (3DGI), +// and Balazs Dukai (3DGI) +// C wrapper implementation for roofer library + +#include "roofer_wrapper.h" +#include +#include +#include + +// Internal wrapper structures +struct RooferConfig { + roofer::ReconstructionConfig config; +}; + +struct RooferMesh { + roofer::Mesh mesh; +}; + +struct RooferMeshArray { + std::vector meshes; +}; + +// Helper function to convert flat array to LinearRing +static void convert_to_linear_ring(const float* points, size_t point_count, roofer::LinearRing& ring) { + for (size_t i = 0; i < point_count; ++i) { + ring.push_back({points[i * 3], points[i * 3 + 1], points[i * 3 + 2]}); + } +} + +// Configuration management +extern "C" { + +RooferConfigHandle roofer_config_create() { + return new RooferConfig(); +} + +void roofer_config_destroy(RooferConfigHandle handle) { + delete static_cast(handle); +} + +void roofer_config_set_complexity_factor(RooferConfigHandle handle, float value) { + static_cast(handle)->config.complexity_factor = value; +} + +void roofer_config_set_clip_ground(RooferConfigHandle handle, int value) { + static_cast(handle)->config.clip_ground = value != 0; +} + +void roofer_config_set_lod(RooferConfigHandle handle, int value) { + static_cast(handle)->config.lod = value; +} + +void roofer_config_set_lod13_step_height(RooferConfigHandle handle, float value) { + static_cast(handle)->config.lod13_step_height = value; +} + +void roofer_config_set_floor_elevation(RooferConfigHandle handle, float value) { + static_cast(handle)->config.floor_elevation = value; +} + +void roofer_config_set_override_with_floor_elevation(RooferConfigHandle handle, int value) { + static_cast(handle)->config.override_with_floor_elevation = value != 0; +} + +void roofer_config_set_plane_detect_k(RooferConfigHandle handle, int value) { + static_cast(handle)->config.plane_detect_k = value; +} + +void roofer_config_set_plane_detect_min_points(RooferConfigHandle handle, int value) { + static_cast(handle)->config.plane_detect_min_points = value; +} + +void roofer_config_set_plane_detect_epsilon(RooferConfigHandle handle, float value) { + static_cast(handle)->config.plane_detect_epsilon = value; +} + +void roofer_config_set_plane_detect_normal_angle(RooferConfigHandle handle, float value) { + static_cast(handle)->config.plane_detect_normal_angle = value; +} + +void roofer_config_set_line_detect_epsilon(RooferConfigHandle handle, float value) { + static_cast(handle)->config.line_detect_epsilon = value; +} + +void roofer_config_set_thres_alpha(RooferConfigHandle handle, float value) { + static_cast(handle)->config.thres_alpha = value; +} + +void roofer_config_set_thres_reg_line_dist(RooferConfigHandle handle, float value) { + static_cast(handle)->config.thres_reg_line_dist = value; +} + +void roofer_config_set_thres_reg_line_ext(RooferConfigHandle handle, float value) { + static_cast(handle)->config.thres_reg_line_ext = value; +} + +int roofer_config_is_valid(RooferConfigHandle handle) { + return static_cast(handle)->config.is_valid() ? 1 : 0; +} + +// Reconstruction functions +RooferMeshArrayHandle roofer_reconstruct_with_ground( + const float* points_roof, size_t points_roof_count, + const float* points_ground, size_t points_ground_count, + const float* footprint_exterior, size_t footprint_exterior_count, + const float* footprint_interiors, const size_t* interior_counts, size_t interior_ring_count, + RooferConfigHandle config) { + + // Convert roof points + roofer::PointCollection points_roof_pc; + for (size_t i = 0; i < points_roof_count; ++i) { + points_roof_pc.push_back({points_roof[i * 3], points_roof[i * 3 + 1], points_roof[i * 3 + 2]}); + } + + // Convert ground points + roofer::PointCollection points_ground_pc; + for (size_t i = 0; i < points_ground_count; ++i) { + points_ground_pc.push_back({points_ground[i * 3], points_ground[i * 3 + 1], points_ground[i * 3 + 2]}); + } + + // Convert footprint + roofer::LinearRing linear_ring; + convert_to_linear_ring(footprint_exterior, footprint_exterior_count, linear_ring); + + // Add interior rings + size_t offset = 0; + for (size_t i = 0; i < interior_ring_count; ++i) { + roofer::LinearRing interior_ring; + convert_to_linear_ring(footprint_interiors + offset * 3, interior_counts[i], interior_ring); + linear_ring.interior_rings().push_back(interior_ring); + offset += interior_counts[i]; + } + + // Get config + roofer::ReconstructionConfig cfg; + if (config) { + cfg = static_cast(config)->config; + } + + // Reconstruct + auto meshes = roofer::reconstruct(points_roof_pc, points_ground_pc, linear_ring, cfg); + + // Create result + auto* result = new RooferMeshArray(); + result->meshes = std::move(meshes); + return result; +} + +RooferMeshArrayHandle roofer_reconstruct( + const float* points_roof, size_t points_roof_count, + const float* footprint_exterior, size_t footprint_exterior_count, + const float* footprint_interiors, const size_t* interior_counts, size_t interior_ring_count, + RooferConfigHandle config) { + + // Convert roof points + roofer::PointCollection points_roof_pc; + for (size_t i = 0; i < points_roof_count; ++i) { + points_roof_pc.push_back({points_roof[i * 3], points_roof[i * 3 + 1], points_roof[i * 3 + 2]}); + } + + // Convert footprint + roofer::LinearRing linear_ring; + convert_to_linear_ring(footprint_exterior, footprint_exterior_count, linear_ring); + + // Add interior rings + size_t offset = 0; + for (size_t i = 0; i < interior_ring_count; ++i) { + roofer::LinearRing interior_ring; + convert_to_linear_ring(footprint_interiors + offset * 3, interior_counts[i], interior_ring); + linear_ring.interior_rings().push_back(interior_ring); + offset += interior_counts[i]; + } + + // Get config + roofer::ReconstructionConfig cfg; + if (config) { + cfg = static_cast(config)->config; + } + + // Reconstruct + auto meshes = roofer::reconstruct(points_roof_pc, linear_ring, cfg); + + // Create result + auto* result = new RooferMeshArray(); + result->meshes = std::move(meshes); + return result; +} + +// Mesh array functions +size_t roofer_mesh_array_size(RooferMeshArrayHandle handle) { + return static_cast(handle)->meshes.size(); +} + +RooferMeshHandle roofer_mesh_array_get(RooferMeshArrayHandle handle, size_t index) { + auto* array = static_cast(handle); + if (index >= array->meshes.size()) return nullptr; + + auto* mesh = new RooferMesh(); + mesh->mesh = array->meshes[index]; + return mesh; +} + +void roofer_mesh_array_destroy(RooferMeshArrayHandle handle) { + delete static_cast(handle); +} + +// Mesh functions +size_t roofer_mesh_polygon_count(RooferMeshHandle handle) { + return static_cast(handle)->mesh.get_polygons().size(); +} + +size_t roofer_mesh_get_polygon_exterior_size(RooferMeshHandle handle, size_t poly_index) { + auto& polygons = static_cast(handle)->mesh.get_polygons(); + if (poly_index >= polygons.size()) return 0; + return polygons[poly_index].size(); +} + +void roofer_mesh_get_polygon_exterior(RooferMeshHandle handle, size_t poly_index, float* points) { + auto& polygons = static_cast(handle)->mesh.get_polygons(); + if (poly_index >= polygons.size()) return; + + const auto& poly = polygons[poly_index]; + for (size_t i = 0; i < poly.size(); ++i) { + points[i * 3] = poly[i][0]; + points[i * 3 + 1] = poly[i][1]; + points[i * 3 + 2] = poly[i][2]; + } +} + +size_t roofer_mesh_get_polygon_interior_count(RooferMeshHandle handle, size_t poly_index) { + auto& polygons = static_cast(handle)->mesh.get_polygons(); + if (poly_index >= polygons.size()) return 0; + return polygons[poly_index].interior_rings().size(); +} + +size_t roofer_mesh_get_polygon_interior_size(RooferMeshHandle handle, size_t poly_index, size_t interior_index) { + auto& polygons = static_cast(handle)->mesh.get_polygons(); + if (poly_index >= polygons.size()) return 0; + + const auto& interiors = polygons[poly_index].interior_rings(); + if (interior_index >= interiors.size()) return 0; + return interiors[interior_index].size(); +} + +void roofer_mesh_get_polygon_interior(RooferMeshHandle handle, size_t poly_index, size_t interior_index, float* points) { + auto& polygons = static_cast(handle)->mesh.get_polygons(); + if (poly_index >= polygons.size()) return; + + const auto& interiors = polygons[poly_index].interior_rings(); + if (interior_index >= interiors.size()) return; + + const auto& interior = interiors[interior_index]; + for (size_t i = 0; i < interior.size(); ++i) { + points[i * 3] = interior[i][0]; + points[i * 3 + 1] = interior[i][1]; + points[i * 3 + 2] = interior[i][2]; + } +} + +// Triangulation +int roofer_triangulate_mesh( + RooferMeshHandle mesh_handle, + float** out_vertices, size_t* out_vertex_count, + size_t** out_faces, size_t* out_face_count) { + + auto* mesh_wrapper = static_cast(mesh_handle); + auto tri_mesh = roofer::triangulate_mesh(mesh_wrapper->mesh); + + // Build vertex map + std::map vertex_map; + std::vector vertices; + std::vector> faces; + + for (const auto& triangle : tri_mesh) { + for (const auto& vertex : triangle) { + if (vertex_map.find(vertex) == vertex_map.end()) { + vertex_map[vertex] = vertex_map.size(); + vertices.push_back(vertex); + } + } + faces.push_back({vertex_map[triangle[0]], vertex_map[triangle[1]], vertex_map[triangle[2]]}); + } + + // Allocate output arrays + *out_vertex_count = vertices.size(); + *out_vertices = new float[vertices.size() * 3]; + for (size_t i = 0; i < vertices.size(); ++i) { + (*out_vertices)[i * 3] = vertices[i][0]; + (*out_vertices)[i * 3 + 1] = vertices[i][1]; + (*out_vertices)[i * 3 + 2] = vertices[i][2]; + } + + *out_face_count = faces.size(); + *out_faces = new size_t[faces.size() * 3]; + for (size_t i = 0; i < faces.size(); ++i) { + (*out_faces)[i * 3] = faces[i][0]; + (*out_faces)[i * 3 + 1] = faces[i][1]; + (*out_faces)[i * 3 + 2] = faces[i][2]; + } + + return 1; +} + +void roofer_free_triangulation(float* vertices, size_t* faces) { + delete[] vertices; + delete[] faces; +} + +} // extern "C" diff --git a/roofersharp/cpp/roofer_wrapper.h b/roofersharp/cpp/roofer_wrapper.h new file mode 100644 index 00000000..880eff89 --- /dev/null +++ b/roofersharp/cpp/roofer_wrapper.h @@ -0,0 +1,80 @@ +// Copyright (c) 2018-2024 TU Delft 3D geoinformation group, Ravi Peters (3DGI), +// and Balazs Dukai (3DGI) +// C wrapper for roofer library to enable C# P/Invoke interop + +#ifndef ROOFER_WRAPPER_H +#define ROOFER_WRAPPER_H + +#ifdef _WIN32 +#define ROOFER_EXPORT __declspec(dllexport) +#else +#define ROOFER_EXPORT __attribute__((visibility("default"))) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// Opaque handle types +typedef void* RooferConfigHandle; +typedef void* RooferMeshHandle; +typedef void* RooferMeshArrayHandle; + +// Configuration management +ROOFER_EXPORT RooferConfigHandle roofer_config_create(); +ROOFER_EXPORT void roofer_config_destroy(RooferConfigHandle handle); +ROOFER_EXPORT void roofer_config_set_complexity_factor(RooferConfigHandle handle, float value); +ROOFER_EXPORT void roofer_config_set_clip_ground(RooferConfigHandle handle, int value); +ROOFER_EXPORT void roofer_config_set_lod(RooferConfigHandle handle, int value); +ROOFER_EXPORT void roofer_config_set_lod13_step_height(RooferConfigHandle handle, float value); +ROOFER_EXPORT void roofer_config_set_floor_elevation(RooferConfigHandle handle, float value); +ROOFER_EXPORT void roofer_config_set_override_with_floor_elevation(RooferConfigHandle handle, int value); +ROOFER_EXPORT void roofer_config_set_plane_detect_k(RooferConfigHandle handle, int value); +ROOFER_EXPORT void roofer_config_set_plane_detect_min_points(RooferConfigHandle handle, int value); +ROOFER_EXPORT void roofer_config_set_plane_detect_epsilon(RooferConfigHandle handle, float value); +ROOFER_EXPORT void roofer_config_set_plane_detect_normal_angle(RooferConfigHandle handle, float value); +ROOFER_EXPORT void roofer_config_set_line_detect_epsilon(RooferConfigHandle handle, float value); +ROOFER_EXPORT void roofer_config_set_thres_alpha(RooferConfigHandle handle, float value); +ROOFER_EXPORT void roofer_config_set_thres_reg_line_dist(RooferConfigHandle handle, float value); +ROOFER_EXPORT void roofer_config_set_thres_reg_line_ext(RooferConfigHandle handle, float value); +ROOFER_EXPORT int roofer_config_is_valid(RooferConfigHandle handle); + +// Reconstruction functions +ROOFER_EXPORT RooferMeshArrayHandle roofer_reconstruct_with_ground( + const float* points_roof, size_t points_roof_count, + const float* points_ground, size_t points_ground_count, + const float* footprint_exterior, size_t footprint_exterior_count, + const float* footprint_interiors, const size_t* interior_counts, size_t interior_ring_count, + RooferConfigHandle config); + +ROOFER_EXPORT RooferMeshArrayHandle roofer_reconstruct( + const float* points_roof, size_t points_roof_count, + const float* footprint_exterior, size_t footprint_exterior_count, + const float* footprint_interiors, const size_t* interior_counts, size_t interior_ring_count, + RooferConfigHandle config); + +// Mesh array functions +ROOFER_EXPORT size_t roofer_mesh_array_size(RooferMeshArrayHandle handle); +ROOFER_EXPORT RooferMeshHandle roofer_mesh_array_get(RooferMeshArrayHandle handle, size_t index); +ROOFER_EXPORT void roofer_mesh_array_destroy(RooferMeshArrayHandle handle); + +// Mesh functions +ROOFER_EXPORT size_t roofer_mesh_polygon_count(RooferMeshHandle handle); +ROOFER_EXPORT size_t roofer_mesh_get_polygon_exterior_size(RooferMeshHandle handle, size_t poly_index); +ROOFER_EXPORT void roofer_mesh_get_polygon_exterior(RooferMeshHandle handle, size_t poly_index, float* points); +ROOFER_EXPORT size_t roofer_mesh_get_polygon_interior_count(RooferMeshHandle handle, size_t poly_index); +ROOFER_EXPORT size_t roofer_mesh_get_polygon_interior_size(RooferMeshHandle handle, size_t poly_index, size_t interior_index); +ROOFER_EXPORT void roofer_mesh_get_polygon_interior(RooferMeshHandle handle, size_t poly_index, size_t interior_index, float* points); + +// Triangulation +ROOFER_EXPORT int roofer_triangulate_mesh( + RooferMeshHandle mesh_handle, + float** out_vertices, size_t* out_vertex_count, + size_t** out_faces, size_t* out_face_count); +ROOFER_EXPORT void roofer_free_triangulation(float* vertices, size_t* faces); + +#ifdef __cplusplus +} +#endif + +#endif // ROOFER_WRAPPER_H