From 6ec18905acdb9b30e5bfc5eee9be0182ce1744c9 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 26 Oct 2023 20:34:55 +0100 Subject: Move OpenMesh/GLM compatibility structs to common place --- assetFactory/modelFactoryMesh.h | 27 +-------------------------- thirdparty/openmesh/glmcompat.h | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 26 deletions(-) create mode 100644 thirdparty/openmesh/glmcompat.h diff --git a/assetFactory/modelFactoryMesh.h b/assetFactory/modelFactoryMesh.h index 32e7ab5..2129fb5 100644 --- a/assetFactory/modelFactoryMesh.h +++ b/assetFactory/modelFactoryMesh.h @@ -2,36 +2,11 @@ #include "modelFactoryMesh_fwd.h" #include -#include #include -#include #include #include #include - -namespace glm { - template - auto - norm(const vec & v) - { - return length(v); - } - - template - auto - vectorize(vec & v, S scalar) - { - v = vec {static_cast(scalar)}; - } -} - -namespace OpenMesh { - template struct vector_traits> { - using vector_type = glm::vec; - using value_type = T; - static constexpr glm::length_t size_ = L; - }; -} +#include struct ModelFactoryTraits : public OpenMesh::DefaultTraits { FaceAttributes(OpenMesh::Attributes::Normal | OpenMesh::Attributes::Status | OpenMesh::Attributes::Color); diff --git a/thirdparty/openmesh/glmcompat.h b/thirdparty/openmesh/glmcompat.h new file mode 100644 index 0000000..708b1a6 --- /dev/null +++ b/thirdparty/openmesh/glmcompat.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include + +namespace glm { + template + auto + norm(const vec & v) + { + return length(v); + } + + template + auto + vectorize(vec & v, S scalar) + { + v = vec {static_cast(scalar)}; + } +} + +namespace OpenMesh { + template struct vector_traits> { + using vector_type = glm::vec; + using value_type = T; + static constexpr glm::length_t size_ = L; + }; +} -- cgit v1.2.3 From 16bec12e3e75e95d251745f904ac4e15af9c9724 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 28 Oct 2023 02:34:45 +0100 Subject: Initial OpenMesh based terrain data and tests --- game/terrain2.cpp | 66 ++++++++++++++ game/terrain2.h | 24 +++++ test/Jamfile.jam | 1 + test/fixtures/height/SD19.asc | 205 ++++++++++++++++++++++++++++++++++++++++++ test/test-terrain.cpp | 48 ++++++++++ 5 files changed, 344 insertions(+) create mode 100644 game/terrain2.cpp create mode 100644 game/terrain2.h create mode 100644 test/fixtures/height/SD19.asc create mode 100644 test/test-terrain.cpp diff --git a/game/terrain2.cpp b/game/terrain2.cpp new file mode 100644 index 0000000..83df3fa --- /dev/null +++ b/game/terrain2.cpp @@ -0,0 +1,66 @@ +#include "terrain2.h" +#include + +TerrainMesh::TerrainMesh(const std::filesystem::path & input) +{ + size_t ncols = 0, nrows = 0, xllcorner = 0, yllcorner = 0, cellsize = 0; + std::map properties { + {"ncols", &ncols}, + {"nrows", &nrows}, + {"xllcorner", &xllcorner}, + {"yllcorner", &yllcorner}, + {"cellsize", &cellsize}, + }; + std::ifstream f {input}; + while (!properties.empty()) { + std::string property; + f >> property; + f >> *properties.at(property); + properties.erase(property); + } + std::vector vertices; + vertices.reserve(ncols * nrows); + for (size_t row = 0; row < nrows; ++row) { + for (size_t col = 0; col < ncols; ++col) { + float height = 0; + f >> height; + vertices.push_back(add_vertex({xllcorner + (col * cellsize), yllcorner + (row * cellsize), height})); + } + } + if (!f.good()) { + throw std::runtime_error("Couldn't read terrain file"); + } + for (size_t row = 1; row < nrows; ++row) { + for (size_t col = 1; col < ncols; ++col) { + add_face({ + vertices[ncols * (row - 1) + (col - 1)], + vertices[ncols * (row - 0) + (col - 0)], + vertices[ncols * (row - 0) + (col - 1)], + }); + add_face({ + vertices[ncols * (row - 1) + (col - 1)], + vertices[ncols * (row - 1) + (col - 0)], + vertices[ncols * (row - 0) + (col - 0)], + }); + } + } + update_face_normals(); + update_vertex_normals(); +}; + +bool +TerrainMesh::triangleContainsPoint(const glm::vec2 p, const glm::vec2 a, const glm::vec2 b, const glm::vec2 c) +{ + const auto det = (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x); + + return det * ((b.x - a.x) * (p.y - a.y) - (b.y - a.y) * (p.x - a.x)) >= 0 + && det * ((c.x - b.x) * (p.y - b.y) - (c.y - b.y) * (p.x - b.x)) >= 0 + && det * ((a.x - c.x) * (p.y - c.y) - (a.y - c.y) * (p.x - c.x)) >= 0; +} + +bool +TerrainMesh::triangleContainsPoint(const glm::vec2 p, FaceHandle face) const +{ + auto vertices = cfv_iter(face); + return triangleContainsPoint(p, point(*vertices++), point(*vertices++), point(*vertices++)); +} diff --git a/game/terrain2.h b/game/terrain2.h new file mode 100644 index 0000000..d2da8d0 --- /dev/null +++ b/game/terrain2.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include +#include +#include + +struct TerrainTraits : public OpenMesh::DefaultTraits { + FaceAttributes(OpenMesh::Attributes::Normal | OpenMesh::Attributes::Status); + EdgeAttributes(OpenMesh::Attributes::Status); + VertexAttributes(OpenMesh::Attributes::Normal | OpenMesh::Attributes::Status); + HalfedgeAttributes(OpenMesh::Attributes::Normal | OpenMesh::Attributes::Status); + using Point = glm::vec3; + using Normal = glm::vec3; +}; + +class TerrainMesh : public OpenMesh::TriMesh_ArrayKernelT { +public: + explicit TerrainMesh(const std::filesystem::path &); + +protected: + [[nodiscard]] static bool triangleContainsPoint(const glm::vec2, const glm::vec2, const glm::vec2, const glm::vec2); + [[nodiscard]] bool triangleContainsPoint(const glm::vec2, FaceHandle) const; +}; diff --git a/test/Jamfile.jam b/test/Jamfile.jam index e221af7..eab3996 100644 --- a/test/Jamfile.jam +++ b/test/Jamfile.jam @@ -60,6 +60,7 @@ run test-worker.cpp ; run test-instancing.cpp : : : test ; run test-glContainer.cpp : : : test ; run test-pack.cpp : : : test ; +run test-terrain.cpp : : : test ..//OpenMeshCore ; compile test-static-enumDetails.cpp ; compile test-static-stream_support.cpp ; explicit perf-assetFactory ; diff --git a/test/fixtures/height/SD19.asc b/test/fixtures/height/SD19.asc new file mode 100644 index 0000000..3cdd711 --- /dev/null +++ b/test/fixtures/height/SD19.asc @@ -0,0 +1,205 @@ +ncols 200 +nrows 200 +xllcorner 310000 +yllcorner 490000 +cellsize 50 +32.8 33.2 33.5 35.3 37.7 41.2 42.5 43.5 43.7 40.1 38.1 36.1 36 38.4 42.3 56.3 65.9 62.2 57.5 53.2 48.6 47.3 40.5 34.7 31.3 32.5 32.2 28.9 24.6 25.4 26.3 26 25 24.4 23.8 22.3 18.4 19 20.5 22.7 29.1 35 39.3 46 53 53.9 46.8 39 39.6 37.9 36.7 35.6 35.1 35.1 31.6 32.1 33 33.7 33.6 34.6 34.7 35.5 36.5 36.8 37 36.9 37.2 38 38.5 37.8 38.4 39.2 39.3 39.1 39.1 38.3 37.3 37.1 36.5 36.8 37.2 37.7 39.1 44.2 50.3 53.9 50.7 46.5 45.5 42.4 39.3 34.4 35.7 37 35.8 34.5 32.5 28.7 27.6 27.1 25.9 25.8 26 27.2 26.9 26.7 26.9 26.5 26.6 25.5 26.3 28.5 32.4 36.2 38.4 38.2 34.7 31.3 31 31.5 31 31.2 33.2 33.8 35.4 38 41.4 42.1 43.3 44.5 45 45.1 46 46.5 45.9 47.2 46.9 47.1 54.5 60.8 73.8 86 83.5 79.3 75.3 70.8 69.9 56.7 60.4 62.1 63.1 65.8 71 68.7 67.6 68 70.5 74.4 76.2 77.7 78.2 81.5 87.1 94.1 101.9 112.7 126 137 146.8 168 201.2 210.7 221.3 202.4 173 203.5 224.5 234.6 236.7 242.5 250.1 243.3 245 247 258.2 262.1 260 255.6 256 253.7 262.6 264.2 279.4 297.3 307 307.8 308.7 307.3 305.8 297.2 +32.7 33 33.2 34 35.8 37.9 39.2 39.9 39.9 37.4 36.5 35.1 35.2 37.2 44.8 61.8 69 63.9 58.2 50.7 47.5 44.6 37.1 34.1 32.3 28.2 29 27.8 28.6 30.3 27.7 25.2 24.5 24 22.3 19 16.6 16.7 18 22.2 29.9 31.3 35.6 40.2 39 34.5 31 31.5 36.5 39.1 38.1 37.1 36.8 36.1 33.3 31.9 32.4 32.8 32.9 33.2 35.5 37.1 37.6 37.8 37.7 37.1 37.3 37.5 37.9 38.1 38.7 41.4 46.3 48.2 43.8 39.9 37.1 36.6 36 36.2 36.9 36.8 37.9 40.4 45.6 48.3 48.1 47.7 47.8 45.4 40.3 33.1 31.2 31.2 32.3 33.5 29.5 27.2 27 26 25 25.5 25.1 25.7 26.1 26.1 25.7 25.9 23.5 25.9 30.6 32.4 33.9 38.3 37.5 36.3 36.6 36.3 37.3 38.4 37.1 36 35.4 36 36.6 38.5 41.3 41 41.9 42.4 43 44.2 45.4 46.4 47.9 48.8 49.3 50 54.5 62.4 76.8 82.4 82.7 83.8 84.1 83.7 81.6 72.4 63.6 64.9 65.1 66.1 67.3 69.4 75.6 82.6 89.1 95.7 98.3 98 98.2 101.9 107.9 118.9 132.5 137.6 148.3 174 180.3 206.9 232.6 238.7 240 235.3 226 223.3 235.7 250.1 257.1 259.4 261.2 253.4 253.9 251.9 254.9 257.9 260.4 259.4 260.6 264.7 266.5 273.5 309.2 319.4 316.4 313.4 320.9 323.2 317.1 295.8 +32.5 32.6 32.8 33.2 34.3 35.1 35.2 35.3 35.4 35.7 34.8 34 34.1 36.5 46.6 59.9 64.2 62.8 54.7 46 42.9 37.5 33.4 30.3 30.9 31.2 30.1 30.9 32.8 31.3 27.5 25 23.7 19.6 16.6 16 15.8 16.1 17.3 19 19.6 21.5 24.5 22.5 22.2 23.2 26 31 35.4 37.5 37.6 37.3 36.6 36 33.4 31.4 31.9 32.1 32.4 32.6 34.3 35.8 36.8 36.7 37.3 37.2 38.1 39.9 40 40.5 40.1 40.8 45 47.8 46.4 40.9 38 36.2 35.9 35.6 35.9 36.3 36.1 38.9 42.7 48 53.1 52 49.4 45 37.8 32.4 30.2 31.9 39.6 36.7 26.4 26.2 26.3 24.4 24.3 24.3 24.3 24.8 24.8 25.1 25.3 25.5 27.2 26.8 31 33 35.1 35.8 38 41.2 45.8 47.3 47.6 46.9 45.7 43.6 41.3 42.7 42.9 41.2 42.5 42.9 43.7 44.9 45.2 46.8 48.2 49.1 50.4 52.6 53.3 52.3 57.5 67.2 73.7 82.6 86.7 90.6 92.2 89.6 85 72.9 66.8 66.6 68 67.9 78.3 88.1 97.4 105.1 110.2 115.8 114 111.8 114.6 118.2 125.1 134.3 150.2 159.6 172.1 211.8 226.3 244.8 255.3 255.7 251.9 245.1 233.8 230.4 239.1 243.4 251.7 255.4 258.6 260.5 261.8 263.2 263.1 258.5 258.7 263.2 261.9 264.1 268.4 275.2 291 303.7 299.5 319.4 320.6 319.2 320.2 300.5 +32.2 32.9 33.2 33.6 33.8 34.4 34.3 33.5 33.1 33.9 33.4 32.5 32.9 35.7 48.2 58.4 59.7 56.2 47.3 41.6 37 32.2 29.1 28.1 29.4 30.4 31.1 31 33.6 31.2 27.7 24.3 21.4 17.3 14.8 15 15.4 16.3 17.2 17.5 17.7 18 18.8 18.6 17.3 20.9 25.7 31.4 34.6 36.2 37 35.7 34.8 34.3 32.2 30.9 31.4 31.6 31.7 32.4 33.4 34.8 35 36 37.4 37.9 42.1 48.7 46.7 45.5 45.4 45.1 45.1 45.4 43.5 41 38.2 35.9 35.2 34.9 34.6 34.5 36.1 40.5 49.1 58.5 62.3 55.1 48.7 42.3 33.6 29.7 28.7 32.6 32.7 25.6 22.5 24.8 24.2 23.9 23.3 23.4 23.6 24 24.4 24.5 24.6 25.9 27.4 30 33.2 35.4 37.2 40.5 46.6 57.6 60.6 64 59.8 56.8 56.3 55.2 53.3 56.1 55.1 54.2 57.9 58.1 57.7 58.2 55.8 56.5 59.8 69.2 66.2 67.6 69.6 71.1 75.3 85.1 92.7 95.6 99.9 109.8 102.9 96.2 87.4 78.8 71.7 72.4 70.7 75.5 91 109.2 118.3 115.5 119.2 121.9 121.3 123.1 123.2 124.8 130.6 144.7 165.5 186.2 204.6 254.4 252.3 266.5 270.4 257.6 256.4 251.3 236.8 233.1 235.4 239.3 240.3 252.8 256 264.4 267.6 264.3 263.7 264.1 262.5 268.1 266.2 264.6 267.3 274.9 280.9 287.6 296.8 313.9 312.9 310 308.7 294.5 +31.6 32.4 32.9 33.5 33.6 33.6 33.7 32.6 32.5 32 31.7 32 32.5 35.5 49.6 57.6 55.5 50 42.5 37.5 33.9 31.1 28.5 27.8 29.2 28.9 28.3 27.6 29.9 28.2 24.8 21.9 18.6 15.6 14 14.5 15.1 15.8 16.2 16.4 16.4 16.4 16.5 17.1 18.6 22.5 26.6 31.6 34.7 35.8 35.4 33.9 33.1 32 30.5 30.5 30.7 30.8 30.8 32.3 33.4 34.2 35.2 37.2 38.1 44 57.2 61.3 61.4 58.7 58.8 55.6 52.7 48.9 46.4 42.5 38.4 35.1 34.5 34.1 34 34.4 36.7 47.6 55.1 58.9 59 51.9 43.2 35.1 27.9 25.3 26.9 30.5 27.2 22.4 21.6 22.3 23.1 22.7 22.8 23.1 24 24.4 22 24.8 25.2 25.9 29.9 34.6 40 40.8 42.2 50.2 58.5 66.1 72.7 72.2 67.9 67 66.9 65.9 67.3 71.7 72.3 71.6 77 79 78.8 80.8 77.9 80.9 81.2 87.8 89.8 81.4 84.8 87.8 93.8 105.2 106.7 109.5 119.3 121 108.6 100 94 89.7 93.5 72 86 87.7 93.3 109.9 119.1 122.6 125.1 127.1 126.6 128.7 130.4 135.5 144.2 163.6 187.6 216.8 234.2 270.4 273.8 271 271 258.9 258.5 251.5 241.3 238.8 236.5 239.5 238.5 250 256.9 261.5 269.2 267 268.3 270.2 268.8 270.7 274.4 267 277.4 277.7 287.8 287.3 291.1 303.1 307.8 303.9 297.8 288.5 +30.9 31.7 32.2 32.5 32.8 32.5 31.5 31.1 31.2 31 31.3 31.9 32.2 34.9 44.1 51.8 48.8 44.7 39.4 34.7 32.5 30.4 27.9 26.5 27.9 25.5 23.9 24.5 24.9 24.8 20.4 17.2 15.9 14.1 14.4 14.7 14.9 15.1 15.3 15.6 15.9 16.2 16.6 16.7 19.1 21.9 26.8 30.9 33 33.6 33.5 32.5 31 32.6 32.1 30.3 30.3 30.1 30.6 32.1 33.3 34.7 36.3 38.6 42.6 49.1 58.5 62.5 67.3 70.9 68.6 60 55.2 52 50.2 42.8 36.9 34.4 34 33.7 33.4 33.9 37.6 44.5 49 49.1 44.4 40.6 36.5 29.2 24.4 23.8 24.7 26.2 23.1 21.2 21.6 22.3 22.8 22.4 23.4 23.8 23.8 23.2 24.3 24.5 24.8 25.7 38.8 43.6 50.8 52.1 53.8 66 78.1 78.1 84.3 81.1 80.2 81.5 80.8 81 83.3 83.9 87.7 89.1 98.5 102.3 99.2 106.2 102.9 101 105.5 104.9 104.7 95.2 97.6 108.7 121 130 127 123 126.3 118.1 111 108.1 117.8 103.2 104.2 78.5 99.1 108.1 107.8 108.1 114 121.6 131.9 130.9 131.5 135.4 140.2 152.3 168.3 189.9 233.4 244.8 244.5 255.2 277.8 275.1 265.7 263.6 255 251.1 243.6 240.2 239.1 241.8 238.4 246.2 263.1 259.8 259.4 267.8 272.5 276.2 274.7 281.6 283.1 277.1 281.5 282.1 285 303.5 303.7 298.6 301.1 304.3 296.2 287.7 +30.3 30.5 30.5 31.2 32.1 31.8 30.8 30.3 30 30.7 31.4 31.7 32.2 33.4 37.5 47.1 44.7 42.2 37.5 34.2 31.9 29.1 26.7 24.3 23.9 22 20 19.8 20.8 21 16.1 14.7 14.3 14.4 14.5 14.7 15.2 15.4 15.5 15.7 16 16.4 16.8 17.2 18.7 21.2 24.2 27.3 28.2 29 29.8 29.7 30 30.3 32.3 32 30.2 30.2 31.1 32.7 35.3 36.4 37.9 43.2 48.4 57.6 64.1 65.1 64.8 65.8 67.5 61.8 55.4 49.5 44.1 37.8 35.4 34.1 33.8 33.6 33.2 33.2 35.9 40.3 40.3 37.6 33.1 31.5 29.8 23.1 20.4 20.5 21 22.1 21.7 21 21.5 22.3 22 22.4 22.8 23.2 22.9 23.1 25.3 26.9 29.5 37.1 50.3 57.6 68.4 69.7 71.5 87.7 106 110.3 102.8 106.4 101.7 100.9 97.4 94.5 97.4 97.6 102.6 105.1 110 116.4 116.9 125.1 125.9 124.7 123.3 121.5 120.4 112.7 120.2 130.7 141.7 148 140.4 133.7 128.2 124.2 119.7 118.8 123.1 119.3 97.7 86.3 111.9 133 136.8 131.3 126 122 128.8 136.2 138.2 144.2 152.5 170.3 204.7 234.4 244.8 248.4 254.6 252.9 258.4 266 265.4 258.1 257 247.8 244.2 242.7 239.9 241 239.9 243.4 251.1 254.9 259.1 272.1 280.1 281.5 277.9 280 280.1 274.1 281.2 284.2 301.1 307.4 303.9 303.4 300.7 298.5 292.8 287.2 +28.3 29.3 29.6 29.8 30.9 31.1 30.7 29.6 29.9 30.6 31.1 31.6 32.2 32.9 34.7 39.3 40.4 40.1 38.2 34.7 31.4 28.2 24.9 22.4 20.5 17.7 14.5 14.4 14.6 14.5 13.5 14.5 14.6 14.7 14.7 15.1 15.5 15.7 16 16.3 16.8 17 17.4 17.6 18.2 19.6 21.2 22.4 23.3 24.3 25.4 27.8 29.3 30.2 30.5 31.1 30.8 32 33.1 34.4 38.3 43.3 49.3 57 59.2 65.9 71.3 74.2 75.1 72.9 68.4 62.9 56.2 50.1 44.4 38.8 35.5 34.2 33.9 33.6 33.2 32.8 34.8 35.7 36.9 33.7 31.9 30.4 25.5 19.9 19.3 19.6 20.1 20.2 20.8 20.8 21.2 21.8 22.3 22.2 22.5 20.7 22.7 27.5 32.6 34.5 39.2 47.1 54.6 67.2 82.1 87.4 84.3 108.1 104.5 114.1 118.9 124.4 126.9 125 122 120.5 116.6 119.9 123.3 122 121.5 126.5 128.2 127 128.6 140.7 136.4 130.9 133.6 131.4 137.1 137.8 139.7 137 136.7 136.7 135.4 131.5 130 128.4 125.8 120 92.1 119 124.9 147.2 154.1 151 144 133.8 135.1 143 142 153.9 169.2 196.6 243.4 246.4 245.1 245.8 247.6 258 258.8 256.6 262.4 260.7 250.1 247.2 244.1 243.1 241.4 242 241.3 241.8 246.6 258.3 264.7 274.1 285.3 287.4 278.2 271.6 266.4 272.9 286.1 282.9 296.8 300.5 309.6 310.1 306.5 295.9 290.4 289.2 +26.6 27 27.8 29.3 30.6 30.6 29.8 29.2 29.8 30.9 32.5 33.3 32.8 33 33.5 34.5 36.8 41.2 40.4 34.8 29.2 26 22.2 20 16.7 14.6 14 14.6 14.7 14.6 14.7 14.7 14.8 13.5 15.1 15.9 16.5 16.8 17.2 17.4 17.7 17.8 18.3 18.4 18.4 19 19.7 20.4 21.2 23 24.9 26.5 27.6 28.5 29.3 31 33.7 35.1 35.8 37.1 43.2 59.4 72.2 75.8 79.8 83.5 89.5 94.2 95.5 93.4 84.3 77 68.3 58.1 50.5 44.5 38.9 35.6 35 33.9 33.5 33.1 32.8 30.9 30.4 31.3 33.1 27.4 22.7 19.1 19.4 19.6 18.3 19.8 20.3 20.4 19.9 21.2 21.7 22.1 22.3 22.9 25.6 36.4 38.5 41.9 52.6 71.2 77.4 84.3 90.9 97 91 92.1 105.9 108.8 125.5 132.7 136.1 140.3 147.8 140.8 139.2 136.5 144.7 146 141.3 137.9 132.6 129.2 132 150.1 148.5 137.2 142.5 138.4 132.1 133.2 136.7 139.5 142.8 143.2 149 146.9 144.8 137 130.4 126.8 101.9 140.6 148.8 159.8 163 155.9 148.2 138.1 144.7 146.3 151 169.5 202.4 211.6 221.9 231.3 232 239.8 249.2 252 255.7 255.9 253.1 252.3 251.3 246.9 245.3 242.7 242.5 244 243.7 244.2 246.1 250.9 262.6 276.2 283.6 279.1 272.1 265 262.1 265.6 272.9 280.9 297.8 319.5 315.4 313.3 305 294.7 291.1 292.8 +25.1 25.1 26.6 28.1 29.2 29.3 28.7 29 29.3 32 35.1 37.1 36.4 33.8 33.4 35 38.6 46.5 39.6 32.7 26.3 22.2 19.2 16 14.2 12.8 14.4 15 15.5 14.9 15.2 15.4 16.1 16.1 17.4 18.1 18.4 18.4 18.5 18.6 19 19.6 20.2 20 19.8 19.3 19.3 19.7 20.4 22.3 24 25.3 26.6 27.5 29.5 33.1 36.7 39.1 42.9 54.3 65.5 77.2 95.6 102.1 106.7 115.4 124.1 129.3 128.4 110.2 97.9 94.4 83.7 73.9 61.3 50.2 42.7 39 36.4 35.3 37.1 40.2 40.3 37.5 31 27.9 24.9 22.1 19.1 19 19.7 19.5 19.8 20.5 20.7 20.9 21.2 20.9 19.3 20.1 25.9 31.4 37.4 43.5 45.8 53 70.3 87.8 95.5 101.3 107.3 102.4 98.7 93.4 101.4 112.2 123.8 131.4 146.6 147.6 148.9 154.4 156.7 156 147.3 147.1 145.2 139.4 133 130.1 140.6 146.9 141.9 134.4 130.4 133.5 136.5 141.4 148.1 152.1 152 152.4 160 159.1 154.8 143.5 135.1 141.3 120.6 161.7 158.2 168.5 165 159.5 152.9 145.2 149.4 150.6 163 188 196.5 192.6 199.4 211.3 217.8 243.3 250.7 253.4 256.1 258.4 253.1 250.6 249 247.1 246.4 243.4 242.4 244.6 244.2 245.4 245.5 245.4 261.4 278.8 284.7 266.7 260.3 259.8 263.2 266.7 271.3 283 304.2 317.8 317.7 309.9 301.7 294.8 295.2 298.4 +23.8 24.4 25.6 27.1 28 28.5 28.5 28.3 29.4 32.9 36.5 38.7 38.2 34.2 33.6 41 41.4 38.5 33.4 29.2 22 19 15.5 14.2 13.7 14 14.2 15 15.3 15.3 15.7 17.2 18.2 19 19.8 20.3 20.3 19.9 19.4 20 21.1 22 21.7 21.4 21.2 21 19.9 20.5 20.9 23.1 25.3 28 31.1 35.9 39.2 42.3 45 50.3 62.3 80.5 94.1 99 111.9 125 136.7 135.3 148.2 142.5 133.2 111.9 106.9 103 88 76.1 61.2 53.5 49.6 42.8 38.6 38.2 40.9 44.5 41.7 39.1 35.7 33.1 29.1 23 19.1 19.4 19.2 19.3 19.7 20.2 20.1 20.5 21.1 22 31.2 31.4 50.3 50.2 48.1 49.6 54 63.5 73.1 94.5 105.6 109.1 115.1 108.8 104.4 96.9 110.3 127 125.5 129.6 139.7 142.6 147.6 152.6 156.8 158 149.2 141.3 143.2 130.6 124.2 124 123.2 126.3 140.9 137.7 138 143.4 142.1 145.1 150.6 155.4 152.2 164.6 169 163.6 157.9 144.7 141.8 152.1 129.2 161.9 155.4 167.8 166.4 162.4 157.8 151.7 152 153.1 172.6 183.6 184.8 186.5 189.5 196.4 214 232.5 246 254.4 259.4 257 254.8 251.1 249.7 247.7 245.3 244 243 242.4 243.5 244.7 245.5 249.2 257 264.5 261.9 256.3 253.8 260.8 266.1 276.8 279.9 296.3 313.7 317.3 317.4 308.4 301.4 301 304.4 307.3 +23.6 24.1 24.8 26.4 27.7 28.3 28.6 27.1 29.4 32.2 35.5 38.1 38.3 34.9 33.2 35.3 34.7 33.3 27.6 22 18.5 15 13.5 11.4 13.6 14.2 14.5 15.2 15.3 15.7 17.1 18.2 19.8 20.7 21.5 21.8 21.6 21 20.6 21.5 22.6 23.7 23.1 22.6 23 23.2 23.6 23.5 26.2 36.1 45.1 47.3 52.1 59.2 66.4 69.2 65.9 67.9 80.7 97.5 113.2 116.6 137.2 152.8 156.5 152.6 144.2 138.4 124.7 107.6 98.9 90.1 78.5 70.2 61.3 58.5 52.5 50.1 41.7 40.3 42.4 45 41.2 40.1 37.5 34.4 32.3 24 19.7 17.6 18.8 18.8 19.5 19.7 20.4 20.5 21 25.7 35.1 46.1 61.8 63.6 56.9 62.2 63.3 76.1 85.2 102.8 107.6 114.6 110.7 112.9 103.1 100.6 114.7 128.8 125.9 129.8 141.8 143.7 133.9 134.8 131.5 136.8 132.9 132.3 124.5 120.7 122.6 124 129.5 136.5 144.7 147 146.2 156.1 156.8 153.6 150.8 156.2 152.9 166 167.6 162.7 157.8 149.2 144.9 153 149.5 149.2 154.2 166.6 168.9 165.3 160 159.4 157.4 159.6 175 182.9 185.6 191.3 197.9 211.2 226.4 244.5 258.5 264.3 265.4 265.8 262.8 258.1 252.6 247.1 245.5 244.9 244.1 243.5 242.9 245.1 244.3 249.9 249.8 251.4 250.1 250.6 253.7 264.7 271.7 278.5 288.7 303.2 315.8 321 315.8 311.2 310.5 311.1 314.7 315.7 +23.1 23 24.2 25.7 26.9 28 28.4 26.5 29.7 31.5 35.2 39 38.6 35.2 32.2 33 31 27.2 20.8 18.6 15.4 13.6 13.3 13.2 13.5 13.9 15 15.2 15.4 16.7 17.7 19.1 20.9 21.4 21.6 22.3 22.5 22.4 21.9 22.6 22.8 23.4 24.4 24.6 26 28.3 30.3 37.9 51.3 61.1 75.1 87.7 88 88 95.4 95.9 91.2 94.1 100.6 114.2 124.7 131.1 149.1 156.5 158.8 156.5 144.3 136.1 121.6 101 90.4 81.5 74.1 65.7 64.7 67.9 62.2 56.6 45.7 41 42.3 44 41 39.8 37.8 34.8 33.8 25.7 19 18.6 18.4 19.3 19.1 19.7 19.7 19.7 25.5 38.3 45.7 61.4 81.8 67.7 71.4 74.5 78.8 89.6 97.4 107 114 120.3 122.6 112.3 98 97.7 105.5 125.8 128 128.7 135.8 130.7 114.5 106.9 106.5 110.8 113.4 127.1 129.2 129.8 134.1 142.9 147.6 156 157 156.2 152.9 165.2 158.5 151.9 152.3 153.1 153 168.3 175.1 169.3 161.7 156.2 150.2 154.6 152.6 151 152 162.9 164.4 163.1 162.4 163.4 165.2 169.7 177.4 186.6 193.3 202.5 211.4 222.5 236.8 244.9 254 261.3 269.6 267.4 259.8 253.5 253 245.6 245.7 245.4 245.1 244.3 243.3 243.4 244 246.4 245.7 246.1 247.9 249.1 251.4 261.5 271.6 282.3 292.2 301.4 314.8 315.1 317.6 316.5 324.3 325.1 323.2 327.8 +21.9 21.9 23.4 25.3 26.5 26.9 26.4 27.1 29.2 31.4 35.8 37.1 37 34.4 31.1 27.8 24.1 19.7 17.9 16.1 14.7 13.3 13.2 13.1 13.4 14.1 14.8 15.2 16 17.1 18.1 20.2 22 22.3 22.6 22.9 23.3 23.2 22.9 23.5 24.7 25.2 29.8 32.7 35.3 44 61.9 81.1 96.8 97.5 101.1 113.5 117.2 115.9 115.9 112.6 109 110 108.8 127.1 144.8 153.4 156.3 166.8 167.5 158.1 144 129.8 114.1 91.6 81.3 76.9 68.1 66.7 68.5 70.8 65.1 56.1 45.2 42.1 42.1 42.1 41.2 39.1 36.8 35.8 34.7 28.9 18.7 18.3 18.3 18.8 19 19.3 21.1 28 37.4 51.2 63.4 74.8 72.8 72 76.1 81.5 91.7 91.6 95.2 112.1 117.9 121.8 109.2 106.8 92.7 88.8 98.6 114 110.7 108 109 98.6 90.8 87.7 90.3 106.7 115 121.1 129.4 141.2 159.3 167.2 173.1 171 164.2 162 161.3 168.6 158.3 150.9 150.8 151.3 153.3 162.6 172.7 172.4 169.6 164.8 159.2 159.5 157.2 157 150.6 160.8 163.7 163.3 166.9 169.4 170.4 175.8 184 192.8 203 206.5 210.9 218.5 226.5 239.3 244 268.7 272.3 260.8 253.7 248.3 243.8 244.3 245.9 245.4 245.7 244.7 244.6 244.3 243.6 243.7 244.1 244.9 246.9 247.8 250.9 261.7 272.3 287.2 288.7 293.1 304 312.4 323 317.3 332.6 339.2 337.3 338.1 +20.7 21.3 23.1 24.7 25.5 25.8 24.7 27.8 29.8 32.5 35.2 34.1 31.1 29.3 26.9 20 19.1 17.9 16.9 15.9 15.3 13.1 13.1 13 13.6 14.2 14.4 15.3 16.4 17.7 20.2 23 23.2 23.5 23.2 24.6 24.2 25.4 26.6 32.6 38.1 42.8 51 55.8 60.1 69.7 88 101.1 113 125.9 128.8 137.1 132.4 134 130.5 116.8 119.8 113.8 114.2 133.2 154.7 166.8 162.5 169.7 171.6 154.1 142.2 125.7 100 82.6 72.8 65.1 61.7 61.5 61 59.6 56.8 50.2 43.7 40.8 37.5 33.9 36.4 37.8 37.2 36.8 35.3 34.1 16.5 17.6 18.1 18.3 18.6 19.4 30.8 43.9 40.3 46.5 66.2 67.3 77.3 75.9 85.4 91.6 99.6 90 95.8 101.8 103.3 102.1 98.9 96.2 86.5 81.3 88.3 93.2 89.2 82.2 78 72.6 68.9 85.4 95.7 103.9 114.4 126.1 134.8 141.4 164.5 169 187 184.6 169.2 166.8 169.2 163 154.7 151.2 150.9 150.9 159.2 176.4 185.7 184.8 178.9 171.9 168.5 171.4 167.1 164.8 156 155.9 162.8 164.3 169.1 171.8 176.2 181.8 187.3 200.3 204.2 211.4 219.6 222.8 232.7 235.8 237.5 243.3 245.6 246.2 244.2 242.5 240 242.6 245.6 249.4 246.7 245.4 245.5 247.1 246.2 243.9 243.9 244.4 245.2 247.6 250 260.9 272.9 275.7 285.5 290.2 296.6 314.3 320.8 317.1 335.8 341.2 365.1 357.4 +20.1 21.4 22.5 24 24.7 24.4 25.2 27.6 28.8 32.3 33.4 31.3 26.6 22.3 21.6 16.9 16.3 16.2 15.8 15.4 15.7 13.3 13 13 14.5 15.3 15.3 16.3 17.6 19.1 21.7 21.9 22.5 24 25.4 29.5 33.1 35.3 44.3 62.3 74.8 84.4 85 87.9 98.6 103.3 110.7 120.6 140.7 145.8 148.3 140.6 133.4 131.8 127.6 121.4 117.4 115.3 116.9 140.1 169.4 172.5 162.9 153.6 151.1 141.5 126.3 105.6 87.2 76.5 66.9 59.7 57.3 56.7 57.8 59.9 56.2 48 42.7 39 33.1 27.5 27.4 34.1 38.9 39.2 34.8 34.4 25.3 17.8 17.8 17.9 18.1 18.3 27.7 43.2 40.7 40.9 48.9 57.2 70.1 72.8 81.9 85.8 91.7 89 92.4 87.7 86.1 84.9 86 84.6 76.2 74.2 69.3 68 61.7 56.9 60.2 70.4 77.8 85.2 96.4 109 123.3 128.4 134.6 142.6 155.8 170 189.9 184.6 176.2 169.7 163.7 161.3 153.1 150.9 150.7 150.9 163.2 175.8 185.1 193.4 191.1 183.6 174.8 177.6 172.5 168.1 164.5 153.1 162.7 166.4 168.9 173.7 180.9 187.8 192.3 199.1 209.7 223.5 230.2 236.5 233.6 232.6 234.6 230.5 231 232.9 235.2 236.6 239.9 246.1 249 250.8 252.4 248.7 246.9 248.5 248.5 244.3 244.1 244.8 246.5 247.4 250.3 255.6 263.9 276.7 287.5 293.2 303.2 313 316.1 318.2 336.2 344.5 364.5 376.4 +19.8 20.3 21.6 23.1 24 24 23.8 26.1 26.7 29.3 28.3 26.2 23.4 20.2 17.6 15.8 14.6 14.1 14.1 14.5 14.1 13.3 13 13.6 14.8 15.6 16.4 17.3 18.9 20.1 21.2 24 33.4 37.2 38.6 45.8 51.4 58 71.3 102.5 129.6 130.8 127.5 123.2 129.7 131.9 142 151.5 153.9 155.6 145.8 136.4 134.6 130.9 128.3 125.4 122.6 117.2 116.1 132.9 157.6 160 153.6 140.5 135.7 127.5 117.9 103.5 90.9 72 63.9 58.3 55.5 54.1 56.9 58.9 54.6 45.6 40.2 34.7 28.3 23.7 24.3 28.5 37.1 37 31.8 31.9 23.5 16.9 17.5 17.7 17.8 18.1 21.9 40 37.9 34.9 47.4 54 69.9 72.5 77.4 75.2 79.8 74.9 74.2 82.6 82.9 81.4 76.5 71.2 63.5 57.3 51.3 46.7 50.4 56.1 61.1 61.4 66.4 82.6 101.6 106.9 118.3 126.9 129.9 142.7 155.7 166.4 181.1 182.1 178.6 171.5 163.9 159.1 153 150.9 150.9 151 165.2 176.9 185 191.4 193 187.4 177.8 176.1 180.4 174.1 169.4 162.9 160.8 165.4 169.5 174.8 180.2 186.2 192.3 199.6 209.7 221.3 233.9 240.3 236.9 228 224.8 225.9 228.9 233.2 234.7 238.2 241.6 246.2 249.1 249.8 250.4 248.9 247.1 246 245 244.3 244 245.1 247.4 247.5 248.9 256.9 263.4 275.8 287.6 297.3 309.6 318.8 324.3 328.4 336.5 349.6 369 386.3 +18.9 19.6 20.8 22.3 23.1 23.4 22.1 24.3 24.7 26 25 22.9 19.9 17.8 16.3 15.1 14.3 13.4 12.6 12.9 12.7 12.8 13.2 14.9 15.8 15.8 16.7 18.4 19.4 20.5 23.9 31.4 42.8 47.6 55.3 63.4 71.5 83.1 100.2 122.3 139.4 155.9 169.2 173.8 178.1 162.5 166.9 165.2 161.2 151.7 149.6 138.6 136 131.4 128.7 127.8 129.1 125.9 117.2 122 135.3 141.5 140.5 134.3 130.8 123.1 114 106.1 96.7 75.7 61.2 55.7 52.6 52.7 57.4 58.2 57.3 46.3 39.1 32.5 23.2 21.7 22.8 30.1 42.7 39 26.9 21.1 17.7 17.3 17.4 17.5 17.8 18.3 18.2 21.5 24.4 26 36.6 51.4 63.2 56.8 54 61.5 59 63 72.7 77.5 74.9 66.4 61.2 53.4 42.7 41.7 43 47.9 52.2 57.5 62 71.5 78.6 86.6 89.5 103.7 113.8 122.9 127.5 139 152.7 156.2 161.4 169.5 176 172.1 164.9 159.2 153.9 151 151 151.2 169.4 184.9 186.2 185.4 184.1 182.7 180.1 179.1 181 178.3 172.4 165.4 160 163.2 166.9 172.6 180.4 185.1 190.2 197.8 209.4 224.7 222.3 225.9 222.3 220.2 222 229 231.3 232.8 237.2 242 244.3 246.8 248.9 250.2 250.4 250 248.9 245.8 245.7 244.9 244.8 244.4 245.1 246.4 247.4 257.2 265.8 278.1 293.1 308.1 321.7 328.9 334.8 341.9 351.4 362 375.9 386.7 +18.4 19.3 20.4 21.7 22.6 23 20.1 22 21.9 22.5 21.9 20.3 17.7 15.7 15.5 15.9 15.1 13.3 11.3 13 13 12.8 13.4 15.9 16.8 17.6 18.4 19.2 20.8 23.8 25.7 42.6 51 63.1 75.9 86.7 97.4 105.5 117.8 138.3 158.7 174.8 188.9 192.3 189 182.2 173.3 168.9 161.4 154.8 152.7 142.9 136.1 131.4 128.2 125.2 126.6 125.7 119.3 111.4 114.5 119.5 136.1 141.9 129.6 118.7 109.8 106.4 94.1 70.9 57.8 53 49.4 50.7 53.9 58.8 53.6 44.7 38.2 28.1 21.3 20.5 22.7 34.7 38.7 29.3 20.8 17.7 16.6 17.1 17.3 17.4 17.3 17.4 17.9 18.6 21.1 23.5 25 33 34.7 34 40.7 44.4 47 53.8 60.5 58.2 53 46.5 40.6 37.4 38.4 40.1 42.9 50.9 55.3 63.4 70.1 77.9 86.8 100.3 87.1 96.2 108.7 116.5 126.7 133.8 142.6 149.1 155.6 166.2 174.9 168.8 163.5 158.4 153.4 151.1 150.9 151.1 163 181 192.6 192.3 189.3 190.1 186.6 184.8 181.5 180.3 173.4 168.1 162.1 164.5 168.6 176.6 179.4 182.2 187.9 194 202.4 214.7 216.3 216.8 216.9 219 227 232.4 235.4 233.9 237.9 245.1 245.9 247 248.4 251.2 252.9 251.6 249.2 247.9 247.8 246.7 246.3 245.6 245.7 247 249 260.3 276.5 292.4 313 323.2 333 344.4 357.8 365.5 370.5 380.5 389.9 396.2 +18.5 19.4 20.2 21.1 21.9 22.8 20.8 19.5 19.1 18.5 18.2 17.2 15.3 14.7 14.1 14.8 13.9 12.7 12.4 12.8 13.2 13 13.7 15.4 17.2 18.7 20.6 22.5 24.4 31.4 39.5 62.6 75.5 96.7 117.9 125.8 134.4 142.2 156.1 162.8 176.2 191.9 192.9 200.4 195.9 183.7 174.1 174.2 171 162.4 151.8 142.8 132.9 129.3 122.9 115.7 115.3 111.9 115.1 100.2 100.2 113.8 140.9 135.5 119.6 106.1 108 113 94.8 65.3 54.3 50 47.4 47.9 48.2 46 43.5 41.9 33.8 24.9 21.2 20.5 23.7 28.5 29.8 23 17.7 16.5 15.2 16.8 17 16.9 17.5 17.8 18 18.6 20.5 21.9 23.2 24.3 26.1 27.3 32.8 36.2 38.4 41.8 38.6 36.7 34 34.3 35.1 36.4 37.9 41.6 47.5 54.6 61.3 76.5 86.3 98 105.7 111.9 124.3 94.2 90.5 109.2 123.2 131.9 137.2 144.2 150.4 156.9 166 161.6 161.6 158.6 153.4 151.1 151 151.4 161.9 176.6 184.8 187.1 188.1 189.4 185.5 181.9 180.8 179.7 173.4 171.7 163.7 164.2 172.7 182.1 188.5 188.7 197.5 200.3 201.9 204.7 210.2 215.7 221.2 225.9 229.7 234.4 239 240.9 239.3 243.2 247.5 249.8 250.1 250.8 251.2 250.4 249.6 249.6 250.2 249.8 252 251.3 248.9 250.1 253 264.2 278.5 296.3 327.7 338.7 354.9 361.6 380.2 404.4 408.2 407.2 408.1 410.9 +18.2 18.7 19.4 21.4 24 24.9 25.3 24.9 23.4 18.8 17.2 16 15.2 14.8 13.6 12.8 12.8 12.2 12.3 13.2 13.3 14.2 15.9 17.5 19.9 22.6 24.3 27.1 38.5 54.7 75.2 81.5 101.7 126.2 143.5 156.4 169.2 179.5 188 189.3 198.2 197.3 194.3 193.6 185.5 179.9 177.7 165.6 161.8 158.6 150.2 134.8 129.9 125 119.2 111 107.7 103.8 98.7 92.2 91.8 106.9 117.4 116.3 110.7 102.9 100.9 97.9 82.9 60.4 52 49 46.9 45.4 45.2 43.9 42.3 43.7 27.9 20.6 19.6 19.1 24.3 25.8 23 16.3 15.9 16.4 16.5 16.5 16.3 16.5 17.5 17.6 17.7 18.5 20 21 21.9 23.1 24.8 26.1 27 28.5 32.4 30.5 30.4 31.2 32.1 33.4 35.8 41.7 45 50.2 57.8 65.9 74.8 85.8 104.4 111.4 119.5 128.9 146.7 131.4 101.2 91 114.6 128.7 133 138.2 142.7 147.3 156 158.4 156.9 157 152.9 151.3 151.2 151.3 160.9 169.3 170.8 179.1 185 188.3 186.9 182.6 181 179 173.4 168 165 168.5 176.2 182.1 188.4 192.6 202.6 202.8 203.6 206.6 212.3 218.4 224.7 230.2 236.6 241.2 246.7 248.6 249.9 245.1 248.3 251.9 253.3 251.4 250.8 251.5 250.5 249.9 251.1 251.6 252.5 252.7 253.4 252.2 251.8 265.5 285.7 298.7 324.6 338.4 354.9 357.7 378.2 420.7 422.9 423.7 432.8 436.6 +18.8 19.1 20.2 25.2 28.9 27.9 26.1 23.3 20.5 19 16 15.1 15.2 15.2 14.3 12.3 12.4 12.4 12.6 13.5 14.4 17.1 20.9 23.1 28.1 32 42.1 58.2 70.6 86 93.1 105.7 126.2 138.7 162.2 181.4 187.5 200.8 205.4 199.6 195.2 196.8 195.1 190.5 186.5 184.4 177.1 165.4 159.8 156.2 147.1 133.8 124.9 121.2 113.1 103.2 100.9 97.8 93.6 86.5 83.3 90.9 96.4 99.4 102.9 94 86.6 75.4 63.4 55.7 50.6 49.9 48.8 40.8 40.5 41.3 39.2 33.3 23.1 17.9 16.9 17.5 19.8 17.7 16.1 15.5 15.7 16.6 16.7 16.4 16.2 16 17.2 17.3 17.3 18 18.9 19.6 21.3 22.7 24.1 26.2 26.3 26.9 28 29.5 30.5 31.5 33.8 38.3 43.8 49.1 61.6 67.3 74.2 86.5 100.9 104.3 127.2 138.7 144.9 136.4 149.7 149.3 136.9 111.8 94.1 110.2 128.5 133.9 140.1 145 156.7 158.3 156.1 154.7 151.6 151.9 152 151.9 155.1 161 167.5 178.3 186.2 185.2 184.7 183.5 183.4 187.1 175.9 167.3 168.9 173 176.9 181.2 186.3 192.1 193.4 201 204.7 211.7 218.5 224.5 230.9 237.7 243.6 248.8 250 254.5 258.3 256.4 253.2 252.2 251.8 251.2 251.9 251.5 250.4 249.9 251.2 251.6 252 252.2 252.1 253.1 259.5 265.2 281.1 296.4 314.6 333 351.2 353.1 376.3 420.3 421.2 428.8 435.7 436.9 +17.6 18.5 22 27.9 30.1 26 22.8 20.5 18.3 17.5 16.2 15.4 13.9 13.7 12.9 11.5 12.4 12.4 13 13.6 16.1 21.4 35.2 45.2 52.6 65.3 72.3 89.3 110 114.9 118.3 136.9 155.2 171.3 193.7 204.3 208.7 204.5 202 199.8 196.3 193.9 192.5 190.4 188 182.5 178.4 166.5 158.6 155.4 150.7 135.1 119.5 111.3 103.7 99.7 97.7 94.2 89.8 80.9 72.6 80 88.7 94.6 94.4 87.1 65.7 57.3 47.3 48.5 48.9 48.7 42.6 35.3 31.6 30.9 29.8 25.4 20.2 14.5 14.3 14.6 14.7 15.1 15.3 15.3 15.4 15.4 16 16.1 16 16.4 16.9 16.9 16.9 17.6 17.9 18.9 20.9 21.8 22.9 24.6 26.1 27.4 28.9 30.1 32.8 36.6 43 52 61 68.2 78.8 90.4 101.2 116.2 121.9 126.3 135.4 133.6 164.8 158.5 153.1 152.5 160.9 143 126.1 110.6 124.1 135.1 141.8 144.9 155.1 156.7 153.4 150.8 152.2 155 155.5 155.5 155.8 160.1 170.1 178.3 187.3 186.4 185.1 183.2 183.2 187.1 176.9 168 171.2 175.5 176.7 179.5 182.9 185.7 189.7 197.4 208.5 218.9 227.2 235.4 240.5 244.4 250.3 254.1 256.1 255.1 258.8 263.9 265.4 259.1 256.9 254.1 251.8 251.4 251 250.4 250.5 251.1 251.7 252.1 253.3 256.7 264.8 271.3 277.5 291.1 308.8 328.9 339.6 348.4 374.4 400.4 414.8 424.4 429 439.9 +17.8 19 23 27.1 26.6 21.7 20.4 19.6 18.9 17.4 16 15.1 14.2 13.4 12.3 12.1 12.4 12.6 13.7 15.7 20.3 33.7 54.2 61.5 77.8 95.8 108.6 119.8 142.6 147.5 155.9 166.5 185.2 197.4 209.2 218.1 208.7 202.1 203.4 206 202.4 195.7 193.1 191 191.4 179.5 178.9 169.9 153.6 147.7 139.4 126.7 118.3 106.9 100.3 97.7 96.7 88.8 81.4 74.2 62.4 63.6 71.7 74.4 71.1 61.2 53.4 34.1 30.2 33.5 36.9 34.9 31.8 26.9 23.8 21.5 21.3 20.3 18.6 14.4 14.3 14.2 14.5 14.5 14.4 15.3 15.4 15.5 15.4 14.5 15.5 15.9 16.5 16.5 16.6 17.5 18.6 20.1 22.4 23.4 24.4 25.5 28.2 34 42 49.2 54.8 58.5 66.8 72.9 84.6 93.8 105.2 118.5 131.1 153.4 157.1 158.5 167 164.4 166 171.5 163.8 157.9 163 154.9 146.3 137.8 109 133 138.6 142.7 152.2 148.6 147.2 150.9 157.2 159.3 164.6 164.1 162.9 166.7 172.8 180.9 183.9 185.1 182.6 181.6 186.4 184.4 176 169.8 170.6 174.7 174.9 178.3 182 185.1 190.1 200 211.3 222.5 233.3 241.2 249 252.6 256.5 256.1 257.2 258.4 262.6 267.4 270.7 267.3 260.2 254.4 252.8 251.7 251.6 251.2 250.5 251.2 251.5 253 255.1 260.6 271.5 281.7 284.1 288 308.1 325.8 333 348.9 368.3 384.2 400.7 418.4 428.9 441.3 +17.4 19 20.6 22.7 22.6 19.9 19 20 18.9 17.7 16.6 15.7 14.5 12.3 12.3 13.1 13.8 15.2 17.4 22.3 33.1 51.7 66.4 77.7 97.7 121.7 135.4 160.4 170.9 172.8 187.7 196.3 200.9 211 216.2 219.3 205.7 202.8 209.5 209 214.2 208.9 196.2 190.8 191.6 177.7 170.5 164 153 140.8 134 122.5 113.3 101 93.4 90 86.9 81.4 74.3 65.3 53.8 46.9 48.3 44.6 42.3 40.9 28.7 20.8 18.8 19.8 24.1 24.7 22.6 18.6 18.4 18.3 18.5 16.7 14.6 13.6 13.7 13.9 14.4 14.5 14.9 15.1 15.4 15.4 15.3 15.8 16.1 15.4 15.9 16.4 16.7 17.7 20.6 23.7 25.4 26.3 27.9 32.1 47.3 58.9 70.3 76.9 84.9 90.5 93.8 102.6 113.2 123.3 135.9 147.2 165.8 173.3 187.6 187.1 192.1 188.5 168.6 173.4 167.1 162.1 158.4 155.9 150.5 145.4 134.6 114.3 130.5 135.2 139.6 143.5 148.9 153.9 160.3 161.5 165.5 164.1 167.5 171.6 176.7 187.1 185.9 178.8 178.8 180.7 183.8 180.6 175.3 173.6 172.2 172.6 174.7 177.3 181.2 188.5 194.8 205.3 214.3 224.5 234.2 245.4 250.8 256.8 259.2 260.8 260.9 260.4 262.6 264.9 265.5 265.8 262.1 253.7 253 253.1 253.3 257.9 252.7 251.2 251.9 253.7 257.4 263 276.5 284.8 289.4 292.2 304.2 315.4 325.7 351.5 378 382.4 397.5 410.2 436.2 452.1 +17.9 18.2 18.6 18 17.8 17.8 18.1 19.6 18.5 17.3 16.5 15.7 14.2 12.1 13 14.5 16.6 18.2 21.5 29.3 51 66.5 80.7 101.4 121.8 145.7 162.1 178 183.8 192.6 204.1 211.5 219.9 218.3 216.6 218.9 211.5 207.8 214.6 215.3 215.4 206 194.4 186.2 179.7 172.9 161.6 155.8 149.8 137.7 130.7 115.7 103.3 86.9 81.3 80.9 79.1 72.3 66.6 59.9 49.3 38.6 31.3 29.4 26 20.8 17.4 15.4 14.7 14.9 15.9 15.1 12.7 12.2 13.7 16.4 15.6 12.9 12.8 13.1 13.4 13.7 14.2 14.3 14.9 15.2 15.1 14.7 15.2 15.3 15.9 16.8 15.2 16.7 18.1 22.7 28.7 35.7 38.7 39.9 43.5 53.8 67.1 88.4 100.2 109.7 121 125.9 135.8 144.5 148.4 152 166 182.2 192.9 202.1 207.2 204.7 213.4 203.2 184.7 178.9 171.8 163.5 157.5 154.4 151.8 148.8 141.1 130.7 131.1 133.1 131.5 139 149.3 151.7 153.9 156.9 157.4 160.9 161.4 162.6 164.5 167.9 173.7 175.8 179.2 184.7 181.4 179.3 175.7 176.5 176 174.7 175.8 178.1 182.4 192.5 199 204.7 212.9 218.7 227.7 238.9 249.6 258.6 264.2 266.4 267.2 265.4 264.6 266.1 265.1 260.8 259.2 255.6 253.2 253.2 253.6 253.9 253.1 251.5 252.9 257.7 264.3 270.3 277.5 282.7 287.5 293.4 303.3 314.6 322.1 340.6 361.1 375.4 387.5 403.3 425.3 449.2 +17.5 17.6 17.4 16.9 16.2 15 15.5 16.6 17.5 17.1 16.9 16.5 14.1 12.8 13.8 16.1 18.5 21.3 31.6 48.5 67.4 85.9 106.1 129.8 153.1 173.6 191.5 198.7 190.2 206.7 222.4 228.4 221.3 219.2 217.1 219.3 218.9 211.4 216.4 220.4 217.5 206.6 191.1 182.7 175.2 165 156.1 153 151 131.1 119.3 103.2 85.7 75.7 72.4 75.5 71.1 62.2 56 50.3 42.4 31.8 22.2 18.3 15.9 15.5 13.8 12 11.6 11.3 10.7 10.5 10.8 11 11.4 11.7 12 12.4 12.5 12.7 12.9 13.4 13.8 14.5 14.6 14.6 14.4 14.2 14.7 14.8 15 15.3 15.6 19.4 27.6 36.5 44.6 53.1 57.6 61.8 60.7 71.2 86.7 107.3 120.9 128 139.3 150.9 169.2 178.6 179.7 182.8 190.2 206.1 224.1 234.3 230 226.2 216.4 203.4 191.8 178.4 173 164 159 156 154.8 152.7 145.8 142.1 139.9 141.1 142.7 139.7 144.6 147.7 151.4 155.1 159.8 164 161.6 162.2 163 165.2 172.2 177.8 183.6 188.1 185 179.8 176.5 177.8 177.3 178.5 177.6 181.2 184.7 193.4 203.1 203.3 206.5 212.2 219.8 231.3 245 257.8 266.7 267.3 268.5 266.8 266.2 265.9 264.5 262.7 259.2 257.4 253.8 253.6 254.6 254 253.4 253.1 254.8 261.5 267.8 273.3 286.6 291.3 293.8 299.1 305.6 313.1 322.9 332.3 348.8 365.2 378.8 412.4 426.3 439.6 +16.7 16.6 16.4 14.9 13.5 12.7 12.8 14 15.1 16.2 16.5 17.4 17.1 13.9 14.6 17.3 23.2 31.8 54.6 71.9 90 113.2 136.7 158.2 179.2 196.7 203 201.4 196.9 212.8 220.6 213.7 211.6 215.2 217.2 221.5 220 211.4 211.7 216 208 198.9 183.5 177.6 176.1 167.6 154.3 144.7 135.3 116.6 100.7 89.2 78.1 67.2 62.6 63.7 59.2 50.9 44.4 38.5 32.6 25.7 17.3 14.1 13.5 12.3 10.1 9.9 10.1 10.1 10.3 10.3 10.8 10.8 11.1 11.4 11.7 12.2 12.8 13.1 13.2 12.9 13.4 13.9 14 14 14 14.3 14.2 14.5 14.7 15.6 24.6 35.4 52 63.4 75.6 79.4 87.6 88 92.1 95.9 103 122.4 137.2 148.4 159.2 174 195 204.6 201.7 202.5 210.1 221.5 233.2 237.9 239.6 231.5 216.4 204 192.6 180.7 174.7 167.6 161.8 159.1 157.5 154.9 150 149.3 148.6 143.9 145.1 147.2 154.1 156.4 158.1 161.2 165.3 167.4 165.9 163.4 163.6 167.2 175.6 182.4 189.5 194 187.2 180.7 178.3 180.9 178.9 177.5 180.1 185.4 185.1 189 196.7 202.1 204.5 210.3 218.1 227.3 235.8 245.7 251.6 256 261.7 264.3 265.7 266 264.7 262.7 260.8 258.5 254.8 254.2 254.7 254.4 254.2 254.7 257.2 262.9 270.5 275.6 281.6 294.5 296.3 300.9 307.9 316.7 321.6 331.2 344.9 355.1 371.3 397.7 415.9 446.9 +15.8 15.8 15 13.6 10.9 10 10.3 10.6 12.3 13.3 15.3 16.7 16.3 13.4 15.6 21.5 37.6 53.2 74.7 99.8 116.8 151.5 178.1 202.1 207.2 201 200.5 203.8 200.7 202.1 200.3 203.8 204.1 206.4 214.6 217.7 210.5 198.1 199.9 201 198.7 185.1 174.3 171.1 171.8 162.3 148 126.3 119.7 100.6 89 80.7 70.1 58.5 51.5 48.1 43.8 37.5 31.7 24.2 22.1 18.4 14.8 12.3 11.7 10.4 9.1 9.2 9.5 9.7 9.9 10.1 10.4 10.6 10.9 11.2 11.6 12.1 12.2 12.6 13 12.9 13.1 13.6 13.7 13.5 13.5 14 13.9 12.2 18.7 28.1 42.4 61.4 79.8 105.8 107.3 112.3 116.5 117.2 122.6 129.2 130.7 142 163.3 175.9 192.1 194.3 202.2 216.7 212.2 217.6 219.9 230.5 234.6 240.1 236.2 228.6 220.6 206.8 198.6 186.5 179.2 171.9 165.8 161.9 159.9 158 155.4 157.3 155.9 150.4 151.7 155.1 159.7 160.9 162.2 164.1 166 168.5 169.1 169 167.1 168.2 176.7 183.8 189.1 194.4 185.8 180 180.4 182.3 179.8 180.9 184 184.5 185.1 187.6 194.2 201.9 205.1 212.8 218 223.8 230.3 234.2 240 244.6 252.5 257.3 266.1 266.8 264.8 264.5 262.9 258.5 255.4 255 255.4 256.8 256.2 257 261.3 266.3 274.5 280.4 284.9 293.2 299.2 302.4 310.8 320.9 327.2 334.9 344 353.5 366.5 386.9 417.6 430.4 +15 14.8 13.8 12 9.7 10 10.5 10.6 10.8 11.1 11.7 12.2 12.7 14.7 21.7 37.9 56.5 71.4 103.7 132.9 152.5 178.5 198.2 205.6 204.4 201.7 206.3 211.5 207.8 198.8 197.8 200 202.9 200.3 204.2 203.1 198.7 186.3 184.6 184.2 189 170 159.9 159 161.2 155.1 135.1 109.2 97.9 82.8 79 74.1 62.4 50 40.9 34.3 29.7 25.2 19.9 16.3 15 14.3 13.7 12.6 10.2 8.9 8.8 8.9 9.2 9.5 9.9 10.2 10.2 10.9 10.9 11.2 11.4 11.9 11.9 12.3 12.6 12.8 13.1 13.6 13.2 13 13.3 11.7 14.8 20.2 32.8 48.2 61.9 82.7 101.2 118.8 141.7 145.2 141.3 142.5 139.3 151.7 156.8 165.7 176.4 192.6 206.1 214.8 215.5 220.2 225.7 230.1 235.5 236.4 235.1 234.3 232.5 230 225.5 211.5 205.1 195.6 186.6 180.4 172.6 167 163.4 161.6 161.2 162.7 163.5 161.7 161.1 161 162.3 164.5 166.5 167.8 169.6 172.5 173.7 173.9 175.7 173.6 177.3 183 188 188.5 182.6 181.8 182.2 182 180.1 181.8 184.3 185.8 187.1 188.9 195.3 203.7 208.5 216.6 221.2 223.1 229 231.9 234.2 236.6 241.4 250.5 259.6 262.7 265.4 264.9 262.6 258.3 255.7 255.5 256.2 257.9 261.9 266.9 268.7 275.2 282.4 287.4 292.9 297.2 304.1 311.3 318.9 324.1 332 336.9 344.6 356 370.8 386.7 406 415 +14 13.7 12.8 11 9.9 10.1 10.9 11.8 12.8 13.5 14.8 16 18.5 25.6 45.2 63.6 88.6 95.1 118.5 139.7 166.7 191 198.9 212 204.7 201.6 201.9 203.1 203 198.4 197.9 195.1 197.2 194.6 196.9 197.3 186.8 172.5 170.2 175.1 171.4 152 142.1 143.5 152.4 143.7 114.6 93.2 77 67.4 65.1 60 53.3 40.7 30.4 22.7 17.5 14.7 13.2 12.8 11.9 11.7 14.1 13.4 9.2 8.6 8.5 8.7 9.1 9.2 9.8 10.3 10 10.6 10.8 11.1 11.3 11.5 11.8 12.2 12.6 12.9 13 12.9 12.9 13.1 12.9 14.9 22 34.9 53.7 70.6 81.9 100.7 117.9 140.6 167.1 173.1 174.5 161.6 158.8 168.4 173.6 181.3 188.2 207.2 219.6 225.8 228.4 234.4 226.6 230.1 233.1 233.3 234.2 235.4 234.2 234.1 230.1 222 212.2 203.7 193 185.1 175.6 170.9 168.5 169 169.6 171 172.7 172.9 171.9 168.1 165.3 168.3 169.7 171.3 173.3 175.5 178 178.8 179.2 180.5 179.9 180 182.5 182.4 182.7 183.6 183.8 182.2 181.6 182.7 183.7 186.4 189.5 189.9 197.1 206.9 215.1 218.3 221 223.8 226.4 228.7 232 235.2 236.6 240.3 248.9 257.8 261.4 262 260.9 256.5 255 255.7 257.2 261.5 267.1 272.3 277.8 290.3 294.9 304 305 308.6 315.1 323.3 329 331.4 335.8 339.2 347.8 358.8 373.7 391.3 403.2 411.2 +13.1 12.4 11.6 10.5 9.8 10.9 12.7 13.6 15.4 17.2 19.2 21.1 29.9 43.9 62.6 81.5 97.5 113.4 141.7 154.3 169.5 192.2 204.8 221.8 213.6 202.3 201.7 201.9 200.7 199.4 200.3 191.4 193.3 190.8 184.6 177.2 167.9 162 155.9 155.5 154 139.9 129 130.8 140.9 127.2 92.6 75.3 62.2 53.8 50.5 46.6 39.3 30 21.1 13.9 12.3 10.8 10.1 10.1 10.3 11 14.1 13.8 8.5 8.3 8.3 8.7 9.1 9.3 9.4 9.7 9.9 10.3 10.8 11 11.1 11.5 11.7 12 12.5 13 12.6 13 11.7 13.8 16.8 24.3 35.2 49.3 71.5 89.2 100.8 114.4 141.9 162.8 191.4 199.8 198 182 176.2 184.7 185.2 183.4 191.3 213.7 233.6 241.1 242.4 232.4 221.9 224.9 228.7 231.4 233.4 237 237.2 243.7 240.1 225.3 216 205.4 195 186.1 177.8 174.7 175.5 174.8 176 177.1 179.2 179.8 178.7 175.4 171.4 171 174.2 176.4 176.8 179.6 181.2 183.6 185.9 185.4 184.7 184.9 188.4 184.5 184 185.1 184.5 182.9 183.5 186.4 186.8 190 190.9 193.3 198.9 208.5 216.1 220 224.3 226.8 228.6 230.8 233.2 235.1 237.6 239.1 241.9 248.3 255.1 257.3 255.4 255.9 254.5 255.5 259 264.7 269.8 273.4 284.1 298.2 310.5 311.7 314.9 317.3 320.2 324.2 330.7 337.6 339.8 341.5 348.3 366.9 384.3 404.8 412.5 422 +12.2 11.6 11 9.6 9.7 11.9 14 16.3 18.7 20.8 26.8 38.5 52.4 64.1 88.8 104 117.8 138.1 150.1 157.1 174.9 192.3 207.2 225.7 223.3 205.7 203.6 204.9 200.8 203.5 193.6 188.9 185.6 184.1 176.3 166.3 159.9 154.8 141.8 138.3 135.1 122.9 114.8 112.2 107.6 86 70.7 58.3 46.4 40.7 39.4 43.1 29.9 19.6 13.7 11.3 10.1 9.7 9 8.7 8.9 9.6 12.4 11.4 8.6 8.4 8.5 8.9 9.2 9.4 9.6 9.8 10.2 10.4 10.8 10.9 11.2 11.1 11.4 12.1 12.5 12.5 11.6 12.6 15.1 20.3 30.6 40.1 60.6 70 88.3 108.8 133.1 155.5 171.2 189.4 203.8 208.4 208.8 203.6 192.1 194.6 195 194.3 200.1 214.2 227.4 242.3 236.5 223.7 216.9 215.5 220.6 229.7 228.4 235.6 239.5 245.9 242 224.8 215.8 205.7 195.2 188.7 186.3 185.2 185.6 186.7 183.7 183.2 183.5 182 181.7 178.9 175 175.5 177.7 179.1 179.8 181.2 183.1 187.5 190.5 192.4 190.5 189.9 191.5 187.8 186 186.2 185.4 184.8 185.5 187 188.7 192.9 194.8 196.1 195.8 206.5 213.3 217.3 220.9 225.1 228.2 231.3 235 242.1 244.2 244.1 247.7 249.5 253.5 253 253 253.4 254.1 255.2 261.5 269.2 272.4 279.1 287.1 295.5 306.1 315.8 319.4 322.9 324.7 326.6 331.1 338.1 340.6 341.7 347.6 374.2 398.3 422 424.6 434.3 +11.6 11.1 10.6 9.6 9.9 12.2 16 19.3 22.5 30.2 54.1 74 86.3 92.8 125.9 128.5 140.5 150.4 156.7 160.2 173.6 189.5 202.4 222.7 227.2 213.7 204.8 209.2 202.5 196.8 190.4 186.9 182.6 174.6 167 159.5 151.2 144.5 132.9 122 108.9 100.6 95.5 86.6 74.8 61.4 53.6 41.1 30.3 26.7 23.5 23 18.5 10.5 9.6 9.3 9.2 8.8 8.3 7.8 8.1 8.1 7.9 8 8.1 8.2 8.5 9 9.3 9.5 9.8 10 10.2 10.5 10.9 11.2 11.3 10.4 10.6 11.5 12.3 11.5 13.3 15.1 21.5 31.6 43.7 58.7 78.6 108.5 124.3 133.4 154.7 167.8 187.7 202.6 220.1 221.6 225.9 224.2 206.2 206.2 210.3 208.4 205.1 215.5 226.2 223.4 224.8 215.3 209.4 209.3 211.5 219.7 224.3 230.4 241.7 240.5 236.5 224.5 215.3 204.4 199.6 198.9 198.5 196.6 194.2 195 190.5 188.8 187 185.9 185.2 182.6 180.5 179.8 180.4 181.2 181.9 184 185.8 188.5 191.3 195.2 196.5 195.3 199.1 193.2 189.1 187.1 186.5 186.9 186.7 187.6 191.2 195 198.9 201.6 202.2 203.9 211.2 215.9 220.1 224.6 227.8 233.4 238.3 244.7 246 247.4 248 250.3 253.2 251.9 252.3 253.1 254.1 255.9 260.9 271.2 277.9 282 287.1 293.2 299 308.4 313.9 321.5 324 326.6 329.7 333.8 337.8 340.4 344 361.5 397.9 412.4 428.6 443.9 +11.6 11.2 10.3 9 10.2 13.5 18.6 23 28.1 41.7 76.4 100.5 113.9 122.7 140 148.5 151.5 155.8 157.5 159.3 166.8 184 195.7 215.2 216 216.1 196.9 195.2 190.4 192.5 190.1 186 182.5 170.3 165.2 156.5 145.9 137 124.2 114.1 95.1 80.7 77.2 68.4 54.6 52.1 40.6 27.5 18.5 14.4 11.8 10.5 9.9 7.9 8.2 8.4 8.8 8.2 8.1 7.5 7.6 7.8 7.3 7.6 7.9 8.2 8.5 8.9 9.3 9.5 9.7 10.1 10.5 10.7 10.8 10.9 9.4 10.6 11.4 11.8 12.8 16.1 18.9 21.4 31 40.9 58.9 84.8 109.5 134.1 156.9 170.9 184.5 188.1 196.7 213.8 225.3 231.6 238.1 238.4 225.6 215.6 219.8 215.6 211.4 214.7 216.9 211.3 211.1 206.1 201.1 202.9 208 215.4 222.8 228.7 233.9 229.2 226.5 219.5 215.9 214.8 211.8 212.7 208.8 203.8 199.4 198 196.8 195.7 193.6 190.2 189.7 188.1 185 183.7 183.6 183.7 184.5 186.5 188.9 191.5 194.9 198 200.8 201.8 205.8 198.2 191.5 188.7 187.9 189.6 188.3 188.9 193.1 199.1 204 205.6 206.7 203.4 210.4 215.1 217.8 221.8 228 234 235.4 240.3 242.4 245.8 244.8 246.3 248.4 250 251.9 253.2 254.4 257.1 260.4 266 271.8 278.2 282.3 287 294.8 299.2 303.5 308 316.5 325.4 327.2 335 338.3 341.7 343.9 356.7 387.1 403 423.3 448.8 +10.8 10.9 9.9 9.1 12.7 17.3 22.1 28.9 36.2 59.2 88.1 113.3 134.9 135.8 147.9 158.4 161.5 162.8 161.1 161.2 164 173.6 193.5 206.9 210.5 203.6 187.1 181.5 183.8 190.7 187.7 182.9 178.5 166.5 158.8 149.8 137.1 125 112.7 101.9 90.3 66.2 52.6 46.5 38.8 36.3 25.5 16.8 11.7 10.3 8.9 8.4 8.2 7.5 7.5 7.7 7.9 7.7 7.9 7.2 7 7.4 7.2 7.8 8.1 8.4 8.7 8.9 9.2 9.6 10 10.3 10.5 10.7 9.5 9.8 10.5 11.4 12.4 14.3 15 20.9 23.4 29.8 39.9 56.1 75.1 89 105.3 133.9 164.9 181.2 191.1 202.4 211.4 221.4 228.2 234.1 240.4 242.5 235.1 223.7 220.3 220.3 215.4 210.1 207.2 204 200.2 196.2 192.5 196.1 203 211.1 220.1 222.1 220.2 217.1 221.7 227.3 227.6 225.9 221.1 219.3 213.9 209.1 203.2 200.2 199.7 199.5 197.4 195.1 195 192.3 188.7 185.9 185 186.2 187.4 188.6 191.6 195.1 197.5 200.4 203.3 205.2 206.5 199.7 193.1 190.3 190.3 195.1 191.2 192.7 197.1 204 209 211.9 209.9 210 207.9 209.6 215.3 221.2 225.5 229.1 232.1 234.4 238.3 240.3 242.3 244.3 247 250.9 253.5 254.9 258.6 261.6 264 270 276.4 280 281.1 283 287.2 293.2 298.7 304.4 311.5 318.6 322.6 331.1 338.5 339.3 341.5 350.1 384.8 398.1 420.9 441.3 +8.6 8.1 8.6 12.8 17.2 24.3 30.9 36.9 48.9 78.2 106.9 136 146.6 145.9 156.6 165.8 168.8 171.6 169.5 165.3 169.1 179.5 191.8 204.7 202.1 192.9 184 178.6 184.6 184.5 180.6 176 167.1 160.9 149.8 138.6 125.6 110.4 94.1 83.8 71 52.8 41.8 31.8 25 19.8 14.4 10.2 8.7 8.1 7.3 7.5 7.6 7.1 7.2 7.3 7.3 7.5 7.7 7.6 7.4 7.6 7.5 7.8 8.1 8.4 8.5 8.7 9 9.3 9.6 9.9 10.2 10 10.1 10.4 10.8 13.5 16.1 21.4 18.4 24.9 28.9 37.1 49.1 63.9 83.1 94.5 106.9 131.9 153.5 173.9 195.5 207.5 212.5 223.4 240.5 248.3 256.8 252.7 245.5 232.7 218.4 215.5 208.8 203.9 199.1 194.4 191.9 189.1 189.2 191.1 196.5 202.2 206 208.1 219.2 229 234.4 235.4 238.1 235.5 229.9 225.8 221.6 216.1 211.7 207.6 204.1 203.8 202.8 202.3 200 197.9 194.1 190.2 189.6 190.3 192.1 194.5 196.1 199.1 200.6 203.1 206.7 209.2 204.9 198.7 195.3 194.5 192 197.2 194.4 197.3 202.3 207.2 211.8 214.4 213.8 215.3 217.5 216.3 215.3 219.6 223.6 226.3 228.5 231 234.2 237.7 241.4 243.8 247.1 252.2 254.6 259.8 266.2 267.4 270 274.6 278 284.1 289.4 289.3 290.9 293.3 299.9 303.5 308.2 313.6 321.3 329 335 338.8 341.5 349.7 373.5 387.6 415.4 441 +11.3 11.5 14.1 20.1 26.4 36.8 47.6 57.7 65.7 95.4 124.7 140.8 149.5 159.9 167.8 170.1 169.5 171.8 171.5 172.4 177.2 184.2 191.2 192.8 189.2 189.7 182.2 176.4 167.9 171.6 170.5 159.7 149.5 146 138.2 123 103.3 87.2 71.9 59.1 47.6 37.8 28.3 19.9 13.1 10.2 7.8 7.6 7 6.5 6.4 6.8 7 6.8 6.8 7 7.2 7.4 7.5 7.4 7.3 7.4 7.6 7.7 7.9 8.2 8.3 8.5 8.9 9.1 9.5 10 9.8 10.3 10.1 10.1 14.2 18.6 23.8 31 30.9 28.8 33.6 44.2 55.7 70.3 86.8 98.6 112.1 131.6 144.6 167.3 183.8 191.4 199.6 220.8 242.8 244.6 244.7 246.1 243.1 230 215.8 208.9 203.4 198.7 194 190.4 188.5 188.4 189.1 190.1 191.2 194.4 206.6 218.4 230.5 239.3 242.7 242.4 245.2 243.1 238.1 233.4 229.1 224.5 222 218.3 216.2 215.5 214 210.6 208.5 207.5 205 200 198.3 197.5 201 202.2 202.9 204.2 205.4 208.1 210.7 212.3 206.4 201.4 198.5 200.1 193 200.7 198.7 201.4 205.4 209.6 216.4 218.5 219.7 219.4 220.5 220.2 220.6 221.8 223.7 227.1 230.7 233.9 236.1 238.4 241 243.9 248.6 253.3 258.1 264.9 269.4 272.5 276.3 280.3 282.8 289.7 292.1 293.7 298.6 300.7 301.6 306.8 313.2 319.6 327.4 331.5 336 339.7 341.9 347.5 361.4 376.6 404 432.6 +15.8 18.5 22.5 29.6 40.6 61.9 70.4 90.1 102.7 114.1 129.5 146.4 155.4 168.3 173.6 172.6 170.7 170.5 169.9 174.3 182.9 182.5 183.1 184.8 185.2 186.4 177.8 168.2 157.5 151.7 147.8 140.9 135.3 125.4 117.2 105.7 86.6 66.6 56.3 46 36.6 26.6 17.9 10.6 8.2 6.9 6.3 6.2 6.5 6.4 6.4 6.5 6.8 6.8 6.8 6.8 7 7.3 7.3 7.2 7.1 7.2 7.5 7.8 7.8 7.9 8.2 8.4 8.7 9.1 9.4 9.8 10.1 9.9 10 12.3 18.1 22 29.1 35.9 41.6 42.3 36.9 47.8 57.8 72 83.1 98.6 116.2 131.8 147.9 165.5 175.1 181.6 186.7 205.3 221.8 220.4 223.9 232.5 229.9 222.2 214.7 204.9 199.5 195.1 191.8 189.2 188.7 188.4 189.1 190.4 194.1 203.5 216.6 225.6 233.9 242.3 245.5 249.6 253.5 251.1 247.3 244.3 239.9 236.5 233.5 228.5 229 224.8 221.8 218 217.1 217.1 215.4 212.2 210.2 209.8 210.3 212.1 213.1 216.2 216.6 216.9 215.1 214.3 208.9 203.3 201.4 201.2 202.1 200.9 202 205.5 209.3 211.8 215.3 219.5 223.4 223.2 222.7 223.5 225 226.8 229 231.1 232.7 234.4 236.9 239.7 241.7 245.4 252 257.3 262 269.5 272.8 276.2 282.9 286.9 290.7 295 295.9 300.4 305.9 312.9 315.8 317.9 318.5 326.7 331.4 334.1 339 340.6 341.8 347.5 356.9 374.1 397.4 408.4 +21.6 31.1 40.2 46.6 63.1 78.4 93.2 119.9 134.4 140.2 145.8 150 158 167.4 171.7 172.4 170.3 169.5 171.1 176.4 181.7 183.3 180.7 178.5 180.1 180.6 168.2 160.6 153.6 148.3 136.3 135.2 121.8 107.2 107 93 69.8 52.2 41.8 33.5 24.4 17.1 10.2 6.9 6.4 6.2 5.6 6.3 6.1 6.6 6.8 6.9 7.3 7 7.1 7 6.8 7.2 7 7 7 7.2 7.5 7.7 8.2 8 8.1 8.3 8.7 9 9.1 7.7 9.6 10.4 12.1 14.4 18.1 23.1 31.1 38.3 45.2 51.7 47.7 51 59.7 74.1 84.8 94 113.7 131.7 147.8 163.2 173.1 176 181.1 190.3 205.1 202.7 207.9 216.7 218 211.8 206.6 200 196 191.2 190 189.1 188.6 188.5 189.4 192.5 197.9 210.7 221.4 231.7 239 245.2 251.7 256.7 262.3 259.7 259.6 256.9 254.2 250.9 247.6 245 239.6 236.3 232.6 229.1 226.4 225.5 223.2 222.8 222 221.8 219.9 221.5 224.1 227.3 226.4 224.2 222.9 220.2 216.5 208.9 204.6 203.4 204.8 200.3 205 208.4 211.4 215.1 216.9 218.4 221.2 224 225.1 225.6 226.8 228 230.6 232.8 234.1 235.9 240.3 242.1 249.2 256.5 263.2 269 275 280 283.9 287.1 290.6 294 296.1 298.2 300.9 307.2 313.6 321.3 324.9 327.5 330.6 333 336.9 338.6 341.3 343.7 345.8 351 356.9 365.1 376.5 387.7 +29.4 45 58.4 67.5 76.5 93.9 112 137.1 153.1 153.9 153.3 152.7 155.9 164.1 166.9 165.8 166.8 170.3 172.4 174.2 179.3 181.2 177.3 175.1 173.9 167.1 156.8 154.3 150.6 143.3 124.3 115.6 99.9 87 76 58.3 46.1 35.8 27.6 20 14.4 9.5 7.7 6 6 5.7 5.8 6.1 6.4 6.7 6.6 7.3 7.8 7.2 7.3 7.4 6.7 6.8 7.1 7 7 7.2 7.4 7.6 7.9 8 8.1 8.3 8.9 7.3 9.1 9.6 10.2 12.1 15.3 18.5 22.9 26.8 32 37.8 44.2 51.5 58 63.9 71.9 78.3 85.9 94.8 94.1 124.8 144.9 158.2 162.5 167.1 171.5 177.3 183.7 189.3 195.1 200.1 203.2 200.6 199 194.1 190.3 188.7 188.4 188.4 188.4 189.3 191.1 196.2 202.4 214.5 224.1 233 239.5 250.6 257.3 262.1 266.6 270.3 272.5 273.4 266.7 261.8 258.7 255.2 250.4 247.4 243.3 239.8 236.7 234.6 234.1 234.9 235.9 234.1 232.1 231.6 236.8 237.9 233.6 232.2 232.1 227.7 221.1 215 208.6 206.5 206.5 206 205.9 209.6 213.7 217 218.3 220.1 221.8 224.4 225.3 225.7 226 227.7 230.8 233.7 236.2 240.6 246.2 251.8 263.1 272.5 279 286.1 293.2 297.5 300.7 302 303.3 304.1 305.1 303.6 307 312.7 318 325 329.4 334.2 341.8 344.5 345.8 346.8 346.6 347.9 348.8 352.4 356.4 361.3 368.1 377.8 +40.5 61.5 76.5 84.7 91.8 107 123.5 152.2 159.7 161.4 156.3 154.7 155.4 159.2 161.7 164.6 170.4 173.7 168.1 166.3 170.4 172.1 168.8 165.7 160.6 156.8 149.1 142.6 143.2 136.7 117.9 91.8 81.8 68.8 54.9 39.6 26.6 18.3 14 9.5 6.6 6.2 5.5 5.5 5.7 6.1 6.4 6.1 6.4 6.5 7.1 8 6.6 5 5.7 5.1 6.5 7 7.2 6.8 7 7.3 7.5 7.5 7.5 7.8 8.1 8.4 8.6 8.7 9.1 9 10.7 14.3 18.8 24.4 27.9 37.8 36.3 41.4 46.7 52.8 60.8 68.9 79.7 91.3 103.9 115.9 121.6 114.1 130.7 148.9 154 159.1 164.4 168.3 172.9 178.5 184.3 188.3 189.8 189.4 189.4 187.5 187.4 187.7 188 188.3 188.3 189.2 192.6 197.8 202.8 210.8 219.4 230.7 241.9 254.8 262.6 269 274.8 281.8 286.2 287.3 276.1 270.5 266.5 262 259.4 255.8 252.4 248 245.1 244.9 247.5 251 253.5 249.6 245.4 246.1 243.9 241.4 235.5 231.5 232.5 229.5 221.1 217.1 210.8 208.7 209.2 209.5 206.9 210.8 213.7 217.8 220.7 221.9 222.2 223.2 223.2 223.3 224.1 227.7 231.4 236.2 241.8 248.8 258.6 270 286.4 300.1 307.5 301.6 306.1 316.3 313 311.9 311.7 311.8 311.2 310.3 310.3 316.5 320.7 328.3 335.5 349.7 353.5 356.1 357.7 357.7 356.8 355.4 354.9 355.4 357 361.3 367.9 372.4 +53.3 70.9 84.7 93.9 103.3 117.6 138.3 159.3 165.2 166.6 159.7 155 155 156.8 160.9 169.8 173.7 175 166.2 162.9 161.1 160.3 163.7 159.5 153.2 148.9 140.9 132.4 136.4 127.3 108.9 84.2 63.2 50 36.6 23.7 13 10.1 7.1 6.7 5.7 5.4 5.4 5.5 5.6 5.4 5.7 6.2 6.6 6.8 7.2 6.2 4.9 5.6 6.1 6.4 6.7 6.4 6.6 6.6 7 7.4 7.4 7.5 7.6 7.8 8.3 8.6 8.5 8.9 9.2 9.4 12.5 16.9 20.1 24.3 29.5 34.6 39.6 46 51.2 57.2 65.2 74.2 89.4 104.5 120.5 129.7 135.7 139.8 136.5 137.3 151.6 159.2 162 166.7 171.4 171.8 174.2 177.4 180.6 183 183.6 185.1 187.6 188.2 187.8 188.1 188.9 190 192.5 198.1 203.9 212.3 220.2 230.3 243.1 255.3 262.6 274.1 283.3 295.7 303.1 295.5 285.8 276.7 273 270.2 267 262.9 259.9 256.1 254.9 255.1 257.4 263 266.3 261.3 254.7 250.2 246 241.3 234.9 230.7 228.1 226.5 220.5 216.3 212.3 212.4 213.9 213.3 210.6 210.7 214.4 217.9 220.4 221.3 221.4 221.4 221.8 222.6 223.6 230.2 234.6 241.1 250.8 253.7 262 272.4 286.3 316.2 324.8 324.4 315.9 318.6 317.9 316.3 315.9 315.9 316 316.2 315.9 317.1 321.6 328.6 336.7 353.6 359 361.2 366.5 363.2 362 361.8 360.6 359.6 360.4 364.2 370 374.4 +71.4 82.7 91.5 99.4 109.8 128.3 148.2 163.9 167.7 166.8 158.1 154.9 155 158.4 165.7 173.2 178 174.9 164 157.7 153.5 155.3 156.4 153.9 142.7 134.8 124.9 123.7 123.7 108 90.3 67.5 50 35.9 23.1 16 9.3 7.6 6.4 5.8 5.6 5.3 5.3 5.4 5.4 5.3 5.7 6.3 6.5 6.2 4.5 5.4 5.5 5.9 5.9 6.1 6.9 6.9 6.6 6.7 5.3 7.2 7.4 7.5 7.9 7.9 8.2 8.2 7.1 10.1 11 11.8 13.7 18.7 22.2 26.2 31.7 38.1 46.8 53.5 59.3 66.4 75.1 88.2 102.8 118.7 131.7 140 144.6 149.1 150.7 136.8 148.4 157.7 160.6 161 160.4 163.1 168.7 174 180 184.2 186.8 191.5 193.1 193.7 190.5 190.7 192 193.9 195.6 203 209.3 215.7 222.9 232.8 242.3 251.6 262.9 279.8 289.4 302.8 309.5 302.1 296.3 285.3 277.3 274.6 271.5 269.1 266.9 266.8 264.5 262 262.1 264 265.2 261.3 256.3 250.7 245.7 239.6 232.9 228.9 226.8 224.5 219.9 217.2 215.4 214.9 215.3 215.3 214.2 210.7 212.9 216.2 218.2 219.1 219.5 220.7 221.7 222.3 223.6 232.2 238.5 245.4 253.1 257.5 263.9 270.8 281.3 299 327.9 326.1 318.4 316.4 316.6 316.6 317.2 318.4 320.1 322.3 320.5 321 324.2 330.4 335.7 347.2 355.5 362.9 366.7 365 364.5 365 363.6 363.8 366.1 368.3 372.6 376.8 +88.6 92.5 99.2 106 116.6 134 150.3 163.2 166.2 162.2 156.1 155 155 161.6 170 173.7 173.1 167.8 154.8 149.1 147.3 143.5 142.3 138.4 129.1 117.3 108.8 104.9 95.6 83.6 63.8 48.1 34.3 21 14.7 10 7.8 7 6.3 5.9 5.5 5.3 5.4 5.3 5.3 5.3 5.9 6.8 5.8 5.3 5.6 5.8 5.7 5.8 6.1 7 9.6 9.3 7.5 7.4 7 7.6 5.9 7.5 7.8 6.1 7.9 8.3 9.4 10.8 11.1 12.9 14.8 18.1 24.6 31.2 37.8 47.5 54 70.7 73.1 79.8 90 104.3 118.7 131.9 140.1 148.3 152.2 153 154.8 156.2 152.8 155 159.4 154.3 165.8 171.6 172.2 178.2 182.3 187.1 189.9 195.1 200.6 201.8 201.1 201.8 201.2 200.7 203.4 208.8 215.5 222.4 233.3 241.7 251.5 259.7 270.4 289.9 299.1 306.9 314.3 307.9 302.8 296.7 284.8 278.2 274.9 273 272.9 273 269.8 265.6 263.7 262.8 262 259.6 254.9 249.6 244.2 238.7 233.3 229.5 225.6 222.9 220.5 219.2 217.6 216.6 216.3 216.4 215.6 213.4 214.1 216.2 217.5 218.8 220.5 221.2 221.6 222.5 223.9 235.9 243.6 249.8 257.8 272.2 271.4 274.9 282 293.5 313.3 321.3 313.3 312.3 313.2 314.7 316.9 318 322.3 325.8 324.7 326.2 331.5 338.7 337.6 342.7 349.8 358.7 362.5 362.5 363.1 365.8 365.8 366.9 368.6 371.4 375.4 379 +99.4 106.7 111.2 115.5 122.4 136.6 147.4 158.3 164.1 161.6 156.2 155 155 162 169.5 169.3 161 150.7 141.8 142.2 142.9 138.2 134.3 126.1 114.8 103.8 94.6 92.4 82 62.5 46.2 33.5 21.6 13 10.4 8.3 7.2 6.5 5.9 5.7 5.6 5.4 5.4 5.3 5.2 5.4 5.7 5.9 5.3 5.3 5.6 5.9 5.8 5.9 7.6 15.6 15.9 11.8 9.3 7.9 7.5 8 7.6 8 8.4 9.4 9.4 10 10.7 10.5 12.3 14.5 17.1 22.8 29.5 36.9 51.2 62.3 66.3 74.6 88 101.8 113 123.9 132.9 147.6 154.6 160.6 160.6 160.6 161.9 165.3 164.8 166.9 170.2 172.9 163.3 167.3 174.6 179.9 184.8 189.5 192.5 196.8 205.9 212.8 215 215.5 213.5 210.4 211.8 217.6 225.9 230.6 237.5 245.8 254.4 264.3 277.1 296.1 306.1 310.5 310.7 303.4 301.5 296.5 292.4 283.5 278.7 275.4 274 273.1 271.2 266.7 264.9 263.7 261.5 258.2 253.4 247.8 243.8 238.1 232.5 229.6 226.6 226 224.3 223.8 222.9 218.2 217.4 216.9 216.7 216.2 215.5 217.1 218.8 220.7 222.7 222.6 222.9 223.7 224.8 230.1 241.4 252.6 261.5 278.2 282.8 281.8 283 289 294 298.5 303.3 306.6 309.1 311.9 315.1 318.2 322.2 325.2 329.1 330.3 334.9 340 339.9 343.4 347.9 354.1 359.5 359.8 361.5 365 366.9 368.4 371.2 376.8 379.8 382.6 +112.5 123.6 119.9 119.6 126 136.2 147 157.9 164.2 161.8 159.1 155 155 160.9 165.9 160.7 148.8 140 136 142.2 135.6 129 127 116.2 101.7 90.4 83.3 73.2 57.2 43.2 31.7 20.2 12 9.2 8.7 7.2 7 6.2 5.5 5.5 5.5 5.3 5.3 5.2 5.2 5.5 5.7 5.2 4.1 5.4 5.5 5.7 6.1 6.4 10.4 21.4 11.8 9.4 8.6 7.7 7.4 7.9 8.3 7.7 8.6 10 10 10 10.7 12.1 14.7 18.7 23.6 29.7 36 45.3 62 78 86.8 93.2 100.3 114.9 130.4 140.4 145.5 149.7 159.4 161.7 165.7 168.9 171.3 171.6 172.7 172.9 175.5 176.4 171.7 167.5 176.7 180.3 185.9 191.5 198 204.1 214.7 227.9 228.9 229.8 228.5 229 228.2 232.7 238.1 237.3 237.6 248.9 257.4 269.9 285.5 294.8 294.2 293.4 289.5 285.9 290.2 292.7 291.1 289.4 282.1 277.8 274.3 272.6 269.7 266.9 265.7 264.7 260.7 256.5 251.8 245.4 240.2 237.1 232.9 230.4 229.2 227.7 226.5 226.3 225.8 222.5 219.9 218.4 218.3 218.1 218.2 218.8 219.9 221.9 222.7 223.8 224.4 225.2 226.3 230.9 241.6 250.8 258.7 265.9 273.6 277.8 280.4 284.6 289.2 293.6 298.4 303.9 310.2 315.4 319.1 321.5 324.3 326.9 329.8 332.4 334 336 338.9 341.5 345.7 351.5 355.4 357.5 360.3 363.4 366.1 369.8 373.9 378.5 384.1 386.1 +122.2 133 124.6 122 126.1 138.1 150.2 158.8 164.2 163.6 165.4 155 152.8 154.9 159.5 150.9 140 133.6 129.9 125.8 122.1 115.1 104.5 96.1 86.1 74.5 64 52.3 39.1 28.4 18.9 12 8.1 7.8 7.2 6.9 6.7 6 5.8 5.6 5.5 5.2 5.1 5.1 5.2 4.3 5.8 5.3 5.2 5.7 5.8 6.1 6.3 7.1 7 7.3 7.6 7.4 7.7 8 8.1 8.1 8.4 8 8.3 8.6 10 11.6 13.9 17.3 24.6 30.7 38.2 44.8 54.2 59 69 86.6 100.9 107.9 113.8 128.1 144.6 151.1 156.2 158.2 166.4 169.2 171.9 174.9 176.9 179.7 180.6 181.4 179.5 180.5 176.7 173.7 179.7 182.9 188.4 194.6 200 207.5 222.8 243 256.8 247.8 248.3 249.3 245.1 249.5 250.1 249.7 251.2 258.5 266.4 276.4 282.5 284.4 282.1 279.9 278 279 283.5 287.9 289 288.4 279.1 274.2 274.1 272.3 269.7 266.7 263.6 259.8 256.7 252.3 245.8 243 242.2 240 233 231.3 231.1 230.6 228.8 228 226.9 224.8 222 220.8 220.5 220.2 220.7 221.5 222.2 222.6 223.6 224.8 225.6 226 227 229.7 240.2 248.2 254.7 260.3 265.4 271 276.2 278.5 283.7 291 297.7 303.5 309.4 315.3 320.3 322.8 325.5 328.1 331.6 334 335.3 337.1 340 343.4 349.1 355.7 357.5 358.9 361.5 365.4 367.4 371 375.7 380.3 384.4 387.8 +129.1 135.8 126 124.1 127.3 144.3 156.2 166.1 165 166.5 164.7 155.8 148.9 147.8 150.1 141.9 135.2 131.5 121.9 114.3 108.9 98.9 88.5 78.4 71 60.6 49.4 36 25 15.8 11.1 8.2 7.6 7.1 6.8 6.6 6.3 6.1 5.8 5.7 5.6 5.4 4.8 5.1 5.3 5.2 5.4 5.5 5.8 6.5 7.4 8.4 8.7 10.2 8.1 8.4 8 8.4 8.3 8.7 9.5 9.3 8.5 8.5 8.5 9.2 10.4 14.4 21.1 33.5 38 43.8 49.6 60.4 67.5 72.5 84.1 98.4 110.2 118.3 127.7 136.8 150.5 158.2 164 169.1 172.8 178.1 181.4 182.4 183 184.4 185.4 185.9 187.5 186.9 182.4 186 179.1 186.3 189 194.6 200.1 207.9 222.3 241.5 259.3 273 261.6 264.8 260.1 260.6 262.6 261.2 261.3 265.3 268.6 270.7 274 274.9 273.2 272.6 272.8 272.6 275.3 276.7 276.8 273.3 269.7 268.7 268.8 268.7 266.9 263.6 259.1 255.4 250.5 247.5 245.1 244.2 244.1 240.9 234.9 233.3 233.1 232.6 232.6 232.7 231.9 230.8 228.3 226.2 223.6 222.6 223.5 224.1 224.2 224.4 225.1 226.6 227.1 227.4 227.7 230 239.3 245.2 250.2 255.7 260.9 269.6 273.2 276.8 282.5 291 297.3 302 308.1 314.6 319.7 321.4 324.6 327.6 332.8 332.8 334.4 337.3 341.4 346.5 352.2 358.9 362.9 366.2 369.5 371.2 372.5 374.1 377 382.3 385.8 387.7 +131.9 132.6 123 129.1 130.1 148.5 162.8 165.7 164.5 165.1 164.9 157.7 143.1 134.5 138 131.1 129.9 125.1 112.6 102.8 96.5 93.8 80.9 65.5 64.1 49.1 30.7 20.9 14.3 10.6 8.5 7.4 7 6.7 6.5 6.2 5.9 5.6 5.6 5.7 5.9 5.7 -2.6 3.8 3.8 5 4.9 5.1 7.2 9.1 17 16.6 11.9 10 9.2 9 9 9.2 9.8 11.6 11.6 11.3 10.2 9.7 11.5 12.9 15.6 22.5 32.1 48.4 58.5 59.1 67.4 73.1 82 91.1 101.2 113.6 127.2 137.8 148.1 150.7 160 169.5 173.9 178.2 179 185 188.3 189.9 191.4 189.4 191 193.4 193.2 192.6 188.6 186.4 177.5 186.9 192.5 197.5 206.1 213.6 222.2 240.4 261.6 282.5 282.7 273.2 275.3 277 274.5 270.8 269.2 268.1 269.1 269.8 270.2 271.8 271 270 269 265.4 263.4 263.7 265.2 264.5 263.7 263.6 262.6 261.3 259.6 257.4 253.5 248.8 247.6 246.6 246 244.5 243.6 241.4 241.6 240.4 239.4 238 239.5 240 239 237.2 235 232.9 230.9 227.4 228.1 228 227.8 228.2 227.8 228.7 229.6 229.9 231.1 231.7 235.2 240.5 247.5 253.3 259.1 266.2 271.1 276 281.2 288.2 292.3 298.9 304.8 311.6 316.1 321.1 325.1 327.5 329.7 332.1 334.3 337.6 343.5 349.5 356.9 364.8 376.3 381.8 378.5 378 377.6 378 380.3 383.3 386.5 386.9 +128.5 125.4 123.1 128 134.2 150 155.9 159.9 161.6 161.5 160.2 154 141.7 129.7 129.1 125.2 118.6 111.1 101.2 92.7 91.7 89.5 68 53.6 42.3 26.9 15.5 11.6 9.2 8.6 7.9 7.2 6.6 6.4 6.2 6.1 5.7 5.6 5.9 5.7 5.8 -2.6 -2.6 5.2 5.4 5.2 4.7 5 8.7 13.4 21.9 17.3 11.7 10.5 10.7 10.6 11 11.8 12.6 13.7 14.3 14.9 13.1 12.7 14.5 17.2 23.5 32.7 41.7 58.5 72.2 71.6 77.7 88.3 99.9 108.7 118.1 135.4 146.8 158 161.3 163.5 165.3 173.2 181.1 186.7 187.9 192.1 194.8 195.5 197.2 198.1 199.1 199.1 199.2 197.7 193.9 189.7 184.6 190.5 195.2 201.2 210.3 220.2 231 245.9 271.3 299.8 298.8 285 281.3 281.2 279.3 275.4 273.8 269.7 269 269.1 268.6 267.8 266.3 264.3 261.8 258 256.7 256.8 258.5 259.7 260.6 258.7 256.6 254.5 252.9 250.4 249 248.2 247.7 246.9 246 246.2 246.4 246.4 250.8 249.9 247.3 246.6 245 244 242.8 241.2 239.6 238.4 237.2 235.7 234.6 234.2 234.2 232.6 230.7 230.3 232.2 235.4 237.3 237.9 237.9 239.1 245.4 250 256.2 262.7 266.8 273 278.1 285.4 293.2 296.8 300.1 309.8 314.9 320.6 326 330.6 333.7 336.6 339.3 342.9 346.3 351.6 359.9 367.9 383.3 382.7 383.4 383.8 381.3 381.8 385.6 386 386.1 386.6 +123.4 123.2 124.6 129.4 135.1 143 147.3 152.3 155.8 156 154 149.1 137.6 125.1 125.5 118.6 107.2 101.2 92.9 87 82 72.8 56 38.9 25.7 13.4 9.6 5.5 7.6 7.7 7.5 6.7 6.2 6.2 6.1 6 5.9 5.6 5.7 5.3 5.5 5.1 -2.6 4.7 5.1 5 4.9 5.6 10.5 12.2 13.5 10.8 11.6 13 13.8 14.1 15.4 16.4 16.9 18.3 18.6 20 18.3 18.3 20.4 22.5 29.9 41.1 47.3 67.3 88 94.6 97.6 103.2 112.6 120.5 134.9 150.5 157.9 162.9 168.4 175.5 173.7 183.9 188.8 191.9 194.7 195.1 197.4 198.4 200.8 201.9 203.7 204.3 203.8 202.9 199.6 194.4 187.4 194.4 199.4 204.9 215.6 226.5 239.6 256.3 280.5 300.7 296.8 288.7 284.8 281.1 277.9 275 272.3 269.7 267.9 266.6 264.3 262 259.3 257 256 253.4 253.1 252.1 251.4 252.5 253.3 252.3 251.4 249.2 248.9 249.3 249.7 248.8 248.2 247.2 247.1 249.4 251.2 252.7 253.6 254.6 253.3 251.8 250.5 249.3 247.8 246 243.8 242.3 240.9 238.6 237.4 237.4 237.1 236.3 232.9 231.7 235.5 239.5 242 243.1 244.1 244.7 245.6 248.9 255.7 262 268.8 276 281.1 286.4 294.7 301.2 306.7 310.9 315.7 321.8 328.3 335.6 340.2 342.9 348 349.7 352.1 353.2 357.7 366.2 373.8 377.7 384.9 385.9 383.5 384.3 386.2 386 386.9 386.9 +117.3 120.6 126.9 127.9 132.2 138.2 143.4 145.5 149.8 150.4 148.1 143.7 129.1 118.6 117 109.5 99.9 96.5 88 79.1 70.3 62.9 43.2 23.7 12.9 8.8 7 5.5 7 7.2 6.6 6 5.9 6.1 6 5.9 5.8 5.3 4.6 4.7 4.4 -2.6 -2.6 4.8 5.1 4.8 4.9 7.5 11.1 10.8 11 11.9 13.4 14.9 15.9 17.1 19.2 20.3 22.9 25.7 25.8 24.5 24.1 26 28 32.1 40.4 51.2 54 75.2 97.1 112 113 114.7 120.8 135.6 141.4 153.7 158.4 170.2 176.7 182.5 183.6 186.9 192.1 196.7 199.1 198.5 198.5 200.8 203.7 206.5 208.1 209 207 205.2 203.3 200.6 188.5 199.7 204.2 209.6 220.2 231.3 246.6 270.1 292.1 296 294 291.2 284.1 279.4 274.8 273 270.8 268.3 264.6 261.4 259.1 257.1 252.8 250.8 250 249.3 247.8 246.5 244.8 245.3 244.9 247.1 246 246.5 247.8 248.9 249.6 249.7 248.9 248.3 248.9 250.4 252.8 255.7 256.4 257.6 258.6 257.8 256.2 255 253.5 251.6 249.1 246.8 245 242.2 241.2 240.6 240.9 240.1 236.2 233.3 238.5 242 244.6 246.3 247.5 248.3 250 251.8 256.3 262.3 268.3 274.5 280.1 285.8 293.2 299.8 306.6 313.1 319.5 327.9 334.8 342.5 345.8 350.3 356.9 362.1 362.5 364.8 364.1 367.2 370.7 375.5 383.4 384 383 383.8 384.9 386.2 387.4 387.7 +111.6 115.5 122 126.2 129.2 135.3 139.9 142.2 144.8 143.3 140.3 130.4 118.7 111.9 105.3 98.9 91.9 91.2 82 71.4 60.5 49.6 30 13 9.1 7.2 6.8 5.5 6.7 6.6 6 5.6 6 6 5.9 5.8 5.8 4.6 4.4 4.9 4.9 -2.6 4.7 7.6 8.5 7.3 6 8.5 9.9 10.3 12.1 13 16 20.1 22.3 24 24.9 27.9 28.4 30.7 31.3 30.8 31.1 34.1 36.2 44.5 54.9 61.2 66.2 77.2 102.6 118.7 116.6 124.5 130.2 142.2 148.3 152.7 165.2 175.5 181.7 185.3 189.3 191.2 195.6 200 201.5 202.3 199.6 201.3 206 209.2 209.7 208.8 208 207.7 208.6 209 202.8 199.7 208.8 213.9 225.4 238.9 256 282.5 283.8 290.1 294.1 290.9 280.6 273 268.2 266.2 265.7 263.2 259 256.1 252.6 248.8 247.1 246.4 245.7 244.6 243.5 241.4 239.4 239.5 241.7 244.4 245 245.6 246.7 248.2 249.5 250 250.3 252.7 257.1 262.8 268.3 270.9 269.8 268.2 266.6 264.5 262.6 260.6 258.7 256.6 254.1 251.9 249.6 246.7 245.2 244 243.1 242.4 240.1 234.4 238.8 242.7 245.2 248.2 249.9 251.4 253.7 256.3 259.5 263.5 267.4 272.4 279 286.1 294 300.4 309.2 317.6 323.3 331.8 340.6 344.5 349.1 355.3 361.7 371.1 370.9 372.9 374.7 375.8 376.4 375.9 380.6 381.4 383.2 384.3 386.4 388.7 388.5 390.8 +108.2 110.9 117 123.1 127.1 132.7 136.4 138.9 139 136.8 126 116.1 109.2 103.6 93 86.3 82.8 78.6 71.3 62.5 50.8 38.4 16.9 10.4 8.2 7.1 6.4 6.4 6.5 6.3 5.8 5.7 6.4 6 5.9 5.7 4.9 4.3 -2.6 3.2 -2.6 -2.6 -2.6 8.4 8.1 7.7 8 9.6 12.2 14.6 18.4 23.1 24 28.1 29.3 30.3 30.4 32.1 34.8 35.2 35 34.3 38.4 40.4 43.1 52.6 64.6 75.4 82.8 92.7 100 108.1 119.3 128.3 143 148.3 151.4 161.1 169.5 179 183.9 188.8 191.6 196.7 198.5 201.6 203.1 203.4 202.8 202.3 206.9 209.2 209.9 209.7 210.2 212.7 214.2 217 215.3 204 206.1 220.9 235.9 242.7 255.4 268.8 273.8 276.7 280.1 276 268 263.9 260.3 256.9 255.3 253.2 251.1 248.3 246 244.2 241.9 240.3 240.4 239.8 240.3 237.4 234.7 237.8 244.1 251.8 249.6 251.4 251.8 249.1 250.8 253.4 256 258.4 263.4 267.6 273.1 276.6 274.8 273 270.8 268.8 266.4 264.6 262.8 260.7 258 255.3 252.6 250.4 247.7 245.6 244.2 243.1 242 238.7 235.9 241.3 245.1 248.4 251.2 253.5 256 259.2 262.3 266.1 269.7 273.8 280.2 288.2 296.1 303.3 312.1 320.4 327.3 336.5 342.5 348.7 359.7 360.1 366.5 372.8 379.5 381.7 382.8 384.2 384.7 381.7 381.4 383.5 384.9 386.4 387.8 389.2 392.9 401.4 +106.9 108.6 111.4 120.7 126.3 132.5 129.4 130.9 128.9 121.3 115.3 111.1 105.3 96.6 85.2 77.5 72.8 67.4 62.2 52.7 37.2 21.1 11.6 9.6 9 7.8 7.3 7 6.7 6.2 5.5 5.9 6.2 6 5.9 5.8 5.3 4.8 -2.6 -2.6 -2.6 -2.6 -2.6 8.7 9.5 9.2 10.3 15.5 18.8 23.6 27.4 29.8 31 31.9 33.5 35.6 37.3 38 39.7 40.1 40 40.2 42 44.6 52.7 64.2 78.6 93.2 99.4 112 119.7 124.7 130.7 139.7 146.8 151.8 158 165.1 171.7 178.5 185.2 192 196.2 198.7 200.1 202.7 205.5 206.7 205.4 204.2 207.7 209.6 210.9 212.1 214.3 217.4 218.8 220.4 222 220 203 227.1 237.3 243.2 251.2 257.6 261.2 265.3 262.3 260.1 259.4 256.4 252.5 248.4 244.2 242.7 242 241 240.5 239.5 235.3 234.5 234.3 234.9 234.1 234.1 234.1 238.5 246.5 253.4 263.8 268.2 265.7 264.6 264.5 264.9 264.9 264.4 266.6 268.7 272.5 276.4 276.9 275 273.2 271.5 269.7 268.1 266 264.1 261.7 259 255.5 253.2 250.8 249 248.2 247.1 245.3 242.6 236.6 240 245.1 248.9 252.4 255 257.9 261.3 264.8 268.1 271.7 277.2 284.5 292.3 299.3 307.7 316.8 324.7 331.7 339 344.9 352.5 359.7 364.9 370.5 378.4 384.9 388.1 389.2 393.1 393.5 391.6 389.4 389.3 388.2 388.6 389.3 391 397.9 406 +105.8 107.2 110 121.1 127 127.1 126.7 123.1 117.3 113.8 110.9 110.1 100.9 88 76.5 68.4 63.9 59.9 53.8 42 27.3 13.8 10.4 10 9.9 8.8 8 7.5 6.4 5.8 5.6 5.6 5.9 5.7 5.7 5.6 5 4.9 4.2 -2.6 -2.6 5.1 5 8.7 8.9 11.3 21.9 25.3 21.6 25.2 31.9 33.9 34.6 34.9 37.5 40.1 41.7 43.6 44.9 45.9 44.4 45.7 48.1 54.5 67.1 80.5 99.2 117.7 122.7 133.4 135.2 137.7 145.7 151.3 156.7 160.6 164.3 170 175.6 180.2 188 194.3 197.7 200.1 201.8 205.4 208.8 209.7 207.7 208.1 208.8 211.3 213.4 214.7 216.6 218.9 220.9 223.5 225.4 226.5 211.4 228 237 240.4 243.9 246 248.3 250.1 251.8 249.6 250.8 248.6 244.1 238.7 236.5 235.3 235.2 234.5 236.1 234.9 234.1 234.1 234.1 234.1 234.1 234.1 236.6 242.7 251.1 262.3 274.3 281.8 279.7 278.1 274.9 273.9 273.1 271.7 271.6 272.2 274.4 276.1 276.8 275.7 274.3 272.9 271.7 269.9 268.4 266.4 264.1 260.6 257.3 255.5 254.3 253.1 251.9 250.2 247.7 244.3 237.9 239.5 244.5 249.1 252.4 255.8 259.5 263.3 266.9 270.4 274.4 281.8 290.3 298.1 306.1 315.2 323.6 331.4 337.3 344.4 350.9 357.8 364.2 369.7 375.8 382.3 387.4 392.2 395.9 398.5 400.4 399.8 397.3 395.9 394.7 392.8 392.4 393.5 396.5 402.6 +104.5 106.5 110.4 120.2 123.2 120.6 120.7 118 114 109.9 105.1 97.7 89.6 82.5 68.5 59.7 56.7 53.4 45.5 34.2 20.8 14.3 13.3 13.8 11.4 9.8 7.7 7.6 6.2 6.1 6.2 6.6 6.6 5.9 5.8 5.3 4.9 4.9 4.6 3.7 -2.6 4.6 5.1 8.3 10.8 17.9 27.2 27.4 28.1 30.3 34.6 35.9 37.7 39.1 42.1 44.3 46 48 49.9 51.5 51.6 51.9 56.7 68.2 91.8 107.2 119.8 136.6 145.4 149.1 148 148.5 154.5 159.2 162.8 164.5 166.6 173.1 179.9 185.6 191.2 194.7 198.8 202.9 205.5 208.5 209.5 210.3 208.9 210.6 210.3 212.3 213.7 215.2 218.1 220.9 222.3 224.6 227.5 229.5 225.9 216.2 233.9 236.9 237.8 238.4 239 238.8 240.1 241.5 241.4 239.4 237 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 238.9 250.4 263 272.7 299.9 302.7 292.6 287.6 284.1 281.7 280.4 279.1 277.6 277.2 277.3 277 276.8 276.4 275.6 274.6 273.4 271.5 269.8 267.6 265.2 261.4 258.1 257 256.7 255.3 253.8 251.6 248.8 245.6 239.1 239 242.2 247.2 251.8 256.4 260.9 264.7 268.4 271.9 279.1 287.7 295.5 304.3 315.3 324.7 334.8 340.8 346.4 352.6 357.7 364.3 370.2 376.4 384.8 393 396.5 399 403.3 404.5 404.1 404.9 402.5 400.4 399.2 399 398 397.1 398.4 402.5 +102.4 105.9 109 114.6 116.4 114.9 117.5 115.9 112.9 103.2 96.5 91 84.6 75.8 62.4 52.6 49.5 45 35.7 22 16.2 13 13.6 12.3 11.5 10.5 8.6 7.9 6.2 6.7 7.8 7.9 6.2 6 5.9 5.6 4.7 4.9 4.8 -2.6 -2.6 6.7 7.2 10 14.2 21.1 25 31.6 34.3 33.7 35.6 37.9 41.4 45 47.2 50.3 51.7 55.1 58.2 58.3 60.6 64 70.9 83 119.1 141.1 152.7 157.4 160.4 160.5 155.1 157.4 161 163.6 164.3 166.1 169.6 175 181.6 186.5 192.1 195.8 201.6 205.8 207.7 208.4 209.6 210.6 212.7 214.1 213.1 213 214.8 216.1 218.4 221.3 223.8 225.9 228.9 232.7 232.5 229.4 230.1 235.2 236.5 236.5 236.9 236.7 234.8 234.2 234.3 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 237.6 249.5 258.2 269.8 278 298.9 293.6 291.8 290.4 287.5 285.6 284.4 283.4 281.5 280.2 279.9 279.6 279.1 278.4 277.5 276.4 275 272.9 270.6 268.1 265.9 263.5 260.9 259.3 258.5 256.9 254.6 251.9 249 246.3 241.3 239.2 240.3 244.4 250.8 256.6 261.3 265.4 269.2 273.7 281.5 290.2 299.3 310.1 319.9 328.5 339.2 347.7 353.4 357.6 362.7 368.9 374.4 379.8 385.5 394.3 400 403.7 407.7 408.2 407.1 407 404.7 403.4 403.1 404.6 405.1 403.4 403.4 404 +100.3 105.3 106.6 108 107.7 108.6 109.6 109 106.2 95.5 88.9 85.7 74.1 64.1 54.8 46.3 39 29.5 21.4 15.7 13 10.6 11.1 12.1 11 9.3 8.5 7 6.8 7.5 8.2 7.1 6 5.2 5.3 5.2 5.1 4.6 -2.6 -2.6 8.3 7.6 9.1 10.9 14.8 19.5 26.8 36.7 36.2 36 38.9 42.4 46.4 50.5 52.9 57.3 62.4 65.4 66.7 67.1 72 76.4 83.4 95.3 128.8 162.4 178.6 173.8 169.5 163.8 160.6 160.6 162.2 164.3 165.8 169.7 173 176.5 183.7 188.1 194.4 202 206.2 208.2 212.2 211.2 212.1 214.9 215.9 217.2 217.6 215.2 217.2 218.6 221.2 223.3 225.3 227.2 230.1 234.4 238 237.2 226.2 231 234.5 235.4 234.9 233.2 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 235.7 242.2 249.3 255.6 260.3 270.3 277.2 280.8 287.2 288.5 286.2 285 284.4 283.3 281.7 280.8 281 280.4 279.5 278.9 277.7 276.3 274.6 272.2 269.8 267.5 265.3 263.4 262.3 261.2 259.5 257.5 254.7 251.8 249 246.4 242.2 239 239.2 242.3 248.4 255 260.6 264.8 268.7 274.2 283.6 292.9 302.5 313.9 324.8 334.1 343.2 350.2 357.9 365.8 369.1 372.8 377.5 381.6 387.3 394.9 402.8 408.6 411.7 410.6 409.7 408.6 407.4 406.6 406.1 406.9 406.6 406 404.4 404.2 +98 105.2 104.8 103.2 103.3 103 103 99.8 96.8 89.1 80.2 69.7 61.9 51.2 43.6 36.3 29 24.6 18.6 14 11.2 9 8.7 7.8 7.4 7.1 6.8 7 7.1 7.9 7.3 6.3 5.2 4.7 4.8 4.8 4.9 -2.6 -2.6 8 9.4 8.2 9.7 13.5 16.1 19.9 29 34.4 36.4 40.4 44.4 48.5 52.7 55.9 60.6 70 71.3 72.3 72.8 75.8 82.9 86.1 90.6 103.1 131.2 169.3 182.4 179.2 171.4 163.5 161.8 162 164.6 167.5 169.3 172.1 176.7 181.3 186.4 190.8 197.2 205.8 211.8 215.9 215.2 216.1 213.7 215.6 216.7 217.7 216.8 218.4 219.6 221.4 223.4 225.2 227.3 229.3 233.7 236.6 239.7 241 239.4 236.6 234.6 232.9 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 235.4 240.6 244.6 249.9 254.1 266 271.8 272.8 276 281.4 281.9 280 279.8 279 279.5 280.7 281.4 279.9 278.6 277.2 275.4 274 272.3 270.2 268 265.8 263.3 260.9 259.3 259.1 257.7 255.1 252.4 251.3 249.1 246.3 243.2 238.5 239 241.7 245.3 252.3 258.9 264.8 270.4 276.9 285.4 297.2 307.4 316.4 326.1 336.4 346.2 354.5 361.5 367.8 374.6 376.6 379.6 384.5 392.3 400.4 409.3 414.5 415.8 414.8 414.8 412.1 411.2 411.5 410.2 409.5 407.5 406 404.2 402.5 +93.4 102.7 101.1 101 101.1 99.1 96.2 93.4 91 85.2 74.6 61.7 51 43.2 37.3 30.2 24.4 22.7 19 13.8 10.1 8.2 7.2 6.3 6.3 6.2 5.6 5.8 5.5 5.8 5.1 4.9 4.6 5.8 4.9 -2.6 -2.6 -2.6 8.7 10.4 10.9 10.6 13.6 17.3 22 26.8 32.7 39.3 43.7 47.4 53.2 58 60.9 62.9 65.7 75 77.4 77.7 78.7 84.7 94.5 94.4 99.2 108.2 131.5 166.7 192.4 183.3 169.5 164.6 162.4 163.1 167 172.3 175.7 178.9 183.6 187.5 190.3 193.7 200.4 211.2 218.8 223.9 225.6 224.3 223.7 218.2 219 218.8 216.9 220.4 222.6 222.2 224.5 226.6 229.9 234.9 236.6 237.8 241.7 244.1 243.7 241.3 238.8 233.4 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 233.3 234.1 234.1 234.2 237.8 241.6 246.9 250.5 256.5 262.5 265.9 268.7 272.3 274.7 273.9 273.2 273.6 274.3 275.9 278.2 276.9 275.4 273.6 271.7 269.8 268.1 266.2 264.6 262.4 261.1 258.8 257.1 256 254.2 252.6 251.2 250.4 248.2 245.5 241 237.9 238.8 241 244.9 250.8 256.9 263.5 270.5 277.7 286 296.3 307 318 327.4 337.7 347.4 353.2 362.3 371.6 376.7 379.2 385 387.4 393 403.3 414.4 420.7 423 420.9 420 417.5 415.9 412.8 409.5 408 405.9 404.3 402.7 401.1 +87.7 92.5 94.8 97.6 98 94.3 90.3 87.3 86.2 79.6 67 58.3 49.8 40.9 32.9 26.9 21.5 20.1 18 13.5 9.9 7.6 6.3 6.1 6 5.8 4.8 4.8 4.7 4.6 4.6 4.9 -2.6 -2.6 -2.6 -2.6 -2.6 6.7 11 11.8 12.6 14.2 17.6 23.9 29.5 34.2 40.5 46.4 52.1 57.8 63.6 68.5 71.3 72.2 74.9 80.3 82.3 82 87.1 94.9 100.5 101 104.9 110.3 127.7 164.1 185.7 178.7 165.4 165.7 163.8 165.4 170.8 176.7 181.2 185.9 189.9 192.5 194.1 195.8 203.6 215.9 222 226.7 229.1 228.9 222.9 221.7 218 216.7 216.3 220.8 222.5 221.4 224.3 227.9 230.8 233.5 236.9 239.1 242.6 245 244.7 241.6 237.5 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.4 233.9 234.5 234.1 235.9 239.2 245.4 248.6 251.9 256.9 260.9 263.9 266.4 269.5 267 264.9 266.3 267.8 268.9 268.7 268.9 268.8 267.2 266.3 264.4 262.4 260.9 259.5 258.6 257.2 256.7 255.3 254 251.2 250.2 249.2 247.2 243.7 239.7 237.2 237.6 238.1 239.8 243.6 249.2 255.2 262.6 269.8 277.2 287.4 296.9 306.5 316 329.4 340.3 346.8 353.2 362 370.8 376.4 382.1 385.2 386.7 391.9 402.8 415.7 426.4 425.5 423.6 420.7 417.5 414 410.9 408.6 406.8 404.3 402.5 400.5 398.1 +82 87.5 92 93.5 93.2 89.2 85.3 83.5 81.1 73.4 62.8 56.5 51.9 40.4 29.9 23.7 19.5 16.8 15.2 12.7 9.5 7.1 5.7 6 5.4 4.7 4.6 4.6 4.6 4.6 5.2 -2.6 -2.6 4.7 4.9 4.8 6.8 10.3 12.1 13.2 15.2 20.6 27.3 35.3 41.2 44.8 49.7 55 61.3 69.1 74.7 77.7 80.2 81.7 84 84.9 86.8 89.5 95.5 101.9 103.5 106.3 108.4 115.1 127.1 139.7 162.5 174.7 161.6 160.3 162.9 167.5 175.4 181.8 186.8 190.8 193 194.5 195 197.2 202.9 214.3 224.7 231.1 230.5 227.7 221.3 221.4 216.7 214.6 214.7 217.1 218.3 219.1 223 227.1 230.4 234.8 240 241.7 241.8 242.3 241.9 239 235.4 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.7 235.8 237.1 237.7 237.1 238.8 242.8 248.6 254.3 257.9 259.3 260.8 261.9 262.6 260.6 258.4 258.2 258.3 257.2 258.2 258.3 259.4 259.7 259.5 258.2 256 255 253.9 253.1 252.6 251.7 251.4 249.4 247.7 247.2 245.6 242.7 237.7 236.2 236.6 237.2 237.6 238.8 242.5 248.1 253.9 262.3 270.5 278.9 289 299.5 308.7 316.9 326.3 336.5 344.1 353.1 359.5 367.1 373.7 375.4 378.3 381.2 386.8 399 411.7 418.4 418.3 416.9 414.9 412.4 409.8 408.4 407.3 405.8 403.2 400.4 397.2 393.7 +79.9 85.1 87.8 87.4 87.2 84.1 79.6 78.8 74 67.1 59.5 55.6 52 39.1 27.3 21.4 17 15.3 13.4 10.8 8.5 7.3 5.8 5.4 5 4.6 4.5 4.7 4.8 4.8 -2.6 -2.6 -2.6 -2.6 5 10.8 13.1 13.5 14.2 15.6 19.8 29 38.8 47.7 53.4 55.8 60.5 65.9 72.6 80.8 83.7 86.5 88.6 89.6 89.6 90.1 91.6 98 106.6 113.8 110.1 109.2 113.1 116.3 123.3 135.2 144.4 157.7 153.4 155.7 165.8 174.4 180.9 186.8 191 194 195.3 195.2 195.2 196.6 203.5 216.3 227.5 228.1 228.9 223.8 218.8 217.1 213.2 212.4 212.5 214.8 214.5 215.4 220.1 225.1 230.8 239.2 243.3 241.8 240.3 241.2 240.8 239.3 237.4 235.1 233.5 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.1 234.9 235.9 235 237.6 238.3 239.2 240.1 240.3 241.1 243.5 250.3 256.5 258.8 258.2 258.4 258.6 258 254.7 254.1 251.8 248.5 248.7 249.4 249.3 249.9 251.6 252.3 251.5 249.5 248.4 247.8 246.8 245.6 246.7 246.6 246.1 245.6 244.5 242.8 239.2 236.3 235.9 236 236.3 236.5 237.9 241.5 246.1 252.4 263.6 272.8 281.3 292.4 305.5 316.3 323.1 330.2 338.4 344.7 350.8 357.3 361.1 365.5 368.2 371.3 374.8 379.8 390 400.6 402.6 405.7 404.7 403.9 403.6 403 403.5 404.2 403.6 400.6 397.5 393.8 389 +71.6 71.5 81.1 79.3 77.2 76.2 74.3 72 67.5 63.7 59.2 55.6 49.2 36.5 24.5 19.1 15.7 13.2 11 8.6 6.5 6.2 6.1 5.9 5.5 5.1 4.8 4.6 4.9 4.6 4.4 -2.6 -2.6 -2.6 7.9 11.6 13.3 16.3 19.8 21.8 28.4 37.7 46.9 54.2 62.2 67.2 72.2 78.9 85.1 89.7 91.3 94.5 95.4 96.2 95.5 95.4 99.3 111.2 126.5 128.2 117.9 114.5 116.9 117.2 120.2 127.7 130.7 140.6 145.2 159.7 171.1 180.5 186.9 191.3 194.8 196.3 195.7 195.6 195.8 200.3 208.1 213.8 221.6 223 220.4 216 213.1 208.9 206.8 206.8 207.8 208.7 210.1 213.9 219.5 224.5 230.9 234.5 236 238.6 240 241.2 241.4 240.6 239.5 239.1 238 234.8 234.1 234.1 234.1 234.1 234.1 234.9 235.2 232.6 235.1 236.1 238.3 240.7 241.5 241.7 241.5 243 244.8 244.7 243.6 244.3 246.7 249.4 251.1 253.4 254.6 254.7 252.8 249.9 247.1 245.2 244.2 243.7 243.3 243.7 245.3 246.3 246.7 246.6 246.2 245.2 243.6 244.2 244 244.1 244.9 245 244.4 242.9 241.6 238.4 236.5 236 235.6 236 236 237 239.9 242.8 250.4 263.6 273.4 284.6 299 314.5 323.2 331.1 336.6 341 345.5 350.1 354.2 357.8 361.3 363.8 365.9 369.1 372.2 378.5 384.7 388.2 392.4 395.4 396.8 397.9 397.9 398.9 401.2 400.7 397.5 394 389.2 383.7 +66.4 65.1 64.8 67.4 68.6 68.7 67.8 66.5 64 61.3 57.5 50.3 43.5 31.1 21.7 16.8 13.7 10.2 8.8 6.8 6 5.5 5.3 5.3 4.9 4.2 4.3 4.3 4.7 4.8 4.6 4.5 -2.6 -2.6 7.5 11.7 17.6 25.1 29.6 29.4 37.5 45.4 56.7 73.7 79.1 82.9 88.4 94.4 98.7 102 104.1 103.7 103.8 103.1 101.5 101.4 106.1 132.9 147.9 137.2 122.4 117.7 116.1 116.8 118.2 120.5 123.3 133.4 147.7 165.8 176.8 184.9 189.3 192 194.7 196.2 195.7 196.2 198.3 204.4 209.4 214 215.2 214.7 213.1 210.6 206.4 204.8 204.1 204.5 206 207.6 210.9 214.6 220.8 227.7 231.2 233.8 238.3 241.7 241.7 242.3 242.9 242.1 240.9 239.9 238.2 236.3 236.2 236.4 236 237.2 240.3 244.7 244.5 243.8 242.7 249.1 256.7 250.5 252.5 252.3 248 246.9 249.2 250.2 249.3 246.5 247.7 248.8 249.7 251.7 253.8 251.8 248.8 245.8 242.8 240.7 239.6 239.4 239.5 240 241.6 242.8 243.3 243.4 242.7 241.8 240.5 240.9 241.5 243.5 246.1 246.8 245.2 242.3 240.7 238.3 237.4 236.1 235.4 235.5 235.8 236.7 239.3 243.3 249.8 263.1 276.4 291.3 311.4 319.9 332.2 338.4 341.3 342.2 344.1 347.5 350.8 353.6 356.3 359.3 361.7 364.3 367.2 371.3 376.9 380.4 385.5 390.8 392.5 393.8 394.1 395.6 397.3 395.7 393 389.5 384 377.7 +76.6 82.3 70.8 60.2 58.8 61.3 63.3 62.8 62.1 59.8 51.2 40.3 33.6 25.3 18.3 14 10.7 7.4 5.5 5.3 4.8 4.5 4.5 4.6 -2.6 -2.6 -2.6 -2.6 -2.6 -2.6 -2.6 -2.6 -2.6 5.3 7.7 12.4 20.7 25.3 27.6 35.8 44.7 52.5 74.8 90 96.8 99.4 101.9 104.1 107.8 111.8 113.3 111.6 109.7 107.8 106.1 106.1 115.7 153.5 161.7 145.6 128.4 120.8 117.5 118.7 122.7 122.4 128.9 138.6 153.2 172.4 181.7 188.2 189.7 190.6 193 194.5 195.4 197.3 200.5 205.6 211.4 210.8 209.1 208.7 206.8 205.2 204.2 202.8 203 203.5 205 207.8 212.8 218.4 225.6 233.2 237.8 240.9 244.4 248.5 249 249.4 247.3 246.8 245.2 243.4 240.2 239.3 243.4 245.9 248.2 250 252.9 259.2 254.9 254.8 254.8 257.8 260.8 256.8 259.7 258.3 254.9 251.9 252.3 252.6 253 249.8 249.5 251.4 252 253.2 251.8 247.8 244.9 242.8 240.7 239.7 239.4 239.2 239 239.2 238.7 239.3 239.1 238.8 238.8 238.7 238.7 238.6 239.2 240.8 245.1 245.2 244 242.1 240.5 239 238.1 237.5 235.6 235.4 235.7 236.5 240 246.7 254.3 265.8 279.8 292.8 308.6 321.1 334.1 336.7 337.1 338.1 341 343.9 347.1 349.6 351.9 354.4 357.6 360.3 362.7 365.3 369.2 373.1 377.3 383.7 387.4 390.1 392.2 392.3 391.6 390.2 388.7 384 377.6 370.5 +80.5 84.2 68.2 57.9 55.5 57.5 60.5 61.8 61.1 58.1 45.4 32.3 25.3 20.8 14.8 12.2 8.8 4.9 4.6 4.3 4.2 4.3 4.7 -2.6 -2.6 4.2 3.8 4.6 4.7 5.1 6 7.4 7.9 8.3 9.9 14.3 21.8 29.2 35.3 45.2 48.4 66.2 83.2 101.9 107.9 108.4 108.3 110.6 114.6 118.3 116.5 113.7 110.2 107.8 107.1 109.3 121.7 150.6 165.2 147.3 131.3 123 119.9 120.8 121.7 126.5 135 145.3 162.2 178.9 183.6 186.8 187.8 189 191.3 194.7 196.2 198.9 204.1 208.6 210.2 206.7 205 204.2 203 202.5 200.8 200 200.4 202.3 205 207.1 214.3 223.5 235.3 247.7 249.8 252.9 258.7 260.7 256.3 257.6 256.1 253.5 250.9 249.2 246.8 252.3 258.2 262.9 265.2 267.3 278.3 277.9 267 266.2 264.2 265.1 264 261.2 262.2 260.5 258.5 257.2 257.2 255 255.6 253.4 251.9 253.4 255 252.6 249.6 246.8 245 244.4 243 240.9 240.3 239.6 239.4 239.9 239.4 238.9 238.8 238.6 238.2 238.1 238 237.8 237.8 239.1 241.2 242 242.1 242.7 242 240.2 238.8 238.2 236.6 235.3 235.6 237 241.9 248.8 256.4 266.8 277.8 288.7 305.1 319.4 330.1 329 330.5 332.4 336 339.2 343.2 345.6 347.5 350.3 353.3 356.1 358.6 360.5 363.3 366.6 370.6 374 381.2 388.2 390.5 389.7 387.9 386.2 382.7 377 370.5 363.6 +78.6 74.9 63.9 57.3 54 55.5 59.8 59.7 58 53.1 38.4 26 20 16 12.5 9.9 4.7 4.6 4.4 4.3 4.2 4.1 4.7 -2.6 -2.6 4.3 4.5 4.5 4.8 7.3 7.3 7.5 10 11.8 15.9 21 27.1 33.6 42.5 43.3 55.5 69.7 84.2 108.8 116.8 112 115.8 118.5 120.5 121.6 118.9 115.4 109.5 107.1 106.9 112.3 122.9 141 153.4 142.5 131.6 125.2 122 122.9 125 134.6 145.1 158.8 174.5 181.7 180.4 183.8 187.9 190.2 192.6 198.2 202.5 206.9 208.6 206.6 205.5 203.8 202.1 201.2 199.8 198.8 197.9 198.4 200.4 203.6 207 211.7 219 228.6 238.7 249.3 258.4 261 269.6 272.2 265.4 263.1 261.5 260.3 257.3 257.5 261.3 270.2 284.8 289.3 288.8 292.7 298 292.3 278.9 277.4 275.7 272.8 270.7 266.2 265.9 266.6 264.6 261.9 260.1 260.7 264.9 263.6 260.6 255.6 253.8 251.7 250.2 248.6 248 247.3 246.5 244.1 241.7 240.1 239.9 240.5 240.1 239.5 239 238.9 239 239.3 238.6 237.9 237.4 237.1 237.9 239.3 240.5 242.3 244.1 244.5 241.3 238.9 236.1 234.9 235.3 237.3 242 250.1 257 266.3 275 284.4 297.3 312 320.1 322.2 324.9 327.2 330.1 333.4 337 340.3 342.8 345.6 348.7 351.3 353.3 355.1 358 363.1 367.4 369.9 376.3 384.9 387.6 387.2 385.8 382.7 377.4 367.5 362.2 357.2 +75.5 72.4 67.2 61.8 54 53.3 56.9 56.5 53.7 42.9 30.3 21.5 16.4 12.8 10.9 8.2 -2.6 -2.6 -2.6 4.2 4.1 4.1 4.9 4.7 -2.6 -2.6 4.6 4.4 5.7 8.8 10.2 10.4 12.9 20.2 20.8 21.4 27.3 36.7 40.5 57.8 65.3 75.7 87.6 108.5 108 111.6 113.6 121.2 126 125.4 122.3 115.6 108.6 106.2 108 114.2 124 138.3 140.1 137.4 131.6 126.8 125 126.8 134.4 144.8 152.5 167.8 170 172.3 176.8 182.2 186 188.1 192.7 200.3 205.5 209.7 208.3 203.6 201.1 199.9 198.6 197.1 196.6 196.5 197.2 199 203.5 206.4 210.4 216.2 224.5 234 245 255.4 264.3 271.4 272.8 274.1 272.4 270.1 268.8 265.5 264.9 267.4 271.8 277.2 287.4 295.2 302.9 309.1 310.3 307.6 292.2 290.7 286.6 281.7 277.3 271.1 273.1 271.4 269.3 266.2 266.9 267.1 271.7 269.4 266.5 263.4 258.3 253.6 253.5 252.7 250.4 248.2 246.5 243.6 241.7 240.9 240.9 240.7 240.6 240.3 239.7 241.2 242 241.4 240.5 238.6 237.7 237.5 236.8 237.7 238 239.8 243.1 243.1 240.1 237.5 235.2 235.1 236.2 238.8 243.4 250.7 254.4 261 270.5 281.2 289.4 302.5 310.2 314.2 316.3 319.4 323.3 327.5 330.9 335.1 338.1 341.3 344.5 347.8 349.2 351 354.8 360.2 364.3 368 373.1 378.4 383.9 386 384 376.8 367.2 361.4 354.2 347.6 +78.4 75.4 71.1 66.3 54.9 52 52.8 54 44.4 34.4 24.6 18 14.1 11.8 10 -2.6 -2.6 3.7 -2.6 3.5 3.9 4.6 4.6 4.4 -2.6 -2.6 5.7 6.9 8.7 10.9 11.9 12.8 12 16.3 18.2 23.3 31.1 41.8 54.3 70.7 76 83.1 88 102.7 101.6 110.8 113.3 124.5 133.7 128.7 123.9 112.7 107.9 106.2 108.5 114.1 123.8 132.6 130.4 130.4 129.7 127.8 126.5 130.5 144.6 146.8 154.6 159.6 164.5 169.7 174.2 177.7 181.1 185.7 191.7 200.4 208.1 210.4 205.8 200.3 198.1 197.1 195.6 193.9 194.4 195.1 197.2 201.1 205.7 210.3 215.1 219.5 230.6 243.3 256.7 269.2 277.5 285.2 282.3 281.9 281.3 279.6 277.4 274.5 272.5 274.9 280.9 289.4 301.1 310.2 315.2 323.3 327.8 321.1 305.4 300 295.6 290.6 283.5 277 277.3 273.7 271.7 270 269.8 269.3 269.5 270.1 269.3 268.6 266.1 259.6 255.4 252.7 250.7 248.2 244.8 242.5 241.5 242.2 242 242.3 241.5 240.7 245.1 247.2 247.7 243.8 242.3 240.4 239.3 238.3 237.8 237.1 236.3 237.8 240.4 239.6 237.2 235.6 234.2 235.1 236.4 239.1 243.1 248.4 252.9 257.3 265.1 272.7 286.8 295.1 302 305.7 309.9 313.8 317.7 321.8 325.6 329.6 333.2 336.4 340.9 344 346.6 349.1 353.4 357.6 362 366.7 373 377.1 380.7 380.2 376.5 367.8 360.4 352.6 345.7 339.3 +82.7 79.6 75.8 67 55.9 51.1 48.9 41.1 35 26.3 20.2 15.3 11.5 8.6 6.6 -2.6 -2.6 4 -2.6 3.5 3.8 4.6 4.5 -2.6 -2.6 6 6.8 8.4 10.2 11.2 12.9 14.7 16.2 17.7 20.4 27.4 43.6 55.1 63.7 87.6 85.3 87.9 90 91.8 96.5 108.6 117.2 128.7 137 123.8 115.6 111.5 107.5 106.5 108.4 114 123.6 118.7 121.9 124.7 125.9 127.3 126.8 135.2 144.5 148.9 155.1 157.9 161.8 168.4 172.1 176.4 181.8 185.2 190.7 197.6 202 203.3 198.3 195.5 195.3 194.1 192.4 191.6 192.6 195.4 198.3 203 207.8 214.3 219.9 226.9 239.2 256.4 269.7 283 291.8 294.7 293.9 291.6 292.5 288.2 285 283.6 283.8 296.4 299.3 315.3 324.4 331 332.9 330.8 335.1 329.3 313.9 305.1 297.6 291.2 286.9 283.8 282.5 278.4 273.5 272.9 274.6 274.8 273.7 272.6 271.5 273.1 271.7 267.9 261.4 255.5 251.9 248.2 244.4 242.6 242.4 243.1 244.1 243.9 243.4 247.9 252.6 255.2 252.5 248.6 245.6 242.3 240.9 240 239 237.8 236.2 236.4 237 237 238.2 234.8 234.3 235 235.6 239.1 242.4 246 251 255.6 261 268.6 277 284.8 292.2 297.4 303.4 307.8 312.1 316.3 320.2 325.9 328 332.9 338.2 343.2 346.1 348.6 351.8 356.1 361.2 367.2 374.6 378.4 379.2 375.4 368.4 358.9 352 343.9 338.2 331.2 +90 82.9 77.8 68.9 55.4 49.3 47.9 47.6 39.2 27 17.9 13.3 10.5 8 6.1 -2.6 -2.6 4.1 -2.6 3.9 4.2 4.3 4.4 -2.6 -2.6 6.2 7.4 9.5 10.6 11.9 14.3 16.7 19.1 22.5 25.1 39.7 52.3 61.2 76.2 81.3 85.7 93 94.5 92.5 93.3 103.7 119.1 132.4 128.8 116 113.1 108.9 107.6 107 108 111.8 112.9 113.8 116.1 119.2 122 125.3 130.9 136.9 143.6 149.3 153.8 157.1 161.1 166.3 169.8 179.5 182.3 184 190.6 193.9 194 193.3 190.9 191.4 191.3 190.6 190.2 189.2 190.3 194 199.1 204.7 212.5 220.6 224.6 237.2 257.1 268.4 280 295.7 310.9 308.8 305 305.2 299.3 295.6 292.2 293.9 295.5 311 313.5 325.3 337.5 347.2 347.3 345.6 337.1 328.4 317.3 308.4 301 297.8 294.5 289 287.5 283.8 278.1 278.5 285.7 285.3 283.2 282.5 276.8 274.4 274.3 271 266.8 260 254.8 249.2 245.2 244.6 244.5 244.8 247.5 247.4 249.2 254.8 258.1 257.6 255.4 252.5 250.2 246.2 243.9 243.2 241.7 238.8 237.2 235.5 234.6 235.7 237.4 234.8 234 234.4 234.7 237.1 240.5 244.3 248.1 252.1 258.1 264.4 271.1 277 283.8 290.1 296.1 301.6 306.8 311.5 317.3 321.5 325.5 332 337.5 342.5 346.3 349.3 352.8 357.4 363.3 372.1 377 378.1 375 367.4 356.9 346.3 339.1 333.2 328.7 322.2 +94.8 83.7 79.1 70.6 56.6 48.9 47.6 45.5 36.9 25.6 19.2 12.5 9.5 8.4 6.1 -2.6 -2.6 3.8 -2.6 3.9 4.2 3.8 -2.6 -2.6 4.8 5.9 7.5 9.6 11.3 13.6 15.7 17.7 22.6 26.1 36.4 53.4 59.6 67.7 76.1 81.4 95.9 96.4 97.3 96 94.9 98.8 113 118.6 114.1 114.1 110.4 108.6 108.1 107.5 107.8 110.2 110.9 111.9 114.7 117.4 120.4 126.1 133 139 144 147.9 152.8 156.4 160.3 164.3 172.2 179.5 184.1 184.8 188.3 189 188.2 186.2 187.8 188.3 188.6 188.4 187.9 187.2 188 192.7 198.9 208 216.9 226 232.4 247.2 261.4 278.6 295.2 303.7 310.1 317.2 317.3 318.3 309.7 305.8 304.4 303.5 305.4 316.9 327.2 335 345.1 355.9 356 353.5 346.1 331.9 320.5 313.2 307.5 304.1 303.1 302.3 292.9 286.9 282.3 282.4 285.5 289.9 292.2 290.5 285.8 278.6 275.7 273.9 271.2 268.4 264.6 257.3 249.8 247.8 248.2 248.5 249.5 250.8 252.6 255 257.2 257.6 257.6 255.3 253.7 251.5 249.3 247.2 244.2 241.6 240.1 239 236.1 233.7 233.3 237.4 235.5 234 234.5 237.6 241.5 244.7 248.5 251.2 255 259.8 266.5 271.2 277 282.8 290.1 296.3 302.2 307.9 312.5 319 325 330.3 335.4 340.4 345.2 349.4 354.1 357.3 361.8 370.2 372.8 372.3 363.4 350.2 339.3 331.3 327.9 322.9 317.7 313.8 +97.8 86 79.5 69.7 56.6 49.7 44.7 41.3 31.1 23.9 16.4 12.1 10.1 8 5.4 -2.6 -2.6 4.1 -2.6 -2.6 3.6 -2.6 -2.6 5.3 5.9 6.4 7.4 10.7 12.5 14.7 16.9 20.6 23.9 29.3 45.8 60.3 75.7 81.1 85 90.3 99.4 103.3 102.7 100.8 98.5 100.5 107.4 109.2 110.7 111.6 109.4 109 108.7 108.7 109.4 109.9 111 112.2 114.3 116.6 120.1 128.1 134.9 139.7 143 150.1 155.6 158.7 161.8 167.9 176.1 180.2 181.7 182.8 184.2 184.8 183.3 184.8 185.3 185.4 185.9 185.8 184.5 182.7 188.3 195.2 199.9 212.2 223.4 233.7 240.8 254.7 266.7 286.9 307.2 314.9 316.2 319.4 328 332.6 323.9 316.1 316.9 318.9 320.4 333.9 340.6 353.3 364.2 374.2 369.2 360 347.8 333.7 326.5 321.7 314.9 307.2 305.9 303.4 297.8 291.8 287.3 286.6 288.5 293.3 300.1 297.8 292.8 286.1 281 278.4 275.2 274.8 271.7 264.5 260.7 256.9 252.9 252.9 253.8 252.8 255.6 255.9 258.5 259.6 260.1 259.1 258.7 256.8 254 251.7 247 244.3 242.5 241.1 238.2 233.7 231.8 235 239.2 240.6 239.3 239.1 241.9 244.4 246.9 249.1 252.4 257.2 262.6 267.2 271.6 276.9 285 291.1 298.7 304 309.9 317.6 323 328.2 332.9 337.6 345.8 349.4 352.9 355 357.9 356.2 358.3 355.7 343.4 329.6 322.2 317.1 313.9 311.2 310.1 307 +100.2 87.9 82.2 67 53.7 49.2 44.8 38.4 29.5 22.9 14.1 10.1 8.3 6.4 5.2 -2.6 -2.6 3.8 4.4 -2.6 -2.6 -2.6 -2.6 6.1 6 6.1 7.9 10.7 12.8 15.1 17.7 21.2 25.7 34.3 51.7 75.3 84.2 90.6 97.4 100 113.8 109.4 107.3 104.3 104 108 111.2 110.7 111.4 112 110.8 109.9 110 111.2 113.2 113.4 114.2 114.5 115.4 117.5 121.4 129.5 134.5 139.4 145.2 153.5 159.6 162.2 165.2 171.3 178.5 181.1 181.5 182.2 182.6 182.8 183 183.2 183.3 183 182.8 182.4 180.9 182.3 191 198.3 205.1 219.8 236.6 245.6 246.9 265.4 278.7 290.9 307.6 319.4 327 325.2 327.7 332.1 334.3 328.6 330 333.8 334.7 343.5 353.6 372.2 380.3 381.9 370.3 359.9 347.8 335.4 335.3 332.6 326.5 317.9 309.2 308.6 307.8 298.9 293.4 292.1 293.7 293.9 299.1 303.9 297.9 293.4 293.7 286.2 283.4 279 276.4 272.9 268.6 264.9 260.9 258.8 258.3 256.5 258.7 261.9 264.6 265.3 266.8 265.4 263.4 261.4 258.5 254.7 250.8 246.9 242.6 240.2 236.9 233.3 231.6 229.5 234.2 240.1 241.6 240.3 241.9 243.6 245.3 247.2 250 254 259.3 262.9 265.1 274.4 281.7 290.6 297.6 302.9 308.7 315 321.5 326 330.2 335.6 341.6 345.6 347.6 346.6 345 340.4 338.4 337.5 325.6 317.2 311.4 306.9 304.1 303.5 303.6 301.7 +100.9 89.1 76.9 60.5 50.3 47 43.9 33.5 27.4 17.7 11.5 7.7 6.9 6.2 5 -2.6 -2.6 3.6 4 5.9 5.4 5.6 6.1 6.2 5.8 6.1 8.7 11.3 13.7 16.1 19.5 24.7 29.6 38.6 56 76.9 90.4 102.6 104.9 107.4 112.9 110.5 109.3 108.3 108.7 113.8 118.1 117.6 117.4 116.2 114.2 114.5 116.4 117 117.6 117.1 116.7 117 118.8 121.9 124.8 130.3 136 142.2 149.8 157.6 164 165.1 168.2 173.9 180.2 181.4 181.7 182 182.3 182.5 182.7 182 181.1 179.8 178.7 178.1 178 182.3 192.1 204.5 211.6 232.6 247.5 253.8 248.6 262.7 278.7 297.9 305 325.3 327.4 330.5 332.2 337.7 344.5 343 337 337.6 340.5 345.9 354 365.9 378.8 382 375.1 365.2 349.8 341.9 344.9 341.8 342.1 330.5 318.2 314.4 313.1 305.8 300.1 298.6 297.4 301.3 302.5 303.7 306.3 304 302.2 296.9 292 285.8 284.3 288.5 279.9 273.8 270.1 268 267.1 264.7 265.2 267.7 269.8 272.5 276.1 273.7 271.1 267.6 263.4 258.7 254.2 249.1 243.7 240.2 237 233.9 231.6 230.4 230.9 237.7 240.1 240.4 240.9 242.4 244.2 245.6 248.1 250.6 253.6 257.6 262.9 271.7 279.4 289.6 295.9 302.1 308.3 314 319.8 324.3 328.6 333.3 337.4 340.2 338.5 334.6 331 328.5 324.6 319.1 312.1 305.3 301.3 298.1 296.7 295.9 296.7 294.8 +95.2 84 66.8 53.2 47.5 45.6 33.8 26.3 21.1 11.5 7.8 6.8 5.9 5.5 4.8 -2.6 -2.6 3.7 4 4.9 5.3 5.5 6 6.3 6.2 7.1 10.2 11.8 13.8 19.2 24.4 28 31.6 44.4 58.7 81.6 111.2 113.7 108.7 110.7 112.7 113.2 113.8 114.1 113.4 116.5 123.2 125.5 125.3 123.7 119.9 119.9 120.7 120.8 120.4 120.4 120.4 120 122.7 125.7 131.1 132.4 138.8 145.7 153.7 163.1 167.3 170.3 173.4 177.6 180.6 181.3 181.9 182.2 182.2 182.2 181.2 179.6 177.5 175.8 174.8 175.3 177.5 184 198.3 214.3 218.5 237.6 250.8 253 247.3 257.6 283.3 295.6 308.8 324 329.2 333.9 341.1 349.5 356 358.4 356 342.9 345.7 349.9 355.8 361.8 372.6 381.6 375.7 365.7 353 347.8 348.7 349.7 347.1 342.4 330.3 319.3 316.4 312.6 308 307.1 309.2 314.8 317.7 313.5 312 312.1 312.6 307.4 303.1 297.3 295 296.3 287.3 284.7 281 276.6 274.4 271.9 273.6 274.7 275.2 277 279.6 279.4 277.2 273.2 269 264.3 259.1 253.3 247.5 242.5 237.9 234.4 231.6 230.3 230.4 234.9 238.8 238.8 238.5 239.1 241.9 243.7 245.4 247 250.3 255.7 261.5 268.5 278 285.3 292.8 301.8 307.6 312.5 316.3 321.3 326.9 329.7 333.3 334 328.5 325.2 320.7 315.1 310.8 308.2 301.3 296.3 293.2 290.3 288.9 289 289.3 288.3 +89.7 74 56.2 45 39.3 36.3 24.5 21 10.6 6.1 6.4 6.3 6.1 5.7 4.6 -2.6 -2.6 4 4 4.9 5.3 5.6 6 6.3 7.7 9 11 13.1 17.1 24.8 26.7 29 35.4 47.9 71 104.2 120.1 118.3 111.8 114.4 117 118.1 120.9 122.8 123 127.1 131.5 132.4 132.1 129.3 126 125.4 124.6 123.7 123.2 122.8 123.6 124.7 126 129.3 131.3 135.4 141.9 148.3 156.8 166.5 171.2 174.1 176.8 179.4 180.7 181.5 182 182.4 181.4 179.9 178.1 176.2 173.7 172.3 172.9 175.3 177.5 185.3 202.2 217.7 226 230 238.1 245.8 242.3 252.2 270.3 281.6 301 316.5 326.9 347.9 356.2 355.9 360.4 362.2 361.7 348.9 349 353.7 357.9 364 373.6 380.5 378.8 366.9 355.2 355.6 358.9 364.2 363.6 351.9 342 331.6 324.1 317.8 314.4 317.8 322.4 324.2 322.9 326.1 325.1 319.8 320.7 318.1 311.2 306.7 303.3 300.2 297 295.8 293.6 288.5 284.2 280.2 280.3 280.9 281 282.9 283.2 282.8 281.6 278.8 274.4 269.6 263.8 257.8 251.6 245.4 239.7 234.3 231 229.8 228.7 234.6 236.7 235 234.8 236.8 238.9 241 242.9 242.9 246.8 252.3 260 265.5 273.1 281 288.8 298.9 306.6 311.2 314 318.3 321.8 322.4 323.8 323 320.3 313.4 308.2 304.9 299.8 296.5 293.6 287.9 284.6 281.9 281.3 281.8 282 282.2 +78.2 61.9 45.7 33.8 25.9 16.8 -2.6 -2.6 -2.6 4.3 4.5 5.7 5.5 5.4 -2.6 -2.6 3.2 3.3 3.7 4.9 5.6 6.4 6.4 8.1 9.5 10.9 12.4 15.9 25.3 26.7 27 30.5 41.6 60.1 98.2 119.1 121.5 117.7 117 118.6 121.3 123.5 129.2 130.9 133.6 135.8 138.9 136.5 137.3 131.9 129.7 128.7 127.4 126.1 125.2 124.7 125.6 126.6 128.9 130.9 133.2 138.1 144.6 152.9 162.3 170 173 175.8 178 179.4 180.4 181.4 181.6 181.5 179.8 177.4 175 172.7 169.5 171.6 173.9 176.9 179.8 187.4 199 209.7 218.4 220.1 225.4 230 236.4 241.8 258.2 278.3 294.9 311.5 328.1 342.8 353.4 360.8 363.1 362.8 358.3 356 358.2 364.4 365.2 366.6 377 382.7 382 365.9 359.2 365 370.5 377.2 376.8 361.9 352.9 343.4 333.2 327 324.8 329.4 333.9 335 335.8 339 339.8 338.2 330.2 327.1 323.5 319.2 313.4 309.3 304.2 302.4 298.8 294.9 290.7 286.3 285.7 286.7 287.4 289.2 289.3 288.2 286.9 284.8 280.9 275.8 268.8 263.4 256.4 248.8 242.2 235.8 231.5 229.1 230.2 233.8 235.9 233.9 233.4 234.1 235.8 237.9 239.8 239.2 243.7 250 256.1 262.3 269.7 278.1 286.5 295.7 304.8 309.5 311 314.8 315.9 315.4 314.3 311 306.5 301.4 297.1 292.3 289 286.8 283.5 280.1 277.5 275.8 275.8 276.2 276.7 277.4 +65.9 48.6 33.2 19.9 -2.6 -2.6 -1 -2.6 -2.6 3.2 3.7 4.8 5.4 5.1 -2.6 -2.6 3.2 4.2 4.3 4.8 5.9 6.1 7 9.7 11.8 12.4 14.3 26.6 27.4 25.6 26.5 33 59.3 82.8 112.9 124.1 122.4 121.3 122.3 124 126.7 130.5 135.4 137.3 139.9 141.6 140.7 139.1 137.9 133.6 132.4 130.9 129 127.2 126.2 126.2 127.3 128.6 130.8 133.3 136.5 141.3 148.3 157.7 167.5 171.8 174.1 176.4 177.7 178.9 180 180.4 180.5 179.5 177.1 174.4 172.2 169.6 168.4 172 175.1 178.1 181.4 187.8 196 203.4 206.8 211.7 219.3 229 237.6 245.2 256.6 272.3 291.7 307.3 321.3 335.1 351.2 363.9 370.3 372.4 370.6 368.6 367.5 371.9 378.3 377.8 378.6 378.6 374.1 366.2 368.1 378.7 384.6 387.5 383.6 370.3 362.7 351.2 341 335.3 336.7 340.4 341.1 342.7 345.4 350.7 349.9 344.6 338.6 338.8 332.6 328 321.6 318.3 311.6 307.6 304.4 301 295.2 294.3 294.1 293.1 293.8 294.9 295.1 295.1 295.1 292.3 287.9 282 275.3 269.7 262.1 253.9 246 239.6 233.3 229.6 229.3 230.9 233.3 232.8 231 231.5 232.9 234.9 235.7 237.2 240.2 245 251.2 259 266.3 274.3 283.3 293.2 300.6 306.1 308.2 310 309.1 307.4 305.7 302.1 297.4 291.8 287 283.3 280.5 277.6 275.2 272.9 272.1 271.3 270.9 270.8 271.7 277.8 +56.3 35.4 17.6 -2.6 -2.6 -2.6 3.6 3.6 -2.6 -2.6 -2.6 3.6 4.4 5.3 -2.6 0.7 3.5 4.2 4.3 5 6.1 6.8 8.6 10.9 13.1 14.1 17.5 28 24.1 23.8 26.3 41.3 65.6 101.9 122.5 130.5 127.2 126.2 127.3 129.5 134 136.8 140.9 142.3 145.1 146.6 145.2 140 136.2 135.2 133.9 132.1 130 127.8 126.4 126.8 128.6 130.3 132.8 135 138.1 142.4 150.2 159.2 168.5 170.7 173.4 175.4 176.6 177.1 178.2 178.6 177.9 176.9 174.8 171.7 169.7 167.3 166.5 171.1 175.8 179 183.3 187.3 191.8 197.7 201.9 210.6 221.8 232.7 243.1 254.7 260.5 270.8 286.2 304.1 328.5 348.5 366.7 378.7 387.6 389.9 388.5 391.9 385.7 382.1 388.9 385.2 384.2 378.3 370.7 368.2 374.4 382.1 391.8 392.5 388.4 379 370.3 360.3 349.9 345.5 347.2 352.1 353.4 349.5 351.6 353.8 356 353.6 347.9 342.2 337.6 328.3 329.2 323.8 317.6 313.3 311.4 306.7 302.6 301.9 303 302 301.4 301.3 303 303.5 303.2 300.4 294.9 289.3 282.6 275.8 268.2 261 252.7 244.5 237.2 231.7 228.4 228.6 230.3 230.5 229.9 230.2 230 230.4 231.6 234.1 236.2 242 249 256.3 264 274.9 282.4 292.1 298.8 303.3 305 304.4 303.2 301.6 299.4 295.3 289.3 282.2 277.8 275.2 271.7 269.2 267.2 265.9 265.8 266.8 266.5 267.3 270.9 276.9 +45.6 23.2 -2.6 -2.6 3.2 4.5 5 5.8 4.9 -2.6 -2.6 0.4 2.7 -2.6 -2.6 -2.6 4.1 4.1 4.3 5.1 6.1 7.3 9.2 11.8 14.1 16.2 19.1 21.7 21.6 22.7 27.6 46.5 79.6 104.9 122.5 129.8 129.4 129.9 131.2 134.3 140.8 143.3 147.1 149 148.8 151.6 144.3 139 137.1 136 134.3 132.7 130.4 127.9 126.7 127.6 130.8 132.3 133.2 136.5 139.4 143.1 151.1 159.4 165.6 168.9 172.5 173.8 174.5 175.2 175.5 174.9 173.5 172 170 168.2 166 163 167 172.3 176.6 179.7 183.4 186.1 189.6 194 202.8 216.1 223.4 237.8 249.3 262.5 271.8 279.9 292.3 316.6 340.1 363.3 396.7 406.3 405.2 402.3 403.8 406 400 392 389 388.7 382.4 373.7 372.8 376.2 383.3 387.3 390.6 395.6 395.8 387.3 377.1 369.1 359.9 356.3 356.6 357.1 357.8 359.9 363.8 361.2 363.2 360.5 351.5 347.4 342 336.3 333.3 328.3 323.8 320 316.2 311.7 309.7 310.6 310.8 310.6 310.4 311.8 314.2 314.9 312.6 308.6 302.9 296.6 288.9 281.8 274.8 267.8 260.6 252.7 245.6 239.2 232.8 228.7 227.2 228.2 228.5 228.9 228.5 228.6 229.4 231 234.2 240.5 247.9 255.5 265.2 272.7 280.2 287.9 297.2 300.3 300.1 298.5 297 295.5 291.9 286.9 279.8 273.1 270.9 268.3 265.1 262.3 261 261 261.2 262.1 263 264.9 269.3 275.2 +41.6 17.3 -2.6 2 4.1 7.8 11.9 13.5 12 12.8 -2.6 -2.6 -2.3 -2.6 -2.6 -2.6 4.1 4.2 4.3 5.3 7.6 9.2 8 11.6 15 17.2 18.9 19.8 21.1 22.5 32.3 56.5 81.4 105.3 115.1 125.4 127.7 131.4 135 139.9 144.8 149 150.8 150.5 152.2 149.6 143.4 140.4 137.8 136 134.2 131.9 129.6 127.4 126.6 128.3 131.4 131.3 133.3 137.6 141.8 146.9 150.5 157.8 163.8 170.3 171.3 171.6 172 172.2 171.3 170.1 168.7 166.1 166 165.7 162.1 161.9 172.4 172 174.9 179.8 183 185.1 188.1 191.5 201.4 216.7 232.6 246.9 261.5 274 285.8 293.1 302.2 325.6 347.4 366.1 393.8 408.6 410.4 414.9 414.6 413.4 410.8 403.1 394.4 387.7 379.8 375.5 380.3 392.8 402.9 405.7 400.9 399.6 400.1 396 386.1 378.6 369.5 363.1 361.2 362.6 366.6 371.7 372.7 370.4 368.2 361.8 354.6 349.6 343.9 341.2 337 331.8 327.8 324.1 321.7 315.9 317.1 317.5 319.6 320.9 322.5 324.3 324 323.2 321.6 318.2 312.7 306.5 298 288.9 280.8 274.5 268 260.7 256.8 247.6 239.7 232.8 228.1 226.2 227.1 227.2 227 227.1 227.7 229.7 233.8 239.3 244.4 253.5 260.8 268.9 276.5 284.3 291.1 292.1 292.5 291.8 289.9 287 282.9 278 271.1 266.5 264.8 262 258.9 256.6 256.5 257 256.9 258.8 261.3 263.2 267.3 272.8 +30.4 11.3 -2.6 3.4 7.8 9.9 13.9 16.7 16.2 17.1 14.8 10.3 -2.6 -2.6 5.3 6.1 5.1 4.9 6 7.2 10.1 11.6 11.4 9.9 13.7 17.1 18.4 19.3 20.2 24.8 39.6 54.1 71.8 91.4 102 111.6 123.9 132.3 136.8 143.5 149.4 152.5 151.9 152.2 153.8 148 142.7 139.8 136.7 134.7 132.7 130.5 128.3 126.1 126.2 128.2 129.4 129.8 134.4 140.8 145 148.3 151.6 155.6 162 166.9 168.1 169.1 170.3 169.1 166.1 163.9 162.3 162.4 164.5 164.4 159.6 162.8 166.6 169.4 179.3 181.7 184.1 183.5 185.8 197.8 218.1 238 245.7 259 275.5 284.4 292.7 297.1 304.9 314.8 333.6 358.4 383.9 401.5 410 420 426 426.7 419.7 407.9 397.5 390.2 390.3 390.7 400 410.9 419.9 424.7 419.3 412.2 408.1 402.6 396.4 387.3 378.6 371 368.4 370.6 372.9 376.9 375.3 371.8 369 363.3 356.1 353.2 349 342.5 338.5 335.1 331.9 329.3 326.9 321.4 324 327.7 333 333.8 335.7 336.6 336.8 333.6 331.8 328.3 324 319.3 310.2 299.7 290.7 285.5 277.6 271.6 265.2 255.1 246 238.3 231.2 227.1 225.2 225.5 225.4 225.7 226.3 228.3 232.1 236.4 241.3 247.6 256.2 263.5 272.5 278.2 281.6 282.7 283.5 282.6 281.8 278.4 274.3 270.7 264 260.7 258.7 257 254.2 252.6 252.2 251.7 255 258.1 260.5 261.5 265.8 272.3 +23.1 -2.6 -2.6 4.5 12.1 12.7 13 15.9 16.6 16.9 16.2 15.9 15.5 14.1 13.6 11.7 9.8 8.2 7.1 8.7 11.1 12.8 14 13.3 14 15.7 18.3 19.4 21.2 26.6 36.3 45.6 58.7 72.1 86.3 105.4 120.5 134.7 142.3 147.4 153 156.6 156.3 153.3 151.5 146.2 141.4 137.7 135.2 133.2 131.1 128.9 126.7 125.1 125.9 127.1 126.6 129.2 138.4 142.8 146 148.4 150.8 153.6 159.9 162.7 165.3 167.5 167.8 164.2 161.3 158.1 157.6 159.2 163.8 159.7 158.7 162.4 165 171.2 176.4 179.5 181.3 181.1 194.9 220 244.8 254.5 260.3 268.5 282.9 288.5 292.8 298.3 306.9 311.2 324.5 347.5 373.3 392.7 418.2 433 433.9 433.3 424.7 413.6 406.2 401.2 400.6 412.5 420.8 433.2 438.5 438.6 431.8 426.7 424.9 414.1 404.5 395.9 389.2 380.5 379.5 380 379.7 379.9 377.9 375.2 371.2 366.6 357.5 355.3 351.4 347.6 342.8 338.9 336.6 334.2 330.6 328.7 332.5 334.8 339.7 342.3 343.3 347.3 347.9 347.9 343.4 339.8 336.4 333 323.9 312.5 302.5 296 288.1 280 272.6 262.9 252.9 244.2 237.2 231.3 226.7 224.9 223.5 224.4 224.8 226.7 229.6 232.7 237.1 242.2 249.6 260 265.7 269.6 271.4 274.3 275.5 275.7 273.4 269.8 267.3 264.1 258.1 254.9 252.4 251.4 249.9 248.8 248.7 248.5 252.3 254.5 256.1 259.2 265.9 272.7 +14.4 -2.6 -2.6 10 17.5 18.3 15.9 14.8 16.6 18.2 19.8 19.1 18.5 18.1 17.9 15.9 12.6 9.8 8.5 9.7 11.9 13.6 15.1 15.4 16.5 17.2 19 19.9 22.1 26.1 33.8 39.5 45.1 54.7 75.3 100.5 122.9 140.4 148.5 149.9 155.7 159.8 158.4 156.3 152.1 144.5 139.1 135.9 133.6 131.6 129.6 127.3 125.4 124.8 125.4 125.2 125.9 132.2 139.1 143.4 145.6 147.9 150.1 152.7 155.6 158.4 163.2 164.5 163.4 159.6 155.1 153.3 154 155.6 156.9 156.3 157.7 161.1 164.5 168.8 171.2 174.4 178.1 191.3 212.5 239.5 256.1 264.2 274.1 277.5 281.6 287.4 294.8 297.9 305.7 313.7 325 345.9 371.4 398.2 427.9 439.6 436.6 433 426.2 420.8 416.3 413.6 422.8 435.4 438.7 446.9 450 448.3 444 441.8 438.1 428.6 419.6 405.2 398 391 388.3 386.6 387.6 386.2 382.7 380 373.8 369.5 363.6 357.9 355.5 349.9 346.2 343.1 339.9 337.6 334.6 334.3 336.2 338.7 342.5 346.2 350.9 354.4 356.9 358.3 357.2 352.9 351.5 346.4 335.8 324.8 316.5 309.7 304.7 292.7 280.6 270.7 260.7 252.5 244.5 237.1 231.5 227.6 225.7 222.7 223.8 224.8 227.4 230.4 233.3 238.7 246.6 253.3 257.6 261.8 265.3 267.7 269 269 266 261.8 259.7 257.8 253.7 249.5 248.3 246.3 245.3 245 243.7 244.8 247.1 248.1 252.6 259.6 266.7 271.1 +5.8 -2.6 -2.6 18.7 22.2 22.2 19.6 18 19.4 20.4 21.3 21.5 20.8 20.4 20.7 18.9 14 11.5 11 12 12.8 14.2 16.7 17.4 17.6 19 20.7 21.7 23.1 26.3 31.5 37.1 42.3 49.1 66.5 97.8 128.1 146.1 149 157 162.2 163.2 161.6 159.7 152.7 142.9 136.9 134.2 131.5 129.6 128.3 126.5 124.4 124 123.1 122.6 126.5 134.2 138.4 142.3 145 147 148.6 150.1 151.9 156.1 159.5 160.3 156.5 154 150.3 150.4 151.4 152.7 153.5 154.7 157.8 160.7 163.7 167.7 170.1 176.7 189.2 206 227.2 246.4 261.3 272.1 279.8 282.4 284.5 293.6 296.4 301.1 312 322.5 333.2 346.9 375.7 405.4 422.4 434.2 433.5 428.5 426.6 425.7 425.4 424.3 433.9 450.6 452.7 461.5 464.4 461.2 456.6 452.6 448.5 443 434.5 417.7 407.5 402.9 400 391.6 391.8 387.7 385.9 382.6 377 372.4 368 361.5 358.4 351.8 350 345.9 342.7 340.6 337.5 339.1 340.5 343.6 350.4 356.5 359.8 367.6 371.1 369.3 370.4 369.8 365.4 357.6 348.3 338 333.1 329 322.1 308.2 294.1 283.5 270 260.4 251.9 243.8 236.8 231.8 229.2 227.2 223 223.8 226 228.7 230.7 234.3 239.9 244.9 248.7 254.8 259.5 262.1 262.6 262.3 260.3 254.1 251.6 251.5 248.5 245.3 243.4 242.3 241.3 239 238.7 240.6 241.6 244.1 251.4 260.9 267 270.4 +-2.6 -2.6 15.5 21.1 22.5 22.6 21.3 19.8 20.2 20.6 21.5 21.9 20.9 19.9 20 18 15.4 14.1 12.4 13 14.9 17 19.3 19.7 19.3 20 21.2 22.7 25.2 28.7 32.6 37.8 42 48.6 65.9 97.3 118.1 134.2 153.6 164 165 167.3 166.3 162.5 151.3 139.6 135.2 132.3 129.4 128.5 127.5 125.7 123.5 122.7 120.4 120.8 128 132.9 136.9 141.3 143.8 145.5 147 148.5 150 152.6 153.6 152.9 151.9 148.6 147.5 147.8 148.9 150.1 151 155.2 159.7 162.6 165.6 171 176.8 185.7 200.4 220.1 236.8 256.1 269.5 279.3 282.7 287.8 290.6 295.2 300.2 304.6 313 324.3 339.2 355.8 373.5 400.9 421.3 428.5 424.6 421.9 428.8 433.8 434.2 433.6 444.2 450.2 461.3 471.7 472.1 469.5 469.3 464.4 457 451.1 442.4 427 419.2 412.7 409.4 401.5 393.7 392.4 391.4 384.9 379.7 376.9 373.5 367 361.4 355.7 354.3 349.2 345.8 343.7 341.1 343.3 345 350.6 359 365 370.3 378.4 380.5 383.4 386.2 382 374.7 366.7 358.2 351.3 347.6 340.2 332.5 321.7 308.9 294.2 278.8 266.9 258.3 250.2 242.6 236.6 232.4 227.5 225 222.1 223.7 225.6 227.5 229.5 233.9 239.5 244.6 248.9 253.5 256.3 257.3 256.6 254.5 250 243.6 244.6 242.7 239.8 238.3 237.2 235.7 233.1 233.7 236.2 237.5 242.5 252.2 261.3 265.5 265.4 +-2.6 -2.6 20.4 21.8 21.7 21.1 21.1 21.6 20.1 20.1 20.4 20.3 19.4 16.7 15.3 14.3 14.5 14.5 13.9 14.7 16.9 18.6 20.1 20.8 20.6 20.7 21.8 22.9 25.2 29.6 33.8 37.7 42.1 49.5 65.4 85.5 103.9 128.1 155.3 166.5 170 168.1 169 159.1 146.4 136.8 133.3 130 127.3 126.8 125.9 124 122.1 121.9 117.5 121.1 126.5 131 134.9 139.4 141.2 143.2 145.2 147 148.2 149.4 150.2 149.8 148.4 145.5 146 146.8 147.9 149.3 151.6 155 161.1 163.9 168.3 174 181.9 194.9 212.8 230.9 248.4 262.5 273.7 280.8 287.5 293.3 295.5 298.2 302.7 305.8 312.6 326.9 342.3 361.2 372.9 381.8 395 402 404.4 417.2 427.1 438.5 439.8 439.4 440.1 448.1 464.2 475.8 478.4 482.1 478 470.6 463.4 454.8 447 434.1 425.5 419.5 417.4 411.6 402.7 398.3 393.6 385.2 384.4 381.3 375.8 370.4 363.6 359.1 356.2 352.2 348.8 345.8 344.5 346.7 350.1 357.9 365 373.4 379.6 386.7 393.7 396.3 394.4 390.2 384 375.2 367 361.2 355.6 347.4 337 323 309.1 295.6 282.6 271.7 262.9 255 247.4 241 235.8 230 225.8 222.6 221.6 222.9 224.4 226.5 230.4 235.2 239.1 244.5 248.8 251 251.7 250.7 248.6 244.9 238.9 238.4 236.6 233.7 232.2 230.9 229.4 228.7 230 232.2 235.2 241.2 247.2 252.2 256.2 259.8 +-2.6 15.5 18.2 17.6 17.3 17.3 19 20.1 19.3 17.9 18.8 17.8 15.7 13 13.1 10.6 11 12.3 11.7 15.1 17.1 19.2 20.5 21.2 21.6 21.8 22.4 24.1 26.7 31.4 34.2 37.7 41.6 48 63.8 79.2 101.6 126.4 143.6 157.3 163.1 167.1 164.2 152.3 141.6 135 131.2 126.9 124.9 124.2 122.6 120.8 119.9 117.9 116.1 120.4 125 129.5 133.1 137.3 138.6 141.2 143.6 145.3 146.5 147.8 148.2 147.1 145.4 145.5 147.2 147.4 148.6 150 153.1 156.2 162.1 165.7 170.6 175.3 190.2 206.1 224.9 243.1 258.1 266.6 275.2 283.4 293 296.2 299.9 302.8 305.9 308.6 312.8 327 343.4 363.4 375.8 377 376.2 379.1 395.1 412 428.2 441.7 442.7 443.4 444.3 456.6 468.2 478.3 479.4 487.8 481 474.4 466.7 455.7 447.2 437.1 429.7 425.8 420.8 417.3 411.8 401.7 394.3 387.9 387.1 383.3 377.7 370 365.7 363.3 359.1 354.3 351.3 347.6 347 350.1 356.3 363 370.5 380.3 390.3 399.3 402 402.4 400.4 397.2 389.7 380.9 376.3 370 362 350.7 337.2 324.2 308.7 296.3 285.5 276.4 267.2 259.4 253.2 246.9 241.6 235.1 229.7 224.8 222.1 220.8 220.7 222.3 223.5 231.3 236.6 239.3 243 245.2 245.9 245.7 243 239.7 235.9 231.8 229.1 226.9 224.8 224.6 223.7 224.2 226.2 228.8 232.8 237.9 242.3 247.7 252.2 257.5 +5.5 15.1 13.2 11.6 11.9 12.4 14.3 16 16.1 13.8 13.9 10.7 9.3 8 8.5 8.7 9 9.9 10.3 11.3 15 18.3 19.6 20.5 21.8 22.9 24.1 25.9 29.4 31.5 34.7 37.9 41.6 48 65.9 90.2 108 120 131.5 144.4 158.8 163.4 154.9 145.9 136.5 131.8 127.1 125.7 123.3 122.1 119.3 116.8 115.6 114.6 115.2 120.2 124.5 128.3 132.5 136.2 137 139.3 141.7 143.2 144.4 146 145.9 144.2 142.4 147.9 149.2 149.4 150.2 152.9 156 159.3 164.5 170.4 175.5 185.8 199.8 214.6 228.4 243.9 258.1 271.1 281.1 288.2 297.4 302.6 306.3 307 308.3 311.2 314.9 327.8 338.9 362.6 364.7 362.5 365.2 371.2 384.6 403 425.9 443.3 445.8 448.5 449 456 465.6 468.8 473.3 480.8 478.8 472.7 466.2 458.1 447.4 439.4 433.2 430 424.8 418.6 413.2 405.7 397.9 393.3 389.6 385.4 378.6 372.3 368.7 365.5 361 356.3 351.2 350.1 351.5 354.5 359.6 367.9 376 389.3 399 403.1 406.8 409.9 408.4 403.5 396.4 389 383.3 374.2 363.7 351.6 338.2 325.5 311 299.9 290.6 281.1 272.8 265.1 257.8 252.3 247.4 241.6 235.6 231.2 226.1 223.6 221.6 219.8 222 228.3 233.3 235.2 236.1 239.3 240.5 239.6 237.3 234.8 231.8 226.2 222.9 220.7 219.5 219.2 218.9 219.3 222.9 225.1 229 234.2 237.8 241.7 248.2 253.9 +4.6 6.2 -2.6 -2.6 5.1 6.6 8.8 11.8 12.5 8.2 7 7.5 7 7.7 8.3 8.6 9.3 9.7 10.3 11.2 13 17.2 18.9 19.5 21 23 25.8 28.2 30.4 32.9 35.6 38.4 41.5 50.5 70 87.3 96.2 105.2 119.5 137 155 152.7 148.7 141.2 133.5 128.1 123.1 121 119.6 116 115.1 113.8 112.6 114.2 114.3 118.9 124 126.1 129.9 132.7 136 136.8 138.4 139.7 141.1 141.9 140.9 140.5 145.1 148.7 150.8 152.4 154.3 157.5 161.5 165.5 171.5 175.6 179.2 189.8 203.9 215.9 229.2 246.3 263.4 277.3 291 302.1 306.6 309.3 310.9 310.3 310.3 312.7 317.4 324 332.1 345.6 349 356.5 361.2 365.6 372.5 389.2 410 427.5 444.7 450.2 447.4 456.3 460.9 465.3 469 475.5 475.6 472.6 466.6 457.4 447.6 440.3 435 429.8 422.5 418 413.7 408.8 401.8 395.6 391.1 386.4 380.5 374.3 370.9 367.1 361.7 357.7 354.4 353.8 355.3 360 367.1 374.7 383 394.9 402.9 409.1 411.4 415.2 413.6 410 404.6 396.2 388 376.6 367 353.4 339.7 325.9 313.8 302.6 295.4 288.2 280.1 270.5 263 257.5 253 247.6 242.7 237.2 231 226.7 223.9 220 219.5 224.9 230 232.5 232.5 233.4 233.1 233.1 231.4 229.7 225.8 222.7 218.6 216.6 216.2 215.5 214.5 216.4 219.1 221 225.9 230 234 240.8 245.8 251.1 +4.3 -2.6 -2.6 -2.6 4.6 5.5 5.4 6.4 7 5.7 6.3 6.4 6.7 7.2 7.9 8.2 8.8 9.7 10.6 11.4 11.9 13.3 16.4 18.8 21 22.5 26.4 28.5 30.3 32.7 35.9 38.8 43.2 51.5 67.3 75.1 81.9 94.1 114.1 131 137.7 143.1 142.7 135.5 128.3 122.8 117.5 115.4 113.9 112.6 111.9 111.5 109.6 110.8 114.5 118.8 121 123.7 127.4 129.3 132.8 135.2 135.2 136.6 136.7 135.3 136.8 140.9 146.2 151.4 154.5 156.6 158.9 163.5 168.1 172.4 175.7 180.4 186.1 194.5 207 219 235.6 253.3 271.6 291.2 303.5 309.9 313.7 314.8 314.5 313.4 313.1 314.8 317.3 320.9 325.5 330.3 339.3 349.5 358.8 363.3 368.2 371.1 389.5 411.8 432.8 440.6 442.1 449.8 456.1 458.6 463.5 474.5 479.8 473.1 464.8 456.8 447.8 440.8 434.4 428.1 421.7 417.3 413.2 409.9 402.4 397 391.8 386.9 381.7 376 372.6 368 363.7 359.9 359.3 358.9 361.4 366.8 372.7 379.5 389 399.4 409.2 414.9 417.3 419.4 418.4 416.1 410.5 401.7 392 382.2 370.4 356.9 342.7 331.4 321.6 310.3 300 293.9 286.4 278 269.6 263.2 258.2 253.8 248 242.6 237 232.1 227.5 222.4 218.3 221.9 226.6 229.3 229.8 229.7 227.9 225.3 224.3 223.2 221.3 219.2 214.7 213.2 212.4 211.8 211.8 213.8 215.9 218.2 221.7 227.2 231.7 235.9 242.5 250.3 +-2.6 -2.6 -2.6 4.3 4.1 4.3 4.6 4.8 5 5.5 5.9 6 6.6 7.2 7.6 8.3 8.9 10 11.4 11.8 12.2 13.4 18.4 19.4 21.8 23 24.9 27.6 31.4 33.8 35.1 38.6 43.9 51.9 60.4 66.7 74.9 90.9 114.4 123.1 129.8 138.1 135.1 129 123.4 118.3 112.9 110 107.8 107.3 107.9 108.5 107.4 111.2 115.3 118.6 120.2 122.2 123.7 125.7 128.1 130.8 131.4 131.1 130.3 135.7 139.7 144.3 147.4 153.3 156.7 159.5 163.9 167.6 171.3 175.1 179 184.8 192.2 200.2 208.9 222.8 238.2 258.9 284.5 302 315.7 321.7 326.2 320.6 317.1 315 313.8 314.1 315.3 316.8 318.7 322.1 330.5 344.9 355 360.4 363.5 366.8 374.6 401.7 416.7 428.8 428.9 432.5 444.1 452.8 466.9 480.6 476.4 468.3 463.8 457.2 448.7 440.6 434 426.9 420.7 416.2 412 408.5 403 397 391.3 386.5 381.8 377.8 374.2 369.6 365.3 364.2 363.9 364 367.5 371.8 377.9 386.2 396.6 405.7 415.6 422.3 424.2 425.3 425.7 422.1 416.2 408.3 398.8 386.4 375 363.4 353.1 342.5 331.2 318.1 307.4 299 291.7 284 275.4 268.4 262.7 258.3 253.2 248.4 242.9 237.5 231 225.1 218.9 217.3 221.1 224.6 225.3 223.1 220.5 217.6 215.3 216.9 216.7 215.7 211 210.1 209.4 209.5 209.3 211.3 213.7 216.1 218.4 223 229.1 235 239.9 248.2 +-2.6 -2.6 5.7 5.8 6.7 6.6 5.1 5.3 4.9 5.2 5.9 6.4 6.9 7.6 8.5 8.7 10.3 10.3 12.1 12.6 12.8 13.8 17.1 20.4 21.7 23.1 25 27.8 30.6 31.4 33.5 39.8 47.2 52.8 58.1 64.4 72.7 84.9 101.3 111.2 125 130.1 126.5 123.4 119.3 114.9 109 105.8 103.8 103.2 103.6 103.3 109.8 113.6 115.5 117.8 119.3 120.8 122 122.9 124 125.6 127.5 128.8 134.1 140.6 143.5 146 150.2 154 158.5 162.1 166 169.8 173.6 177.4 182.3 188.9 195.5 203.3 212.5 226.6 242.3 265.2 293.8 318.3 326.4 327.9 326 319.8 314.5 312.8 312.1 311.3 311.4 311.7 313.5 317.4 324.1 339.8 348.1 356.3 360.7 365.1 369.4 384.4 398.9 404.2 410.7 430 442.7 446.8 453.6 461.9 464.7 465.4 462.8 456.2 449.3 441.1 433.6 426.5 420.4 415.4 411.3 407.8 402.3 397.3 391.3 386.5 382.2 379.2 376.1 371.2 369.3 368.2 367.9 368.8 371.8 376.3 383.2 391.9 402.9 413.9 422 428 431.8 433 432.7 429.4 423.1 414.5 404.8 393.9 384 374.3 364.1 352.8 340.3 325.1 313.4 304.2 297.4 289.5 281.4 274 267.4 262.7 257.6 253.2 248 242.8 235.7 227.9 220 215.5 215.9 219.3 219.7 216.7 215 214 211.1 210.2 212.2 211 208.7 207.8 206.5 206.4 207 208.5 211 212.8 216.3 221 227.5 238.3 242.5 247.4 +5.2 5.9 8.3 10 11.1 11 10.3 10.2 5.7 6.4 6.9 7.5 8.9 10.3 10.6 10.3 12.4 11.9 13.8 14.1 13.8 14.2 15.1 18.6 21.9 23.1 25.3 27 29.4 31.1 33.3 41.5 48.5 52.8 57.2 64.2 71.3 81.3 90.8 102.8 115.4 118.6 118.6 118.9 116.6 111.9 105.7 102.2 100.7 100.6 101 102.3 107.7 111.2 113.8 116.2 116.8 118 120 121.3 123.1 126.3 130.1 133.9 138.6 142.5 146 150 152.9 156 159.6 163.8 167.5 171.3 175.1 179 185.7 191.6 198.3 206.5 216.6 228.5 245.6 270.6 301.1 322.7 321.8 320.5 315.6 310.5 307.7 308 307.9 307.1 306.2 306.4 309.2 313.7 319.5 330.7 342.7 354 359.2 365.6 370.7 375.5 382.8 389.9 398.8 418.1 435 443 446.8 453.2 460.7 463.6 462.3 456.7 449.8 440.6 434 426.9 420.6 415.5 411.9 406.8 401.6 396.5 391.3 386.9 382.8 379.8 376.8 373.3 371.8 371.3 371.5 372.5 376 380.9 388.7 397.2 409.4 417.9 426.9 434.2 438.7 440.1 439 436.3 429.6 422.1 413.1 405.8 397.3 387.7 375.5 362.4 348.4 333.2 320.8 310.7 301.8 294.1 286 279 272.1 266.4 261.3 256.7 251.9 245.8 238.8 230.5 222.9 216.2 212 213.4 213.6 211.4 209.8 211.5 211 207.4 206.4 206 205.9 204.4 202.9 203.3 204.5 206.2 207.9 211.2 215.7 220.6 227.9 236.8 243.9 249.5 +6.2 7 8.7 12.3 14.1 14.9 13.9 14 12.8 13.2 12.2 11.3 10.4 12.9 14.1 15.5 16.8 16.9 17.4 16.8 16.4 15.3 15.6 17.5 21.6 23.2 24.6 26.3 29.2 29.7 35.3 44.3 48.7 53.4 57.8 63.7 70.9 80.3 89.6 98.2 106.1 111.1 114 115.5 113.9 108.9 103.5 100.3 99.2 99 99.8 100.7 102.8 106.7 111.1 114.1 115.6 117.5 118.8 123.9 125.9 131.6 134.1 137.2 140.6 144.6 148.1 150.9 153.5 156.7 161.4 165.3 169.2 172.9 176.8 182.6 188.2 195 201 209.5 219.5 232.4 249 269.4 283.9 299.5 304.9 303.6 303 300.9 301.6 302.2 302.2 300 299.8 301.7 305.1 309.9 315.3 323.1 337.4 351 352.9 360.8 366.6 374.3 379.5 381.7 388.8 410 432.4 442.2 444.4 453.5 462.4 463.5 460.4 454.7 447.9 441.2 434.3 427.7 421.4 416.3 412.1 407.9 403 398.1 392.6 388 383.4 380.2 377.4 375.2 374.1 373.6 374.2 376 380.3 386.1 396.4 402.9 411.6 423.2 432.6 439.5 445.2 447.2 445.3 441.1 436 430 422.9 416.6 408.5 399.1 387.2 371.4 355.1 340.6 328.5 317.1 307.8 299.7 291 283.3 275.6 268.8 263.4 259.2 254.2 247.5 240.8 233.3 225.5 216.8 212.8 211.6 209 209.1 210.7 209.2 203.3 200.4 198.6 199.7 200.3 199.8 200.6 200.4 202.4 204.5 208 212 217.2 222.1 229.8 240.6 247.9 254.3 +7 9 9.7 11.7 14.8 17.6 17 16.5 15.7 15.3 15.5 15.2 13.6 16.5 18.1 19.7 19.8 20.5 20.5 19.9 19.4 16.9 16.2 16.8 18.8 20.7 23 24.5 26.1 28.7 39 45.1 49.1 53.4 57.7 63.4 70.9 80.8 87.9 94.8 101.7 107 111 112.9 111.5 107 101.9 98.7 98.6 98.5 99.4 100.6 101.8 104.3 108.4 111.4 115.7 116.4 120.8 126.5 129.6 132.7 135.9 139.1 142.4 145.5 148.6 151.2 154.6 159.6 162.9 166.5 170 173.7 178.2 184.1 190.6 197.2 204.3 213.4 224.2 235.8 250.7 264 276.2 286.7 291.8 293.2 295.7 296 296.2 296.3 295.2 293.3 294.7 298.4 302.3 306.3 311.1 316.9 326.1 335.5 341.8 351.1 358.7 369.6 373 376.3 383.1 404.5 430.2 431.7 434.2 446 456.2 457.5 453.9 450.1 446.2 440.7 433.7 427.3 423 418.7 415.2 411.2 406 399.1 393.1 388.6 384.8 381.6 378.9 377.3 376.2 375.9 377.2 379.8 383.9 389.5 398.6 405.2 414.2 426.6 435.9 443.8 449.7 452.9 450.4 447.4 443.3 436.6 432 426.1 418.6 408.7 396.3 380.6 363.3 348 336.4 324.7 314.2 304.8 295 286.3 278.4 271.2 264.5 260.7 256.4 251.3 243.9 235.9 227.5 220.3 214.8 211.1 212.1 215.2 214 211.9 207.4 203.6 199 196.6 196.2 197 199.1 198.4 201.6 204.4 207.6 213.2 218.4 226.5 236.1 244.3 253.1 259.5 +8.5 10.2 10.8 12 14.9 17.6 17.8 18.5 17.9 17 18.4 14.7 17.3 18.8 20.8 21.5 22.2 22.1 22.6 22.6 21.6 17.7 17 17.4 19.8 23.2 24.4 25.5 27.5 31.6 39.5 45.7 49.8 53 58.6 66.8 73.7 79.6 85.4 92.3 97.8 104.5 109.2 110.7 109.3 105 99.9 98.6 98.1 98.2 99.3 100.4 101.5 102.6 105.9 110 112.1 114.4 121.9 127.3 131.2 135.4 138.6 141.6 143.6 146.6 149.6 152.2 156.6 160.9 163.8 166.7 170 174.2 179.3 185.1 191.2 197.9 205 214.4 226.5 236.5 247.1 257.7 269.8 278 283.3 288.6 289.9 289.8 289.9 290 289.7 290.9 292.7 295.9 299.8 303.1 306.5 311.5 317.9 325.6 332.7 340.8 353 361.5 365 371.4 381 395.3 412.5 421.4 425.5 432.2 441.6 443.5 446.5 447.9 446.5 440.5 432.9 427.1 423.3 419.3 417.2 414 407.3 400 394.2 389.8 386.1 382.9 380.2 378.8 377.9 378.2 379.6 382.3 385.5 391 398.1 407.7 417.3 429.1 438.6 446.9 452.3 455.1 454.8 454 450.3 446 441.2 435.5 427.8 416.9 403.8 386.9 370.2 355.2 343.3 329.9 319 309.1 299.7 289.2 281.5 274 267.9 262.8 258.1 252.8 245.4 238.5 229.8 222.8 217.9 213.6 214 215.6 213.6 210.3 207.9 205.5 202.9 200.6 196.9 192.6 195.9 199.2 200.8 202.9 208.2 214.3 220.8 229.4 239.7 247.1 259.5 270.8 +10.4 12.1 12.5 12.8 13.7 17.9 19.4 20.4 20.6 19.1 19.3 16.5 19.8 21.2 22.7 22.7 23 24 24.4 24.2 23.5 17.3 17.6 18 20.8 25.2 26.1 27.3 28.8 32.7 40.5 44.9 49.1 54 62.7 69.9 74.3 78.6 82.3 88.6 95.1 100 105.6 107.1 106.1 103.5 100.3 98 97.7 98 99.2 100.5 101.9 102.7 105.1 107.4 109.8 117.5 123.4 128.1 133.3 137.3 140.2 142.9 144.1 146.7 150.2 153.4 156.8 160.3 163.3 166.3 170 174.3 178.7 185.3 191.6 198.3 205.8 216.2 227.3 238 247.7 257.5 265.4 275 280.9 282 281.7 282.9 284.9 286.2 287.6 289.1 291.3 294.2 297.9 300.3 302.4 305.6 310 317.9 326 333.9 344.4 352.1 359.3 366.8 378 391.6 402.7 412 416.5 427.9 438.1 440.1 443.1 451.4 448.8 440.4 434.4 428.1 423.4 419.6 416.6 414.2 408.7 401.2 396.1 391.2 387.4 384.3 381.4 379.6 379.2 379.7 380.8 382.7 385.8 390.5 397.9 409.8 419.5 430.8 440 447.2 452.6 456.5 458.4 458.6 458 454.8 449.6 444.1 436.4 424.3 410 391.6 375.2 360.8 348.5 336.2 324.1 312.9 303.5 294 286.1 279.2 270.7 264.6 259.9 254.8 248.5 240.9 232.3 226.1 222.1 216.2 212.5 211.2 211.5 209.5 207.9 205.6 204 201.1 195.9 191.9 194.3 197.6 199.7 202.2 207.5 216.6 223.3 232.7 245.9 257.6 262.2 267.2 +12.6 13.7 13.6 14 16.3 19.2 20.9 21.7 21.6 20.4 19.9 17.7 20.8 23.2 24.3 24.1 24.4 25.3 25.9 25.4 22.6 17.7 18 19.1 20.4 24.1 25.8 27.6 29.8 34 40.5 44.5 50.2 58 66.5 70.9 73 76.6 81.6 87.3 92 96.6 101.6 104 104.5 102.4 99.7 97.5 97.1 98.2 99.5 101.1 102.7 104.1 105.4 108.4 114.5 119.9 125.8 130.5 134.3 137.8 140.1 141.3 142.9 145.1 149.1 151.9 155.1 159.1 162.5 166.4 170.1 174.3 178.9 186 192.3 199.8 206.6 214.2 223.1 234.3 245.1 253.8 261.1 267.2 272 273 273.8 277 279.6 284.5 286.8 289.4 291.6 293.9 296.3 298.7 300.9 304.9 309.1 315.5 322.6 331.3 339.5 348.4 355.6 365.1 381.2 392.8 399.1 406.6 412.1 423.4 431.1 433.9 439.2 451.5 445.9 439.3 434 428.4 424.4 420.5 416.9 414.1 410.5 404.2 397.7 392.1 387.9 385.3 382.5 379.5 379.2 379 379.5 380.8 383.7 388.1 395.7 407.4 419.3 429.2 437.5 445.7 452.6 459.1 463.8 465.2 465 462.7 457.5 451.9 443.7 431.6 415.3 398.2 380.5 366.1 352.9 340.6 329.1 318 306.1 296.5 289.6 281.6 274 267.6 263.1 257.1 250.6 242.3 235 229.9 225.3 219.1 213.1 209.9 209.6 209.2 208.2 206.2 202.8 199.9 196.2 190 189.5 194 196.9 200.2 207.3 214.5 223.1 235.5 250.4 266.4 265.2 271.2 +12.6 14.1 15.2 15.4 17.1 19.5 21.5 22.3 22.3 22.2 21.3 19.9 20.2 22.3 24.8 25.6 25.5 26.5 26.9 26.2 21.9 18.3 18.9 20.1 20.9 23.1 24.6 27.6 30.7 35.7 40.3 44.8 51.4 59.3 65.6 68.9 71.2 74.6 79.9 85.1 90.5 95.1 98.5 101.6 102.2 100.9 98.8 96.7 96.9 98.6 100.6 102.5 104.3 105.9 107.8 113 119.2 124.2 127 131.1 134 135.9 135.5 139.8 142 144.8 147.4 150 153 157.1 160.3 163.8 169.5 174.4 180.1 186.7 192.6 198.8 205.2 211.7 221.4 231.5 239.5 248.7 256.5 258.3 259.3 266.1 274.7 280.1 282.6 285.3 289.9 292.6 293.5 295.4 298.7 301.2 303.4 307.6 311.9 317.5 326.4 333.6 344.5 355.9 362.4 369.1 378.5 385.6 397 408.5 417.3 417.3 421 427.7 433.6 439.5 439.8 436 432.3 428 425.2 422.4 418.7 415.5 412.2 405.7 398.1 392.1 387.8 384 381.7 378.2 376.5 376 376.5 377.7 381.2 386 393.5 404.2 413.7 424.3 434.3 443.5 453.2 461.6 467.3 470.3 471.4 470.1 465.3 459.6 452 438.8 423.2 404.3 387 372.2 357.5 343.4 332.5 321 309.4 300.3 292.5 284.6 277.9 270.7 265.6 259.8 253.3 245.6 238.1 232.5 227.6 222.3 217.1 211.6 208.9 209.2 209.3 207 202.1 195.3 193.7 188.9 185.1 191.4 194.7 197.7 203.9 211 221.9 236.9 247.8 263.2 265.3 266.1 +11.1 12 14.1 15.4 17.5 19 20.9 22 22.9 23.5 23.7 24.4 24.3 24 24.6 26 26.3 27 27.3 27.2 22.2 19.2 19.7 20.3 21.2 21.9 24 26.9 29.9 34.3 38.6 45.1 50.6 57.6 62.3 66 70.1 74.2 79 84.3 89 93.6 97.9 100.1 99.3 98.4 97.1 95.9 98 99.6 101.5 103.4 106 108.4 111.5 116.1 120.8 124 123.5 126.2 130.2 133.5 137.7 141 144.1 146.9 149.3 151.9 155.7 158.6 160.9 163.7 168 172.6 177.5 183.9 188.8 194.6 202.3 209.5 215.8 223.1 231.8 240.4 250 257.3 262.1 267.9 271.7 276.9 282.6 287.4 293.3 295.3 296.2 298 301.6 304.9 308 315 317.3 322.6 330.2 337.7 349.7 362.1 368.6 373 381.3 387.6 396.9 403.3 409 412.2 414.8 419.5 429.3 437.8 435.7 433.6 430.5 427.3 424.6 422.9 421.5 417.3 412.2 406.1 398.5 392.1 387.2 382.7 379 375.5 373.4 373 373.1 373.9 376.7 381.4 389.2 398 408.5 420.3 431.5 442.3 452.9 462.6 469.7 472.9 475.6 475.3 471.6 468 460.2 447.2 432.4 413.1 394.3 378.5 364.9 350.6 336.2 323.6 313.4 305.1 297.4 289.6 282.5 275.6 269.3 263.2 256.2 248.8 241.4 235.2 229.2 224.1 219.7 214.8 210 207.2 207.9 207 202.8 194.9 189.9 186.3 181.9 189.4 191 194.1 199.1 208 218.9 223.5 235.8 251.2 254.7 250.6 +9.2 11.5 11.4 13.1 16.6 18.7 20.9 22.2 23.1 24.4 24.6 25.8 26.1 26.5 25 25.6 25.9 27.2 27.3 27.4 23.7 20.2 20.4 21.2 22.2 23 24.6 27.2 28.5 31.6 35.3 39.9 40.8 45.9 51.3 63 68.1 72.8 78.4 84.4 89.3 93.3 98.4 97.3 95.5 94.8 94.5 96.4 98.3 100.4 102.6 104.3 106 110 113.4 116 118.3 120 125.4 129.9 132.4 135.3 138.7 143 147 150.1 153.2 156.6 160.3 163.4 166.8 170.7 174.7 180.3 187.2 182.5 193.5 201.5 208.9 216.2 223.3 230.8 237.5 245 251.1 257.8 265.7 271.4 277.3 283.1 288.2 290.6 295.7 297.3 298.2 301.1 305.5 306.7 312 318.7 323.3 329.9 334 340.2 349.6 362.1 370 373.7 383.9 390.7 394.6 401.2 407.7 415.9 422.7 428 436.5 437.3 434.9 432.4 430.4 427.7 424.1 423 422 417.5 412.1 406.1 398.9 392.1 386.1 381.3 375.6 371.3 368.9 368.6 368.8 369.6 373 377.5 383.9 393.8 405.9 415.7 427.3 438.5 451.5 460.5 468.6 472.9 475.5 476.7 475.5 473.4 466.2 453.8 439.1 421.9 402.5 384.4 369 355 340.3 327.1 317.3 308.3 300.5 293.3 286.2 280 272.3 266 259.2 251.7 244.7 237.5 231.5 226.9 222.8 218.6 214.4 210 203.7 203 199.4 194.1 187 184.2 179.7 184.7 184.9 187.2 191.3 199.6 209.2 215.8 225.9 230.5 237.3 246.5 +13.3 13.9 15.6 14.6 16.6 19.3 19.7 21.5 23.3 24.8 25.7 26.1 26.7 27.4 27.1 27.2 27.4 27.6 28 27.9 27.1 25.4 21 22.3 23.4 23.9 25.2 28.2 28.6 30.5 33 37.9 45.7 52.5 56.6 61.4 67.2 72.4 78.4 85.3 89.6 94.5 99.5 94 92.6 93.5 95 96.7 98.3 100.5 103.7 106.9 110.6 115.9 119.2 122.6 124.6 126.2 128.6 131.4 133.9 137.7 141.9 146.1 150.1 153.6 157.3 161 164.3 167.3 172.4 177.1 184.1 191.5 196.7 197.2 192.1 199.3 209.6 217.9 224.5 230.5 232.3 245 255 261.4 266.9 271.3 277.8 283.3 289.6 292.4 294.9 297.2 299.6 304.1 306.9 309.4 315 322.2 331.2 337.3 341.5 344.8 351.7 364.9 370.9 376.7 386.7 391.3 395.5 405.6 415.9 426.3 432.3 438.4 440.9 440.7 437.2 433.5 430.9 427.8 424.3 422.5 421 416.6 410.9 403 396.3 390.4 383.6 378 371.3 367.7 364.3 365.2 364.7 366.7 369.5 373.6 379.6 388.5 399.6 408.7 419.4 433.5 447.4 456.5 464.2 469.8 474.4 477.3 477.1 474.5 468.3 458 442.9 427.1 409.4 390.8 373.7 359.8 346 333.7 322.7 312.9 304.4 296.3 289.5 281.9 274.9 268.3 261.9 254.6 246.6 239.7 234.4 230.3 226.3 223 217.2 212.4 206.1 196.7 194.4 190 185 181.8 175.4 180 179.6 180.6 184.2 189 195.6 203.8 210.4 220.5 232.3 241.4 +15.6 16.8 17.8 17.6 17.2 19.8 21.7 23.1 23.6 25 26.4 27 28 28.8 29.8 30.1 29.7 28.9 29 29.4 29.5 28.2 24.6 22.9 23.6 24.8 25.9 27.4 29.4 32 37.5 43 51.2 55.5 54 60 64.8 69.7 76.2 82.8 89.1 92.8 94.3 91.3 92.1 94.1 95.4 96.9 100 104 108.6 111.3 114.3 118.1 122.1 125 127.4 128.6 130.3 132.3 136.2 141.2 146 149.9 153.6 157.2 160.3 164.4 168.1 171.9 177.6 184.8 191.7 197 202.4 205.9 206.6 203.6 204 210 215.1 223.3 235.1 250.6 256.6 262.2 266.9 270.4 274.3 279.1 284.2 290.8 294.2 296.8 301.8 308.7 310 315.3 320.5 331.8 339.9 344.5 347.6 351.2 355.6 365.1 370.5 376.4 387 398.4 408.7 422.7 427.5 436.3 446.9 445.1 447.7 443.7 438.3 433.5 431.2 428.5 424.4 421.8 419.6 414.6 406.8 398.4 391.4 385.5 379.2 371.7 366.3 363.4 359.4 360.5 360 363 366.2 370.9 376.6 383.8 393.9 403 413.6 427.3 440.9 451.2 458.7 465.5 472.2 475.2 475.5 473.1 466.3 457.8 444.1 430.1 412.6 395.3 379.2 364.7 352.6 340.6 330.4 319.9 310.7 300.8 293.2 285.5 278.4 270.3 263.1 256.2 250.2 244.2 238 233.8 229.4 224.4 218.6 213.3 206.9 197.2 190 185.4 182 179 175.6 174.5 175.2 176.8 179.3 182.2 186.1 193.9 200.7 210.2 216.6 220.3 +17.3 18.1 19 19.5 18.5 19.6 22.2 24 25.4 25.9 27 28.1 29.7 30.7 31.7 32.6 32.1 31.2 31.1 31.7 32 30.8 25.4 24.9 26.7 28.9 29 32.2 37.5 38.1 43.4 48.9 54.6 60.3 65.5 69 70.6 66.5 71.5 78.1 84.4 88.7 90.6 91.5 93.5 96.4 97.7 99.1 103.4 108.5 111.4 112.9 115.6 119.6 123.4 125.8 127.9 129.8 131.9 135.2 139.9 145.3 150 153.8 157 159.8 163.8 167.8 171.6 176.9 184 190.1 195.9 202.7 208.2 212.2 216.2 219.6 221.2 221.5 230.5 240 249 252.3 256.7 261.3 265.6 269.7 273.8 278 282.9 288.7 293.5 299.4 305.4 307.9 313 320 330 340.1 345.2 349.7 353.1 359.8 364 372 380.6 387.7 396 410.9 421.7 433.6 439.3 448.8 458.7 452.4 448.6 443.5 437.8 432.9 430.4 427.7 423.6 418.8 415.6 409.7 402.4 394.1 386.5 380.6 374.7 368 361.8 357.6 354.5 355 356.9 359.7 363.1 367.8 373.1 379.1 386.9 396.2 407.5 420.1 434.2 444.7 452.7 459.7 466.5 470.7 471.9 467.6 463.3 455.7 443.7 429.9 413.3 397.9 383.5 369.7 357.2 346.4 336.5 325.9 314.7 305.3 296.8 288.1 280.5 273.4 266.8 260.7 254.3 247.7 242 237 232 225.8 219.4 212.2 205.7 199.5 192 185.8 181.2 177.8 174.3 170.2 170.2 172.9 175.3 176.8 181.7 189.5 196.5 205.6 208.4 212.5 +18.6 19.2 19.8 21 20.3 19.9 22.6 24.2 25.9 27.2 28.2 29.6 31.1 32.4 33.4 34.8 35.1 34.2 33.5 34.4 35.3 33.6 27.1 28.5 32.1 35.1 36.1 37.9 44 45.1 48.4 53.1 58.1 63.7 68.2 71.6 74.7 77.8 74.2 77.8 82.8 87.4 90.7 92.4 94.4 97 98.6 100.8 104.6 108.5 111.4 114.1 117.2 120.3 123.1 125 127.3 129.9 133.7 138.1 144.3 149.5 153.5 157.2 160.3 163.3 167.6 171.6 176.3 182.4 189.4 194.7 201.9 208 212.5 217.2 222.7 226.4 229.6 234 240.8 246.2 251.1 254.4 257.2 260.3 265.4 271.3 275.4 278.3 284.7 289.7 294.4 299.5 305.1 309.8 316.6 323.8 335.2 341.8 348.1 355.5 362.1 372.3 380.5 387.4 398 414.3 416.5 424.7 444.1 448.6 448.7 458.5 462 456.8 447.6 443.2 437.7 431.7 428 424.8 421.5 415 409.9 404.1 396 388.3 381.2 375.6 369.6 362.8 357.3 352.7 349.7 350 352.1 355.7 359.9 364.2 369 374.7 381.2 389.3 401 415.3 427.5 437.9 446.5 452.9 458.2 462.1 464.7 460.9 458.4 452 439.6 426.3 413.6 400.1 386.1 373.3 360.6 351.1 339.2 329 316.9 307 299 291.5 283.6 276.5 270.6 264.8 257.9 250 243.7 238.4 232.2 225.7 218.2 211.1 205.5 199.5 193.2 185.6 180.4 176.4 173.9 170.5 167.7 167.7 171.1 171.6 174 182.1 186.4 191.5 197 201.2 +18.8 19.2 20.3 21.7 22.6 22.3 23.4 25.8 26.8 28.1 29.4 30.8 32.3 33.8 35.3 36.8 37.6 37.1 36.6 36.7 37.3 33.8 29.6 34.8 39.8 41.8 45.7 46.9 50.5 53.1 56.6 58.7 63.6 67.9 70.6 73.3 77 80.7 82 85.4 89.3 91.2 93.5 95.6 96.2 97.7 100 102.9 105.2 107.9 110.5 113.9 117.5 120.2 123 127.3 128.5 131.4 135.8 141.3 147.6 152.3 156.4 160.6 163.7 166.7 171.6 175.8 180.9 187.4 193.6 199.2 206.9 211.9 216.5 221.5 226.1 229.9 233.7 239.1 245 245.7 249.4 253.2 256.2 259.9 264.4 271.6 278.4 281.7 287.8 291 294.8 302.6 307.2 312.6 319.2 327.6 334.7 342.5 352 361.3 377.4 389.4 397.7 408.3 410.6 427.7 433.5 441 452.9 462.5 458.8 461.5 464.8 457.5 449.3 442.5 436.2 430.1 425.1 421.4 418 410.8 403.5 397.5 390.6 384.1 375.2 369.5 364.3 358.5 352.6 348.6 345.4 345.7 347.8 351.3 355 359.2 364.1 370.3 377.2 385.3 395.9 409.2 421.1 431.7 439.7 445.5 448.8 450.6 453.2 453.7 452.7 444.2 433.7 423.8 411.4 397.4 385.8 373.4 363 351.8 340.2 329.1 315.5 306.9 300.8 294.7 287.3 279.7 272.3 265.5 257.8 251.2 244.6 238.6 230.9 223.1 215.6 209.8 204.5 199.6 194.1 186 181 176.7 173.6 169.8 165.6 161.4 167 167.2 166.3 169.2 173.4 176.9 186.9 201.6 +18.8 19.4 20.8 22 23.3 24.4 24.4 25.8 27.3 28.7 30.1 31.6 33.4 34.8 36.4 37.9 39.1 39.7 39.6 39.5 38.3 31.6 34.6 44.2 42.1 50.1 55.9 54 56.8 60.5 63.3 64.1 69.4 72.7 75.6 78.6 82.2 84.3 88.4 90.7 92.7 94.2 95.4 97.9 99.9 101.4 101.5 103.4 106.6 109.6 112.5 115.8 119.8 121.9 124.1 128.7 132.1 134.5 138.9 144.6 150.6 155.2 159.3 163.1 166.2 169.6 175.2 180.1 185.5 191.4 197.4 205.8 211 215 220 223.2 226.7 230.6 235.7 241.4 243.7 243.6 248 251.7 255.3 259.7 264.2 269.4 278.8 285.3 289.9 292.2 296 302.8 307.8 314.5 323.3 331.5 337.8 346 359.2 373.5 392.2 414.9 423.9 433.3 431.6 438.2 444.5 456.8 458.8 463.7 466 462 463.6 455.2 447.7 438.4 433.9 428.7 422.8 417.7 412.1 404.8 397.7 391.8 385.9 379.4 370.2 363.6 358.7 353.6 348 345.4 341.9 341.1 342.4 345.6 349 354.4 359.3 365.5 373.1 382 391.7 403.8 414.4 425.3 431.8 435.9 438.1 439 441.2 442.5 441.7 434.2 428.4 417.2 405.6 394.3 382.6 371.3 360.1 348 336.5 328.2 316.3 307.4 302.8 297.4 289.7 280.9 272.8 264.5 257.3 250.7 243.7 236.1 227.8 221.3 214.1 208.6 204.8 199.6 194.7 187 182.6 176.7 172.9 167.2 162.7 157.1 162.9 161.5 159.9 158 159.5 169 177.1 183.1 +18.2 19.9 21.3 22.3 23.4 25.1 26.3 27.5 28.5 30.2 30.7 32 33.4 35.1 37.2 38.5 39.7 41 41.2 41 37.4 34.6 37.6 41.9 49.6 48.5 46.6 61.5 65.9 68.1 70.8 71.1 73 78.2 81.5 84 87.4 90.3 90.9 92.7 95.6 97.1 98 98.9 102.8 104.9 104.5 105.7 107.5 110.2 112 119.8 121.6 123.7 125.8 130.1 134 138 143 148.2 152.9 157.4 161.5 165.2 168.3 172.9 178.5 184.2 189.4 195.4 203.6 209.5 213 218.3 221.9 224.7 227.4 231.9 236.7 240.5 241.2 241.8 246.6 251.2 255.3 260 264.8 269.3 274.8 280.4 285 287.5 295.5 303 309.9 317.5 328.4 335 342.7 352.6 368.3 386.2 409.4 436.6 451.9 456.8 456.5 453.4 454.4 469.4 473 472 471.3 468 459.4 452.6 444.6 435.6 430.5 425.6 419.6 413.1 406.8 400.1 393 386.2 380.4 372.6 363.5 356.9 353.3 348.9 344.3 341.7 336.4 336.2 337.4 339.9 343.2 348.3 353.3 361.2 370.1 379.7 389.9 399.4 409.3 416.8 422.4 426.3 427.2 427.7 427 427.1 427.5 423.1 417.6 407.6 397.4 386.2 375 364.1 353.9 342.3 334.6 325.3 317.5 311 304.6 298.1 290.1 280.7 272.2 264.4 257.1 248.9 240.3 232 224.6 219.3 213.9 209.3 205.2 200.6 195.2 188.3 182.8 177.5 172.2 166.7 161.6 154.3 158 157.7 155.6 153.9 154.8 162.2 168.7 176.6 +18.7 20.3 21.9 22.4 24 26 27 28.2 29.6 31 32.3 33 33.7 35.5 37.7 39.1 40.4 41.5 42.6 42.1 37.6 39.5 44.4 39.2 39.6 66.9 69.4 70 71.2 73.4 75.5 77 77.6 83.5 85.9 88.5 91.4 92.9 93.9 94.5 97.6 99.7 101.3 103.4 106.1 108.3 107.8 108.8 109.6 111.7 114.5 116.6 123.2 126.3 130.4 134.2 138.5 142.6 146.2 149.7 153.7 158.3 163.1 167.1 171.6 176.5 181.7 187.5 193.1 200.4 206.5 211.1 215.2 219.7 222.5 224.4 227.8 231.8 235.7 238.1 238.5 240.7 245.9 250.6 255.1 258.9 263.6 267.8 271.5 274.8 279.5 286.3 294.2 303.1 310.4 317.3 327 334.9 348.1 363.6 381.4 400.8 423.7 449.1 472 474.1 471.3 466.6 464.7 476.9 482.5 474.4 470.7 468.1 457.1 449.7 442.6 435.1 428.3 422.2 415.9 408.9 402.3 395.5 388.3 381.4 373.9 365.5 357.5 352.9 348.5 343.5 339.8 336.4 332.4 332.7 333.1 334.3 337.7 341.9 347.5 355.7 365.4 376.1 384.5 392.9 399 406.4 412.7 414.2 414 413.7 411.5 411.9 410.3 404.7 401.1 393 382.7 373.9 364.9 355.2 347.6 340.2 333.9 326.6 319.4 312.4 304.9 298 289.3 279.8 271.5 264 255.1 245.5 237 229.7 224.8 220 215.6 211.2 206.2 200.6 195.2 189.3 181.9 176.7 171.8 166.4 161.1 155.4 152.1 153.4 152.2 151.2 153.5 161.5 166.8 174.4 +19.6 21.2 22.3 22.9 25.1 26.4 27.1 28.8 30 31.2 32.7 33.9 34.8 36 37.8 39.5 41.1 42.5 43 41.8 39.9 42.8 49.9 56.9 56.6 67.9 72.3 74.5 75.8 78.4 81.5 82.1 82.8 86.1 87.9 90 93.5 96 97.3 99 100.4 103.1 104.7 107.6 110.3 111.8 111.9 114.8 112.7 114.3 117.9 122.2 125.1 130.2 134.5 138.7 141.9 145 148.3 151.5 154.7 159.8 165.6 170.3 175.8 180.1 184.8 190 197.9 204.1 207.9 212.4 215.9 219.2 221.5 222.3 226 228.9 231.9 234.8 236.6 239.6 245.2 249.1 253.1 257.1 261 264.2 267.5 272.8 279.1 286.4 293.4 299.7 308 315.3 326.2 341.2 356.1 372.6 390.6 411.1 430.6 457.6 483.2 490.9 483.2 476.6 471.5 472.8 474.5 471.4 466.2 461.9 456.4 448.7 441.1 433.8 427.3 421 413.1 406.6 399.8 392.4 384.7 376.4 367.7 359.6 353.7 348.2 343.7 339.4 336 333.2 329.4 328.7 328.9 330.5 332.2 335.5 340.2 347.9 356.1 366.6 374 378.7 386.2 391.4 398.3 395.9 392.6 391.4 389.1 388.7 386.2 381.1 377.8 372.6 366.2 360.1 354.8 348.7 342.7 337.9 330.4 324.5 317.2 311.1 304.2 295.4 285.7 277.5 269.7 261.1 251.7 243.7 236.6 230.9 225.9 221 216.2 211.8 207.1 201.5 194.2 188.8 180.9 176 171.2 164.5 159.4 154.6 150.4 146.9 146.4 145.1 156 161.1 164.5 166.1 +19.6 20.2 21.5 22.6 23.8 25.4 26.6 28.2 29.8 31.3 33 34.7 35.8 37 38.4 39.9 41.3 42.1 42.5 41.9 41.8 46.4 55.1 60.9 64.8 69.4 73 76.8 79.3 82.3 83.6 84.6 86 86.7 89.8 92.1 96.4 100 102.2 104.4 105.2 106.1 108.1 111.6 113.6 114.7 115.5 115.9 116.2 118.6 123.3 128.9 128.4 129.2 137.5 141.3 143.5 146 149.8 154 159.1 163.7 168.1 173.1 178.7 183.5 188.2 194.4 201.5 205.2 208 211.5 214.3 216.4 217.7 219 221.3 223.9 227.6 231.8 234.3 237.5 242 245.5 248.8 252.3 254.6 258.3 265.2 271.5 278.2 284.9 291.4 297.5 303.7 315.2 329.6 345.7 360.2 377.7 399 415.6 438.4 464.8 481.5 490.1 487.8 481.3 476.2 472.4 471.5 469.2 465.5 461.1 455.6 448.2 440.1 433 426.6 419.1 411.9 404.3 397.1 389.6 381.4 371.9 362 353.8 348.1 343.3 339.5 336 332.2 329.9 327.1 324.6 325.3 326.5 327.5 329.2 332.8 338.5 345.9 352.8 362.8 368.2 367.3 367.5 370.8 364.4 363.9 367.2 360.4 361.6 360.7 359.4 356.1 352.5 349.7 346.3 342.6 339.8 336.3 330.4 324.5 320.3 314.7 306.1 298.6 291.7 283.8 275.3 267.5 258.7 250.4 243.2 237.6 232.2 227 221.5 216.5 211.7 206.5 199.6 193.4 187.3 180.5 174.8 168.6 163.1 159.2 154.8 152 148.7 146.6 132.3 150.9 148.6 151.2 142.9 +18.8 16.3 17.3 19.6 21 23.1 25.8 27.6 29.1 30.6 32 33.4 35.4 36.9 39.1 39.5 40 41.3 42 43.3 43.5 48.8 56.6 61.2 66 69.5 75.3 80.5 83.3 84.6 85.7 87.1 88.7 89.8 91.3 94 99.3 103.3 105.2 107 108.5 109.3 111.6 114.1 116.5 116.7 117.8 118.8 119.3 124.4 129.4 132.9 135.7 134.8 133.3 140.4 142.8 147.5 153.5 158.6 164.9 168.1 171 175.3 180.6 187.3 192.9 198.6 203.4 204.8 206.9 209.2 211.4 213 214.2 215.5 217.9 220.8 224 227.5 229.4 232.9 236.5 240.1 243.4 246 249.2 258 263.9 269.7 277.3 284.5 290.3 297.8 308.6 321 334.3 349 363.9 381.3 400.2 425.8 445.3 467.7 477.3 487.1 488.7 482 477.8 474.1 471 468.5 468 461.7 456 447.7 440 433.2 425.4 417.8 410.4 402.2 394.5 386.8 378.7 367.7 357.7 348.8 341.5 339.2 334.9 331.9 328.5 325.9 324.2 321.2 322 322.4 323.1 324 325.9 330.5 335.8 338.3 344.4 350.3 347.8 341.9 339.2 337.2 340.8 340.3 335.9 335.4 338.4 338.9 338 338.7 334.7 332 330.3 327 325.3 322.8 320.1 314.3 308.1 302 296.1 289.5 282.1 274.5 266.6 257.5 250 244.3 239.1 233.3 228.5 222.9 217.2 212.1 206 199.2 193.2 188 181.6 174.5 169.4 164.7 160 156 152.8 149.6 144.2 135.5 134 131.4 129.3 125.4 +11.9 11.5 12.7 14.5 14.8 17.1 23.9 25.8 28 29.6 29.5 31.9 34.7 37 38.9 40.2 40.7 40.7 41 42.9 44.8 49 54.5 60.4 66.1 71.5 77.5 81.8 84 85.7 87.2 88.9 90.5 91.7 92.7 95.9 100.1 102.7 104.7 107 109.9 111.6 113.2 116.1 117.8 118.6 120.2 121.5 124.4 126.5 132.4 135.3 138 140.1 140.2 139.4 142 147.2 157.2 162.5 168.2 170.7 173.9 178.4 185 191.7 197.8 201.8 202.5 203.5 205.4 205.8 206.3 208.9 211 215 217.1 219.7 221.6 223.7 228.1 231.2 234 237.3 240.3 244.1 250.1 260.4 265.5 270.1 278.4 285.8 291.2 300.4 313.5 326.7 339.7 354.2 367.6 383.5 404 431.4 450.1 466 477 482.3 488.8 481 478.2 474.7 471.5 468.7 465.3 461.7 457.5 447.9 439.5 432.6 424.9 417 409.1 401.3 393.7 385.2 374.9 363.9 353.8 344.4 338 332.4 330.3 327.3 324.5 322.6 321.1 318.4 318.5 318.8 319.5 319.6 320.2 322.6 325.1 328.5 328.2 330.6 331.4 325.5 321.8 322.9 322.1 320.4 321.2 320.9 321.3 322.2 320.5 320.6 318.9 317.2 318 319 319.4 317.3 313.6 309.4 304.2 298.9 293.6 287.4 280.8 274.3 266.4 257.8 251.3 246.5 241.3 235.7 230.4 224.4 218.3 212.4 204.9 198.9 192.6 186 180.5 175.1 170.2 165.5 160.7 156.6 151.9 146.1 140 131.1 118.2 113.3 111 115 +10.3 12.6 14.1 14.5 16.1 16.1 18 23.8 27.5 29.9 31.2 32.8 34.7 36.3 37.8 39.7 40 39 40 42.9 45.8 51.7 57.8 64.5 68.3 73.2 77.8 81.2 83.5 85.3 87.4 89.5 91.4 93.6 94.9 96.9 99.6 102.9 106 109 111.2 113.2 114.5 117.3 119.3 120.9 122.5 124.7 128.7 131.7 133.4 136.9 139.6 141.6 144.5 145.6 149.8 151.7 150.2 156 167.2 171.8 176 182.9 190.1 196 199.4 198 200 199 205.4 208.7 210.4 212.1 214.3 216.9 219.2 222.5 224 226.4 232.4 234.6 237.8 239.5 246.9 251.7 256.1 264.4 270.5 274.8 281 287.1 293.6 306.5 319.5 330.7 344.2 359 376.3 391.1 407.3 431.4 449.2 464.4 473.3 479.3 481.6 479.3 477.3 475.5 472.4 469.2 465.6 461.4 455.5 447.6 438.6 431.7 424.4 416.9 408.9 400.7 392.1 382.9 371.2 360.5 350.5 341.1 334.8 330.1 326.2 323.9 321.9 320 318.6 316.9 315.7 316 315.9 315.1 314.2 315 316 318.4 319.2 320.9 317.5 311 306.6 308.2 309.5 307.7 307.5 308 307.2 307.3 305.8 304.3 305.7 307.7 309.1 311.7 311.2 310.4 308.2 305.4 302.2 297.9 292.3 286.1 280.3 274 267.8 260.6 255.3 249.8 244.2 238.1 233.1 227.3 220.8 214.2 205.9 199.8 193.2 187 181.5 176.3 171.4 167.4 162.4 158.4 153.2 148.3 143 139 135.9 126.3 110.2 107.8 +12.6 15.6 18.8 20.7 21.3 21.6 17.6 21.7 26.3 29.4 31.2 33 35.1 36.4 37.7 38.1 37.1 37.8 41.1 44.4 49 56.2 63.9 65.7 70.8 75.7 80.1 82.1 84.4 87.1 89 90.2 91.9 95.2 97.3 99.5 101.5 103.9 106.7 109.8 112.2 114.4 115.8 117.7 120.1 122.6 123.4 128.3 132.1 134.7 135.7 138.3 140.9 143.9 147.1 150.5 152.8 155.9 162.4 162.4 160 164.7 172.9 179.1 187.7 188.4 190.4 196.3 200.8 206.4 209.1 210.2 211.4 213.2 215.4 218.3 221 224.1 228 232.1 236.8 239.6 241.7 243.6 245.3 255.6 261.2 266.7 272.4 277.9 284.5 292 300.3 313.1 326 338.2 354.6 371.2 387.1 399.5 411.4 429.6 449 461.2 472.6 476.8 478.4 478.8 476.1 475.6 473.6 470.2 467 461.2 453.5 445.7 438.2 431.3 424.1 416.6 408 399.7 390.3 379.8 368.1 357.4 347.8 338.6 332.5 327.7 324 321.1 319.1 317.3 316.6 315.4 314.2 313.8 313.4 312 310.9 310.7 311.8 312.5 311.9 308.7 303.2 298.6 298.1 299.2 299 298 297.7 297.2 297 294.4 292.9 294.5 296.7 298.1 299.9 304.1 305.7 303.2 302 301.2 299.7 297.5 292.6 287.3 281.7 275.2 269.1 263.4 259.1 254.2 246.9 242.1 236.3 230 222.5 214.9 207 200.5 194.1 188.2 183.1 178.3 173.4 169.6 165 159.3 153.1 145.3 140.8 137.6 137.9 126.1 103.5 104.5 +16.6 17.7 20.5 23.2 24.6 24.9 23.4 17.4 21 26.1 29.3 31.9 33.9 35.4 35.4 35.4 37 39.8 43.9 48.5 53.5 59.9 66.5 68.9 72.9 77.1 81.1 83.2 85.1 87.8 89.6 91.6 93.4 97.1 99.2 101.3 103.1 106.1 108.9 111.6 113.3 115.4 117.2 118.8 120.8 123 126.9 131.1 133.5 135.4 137.4 140.7 143.5 147.1 150.7 154.1 157.5 161.1 163.3 167.8 172.7 174.3 174 180.5 185.2 192 196.6 201.4 205.4 208.2 209.5 210.6 212.2 214.1 216.8 220 223.2 225.8 229.6 233.3 237.1 240.3 243.6 247.3 251 253.8 262.3 269 274.8 281 287.4 295.9 306.5 319.1 333.4 347.5 360.4 376 391.8 402.4 416.8 432.8 446 458.1 468.2 474.9 476.9 476.4 475.2 477 476.3 471.4 467.7 460.9 452.8 444.4 437.5 431 424.3 415.3 407.6 398 387.8 377.4 366.6 358.2 349 337.3 329.8 325.6 323.3 319.3 316.4 315.5 315.4 314.7 313.5 312.2 312.3 311.6 310.2 309.3 308.9 307.4 303.8 300.2 296.4 293.5 294.6 294.7 293.2 291.5 289.8 289.7 288.9 286.8 286.3 286.3 287.8 290.3 293.4 295.7 296.4 297.8 297.7 298.3 299.5 298.2 295.3 290.1 284.2 277.8 271.9 266.3 261.8 257.6 252.7 247.3 240.5 232.2 224.4 216.4 208.7 202 196.3 189.8 183.8 179.9 176 172.6 166.9 161 153.1 145 137 132.9 126.5 121.2 104.8 97.8 +19.4 19.8 21.8 24.7 26 27 26.4 25.8 23.1 21 28.9 30.4 32.5 32.3 33.1 35.6 38 42.9 49.1 55.9 59.8 65.5 70.6 73 74.1 78.8 81.9 83.8 85.9 88.3 90.2 92.9 95.8 98.8 101.2 103 104.7 107.5 110 112.8 115.5 117.4 118.8 120.1 121.8 124.6 128.6 131 133.8 135.9 139.6 143.7 147 149.9 154.1 157.7 161.1 163.7 166.9 169.1 173 176.1 181 185.4 189.7 194.7 199.7 203.9 207.1 208.6 209.7 211.2 212.9 215 217.9 220.9 223.7 226.9 230.5 234.1 237.9 242.6 246.4 249.1 255.6 261.5 264 273.1 279.5 283.7 292.8 302.2 317.6 329.4 343.7 356.6 364.7 380.4 395.5 408 421.2 435.8 445.4 455.8 467.9 473.4 475.4 476.1 476.5 479.6 477 471.5 466.9 460.1 452.1 444 436.4 429.7 422.8 414.2 405.7 397 387.2 377.1 366 356.3 347.2 337.5 327.9 323.3 320 317.3 315.1 313.7 314 313.7 312.8 311.5 311.6 311.5 311 309.6 304.6 301.2 298 295.1 291.4 289 290.9 292.2 290.1 287.6 285.7 284.4 283.7 282.2 280.3 279 279.8 282.3 286.2 285.7 288.3 290.4 293.3 296.2 298.4 299 297.1 293.5 288.5 283 277.1 271.2 266 262.6 258.5 252.8 244.6 235.4 226.6 218.9 212 205.9 199.5 193 186.9 182.4 177.5 173.9 169.3 162.1 154.3 145.6 135.9 127.9 123 126.6 119.8 90.2 +22.2 23.4 23.6 25.4 27.2 28.8 29 28.7 27.9 23.3 25.6 29.1 28.8 30.6 33.2 36.7 43.4 48.5 55 59.8 66.2 68 71.8 75.2 76.7 78.9 81 83.6 85 87.9 91.6 93.5 98.9 101 102.5 104.1 106.6 109.6 113.7 115.2 117.2 119.1 120.4 121.7 123.1 127.6 130.2 132.1 134.9 138.9 143 147.1 151.2 153.4 156.1 160.1 162.6 165 168.1 171.2 174.4 178.2 182.2 187.1 191.5 197.3 201.5 205.1 207.1 208.3 210.3 212.3 214.2 216.2 217.6 220.7 225.5 228.3 232.4 236.2 241.7 247.5 252 254.3 263.4 271.2 274.4 277.5 283.6 291.9 303.4 314.8 327.3 339.7 349.2 360.6 367.8 382.4 400 415.4 428.7 438.2 449.2 460 467.6 472.3 477.6 478.6 479.4 482.6 476.9 471.9 465.5 459.4 452.8 445 437.8 429.8 422 412.8 405.2 397.1 387.9 375.5 363.8 354.8 347.2 337.6 327.7 321.4 319 316.4 313.9 312.5 312.3 312.2 311.5 310.4 311 311.3 311 307.3 303.1 297.6 294 291.7 290.5 289.9 285 287 286.4 284.4 281.3 278.8 277.5 276.1 273.8 272.4 272.8 274 274.7 278 279.8 284.4 290.6 295.1 298.9 300.9 300.1 297.9 294.1 288.3 282.6 277.4 272.1 268.3 263.6 256.4 248.7 239.7 230.9 222.8 216 209.3 202.9 196.1 189.6 185.2 179.6 176.4 172.7 164.5 156.3 147.3 133.7 125.3 125.5 130.3 123.7 103.5 +23.1 24.4 24.4 26.4 28.3 30 30.9 31.3 30.5 28.3 25.8 25.7 28.5 30.9 34.7 41.8 49.3 55.6 60 66.5 70.8 73.6 75.2 76.7 79.1 80.8 84.4 86.9 88.1 90 93.4 97.8 101.4 107.3 107.7 108 110.7 114.3 116.6 118.5 120.7 121.3 121.7 123.8 126.5 129.7 131.6 133.9 138.7 144.4 148.7 150.8 153.4 155.9 158.4 160.7 163.7 166.4 168.7 171.8 174.8 178.9 183.9 188.9 193.9 198.9 202.6 204.2 205.8 207.7 210.4 212.7 214.9 217.2 219.1 221.5 227.5 232.6 236.9 240.8 244.2 250.2 255.7 261.9 269.7 275.7 281.2 282.7 291.3 300.5 313 325.5 336.8 349.8 358.5 367.5 374.6 388.5 407.3 419.7 429.1 444.5 456.4 462.6 465.9 471.4 478.9 482.1 482.5 481.5 477.4 472.4 465.1 459.5 453.4 446.1 439.4 431.2 421.6 412.4 405.3 397.9 389.4 381.2 371.2 359.7 347.8 338.7 330.7 325.2 320.6 316.4 313.6 311.9 310.6 310.3 310.1 310.2 309.6 310.1 306.9 304.5 299.4 301.1 302.6 301.6 298.6 295.6 285.1 279.2 278.3 277.4 274.5 272.3 270.6 269 266.8 265.5 266 266.6 267.9 269.7 274.5 282.4 289.2 295.2 300.7 304 304.8 303.5 300.6 294.6 289.8 284.2 277.8 273.6 268.7 261.7 253.8 244.7 234.7 225.5 218.2 212.7 206.8 199.6 192.4 186.7 183.1 179.4 174.9 168.8 160.9 145.9 129.7 121.1 126.6 127.6 120.1 103.2 +22.8 23.6 23.7 26 28.1 30.4 32.2 33.3 33.6 32.1 29.7 26.4 28.9 31.4 38.6 47.6 56.1 60.6 65.9 71.2 74.9 76.7 77.2 78.6 80.7 82.9 85.4 88.3 90.7 92.8 96.6 99.7 104.9 109.5 110.2 111.1 114 115.7 118 120.3 122.4 122.7 123.7 125 127.7 129.8 132.1 135.2 140.8 144.6 148.3 152.1 154.4 156.8 159.1 161.8 164.2 166.7 169.4 172 174.6 179.8 184.8 189.9 196 199.6 201.8 203.4 205 207.3 210.2 212.9 215.4 217.8 220.5 224.1 230 234.9 239.1 243.7 247.4 253.1 259.6 268.1 273.6 279.7 283.6 289.8 294.4 308 322.1 335 346.7 360 367.1 373.1 380.3 391.4 404.1 420.4 436.4 448.2 457.8 463.1 466.9 473.3 478 483.7 484.6 481.9 477.9 472.3 465.8 459.4 453 447.2 440.3 432.5 423.6 415.7 408.1 401.2 393.6 385.6 375.6 365.3 355.6 346.1 337.6 329.6 322.8 317.1 313.5 312.2 311 310.1 308.9 308.5 307.8 307.6 310.3 310.3 309.7 311 310.7 309.2 306.6 301.9 295.9 288.2 281.1 271 265.6 263.8 263.4 260.7 260.5 259.1 260 260.7 261.1 264.1 271.1 279.2 287.2 296 303.5 309 311.2 310.2 306.7 302.4 297.2 291.4 285.6 278.8 273.2 267 258.3 248.6 237 226.8 221.5 216.3 209.1 201.1 194 190.2 185.4 181.2 176.3 172.8 165.2 150.9 127.9 110.2 110 119.9 117.5 101.6 +21.1 21.7 22.5 25.2 27.8 30.1 32.2 34.1 35.3 35.1 33.2 28.8 30.3 35.6 42.4 54.7 61.8 65.3 69.9 74.4 76.7 77.9 79.1 80.3 82.6 85.5 87.5 89.7 92.3 95 97.6 103.4 108 110.1 111 113.2 115.3 117.4 119.9 122.8 123.7 123.4 124.9 128 130.6 133.1 136.2 139 142.4 146.2 149.9 153 155.7 158.2 160.1 162.2 164.2 166.8 169.4 172 175 181.7 186.7 193.1 196.7 198.7 200.8 202.5 204.6 206.9 209.5 212.4 215.4 218.7 222 226.2 231.3 235.7 241.7 247.7 251.7 257.8 263.8 271.1 278.9 284.7 289.2 298 309.2 311.2 327.2 342.3 355.2 365.6 374.8 378.7 384.3 393.4 409.1 424.6 440.6 456 459.7 462 467.4 472.2 478.2 482.2 486.1 484.7 480.5 474.3 467.5 460.3 453.6 448.8 443.3 436.2 427.9 420.8 413.6 406.1 398.7 391.3 383.7 373.7 363.6 353.7 344.4 334.7 326.7 319.9 315.9 312.8 311.4 311.4 310.9 310.4 311.8 314.5 316.4 317.2 317.1 316.9 316.3 315.3 313.3 309.4 304 297.4 290.2 282.4 272.9 265 255.2 253.9 255.8 254.7 255.8 256.1 255.3 258.8 267.6 275.2 286 296.1 305.1 312.6 317.5 317.7 314.6 310 303.7 299 294 289.2 282.2 273.3 261.9 251.3 238.1 227.7 225 217.3 210 202.3 195.8 193.5 189.9 185.4 181.2 179.8 170.4 145.9 125 105.9 96.1 100.9 103.3 97 +17.9 19.7 22.1 24.8 27 29.6 32 34.1 35.7 36.2 34.7 30.8 33.7 38.8 46.3 56 62.1 67.8 73.5 76 77.8 79.5 80.9 83 84.3 88.2 90.3 91.1 93.5 95.9 100 105.9 109.4 110.6 112.7 114.9 117 120 123.7 125.5 126.2 123.8 126.7 131.4 134 137.2 139.3 142.1 144.7 147.7 151.6 154.6 156.3 158.2 160.2 162.5 165.2 167.5 170.9 174 180.4 185.6 190.5 194.2 196.3 197.8 199.5 201.8 204.2 206.3 208.7 212 215.2 219.2 223 227.5 231.8 237 245.5 250.6 255.7 262.4 271 279.2 286.4 294.1 299 308.3 319.3 329.4 338.5 343.8 356.7 369.2 379.1 384.3 387.7 395.4 410 429.6 448.9 455.9 458.4 462.5 467.1 472.8 479.1 485.7 490 486.3 482.4 477.2 471.2 463.7 457 451.7 445.4 438.3 432.5 426.6 419.4 412.3 405.7 398.4 391.3 382.3 373 362.8 352.5 342 333.5 326.6 320 315.6 313.5 314.1 314.6 315.8 317.5 320 321.8 322.1 321.6 321 320.4 319.4 316.9 313.3 309 303.4 296.3 289.3 280.1 271.1 259.7 248.9 249.2 249.6 249.9 248.5 248.9 254.8 262.4 272.1 283.4 295.2 303.1 313.3 323.3 324.5 322.2 317.9 314.2 309.1 304.7 297.9 290.8 282.9 267.8 250.7 236.8 227.4 225.9 217.4 213.4 201.4 193.7 191 189.4 181.2 173.3 162.9 155.7 140.4 118.4 102.1 91 81.8 79.8 76.8 +18.6 20.9 23.5 26.1 28.3 29.8 32.2 34.4 35.9 36.2 31.3 34.4 37.4 41.4 50.2 57.6 63.7 71.5 74.4 76.8 78.6 80.5 82.2 85 87.1 89.4 90.5 92.5 94.9 98 103.5 107.4 109.5 111.4 114.5 116.7 118.9 122.9 125.2 127.4 128 124.6 130.6 134.5 136.7 140.1 142.3 144.8 147.1 149 152.2 154.2 156.2 159.1 162.7 166.1 168.8 171.8 175.3 179.2 184.2 189.3 192.8 194.7 195.7 197.3 199 201.5 203 205 208 211.7 215.2 218.8 223.5 228.5 234.6 240.5 247.8 254.8 262.2 269.8 278.7 286.1 294.4 299.9 306.5 319.5 325.6 341.4 353 358.7 362.3 367.8 378.5 385.5 390.1 397.5 411.2 429.6 445.9 451.8 455.8 463 468.1 472.2 480.6 488.6 488.6 487.6 484 479.3 473.6 465.4 460.1 454.2 448.2 442.4 436.2 430.5 425.6 418.6 413.3 406.7 398.5 390.1 380.8 370.9 360 349.4 339.2 331.2 324.9 319.4 316.3 316.8 318.5 320 321.9 323.7 324.3 324.8 324.4 323.8 323.5 322.4 319.8 316 311.6 306.8 301.1 295.3 286.7 277.1 264.6 255.5 244.1 245.1 244.8 243.7 244.4 252.7 261 268.4 277.6 286.5 298 313.8 328.3 329.9 330.7 328.9 325.4 320.5 315.4 309.1 302.6 292.7 272.6 249 235.3 224.9 220.9 211.1 205.3 198.6 191.3 186.6 178.5 170.9 162.4 156.1 145.6 133.6 115.7 102.5 89 77.6 72.7 67.3 +17.5 19.9 23.3 26.8 29.5 31.2 33.4 35.1 36.3 35.9 32.6 37 39.7 43.5 52.1 59 67.9 72.8 74.4 76.7 78.6 80.3 81.6 84.9 88.7 91.9 93.8 95.7 96.8 100 103.9 107.3 109.9 112.4 115.9 118.4 121.2 124.3 126.5 129.2 127.3 125.4 133.8 137.3 140.1 142.2 144.8 146.9 149.1 151.2 153.7 155.2 158.8 164 168.9 172.6 175.4 177.7 180.6 184.2 188.1 191.2 193 193.8 194.8 196.5 198.4 200 201.7 204.7 207.4 210.3 214 217.8 222.8 228.9 237.6 245.6 252 261.2 269.7 278.7 286.3 293.9 301.3 307.7 315.1 326 338.2 347.9 360.8 368.5 373.2 375.7 380.4 386.5 391.9 399.2 411.4 426.8 439.3 447.5 454.7 460.6 464.2 469.4 477.7 483.3 485.7 486.5 484.7 481.5 476.9 469.5 463.2 458.9 455.2 449 442.8 438.4 434.3 428.4 423.1 415.2 408 398.1 388.5 379 367.5 356.2 345.4 336.4 329.5 323.9 320.1 320.8 322.7 324.5 326.1 327.1 327.7 327.5 326.9 326.6 325.6 323.9 321 317.3 313.6 309.5 303.6 299.4 294.2 285 272.7 260.1 250.4 239.2 239.7 241.7 243.8 251.3 260.1 266 270.9 280 294.4 313 330.7 336.2 338.5 339.5 336 332.5 326.4 320 310.6 300.4 265.4 245.3 230.8 220.5 212.7 207.9 203.9 193.7 190.2 186.5 173.9 161.1 159.4 156.7 147.9 138.6 109.7 97.1 78.7 71.1 67.3 64.6 +21.2 22 25.6 27.6 29.8 31.8 33.6 34.5 35.9 35.9 35 38 40.7 45.4 51.6 60.8 68.9 71.5 71.9 75.4 76.3 80.1 84.3 87.5 91.5 94.4 96.3 98.2 100.9 102 104.5 107.9 111 114.1 118.5 120.6 123.4 125.7 127.7 129.7 127.1 129.3 136.2 139.9 142.1 143.7 146.8 149.4 151.3 154.5 155.7 159.9 165.8 170.1 174.1 177.2 179.5 181.7 183.9 187 189.7 191.5 192.2 192.8 193.9 195.5 197.1 198.7 200.8 202.9 205.7 209 213.5 217.8 223.9 234.6 246.4 253.2 259 265.3 275.9 284.2 294.5 305.8 312.7 321.6 332.7 343.5 352.7 361.7 369.6 377.2 382.1 384 385.7 389 393.4 400.3 412.5 420.8 430 437.4 446.3 452.2 459.7 466.8 471.9 476.1 481.5 482.9 482.5 482.2 478.6 474 469.4 466.2 462.5 458.1 452.4 447.5 442.9 440 432.5 427.2 419.3 409.9 400.1 387.5 375.3 364.2 353.1 342.9 334.5 328.7 327.2 327.1 327.9 329 330.5 331.1 331.5 331.1 330.2 328.7 326.7 324.4 321.2 317.6 314.1 310.4 306 303.1 298.9 292.8 281 267.8 255.3 245 238.2 238.1 242.2 248.8 254.9 260.2 267.5 278.7 293.9 309.2 325.8 335.5 347.6 351 348.2 343.9 338.2 328.6 316.1 292.3 259.3 241.1 226.6 215 210.7 209.3 205.4 191.8 177.7 172.5 151.3 150.8 159.1 162 149.4 126.4 94.3 82.6 74.9 67.9 66.4 62.2 +23.5 23.8 25.6 29 32.5 33.2 34.1 35.1 37.7 36.3 36.1 39.1 42.5 44.8 52 60.6 66.6 68 71.3 74.6 78.1 81.5 86.9 91.1 93.7 96.3 99.1 99.7 102 103.7 105.7 108.9 111.6 116.3 119.9 122.7 124.6 126.2 128.2 127.8 127.1 132.1 137.1 141.6 142.9 145.5 149.3 151.8 153.6 156.2 160.9 165.9 170.5 174.9 177.7 180.5 182.4 183.9 185.9 187.7 189.8 190.7 191.4 192 193.1 194.8 196.6 198.4 200.1 201.7 204 208.5 213.5 220.9 231.5 244.3 251.4 257.2 266.7 271.8 278.9 293.3 304 313.2 321.8 335 347.1 359.8 366.7 374.3 381.5 386.4 390 390.9 393 394.2 394.4 401.2 409.3 418.4 425.5 431.1 437.7 446.9 456.3 463.7 467.7 473.4 478 478.5 479.8 479.9 479.4 477.7 477.6 475.1 471.6 467.8 462.4 458.4 455.2 449.4 444.6 439.8 432.3 420.7 409.4 397.1 383 370.8 359 347.7 340.1 334.1 333.7 332.9 333.4 333.8 334.7 335.3 335.5 334.3 332.5 330.5 328.3 325.2 321.9 318.2 314.8 311.1 308.4 305.8 303.7 299.3 290.9 276.6 263.1 249.5 240.4 233.2 239.7 246.2 251.3 258.2 267.5 280.1 293.5 308.3 321 339.5 351.1 354.5 358.2 355.7 348.4 332.4 308.1 282.9 252.2 233.9 220.9 208.1 211.2 210.1 197.9 179.4 154.7 154.8 142.3 141.7 136 142.1 125.4 100.1 85.6 72 66.7 64.9 63.4 60 +25 27.2 28.2 28.6 30 33.1 35.9 37.2 38.9 37.4 37.2 38.9 41.8 44.9 49.9 59.1 63 67.2 70.8 73.7 78.3 83.6 90.2 92.5 95.3 97.6 98.8 100.3 102.1 105.6 108.1 110.4 114.1 119 122.1 123.5 125.1 126.6 127.5 125.1 126.7 134.7 139.2 142.6 143.6 147.1 150.6 153 155.7 158.5 164.9 169.8 174.3 177.6 180.4 182.4 183.6 184.7 185.6 187.3 188.7 189.8 190.5 191.3 193.6 194.8 196.6 198.4 200 201.9 205.2 210.1 218.8 229.1 239 248.7 253.3 261.9 273.6 281.9 289.1 299.8 312.8 322.3 334 346 358.3 370.8 377.9 383.9 391.5 394.9 396.5 397.9 397.5 399 399 400.7 407 414.9 421.2 426.8 432.2 442.7 451.7 459.2 463.8 467.3 470.6 473.7 477.6 479 480.2 482.9 485.5 483.1 480.9 477.2 472.9 468.5 465 461.5 458 451.3 442.1 429.7 417.9 403.1 388.1 374.9 362 349.5 343.8 342.3 341.2 340.5 339.9 339.6 340 339.8 338.9 336.4 334.1 331.9 329.4 326.3 323.6 320.2 317.2 313.8 311.3 309.3 307.8 304.6 298 287 272.3 258 244.7 235.3 235.3 242.4 248.5 257.7 266.6 279.5 292.6 303.5 311.6 328.5 344.3 359 365.6 364.3 348.5 319.5 297 269.1 243.8 229.6 212.9 199.8 209.3 191.9 172.8 158.7 132.2 120.9 109.9 96.6 92.1 91 94.8 84.5 70.7 65.3 63.7 64.4 62.1 54.8 +26.1 27.9 29.3 30.4 31.3 34 36.7 38.9 40.4 39.6 37 38.6 42 48.5 52.8 58.3 61.8 64.4 69.4 73.5 78.4 85.8 88.9 93.9 96.2 97.8 99.2 102.1 105.8 108.5 110 111.8 116.7 121.8 124.5 125.1 125.4 126.7 124.8 124.3 130.6 137.1 140.8 142.4 143.8 147.8 151.4 153.7 156.3 161.9 168 172.6 176.4 179.2 181.2 182.8 184 184.4 184.8 186.2 187.6 188.6 189.7 190.9 193 194.9 197.6 199.5 201.2 203.9 207.6 215.5 225.4 233.8 242.5 246.6 257.2 268.7 281.3 294.4 303.3 301.5 319.2 328.5 339.6 356.4 368.9 379.1 385.5 393 399 401 403.9 404.2 404 402.6 403.2 405.1 409.1 412.4 418.9 424 430.6 439.9 446.2 452.4 456.9 461.7 467 471.6 478.2 482.5 485.6 489.8 490.7 490.7 489.7 487.4 483.2 479.4 476.7 472.8 470 463.6 454 437.9 424.3 408.1 391.5 378.4 365.8 356.2 351.7 350.1 349.5 348.5 347.4 346.6 346.3 344.5 341.5 338.4 335.8 332.6 330.1 327.4 325.2 322.6 320.5 318.2 315.7 314.1 314 312.6 305.8 295.3 281.4 266.8 251.1 237.1 231.1 236.6 244.1 252 262.8 272.6 280.7 284.6 299.6 319.1 330.3 342.2 353.6 345.4 332.7 304.9 273.8 248.6 234.2 226.7 200.9 187.8 185 158.4 143.9 145.4 114.2 95.4 84.9 75.9 70.5 78.7 77.1 70.3 65.3 62 61.5 63.2 57.5 58.3 +26.7 28.6 30.6 31.5 33.1 35.8 38.6 40.8 42.1 40.8 38.3 43.2 43.6 46 51 56.2 58 62.5 69.2 73.4 79 84.9 91 94.7 97 98.3 102.4 108.4 110.9 111.5 111.6 114.3 118.8 123 125.3 125.9 125.2 125.5 123.1 124.7 133.2 137.6 140 141.6 144.5 148.9 152 154.6 159.3 165.5 170.8 174.4 177.4 180 181.4 181.9 182.4 182.7 183.6 184.9 186.1 188 189.3 190.6 192.6 195.8 198.9 201.3 203.6 205.9 211.3 220.7 228.4 234.1 242 250.6 262.8 277.1 291.7 307.8 317.4 322.9 318.5 337.5 354.8 367.7 379.3 388.3 394.5 402.7 408.2 409.5 412.9 411.4 409.6 408.6 408.5 408.3 413.8 416.7 418.8 424.3 428.8 435.9 441.8 449.3 455.5 461.6 467.1 472.4 480.8 487.7 489.9 491.3 494.7 498 499 497.2 494.3 492.4 488.5 484.5 480.1 475.4 463.5 446.1 430.1 413.3 396.1 382.7 372.9 365.2 361.6 360.1 358.6 356.9 354.7 352.7 350.7 347.5 344.1 340.7 337.2 333.4 330.7 328.5 326.5 324.6 322.9 321.9 320.2 322.4 322.5 320.2 315.7 302.5 289.1 275.8 259.5 241.8 228.7 230.9 238.8 245.5 252.9 255.6 259.2 267.3 280.5 293.8 306.7 314.1 324.2 328.2 313.7 282 253.8 223 212.7 208.3 182.4 160.9 138.1 120.5 114.1 109.5 92 79 70.7 64 60.7 64.2 64.9 64.4 62.4 61.7 60.4 57 54.6 62.5 +27.8 29.6 30.9 32.2 35.3 37.8 39.8 41.7 43.1 42.1 39.7 42.4 47 49.8 52.2 54.3 57 61.6 68.9 74.5 79.7 85.7 93.3 95.7 97.2 99.5 106.5 110.3 112.7 113.2 112.7 116.8 122 125.8 128.2 126.6 125.3 124 123.4 127.9 133.9 137 139.5 141.5 145 149.1 152.1 155.9 162.3 167.4 172.2 175.5 178.1 179.7 179.7 179.8 180 180.4 182.4 183.8 185.5 187.6 188.8 190.5 192.9 196.6 199.5 202.7 204.7 207.8 214.6 223.5 229 233.3 246.2 256.8 267.3 286.7 307.2 320.5 330.6 337.5 339.5 346.5 363.8 377.7 389.7 399.2 404.8 412.9 418.8 422.9 424.3 421.9 418.2 416 415.6 416.3 419 422.8 424.4 427.3 431.3 436.6 442.7 450.4 457.6 463.6 469.1 474.5 483.1 488.4 491.7 498.3 504.9 508.8 510.2 509 507.5 508.5 508.9 504.1 495 486.2 473.2 453.9 437.3 420.1 402.3 388.9 381.4 374.9 372.4 370.7 368.5 366.3 363.8 358.3 354 350.2 346.5 343 339.3 335.1 331.2 328.7 327 325.5 325.1 324.9 326.2 328.1 328.2 326.1 319.9 308.1 293.7 281 263.6 248.3 236.5 225.7 231.6 236.3 240.7 244.8 250.1 256.4 265.2 275.9 291 302.3 309.8 312.7 291.9 263.9 232.8 201.4 187 175.6 152.6 130.5 109.4 92.9 84.6 79 69.9 61.4 61.2 58.9 56.2 58.1 58.8 59.2 60.5 62.4 58.9 55.2 58.2 68.2 +28.9 29.1 30.5 33 35.7 38.2 39.9 42.1 43.6 43.2 41.1 41.8 45 48.9 52.3 54.6 58 63.3 70 76.1 82.6 87.4 92.3 95 97.7 101.9 109.2 111.3 112.9 112.5 113.1 119 124.6 129.9 131.4 128.4 125.8 122.9 123.3 130.8 134.6 136.5 138.8 142.1 145.5 149.3 152.8 158.1 164.2 169.3 173 175.5 177.3 177.4 177.2 177.3 177.7 179.1 181.4 183.4 185 186.7 188.2 191.4 193.1 196.7 199.5 202.3 205.7 209.8 220.1 226.2 230.9 240.3 252.8 265.2 280.8 299.6 316.5 331.9 343.8 351.3 350.8 357.5 375.2 388.7 400 410.4 416.6 422.5 428.7 432.1 434.8 434.5 431.1 425.5 425 424.7 425.2 427.6 430.4 433.5 436.8 437.8 445.2 453.5 458.7 464 471.2 476.6 483.6 489.9 496.9 504.5 513 517.5 518.5 519.3 517.6 525.5 525.2 522.4 510.1 498.4 482.2 461.5 444.8 429.5 412.7 397 389.1 384.3 381.5 379.6 378 375.3 370.6 364.2 358.1 352.1 347.4 343.1 339.1 335.1 331.1 327.3 325.8 325.3 325.8 326.9 329.5 331.5 330.2 329.3 323.9 313.3 296.7 280.4 263.6 253 244.8 225.4 223.3 229.6 234.6 239.2 245.2 250.5 258.4 267.7 280.1 290.9 289.4 290.5 278.1 254.4 219.4 186.4 162.5 145.2 126.3 106.9 87.5 75.9 68.1 62.7 58.4 56.5 57.3 55.5 56.6 56.3 56.3 57 57.7 58.7 55 55 60.4 69 +28.1 27.9 30.6 33.2 35.6 37.9 39.6 42.1 44 44.1 42.5 41.7 43.8 46.3 49.3 52.7 56.8 63.2 70.8 77.3 82.3 86.3 90 95 99.3 105.6 111.1 112.3 110.9 110.2 115.9 122.8 128.1 131.8 132.5 129.5 126 122.6 124.5 131.9 134.9 136.9 138.6 143.2 146.3 149.5 154.9 160.4 166.9 170 172.4 173.8 174.5 174.7 174.4 175 176.7 178.9 181.5 182.6 183.5 185.3 187 189.8 194 197.4 199.2 201.7 205.9 216 224.1 230.3 236.9 246.9 261.6 276.1 290.8 307.1 324.6 345.1 357.1 366.7 372.8 377.2 387.8 397 408.1 418.9 427.6 432.6 435.6 440.1 443.8 444.8 443.9 440.6 436.1 432.8 431.9 432.1 435.3 439.3 443.6 447.4 449.8 453.4 458.1 468 477.3 482.8 488.6 494.8 505.9 514 517.7 521.6 526.4 531.5 533.4 536.7 539.2 536.7 524.6 508.7 490.6 468 451.1 436.1 420.5 406.6 397.5 392.9 390.3 387.9 384.3 380.2 375.3 369.5 361.8 353.4 346.4 340.7 336.2 332.3 328.3 324.5 323.3 323.4 324.8 327.1 328.8 332.2 329.9 326.3 324.6 315 295 280 262.4 254.8 246.7 228.8 216.8 221.9 228.9 234.8 240.7 245.7 250.8 257.1 261.7 263.9 262.6 266.2 259.9 237.3 208.2 174.8 148.5 127.9 110.1 91.6 78.7 70 62.8 57.5 54.6 54.6 54.6 54 56.3 55.5 57.1 58.5 54.5 50.6 55.3 57.5 61.4 67.2 +24.9 27.5 30.6 33.3 35.2 37.8 40 42.2 44 44.6 43.4 43 43.9 46.5 49.5 53.1 58.2 67.9 73.7 78.3 83.9 88.2 91.9 96.5 101.8 107.1 109.3 108.8 108.3 111.9 119.6 124.7 129.3 132.5 132.3 129.5 124.6 122.5 127 132.7 135.3 136.9 138.9 144.7 147.6 152.1 158.5 164.3 167.2 169 170.1 170.9 171.2 171.8 172.8 173.8 176 178.5 181 181.5 182 184 186.4 190.4 195.7 198.1 199.4 204.2 210.7 220.2 226.8 234.7 243.6 254.6 270.2 285.5 299.5 317.3 335.9 356 369.5 380.4 386.5 389 396.4 404 413.9 424.6 435.2 440.4 444.4 447.3 451.3 454.5 453.6 451.1 448.7 444.8 440.1 438.7 441.1 447.9 452.7 455.4 456.3 457.9 461.8 476.4 486.5 490.7 498.1 501.1 510.6 516.4 520.8 527.2 534.8 543.3 548.1 550 551.9 548 535.9 517.7 496.7 475.3 458.8 441.1 425 412.3 402.7 397.2 395.1 393.1 389.2 384.2 378.6 372.4 362.8 351.2 342.7 336.9 331.6 327.3 322.5 319.7 318.9 319.2 322.3 324.1 323.5 325.6 326.6 323.8 318 306.5 293.9 280.1 262.3 255.6 239.9 228 221.6 212.5 224.7 230.6 236.7 241.4 247.6 247.3 250.6 250.8 250.9 248.3 233.6 213.2 192.7 162.4 138.5 118.1 100.1 85.6 75.2 67.6 60.6 55 53.7 53.6 53.8 53.6 54 55 57.4 54.1 51.5 54.6 56.7 61.8 65.4 72.8 +24.4 26.9 30.1 32.7 34.9 37.7 40.2 42 43.4 43.8 43.3 43.8 45.9 47.9 51.7 56.5 64.3 68.2 74.4 82.1 85.7 89.6 94.9 98.4 103.4 106.6 105.8 107.3 110.9 116.3 121.4 126.1 129.9 132.2 130.2 127.9 123.1 122.6 125.1 132.9 136.5 137.6 141.4 145.5 149.7 155.3 161.6 164.7 166.3 167.4 167.7 168.1 168.7 169.9 171.4 173 175.2 177.4 179.3 179.3 181.7 184.5 189.9 192.7 195.1 197.6 200.5 209.4 218.3 224.1 231.6 240.2 249.8 263.5 278.3 292.3 307.7 326.4 346.1 366 380.2 392.5 399.2 401.5 405.6 413.8 422.9 431 438.5 443.3 449.1 454.6 458.6 462 460.7 459.6 459.6 458.7 456.6 453.4 452.9 457.3 461.6 464.1 464 463.2 467.7 482.9 493.9 498.6 501.5 506.5 512.3 516.3 524.4 532.7 544.3 554 556.7 557.5 558.7 553.1 541.5 524.2 501.8 483.2 462.7 445.4 426.5 413.3 404.3 398.2 395 392.7 389.7 385.8 381.8 373.6 362 349.1 337.7 330.9 326.1 321 315.7 312.3 313.5 313.8 317.8 316.9 317.2 316.8 316 313.2 307.1 300.1 290.7 280.2 259 247.7 236.5 229.9 220.9 209.6 218.7 226.8 232.6 238.5 239.4 239.8 240.9 240.6 239 232.5 209.7 191.4 174.1 154.7 133.7 110.7 93.5 79.4 70.5 63.6 57.9 54.6 53.3 53.3 53.3 53.5 53.9 56.8 54.1 50.7 53.7 55.6 59.9 67.8 72 77.2 +26.2 26.9 29.7 33 35.6 38 40.2 41.2 42.8 43.2 43 43.8 45.6 48.9 54.5 60.4 66.7 76.6 80.5 82.4 87.3 93.5 95.9 99 100.3 101.7 105.2 109.1 113.6 119 122.3 125 128.2 129.2 126.8 124.6 121.2 121.5 126.5 135 138.2 140 143.4 147.2 152.8 159 162.5 164.7 165.7 166 166 166.3 167.5 169.2 170.9 172.4 174.2 176 176.9 178.3 182.2 186.1 191.2 194.2 196.2 198.8 203.2 211.7 221.9 229.4 237.4 245.6 257.5 271.1 288.9 301.3 316.6 335.8 357.3 376.4 391 402.9 409.2 411.1 414.7 423.8 432.9 438.5 443.3 447.9 455.5 463.6 467.7 468.6 468.4 467.5 469.1 471.5 470 468.8 467.8 468.5 470.3 474.7 473.2 471.1 482.5 493.3 500 502.4 505.7 510.2 514.8 520.6 529.5 543.7 557.8 566.6 565.2 561.1 558.4 552.4 541.7 524.7 505.8 486 463.8 442.8 427.1 408.4 400 395.3 391 388.7 387.1 385.7 381.8 373.5 360 345.3 329.6 322 317.3 313.2 309.2 304.3 305 305.4 304.6 304.6 304.4 302.9 306.6 303.5 296.5 294 285.2 273.2 256.4 244.5 233.6 219.6 212.1 203.2 214 224.4 230.8 233.6 230.9 228.1 228.8 223.7 219.7 208.2 188.8 176 159.9 150.2 129.2 104.3 87.6 73.6 65.3 60.1 55.8 53.8 53 53 53.2 53.3 53.4 53.7 51.5 53.5 55.1 57 62.3 70.8 78.5 83 +25.9 28.5 31 33.5 36.1 38.4 40.1 41.7 42.7 42.4 42.9 44.7 47.2 51.8 60.7 67.9 72 78.9 83.9 87 89.7 93.8 97.4 100 101.8 103.4 106.3 111 117.7 120.5 122.2 123.5 125.1 125.5 124.3 122.9 120.6 121.6 129.1 136.6 140.3 142.8 145.8 151.6 157.6 160.4 163.1 163.9 164.7 164.3 164.3 165.2 167 168.7 170 172.1 173.9 174.7 174.5 176.9 183.7 188.2 193.1 196.1 198.2 200.6 207.8 218.3 225.8 234 241.6 250.4 263 278.7 295.3 308.2 327.7 348.7 367.8 385.9 400.8 412.9 419.9 421.6 422.8 432 440.4 444.8 449.5 455.9 463.1 469.9 474.3 476.5 477.7 477.4 477.7 477.7 479.8 481.6 483.4 484.6 482.5 484.8 483.9 483.3 495.5 501 503.6 505 508.4 511.3 517.1 523.9 535 549.5 562.6 571.6 567.5 560.2 555.9 549.4 537.2 520.4 501.8 481.8 459 437.2 416.7 398.7 392.4 389 383.1 380.4 379.4 380.1 377.2 370.9 353.2 337 320.7 312.7 308.2 303.7 300.2 297.3 296.8 296.9 292.9 291 292.3 292.2 292.4 291.6 289.2 284.4 277.1 267 257.6 240.6 226.3 215.7 207.2 196.9 210.9 220.7 227.8 229.4 224.7 220.8 215.9 209.6 201.7 188.4 178.1 165.9 152.8 139.1 120 99.6 83.5 70.1 62.4 57.1 54 52.7 52.6 52.6 52.7 52.8 53 53.6 48.3 54.2 56.3 60.3 65.2 72.5 82.6 88.8 +18.8 22.6 27.8 33 36.4 39.1 40.8 41.1 41.1 41.5 44.2 46.9 49.8 56 68.6 73.1 76.4 79.2 82.6 86.6 90.2 96.2 98 99.8 101.8 103.2 108.2 114.6 119.3 122.2 123.7 123.5 123.5 124.1 123.6 122 120.6 121.4 131.6 138.8 142.9 146.4 150.3 154.3 158.4 160.8 162.1 162.9 163.1 162.6 163 164.3 166 168.2 169.4 171.3 173.2 172.8 173.4 179.7 185 189.6 193.9 197.7 200.3 204.7 213.9 222.4 229.6 238.2 246.1 257.6 271.2 285.7 301.1 316.1 339.2 361.2 379.1 397.6 411.3 424.2 431.3 433.1 434.2 441.2 448.8 453.7 458.4 464.3 468.4 473.6 478.8 483.3 485.4 486.1 486.5 486.8 489.6 493.5 495.3 497.9 501.1 499.1 493.9 495.4 499 505.3 506.9 508.6 511.4 513.5 518.3 529.3 538.6 550.4 560.4 563.2 558.3 553 549.3 540.5 528.2 513.6 497.8 477 453.3 435 410.4 388.4 381.1 375 369.3 367.5 363.1 365.5 363 354.4 338.2 322.7 309.9 302.5 298.9 295 293.3 290.6 288.8 288 284 281.6 280.5 281 278 279.6 281.6 270.5 262 257.5 250.4 233.7 221.2 211.9 205.4 194.9 206.2 217 224.7 224.3 217.1 213.5 207.9 201.8 191.7 180.3 173.8 159.6 145.7 129.9 112.9 95.8 79.6 67.1 60 55.6 52.8 51.9 52.1 52.1 52.2 52.4 52.6 50.4 51.3 54.9 57 60.9 67.7 73.7 83.1 89.8 +27.2 26.2 23.5 29.5 35.3 37.8 39.6 40.3 39.9 41.9 47.3 49.5 53.1 61.7 69.6 73 75.6 79.1 82.5 87.5 92.7 98 99.2 99.9 101.6 103.2 110.9 117.4 120.4 123 124.6 125.6 124.1 123.4 127.7 126.5 120.4 120.3 129.8 141.6 145 148.3 152.1 155.8 158.8 159.8 160.2 160.2 161.2 161 161.4 163.3 165.6 167.7 169.3 171.1 171.4 171 177.1 182.7 185.9 190.3 196 199 203 209.2 219.7 227.2 234.6 242.7 252.1 264.1 277.9 291.2 307.1 326.8 349.3 369.8 390.7 408.1 420.3 433.9 441.5 446.9 449.8 451.2 460.6 466.6 470.3 473.7 477.3 480.6 487 490.1 493.5 494.7 496.3 497.1 501.1 504.4 508.5 510.7 511 509.6 510.3 513.6 512 510.4 512.3 512.5 514.8 517 524.5 532.9 540.9 548.1 555.1 553.9 549.2 544 538.9 530.6 520.4 506.8 493.2 470.8 448.8 426.5 401.3 381.5 371.7 363.6 356.6 352.2 348.3 347.4 345.2 337.3 324.9 313 305.2 296.1 289.9 288.3 285.5 280.9 280 278.1 276.3 273.3 270.8 269.3 269.4 267.8 263.5 259.3 254.3 247.9 237.6 226.1 216.3 212.7 206 196.7 199.5 210.9 216.9 215.2 210 203 198.3 193.8 184.6 176.5 170.5 155 139.7 123.4 108 93.4 77.5 65.4 58.9 54.7 52.4 51.4 51.4 51.8 52 51.6 47.2 52 53.1 55.1 59.2 63.3 69.7 78.7 87.1 95.7 +31 32.1 32.4 28.4 31.3 34.4 35.6 37.7 40.7 43.3 47.5 52.2 57.2 63.5 68 72.5 76.4 80.1 84.6 89.3 95.9 99.4 99.8 99.8 101.1 104.9 115.1 119.4 122.1 123.8 125.8 126.4 124 123.9 132.3 134.3 122.7 119.9 127.8 142.3 146 149.4 153.1 155.9 157.8 157.9 157.2 157.2 158.1 158.3 160.2 163.1 165.5 167.2 168.2 169.2 169.3 173.2 178.6 183.2 187 193 196.8 200.9 207.6 214.1 224 232.4 239.1 246.1 257.5 269.8 282.5 298.1 316 334.1 355.7 379.7 399.5 415.1 429.4 442.8 454.6 461.3 465.4 460 472.2 476.6 480.1 483.9 486.7 489.2 493.4 497.4 501.7 503.8 504.9 506.7 511.4 515.6 517.8 518.4 519 519.4 519.9 519.9 519.8 517.1 516.6 517.1 518.1 521.5 527.4 532.8 538.8 543.2 544.7 544.1 540.5 536.6 531 523.7 512.8 498.8 484.9 468.1 449.1 421.8 398 375.8 364.6 355.4 347.3 338.3 334 332.4 327 315.5 312.3 303.2 296.1 290.5 282.1 279.9 277.6 268.3 267.5 266.6 265.6 263.9 261.6 260.2 259 256.8 255 251.5 248.4 241.9 231.5 221.2 213.5 208.3 203.8 195.8 188.3 202.5 199.9 199.2 197.9 197.5 197 192.1 182.4 174.9 167.1 154.1 136.6 118.7 103 88.7 73.7 63.8 58.1 55.4 52.8 51.2 51 51.4 50.4 47.2 51.3 53.6 54.4 55.5 62.6 65.2 73.6 83.8 92.9 107.7 +31.6 34.1 35.4 34.2 27.2 31.2 35.8 39 40.3 44 49.7 54.9 60.8 66.8 70.5 74.3 78.4 82.9 89.7 92.7 96.9 100.4 100.6 100.1 101.2 110.3 117.1 121 122.7 124.5 126.4 128 124 124.5 132.6 137.4 125.8 118.8 128 141.7 146.8 150 152.7 155.4 155.8 155.1 154.4 155.1 156.2 156.8 160.1 162.8 164.4 165.5 165.4 166.5 170.8 175.1 180.7 185.4 188.9 192.8 197.1 205.9 212.8 219.9 228.3 235.3 242.4 252 264.1 275.5 288.6 305.7 322.4 342.2 364.1 386 404.4 422.4 439.5 456.2 467.7 476.9 478.5 474.8 481.7 485.5 490.3 493.2 494.6 496.4 500.1 504.2 507.6 510.4 512.1 516.4 519.9 522.5 524.4 525.7 526.2 526.1 525.9 525.7 523.8 522.2 519.7 519.1 520 523.3 527.7 532.7 535.9 538.4 538.8 535.6 531.5 528.6 523.1 515.1 504.5 492 478.7 464.7 446.8 423.6 396.2 372.2 358.6 349.2 338.8 327.9 318.7 314.9 308.9 303.4 302.4 292.4 286.9 279.9 273.1 269.4 263.2 260.9 260.4 260.1 258.7 256.9 255.8 252.8 249.8 248.9 248.8 247.1 244.1 238.6 226.3 217.2 211.1 206.8 203.5 195.2 175.9 190.8 192.3 190.9 188.5 188.1 193.2 191.4 181.4 171.9 160.4 145.5 127.9 114.5 97.2 83 69.8 62.8 58.3 56.2 53.9 51.6 50.4 49 47.5 52.7 56.4 56.2 55.7 59.4 64.1 71.3 79.7 87.8 99.4 116.5 +33.3 35.8 36.1 33.5 30.1 31.8 37.1 38.6 42.7 47.5 52.1 57.4 64.6 69.9 73.9 77.4 81.2 88.7 93.9 97.1 99.4 101.6 101 100 103.7 115.3 119.6 122.1 123 125.2 126.8 130 123.8 124.4 132.7 134.4 123.9 118.6 128.6 142.3 146.9 149.8 152.1 153.2 152.9 152.5 152.8 153.1 154.2 157.2 159.9 161.3 162.4 162.2 163.4 167.8 173.9 178.4 183.1 186.8 189.8 193.1 200.1 209.7 215.7 223.2 231.1 237.8 247.6 257.4 269.1 280.5 295 310.1 326.9 348.6 370.7 391.8 414.4 432.8 447.1 462.5 476 486.5 488.4 484.7 490.5 494.6 499.7 500.3 500.7 502.7 505.6 509.4 513.4 516 518.3 522.9 526.4 529.9 530.8 532.2 531.9 531.7 531.1 529.4 526.7 524.3 521.1 519.5 520.4 522.2 525.4 528.5 529.6 529.9 527.8 525.5 519.5 515.4 511.7 506.6 496.4 484.2 471.8 459.3 444.8 424.3 391.5 365 353.4 344.4 334 322.3 307.1 295.5 292.9 290.3 285.9 281.6 275.5 269 263.8 261.3 259.1 258.4 258.5 257.7 255.7 252.9 248.5 245.6 243.7 242.2 242.6 241.5 238.5 230.4 220.8 214.1 208.8 204.4 199.9 190.7 175.3 179.8 185.1 183.8 181.5 180.3 185.6 184.2 178.5 168.6 153.4 133.7 117.7 101.2 90.5 78.2 67.6 62.2 59.2 56.7 55.1 51.8 47.6 49.1 50.8 51.8 56.1 56.1 61.2 64.1 65.2 73.3 80 90.7 103.5 122.6 +33.8 36.6 35.7 32.3 30.5 30.1 34.1 39.7 44.4 49.4 55 60 67.5 72.1 77.3 81 85.8 93.8 96.1 98.4 101.8 103 100.2 99.5 107.7 116.5 119.8 121.7 123.7 125 128.7 133.3 124.6 125.4 128.6 128.6 119 118 130.6 142.8 146.2 148.3 149.7 150.7 150.9 150.9 150.9 151 153.7 156.6 158.6 159.2 159.9 161.2 164.9 170.5 175 179.8 184.7 189.6 193 196.5 206.3 212.8 218.7 226 233.9 242.2 251.5 262 273.9 285.8 299.2 315.4 333.8 354.3 374.5 397.1 420.1 436.5 451.7 466.8 480 486.4 491.1 492.2 494.3 500.6 503.2 504.9 505.7 507.8 511.3 514.6 517.7 520.5 524.5 528.8 532.4 533.9 535.4 535.9 535.9 535.3 533.4 530.9 527.3 523.7 519.6 517.1 517 516.5 517.5 519.2 520.6 517.5 514.2 510.2 506.8 504.4 500.5 493.5 485.5 474.9 464.6 454.6 442.3 423.6 389.4 361.2 350.7 340.1 329.8 321 303.9 287.8 279.7 278 274.9 271.8 266.6 262.3 259 258.2 257.2 256.8 257.1 256.3 256.1 253.5 244.8 241.6 239.7 238.7 237.7 236.7 233.6 228 219.5 212.4 207.5 201.9 197.6 188 176.7 164.6 176.8 175.7 174.6 173.3 174.4 174.5 174.5 161.7 143.9 124.5 109.1 95.9 86.1 75.5 68 63.8 60.5 58.6 55.7 52.5 46.4 48.7 49.5 50.8 55.3 57.8 64.5 63.3 64.8 68.4 79.8 92.9 114.1 128.4 +34.6 37.3 36.8 35.2 34.6 36.5 38.3 40.9 45.1 52.1 57.3 62.3 69 75.8 80.4 84.2 90.2 95.2 97.6 101.7 106.4 107.3 100.6 99.4 103 112.5 118.8 121.7 123.9 125.8 131.9 135.3 126.8 123.6 124.2 118.8 117.5 119 135.7 142.2 144.7 146.2 147.3 148.1 148.2 148.2 148.2 150.3 153.3 155.5 157.5 157.3 159.1 162.6 166.9 170.6 174.8 180.6 185.3 190.1 195.8 201.4 207.4 215.1 221.5 228.5 237 245.4 254.8 265.3 276.3 288.7 303.5 320.8 340 360.1 381.7 402.5 421 440.3 457.5 469.8 476.8 483 489.7 492.6 495.9 501.8 506 509.7 510.6 512.3 515.1 518.5 521.6 525.2 529.5 533.3 535.8 537.5 539 538.5 538.2 536.7 534 530.3 526.3 521.2 516.3 512.5 511.4 510.2 509.9 510.3 507.6 504.4 501.1 496.2 491 487.9 484.2 480.5 474.5 465.2 458.5 450.9 440.8 421.3 386.4 358.2 345.6 334.4 324.4 316 305 285.3 275.5 271.3 269 266.3 263.3 260.2 257.8 256.8 256.2 256.1 256.1 256.3 256 250 243.8 239 237.2 235.8 232.9 230.5 227.6 222.7 217.2 209.7 205.9 199.6 195.4 187.3 178.9 160.6 164.9 168 166.3 164 163.2 166 163 150.4 133.9 118.5 106.1 94.5 83.5 73.6 69.3 65.1 61.6 58.5 55.5 52.6 50.1 46.5 48.3 49.1 54.1 56.3 59 63.9 65.7 67 74.6 91.3 101.6 122.7 +35.3 38.1 39.4 40.4 39.1 39.2 39.6 42.5 48.8 53.9 59.9 64.2 72.7 78.2 81.8 86.9 93.1 97.3 100.8 107.1 111.3 112.7 105.1 99.5 100 107.4 115.6 120.5 122.8 129.3 134.9 135.4 127.7 120.2 117.7 117.5 120.6 129.8 138.1 141.3 142.8 143.8 145 145.5 145.6 145.7 147 149.9 152.5 154.5 155.1 155.1 159.2 163.2 167.3 171.4 176.1 181.3 186.5 192.9 199.1 206.5 210 216 221.6 228.9 238.5 248 257.8 268.1 278.8 292.4 307.4 326 344.3 364.4 384.1 405.1 424.7 443.3 456.6 465.5 472.6 479.3 487.7 491.8 496.5 503.8 509.2 514.1 515.5 516.6 519.4 522.5 525.2 529.2 533.4 536 538.1 539.1 539.9 540.1 539.5 537.6 533.8 529.3 523.9 517.9 511.7 507.4 504.7 503.6 502.1 500.8 496.2 491.7 485.4 479.4 476.8 475 472.5 468.4 461.7 457.3 452.2 445.2 435.4 421.1 384.9 358.5 341.6 330.4 320.5 311.1 299.4 282.3 274.3 269.8 266.6 264.4 262.3 260.3 258.9 257.3 256 255.6 255.6 254.8 253 248 243.6 239.8 236.9 234 230 225.4 222.2 218.4 213.7 208.7 203.9 196.9 192.9 185.2 180.7 169 150.1 153 157.6 157.2 155.8 154.3 149 138.7 126.1 113.4 104.7 93.6 79.9 73.2 67.3 65.7 61.4 58.3 55.3 52.8 50.1 47.1 47.6 48 49.9 54.1 58.3 66 63.9 64.4 69.9 77.3 88.5 105.7 +35.9 37.9 39.2 40.1 39.4 38.7 39.9 45.1 50.7 55.6 62.1 66.8 74.9 79.1 83.6 88.9 96.1 100.1 105.3 112.7 115.9 117.1 111.3 102 99.7 101.6 110.6 118.5 125.5 131 135.1 134.1 126 117.7 117.4 118.7 128.1 133.8 137.3 140 140.9 142.2 142.8 143 143.1 143.7 146.8 149.7 151.8 152.7 151.7 154.7 159.5 164.6 168.4 174 179.9 183.2 188 195.3 202.2 207.8 212.5 219.1 225.4 232.2 238.5 247.6 257.9 269 281.2 295.3 311.3 331.2 349.1 367.5 389.6 409.3 425.2 442.7 454.5 463.3 470 477.7 485.3 490.5 496.8 505.4 513.4 518.1 520.1 521 523.2 525.8 527.8 531.1 534.8 537.5 539.1 540.4 541.2 541.5 540.1 538.8 534.1 527.7 522.1 515.1 508.1 501.7 498.3 494.9 491.4 486.8 482.8 477.5 471.4 466 462.9 460.5 457.9 452.6 449.4 447.4 443.5 434.9 427.9 415.9 388.1 358.2 339 327.7 316.4 305.8 291.9 280.2 273.8 268.6 265.4 263.3 261.4 259.6 258.3 257.1 255.9 255 254.8 254.1 251.5 248.2 244.6 241.3 239 235.8 231.2 224.4 219.6 216.1 211.6 207.8 202.4 193.8 191.8 188.7 183.7 176.6 164.9 146.9 136.7 137.7 138.2 142 135.9 129.8 120.3 109.7 95.3 84 84.4 86.6 71.9 63.7 61.2 57.8 55.2 53.3 51.1 48.4 46.7 47.4 48.6 54.1 58.8 58.9 59.6 60.1 64.2 68.8 83.2 96.9 +36.3 37.2 38.2 38.6 37.9 37.3 41.6 46.5 52.2 57 63.4 72 77.8 82.2 86.9 92.4 98.6 103.7 111 116.2 118.9 120.4 117.9 108.5 102.7 99.1 102.9 115.4 123.9 130.6 133.5 131.2 121.3 117.6 117.7 120.2 124.2 131.3 135.2 138 140.1 140.6 140.6 140.7 140.9 143.9 146.6 148.8 150 148.6 151 154.6 161.2 167.5 172.2 177.6 181.8 185.9 190 195.3 203 207.7 213.1 219.3 226.1 233.6 242.9 252.7 261.9 271.6 282 298.1 314.8 333.5 351.6 372.2 393.4 409.5 425.8 440.7 452 460.8 468.6 475.8 482.9 488.8 497.6 508.8 516.4 521.4 523.5 524.7 526.6 528.2 529.8 532.5 535.5 537.9 539 540.2 541.7 541.7 542.1 540.6 534.2 526.8 519.9 512.5 504.7 496.4 490.2 485.1 479.5 474.1 468.8 462.8 457.3 451.4 449.5 447.6 444 440.9 439.5 437.2 432.6 424.7 418.2 405.6 380.4 355.6 336.7 323.9 312.5 300.4 288.5 279.5 273.2 267.8 264.3 262.6 261.4 260 258.7 257.4 256.2 254.8 252.9 253.3 251.7 249.2 246.3 243.6 240.7 237.3 233.1 226.4 221.9 219.8 215.2 209.7 204 199.3 194.5 188.4 183.1 178.3 170.9 160 150.3 143.2 135.8 122.7 117.3 114.4 104.8 99.9 105.5 104.5 103.1 95.5 82.9 66.6 58.8 56.4 53.8 52.1 49.1 46.6 45.4 46.7 47.7 50.5 53 53.1 55.4 56.6 58.7 62.5 85.5 90.7 +36 36.7 36.8 36.8 36.3 39.2 43.6 48.4 53.5 58.7 66.2 75.8 81.1 86.2 90.1 94.8 101.6 108.8 115 119 121.4 122.8 122.1 118.1 114 104.1 99.8 101.1 114.1 125.9 130.3 127.2 119.4 116.7 117.5 120.7 122.7 128.9 133.8 137.3 138.9 139 138.8 138.5 140.4 143.1 145.4 146.1 144.9 148.3 153 157.8 166 170.6 175.3 180.2 184.2 187.8 191.8 197.2 203.5 208.1 214.1 219.4 226.6 235.1 245 256.1 266.9 277.3 288.5 301.5 315.2 333.8 354.1 373.3 393.2 409.4 424.4 437.8 450.3 459.8 467.3 474.3 479.8 487.6 499.8 510.7 518.2 523.2 525.4 526.7 528.5 529.7 530.3 532.5 535.1 537.1 538.5 540 541.4 542.1 542.6 541.7 534.2 526.3 517 507.7 498.5 489.3 479.5 471.1 465.1 460.6 455 450.1 443.7 438.6 437 433.4 431 431.1 430.2 427.5 423.3 417 409.3 397.1 375 351.7 330.8 318.6 309.4 299.3 287.6 278.6 273.4 268 263.7 261.6 261.4 260.7 259.4 257.3 255.7 254.2 252 251 250.6 249.9 248.1 245.5 242.2 238.4 233.8 228.9 224.9 222.3 217.5 211.9 206.1 200.4 194.6 188.3 180.9 175.8 168.1 160 155.1 152.2 146.1 135 125 117.8 114.6 114.3 115.8 114 108.4 96.5 84.7 72.2 62.5 54.7 52.8 49.9 48 46.4 43 46.2 46.5 49.6 49 50.9 53.2 54.4 55.1 62.7 78.4 93.9 +35.5 36.2 35.8 34.7 35.4 39.7 44.8 50.1 55.4 61.5 70.9 81 84.8 90.4 94.4 99 107.3 112.4 117.1 120.9 123.2 124.3 123.6 120.6 119.3 114.6 106.8 99.9 102.7 118.2 125.3 123.7 116.9 116.2 117 120.1 122.9 126 132.4 136.3 137.3 136.7 136.3 137.6 139.7 142.1 142.3 141.3 143.9 149.2 155.4 160.9 168.6 173.1 177.8 181.6 185.7 189 193.1 198.6 204.1 209.3 215.6 220.5 226.8 236 247.4 258.9 270.4 282 293.7 308.9 324.3 340.3 359.1 373.2 391.3 404.4 420.8 434 448.2 458.4 465.8 472 478.4 488 501.4 511 518.7 524.3 525.9 527.2 528.5 529.2 530.1 531.7 533.8 535.1 537 539.3 540.8 540.7 539.3 537.5 531.7 524.7 515 503.8 490.1 479.6 465.6 455.9 449.4 443.5 442.6 438.4 431.4 425.3 421.3 419.1 420.1 421.3 422.3 418.9 414.8 408.1 400.5 386 358.9 341.6 325.4 312.7 306.3 300.4 285.3 277.1 272.7 266.3 261.8 260.1 259.8 259.7 258.2 256.5 254.6 252.5 250.5 247.7 249.2 248.7 248.2 246.6 243.8 239.3 235.1 231.4 227.1 223.2 218.5 213.1 207.2 201.4 194.4 187.9 179 171.5 163.4 158.9 154.9 153.6 150.3 142.3 131.8 125.8 121.4 120.1 123 123 112.5 99 87.6 75 65.5 59.1 56.7 54.6 50 46.7 44.8 45.4 46.1 47.9 48.5 48.5 49.2 50.8 53 62.4 79.7 93.5 +34.4 34.9 34.5 33.7 35.4 39.9 45.2 51.6 57.9 64.5 75.3 84.6 89.3 95.1 99.4 104.6 110 114.9 119.2 122.2 124.2 124.9 123.8 120.3 120.2 119.9 116.9 108.5 98 106.9 119.1 120.6 115.8 115.5 116 118.9 121.7 123.4 129.9 134.4 135.3 134.6 135.4 137.1 139.1 139.4 138.4 140.9 145.6 151.3 156.5 163.2 170.6 174.8 178.5 182.5 187 190.3 194.8 199.6 204.6 210.3 216.4 222.4 229.1 238.7 249.8 261.8 273.4 285.1 298.8 314.9 330.4 348.6 368.9 387.4 400.4 409.4 423.3 435.8 446 456.3 464.7 470.2 479.1 489.3 499.7 509.3 516.3 521.3 524.5 527.3 526.8 527.4 528.7 530.2 531.6 533 535.6 538.5 539.2 538.3 536.3 534.2 529 521.9 512 498.6 482.3 468.8 456.6 446.4 438.4 433 430.6 427.6 420 412.4 409.6 409.2 410.3 412.5 413.3 411.3 407.1 400 388.1 373.5 352.2 338.4 322 308.5 301.8 291.3 283.5 274.1 268.1 261.7 258.7 257.4 257.3 256.7 255.6 254.1 252 250 247.9 246.1 246.5 247 247.1 246.3 244.1 240.1 236.1 232.3 228.3 223.7 218.8 213.6 207.4 201.5 194.4 186.7 179.3 169.7 163 156.6 153.2 149.5 148.1 141.8 135.8 130.4 125.1 123.9 124.8 122.9 113.7 106 89 77.1 68.1 63.3 62.2 61.2 53.6 48.4 47.3 44.1 45.2 45.5 47.1 47.7 48.3 50.3 52.4 59.2 70.1 81.3 +33 33.2 32.3 33.3 35.1 39.6 45.2 53 59.5 67.2 79.9 87.4 93.8 99.2 103.8 107.3 112.6 117.6 121.4 123.5 124.7 124.5 121.8 121 120.5 122.5 124.1 116.7 99.4 97.2 113.9 118.9 114.8 115.2 115 117.6 119.7 121.5 127.7 132.6 133.2 133.1 135 136.9 137.7 135 137.8 141.8 148 152.1 158.5 165.3 171.5 174.8 179.3 184.1 187.8 192.4 197.1 201.6 206.6 212.3 217.7 221.7 227.5 241.7 253.3 264.6 276.8 288.7 302.6 322 339.4 357.9 377.5 392.7 402.7 416.3 427.4 438.8 447.6 456.3 463.7 469.5 480.5 488.7 497.3 506.8 515.2 520.8 524.1 526.3 524.2 524.4 525.6 527.4 529.5 531.3 533.7 535.6 536.2 535.9 533.4 530.2 525.5 517.5 506.5 487.9 472 461.3 449.9 438.7 430.7 424.3 421.4 417.4 407.3 400 399.7 400 401.2 402.7 405.5 404.1 399.7 394 380.7 364.3 348.3 333.3 320.4 307.1 295.4 286.1 279.8 270.9 264 258.8 255.4 253.8 253.4 253.4 252.5 251.2 249.3 247.3 245.1 243.5 242.5 243.9 244.5 244.7 243.3 240.2 236.4 233 228.7 223.9 218.6 212.9 207.2 201.1 193.9 186 178 169.3 162 155.6 151.5 146.9 142.7 137.8 133.4 129.9 127.8 128.4 128.6 122.3 115.2 107.2 89.6 79.8 70.5 65.3 64.4 62.1 57.1 48.6 46.8 43.3 44.8 44.9 45.1 46.5 48.3 50.7 53.1 57.7 68.2 81.9 +31 31.9 32.5 33 35.3 39.4 45.4 54.3 63.3 69.6 84.1 91.6 97.8 103.2 107.3 110.6 115 118.8 122.2 124.5 124.9 123.2 120.3 121.3 121.5 124.6 126.3 120 101 92.2 101.4 116.3 114.6 114.3 114.4 115.6 118.6 120.5 125.8 131.3 131.1 132.4 134.3 135.6 134.1 133.8 138.3 143.5 148.1 153.1 160 166.7 171.4 175.5 180 184.8 189 193.9 198.2 203.3 209.1 215.3 220.8 224.7 232.6 245.1 256.1 266.8 278.2 293.7 310.8 327.1 346 363.6 380.3 394.2 402.5 418.9 429.9 440.9 447.7 456.3 463.4 469.3 479.2 487.2 494.5 503.6 515.7 520.3 521.2 521.3 519.1 520 521.3 523.3 526 528.2 531.6 532.9 533.4 532.6 529.4 525.3 518.7 510.5 500.5 481.1 463.4 451.8 439.6 430 422.9 416 411.3 405.3 396.3 390 390.7 392.4 393.7 395.6 397.4 396.5 392.9 388.2 378 359.8 341.9 331.9 320.6 305.2 290.5 281.4 279.1 267.4 261.8 256.9 252.6 250.8 249.8 250 249.5 248.1 246.4 244.3 242 241.2 240.8 241 241.8 242 241.8 239.6 237 233.3 228.7 223.9 218.4 212.8 206.8 199.8 192.4 186.3 178 168.5 161.9 155.2 149.5 145.4 141.7 136.3 132.6 130.6 129.9 131.2 132.8 126.5 122.9 109.5 91.1 81.9 73 67 64.4 61.7 56.6 49 46.7 44.8 43.8 44 45.8 47.5 49.2 51.4 55.4 64.8 71.1 85.2 +29.7 30.7 31.1 32.4 36.1 40.4 46.5 55.4 64.9 72.7 88 95 100.6 105.7 109.3 112.7 116 119.7 123.3 125.3 124.7 121.7 120.8 120.3 122 125.3 125.6 118.8 102.8 92.1 92.9 112 115.9 114 114 114.5 116.8 119.6 124.6 129.5 128.9 131.6 132.6 133.4 131.1 133.6 139.8 144 148.2 155.2 161.1 167 170.7 175.7 180.8 185.8 190.1 195.2 200.2 206.2 214.1 220.9 226.4 228.9 237.8 247.3 258.1 269.4 281.7 298.3 318 334.6 351 364.1 376.4 394.2 404.4 421 429.6 440.8 448.3 454.9 464.3 470.5 477.2 485.9 493.1 501 512.1 515.7 515.7 513.8 513.1 513.8 515.6 518.1 521.3 524.9 528.9 529.9 529.8 528.1 525.6 518.7 511.9 504.6 491.7 473.7 455.1 442.7 430.5 421.3 413.3 408.2 402 395.1 387.6 381.4 383.3 385.5 386.6 388.2 389.7 390.1 388.2 383 372.7 357 341.5 331.4 320.5 302.7 286.4 275.1 271.4 262.5 259.6 255.2 251.4 248.5 247.3 247.2 247.2 246.1 244.4 241.7 240.3 239.5 239.1 239.3 239.3 239.6 239.8 238.7 236.8 233.2 228.7 224 218.6 212.9 206.2 199.3 192.6 186 178 168.1 159.5 153.9 150.8 146.4 141 136.8 134.6 134.3 131.2 131.6 130.1 127.8 127.6 113.5 95.5 85.2 75.2 68.2 63.9 60.4 53.9 48.7 47.4 44.8 42.8 45 46.6 47.3 48.3 53.2 59 67.7 75.2 86.1 +28.6 28.9 30.3 32.3 36.7 41.5 47.7 58.5 73 82.5 90.8 96.5 102.5 107.5 110.8 114.1 117.6 121.2 124.2 125.5 123.8 121.1 120.3 119.4 122.5 124.8 125 120 108 92.9 91.3 109 122.2 118.3 114.5 113.5 114.5 116.7 123.1 125 128.4 129.6 130.7 127.6 129.5 134.7 139.7 144.1 150 156 161 165.8 171.1 177.3 182.4 186.6 191.5 197.1 203.5 209.8 217.9 224.6 230.6 235.3 241.9 250.6 263.3 277.2 289.8 304.2 321.8 338.3 354.2 369.9 383.8 397.8 405.1 420.8 430.6 440.6 448.8 455.3 464.8 469.6 477.8 485.6 491 498.8 505.4 508.6 507.9 505.6 504.5 506.4 510.8 513.8 515.6 521 525.5 527.4 526.4 525 519.8 511.7 505.1 495.9 483 464.1 447.2 434.7 423.1 412.5 403.5 398.8 393.6 387.2 380.8 377.1 377.9 379.1 379.9 381.3 383.3 384.3 382.1 376.5 367.5 352.7 342.4 330.2 319.1 294.1 276.6 272.2 266.6 259.9 257.1 252.7 249 247 246 246.7 247.1 246.2 244 240.8 238.9 238.3 238.4 239.1 238.5 237.9 237.5 236.9 235.7 233.1 229 224.2 218.1 211.5 204.9 197.8 190.9 184.8 177.7 170.4 162.6 154.8 150.9 146.1 140.6 136.9 134.8 132.8 134.1 137 127.6 126.7 129.8 115.3 100.9 87.1 76.6 69.9 62.8 57.7 51.6 48 47 44.3 42.1 48.2 46.1 46.8 48.5 50.8 57.3 66.8 76.8 80.5 +29.9 29.2 30.2 32.9 37.2 42.2 48.8 59.6 73.6 83.6 92.9 100.3 105.8 108.7 111.7 115.3 118.8 122 124.2 124.1 122.5 120.4 119.1 118.8 121.7 124 124.3 122.7 110.6 94.6 91.3 102.1 119.5 123.6 118.5 114.3 113.8 115.7 119 123.8 126.7 127.6 126.3 122.8 130 136.6 140.3 145.3 151.6 156.9 161.3 167.2 173.8 180 184.4 189.3 194.5 200.2 207.3 213.8 222.7 226.9 233.3 239 246.6 254.6 269.2 281.8 295 308.8 324.2 341.2 356.4 372.1 386.7 396.4 408 419.2 429.8 439.3 447.6 457.4 464 468.5 477.6 483.9 487.8 493.8 498.4 498.8 497.3 496.9 495.6 499 503.5 506.6 509.4 516.3 521.7 523.3 522 519.3 514 505.6 498 487.9 474 455.5 440.8 429 417.6 407 397.7 391.3 387 381.3 377.1 372.1 372.3 373.2 374.3 375.9 377.9 378.8 376.2 370.4 360.3 350.1 340.1 327 316.1 293.7 273.2 269.9 262.3 256.5 254 250.3 246.6 245.2 245.2 246.5 247.5 246.6 244.8 241.1 238 237.3 238.5 239.4 239 237.8 236.4 235.5 234.2 231.9 228.6 223.6 218.6 213.5 206.7 199.1 195.2 187.2 180.5 173.4 166.7 157.8 149.5 144.1 136.5 133.9 131.7 130.8 131.6 130.9 124.9 123.9 123.2 112.1 104.4 91.1 79.1 72.6 63.3 56 50.8 47.7 44.8 42.6 44.8 47 44.9 45.8 47.5 47.5 55 64.3 61.4 65.3 +30.8 29.4 30.9 33.4 37.6 42.6 49.1 60.8 75.5 84.1 94 102.5 108 111.3 114.4 116.7 119.7 122.2 122.8 121.6 120.3 118.8 118.7 118 119.6 121.7 122.5 120.3 108.7 94.5 91.1 93.9 113.9 121.5 119.9 116.2 114 113.9 115.7 120.1 123.8 124.7 119.5 124.5 131.2 136.6 140.7 145.9 152.6 158.6 163.6 170.2 176.2 182.3 187 192.8 198.1 203.4 210.8 216.9 223.6 229.4 236 243.4 251.5 260.8 272.7 284 297.4 311.6 327 342.9 358.8 374.4 387.8 397.2 408.6 418.7 428.8 439.3 447.6 457.6 462.9 467.3 476 481 484.6 487.2 489.6 487.9 488.7 488.5 487.6 487.9 490.9 495 502.2 509.3 517.3 518.4 516 513.7 507.6 499 491.3 478.6 465.2 449.8 437 423.4 413.6 404.7 395.2 386.8 381.6 377.6 373.4 370.3 366.9 368 369.2 370.8 372.2 372.7 369.7 364.2 356.7 347.8 338.4 325.3 307.7 290.9 271.6 263.2 257.1 254.5 251.4 247.3 244.4 243.3 244 246.8 247.7 247.1 245.5 242 237.4 236.5 238.2 239.4 239.4 238.2 236.5 234.7 233.8 232.2 230.1 227 222.2 216.2 209.5 202 195.2 188.7 181.9 174.8 166.7 158.6 149.4 141.6 135.7 132.4 129.6 128.3 128.3 126.6 123.1 120.4 117.5 111.7 109.3 94.2 81.4 73.8 65.3 57.8 51.8 48.8 45.5 43.3 44.2 44.7 44.3 44.1 45.1 45.1 47.9 47.2 48.8 55.3 +31.7 31.4 32.4 34.7 38.1 42.5 49.1 59.8 75 84 94.6 103.1 109.6 114 116.2 118 120.2 121.4 120.1 118.7 117.9 117.6 118.1 117.3 118.1 118.9 119.3 119.4 107.7 94 91.1 92 107.8 119.2 118.8 117.6 114.6 113.1 113.3 115 118.9 118.4 120.4 125.1 131.4 137.6 142.2 148.2 154.8 160.7 166 172.9 179.2 184.9 190 195.8 200.6 206.4 212.7 218.2 224.5 231.2 239.3 247.4 255.2 266.4 276.8 286.8 298.5 312.8 327.5 344.2 358.1 375.3 388.1 396.8 410.8 419.5 427.5 437.3 446.1 456.1 461.7 466.4 472.8 476.6 478.5 479.4 479 479.5 480.8 480.8 480.9 482.2 484.9 485.3 493.7 502.8 508.5 510.5 510.1 506.4 501 492.2 480.9 470.8 455.9 445.2 435 422.9 413.5 404.3 393.7 382.9 376.9 373.2 370.3 367.4 363.8 363.3 364 365.4 366.5 365.6 363.2 359.5 353.6 346.7 336.9 326.2 309.7 290.1 273.6 259.7 254.2 251.4 249.2 245.3 242.5 241.3 241.9 244.3 245.5 245.6 244.9 240.4 236.2 235.6 237.9 238.9 239.1 238.4 237.3 236.2 235.4 234.1 232.3 229.1 225 219.1 211.6 203.6 197.1 189.4 182.2 175.1 168 159.6 151 143 139.6 136 129.5 126.4 124.8 123.9 121.3 116.8 114.2 110.1 104.9 93.7 84.2 75.8 68.1 60.8 55 50.8 46 41.6 43.3 43.3 43.2 42 41.8 42.9 43.9 44.5 45.6 50.7 +33.1 32.8 34.2 36.9 39.6 42.7 49.7 59.8 73.5 83.1 93.5 103.3 110.3 114.4 116.6 118.3 119.6 119.8 117.8 116.4 116.1 115.9 116.2 116 116.8 118.4 118.1 117.5 106 94.2 90.6 92.1 103.7 115.7 117.2 118.2 116.8 112.1 112.6 114 114.4 114.7 119.9 125.3 132.3 137.9 144 150.8 156.9 162.8 169.3 176.4 182 187 192.1 197.2 202.8 208.3 214.3 220 226.5 234.4 242.6 252 261.3 270.8 279.9 289.1 300.2 313 327.7 343.4 357.7 373.7 386.4 394.1 411.5 418.9 427.2 435.7 444.8 452.2 460.1 465.3 468.8 471.2 471.9 471.3 471 470.6 473.1 474.1 474.7 476.5 477.1 477.7 486.3 495.9 500.9 503.1 502 498.9 492.9 483 475.5 465 451.9 442.4 432.4 423.1 414.6 405.1 394.8 382 374.1 370.8 368.4 365 361.6 360.2 360.4 360.7 360.2 359.2 356.9 354.3 350.5 343.7 334.4 324.1 305.7 286.9 271.4 258.5 252.3 249.4 248.1 244.4 241.4 239.4 238.9 238.4 238.5 240.1 241.7 237.9 232.7 234.3 237 238.7 239.1 239 238.4 237.9 237 235.8 234.1 231 227.2 221.1 213 205.1 197.9 190.7 183.6 175.8 169.3 161.3 153.5 146 144.2 143.1 131.7 126.4 123.3 120.7 117.9 114.9 112.1 109.1 104.3 96.9 89.1 80.4 72.5 65.1 58.7 53.9 48 43.3 41.8 42.2 41.8 40.8 41.6 39.1 38.9 41.2 43.9 45.3 +33.3 33.6 35.8 37.7 40.2 44.2 51.4 59 71.4 83.1 93.8 103.2 109.3 113.2 115 116.7 117.7 117.8 115.1 112.9 112.3 112.1 113.1 113.8 114.9 118.3 120 117.6 106.4 94.5 91.3 92.1 105.3 114.6 116.9 117.3 116.1 112.4 110.7 112 112.1 114.8 119.8 125.9 132.2 138 146.9 153.9 160.1 166.1 173 178.2 183.8 188.6 193.4 198.1 204.2 210.1 216 222.1 229.9 239.3 246.5 254.7 263.8 272 280.2 289.4 300 312.7 325.1 340.9 357 370.9 384.9 394.6 409.3 416.9 425.9 434.4 442.3 449.5 456.6 461.6 463.9 464.4 464.8 464.7 464.2 464.7 466.7 468.2 468.4 470.6 472.2 472.8 479.4 490.2 495.4 496 494.3 491.1 486.6 479.1 471.3 460.9 450.5 440.4 431.9 421.2 413.3 405.6 396.2 383.7 374.4 371.3 367.8 364.1 359.9 357.2 356.9 357.2 356.2 352.3 349.4 348.8 345.3 338.5 327.8 310.9 294.5 285.5 267.2 259.7 257.2 255.1 252 245.2 242.3 240 237.3 235.9 235.8 236.2 237.4 234.7 231.9 233.7 236.1 238.6 240 240.2 239.9 239.4 238.8 237.6 235.6 232.5 229 222.5 213.7 206.7 199.6 191.9 183.9 175.1 169 162.9 155.5 146.4 143.1 139.3 134.1 128.8 125.1 122 119 118.6 116.6 114.2 110.9 103.8 95 85.8 77.7 70.3 64 57.8 50.6 44.8 42.2 41.5 41.2 40.3 47.1 42.1 41.1 39 40.8 43.7 +33.4 34.3 36.2 38.3 40 44.4 51.8 58.6 70.1 83 94.7 102.3 107.7 111.2 112.2 114.3 115.2 114.5 111.2 107.1 107 108.6 111.1 111.5 111.7 112.4 114.8 115.5 110.5 95.5 91.7 92.9 104.3 114.8 116 115.3 114.5 114.1 108.1 109.8 111.3 116.9 121.4 126.5 132.5 141.5 150.6 156.3 162.9 169.9 175 179.8 185 189.5 194.1 199.1 205.1 211.3 217.4 225 235.3 242.9 248.1 256.4 264.7 273.1 281.5 290.2 300.4 312.6 325.4 339.8 354.4 369 381.4 393 407.4 414.3 424.1 431.9 438.2 447.1 452.8 455.2 456.9 456.8 457.7 457.6 457.9 459.1 461.5 462.4 464.1 467 468.4 470.1 475.8 483.2 487.3 488.3 487.3 486.2 482.2 477 469.6 459.5 449.6 439.2 431.7 418.8 410.6 404.3 395 384.8 376.7 372.7 368.6 364.6 360.6 356.8 355.3 354.9 353.9 353.5 349 343.1 341.4 337.9 331.9 321.6 309.1 295.8 281 268.5 263.2 261 257 247.5 242.6 239.5 237 234.8 234.2 234.9 235.5 232.7 231.2 233.6 236.4 239 240.8 241.4 241.3 240.7 240 239 236.9 234 229.5 221.9 214.4 207.5 200.8 192.3 183.6 173.3 167.2 160.7 154.7 149.2 144.6 139.2 133.9 131.2 130.3 124.8 122.4 124.2 125 124.3 120.1 110.2 101.2 92.2 84.1 76.9 69.8 62.2 54.1 47.9 43.3 41.9 41.5 48.4 44.5 42.6 42.4 41.2 37.5 41.8 +33.7 34.8 36.5 38.4 40 42.9 50.9 58 69.7 82.7 93.3 101.1 104.9 107.3 108.3 110.8 111.7 111.4 109 104.6 105.1 106 109.1 110.6 110.2 109.9 111.2 112.1 111 97.1 91.3 93.3 97.8 106.5 111.7 113.3 114.2 113.5 106.7 109.2 110.9 119.7 124.1 129.6 137.5 147.2 152.8 158 166.2 171.7 176.4 181.2 185.7 190 194.4 199.7 205.7 211.9 218.4 228 237.8 243.4 249.7 258.1 266.1 274.6 282.6 292.4 301.1 312.5 324.9 338.4 353.2 366.3 380.5 391.6 403.7 412.8 421.7 429.1 435.4 444.5 448.5 449.7 449.8 449.9 449.7 450.5 451.9 452.5 453.6 456.7 460.2 463.4 465.3 468.2 472 476.7 481.8 483 483.3 482.2 479.1 475.4 470.2 461.6 450 440 431.3 420.2 412.7 405.7 392.4 383.5 376.7 372.6 366.6 363.8 359.5 357.5 356.4 355.1 354.4 355.3 353.9 350.3 348.2 345 341.1 333.3 322.1 304.9 288.7 274.9 268.1 265.5 261.8 251.9 243.6 238.9 236.1 234.7 233 231.9 232.2 230.9 231.8 234.4 236.8 239.1 240.9 242.1 242.5 242.1 241.3 240.3 238.3 235.7 230.6 221.7 216.6 209.7 201.7 193.2 181.9 170.6 164.8 159.4 156.9 151.3 146.9 141.9 135.3 135.2 134.1 128.5 128 132.2 134.8 132.4 125.4 117.8 108.6 100.1 91.1 82.9 75.5 66.9 58.1 51.4 45.8 42.6 41.9 42.8 43 42.7 41.9 40.7 38.9 36.8 +33.8 35.1 37.3 38.7 40.3 43.4 49.7 56.2 67.9 80.9 89.3 97.4 101.4 103 104.7 107.2 107.7 107.5 104.9 103.2 103.7 105.7 108.1 110.2 110.5 109.3 108.4 108.5 106.5 95.3 91.4 94 95.6 98.1 99.1 109.9 113 109 105.9 109 112.7 122.5 127.6 133.9 143.3 148.7 153.8 160.2 167.3 172.4 176.5 180.8 185.4 189.8 194.7 200.2 206.6 212.7 219.6 229.9 238.2 244.4 251.8 259.1 267.1 275.1 283.7 293.9 302.6 312.8 325.1 339.4 352.4 366.9 379 388.5 403.1 412.1 420.2 425.8 431.8 438.4 442.4 442.4 442.5 442.4 442.4 443.7 445.7 446.3 449.8 454.7 457.6 461.1 463.4 465.7 469.1 472.6 475.9 478.1 480 479.1 477.2 473.8 468.3 459.5 451.7 441.3 432 422.1 413.5 404.2 390.5 382.3 376.7 373.5 370.6 365.1 363.2 360.9 359.2 356.9 356.7 358.5 357.5 354 352.1 349.9 346.5 339.4 330.5 313.4 294.5 281.3 272.2 268.2 263.8 254.6 246.1 240.4 235.8 234.1 233.1 231.8 230.2 229.2 233.9 234.7 235.7 238.5 240.8 242.1 242.8 242.9 242.2 241.4 238.1 235.2 231.6 221.7 219.6 212.4 201.1 190.3 180.6 170.5 163.4 159 157.6 153.1 148.1 144 138.7 139.8 137.8 133.7 135.6 141.3 143.7 143.7 130.1 124.1 114.8 105.2 96.5 88.7 81.3 72 62.2 54.5 47.3 43.1 42.5 42.3 43.3 43.1 42.6 42.7 42.2 39.3 +33.3 34.7 37.4 38.7 40.5 42.8 47.8 53.8 64.3 77.8 86.6 93.3 96.9 99 101.4 103.2 103.3 102.9 102.3 101 103.3 105.1 107.4 110 111 109.3 104.1 100.5 99.1 91.8 91.2 99.7 111.8 112.5 107 101.7 101.7 104.1 106.1 109.1 114.6 123.9 130.2 139 144.4 149.7 154.8 161.4 166.9 171.9 176.1 180.3 184.9 189.8 195 201.6 207.6 214.3 221.5 230.8 238.4 245.5 252.8 259.6 266.7 275.1 283.7 294.7 303.8 314.6 325.7 338.2 352.6 365.4 379.2 390.3 403.5 411.3 418.7 422 427.3 432.7 434.7 433.9 434 431.7 428.2 436.2 440.1 445.8 451.1 456 457.8 462 463.8 464.9 467.1 470.6 472.9 474.6 476.6 476.9 475.3 472.1 467.1 458.6 452 440.5 429.8 421.4 409.5 397.2 392.4 386.9 381.6 378.1 374.5 369.4 369.9 369.2 370.4 368.8 360.5 361 361.5 359 357.2 354.9 351 343.2 332.2 319.3 300.5 286.8 278.2 272 264.7 257.2 249.3 244.2 237.6 235.1 233.8 232.8 231.3 226 233.7 233.5 234.1 237.3 240.1 241.9 243 243.3 241.9 241.1 237.5 233.8 229.2 221.2 222.5 216.8 199.3 185.9 176.9 170 164.2 161.2 157.9 153.5 151 145.9 144 144.2 141.4 138.9 142.5 149.9 150.9 145 137.5 126.9 116.1 107.3 100 92.8 85.4 77.1 67 58 48.4 45.1 42.2 43.7 44.9 44.1 43 43.3 44.8 40.2 +32.1 35.1 36.8 37.9 38.5 40.3 44.3 50.5 56 71.8 82.3 88.3 92.3 95.5 97.6 99.1 99.4 100.7 99.2 101.3 103 104.6 108 110.4 111.6 109.7 102.7 98.3 91.9 89.2 91.4 106.5 113.2 114.5 116.6 111.9 106.9 106.1 105.4 108.4 118.3 123.9 132.7 140.2 145.2 150 153.9 161.2 166.4 170.8 175.2 179.6 184.8 190.3 195.6 202.4 208 214.9 224.3 232.6 239.1 245.7 252.9 259.5 266.9 274.2 283.6 295.1 304.9 316.2 327.2 340 352.3 368.1 380.6 391.9 402.5 409.4 414.6 417.4 421.1 425 424.5 424.8 421.1 429.1 435.2 439.4 443.1 446.9 452.6 457.6 461.2 464.3 467 468.4 469.1 471.2 472.4 474.5 476.4 477 474.7 472.2 468 459.5 452.5 441.5 432.4 421.6 412.5 405.4 397.6 391.9 386.3 384.3 381.2 376.2 377.4 381.1 382.8 381.5 372.2 363.7 367.2 366.3 364.4 361.3 354.6 346 335 322 304.3 293.8 284.4 278.8 267.2 259.2 250.4 245.5 240.3 238.3 237.1 236.4 234.3 226.8 219.9 230.2 231.8 235 238.4 240.6 242.3 243.3 240.5 238.6 237.7 230.2 222.2 219 222.2 218 197.6 183.3 174.2 169.7 166 164.3 161.4 155.5 152.1 149.5 150.2 149.2 146.4 143.2 147 152.3 150.1 148.6 139.4 128 117 108.4 102.8 96.7 89.4 81.3 72.6 68.7 50.8 45.2 43.6 47.2 51.3 51 47.9 43.4 42.2 39.1 +31.6 33.3 35.4 36.5 37.3 38 40.5 45.3 47.8 61.3 76.2 83.2 87.7 90.8 92.9 94.9 97.2 97.5 97 100.4 102.3 104.2 108.8 111.4 112.5 110.5 104.2 97.1 89.6 88 94.9 109 112.5 112.7 112.8 114.1 114.2 115.8 106.7 113.9 122.4 128.3 137.3 142 146.5 150 154.3 160.8 165.7 169.8 174.3 179.1 185.3 190.6 196.6 202.8 208.8 216.2 225.8 232.5 238.6 245.8 253 259.3 266.1 273.5 283.4 295.7 307 317.7 329.1 341.6 355.9 371.8 383.2 392.5 402.8 406.6 409.1 412.5 413.2 414.2 406.5 417 426 432.6 438.1 441.8 445.1 451.1 456 459.3 463.2 468.3 468.4 468.8 471.9 473 474.2 476.1 476.9 477.6 476.1 474 471.2 464.4 453.6 444 437.8 430.1 419.6 410.6 402.1 396.3 390.2 388.7 387.4 386.3 385.7 390.2 392.2 391.6 385 379.9 377.3 375.5 372 367.2 358.9 350.3 339.3 325.8 311.6 299.8 289.4 283 269.3 261.1 252.1 247.2 243.8 241.9 240.3 238.1 235.6 231.7 215.9 224.5 228.9 232.6 236 239.4 241.4 242.7 242.3 238.3 233 223.3 216.7 213.3 210.7 202.1 191.7 183.4 176 171 167.8 166 163.1 157.5 153.7 154.2 154.5 152.8 150.8 147.5 149.8 150.5 147.3 147.5 145.6 128.7 118 110.7 105.9 100.8 94.2 87.2 78.9 68.4 55.1 47.3 45 47.3 52.2 54 50.4 44.6 40.3 37.5 +35.4 36.8 37 37.6 38.4 39 39.7 41.2 43.4 48.8 64 74.8 82.3 86.3 89.3 92.2 94.9 95.6 94.9 98.3 101.6 105 109.1 111.8 112.4 109.5 104.1 91.9 87 88.4 102.3 111.5 114.5 113.9 112.5 112.1 111.8 109.4 108.3 118.4 125.1 133.9 141.1 144.7 147.1 149.6 154.5 160.1 165.1 168.6 173.1 180.6 185.7 191.3 197.3 203.8 209.8 217.8 225.8 231.6 238.1 245.5 252.2 258.7 265.5 273.7 284.4 296.2 307.3 318.4 330 346 361.2 373.9 384.4 392.6 399.4 399.9 402.1 402.4 403.1 400 412.2 420.5 427.8 434.3 439.2 444.3 449.5 454.7 460.7 463.4 469.8 471.8 473.6 473.9 474.6 474.2 476 477.3 478.1 479.2 478.5 477.2 473 468.6 461.3 452.1 443.2 435.8 425.8 416 412.7 406.5 395.5 397.5 395 395.7 394.9 397.8 402.9 402.8 396.9 392.3 387.8 383.1 378.9 372.8 365.7 357.6 345.5 333 317.2 304.9 293.9 284 272.1 261.8 254.1 249.9 246.6 244.7 243.4 240.4 236.2 231.7 216.3 217.6 225.7 229.9 233.8 237.7 239.7 242 243.1 241.6 232.3 221.2 212.7 207.9 203.8 196.3 185.8 181.9 177.5 172 168.4 165.8 164.2 158.5 157.7 158.4 157.7 155.6 153.8 150.9 151.8 150.4 146.6 144.2 140.8 131.7 118.9 112.6 108.4 104.3 98.9 93.2 85.3 71.8 61 52 47 47.8 52.7 54 49.5 43.6 39.6 36.7 +37.7 39.1 39.9 40.7 40.9 40.8 40.9 41.1 43.2 46.1 53.8 69.9 79.3 84.8 88 91 93.3 94 93.6 98.9 102.1 105.7 109.3 111.6 111.1 108.3 99.5 86.9 90.7 95.7 105.8 111.9 114.4 114.3 114 112.8 110.1 108.5 110.8 120.6 128.7 136.3 141 143.3 144.6 148.8 154.1 159.2 163.7 167.7 174.4 181.5 186.2 191.3 197.3 203.4 209.4 218 225.6 231.5 238.1 245.3 251.6 258.1 267.3 276.2 285.8 296.2 307.5 319.1 331.2 348.7 365.6 375.7 384.5 391 395.1 394.1 392.6 391.2 390.1 405.9 413.4 420.7 426.8 432.5 439.4 445.4 451.5 462.3 468.7 473.2 476.8 477.7 478.2 477 477.3 476.6 477.4 479.3 480.9 482.6 483.6 487.4 480.4 474.1 467.3 458.1 448 440.6 433.1 424.5 420.9 414.8 405.8 405.9 405.6 407.1 405.1 406 411.3 413.2 409.7 404.6 397.2 390.5 387.6 382.8 374.9 366.7 355.4 341.6 320.6 308.9 296.8 287 276.5 263.6 257.3 252.8 250.2 247.5 244.5 240.5 234.9 229.7 222.8 211.8 213.2 226.9 231.3 235.1 237.8 241.2 243.1 243.2 234.1 219.2 209 203.9 200 192.6 183.7 179.7 176 170.9 168.1 165.7 164.8 162.7 161.6 161.4 160 157.4 155.5 153.4 152.7 155.3 155 140.9 137.5 131.1 119.7 113.9 110.4 106.6 102.6 98.6 89.6 73.2 65.7 57.2 50.4 48.9 60.2 52.5 45.9 42.6 38.9 35.4 +40.1 41.6 42.7 43.3 43.5 44.3 45 47 51.5 46.8 49.8 66.2 78.1 83.5 86.4 88.7 90.2 89.3 94.9 99.6 102.2 105.9 109.3 110.5 109.4 107.3 94.4 86.6 96.1 100.2 108.3 108.5 111.6 113 113.3 111.7 109.4 110.2 112.3 121 128.8 135.3 139.5 141.1 144.3 149.5 153.9 158.9 163.3 169.2 176.2 181.4 186.8 192.3 197.9 203.8 210.1 218.8 225.5 231.5 238.1 245 251.8 258.6 268.7 277.4 285.7 295.5 307.3 319 331.4 351 366.6 377.3 384.8 388.9 384.5 384.5 384.5 386.7 400.6 407 413.7 419.4 425.2 431 439.4 449.7 461.4 470.3 476 479.1 481.7 481.4 480.7 479.1 479.4 479.4 480.6 482.7 484.8 488.8 490.3 491.9 486.6 479.8 472.7 463.9 453.5 445.2 438.6 431.9 426.6 421.2 414 411 414.2 415.1 415.2 415.9 417.6 420.2 417.7 413.9 406.3 402.6 396.1 391.1 382.1 372.5 357.8 340.5 321.7 310.1 297.9 290.2 278.7 266.2 260.3 255.7 253.9 250.4 246.1 240.6 233.7 227.9 221.4 211.5 214.1 223.5 228.4 232.6 235.2 237.7 239 236.6 235.9 213.8 203.8 201.2 199.1 190.7 182 177.9 174.3 169.7 167.1 166.2 166.1 165.2 164.6 163.1 161.2 159.5 158.2 156.2 154 155.4 156 146.1 133.8 128 118.6 116.3 112.8 108.9 104.5 100.9 99.8 79.8 69.5 61.7 54.5 50.3 56.6 56.9 44.5 41.4 38.3 35.1 +42 44 44.8 45.8 47.4 49.1 50.6 52 54.9 50.7 50.2 61.1 73 80 83 84.8 86.3 92.4 96.4 100.1 102.5 105.8 108.2 109.7 109.5 105.6 90.9 86.6 96.6 100.9 110.6 111.7 110.9 110.7 109.9 109.1 109.5 110.8 113.7 120.3 127.4 134.6 138.3 142.1 146.5 150.4 155.2 159.2 163.6 169.6 176.1 181.7 187.2 193 198.7 205.4 211.9 219.6 226 231.7 238.2 245.3 252 259.4 270 279 286.5 294.1 307.1 319 331.6 351.3 366.2 377.1 383.3 384.7 377.9 373.1 379.2 393.8 401 407.1 413 419 425.2 433.7 443.4 457.7 467.9 476.5 481.1 483.1 485.5 485.4 484.3 483.3 483.4 484.2 483.9 486.2 489.3 494.1 496.7 498.2 494 485.6 477.8 469.2 459.6 451.2 442.6 435.5 429.6 425.1 420.9 417.4 420.2 420.3 422.2 422.4 423.4 427.1 427.9 424.6 417.8 410.6 404.3 399.9 387.3 373.5 354.7 334.6 321.4 309.1 298.8 289.5 278.4 268 261.1 257.5 256 252.5 248.2 241.6 234 226.6 219.1 207.6 213.9 219.9 224.7 230.1 232 232.7 231.7 233.2 230.8 209.1 201.1 199.1 195.7 186.8 179.4 175.6 172.1 169.3 167.6 167.5 167.3 167 166 164.1 163 162.4 161.6 157.9 154.6 153.6 152 147 133.3 126.1 121.7 121.3 118.2 113.3 104.8 103.6 97 84.4 74 66.4 59.5 50.8 45.4 46.9 45.2 39.6 37.2 34.5 +42 43.8 46.5 48.5 49.9 51.2 52.9 54.5 55.3 52.5 51.2 58.5 69.2 76.4 79.8 84.5 90.2 94.1 97.3 100.7 102.3 105.6 108 110.5 110.7 105.1 88.9 90.4 97.7 102.1 110.1 112.4 112.4 112.2 110.8 108.7 109.2 110.3 112.7 119.2 128.8 134.7 137.9 143.4 147.2 151.2 155.3 159.2 164.2 169.7 175.7 181.5 187 193.4 199.9 206.4 212.7 220.1 226.2 231.9 239 246.7 252.4 260.5 270.8 279.2 287.1 295.4 308.1 319 332.9 350.7 364.8 374.1 379.6 377.1 368 376.4 386 392.9 399.9 406.6 412.6 420 427.9 437.9 447.3 461 473 483.4 487.9 488.9 490.2 491.7 491.3 489.6 488.4 489.5 488.9 490.3 493.7 497.4 501.1 504.7 504.9 493.3 484.3 474.5 464.8 456.9 447.9 440 433.4 429.7 427.3 426.2 425.1 426.3 428 428.4 431.1 434.4 436.3 435.2 431.2 426.6 414.6 399.8 388 370.2 350.4 333.3 320.3 308.7 298 287.7 277.9 268.3 260.8 257.5 255.7 252.8 247.9 241.4 234.5 225.3 217.5 204 207.9 215.9 221.7 226.5 228.1 226.2 224.8 226.4 219.9 205 199.8 198.9 193.9 185.4 179.1 174.6 171.5 169.5 169.2 169 168.7 168.1 167.1 165.8 165.3 164.8 163.9 160.3 156 153.7 151.4 149.5 138.3 129.5 128.1 125.4 122.4 115.1 107.2 101.1 96.5 88.4 78.2 74.3 65.8 52.7 44 40.4 38.7 37.3 35.5 32.9 +40.5 42.3 45.9 48.9 50.8 52 53.2 53.5 53.8 49.5 48 62.1 71.4 76.7 80.6 86.2 90.9 94.5 97.9 100.1 102.2 106.9 109.3 110.9 110.3 104 89.4 87.6 98.3 102 109.6 111.5 112.3 112 110.1 108.6 109.2 110.3 112.4 119.7 126.2 132.1 139.3 144 148.2 152.3 156.2 160 164.1 169.7 176 181 188 193.9 200.2 206.7 213.4 220 226.2 232.5 239.6 246.6 253.2 261 270.8 279.4 288.3 297.5 308.6 319.9 332.1 349.1 362.1 369.3 372.5 367.5 358 377.2 384.6 391.5 398.3 406.7 415.2 423 431.7 439.2 450.7 464.9 479.7 492.8 496.5 497.7 498 499.3 499.5 498.3 495.6 495.5 494.4 493.4 495.8 502.1 505.9 513.2 511.2 503.3 488.1 477.8 469.3 461.6 453.8 447.4 439.6 436.2 433.6 432.1 430.2 429.5 431.6 433.5 435.6 439.6 442.4 443.9 440.9 433.8 421.6 402.9 386.1 367.7 349.6 335.8 322.5 309.8 298.3 288.1 278.7 268.5 260.8 257.9 254.2 251 246.8 240.8 233.6 224.3 216.3 204.9 202.6 211.2 218.5 222.1 223.8 221.8 221.4 219.5 209.8 203.6 199.5 198.7 192.9 185.8 180.4 176.1 172.9 170.9 170.3 170.1 169.5 168.9 168.2 167.5 167 166.6 165.8 163.8 159.5 155.5 152.4 150.7 142.7 137.8 133.4 128.9 126.4 119.9 109.6 102.9 98.4 93.8 88 75.4 73.2 52.7 42.4 38.1 36.3 33.9 33.2 31.6 +40.6 42.8 46.3 48.5 50.1 51.3 51.1 50.9 50.5 46.1 45.6 61 68.9 75.5 80 84.9 89 92.8 95.6 97 99.3 106.6 108.4 109 109.2 104.4 89.5 85.7 96.9 100.9 107.6 109.8 110.8 111.3 110.8 110 108.8 109.9 112.4 120.9 125.7 132.5 139.3 144.1 149 152.6 156.6 160.2 164.4 171.5 177.1 181.9 188.9 194.6 200.4 207.5 213.6 220 226.2 232.2 238.9 245.7 253 261.6 271.4 280.1 291.1 299.7 309.1 320.5 332 346.9 358.2 365.4 363.8 355.8 364.1 374 381.5 388.9 397.8 406.9 417.4 424.6 431.3 439.5 455.6 471.6 486.7 500.2 503.7 505.4 507.1 507.4 506.6 504.7 502.9 500.7 499 496.7 498.9 506.5 510.7 516.8 520.7 514.1 493.9 480.8 472.8 465 458.1 452.1 446.3 441.2 438.3 435.2 433.6 432.7 432.3 435.3 438.9 442.3 445.7 446.5 443.2 435.3 420.9 402.9 385.5 368.8 352.2 337.8 324 311.5 298.9 288.4 278.7 268.3 261.9 259.5 255.5 251.3 245.4 239.2 232.4 223.1 215.1 205.4 194.3 206.9 213.5 216.6 218.1 216.9 217.1 216.1 206.6 202.1 198.3 196.7 194.1 188.1 182.6 177.2 174.4 172.3 171.5 170.7 170 169.5 169.1 169 168.9 168.7 167.9 166.2 162.6 159.2 158.9 151.9 146.7 144.6 136.3 135.3 134.8 124.9 112.5 105.6 99.8 96 92.2 73.9 76.1 53.8 42.7 37.5 33.4 30.4 32.5 36.6 +41.9 44.1 46.2 48.3 49.1 48.7 48.5 48 45.4 42.9 45.3 56.2 67.2 75.3 80.5 84 86.9 90.3 92.1 93.7 96.6 102.3 106 105.4 107.2 104.4 89.7 84.7 94.6 101.2 105.2 108 110.1 111.5 113.5 114.8 110.9 109.2 113.2 120.4 126.4 132.7 138.3 143.9 148.6 152.6 156.7 160.4 165.4 171.9 177.9 183.3 189.4 194.9 201.7 208.6 214.3 220.3 225.5 231.7 238 244.8 252.8 262.3 271.7 280.4 290.7 300.8 309.4 319.7 331.7 343.6 350.8 357.1 354.9 347.9 362.9 370.2 377.6 386.6 396.6 406.7 417.3 423.3 430.2 440.7 458.9 478.1 493.7 501.1 509.9 512.5 514 513.1 511.8 510.2 508.3 506 503.7 501.3 505.1 509.7 516.7 520.6 531.6 519 501.1 484.3 475.5 468.1 461.1 454.8 450.3 444.6 441.1 437.7 435.5 434.4 433.9 436.5 439.9 443.1 446.8 447.3 441.7 432.5 416.8 401.2 385 370.9 357.6 343.1 329.1 313.6 299.5 287.4 276.9 267.1 260.7 257.9 255.5 251.4 245.7 239.6 231.6 222.7 215.5 207.7 195 199.9 207.8 210.4 211.6 209.9 211.1 210.6 202.5 198.3 196.4 196.2 191.4 187.9 181.8 176.6 174.6 173.1 172 171 170.4 170.1 169.8 169.8 169.6 169.7 169.8 169.3 168.5 164.6 162.2 154.7 149.9 147 141.3 140.7 139.1 127.1 118.8 111.2 100.7 96.2 91.3 71.3 73.8 56.8 43.8 35.3 30.9 32.8 33.7 37.3 +42.3 44.3 46.1 47.5 47 46.4 45.7 45.4 42.4 41.5 44.6 55.5 65.7 74.4 80.3 83 85.2 87.7 89.4 91.1 93.6 96 100.2 101.9 105 103.1 89.2 84 97.4 101.9 107 110 111.6 113.3 115.3 115.7 111.6 108.2 112 120.2 127.7 132.8 137.8 143 147.8 152.7 156.8 160.8 167 172.3 178.4 183.3 189.6 195.2 202.2 208.4 214.7 218.9 224.9 230.9 237.1 244.6 252.9 262.4 271.1 279.7 289.2 300.5 309.4 320.6 329.7 339 345 346 336.1 349.3 359.1 365.6 370.3 382.1 391.9 404 413.6 421.2 428.6 442.4 460.8 483.8 494.1 500 513.1 516.2 518.2 519.3 516.7 513.9 511.7 510.2 509.1 508.8 512.2 516.1 520.9 528.3 536.6 523.7 505.5 488.5 479.7 469.3 462 455.6 451 446.5 443.1 439.5 435.8 433.8 433.2 436.1 438.7 441.5 444.9 444.2 437 427.6 416 398.7 383.9 371.2 358.3 346.9 331 315.2 301 289.3 278.5 267.8 261.9 257.1 254.6 249.4 244.7 238.5 230.6 223.2 216.3 206.2 197.9 187.6 199.4 204.6 205.7 205.4 205.2 203.2 196.1 193.7 194 192 188.3 185.6 180 176.5 175.3 173.6 172.2 171.2 170.6 170.4 170.3 170.4 170.8 171.2 171.5 172.3 172.7 173.9 169.2 159.7 152.2 148.3 145.9 145.2 142.9 134.6 125.5 112.4 101.3 95.4 87.7 68 64.9 54.3 42.6 34.3 31.1 32.5 34.2 36.4 +41.8 43.5 44.5 45.3 44.9 44.4 43.6 42.7 41 41.3 45.1 52.6 62.1 72.9 78.8 81.3 82.8 85.1 86.9 89.8 91.9 94 97 99.3 100 98.3 87.8 83.7 96.8 101.5 107.3 109.8 111.9 113.8 115.7 115.4 111.1 108.1 109.6 120.9 126.8 131.5 137.2 142.3 147.4 152.7 157 162 167.4 172.5 178.1 183.7 190.1 195.2 201.4 207.8 213 216.7 223.8 230 236.9 245.4 253.3 262.2 270.8 279.5 289.2 299.4 311.7 324.8 330.7 336 338.7 333.5 331.4 343.4 354.9 362 366.5 376.8 385.8 398.9 407.4 417 426.4 443.6 458.1 477.6 488.7 496.9 509.5 516 521.5 526.8 528.8 517.3 514.4 513.2 514.3 515.3 518.4 521.6 526.7 538.9 533.3 524.1 506.1 490.9 482.6 471.8 462.6 455.8 449.4 444.3 441.2 437.7 433.8 429.9 430 433.8 436.6 438.2 438.2 436.9 429.3 421.1 409.2 395 383.1 369.8 358.1 345.7 332.2 315.3 302.1 291.4 281.5 268.4 263.1 257.3 254.9 252 245.7 239.2 231.5 223.7 216.1 206.4 196.5 188.9 189.1 198.9 200.4 199.8 200 196.2 190.7 189.7 191.9 188.1 184.8 181.4 177.9 175.8 174.9 173.6 172.3 171 170.5 170.3 170.5 170.8 171.9 172.5 173.3 174.5 175.7 177.9 177.9 164.8 156.6 153.4 152.8 153.2 152.1 143.5 133.6 111.6 101.4 92.6 82.2 68.6 63.7 52 41.6 34.4 29.8 32.3 34.8 35.1 +40.9 42.3 43.4 43.4 42.7 41.9 41.2 40.6 40 41 44.7 51.2 57.8 68.8 76.3 78.7 80.3 82.9 84.6 89 91.8 94 96.4 98 98.5 96.3 86.8 84.9 96.3 101.7 107.7 111.2 112.2 114.1 115.2 114.3 109.1 107.5 109.1 117.1 124.9 130 135 141.7 147.1 152.6 156.9 161.8 167.5 172.5 177.2 184 190.2 195.3 200.2 206.2 210.1 216.8 224.3 230.9 239.3 246.1 252.7 261.5 269.4 280.3 288.2 298.9 311.1 322.7 327.9 332.1 329.3 325.6 324.1 340.4 349.1 355.5 361.1 369.9 379.7 391.4 400.6 410.3 423.2 440.3 454.5 467.2 478.1 490.5 506 513.7 520 529.3 531.2 526.8 515.6 514 514.9 517.3 523.5 525.3 527.8 544.7 536.2 521.8 506.7 490.5 482.3 471.4 461.6 454.4 446 439.3 436.7 433 429 424.9 424.7 428.2 430.5 431.3 430.5 427.2 421 413.6 404 392 381 368.2 356.6 344.9 331 314.8 302.2 293.5 283.7 269.9 262.7 258.1 254.5 251.4 246.8 239 231.6 224 215.1 207.1 198 186.5 181.3 192.7 194.7 194.3 193.4 188.8 185.3 185.2 187.3 184.7 180.3 178 175.5 174.8 174.3 173.2 172 170.7 170.2 170.3 170.3 171.1 172.7 174.5 175.8 178.2 179.9 180.3 184 172.9 166 161.9 165.3 164.4 161 154.1 141.1 116.5 101.5 93 79.1 70.3 63.4 52.7 43.9 36.2 28.4 31.8 34.1 34.6 +40.5 40.6 41.7 42.1 40.7 39.6 39.3 39.3 39.6 40.5 44.8 49.9 54.1 64.4 71.7 74.5 77.3 79.9 83.8 88.2 90.9 93.6 96.9 97.9 98 95 83.9 84.6 96.6 102.8 107.8 111.7 112.4 114 114.9 113.6 107.9 106.9 108.9 115.6 125.1 130.5 135.6 140.8 147.1 152.7 156.4 161.8 167.4 172 177 184.1 189.4 194.5 199.3 204.9 210 218.2 225.1 232.4 240.1 245.9 251.9 260.1 268.8 278 286.8 295.9 308.7 317.7 321.6 324 318.7 310.3 327.7 335.7 342.3 347.8 355.7 363.7 372.3 380.6 393.3 405.5 417.8 432.2 446.7 460 471.5 485.7 499.2 506.7 515.2 530.9 529.7 523.9 513.8 512.5 514.1 518 529.6 530.5 528.7 527.9 536.8 519.6 498.6 488.7 480.2 469.4 459.6 452 443.2 434.8 430.7 427.3 422.1 416 416.8 421.1 423.1 424.7 424.1 420.2 414.3 406.4 395.9 385.4 376 364.7 353.3 341.1 328.2 313.2 299.7 293.6 283.9 269.4 261.9 258.6 254.5 250.7 246.1 238.3 231.3 223.8 215.2 206.7 198.1 187.3 180.3 184.8 189.2 189.6 187 181.5 180.3 181 183 181 178 175.3 173.4 173.3 173.2 172.4 171.1 169.8 169.4 169.7 170.1 171.1 173.4 175.7 178.1 182 184 186.5 195.2 181.6 172.7 167.9 168.9 170.6 167.5 162.4 146.4 117.7 97.5 88.3 82.9 76.6 50.8 50 43.2 37.5 30.9 30.2 32.8 35 +39.5 39.7 39.2 40.4 39.3 38.4 38.5 38.9 39.3 40.6 44.4 48.7 52.5 60.1 66.9 69.5 74.2 78.3 82.8 87.3 90.1 93.7 96.9 97.9 97.4 91.7 82.1 85.1 97.9 100.1 105.8 109 111.8 113.6 114.2 112.9 106.5 106.2 108.7 120.3 127.2 131 136.2 141 147.1 152.1 155.2 161.3 166.7 171.4 177.1 183 188.4 193.8 197.9 202.6 209.7 218.2 226.1 233.1 239.8 244.8 249.9 259.7 268 276.4 284.1 293.4 304.2 307.4 307.1 310.5 308.1 312.2 323.2 330.3 334.9 338.5 348.9 356.8 364.5 373.2 383.1 395.9 408.1 421.7 435.6 447.7 461.9 475.7 486.9 496.7 503.4 512.9 513.4 512 507.6 508 510.2 514.8 525.6 530.1 525.4 520.9 524.1 506.2 496.2 485.9 475.9 465.6 456.2 448.4 439 429.9 424.8 419.3 413.8 407.1 407 411.2 414.6 416.3 414.7 411.4 404.1 396.7 389.7 381.8 372.3 360.7 347.5 335.2 323.4 309.1 296.2 289.8 278.3 266.2 258.4 256 252.7 249.1 244.3 237.4 230.3 223 213.9 205 196.6 187.3 178.9 178.4 184.4 184.8 181.5 177.1 176.2 177.7 178.2 178.4 177.2 171.9 171.2 171.8 171.8 171 169.5 168.5 168.4 168.4 169.3 170.8 173.6 176.5 180.4 185.9 189.6 189.8 195.1 182.7 178.5 175.4 176.8 175 168.3 165 147.3 111.7 101.5 82.8 74.1 65.6 43.7 36.2 33.6 33 30.3 29.3 31.7 33.7 +37.9 39 38.2 39.7 38.5 37.9 38.2 38.5 39.1 40.7 43.2 47.3 51.2 56.1 63.8 66.4 72.9 78.5 82.2 86.2 88.9 92.2 95.7 97.1 96.4 86.7 81.5 88.5 99.5 102.1 102.1 104.9 109.2 111.1 111.2 110.2 104.9 106 110.8 120.1 128.7 133.8 137.8 142.2 147.6 151.3 154.3 161.1 166.1 170.5 175.9 181.7 187.8 193.1 196.7 202.4 209.8 217.9 225.4 232.8 240 245 250.6 258.4 266.8 274.9 281.6 287.3 296.4 296.4 299.7 301.4 297.7 311.6 318.1 325.6 329.6 334.2 341.3 348.2 357.3 367.2 377.2 388.4 400.1 411.2 421.8 436.1 452.8 466.8 476.7 484.7 492.8 498 502.4 501.1 501 502 502.6 507.1 522.4 527.5 519.7 514.3 508.7 500.8 493.2 482.4 472 460.5 451.4 442.9 433 423.3 417.8 412.4 405.7 398.9 396.7 400.1 403 404.5 403.6 398.9 393.6 389.2 383.2 376.3 366.7 356.2 342.2 330 318 305.1 291 283.5 274.4 262.1 257.1 252.5 248.8 245.5 240.7 235.1 228.5 221.3 214.9 207.1 197.8 189.1 179.2 176 179 180.5 178.9 175 172.3 174.4 175 176.1 173.8 170.1 169.2 169.7 169.3 168.6 167 165.6 165.9 166.6 168.4 169.9 172.5 178.4 183 189.1 194.6 190.6 192.7 185.3 183.1 186.1 180.6 177.2 172.3 157.7 137.9 112.1 93.1 81.5 56.7 45.5 38 34 32.4 31.5 31 27.4 31.5 32.7 +37 39.4 38.9 38.5 37.9 37.7 38 38.5 39.4 40.7 42.9 45.5 50 54.5 60.9 61.6 69.2 76.7 81.5 84.5 83.9 82.5 90.5 95.4 88.1 81.7 81.7 88.7 100.2 104.7 104.3 103 103.7 104.7 104.7 103.7 103.9 105.5 116.7 125.3 130.3 134.4 139 143.2 147.2 150.9 153.8 160.2 165.5 169.7 175.1 181 187.1 192.1 195.2 201.3 209 217.7 224.7 234.1 240.5 245.4 252.1 258.3 265.6 272.3 278.4 283.3 287.2 290.9 292.6 294 294 305.9 312.9 320.1 325.2 330.1 334.6 340.3 348 357 368.2 378.7 394.6 406.2 417.6 431.9 446.2 459.2 469.9 476.9 484.7 490.3 493.6 494.1 495.2 495.5 496.8 497.9 504.3 515.1 512.4 507.6 502.9 497.1 488.5 477.4 466.6 455.5 446.7 436.3 425.4 416.6 410.8 403.3 397.8 391.2 388.3 390.4 392.9 393.3 390.9 387.7 384.3 379.2 374.5 368 360.6 350.8 337.5 327 313.7 299.4 286.9 281.1 271 259.9 256.5 252.8 251.2 252 246.5 239.6 232.2 224.7 218.2 209.3 200.1 191.9 180.3 175.3 174.8 176.5 176.5 173.5 170.1 171.6 170.6 170.5 168.5 168 166 166.7 166.7 165.5 163.4 162.1 162.8 164.5 166.4 168.8 172.2 179.1 185.4 189.8 193.5 191.2 194.6 190.9 190.1 189.1 182.3 177 172.3 156.8 129.5 104 88.6 73.5 52.1 42 35.5 32.8 32.1 31 30.6 29.7 31.1 32.6 +36.4 38.9 39.1 38.4 37.7 37.6 38 38.5 39.5 40.6 41.9 43.4 47.6 50.7 54 54.9 65.6 73.9 77.7 76.3 71.8 81 87.3 82.3 80.2 80.9 84.2 88.6 101 108.8 107.1 103.3 101.2 101.5 101.5 100.5 102.4 110.9 122.8 127.3 132.1 136.5 139.7 143.8 147.2 150.7 152.9 158.8 164.8 169.3 175.1 181 186.2 190 194.4 201.9 208.6 217.6 224.3 233.7 240.3 245.9 251.5 258.9 265.2 269.6 276.6 281.6 284 288.1 287.1 290 290.1 301 307.5 314.8 321.9 327 330.8 335.3 342.1 350.7 357.4 368 387.6 398 409.2 427.5 442.2 453.3 463.6 471.1 476.7 483 485.5 486.9 487.9 488.3 490.3 492 494.9 497.5 500.3 501.1 497 491.6 482.4 472.4 462.3 453.1 439.4 429 419 410.8 403.7 397.6 391.5 384.9 382 380.6 381 379.9 377.9 374.7 371.7 368.5 365.9 361.6 353.7 343.3 331.8 321.9 310.9 295.4 286.1 281.1 271 264.5 260.3 255.8 255.8 254.1 249.2 241.4 233.9 227 220.3 212.1 204.1 195.9 184.8 178.4 170.4 170.6 167.8 166.5 166.2 167.8 166.1 165.9 164.8 162.2 162.5 163.8 163.9 162 160.2 159.5 160.2 162.1 164 167 172.4 181.1 189.3 191.6 193.7 195.2 198 195.1 195.8 194.1 183 175.3 169.4 154 117 103.6 87.6 65.2 49.9 40.3 34.4 32.1 31.8 30.8 30 29.5 29 33.9 +35.9 38.3 39.2 38 37.5 37.3 37.4 38.1 39.8 40 41.4 42.1 44.3 46.5 49.6 54.8 59.6 61.5 65.6 74.9 81.1 75.6 79.5 78 78 80 84.8 89.6 102.2 109.4 109.8 108.2 104 106.8 105.5 101.6 103.2 116 124.3 127.7 132.1 136.2 139.4 143.9 147 149.6 152.1 159.3 164.1 169.3 175.1 181.2 184.9 189.1 194.8 203.4 208.9 217.9 225.2 233.7 239.4 244.6 251.5 257.5 263.9 268.7 274.4 279.3 281.9 284.3 283.9 285.1 288.4 298.3 304.1 309.9 317.6 322.9 327.3 332 336.7 346 354.8 365.3 378.5 389.4 399.6 415.1 433.4 443.4 453.1 461.9 467.8 473.5 477.5 479.8 481 482 484.6 487.1 490.9 493.4 494.2 494.1 491.1 485.9 477.4 468.2 458.4 446.8 432.5 422.1 413.1 405.5 399.5 393.2 387.2 381.3 376.6 373.4 371.3 370.2 368.3 365.3 362.5 359.2 356.6 351.1 345.5 338.2 327.8 317.9 305.6 291.7 282.6 276.7 270.1 265.9 262.3 260.9 258.9 254.6 250.2 243.8 237.6 230.6 223.1 215.8 207.6 199.2 191 184.7 176.5 173.4 171.5 166.8 163.6 159.6 161.6 161.7 159.7 158.6 158.9 160.4 161.2 159.9 158.1 157.7 157.7 159.6 161.7 165.8 171.7 178.7 191.4 197.9 201.8 203.3 203 200.7 203.1 195.6 186.8 178.1 163.6 133.5 119.9 102 80.3 61.4 49.2 39.3 33.2 31.7 31.2 31.1 29.8 28.6 30.3 44 +35.1 37.8 39.1 38.1 37.2 37 36.8 37.6 39.3 40.1 40.1 40.9 41.7 42.9 48.8 54.4 61.4 69.2 76 83.4 87.3 86.1 81.1 78.2 75.3 75.9 83.7 92.9 104.6 109.5 111.5 111.7 109.9 110.1 104.1 101.8 106.9 121.5 123.6 127.3 131.7 135.5 139.5 142.5 144.8 148 151.3 158.6 164.3 169.2 175.5 181.4 185.4 187.8 198.1 205.2 209.9 217.8 224.4 232.4 236.8 244 250 256.3 261.6 265.9 270.4 276.2 279.4 278 279.5 280.3 285.6 296.1 300.5 305.2 312.3 317.9 323.6 329.1 334.2 340.4 350.1 361.8 372.4 383.5 394.5 408.6 423.3 433.9 443.7 451.6 458.3 463.4 468.9 473.6 474.9 476.2 479.9 481.9 484.7 489 491.1 489.9 486.6 481.1 472.2 462.5 452.6 437.5 425.9 416.3 407.9 400.4 394.2 388.4 382.6 377.6 373.1 368.4 364.8 361.3 360 359.6 357.3 354.2 350.8 346.2 341 333.9 325.4 314.8 302.4 292.5 285.9 279.5 270.8 266.9 263 263.2 262.9 259.5 254.9 248.4 242 233.9 226.4 218.6 211.3 202.5 195.4 188.3 180.5 177.2 175 169.8 165.5 161.7 157 153.1 154.1 153 155.1 157.7 158.3 158.1 156.8 155.8 155.7 157.1 159.6 163.7 169.7 177.1 188.5 201.5 209.2 211.2 212 207.5 206.5 202.2 193.5 175.5 147.6 131.7 125.3 99.2 71.9 59.1 50.7 40.6 32.5 31.2 30.9 30.8 29.8 26.2 30.6 42.3 +34.1 36.7 38.4 38.7 37.5 36.6 36.7 37 37.9 38.9 39.2 39.8 40 40.7 45.8 52.6 63 71.1 77.5 83.7 88.1 91.3 88.7 86.5 79 73.3 81.5 101.6 108 109.9 111.8 113.2 112.2 109.3 102.2 100.5 108.5 120.1 123.4 126.6 131.2 135 138.8 140.5 142.3 145.8 152.8 159.1 165.1 168.5 174.5 180.1 183 191.4 199.5 205.5 209 216.5 221.9 230.6 235.1 241.7 247.5 251.8 257.1 262.9 266.8 271.1 271.3 273.2 274.4 273.8 287.3 292.5 297.7 302.5 308.1 312.7 319.4 325.6 330.8 337.1 345.6 357.3 369.8 379.9 393.2 406.5 416.3 425.6 436.3 444.4 451.3 457.2 461.4 463.7 466.5 469.2 472.1 475 480.3 484 486.6 485.5 482 476.3 466.8 457 444.5 428.6 417.7 409 402.9 395.2 389.3 383.8 378.7 374.1 370.1 365.3 361.4 359.6 356.3 355.5 353.7 350.9 347.7 343.7 338.8 331.6 324.4 313.9 302.8 295.3 289.2 283.3 272.9 269.6 268.9 267.3 266.6 264.2 259.8 253.2 246.2 238.3 230.2 222.3 214.1 206.4 199 192.2 184.7 180.2 177.9 172.9 168.5 164.3 160 154.5 150.3 148.1 151 154.3 156.1 155.9 154.9 153.9 153.2 154 157.2 161.2 167.9 175.3 191.5 207.8 215.5 221.9 222.6 214.1 212.6 208.7 196.3 177.7 144.9 133.3 123.4 93.4 68 57.4 50.9 38.1 32.1 31 30.8 30.6 29 26.8 30.7 41.4 +32.8 34.1 37.5 38.8 38.2 37.5 37.5 37.3 37.3 38.1 38.1 39.4 39 38.9 43.6 51.4 62.4 71.3 79.7 85.5 91.7 93.1 91.9 90.3 87.3 75 90.5 104.5 108.2 110.2 112 113.8 112.6 108.7 99.9 103 113.2 119.3 122.7 125.9 130.5 134.5 138 138.6 141 148.4 154.2 159.3 163.4 167.7 173.6 178 182.7 191.3 198.6 203.3 208.1 215.3 221.1 228 233.7 239.7 246.2 248.1 253.3 258.5 261.7 264.7 266.4 269.9 264.8 279.6 285.2 289 294.4 299.3 304.5 309.1 315.8 323.5 329.7 336.6 345.8 355.2 367.4 378.9 391.9 403 411.8 420.4 430.5 437.7 445.9 451.7 454.1 455.3 457 460.8 464 469.3 475.3 479.6 481.4 480.8 477.4 470.9 462.3 453.4 436.5 422.8 412.1 404.1 397.8 391.5 385.7 380 374.9 369.3 365.4 362.6 359.1 355.6 353.6 351.4 350.1 348.4 346.1 343.1 339.3 332.1 324.2 316.5 305.4 299.5 293.3 289.3 279.5 274.2 273.8 273.9 272.6 269.2 264.4 257.7 250.1 243.1 234.1 225.5 217.7 209.7 203.1 196.5 189.3 184.3 181 176.4 171.2 167.1 162.6 157.4 151.6 146.7 145.3 150.8 154.1 154 152.4 151 150.4 151.2 153.6 158.7 166.4 175.1 189.9 212.2 225.2 232.9 231.4 220 222 209.7 195.2 176.7 140.8 116 102.6 81 66.8 57.2 50.7 37.7 32.3 30.9 30.4 30 28.3 25.6 33.1 43.1 +31 32.4 36.2 39.2 40.6 38.9 37.3 37 36.8 36.9 36.9 37.8 38.6 38.2 38.6 47.3 61.1 72.2 80.9 85.8 90 92.8 95.3 90.7 70.7 88.6 97 105 108.1 110.5 112.6 114.3 113.8 107.6 99.3 103.2 114.9 118.9 122 125.5 129.8 133.9 136 136.8 142.6 149 153.8 157.5 161.3 168.2 172.5 175.3 181 189.8 196.6 200.5 207.2 213.4 219 226.1 232 238.8 244.4 245.4 249.8 254.5 255.8 259.5 267.2 265.9 264.1 279.7 283.6 286 290.4 297 301.6 306.1 312.8 322.1 328.3 334.5 344.5 353.8 363.6 375.9 388.1 398.1 406.3 414.8 425.9 432.9 440.6 444.6 446.8 447.7 449.6 452.4 456.4 462.6 469.2 474.3 477.2 476.7 472.9 465.8 459.1 447.4 431.1 417.8 408 399 393.2 387.4 382.5 378.1 372.9 367.5 362.1 359.5 356.9 353.7 351.1 349.7 348.5 347.9 346.5 344.4 340.6 334.6 328.7 320.4 309.3 302.9 298.8 292.2 285.3 280.5 279.6 278.8 277.7 274.6 270 261.5 254.2 247.4 238.3 229.5 221.5 213 206.2 200.4 194.6 189.1 184.6 179.8 174.6 168.9 164.5 159.3 152.5 146.7 142.6 147 150.6 151.4 149.8 147.9 146.9 147.9 150.5 155.5 164.1 174 187.6 210.8 226.7 241 235.7 221.6 223.9 207.5 190.9 165.4 134.4 114.3 90 75.1 67 59.4 49.6 37.9 32.6 30.9 30.1 28.8 27.3 25.6 33.8 46.1 +29.3 32.6 36 41.1 42 41.1 38.2 36.7 37.2 36.7 36.7 37 37.6 37.9 37.8 42.9 59.1 70.7 77.9 83.5 88.8 92.3 94.8 84.1 74.2 91.2 99.1 105.4 108.6 110.8 112.6 114.3 113.9 109.4 100.3 101.6 110.4 118.1 121.6 125.1 129.3 133.3 135.2 136.9 143.2 148.9 153.9 157 161 166.9 170.6 173.4 179.8 188.1 194.1 197.8 205 210.8 217.2 223.7 229.8 236.1 240.6 242.2 245.7 248.2 250.3 257.2 265.3 261.6 260.3 275 279.8 283.2 287.8 293.6 298 301.4 307.9 318.6 326.5 333.5 344.2 353.6 361.8 371.1 382.8 393.5 401.8 408.7 421.3 428.6 436 438.8 439.5 440.1 443.5 445.8 449.6 455.5 463.1 469 471.3 471.7 469.1 462.4 456.2 442.5 427.8 414.8 403.4 395.6 389.1 383.8 379 375.2 370.8 366.1 360.4 356.3 353.9 351.8 349.8 347.7 347.2 347.3 345.9 345.4 342.3 338.4 334.4 327.9 320.6 311.9 304.6 296.3 290.2 287 285.1 283.9 282.6 279.6 274.3 264.5 257.1 250.6 241.9 233.4 225 216.7 209.7 203.1 197.5 192.1 187.2 182.6 177.3 170.1 165.5 160.3 153.2 147.5 142.5 142.6 145.7 147.4 146.1 144.3 143.1 144.5 147.8 152.9 162.3 172.8 186.8 208.9 224.4 236 236.4 221 217.7 197.3 183.2 160.6 139.5 125.7 92.8 75.8 70.9 61.2 51.2 38.4 33.2 32.2 30.5 28.1 26.3 24.4 37.8 49.5 +30.4 33.3 37.6 41.2 43.4 43.6 40.8 37 38.1 38.6 37.5 36.6 36.6 37 37.2 40.8 55.9 69.2 76.9 82.7 88.8 92.2 95.1 85.1 70.5 90.6 101 106.1 109.3 111.3 113.2 114.9 114.6 111.1 104.5 98.8 111.3 117.6 122 125.7 130.3 134.3 136.1 137.1 143.9 149.5 153.8 157.2 160 164.8 168.3 170.6 178.6 185.7 190.8 195 201.6 208.3 214.3 220.1 226.8 232.4 235.5 238.4 240.9 241.9 245.7 253.6 257.4 249 261.2 272.9 278.3 280.9 284.8 290 294.8 297.9 303.6 316.8 325.9 334.6 344 351.3 359.3 369.2 379 389.2 397.2 405.2 414.8 423.6 429.7 431.4 431.5 432.6 434.8 437.9 443.3 450.5 456.3 462.9 465.2 467.7 465.8 460.9 451.3 438.2 425.9 412.1 401.6 394.6 387 380.8 375.8 372.1 368.5 363.5 359 355.3 351.7 349.2 347.2 345.2 344.8 345.3 346.4 345.4 343.5 340.3 335.9 330.7 324.8 319 309.7 301.7 296.8 293.7 290.8 289.2 287.1 283.4 276.6 266.7 258.8 251.8 244.3 236.3 228.5 220.7 213.4 206.3 200.1 194.5 189.4 184.9 180.1 172.6 166.6 161.8 156.2 149.8 145.6 141.7 138.5 141.6 141.6 140.2 139.5 140.2 143.5 150.2 158.7 166.3 184.4 202.1 216.7 225.6 225.6 213 196.9 186.6 177.5 152.5 145.7 127.8 98 77 70.2 56.2 54.3 36.6 31.9 32.3 34 27.3 24.3 32.2 43.1 53.6 +30.8 34.3 38.1 41.3 44.1 45.9 45.1 41.5 40.6 39.7 38.5 37.5 36.3 36.2 36.5 39.1 54.9 69.5 75.7 84.1 88.1 91 93.8 88.7 72.9 91.6 100.6 106.4 110.3 111.1 113.6 115.6 115.2 112.6 108.3 98.1 110 117.4 121.5 125.7 130.8 135.3 137.1 136.9 144.4 150.4 154.2 156.9 158.7 162.4 166.3 168.4 176.4 183 188.2 192.4 198.6 206.2 210.8 216.6 222.7 227.4 230.7 232.7 233.8 236 241.1 245.8 242.6 252 269.5 272.3 277.7 279.8 282.2 287.3 291.9 295.6 303.2 313.8 322.4 332.1 340.6 347.9 355.2 364.6 373.3 384.1 391.1 400.5 409 417.1 421.4 422.8 424.6 424.9 426.9 432.1 437.5 444.1 451.2 455.9 461.5 464.9 463.6 459.4 448 435.3 424.5 411.2 401.1 393.8 386 379.4 374.2 370.1 365.5 361.9 357.5 353.2 349.9 346.5 344.4 342.8 342.6 343.3 344.9 345.5 344.1 341.2 337.3 332.3 326.4 321.2 313.2 306.4 302.4 299.2 295 292.8 290.4 285.5 277.5 268.3 259.6 252.1 245.4 238.8 231.1 223.4 216.3 209.1 202.7 196.7 191.5 186.3 181.7 175.6 168.5 163.2 158.3 152.6 147.3 142.4 138.7 135.8 135.5 136.1 136.1 136 138.8 141.6 149 158.1 173.6 193.1 200 198.9 196.8 192.9 180.3 178.3 165 156.8 138 123.3 94.8 77.9 62.4 50.8 44.7 35.4 30.1 29.6 36.3 24.9 28.5 38.6 46.1 54.6 +29.2 33.4 38 41.6 44.8 47 47.1 45.1 43.1 42.1 40.4 37.9 36.6 35.9 36.1 38.6 51.4 64.2 74.7 82.6 86.7 89.9 93.1 82.2 71 91.3 98.9 106.4 110.1 110.8 113.7 115.9 115.3 113.4 108.3 98.1 109.5 117.4 121.7 126 131.6 135.7 136.2 138.9 144.6 150.3 154.7 156.1 156.7 159.8 163.8 166.7 173.9 180.7 185.6 187.5 195.9 201.7 207.8 213.9 219 222.3 225.4 226.2 227.2 233.3 239 234.1 247.1 262.2 268.1 269.6 275.9 278.1 279.9 284.5 288.7 294.5 302.2 310.1 317.8 327.6 335.8 343.8 351.1 359.4 367.9 378.1 385.8 393.4 403.2 408.3 412.8 413.2 414 416.8 419.7 424.7 432.7 439.1 442.8 451.9 456.4 461 461.4 455.2 446.1 434.9 423.6 411.4 400.5 392.5 384.2 378 373.1 368.8 364.5 359.7 354.6 350.8 347.3 344 342.2 340.5 340 342 344 345.1 344.1 342.1 338.3 334 328.4 320.4 314.6 309.5 305.7 302 298.1 295.5 293.1 287.4 279.2 269.5 260.6 252.9 246.4 239.8 232.8 225 218 211.3 204.6 198.9 193.8 188 183.4 178.4 171.3 164.6 159.1 154.7 148.9 144 139.5 135.9 133.4 134.1 132.2 133.3 133.5 133 134.9 140.6 156.8 170.1 174 173.4 173.9 166.9 158.6 154.8 149.2 149.9 136.2 116.9 93.2 77.5 55.2 45.4 37.2 31.4 27.7 27.8 29.7 23.3 30.6 40.4 47.7 56.5 +27.1 32.3 36.8 41 44.1 45.9 46.4 44.8 43.2 42.2 39.9 37.5 37.9 36.5 35.8 37.9 51.5 56.8 71.1 79.1 84.8 89 92 82.5 63.8 82.6 94.7 104.5 109.1 110.7 114 115 114.7 113 107.4 97.6 105.8 117.4 121.9 125.9 131.2 134.6 135.1 139.6 144.4 149.8 154.6 156.4 156.1 157.4 161.6 162.9 172.8 178.9 181.9 184.4 192.7 198.1 204.3 209.6 214.8 217.8 219.3 220.3 223.8 232.7 235.6 230.4 251.3 261.7 266.2 268.5 275.1 275.5 277.7 281.2 284.5 293.1 301.8 308.8 315.7 323.3 329.4 338.8 346.8 353.9 360.5 369.9 378 385.6 393.6 399.3 401.4 403.3 404.4 407.3 410.8 417.3 421.8 429.7 436 445.5 454.3 456.3 460.2 452.1 442.1 433.3 423.9 412 400.5 390.8 382.4 376.7 371.7 367.3 362.6 358.6 353.6 347.6 344.3 341.1 339.7 339.2 337.7 340.2 343 343.2 342.9 342.6 339.9 334.5 329.7 322.8 315 310.3 307 303.9 300.3 297.8 295.3 290.5 281.5 271.6 262.5 254.9 248.8 241.7 234.2 225.9 219 213.1 207.2 201.5 195.8 189.9 185.4 180.5 174.3 167.3 161.2 156.1 149.7 144.4 139.5 135.7 133.2 132 129.6 128.3 128.7 128.4 128.8 130.9 136.8 147.8 151.5 155.3 154.7 147.5 139.2 134.8 135.9 134.6 132.8 114.4 92.5 70.2 50.4 39.3 31.8 27.7 26.6 26.4 24.7 25.3 33.3 40.8 47.8 55.7 +26.7 32 35.8 39.6 41.9 43.5 43.2 42.1 41.1 39.7 37.7 37.4 38.6 36.3 35.8 37.9 49.6 55.4 63.1 75.8 83.7 87.9 89.9 86.5 63.7 86.1 95.5 104.6 108.8 109.9 113.9 114.5 114 112.3 104.6 97.3 102.9 115.5 121.1 125.5 129.8 132.3 133.8 137.9 143.7 149.3 153.7 156.4 155.5 155.9 159.5 161.9 171.3 176 177.9 183.4 189.5 194.1 200.6 206.6 212 212.6 213.4 216.5 222 230.9 222.4 232.1 249.9 259.7 262.6 265.3 271.7 273.1 275.8 278.8 283 289.7 299 305.6 312 318.8 324.9 331.9 340 345.7 350.6 358.5 367.8 377.5 387.2 391.1 393.5 395.5 396.4 399.5 401.6 408.2 414.5 421.5 429.4 438 449.4 450.6 452 448.7 440.3 431.3 422.3 411.4 400.1 390.6 381.9 375.4 370.6 365.8 360.8 356.7 351.7 345.9 341.5 338 336.8 336.4 335.1 338.7 339.1 339.2 340.4 341.6 341.7 337.8 332.1 325.8 317.4 310.5 308 305.3 302.4 300 297.4 292.2 283.1 273.1 265.4 257.8 250.4 243.6 234.4 227 220.6 214.6 209.4 204.1 197.9 191.4 186.9 182.6 177.4 171.1 165.1 158.4 150.8 145 140.2 136.2 134.5 134.1 130 125.9 123.9 124.9 124.8 127.3 132.4 140.2 144.6 148.8 146.6 137.4 125.2 121.8 118.7 124.1 111.8 96.1 90.6 69.3 45.2 33.6 28 26.2 25.9 25.8 22.2 28.6 35 42.1 50.7 59 +23.9 30.4 32.8 36.5 39.5 41.1 39.8 38.9 38.6 37.3 36.9 37.6 37.2 36 35.8 37.5 46 51.8 57.4 72 82.3 80 71.6 80.1 59.5 88.1 98.3 105.1 108.8 109.4 113.4 113.7 113 110.4 100.1 97.1 99.9 113.3 120.3 124.3 127.9 129.7 132.1 137 142.9 148.5 152.1 154.6 153 154.5 158.5 162.3 169.4 171.8 170.6 177.2 184.7 188.8 194 203.4 205.8 206.6 211 217.2 216.3 217.7 219.1 231.9 248.1 258 259.9 263.7 268 272.1 274.4 276.7 279.7 286.3 294.5 299.9 306.4 312.8 319 324.7 331.8 336.6 340.1 346.8 356.5 363.9 375.5 380.4 381.9 384.2 388 391.5 394.3 401.2 409.7 416.9 422.7 429.7 438.6 445.3 448.3 444.1 437.7 429.7 420.6 409.1 398.1 389.1 381.3 374.7 369.8 365.2 360.1 354.9 349.4 343.3 338.5 334.6 332.9 331.7 330.8 333.2 334.9 335.9 338.2 340.3 342.1 340.7 336 328.7 319.7 310.7 308.2 306.6 304.1 301.3 297.8 293 283.9 275.7 268 260 252 243.7 235.1 227.8 222.2 216.5 211.1 205.9 200.4 193.1 188.7 184.4 180.3 175.2 169.2 163.5 155.4 147.3 142.7 139.1 137.8 136.8 135 133.3 132.3 129.3 121.2 120.9 124.2 128.4 135.7 137.3 135.7 128 113.8 111.4 107 102.9 94.2 78.3 74.5 61.2 39.4 30.1 27.1 25.6 25.4 24.5 21.9 31.3 36.8 44.3 52.8 61.5 +20 24.9 29.1 35 38 39.8 38 37.2 36.8 37 36.7 37.7 37.4 35.9 36.5 37.6 40.9 46.1 52.6 73.1 78.5 53.1 51.8 55.8 76.2 89.7 99.3 105.1 108.4 108.8 111.9 112.5 111.9 107.7 98.3 96.8 98.7 112.8 118.2 122.6 126.2 127.2 131.2 136.4 141.7 146.3 149.9 152.1 151.2 152.9 157.4 160.5 161.4 155.6 162.4 162.7 173.5 175.4 179.8 185.1 191 194.1 200.6 202.8 204.3 211 225.1 233.9 246.4 256.2 259.8 260.9 265.3 269.9 273.6 274.6 277 283 289.5 295.1 300.5 305.9 311.8 317.2 322.2 325.4 331.2 337.9 343.6 349.1 362.2 368 372.2 373 379.6 383.9 388 397.6 404.9 412.5 420 425.7 433.6 440.6 442.6 439.9 434.4 427.3 419.1 408.7 396.5 386.8 379.7 373.9 369.2 364.5 359.3 353.9 347.2 340.5 335.8 331.7 328.8 328 327.2 330.2 331.7 334 337.1 340.6 343.2 342.4 337.5 330.1 320.7 312.1 308.1 307.5 305.7 302.3 298.2 293.1 285.6 278.1 270.3 261.8 253.5 245.4 236.5 229 223.9 218.1 212.8 208 202.3 194.9 189.9 185.5 181.5 176.9 171.7 166.8 161.2 153 147.2 143.8 142 140.3 138 136.4 134.7 132.3 129.6 122.6 114.6 120 124.7 127.8 120 108.1 103.1 101.8 97.7 91.8 85.2 75.6 79.9 55.5 34.1 27.2 25.5 24.7 24.8 24.3 23.4 31.9 38.6 45.9 53.7 62.8 +19 24.9 30.7 33 36.8 40.2 39.6 38.7 38.3 37.1 36.4 37.9 36.2 36.1 36.9 38 39.1 41.1 47.7 70 70 49.7 67.7 71 82.9 93 99 105.2 108.6 108.6 110.4 111 110.8 106.9 97.6 96.7 99.5 107 116.7 119.7 123.9 126.1 129.9 134.4 139.2 143.1 146.4 148.8 147.4 149 148.4 148.4 154.5 163.6 168.8 174 169.4 174.2 185.2 189.5 187.5 193.6 199.9 206.9 213.9 216.1 217.8 228.3 240.6 246.3 253.5 258.4 261 267.1 269.5 271.6 273.6 279.1 286 291.1 295.5 299.9 306.1 310.6 313.6 316.9 324.9 332.1 336.7 340.3 350.2 358.1 363.3 365.6 371.2 378.1 384.8 395.2 403 410.4 418 423 427.6 434.1 436.3 434.8 429.3 423.8 416.5 406.8 394.3 384.9 377.4 371.7 366.8 362.3 357.3 351.3 344.8 338.9 334.9 330.5 325.6 324.3 324.6 326.7 329 332.9 337.7 341.4 344.3 343 338.6 329.2 318.6 312.6 306.3 307 306.7 303.6 298.7 291.6 286.8 281 272.3 263.9 255.3 247 238.2 230.7 225.2 220.1 214.9 210.7 204.7 197.2 191.3 186.8 182.6 178.4 174 169.5 164.7 157.7 152.8 149 146.7 144.8 142.9 139.5 136.8 134.4 131.9 125.9 116.3 106.7 113.8 120.3 119.2 101.6 93.5 93.6 91.3 81.6 73.2 62.4 64.1 55.6 33.6 28 25.4 24.2 24.5 23 24.6 31.4 38.3 47.2 55.1 64 +17.9 23.1 26.7 31.2 37.3 40.3 42.1 40.2 39.5 39.1 38.8 38.7 35.1 36.2 36.4 37.4 38.7 40 43.2 58.4 47.9 57.3 67.9 78.6 85.9 93.6 100 105.7 108.3 109.8 109.1 109.5 109.5 108.5 99.3 96.4 100.3 114.8 117.9 120.6 122.2 124.3 128.1 131.5 135.2 138.2 140.4 140.5 139.7 140.9 142.2 148.4 161 169.5 174.2 179.2 185.1 191.8 195.1 198.3 202.6 208.2 215.1 220 221.5 224.9 234.3 233.9 240.1 242.9 242 255.6 255.8 262.5 264.5 266.1 270.4 275 280.9 287.2 290.8 295.2 300.4 305.3 309.1 312.3 319.2 327.9 333.5 338 343.1 349.6 354.2 358.8 366.4 373.7 383 390.3 398.9 407.6 413.7 418.9 423.7 427.5 430.3 429.3 425.6 420.5 413.8 405 391.8 383 374.5 368.4 363.9 359.1 354.4 349.4 343.1 337.8 333.7 329.8 325.3 321.8 323 324.8 327.8 332.9 338 342.1 344.1 343.1 337 326.8 316.2 310.8 304.6 305.6 307.2 305 300.4 293.7 288.6 282.6 274 265.5 257 248.7 239.9 232.7 227.1 221.9 216.9 212.8 207 200.6 193.5 188.4 184.3 180.5 176.4 172.5 168 163.3 156.9 154.7 151.6 149.3 146.6 142.7 139.4 135.9 132.8 127.9 121.6 115.6 103 96.3 95.2 91 81.6 85.3 82 68.5 61.4 53 43.9 47.7 34.3 30.2 27.1 23.1 23.4 19.6 27.5 31.1 38.7 49.2 58.8 67.3 diff --git a/test/test-terrain.cpp b/test/test-terrain.cpp new file mode 100644 index 0000000..b2358d6 --- /dev/null +++ b/test/test-terrain.cpp @@ -0,0 +1,48 @@ +#define BOOST_TEST_MODULE terrain +#include +#include + +#include + +class TestTerrainMesh : public TerrainMesh { +public: + TestTerrainMesh() : TerrainMesh {FIXTURESDIR "height/SD19.asc"} { } +}; + +constexpr size_t ncols = 200, nrows = 200, xllcorner = 310000, yllcorner = 490000, cellsize = 50; + +BOOST_FIXTURE_TEST_SUITE(ttm, TestTerrainMesh); + +BOOST_AUTO_TEST_CASE(loadSuccess) +{ + BOOST_CHECK_EQUAL(ncols * nrows, n_vertices()); + BOOST_CHECK_EQUAL(2 * (ncols - 1) * (nrows - 1), n_faces()); +} + +BOOST_AUTO_TEST_CASE(normalsAllPointUp) +{ + BOOST_CHECK(std::all_of(faces_begin(), faces_end(), [this](auto && vh) { + return normal(vh).z > 0; + })); + BOOST_CHECK(std::all_of(vertices_begin(), vertices_end(), [this](auto && vh) { + return normal(vh).z > 0; + })); +} + +BOOST_AUTO_TEST_CASE(trianglesContainsPoints) +{ + const auto face = face_handle(0); + auto vertices = cfv_iter(face); + + BOOST_TEST_CONTEXT(point(*vertices++) << point(*vertices++) << point(*vertices++)) { + BOOST_CHECK(triangleContainsPoint(glm::vec2 {xllcorner, yllcorner}, face)); + BOOST_CHECK(triangleContainsPoint(glm::vec2 {xllcorner + cellsize, yllcorner + cellsize}, face)); + BOOST_CHECK(triangleContainsPoint(glm::vec2 {xllcorner, yllcorner + cellsize}, face)); + BOOST_CHECK(triangleContainsPoint(glm::vec2 {xllcorner + 1, yllcorner + 1}, face)); + BOOST_CHECK(triangleContainsPoint(glm::vec2 {xllcorner + 1, yllcorner + 2}, face)); + BOOST_CHECK(!triangleContainsPoint(glm::vec2 {xllcorner + 3, yllcorner + 2}, face)); + BOOST_CHECK(!triangleContainsPoint(glm::vec2 {xllcorner + cellsize, yllcorner}, face)); + } +} + +BOOST_AUTO_TEST_SUITE_END(); -- cgit v1.2.3 From 49a422ed91289a31142a8c0fb8b7030d2dea98a1 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 29 Oct 2023 14:11:46 +0000 Subject: Initial commit of findPoint on terrain 2D navigate from a default/given starting point, possible scope for improvement, but it's not exactly slow; <9ms --- game/terrain2.cpp | 33 ++++++++++++++++++++++++++++++++- game/terrain2.h | 4 ++++ test/Jamfile.jam | 4 +++- test/perf-terrain.cpp | 18 ++++++++++++++++++ test/test-terrain.cpp | 19 +++++++++++++++++++ 5 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 test/perf-terrain.cpp diff --git a/game/terrain2.cpp b/game/terrain2.cpp index 83df3fa..cc0bf90 100644 --- a/game/terrain2.cpp +++ b/game/terrain2.cpp @@ -48,6 +48,32 @@ TerrainMesh::TerrainMesh(const std::filesystem::path & input) update_vertex_normals(); }; +OpenMesh::FaceHandle +TerrainMesh::findPoint(glm::vec2 p) const +{ + return findPoint(p, *faces_begin()); +} + +OpenMesh::FaceHandle +TerrainMesh::findPoint(glm::vec2 p, OpenMesh::FaceHandle f) const +{ + ConstFaceVertexIter vertices; + while (f.is_valid() && !triangleContainsPoint(p, vertices = cfv_iter(f))) { + for (auto next = cfh_iter(f); next.is_valid(); ++next) { + f = opposite_face_handle(*next); + if (f.is_valid()) { + const auto e1 = point(to_vertex_handle(*next)); + const auto e2 = point(to_vertex_handle(opposite_halfedge_handle(*next))); + if ((e2.x - e1.x) * (p.y - e1.y) > (e2.y - e1.y) * (p.x - e1.x)) { + break; + } + } + f.reset(); + } + } + return f; +} + bool TerrainMesh::triangleContainsPoint(const glm::vec2 p, const glm::vec2 a, const glm::vec2 b, const glm::vec2 c) { @@ -61,6 +87,11 @@ TerrainMesh::triangleContainsPoint(const glm::vec2 p, const glm::vec2 a, const g bool TerrainMesh::triangleContainsPoint(const glm::vec2 p, FaceHandle face) const { - auto vertices = cfv_iter(face); + return triangleContainsPoint(p, cfv_iter(face)); +} + +bool +TerrainMesh::triangleContainsPoint(const glm::vec2 p, ConstFaceVertexIter vertices) const +{ return triangleContainsPoint(p, point(*vertices++), point(*vertices++), point(*vertices++)); } diff --git a/game/terrain2.h b/game/terrain2.h index d2da8d0..713fe23 100644 --- a/game/terrain2.h +++ b/game/terrain2.h @@ -18,7 +18,11 @@ class TerrainMesh : public OpenMesh::TriMesh_ArrayKernelT { public: explicit TerrainMesh(const std::filesystem::path &); + [[nodiscard]] FaceHandle findPoint(glm::vec2) const; + [[nodiscard]] FaceHandle findPoint(glm::vec2, FaceHandle start) const; + protected: [[nodiscard]] static bool triangleContainsPoint(const glm::vec2, const glm::vec2, const glm::vec2, const glm::vec2); [[nodiscard]] bool triangleContainsPoint(const glm::vec2, FaceHandle) const; + [[nodiscard]] bool triangleContainsPoint(const glm::vec2, ConstFaceVertexIter) const; }; diff --git a/test/Jamfile.jam b/test/Jamfile.jam index eab3996..7fa7bfc 100644 --- a/test/Jamfile.jam +++ b/test/Jamfile.jam @@ -61,9 +61,11 @@ run test-instancing.cpp : : : test ; run test-glContainer.cpp : : : test ; run test-pack.cpp : : : test ; run test-terrain.cpp : : : test ..//OpenMeshCore ; +run perf-terrain.cpp : : : test ..//OpenMeshCore benchmark ; compile test-static-enumDetails.cpp ; compile test-static-stream_support.cpp ; explicit perf-assetFactory ; explicit perf-persistence ; -alias perf : perf-assetFactory perf-persistence ; +explicit perf-terrain ; +alias perf : perf-assetFactory perf-persistence perf-terrain ; explicit perf ; diff --git a/test/perf-terrain.cpp b/test/perf-terrain.cpp new file mode 100644 index 0000000..e998f60 --- /dev/null +++ b/test/perf-terrain.cpp @@ -0,0 +1,18 @@ +#include +#include + +namespace { + const TerrainMesh tm {FIXTURESDIR "height/SD19.asc"}; + + void + terrain_findPoint(benchmark::State & state) + { + for (auto _ : state) { + benchmark::DoNotOptimize(tm.findPoint({315555, 495556})); + } + } +} + +BENCHMARK(terrain_findPoint); + +BENCHMARK_MAIN(); diff --git a/test/test-terrain.cpp b/test/test-terrain.cpp index b2358d6..d062853 100644 --- a/test/test-terrain.cpp +++ b/test/test-terrain.cpp @@ -1,4 +1,5 @@ #define BOOST_TEST_MODULE terrain +#include #include #include @@ -46,3 +47,21 @@ BOOST_AUTO_TEST_CASE(trianglesContainsPoints) } BOOST_AUTO_TEST_SUITE_END(); + +using FindPointData = std::tuple; + +static const TestTerrainMesh fixedTerrtain; + +// No boundary cases as these can produce different valid results depending on starting point +BOOST_DATA_TEST_CASE(findPointOnTerrain, + boost::unit_test::data::make({ + {{0, 0}, -1}, {{xllcorner, 0}, -1}, {{0, yllcorner}, -1}, {{xllcorner + 1, yllcorner + 2}, 0}, + {{xllcorner + (cellsize * (nrows - 1)) - 2, yllcorner + (cellsize * (ncols - 1)) - 1}, 79200}, + {{315555, 495556}, 44400}, // perf test target + }) + * boost::unit_test::data::make( + {0, 1, 2, 3, 4, 5, 6, 10, 100, 150, 200, 1000, 1234, 17439, 79201, 79200, 79199}), + p, fh, start) +{ + BOOST_CHECK_EQUAL(fh, fixedTerrtain.findPoint(p, TerrainMesh::FaceHandle(start)).idx()); +} -- cgit v1.2.3 From 583aa8eb078090fd48c6d6db8ee69da5ad8811fb Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Tue, 31 Oct 2023 00:29:35 +0000 Subject: Initial commit of walk/walkUtil terrain --- game/terrain2.cpp | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++- game/terrain2.h | 3 +++ test/test-terrain.cpp | 41 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+), 1 deletion(-) diff --git a/game/terrain2.cpp b/game/terrain2.cpp index cc0bf90..3e24778 100644 --- a/game/terrain2.cpp +++ b/game/terrain2.cpp @@ -54,6 +54,28 @@ TerrainMesh::findPoint(glm::vec2 p) const return findPoint(p, *faces_begin()); } +namespace { + [[nodiscard]] constexpr inline bool + pointLeftOfLine(const glm::vec2 p, const glm::vec2 e1, const glm::vec2 e2) + { + return (e2.x - e1.x) * (p.y - e1.y) > (e2.y - e1.y) * (p.x - e1.x); + } + + static_assert(pointLeftOfLine({1, 2}, {1, 1}, {2, 2})); + static_assert(pointLeftOfLine({2, 1}, {2, 2}, {1, 1})); + static_assert(pointLeftOfLine({2, 2}, {1, 2}, {2, 1})); + static_assert(pointLeftOfLine({1, 1}, {2, 1}, {1, 2})); + + [[nodiscard]] constexpr inline bool + linesCross(const glm::vec2 a1, const glm::vec2 a2, const glm::vec2 b1, const glm::vec2 b2) + { + return pointLeftOfLine(a2, b1, b2) && pointLeftOfLine(a1, b2, b1) && pointLeftOfLine(b1, a1, a2) + && pointLeftOfLine(b2, a2, a1); + } + + static_assert(linesCross({1, 1}, {2, 2}, {1, 2}, {2, 1})); +} + OpenMesh::FaceHandle TerrainMesh::findPoint(glm::vec2 p, OpenMesh::FaceHandle f) const { @@ -64,7 +86,7 @@ TerrainMesh::findPoint(glm::vec2 p, OpenMesh::FaceHandle f) const if (f.is_valid()) { const auto e1 = point(to_vertex_handle(*next)); const auto e2 = point(to_vertex_handle(opposite_halfedge_handle(*next))); - if ((e2.x - e1.x) * (p.y - e1.y) > (e2.y - e1.y) * (p.x - e1.x)) { + if (pointLeftOfLine(p, e1, e2)) { break; } } @@ -74,6 +96,37 @@ TerrainMesh::findPoint(glm::vec2 p, OpenMesh::FaceHandle f) const return f; } +void +TerrainMesh::walk(const glm::vec2 from, const glm::vec2 to, const std::function & op) const +{ + walkUntil(from, to, [&op](const auto & fh) { + op(fh); + return false; + }); +} + +void +TerrainMesh::walkUntil(const glm::vec2 from, const glm::vec2 to, const std::function & op) const +{ + auto f = findPoint(from); + assert(f.is_valid()); // TODO replace with a boundary search + FaceHandle previousFace; + while (f.is_valid() && !op(f)) { + for (auto next = cfh_iter(f); next.is_valid(); ++next) { + f = opposite_face_handle(*next); + if (f.is_valid() && f != previousFace) { + const auto e1 = point(to_vertex_handle(*next)); + const auto e2 = point(to_vertex_handle(opposite_halfedge_handle(*next))); + if (linesCross(from, to, e1, e2)) { + previousFace = f; + break; + } + } + f.reset(); + } + } +} + bool TerrainMesh::triangleContainsPoint(const glm::vec2 p, const glm::vec2 a, const glm::vec2 b, const glm::vec2 c) { diff --git a/game/terrain2.h b/game/terrain2.h index 713fe23..848c36e 100644 --- a/game/terrain2.h +++ b/game/terrain2.h @@ -21,6 +21,9 @@ public: [[nodiscard]] FaceHandle findPoint(glm::vec2) const; [[nodiscard]] FaceHandle findPoint(glm::vec2, FaceHandle start) const; + void walk(const glm::vec2 from, const glm::vec2 to, const std::function & op) const; + void walkUntil(const glm::vec2 from, const glm::vec2 to, const std::function & op) const; + protected: [[nodiscard]] static bool triangleContainsPoint(const glm::vec2, const glm::vec2, const glm::vec2, const glm::vec2); [[nodiscard]] bool triangleContainsPoint(const glm::vec2, FaceHandle) const; diff --git a/test/test-terrain.cpp b/test/test-terrain.cpp index d062853..429207c 100644 --- a/test/test-terrain.cpp +++ b/test/test-terrain.cpp @@ -65,3 +65,44 @@ BOOST_DATA_TEST_CASE(findPointOnTerrain, { BOOST_CHECK_EQUAL(fh, fixedTerrtain.findPoint(p, TerrainMesh::FaceHandle(start)).idx()); } + +using WalkTerrainData = std::tuple>; + +BOOST_DATA_TEST_CASE(walkTerrain, + boost::unit_test::data::make({ + {{310002, 490003}, {310002, 490003}, {0}}, + {{310003, 490002}, {310003, 490002}, {1}}, + {{310002, 490003}, {310003, 490002}, {0, 1}}, + {{310003, 490002}, {310002, 490003}, {1, 0}}, + {{310002, 490003}, {310202, 490003}, {0, 1, 2, 3, 4, 5, 6, 7, 8}}, + {{310202, 490003}, {310002, 490003}, {8, 7, 6, 5, 4, 3, 2, 1, 0}}, + {{310002, 490003}, {310002, 490203}, {0, 399, 398, 797, 796, 1195, 1194, 1593, 1592}}, + }), + from, to, visits) +{ + std::vector visited; + BOOST_CHECK_NO_THROW(fixedTerrtain.walk(from, to, [&visited](auto fh) { + visited.emplace_back(fh.idx()); + })); + BOOST_CHECK_EQUAL_COLLECTIONS(visited.begin(), visited.end(), visits.begin(), visits.end()); +} + +BOOST_DATA_TEST_CASE(walkTerrainUntil, + boost::unit_test::data::make({ + {{310002, 490003}, {310002, 490003}, {0}}, + {{310003, 490002}, {310003, 490002}, {1}}, + {{310002, 490003}, {310003, 490002}, {0, 1}}, + {{310003, 490002}, {310002, 490003}, {1, 0}}, + {{310002, 490003}, {310202, 490003}, {0, 1, 2, 3, 4}}, + {{310202, 490003}, {310002, 490003}, {8, 7, 6, 5, 4}}, + {{310002, 490003}, {310002, 490203}, {0, 399, 398, 797, 796}}, + }), + from, to, visits) +{ + std::vector visited; + BOOST_CHECK_NO_THROW(fixedTerrtain.walkUntil(from, to, [&visited](auto fh) { + visited.emplace_back(fh.idx()); + return visited.size() >= 5; + })); + BOOST_CHECK_EQUAL_COLLECTIONS(visited.begin(), visited.end(), visits.begin(), visits.end()); +} -- cgit v1.2.3 From a0f1dc90aabd4cb5cfe2aef7116af170e6d0b953 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Tue, 31 Oct 2023 01:26:58 +0000 Subject: Helper type for storing/passing/returning a point and its containing face point is const as face is mutable as a cache of the face containing point. --- game/terrain2.cpp | 18 ++++++++++++++++++ game/terrain2.h | 10 ++++++++++ test/test-terrain.cpp | 9 +++++++++ 3 files changed, 37 insertions(+) diff --git a/game/terrain2.cpp b/game/terrain2.cpp index 3e24778..e98cebb 100644 --- a/game/terrain2.cpp +++ b/game/terrain2.cpp @@ -54,6 +54,24 @@ TerrainMesh::findPoint(glm::vec2 p) const return findPoint(p, *faces_begin()); } +bool +TerrainMesh::locate(const TerrainMesh::PointFace & pointFace, FaceHandle start) const +{ + if (pointFace.face.is_valid()) { + assert(triangleContainsPoint(pointFace.point, pointFace.face)); + return true; + } + else { + return (pointFace.face = findPoint(pointFace.point, start)).is_valid(); + } +} + +bool +TerrainMesh::locate(const TerrainMesh::PointFace & pointFace) const +{ + return locate(pointFace, *faces_begin()); +} + namespace { [[nodiscard]] constexpr inline bool pointLeftOfLine(const glm::vec2 p, const glm::vec2 e1, const glm::vec2 e2) diff --git a/game/terrain2.h b/game/terrain2.h index 848c36e..e516719 100644 --- a/game/terrain2.h +++ b/game/terrain2.h @@ -18,6 +18,13 @@ class TerrainMesh : public OpenMesh::TriMesh_ArrayKernelT { public: explicit TerrainMesh(const std::filesystem::path &); + struct PointFace { + PointFace(const glm::vec2 p) : point {p} { } + + const glm::vec2 point; + mutable FaceHandle face {}; + }; + [[nodiscard]] FaceHandle findPoint(glm::vec2) const; [[nodiscard]] FaceHandle findPoint(glm::vec2, FaceHandle start) const; @@ -28,4 +35,7 @@ protected: [[nodiscard]] static bool triangleContainsPoint(const glm::vec2, const glm::vec2, const glm::vec2, const glm::vec2); [[nodiscard]] bool triangleContainsPoint(const glm::vec2, FaceHandle) const; [[nodiscard]] bool triangleContainsPoint(const glm::vec2, ConstFaceVertexIter) const; + + bool locate(const PointFace &) const; + bool locate(const PointFace &, FaceHandle start) const; }; diff --git a/test/test-terrain.cpp b/test/test-terrain.cpp index 429207c..f737f4f 100644 --- a/test/test-terrain.cpp +++ b/test/test-terrain.cpp @@ -46,6 +46,15 @@ BOOST_AUTO_TEST_CASE(trianglesContainsPoints) } } +BOOST_AUTO_TEST_CASE(locatePointFace) +{ + const PointFace pf {{310002, 490003}}; + BOOST_CHECK(!pf.face.is_valid()); + BOOST_CHECK(locate(pf)); + BOOST_CHECK(pf.face.is_valid()); + BOOST_CHECK_EQUAL(pf.face.idx(), 0); +} + BOOST_AUTO_TEST_SUITE_END(); using FindPointData = std::tuple; -- cgit v1.2.3 From a4f1c55ad34f6be9adc9573fd7f26507ae2c59b0 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Tue, 31 Oct 2023 02:40:03 +0000 Subject: Update walk/walkUntil to work on PointFace from parameter --- game/terrain2.cpp | 11 ++++++----- game/terrain2.h | 4 ++-- test/test-terrain.cpp | 14 ++++++++++++++ 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/game/terrain2.cpp b/game/terrain2.cpp index e98cebb..5d1c595 100644 --- a/game/terrain2.cpp +++ b/game/terrain2.cpp @@ -115,7 +115,7 @@ TerrainMesh::findPoint(glm::vec2 p, OpenMesh::FaceHandle f) const } void -TerrainMesh::walk(const glm::vec2 from, const glm::vec2 to, const std::function & op) const +TerrainMesh::walk(const PointFace & from, const glm::vec2 to, const std::function & op) const { walkUntil(from, to, [&op](const auto & fh) { op(fh); @@ -124,10 +124,11 @@ TerrainMesh::walk(const glm::vec2 from, const glm::vec2 to, const std::function< } void -TerrainMesh::walkUntil(const glm::vec2 from, const glm::vec2 to, const std::function & op) const +TerrainMesh::walkUntil(const PointFace & from, const glm::vec2 to, const std::function & op) const { - auto f = findPoint(from); - assert(f.is_valid()); // TODO replace with a boundary search + locate(from); + assert(from.face.is_valid()); // TODO replace with a boundary search + auto f = from.face; FaceHandle previousFace; while (f.is_valid() && !op(f)) { for (auto next = cfh_iter(f); next.is_valid(); ++next) { @@ -135,7 +136,7 @@ TerrainMesh::walkUntil(const glm::vec2 from, const glm::vec2 to, const std::func if (f.is_valid() && f != previousFace) { const auto e1 = point(to_vertex_handle(*next)); const auto e2 = point(to_vertex_handle(opposite_halfedge_handle(*next))); - if (linesCross(from, to, e1, e2)) { + if (linesCross(from.point, to, e1, e2)) { previousFace = f; break; } diff --git a/game/terrain2.h b/game/terrain2.h index e516719..1a4e263 100644 --- a/game/terrain2.h +++ b/game/terrain2.h @@ -28,8 +28,8 @@ public: [[nodiscard]] FaceHandle findPoint(glm::vec2) const; [[nodiscard]] FaceHandle findPoint(glm::vec2, FaceHandle start) const; - void walk(const glm::vec2 from, const glm::vec2 to, const std::function & op) const; - void walkUntil(const glm::vec2 from, const glm::vec2 to, const std::function & op) const; + void walk(const PointFace & from, const glm::vec2 to, const std::function & op) const; + void walkUntil(const PointFace & from, const glm::vec2 to, const std::function & op) const; protected: [[nodiscard]] static bool triangleContainsPoint(const glm::vec2, const glm::vec2, const glm::vec2, const glm::vec2); diff --git a/test/test-terrain.cpp b/test/test-terrain.cpp index f737f4f..bf30179 100644 --- a/test/test-terrain.cpp +++ b/test/test-terrain.cpp @@ -96,6 +96,20 @@ BOOST_DATA_TEST_CASE(walkTerrain, BOOST_CHECK_EQUAL_COLLECTIONS(visited.begin(), visited.end(), visits.begin(), visits.end()); } +BOOST_DATA_TEST_CASE(walkTerrainSetsFromFace, + boost::unit_test::data::make({ + {{310002, 490003}, {310002, 490003}, {0}}, + {{310003, 490002}, {310003, 490002}, {1}}, + {{310002, 490003}, {310003, 490002}, {0, 1}}, + {{310003, 490002}, {310002, 490003}, {1, 0}}, + }), + from, to, visits) +{ + TerrainMesh::PointFace pf {from}; + BOOST_CHECK_NO_THROW(fixedTerrtain.walk(pf, to, [](auto) {})); + BOOST_CHECK_EQUAL(pf.face.idx(), visits.front()); +} + BOOST_DATA_TEST_CASE(walkTerrainUntil, boost::unit_test::data::make({ {{310002, 490003}, {310002, 490003}, {0}}, -- cgit v1.2.3 From b46cf55d66f262778bf0353650f00620c7740f2a Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Tue, 31 Oct 2023 19:36:16 +0000 Subject: Make PointFace harder to misuse --- game/terrain2.cpp | 33 +++++++++++++++++++++------------ game/terrain2.h | 21 +++++++++++++++++---- test/test-terrain.cpp | 16 +++++++++++----- 3 files changed, 49 insertions(+), 21 deletions(-) diff --git a/game/terrain2.cpp b/game/terrain2.cpp index 5d1c595..8d29143 100644 --- a/game/terrain2.cpp +++ b/game/terrain2.cpp @@ -54,22 +54,32 @@ TerrainMesh::findPoint(glm::vec2 p) const return findPoint(p, *faces_begin()); } -bool -TerrainMesh::locate(const TerrainMesh::PointFace & pointFace, FaceHandle start) const +TerrainMesh::PointFace::PointFace(const glm::vec2 p, const TerrainMesh * mesh) : + PointFace {p, mesh, *mesh->faces_begin()} +{ +} + +TerrainMesh::PointFace::PointFace(const glm::vec2 p, const TerrainMesh * mesh, FaceHandle start) : + PointFace {p, mesh->findPoint(p, start)} { - if (pointFace.face.is_valid()) { - assert(triangleContainsPoint(pointFace.point, pointFace.face)); - return true; +} + +TerrainMesh::FaceHandle +TerrainMesh::PointFace::face(const TerrainMesh * mesh, FaceHandle start) const +{ + if (_face.is_valid()) { + assert(mesh->triangleContainsPoint(point, _face)); + return _face; } else { - return (pointFace.face = findPoint(pointFace.point, start)).is_valid(); + return (_face = mesh->findPoint(point, start)); } } -bool -TerrainMesh::locate(const TerrainMesh::PointFace & pointFace) const +TerrainMesh::FaceHandle +TerrainMesh::PointFace::face(const TerrainMesh * mesh) const { - return locate(pointFace, *faces_begin()); + return face(mesh, *mesh->faces_begin()); } namespace { @@ -126,9 +136,8 @@ TerrainMesh::walk(const PointFace & from, const glm::vec2 to, const std::functio void TerrainMesh::walkUntil(const PointFace & from, const glm::vec2 to, const std::function & op) const { - locate(from); - assert(from.face.is_valid()); // TODO replace with a boundary search - auto f = from.face; + assert(from.face(this).is_valid()); // TODO replace with a boundary search + auto f = from.face(this); FaceHandle previousFace; while (f.is_valid() && !op(f)) { for (auto next = cfh_iter(f); next.is_valid(); ++next) { diff --git a/game/terrain2.h b/game/terrain2.h index 1a4e263..641d608 100644 --- a/game/terrain2.h +++ b/game/terrain2.h @@ -19,10 +19,26 @@ public: explicit TerrainMesh(const std::filesystem::path &); struct PointFace { + // NOLINTNEXTLINE(hicpp-explicit-conversions) PointFace(const glm::vec2 p) : point {p} { } + PointFace(const glm::vec2 p, FaceHandle face) : point {p}, _face {face} { } + + PointFace(const glm::vec2 p, const TerrainMesh *); + PointFace(const glm::vec2 p, const TerrainMesh *, FaceHandle start); + const glm::vec2 point; - mutable FaceHandle face {}; + [[nodiscard]] FaceHandle face(const TerrainMesh *) const; + [[nodiscard]] FaceHandle face(const TerrainMesh *, FaceHandle start) const; + + [[nodiscard]] bool + isLocated() const + { + return _face.is_valid(); + } + + private: + mutable FaceHandle _face {}; }; [[nodiscard]] FaceHandle findPoint(glm::vec2) const; @@ -35,7 +51,4 @@ protected: [[nodiscard]] static bool triangleContainsPoint(const glm::vec2, const glm::vec2, const glm::vec2, const glm::vec2); [[nodiscard]] bool triangleContainsPoint(const glm::vec2, FaceHandle) const; [[nodiscard]] bool triangleContainsPoint(const glm::vec2, ConstFaceVertexIter) const; - - bool locate(const PointFace &) const; - bool locate(const PointFace &, FaceHandle start) const; }; diff --git a/test/test-terrain.cpp b/test/test-terrain.cpp index bf30179..bf73356 100644 --- a/test/test-terrain.cpp +++ b/test/test-terrain.cpp @@ -49,10 +49,16 @@ BOOST_AUTO_TEST_CASE(trianglesContainsPoints) BOOST_AUTO_TEST_CASE(locatePointFace) { const PointFace pf {{310002, 490003}}; - BOOST_CHECK(!pf.face.is_valid()); - BOOST_CHECK(locate(pf)); - BOOST_CHECK(pf.face.is_valid()); - BOOST_CHECK_EQUAL(pf.face.idx(), 0); + BOOST_CHECK(!pf.isLocated()); + BOOST_CHECK(pf.face(this).is_valid()); + BOOST_CHECK_EQUAL(pf.face(this).idx(), 0); +} + +BOOST_AUTO_TEST_CASE(preLocatePointFace) +{ + const PointFace pf {{310002, 490003}, this}; + BOOST_CHECK(pf.isLocated()); + BOOST_CHECK_EQUAL(pf.face(this).idx(), 0); } BOOST_AUTO_TEST_SUITE_END(); @@ -107,7 +113,7 @@ BOOST_DATA_TEST_CASE(walkTerrainSetsFromFace, { TerrainMesh::PointFace pf {from}; BOOST_CHECK_NO_THROW(fixedTerrtain.walk(pf, to, [](auto) {})); - BOOST_CHECK_EQUAL(pf.face.idx(), visits.front()); + BOOST_CHECK_EQUAL(pf.face(&fixedTerrtain).idx(), visits.front()); } BOOST_DATA_TEST_CASE(walkTerrainUntil, -- cgit v1.2.3 From 4f66e69de7dc327cc8bd285e2d16df21f55afbdc Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 2 Nov 2023 20:34:02 +0000 Subject: Add test-terrain dependency on sample height data --- test/Jamfile.jam | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Jamfile.jam b/test/Jamfile.jam index 7fa7bfc..d88a238 100644 --- a/test/Jamfile.jam +++ b/test/Jamfile.jam @@ -60,7 +60,7 @@ run test-worker.cpp ; run test-instancing.cpp : : : test ; run test-glContainer.cpp : : : test ; run test-pack.cpp : : : test ; -run test-terrain.cpp : : : test ..//OpenMeshCore ; +run test-terrain.cpp : -- : fixtures/height/SD19.asc : test ..//OpenMeshCore ; run perf-terrain.cpp : : : test ..//OpenMeshCore benchmark ; compile test-static-enumDetails.cpp ; compile test-static-stream_support.cpp ; -- cgit v1.2.3 From 1117f91396da00fc48158866ff0ffd1883c4cbd1 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 2 Nov 2023 20:37:08 +0000 Subject: Generic N-dimensional terrain triangle --- game/terrain2.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/game/terrain2.h b/game/terrain2.h index 641d608..c2c3d19 100644 --- a/game/terrain2.h +++ b/game/terrain2.h @@ -1,5 +1,6 @@ #pragma once +#include "collections.h" // IWYU pragma: keep IterableCollection #include #include #include @@ -41,6 +42,19 @@ public: mutable FaceHandle _face {}; }; + template struct Triangle : public glm::vec<3, glm::vec> { + using base = glm::vec<3, glm::vec>; + using base::base; + + template Triangle(const TerrainMesh * m, Range range) + { + assert(std::distance(range.begin(), range.end()) == 3); + std::transform(range.begin(), range.end(), &base::operator[](0), [m](auto vh) { + return m->point(vh); + }); + } + }; + [[nodiscard]] FaceHandle findPoint(glm::vec2) const; [[nodiscard]] FaceHandle findPoint(glm::vec2, FaceHandle start) const; -- cgit v1.2.3 From 8a5d36623e4fa261aea16731954c9987dcbb1ef1 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 2 Nov 2023 20:38:10 +0000 Subject: Terrain mesh method for getting the height/position at a point on the surface --- game/terrain2.cpp | 11 +++++++++++ game/terrain2.h | 2 ++ test/test-terrain.cpp | 23 +++++++++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/game/terrain2.cpp b/game/terrain2.cpp index 8d29143..b129284 100644 --- a/game/terrain2.cpp +++ b/game/terrain2.cpp @@ -1,5 +1,7 @@ #include "terrain2.h" #include +#include +#include TerrainMesh::TerrainMesh(const std::filesystem::path & input) { @@ -124,6 +126,15 @@ TerrainMesh::findPoint(glm::vec2 p, OpenMesh::FaceHandle f) const return f; } +glm::vec3 +TerrainMesh::positionAt(const PointFace & p) const +{ + glm::vec3 out {}; + Triangle<3> t {this, fv_range(p.face(this))}; + glm::intersectLineTriangle(p.point ^ 0.F, up, t[0], t[1], t[2], out); + return p.point ^ out[0]; +} + void TerrainMesh::walk(const PointFace & from, const glm::vec2 to, const std::function & op) const { diff --git a/game/terrain2.h b/game/terrain2.h index c2c3d19..f1d288e 100644 --- a/game/terrain2.h +++ b/game/terrain2.h @@ -58,6 +58,8 @@ public: [[nodiscard]] FaceHandle findPoint(glm::vec2) const; [[nodiscard]] FaceHandle findPoint(glm::vec2, FaceHandle start) const; + [[nodiscard]] glm::vec3 positionAt(const PointFace &) const; + void walk(const PointFace & from, const glm::vec2 to, const std::function & op) const; void walkUntil(const PointFace & from, const glm::vec2 to, const std::function & op) const; diff --git a/test/test-terrain.cpp b/test/test-terrain.cpp index bf73356..38cb51f 100644 --- a/test/test-terrain.cpp +++ b/test/test-terrain.cpp @@ -1,4 +1,5 @@ #define BOOST_TEST_MODULE terrain +#include "testHelpers.h" #include #include #include @@ -81,6 +82,28 @@ BOOST_DATA_TEST_CASE(findPointOnTerrain, BOOST_CHECK_EQUAL(fh, fixedTerrtain.findPoint(p, TerrainMesh::FaceHandle(start)).idx()); } +using FindPositionData = std::tuple; + +BOOST_DATA_TEST_CASE(findPositionAt, + boost::unit_test::data::make({ + // corners + {{310000, 490000}, 32.8F}, + {{310050, 490050}, 33.0F}, + {{310000, 490050}, 32.7F}, + {{310050, 490000}, 33.2F}, + {{310750, 490150}, 58.4F}, + // midpoints + {{310025, 490025}, 32.9F}, + {{310025, 490050}, 32.85F}, + {{310000, 490025}, 32.75F}, + // other + {{310751, 490152}, 58.326F}, + }), + p, h) +{ + BOOST_CHECK_CLOSE_VEC(fixedTerrtain.positionAt(p), p ^ h); +} + using WalkTerrainData = std::tuple>; BOOST_DATA_TEST_CASE(walkTerrain, -- cgit v1.2.3 From 92f373bb676fa0b272ca2ac6091890f651377d01 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 3 Nov 2023 19:57:02 +0000 Subject: Increase BOOST_CHECK_CLOSE_VEC stream precision Spent way too long trying to explain a test failure because the precision of the debug didn't show the differences. --- test/testHelpers.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/testHelpers.h b/test/testHelpers.h index 54b7fc6..79e966a 100644 --- a/test/testHelpers.h +++ b/test/testHelpers.h @@ -2,6 +2,7 @@ #include #include +#include // IWYU pragma: keep std::setprecision #include std::unique_ptr uasprintf(const char * fmt, ...) __attribute__((format(printf, 1, 2))); @@ -9,7 +10,7 @@ std::unique_ptr uasprintf(const char * fmt, ...) __attrib #define BOOST_CHECK_CLOSE_VEC(a_, b_) \ { \ const auto a {a_}, b {b_}; \ - BOOST_TEST_CONTEXT("BOOST_CHECK_CLOSE_VEC(" << a << ", " << b << ")") { \ + BOOST_TEST_CONTEXT("BOOST_CHECK_CLOSE_VEC(" << std::setprecision(8) << a << ", " << b << ")") { \ BOOST_CHECK_LT(glm::length(a - b), 0.1F); \ } \ } -- cgit v1.2.3 From 889baa0abe996976d8717e7e411961804b853465 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 3 Nov 2023 20:10:56 +0000 Subject: Helper to get cartesian position from baricentric on Triangle --- game/terrain2.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/game/terrain2.h b/game/terrain2.h index f1d288e..da9f823 100644 --- a/game/terrain2.h +++ b/game/terrain2.h @@ -53,6 +53,13 @@ public: return m->point(vh); }); } + + glm::vec + operator*(glm::vec2 bari) const + { + const auto & t {*this}; + return t[0] + ((t[1] - t[0]) * bari.x) + ((t[2] - t[1]) * bari.y); + } }; [[nodiscard]] FaceHandle findPoint(glm::vec2) const; -- cgit v1.2.3 From 3931bda936aba6ddae26c1d9f1d450781df800e8 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 3 Nov 2023 20:12:03 +0000 Subject: Implement terrain intersect ray --- game/terrain2.cpp | 23 +++++++++++++++++++++++ game/terrain2.h | 4 ++++ test/test-terrain.cpp | 12 ++++++++++++ 3 files changed, 39 insertions(+) diff --git a/game/terrain2.cpp b/game/terrain2.cpp index b129284..d1af221 100644 --- a/game/terrain2.cpp +++ b/game/terrain2.cpp @@ -135,6 +135,29 @@ TerrainMesh::positionAt(const PointFace & p) const return p.point ^ out[0]; } +[[nodiscard]] std::optional +TerrainMesh::intersectRay(const Ray & ray) const +{ + return intersectRay(ray, findPoint(ray.start)); +} + +[[nodiscard]] std::optional +TerrainMesh::intersectRay(const Ray & ray, FaceHandle face) const +{ + std::optional out; + walkUntil(PointFace {ray.start, face}, ray.start + (ray.direction * 10000.F), [&out, &ray, this](FaceHandle face) { + glm::vec2 bari {}; + float dist {}; + Triangle<3> t {this, fv_range(face)}; + if (glm::intersectRayTriangle(ray.start, ray.direction, t[0], t[1], t[2], bari, dist)) { + out = t * bari; + return true; + } + return false; + }); + return out; +} + void TerrainMesh::walk(const PointFace & from, const glm::vec2 to, const std::function & op) const { diff --git a/game/terrain2.h b/game/terrain2.h index da9f823..5539a50 100644 --- a/game/terrain2.h +++ b/game/terrain2.h @@ -1,9 +1,11 @@ #pragma once #include "collections.h" // IWYU pragma: keep IterableCollection +#include "ray.h" #include #include #include +#include #include struct TerrainTraits : public OpenMesh::DefaultTraits { @@ -66,6 +68,8 @@ public: [[nodiscard]] FaceHandle findPoint(glm::vec2, FaceHandle start) const; [[nodiscard]] glm::vec3 positionAt(const PointFace &) const; + [[nodiscard]] std::optional intersectRay(const Ray &) const; + [[nodiscard]] std::optional intersectRay(const Ray &, FaceHandle start) const; void walk(const PointFace & from, const glm::vec2 to, const std::function & op) const; void walkUntil(const PointFace & from, const glm::vec2 to, const std::function & op) const; diff --git a/test/test-terrain.cpp b/test/test-terrain.cpp index 38cb51f..53eebfb 100644 --- a/test/test-terrain.cpp +++ b/test/test-terrain.cpp @@ -104,6 +104,18 @@ BOOST_DATA_TEST_CASE(findPositionAt, BOOST_CHECK_CLOSE_VEC(fixedTerrtain.positionAt(p), p ^ h); } +using FindRayIntersectData = std::tuple; + +BOOST_DATA_TEST_CASE(findRayIntersect, + boost::unit_test::data::make({ + {{310000, 490000, 50}, {1, 1, -2}, {310008.59, 490008.59, 32.834301}}, + {{310000, 490000, 50}, {1, 1, -1}, {310017.12, 490017.12, 32.868526}}, + }), + p, d, i) +{ + BOOST_CHECK_CLOSE_VEC(fixedTerrtain.intersectRay({p, d}).value(), i); +} + using WalkTerrainData = std::tuple>; BOOST_DATA_TEST_CASE(walkTerrain, -- cgit v1.2.3 From 19e60cf08ba8800b7214c0865ebb2fc6b880c7bd Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 3 Nov 2023 21:31:35 +0000 Subject: Don't request a specific OpenGL version, just check we get something sufficient from gladLoadGL --- ui/applicationBase.cpp | 3 --- ui/window.cpp | 8 +++----- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/ui/applicationBase.cpp b/ui/applicationBase.cpp index 32af3af..2be1f6c 100644 --- a/ui/applicationBase.cpp +++ b/ui/applicationBase.cpp @@ -21,9 +21,6 @@ ApplicationBase::ApplicationBase() setGlAttribute(SDL_GL_DEPTH_SIZE, 16); setGlAttribute(SDL_GL_DOUBLEBUFFER, 1); - setGlAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); - setGlAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); - setGlAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); setGlAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1); } diff --git a/ui/window.cpp b/ui/window.cpp index 93e85bd..6855aa0 100644 --- a/ui/window.cpp +++ b/ui/window.cpp @@ -1,17 +1,15 @@ #include "window.h" #include "uiComponent.h" -#include "worldOverlay.h" #include #include #include -#include -#include Window::GLInitHelper::GLInitHelper() { [[maybe_unused]] static auto init = []() { - if (const auto version = gladLoadGL(reinterpret_cast(SDL_GL_GetProcAddress)); version != 40006) { - throw std::runtime_error {std::to_string(version)}; + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + if (const auto version = gladLoadGL(reinterpret_cast(SDL_GL_GetProcAddress)); version < 30003) { + throw std::runtime_error {"Insufficient OpenGL version: " + std::to_string(version)}; } else { return version; -- cgit v1.2.3 From a46fded5d93487974ac5f40ff36c8c0f4f7a9db2 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 4 Nov 2023 11:21:23 +0000 Subject: Static helper for loading ASCII grid data --- game/terrain2.cpp | 16 ++++++++++------ game/terrain2.h | 5 ++++- test/test-terrain.cpp | 2 +- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/game/terrain2.cpp b/game/terrain2.cpp index d1af221..105eb33 100644 --- a/game/terrain2.cpp +++ b/game/terrain2.cpp @@ -3,7 +3,8 @@ #include #include -TerrainMesh::TerrainMesh(const std::filesystem::path & input) +TerrainMesh +TerrainMesh::loadFromAsciiGrid(const std::filesystem::path & input) { size_t ncols = 0, nrows = 0, xllcorner = 0, yllcorner = 0, cellsize = 0; std::map properties { @@ -22,11 +23,12 @@ TerrainMesh::TerrainMesh(const std::filesystem::path & input) } std::vector vertices; vertices.reserve(ncols * nrows); + TerrainMesh mesh; for (size_t row = 0; row < nrows; ++row) { for (size_t col = 0; col < ncols; ++col) { float height = 0; f >> height; - vertices.push_back(add_vertex({xllcorner + (col * cellsize), yllcorner + (row * cellsize), height})); + vertices.push_back(mesh.add_vertex({xllcorner + (col * cellsize), yllcorner + (row * cellsize), height})); } } if (!f.good()) { @@ -34,20 +36,22 @@ TerrainMesh::TerrainMesh(const std::filesystem::path & input) } for (size_t row = 1; row < nrows; ++row) { for (size_t col = 1; col < ncols; ++col) { - add_face({ + mesh.add_face({ vertices[ncols * (row - 1) + (col - 1)], vertices[ncols * (row - 0) + (col - 0)], vertices[ncols * (row - 0) + (col - 1)], }); - add_face({ + mesh.add_face({ vertices[ncols * (row - 1) + (col - 1)], vertices[ncols * (row - 1) + (col - 0)], vertices[ncols * (row - 0) + (col - 0)], }); } } - update_face_normals(); - update_vertex_normals(); + mesh.update_face_normals(); + mesh.update_vertex_normals(); + + return mesh; }; OpenMesh::FaceHandle diff --git a/game/terrain2.h b/game/terrain2.h index 5539a50..69cd380 100644 --- a/game/terrain2.h +++ b/game/terrain2.h @@ -18,8 +18,11 @@ struct TerrainTraits : public OpenMesh::DefaultTraits { }; class TerrainMesh : public OpenMesh::TriMesh_ArrayKernelT { +private: + TerrainMesh() = default; + public: - explicit TerrainMesh(const std::filesystem::path &); + static TerrainMesh loadFromAsciiGrid(const std::filesystem::path &); struct PointFace { // NOLINTNEXTLINE(hicpp-explicit-conversions) diff --git a/test/test-terrain.cpp b/test/test-terrain.cpp index 53eebfb..512a90e 100644 --- a/test/test-terrain.cpp +++ b/test/test-terrain.cpp @@ -8,7 +8,7 @@ class TestTerrainMesh : public TerrainMesh { public: - TestTerrainMesh() : TerrainMesh {FIXTURESDIR "height/SD19.asc"} { } + TestTerrainMesh() : TerrainMesh {TerrainMesh::loadFromAsciiGrid(FIXTURESDIR "height/SD19.asc")} { } }; constexpr size_t ncols = 200, nrows = 200, xllcorner = 310000, yllcorner = 490000, cellsize = 50; -- cgit v1.2.3 From c463bce75418a145d319f214571e30df311ff8df Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 4 Nov 2023 12:14:59 +0000 Subject: Calculate and expose the extents of the terrain mesh --- game/terrain2.cpp | 5 +++++ game/terrain2.h | 9 +++++++++ test/test-terrain.cpp | 3 +++ 3 files changed, 17 insertions(+) diff --git a/game/terrain2.cpp b/game/terrain2.cpp index 105eb33..0e8b78e 100644 --- a/game/terrain2.cpp +++ b/game/terrain2.cpp @@ -24,10 +24,15 @@ TerrainMesh::loadFromAsciiGrid(const std::filesystem::path & input) std::vector vertices; vertices.reserve(ncols * nrows); TerrainMesh mesh; + mesh.lowerExtent = {xllcorner, yllcorner, std::numeric_limits::max()}; + mesh.upperExtent + = {xllcorner + (cellsize * ncols), yllcorner + (cellsize * nrows), std::numeric_limits::min()}; for (size_t row = 0; row < nrows; ++row) { for (size_t col = 0; col < ncols; ++col) { float height = 0; f >> height; + mesh.upperExtent.z = std::max(mesh.upperExtent.z, height); + mesh.lowerExtent.z = std::min(mesh.lowerExtent.z, height); vertices.push_back(mesh.add_vertex({xllcorner + (col * cellsize), yllcorner + (row * cellsize), height})); } } diff --git a/game/terrain2.h b/game/terrain2.h index 69cd380..eda56d0 100644 --- a/game/terrain2.h +++ b/game/terrain2.h @@ -77,8 +77,17 @@ public: void walk(const PointFace & from, const glm::vec2 to, const std::function & op) const; void walkUntil(const PointFace & from, const glm::vec2 to, const std::function & op) const; + [[nodiscard]] auto + getExtents() const + { + return std::tie(lowerExtent, upperExtent); + } + protected: [[nodiscard]] static bool triangleContainsPoint(const glm::vec2, const glm::vec2, const glm::vec2, const glm::vec2); [[nodiscard]] bool triangleContainsPoint(const glm::vec2, FaceHandle) const; [[nodiscard]] bool triangleContainsPoint(const glm::vec2, ConstFaceVertexIter) const; + +private: + glm::vec3 lowerExtent {}, upperExtent {}; }; diff --git a/test/test-terrain.cpp b/test/test-terrain.cpp index 512a90e..71fc1ec 100644 --- a/test/test-terrain.cpp +++ b/test/test-terrain.cpp @@ -19,6 +19,9 @@ BOOST_AUTO_TEST_CASE(loadSuccess) { BOOST_CHECK_EQUAL(ncols * nrows, n_vertices()); BOOST_CHECK_EQUAL(2 * (ncols - 1) * (nrows - 1), n_faces()); + const auto [lower, upper] = getExtents(); + BOOST_CHECK_EQUAL(lower, glm::vec3(310000, 490000, -2.6)); + BOOST_CHECK_EQUAL(upper, glm::vec3(320000, 500000, 571.6)); } BOOST_AUTO_TEST_CASE(normalsAllPointUp) -- cgit v1.2.3 From d46d8385ab68fd8f902016b3e7406290cb46c0db Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 4 Nov 2023 13:12:24 +0000 Subject: Reformat test source --- test/enumDetailsData.h | 3 +++ test/test-assetFactory.cpp | 11 +++++++++++ test/test-collection.cpp | 2 ++ test/test-geo.cpp | 7 +++++++ test/test-glContainer.cpp | 3 +++ test/test-glContextBhvr.cpp | 2 ++ test/test-instancing.cpp | 1 + test/test-lib.cpp | 1 + test/test-maths.cpp | 7 +++++++ test/test-network.cpp | 3 +++ test/test-persistence.cpp | 4 ++++ test/test-render.cpp | 9 +++++++++ test/test-text.cpp | 2 ++ test/testMainWindow.h | 1 + test/testRenderOutput.h | 1 + 15 files changed, 57 insertions(+) diff --git a/test/enumDetailsData.h b/test/enumDetailsData.h index 713d742..b7bd601 100644 --- a/test/enumDetailsData.h +++ b/test/enumDetailsData.h @@ -3,13 +3,16 @@ enum GlobalUnscoped { aa, b, c }; enum class GlobalScoped { aa, b, c }; + namespace ns { enum Unscoped { aa, b, c }; enum class Scoped { aa, b, c }; } + namespace test1 { enum class DefaultDense { a, bee, ci, de }; } + namespace test2 { enum class NumberedSparse { a = 0, bee = 3, ci = -20, de = 100 }; } diff --git a/test/test-assetFactory.cpp b/test/test-assetFactory.cpp index 18dc778..145481e 100644 --- a/test/test-assetFactory.cpp +++ b/test/test-assetFactory.cpp @@ -24,44 +24,52 @@ BOOST_GLOBAL_FIXTURE(ApplicationBase); BOOST_GLOBAL_FIXTURE(TestMainWindow); const std::filesystem::path TMP {"/tmp"}; + class FactoryFixture : public TestRenderOutputSize, public SceneProvider { public: FactoryFixture() : sceneRenderer {size, output} { } + ~FactoryFixture() { auto outpath = (TMP / boost::unit_test::framework::current_test_case().full_name()).replace_extension(".tga"); std::filesystem::create_directories(outpath.parent_path()); Texture::save(outImage, outpath.c_str()); } + void content(const SceneShader & shader) const override { shader.basic.use(Location {{0, 0, 0}, {0, 0, 0}}); objects.apply(&Renderable::render, shader); } + void lights(const SceneShader & shader) const override { shader.pointLight.add({-3, 1, 5}, {1, 1, 1}, .1F); } + void environment(const SceneShader &, const SceneRenderer & sceneRenderer) const override { sceneRenderer.setAmbientLight({.4, .4, .4}); sceneRenderer.setDirectionalLight({.6, .6, .6}, east + south + south + down, *this); } + void shadows(const ShadowMapper & mapper) const override { mapper.dynamicPoint.use(Location {{0, 0, 0}, {0, 0, 0}}); objects.apply(&Renderable::shadows, mapper); } + void render(float dist = 10.f) { sceneRenderer.camera.setView({-dist, dist * 1.2f, dist * 1.2f}, south + east + down); sceneRenderer.render(*this); } + Collection objects; private: @@ -69,6 +77,7 @@ private: }; BOOST_FIXTURE_TEST_SUITE(m, FactoryFixture); + BOOST_AUTO_TEST_CASE(brush47xml, *boost::unit_test::timeout(5)) { auto mf = AssetFactory::loadXML(RESDIR "/brush47.xml"); @@ -115,6 +124,7 @@ BOOST_AUTO_TEST_CASE(foliage, *boost::unit_test::timeout(5)) render(5); } + BOOST_AUTO_TEST_SUITE_END(); BOOST_AUTO_TEST_CASE(loadall) @@ -125,6 +135,7 @@ BOOST_AUTO_TEST_CASE(loadall) } template using InOut = std::tuple; + BOOST_DATA_TEST_CASE(normalizeColourName, boost::unit_test::data::make>({ {"", ""}, diff --git a/test/test-collection.cpp b/test/test-collection.cpp index 16db792..00204fc 100644 --- a/test/test-collection.cpp +++ b/test/test-collection.cpp @@ -13,12 +13,14 @@ public: Base() = default; virtual ~Base() = default; DEFAULT_MOVE_COPY(Base); + virtual bool add() { total += 1; return false; } + unsigned int total {0}; }; diff --git a/test/test-geo.cpp b/test/test-geo.cpp index e672e54..9874fb7 100644 --- a/test/test-geo.cpp +++ b/test/test-geo.cpp @@ -108,6 +108,7 @@ BOOST_AUTO_TEST_CASE(get_height_at) using TestRayTracerData = std::tuple>; BOOST_TEST_DECORATOR(*boost::unit_test::timeout(1)) + BOOST_DATA_TEST_CASE(raytracer, boost::unit_test::data::make({ {{1, 2}, {4, 5}, 4, @@ -145,6 +146,7 @@ BOOST_DATA_TEST_CASE(raytracer, using TestRayData = std::tuple; BOOST_TEST_DECORATOR(*boost::unit_test::timeout(1)) + BOOST_DATA_TEST_CASE(intersect_ray, boost::unit_test::data::make({ {{-1, -1, 1.0}, {1, 1, 0}, {0, 0, 1}}, @@ -169,6 +171,7 @@ BOOST_DATA_TEST_CASE(intersect_ray, nodes[at(1, 1)].height = 4; const auto intersect = intersectRay({start, glm::normalize(dir)}); + BOOST_CHECK_IF(has_intersect, intersect) { BOOST_CHECK_CLOSE_VEC(*intersect, pos); } @@ -178,6 +181,7 @@ auto xs = boost::unit_test::data::xrange(-20.F, 0.F, 0.6F), ys = boost::unit_tes auto targetsx = boost::unit_test::data::xrange(0.2F, 4.9F, 1.3F), targetsy = boost::unit_test::data::xrange(0.3F, 4.9F, 1.3F); BOOST_TEST_DECORATOR(*boost::unit_test::timeout(1)) + BOOST_DATA_TEST_CASE(intersect_ray_many, xs * ys * targetsx * targetsy, x, y, targetx, targety) { // at(x,y) is index based @@ -189,8 +193,10 @@ BOOST_DATA_TEST_CASE(intersect_ray_many, xs * ys * targetsx * targetsy, x, y, ta const glm::vec3 start {x, y, 10}; const auto target {this->positionAt({targetx, targety})}; const Ray ray {start, glm::normalize(target - start)}; + BOOST_TEST_CONTEXT(ray) { const auto intersect = intersectRay(ray); + BOOST_CHECK_IF(has_intersect, intersect) { BOOST_CHECK_CLOSE_VEC(*intersect, target); } @@ -198,6 +204,7 @@ BOOST_DATA_TEST_CASE(intersect_ray_many, xs * ys * targetsx * targetsy, x, y, ta } BOOST_TEST_DECORATOR(*boost::unit_test::timeout(1)) + BOOST_DATA_TEST_CASE(intersect_ray_miss, boost::unit_test::data::make({ {{3, 3, 5}, {-1, -1, 0}}, diff --git a/test/test-glContainer.cpp b/test/test-glContainer.cpp index 33ec992..cd57a6b 100644 --- a/test/test-glContainer.cpp +++ b/test/test-glContainer.cpp @@ -281,6 +281,7 @@ struct C { int x; float y; }; + static_assert(std::is_trivially_destructible_v); BOOST_FIXTURE_TEST_SUITE(c, glContainer) @@ -307,9 +308,11 @@ struct CC { { ++x; } + int x; float y; }; + static_assert(!std::is_trivially_destructible_v); BOOST_FIXTURE_TEST_SUITE(cc, glContainer) diff --git a/test/test-glContextBhvr.cpp b/test/test-glContextBhvr.cpp index 1f1215c..2f71aec 100644 --- a/test/test-glContextBhvr.cpp +++ b/test/test-glContextBhvr.cpp @@ -11,12 +11,14 @@ BOOST_GLOBAL_FIXTURE(ApplicationBase); #define TEST_WINDOW_PARAMS __FILE__, 0, 0, 640, 480, static_cast(SDL_WINDOW_OPENGL | SDL_WINDOW_HIDDEN) + static void CreateProgramTest() { const ProgramRef p; BOOST_REQUIRE(p); } + BOOST_AUTO_TEST_CASE(windowContextThingsBehaviour1) { BOOST_REQUIRE(!glCreateProgram); // Init not called yet diff --git a/test/test-instancing.cpp b/test/test-instancing.cpp index 7d8ea55..c1860a4 100644 --- a/test/test-instancing.cpp +++ b/test/test-instancing.cpp @@ -163,6 +163,7 @@ BOOST_DATA_TEST_CASE(shuffle_random, boost::unit_test::data::xrange(0, 10), x) iused.emplace(index[i]); } } + BOOST_TEST_CONTEXT(index) { BOOST_REQUIRE_EQUAL(iused.size(), size()); if (!iused.empty()) { diff --git a/test/test-lib.cpp b/test/test-lib.cpp index aaf6292..58b769a 100644 --- a/test/test-lib.cpp +++ b/test/test-lib.cpp @@ -9,6 +9,7 @@ #include std::set active; + void generator(GLsizei n, GLuint * out) { diff --git a/test/test-maths.cpp b/test/test-maths.cpp index a4a881d..2560319 100644 --- a/test/test-maths.cpp +++ b/test/test-maths.cpp @@ -36,6 +36,7 @@ static_assert(east.x > 0); static_assert(west == -east); // (-ve, y, z) is "west" static_assert(west.x < 0); + // // Therefore, the geographic world exists west -ve to east +ve and from south -ve to north +ve. Forward shall be // considered +ve motion; the "front" of a vehicle shall have a +ve value in y axis. @@ -110,9 +111,11 @@ const auto rots = boost::unit_test::data::make; + BOOST_DATA_TEST_CASE(test_create_arc, boost::unit_test::data::make({ {{0, 0, 0}, north, east, {0, half_pi}}, @@ -148,6 +152,7 @@ BOOST_DATA_TEST_CASE(test_create_arc, } using fac = std::tuple; + BOOST_DATA_TEST_CASE(test_find_arc_centre, boost::unit_test::data::make({ {{2, 2}, pi, {3, 3}, half_pi, {3, 2}, true}, @@ -178,6 +183,7 @@ struct TestLinkStraight : public LinkStraight { }; using StraightsData = std::tuple; + BOOST_DATA_TEST_CASE(straight1, boost::unit_test::data::make({ {north, 0, pi}, @@ -210,6 +216,7 @@ struct TestLinkCurve : public LinkCurve { }; using CurvesData = std::tuple; + BOOST_DATA_TEST_CASE(curve1, boost::unit_test::data::make({ {north + east, east, 0, -half_pi}, diff --git a/test/test-network.cpp b/test/test-network.cpp index a8db2b6..ab0818a 100644 --- a/test/test-network.cpp +++ b/test/test-network.cpp @@ -25,8 +25,11 @@ BOOST_GLOBAL_FIXTURE(TestMainWindow); struct TestLink : public LinkStraight { TestLink(const Node::Ptr & a, const Node::Ptr & b) : TestLink {a, b, (a->pos - b->pos)} { } + TestLink(Node::Ptr a, Node::Ptr b, glm::vec2 l) : Link {{std::move(a), 0}, {std::move(b), pi}, glm::length(l)} { } + TestLink(Node::Ptr a, Node::Ptr b, float l) : Link {{std::move(a), 0}, {std::move(b), pi}, l} { } + using StraightLink = TestLink; using CurveLink = TestLink; }; diff --git a/test/test-persistence.cpp b/test/test-persistence.cpp index 38bbf2f..abb68c2 100644 --- a/test/test-persistence.cpp +++ b/test/test-persistence.cpp @@ -26,6 +26,7 @@ struct JPP { BOOST_REQUIRE(to); return to; } + // Presumably BOOST_TEST_CONTEXT is implemented as an if (...) { } throw std::logic_error("We shouldn't ever get here, but apparently we can!"); } @@ -213,6 +214,7 @@ auto const TEST_STRINGS_DECODE_ONLY = boost::unit_test::data::make({ {R"J("\u056b ARMENIAN SMALL LETTER INI")J", "Õ« ARMENIAN SMALL LETTER INI"}, {R"J("\u0833 SAMARITAN PUNCTUATION BAU")J", "à ³ SAMARITAN PUNCTUATION BAU"}, }); + BOOST_DATA_TEST_CASE(load_strings, TEST_STRINGS + TEST_STRINGS_DECODE_ONLY, in, exp) { std::stringstream str {in}; @@ -220,6 +222,7 @@ BOOST_DATA_TEST_CASE(load_strings, TEST_STRINGS + TEST_STRINGS_DECODE_ONLY, in, } using cpstr = std::tuple; + BOOST_DATA_TEST_CASE(utf8_decode, boost::unit_test::data::make({ {9, "\t"}, @@ -296,6 +299,7 @@ BOOST_AUTO_TEST_CASE(get_default_id) { SubObject2 so; const auto id {so.getId()}; + BOOST_TEST_CONTEXT(id) { auto ptr = std::stoul(id, nullptr, 16); BOOST_CHECK_EQUAL(ptr, reinterpret_cast(&so)); diff --git a/test/test-render.cpp b/test/test-render.cpp index 0d384a3..b16f241 100644 --- a/test/test-render.cpp +++ b/test/test-render.cpp @@ -43,16 +43,19 @@ public: train2->bogies.front().setPosition(train2->bogies.front().position() + train2->location.position()); train2->bogies.back().setPosition(train2->bogies.back().position() + train2->location.position()); } + void content(const SceneShader & shader) const override { terrain.render(shader); brush47rvc->render(shader); } + void lights(const SceneShader &) const override { } + void shadows(const ShadowMapper & shadowMapper) const override { @@ -95,6 +98,7 @@ BOOST_AUTO_TEST_CASE(pointlight) { SceneRenderer ss {size, output}; ss.camera.setView({-10, -10, 60}, glm::normalize(glm::vec3 {1, 1, -0.5F})); + class PointLightScene : public TestScene { public: void @@ -103,6 +107,7 @@ BOOST_AUTO_TEST_CASE(pointlight) r.setAmbientLight({0.2F, 0.2F, 0.2F}); r.setDirectionalLight({0.2F, 0.2F, 0.2F}, west + down, *this); } + void lights(const SceneShader & shader) const override { @@ -113,6 +118,7 @@ BOOST_AUTO_TEST_CASE(pointlight) } } }; + const PointLightScene scene; ss.render(scene); Texture::save(outImage, "/tmp/pointlight.tga"); @@ -122,6 +128,7 @@ BOOST_AUTO_TEST_CASE(spotlight) { SceneRenderer ss {size, output}; ss.camera.setView({-10, -10, 60}, glm::normalize(glm::vec3 {1, 1, -0.5F})); + class PointLightScene : public TestScene { public: void @@ -130,6 +137,7 @@ BOOST_AUTO_TEST_CASE(spotlight) r.setAmbientLight({0.2F, 0.2F, 0.2F}); r.setDirectionalLight({0.2F, 0.2F, 0.2F}, west + down, *this); } + void lights(const SceneShader & shader) const override { @@ -139,6 +147,7 @@ BOOST_AUTO_TEST_CASE(spotlight) shader.spotLight.add({60, 50, 3}, north + east, {1.0, 1.0, 1.0}, 0.0001F, .7F); } }; + const PointLightScene scene; ss.render(scene); Texture::save(outImage, "/tmp/spotlight.tga"); diff --git a/test/test-text.cpp b/test/test-text.cpp index 629892f..166a6fa 100644 --- a/test/test-text.cpp +++ b/test/test-text.cpp @@ -36,6 +36,7 @@ struct FontTest : public Font { BOOST_TEST_DONT_PRINT_LOG_VALUE(Font::CharData); using TextureSizeTestData = std::tuple; + BOOST_DATA_TEST_CASE(fontTextureSize, boost::unit_test::data::make({2, 3, 10, 50, 250}), fontHeight) { auto isPowerOfTwo = [](auto x) { @@ -64,6 +65,7 @@ BOOST_AUTO_TEST_CASE(initialize_chardata) } using CharDataTest = std::tuple; + BOOST_DATA_TEST_CASE(initialize_chardata_A, boost::unit_test::data::make({ {'A', {0, {34, 35}, {627, 0}, {-1, 35}, 32}}, diff --git a/test/testMainWindow.h b/test/testMainWindow.h index bc9c0bd..445491d 100644 --- a/test/testMainWindow.h +++ b/test/testMainWindow.h @@ -7,6 +7,7 @@ class TestMainWindow : public Window { // in the same way a real main window would always exist. public: TestMainWindow(); + void tick(TickDuration) override { diff --git a/test/testRenderOutput.h b/test/testRenderOutput.h index f5cd56b..13c380f 100644 --- a/test/testRenderOutput.h +++ b/test/testRenderOutput.h @@ -17,6 +17,7 @@ public: glRenderBuffer depth; glTexture outImage; }; + template class TestRenderOutputSize : public TestRenderOutput { public: TestRenderOutputSize() : TestRenderOutput {Size} { } -- cgit v1.2.3 From 582ac127f763f512c45f35e17b768487e3b51796 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 4 Nov 2023 17:07:58 +0000 Subject: Rename TerrainMesh to GeoData to drop inplace --- Jamroot.jam | 1 + application/main.cpp | 16 +-- game/geoData.cpp | 340 +++++++++++++++++++++++++++----------------------- game/geoData.h | 115 +++++++++++------ game/terrain.cpp | 65 +++------- game/terrain2.cpp | 221 -------------------------------- game/terrain2.h | 93 -------------- test/Jamfile.jam | 5 +- test/perf-geoData.cpp | 18 +++ test/perf-terrain.cpp | 18 --- test/test-geo.cpp | 225 --------------------------------- test/test-geoData.cpp | 175 ++++++++++++++++++++++++++ test/test-render.cpp | 3 +- test/test-terrain.cpp | 175 -------------------------- ui/gameMainWindow.cpp | 2 +- 15 files changed, 480 insertions(+), 992 deletions(-) delete mode 100644 game/terrain2.cpp delete mode 100644 game/terrain2.h create mode 100644 test/perf-geoData.cpp delete mode 100644 test/perf-terrain.cpp delete mode 100644 test/test-geo.cpp create mode 100644 test/test-geoData.cpp delete mode 100644 test/test-terrain.cpp diff --git a/Jamroot.jam b/Jamroot.jam index 8a111ee..ef2f4c2 100644 --- a/Jamroot.jam +++ b/Jamroot.jam @@ -101,6 +101,7 @@ lib ilt : . lib thirdparty//glad + OpenMeshCore ; build-project test ; diff --git a/application/main.cpp b/application/main.cpp index 532c23d..9e4ca33 100644 --- a/application/main.cpp +++ b/application/main.cpp @@ -34,11 +34,11 @@ static const int DISPLAY_HEIGHT = 1024; class MainApplication : public GameState, public ApplicationBase { public: using Windows = Collection; + int run() { - geoData = std::make_shared(GeoData::Limits {{-120, -120}, {120, 120}}, 10.F); - geoData->generateRandom(); + geoData = std::make_shared(GeoData::loadFromAsciiGrid("test/fixtures/height/SD19.asc")); Windows windows; windows.create(DISPLAY_WIDTH, DISPLAY_HEIGHT); @@ -78,12 +78,12 @@ public: train->orders.create(&train->orders, l3->ends[1], l3->length, rl->findNodeAt({-1100, -450, 15})); train->currentActivity = train->orders.current()->createActivity(); - auto foliage = std::dynamic_pointer_cast(assets.at("Tree-01-1")); - for (float x = 900; x < 1100; x += 3) { - for (float y = 900; y < 1100; y += 3) { - world.create(foliage, Location {geoData->positionAt({-x, -y})}); - } - } + // auto foliage = std::dynamic_pointer_cast(assets.at("Tree-01-1")); + // for (float x = 900; x < 1100; x += 3) { + // for (float y = 900; y < 1100; y += 3) { + // world.create(foliage, Location {terrainMesh->positionAt(glm::vec2 {-x, -y})}); + //} + //} } auto t_start = std::chrono::high_resolution_clock::now(); diff --git a/game/geoData.cpp b/game/geoData.cpp index 34a1030..d32bf8c 100644 --- a/game/geoData.cpp +++ b/game/geoData.cpp @@ -1,214 +1,238 @@ #include "geoData.h" -#include "gfx/image.h" -#include -#include -#include -#include +#include #include -#include -#include #include -#include -#include -#include -#include -#include - -GeoData::GeoData(Limits l, float s) : - limit {std::move(l)}, size {(limit.second - limit.first) + 1}, scale {s}, nodes {[this]() { - return (static_cast(size.x * size.y)); - }()} -{ -} -void -GeoData::generateRandom() +GeoData +GeoData::loadFromAsciiGrid(const std::filesystem::path & input) { - // We acknowledge this is terrible :) - - // Add hills - std::mt19937 gen(std::random_device {}()); - std::uniform_int_distribution<> rxpos(limit.first.x + 2, limit.second.x - 2), - rypos(limit.first.y + 2, limit.second.y - 2); - std::uniform_int_distribution<> rsize(10, 30); - std::uniform_real_distribution rheight(1, 3); - for (int h = 0; h < 500;) { - const glm::ivec2 hpos {rxpos(gen), rypos(gen)}; - const glm::ivec2 hsize {rsize(gen), rsize(gen)}; - if (const auto lim1 = hpos - hsize; lim1.x > limit.first.x && lim1.y > limit.first.y) { - if (const auto lim2 = hpos + hsize; lim2.x < limit.second.x && lim2.y < limit.second.y) { - const auto height = rheight(gen); - const glm::ivec2 hsizesqrd {hsize.x * hsize.x, hsize.y * hsize.y}; - for (auto y = lim1.y; y < lim2.y; y += 1) { - for (auto x = lim1.x; x < lim2.x; x += 1) { - const auto dist {hpos - glm::ivec2 {x, y}}; - const glm::ivec2 distsqrd {dist.x * dist.x, dist.y * dist.y}; - const auto out {ratio(sq(x - hpos.x), sq(hsize.x)) + ratio(sq(y - hpos.y), sq(hsize.y))}; - if (out <= 1.0F) { - auto & node {nodes[at({x, y})]}; - const auto m {1.F / (7.F * out - 8.F) + 1.F}; - node.height += height * m; - } - } - } - h += 1; - } + size_t ncols = 0, nrows = 0, xllcorner = 0, yllcorner = 0, cellsize = 0; + std::map properties { + {"ncols", &ncols}, + {"nrows", &nrows}, + {"xllcorner", &xllcorner}, + {"yllcorner", &yllcorner}, + {"cellsize", &cellsize}, + }; + std::ifstream f {input}; + while (!properties.empty()) { + std::string property; + f >> property; + f >> *properties.at(property); + properties.erase(property); + } + std::vector vertices; + vertices.reserve(ncols * nrows); + GeoData mesh; + mesh.lowerExtent = {xllcorner, yllcorner, std::numeric_limits::max()}; + mesh.upperExtent + = {xllcorner + (cellsize * ncols), yllcorner + (cellsize * nrows), std::numeric_limits::min()}; + for (size_t row = 0; row < nrows; ++row) { + for (size_t col = 0; col < ncols; ++col) { + float height = 0; + f >> height; + mesh.upperExtent.z = std::max(mesh.upperExtent.z, height); + mesh.lowerExtent.z = std::min(mesh.lowerExtent.z, height); + vertices.push_back(mesh.add_vertex({xllcorner + (col * cellsize), yllcorner + (row * cellsize), height})); } } -} + if (!f.good()) { + throw std::runtime_error("Couldn't read terrain file"); + } + for (size_t row = 1; row < nrows; ++row) { + for (size_t col = 1; col < ncols; ++col) { + mesh.add_face({ + vertices[ncols * (row - 1) + (col - 1)], + vertices[ncols * (row - 0) + (col - 0)], + vertices[ncols * (row - 0) + (col - 1)], + }); + mesh.add_face({ + vertices[ncols * (row - 1) + (col - 1)], + vertices[ncols * (row - 1) + (col - 0)], + vertices[ncols * (row - 0) + (col - 0)], + }); + } + } + mesh.update_face_normals(); + mesh.update_vertex_normals(); -void -GeoData::loadFromImages(const std::filesystem::path & fileName, float scale_) -{ - const Image map {fileName.c_str(), STBI_grey}; - size = {map.width, map.height}; - limit = {{0, 0}, size - glm::uvec2 {1, 1}}; - const auto points {size.x * size.y}; - scale = scale_; - nodes.resize(points); - - std::transform(map.data.data(), map.data.data() + points, nodes.begin(), [](auto d) { - return Node {(d * 0.1F) - 1.5F}; - }); -} + return mesh; +}; -GeoData::Quad -GeoData::quad(glm::vec2 wcoord) const +GeoData +GeoData::createFlat(glm::vec2 lower, glm::vec2 upper, float h) { - constexpr static const std::array corners {{{0, 0}, {0, 1}, {1, 0}, {1, 1}}}; - return transform_array(transform_array(corners, - [coord = (wcoord / scale)](const auto c) { - return glm::vec2 {std::floor(coord.x), std::floor(coord.y)} + c; - }), - [this](const auto c) { - return (c * scale) || nodes[at(c)].height; - }); -} + GeoData mesh; -glm::vec3 -GeoData::positionAt(const glm::vec2 wcoord) const -{ - const auto point {quad(wcoord)}; - const glm::vec2 frac = (wcoord - !point.front()) / scale; - auto edge = [&point, &frac](auto offset) { - return point[offset].z + ((point[offset + 2].z - point[offset].z) * frac.x); - }; - const auto heightFloor = edge(0U), heightCeil = edge(1U), - heightMid = heightFloor + ((heightCeil - heightFloor) * frac.y); + mesh.lowerExtent = lower ^ h; + mesh.upperExtent = upper ^ h; + + const auto ll = mesh.add_vertex({lower.x, lower.y, h}), lu = mesh.add_vertex({lower.x, upper.y, h}), + ul = mesh.add_vertex({upper.x, lower.y, h}), uu = mesh.add_vertex({upper.x, upper.y, h}); + + mesh.add_face(ll, uu, lu); + mesh.add_face(ll, ul, uu); - return wcoord || heightMid; + mesh.update_face_normals(); + mesh.update_vertex_normals(); + + return mesh; } -GeoData::RayTracer::RayTracer(glm::vec2 p0, glm::vec2 p1) : RayTracer {p0, p1, glm::abs(p1)} { } -GeoData::RayTracer::RayTracer(glm::vec2 p0, glm::vec2 p1, glm::vec2 d) : - RayTracer {p0, d, byAxis(p0, p1, d, 0), byAxis(p0, p1, d, 1)} +OpenMesh::FaceHandle +GeoData::findPoint(glm::vec2 p) const { + return findPoint(p, *faces_begin()); } -GeoData::RayTracer::RayTracer( - glm::vec2 p0, glm::vec2 d_, std::pair xdata, std::pair ydata) : - p {glm::floor(p0)}, - d {d_}, error {xdata.second - ydata.second}, inc {xdata.first, ydata.first} +GeoData::PointFace::PointFace(const glm::vec2 p, const GeoData * mesh) : PointFace {p, mesh, *mesh->faces_begin()} { } + +GeoData::PointFace::PointFace(const glm::vec2 p, const GeoData * mesh, FaceHandle start) : + PointFace {p, mesh->findPoint(p, start)} { } -std::pair -GeoData::RayTracer::byAxis(glm::vec2 p0, glm::vec2 p1, glm::vec2 d, glm::length_t axis) +GeoData::FaceHandle +GeoData::PointFace::face(const GeoData * mesh, FaceHandle start) const { - using Limits = std::numeric_limits; - static_assert(Limits::has_infinity); - if (d[axis] == 0) { - return {0, Limits::infinity()}; - } - else if (p1[axis] > 0) { - return {1, (std::floor(p0[axis]) + 1.F - p0[axis]) * d[1 - axis]}; + if (_face.is_valid()) { + assert(mesh->triangleContainsPoint(point, _face)); + return _face; } else { - return {-1, (p0[axis] - std::floor(p0[axis])) * d[1 - axis]}; + return (_face = mesh->findPoint(point, start)); } } -glm::vec2 -GeoData::RayTracer::next() +GeoData::FaceHandle +GeoData::PointFace::face(const GeoData * mesh) const { - const glm::vec2 cur {p}; + return face(mesh, *mesh->faces_begin()); +} + +namespace { + [[nodiscard]] constexpr inline bool + pointLeftOfLine(const glm::vec2 p, const glm::vec2 e1, const glm::vec2 e2) + { + return (e2.x - e1.x) * (p.y - e1.y) > (e2.y - e1.y) * (p.x - e1.x); + } - static constexpr const glm::vec2 m {1, -1}; - const int axis = (error > 0) ? 1 : 0; - p[axis] += inc[axis]; - error += d[1 - axis] * m[axis]; + static_assert(pointLeftOfLine({1, 2}, {1, 1}, {2, 2})); + static_assert(pointLeftOfLine({2, 1}, {2, 2}, {1, 1})); + static_assert(pointLeftOfLine({2, 2}, {1, 2}, {2, 1})); + static_assert(pointLeftOfLine({1, 1}, {2, 1}, {1, 2})); - return cur; + [[nodiscard]] constexpr inline bool + linesCross(const glm::vec2 a1, const glm::vec2 a2, const glm::vec2 b1, const glm::vec2 b2) + { + return pointLeftOfLine(a2, b1, b2) && pointLeftOfLine(a1, b2, b1) && pointLeftOfLine(b1, a1, a2) + && pointLeftOfLine(b2, a2, a1); + } + + static_assert(linesCross({1, 1}, {2, 2}, {1, 2}, {2, 1})); } -std::optional -GeoData::intersectRay(const Ray & ray) const +OpenMesh::FaceHandle +GeoData::findPoint(glm::vec2 p, OpenMesh::FaceHandle f) const { - if (glm::length(!ray.direction) <= 0) { - return {}; - } - RayTracer rt {ray.start / scale, ray.direction}; - while (true) { - const auto n {rt.next() * scale}; - try { - const auto point = quad(n); - for (auto offset : {0U, 1U}) { - glm::vec2 bary; - float distance; - if (glm::intersectRayTriangle(ray.start, ray.direction, point[offset], point[offset + 1], - point[offset + 2], bary, distance)) { - return point[offset] + ((point[offset + 1] - point[offset]) * bary[0]) - + ((point[offset + 2] - point[offset]) * bary[1]); + ConstFaceVertexIter vertices; + while (f.is_valid() && !triangleContainsPoint(p, vertices = cfv_iter(f))) { + for (auto next = cfh_iter(f); next.is_valid(); ++next) { + f = opposite_face_handle(*next); + if (f.is_valid()) { + const auto e1 = point(to_vertex_handle(*next)); + const auto e2 = point(to_vertex_handle(opposite_halfedge_handle(*next))); + if (pointLeftOfLine(p, e1, e2)) { + break; } } - } - catch (std::range_error &) { - const auto rel = n / !ray.direction; - if (rel.x > 0 && rel.y > 0) { - return {}; - } + f.reset(); } } + return f; +} - return {}; +glm::vec3 +GeoData::positionAt(const PointFace & p) const +{ + glm::vec3 out {}; + Triangle<3> t {this, fv_range(p.face(this))}; + glm::intersectLineTriangle(p.point ^ 0.F, up, t[0], t[1], t[2], out); + return p.point ^ out[0]; } -unsigned int -GeoData::at(glm::ivec2 coord) const +[[nodiscard]] std::optional +GeoData::intersectRay(const Ray & ray) const { - if (coord.x < limit.first.x || coord.x > limit.second.x || coord.y < limit.first.y || coord.y > limit.second.y) { - throw std::range_error {"Coordinates outside GeoData limits"}; - } - const glm::uvec2 offset = coord - limit.first; - return offset.x + (offset.y * size.x); + return intersectRay(ray, findPoint(ray.start)); } -unsigned int -GeoData::at(int x, int y) const +[[nodiscard]] std::optional +GeoData::intersectRay(const Ray & ray, FaceHandle face) const { - return at({x, y}); + std::optional out; + walkUntil(PointFace {ray.start, face}, ray.start + (ray.direction * 10000.F), [&out, &ray, this](FaceHandle face) { + glm::vec2 bari {}; + float dist {}; + Triangle<3> t {this, fv_range(face)}; + if (glm::intersectRayTriangle(ray.start, ray.direction, t[0], t[1], t[2], bari, dist)) { + out = t * bari; + return true; + } + return false; + }); + return out; } -GeoData::Limits -GeoData::getLimit() const +void +GeoData::walk(const PointFace & from, const glm::vec2 to, const std::function & op) const { - return limit; + walkUntil(from, to, [&op](const auto & fh) { + op(fh); + return false; + }); } -float -GeoData::getScale() const +void +GeoData::walkUntil(const PointFace & from, const glm::vec2 to, const std::function & op) const +{ + assert(from.face(this).is_valid()); // TODO replace with a boundary search + auto f = from.face(this); + FaceHandle previousFace; + while (f.is_valid() && !op(f)) { + for (auto next = cfh_iter(f); next.is_valid(); ++next) { + f = opposite_face_handle(*next); + if (f.is_valid() && f != previousFace) { + const auto e1 = point(to_vertex_handle(*next)); + const auto e2 = point(to_vertex_handle(opposite_halfedge_handle(*next))); + if (linesCross(from.point, to, e1, e2)) { + previousFace = f; + break; + } + } + f.reset(); + } + } +} + +bool +GeoData::triangleContainsPoint(const glm::vec2 p, const glm::vec2 a, const glm::vec2 b, const glm::vec2 c) { - return scale; + const auto det = (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x); + + return det * ((b.x - a.x) * (p.y - a.y) - (b.y - a.y) * (p.x - a.x)) >= 0 + && det * ((c.x - b.x) * (p.y - b.y) - (c.y - b.y) * (p.x - b.x)) >= 0 + && det * ((a.x - c.x) * (p.y - c.y) - (a.y - c.y) * (p.x - c.x)) >= 0; } -glm::uvec2 -GeoData::getSize() const +bool +GeoData::triangleContainsPoint(const glm::vec2 p, FaceHandle face) const { - return size; + return triangleContainsPoint(p, cfv_iter(face)); } -std::span -GeoData::getNodes() const +bool +GeoData::triangleContainsPoint(const glm::vec2 p, ConstFaceVertexIter vertices) const { - return nodes; + return triangleContainsPoint(p, point(*vertices++), point(*vertices++), point(*vertices++)); } diff --git a/game/geoData.h b/game/geoData.h index f433a5c..3a4f98e 100644 --- a/game/geoData.h +++ b/game/geoData.h @@ -1,61 +1,94 @@ #pragma once -#include +#include "collections.h" // IWYU pragma: keep IterableCollection +#include "ray.h" +#include #include -#include +#include #include -#include -#include -#include +#include -class Ray; +struct GeoDataTraits : public OpenMesh::DefaultTraits { + FaceAttributes(OpenMesh::Attributes::Normal | OpenMesh::Attributes::Status); + EdgeAttributes(OpenMesh::Attributes::Status); + VertexAttributes(OpenMesh::Attributes::Normal | OpenMesh::Attributes::Status); + HalfedgeAttributes(OpenMesh::Attributes::Normal | OpenMesh::Attributes::Status); + using Point = glm::vec3; + using Normal = glm::vec3; +}; + +class GeoData : public OpenMesh::TriMesh_ArrayKernelT { +private: + GeoData() = default; -class GeoData { public: - struct Node { - float height {-1.5F}; - }; - using Quad = std::array; + static GeoData loadFromAsciiGrid(const std::filesystem::path &); + static GeoData createFlat(glm::vec2 lower, glm::vec2, float h); - using Limits = std::pair; + struct PointFace { + // NOLINTNEXTLINE(hicpp-explicit-conversions) + PointFace(const glm::vec2 p) : point {p} { } - explicit GeoData(Limits limit, float scale = 10.F); + PointFace(const glm::vec2 p, FaceHandle face) : point {p}, _face {face} { } - void generateRandom(); - void loadFromImages(const std::filesystem::path &, float scale); + PointFace(const glm::vec2 p, const GeoData *); + PointFace(const glm::vec2 p, const GeoData *, FaceHandle start); - [[nodiscard]] glm::vec3 positionAt(glm::vec2) const; - [[nodiscard]] std::optional intersectRay(const Ray &) const; + const glm::vec2 point; + [[nodiscard]] FaceHandle face(const GeoData *) const; + [[nodiscard]] FaceHandle face(const GeoData *, FaceHandle start) const; - [[nodiscard]] unsigned int at(glm::ivec2) const; - [[nodiscard]] unsigned int at(int x, int y) const; - [[nodiscard]] Quad quad(glm::vec2) const; + [[nodiscard]] bool + isLocated() const + { + return _face.is_valid(); + } - [[nodiscard]] Limits getLimit() const; - [[nodiscard]] glm::uvec2 getSize() const; - [[nodiscard]] float getScale() const; - [[nodiscard]] std::span getNodes() const; + private: + mutable FaceHandle _face {}; + }; - class RayTracer { - public: - RayTracer(glm::vec2 p0, glm::vec2 p1); + template struct Triangle : public glm::vec<3, glm::vec> { + using base = glm::vec<3, glm::vec>; + using base::base; - glm::vec2 next(); + template Triangle(const GeoData * m, Range range) + { + assert(std::distance(range.begin(), range.end()) == 3); + std::transform(range.begin(), range.end(), &base::operator[](0), [m](auto vh) { + return m->point(vh); + }); + } - private: - RayTracer(glm::vec2 p0, glm::vec2 p1, glm::vec2 d); - RayTracer(glm::vec2 p0, glm::vec2 d, std::pair, std::pair); - static std::pair byAxis(glm::vec2 p0, glm::vec2 p1, glm::vec2 d, glm::length_t); - - glm::vec2 p; - const glm::vec2 d; - float error; - glm::vec2 inc; + glm::vec + operator*(glm::vec2 bari) const + { + const auto & t {*this}; + return t[0] + ((t[1] - t[0]) * bari.x) + ((t[2] - t[1]) * bari.y); + } }; + [[nodiscard]] FaceHandle findPoint(glm::vec2) const; + [[nodiscard]] FaceHandle findPoint(glm::vec2, FaceHandle start) const; + + [[nodiscard]] glm::vec3 positionAt(const PointFace &) const; + [[nodiscard]] std::optional intersectRay(const Ray &) const; + [[nodiscard]] std::optional intersectRay(const Ray &, FaceHandle start) const; + + void walk(const PointFace & from, const glm::vec2 to, const std::function & op) const; + void walkUntil(const PointFace & from, const glm::vec2 to, const std::function & op) const; + + [[nodiscard]] auto + getExtents() const + { + return std::tie(lowerExtent, upperExtent); + } + protected: - Limits limit {}; // Base grid limits first(x,y) -> second(x,y) - glm::uvec2 size {}; - float scale {1}; - std::vector nodes; + [[nodiscard]] static bool triangleContainsPoint(const glm::vec2, const glm::vec2, const glm::vec2, const glm::vec2); + [[nodiscard]] bool triangleContainsPoint(const glm::vec2, FaceHandle) const; + [[nodiscard]] bool triangleContainsPoint(const glm::vec2, ConstFaceVertexIter) const; + +private: + glm::vec3 lowerExtent {}, upperExtent {}; }; diff --git a/game/terrain.cpp b/game/terrain.cpp index f3bec1e..5bb8abd 100644 --- a/game/terrain.cpp +++ b/game/terrain.cpp @@ -2,7 +2,6 @@ #include "game/geoData.h" #include "gfx/models/texture.h" #include -#include #include #include #include @@ -18,8 +17,8 @@ #include #include -Terrain::Terrain(std::shared_ptr gd) : - geoData {std::move(gd)}, grass {Texture::cachedTexture.get("grass.png")}, +Terrain::Terrain(std::shared_ptr tm) : + geoData {std::move(tm)}, grass {Texture::cachedTexture.get("grass.png")}, water {Texture::cachedTexture.get("water.png")} { generateMeshes(); @@ -29,51 +28,23 @@ void Terrain::generateMeshes() { std::vector indices; - const auto isize = geoData->getSize() - glm::uvec2 {1, 1}; - indices.reserve(static_cast(isize.x * isize.y) * 6); - - const auto limit = geoData->getLimit(); - // Indices - constexpr std::array indices_offsets {{ - {0, 0}, - {1, 0}, - {1, 1}, - {0, 0}, - {1, 1}, - {0, 1}, - }}; - for (auto y = limit.first.y; y < limit.second.y; y += 1) { - for (auto x = limit.first.x; x < limit.second.x; x += 1) { - std::transform(indices_offsets.begin(), indices_offsets.end(), std::back_inserter(indices), - [this, x, y](const auto off) { - return geoData->at(x + off.x, y + off.y); - }); - } - } - - const auto nodes = geoData->getNodes(); - const auto scale = geoData->getScale(); + indices.reserve(geoData->n_faces() * 3); std::vector vertices; - vertices.reserve(nodes.size()); - // Positions - for (auto y = limit.first.y; y <= limit.second.y; y += 1) { - for (auto x = limit.first.x; x <= limit.second.x; x += 1) { - const glm::vec2 xy {x, y}; - vertices.emplace_back((xy * scale) ^ nodes[geoData->at(x, y)].height, xy, ::up); - } - } - // Normals - const glm::uvec2 size = geoData->getSize(); - for (auto y = limit.first.y + 1; y < limit.second.y; y += 1) { - for (auto x = limit.first.x + 1; x < limit.second.x; x += 1) { - const auto n {geoData->at(x, y)}; - const auto a = vertices[n - 1].pos; - const auto b = vertices[n - size.x].pos; - const auto c = vertices[n + 1].pos; - const auto d = vertices[n + size.x].pos; - vertices[n].normal = -glm::normalize(glm::cross(b - d, a - c)); - } - } + vertices.reserve(geoData->n_vertices()); + std::map vertexIndex; + std::transform(geoData->vertices_begin(), geoData->vertices_end(), std::back_inserter(vertices), + [this, &vertexIndex](const GeoData::VertexHandle v) { + vertexIndex.emplace(v, vertexIndex.size()); + const glm::vec3 p = geoData->point(v); + return Vertex {p, p / 10.F, geoData->normal(v)}; + }); + std::for_each( + geoData->faces_begin(), geoData->faces_end(), [this, &vertexIndex, &indices](const GeoData::FaceHandle f) { + std::transform(geoData->fv_begin(f), geoData->fv_end(f), std::back_inserter(indices), + [&vertexIndex](const GeoData::VertexHandle v) { + return vertexIndex[v]; + }); + }); meshes.create(vertices, indices); } diff --git a/game/terrain2.cpp b/game/terrain2.cpp deleted file mode 100644 index 0e8b78e..0000000 --- a/game/terrain2.cpp +++ /dev/null @@ -1,221 +0,0 @@ -#include "terrain2.h" -#include -#include -#include - -TerrainMesh -TerrainMesh::loadFromAsciiGrid(const std::filesystem::path & input) -{ - size_t ncols = 0, nrows = 0, xllcorner = 0, yllcorner = 0, cellsize = 0; - std::map properties { - {"ncols", &ncols}, - {"nrows", &nrows}, - {"xllcorner", &xllcorner}, - {"yllcorner", &yllcorner}, - {"cellsize", &cellsize}, - }; - std::ifstream f {input}; - while (!properties.empty()) { - std::string property; - f >> property; - f >> *properties.at(property); - properties.erase(property); - } - std::vector vertices; - vertices.reserve(ncols * nrows); - TerrainMesh mesh; - mesh.lowerExtent = {xllcorner, yllcorner, std::numeric_limits::max()}; - mesh.upperExtent - = {xllcorner + (cellsize * ncols), yllcorner + (cellsize * nrows), std::numeric_limits::min()}; - for (size_t row = 0; row < nrows; ++row) { - for (size_t col = 0; col < ncols; ++col) { - float height = 0; - f >> height; - mesh.upperExtent.z = std::max(mesh.upperExtent.z, height); - mesh.lowerExtent.z = std::min(mesh.lowerExtent.z, height); - vertices.push_back(mesh.add_vertex({xllcorner + (col * cellsize), yllcorner + (row * cellsize), height})); - } - } - if (!f.good()) { - throw std::runtime_error("Couldn't read terrain file"); - } - for (size_t row = 1; row < nrows; ++row) { - for (size_t col = 1; col < ncols; ++col) { - mesh.add_face({ - vertices[ncols * (row - 1) + (col - 1)], - vertices[ncols * (row - 0) + (col - 0)], - vertices[ncols * (row - 0) + (col - 1)], - }); - mesh.add_face({ - vertices[ncols * (row - 1) + (col - 1)], - vertices[ncols * (row - 1) + (col - 0)], - vertices[ncols * (row - 0) + (col - 0)], - }); - } - } - mesh.update_face_normals(); - mesh.update_vertex_normals(); - - return mesh; -}; - -OpenMesh::FaceHandle -TerrainMesh::findPoint(glm::vec2 p) const -{ - return findPoint(p, *faces_begin()); -} - -TerrainMesh::PointFace::PointFace(const glm::vec2 p, const TerrainMesh * mesh) : - PointFace {p, mesh, *mesh->faces_begin()} -{ -} - -TerrainMesh::PointFace::PointFace(const glm::vec2 p, const TerrainMesh * mesh, FaceHandle start) : - PointFace {p, mesh->findPoint(p, start)} -{ -} - -TerrainMesh::FaceHandle -TerrainMesh::PointFace::face(const TerrainMesh * mesh, FaceHandle start) const -{ - if (_face.is_valid()) { - assert(mesh->triangleContainsPoint(point, _face)); - return _face; - } - else { - return (_face = mesh->findPoint(point, start)); - } -} - -TerrainMesh::FaceHandle -TerrainMesh::PointFace::face(const TerrainMesh * mesh) const -{ - return face(mesh, *mesh->faces_begin()); -} - -namespace { - [[nodiscard]] constexpr inline bool - pointLeftOfLine(const glm::vec2 p, const glm::vec2 e1, const glm::vec2 e2) - { - return (e2.x - e1.x) * (p.y - e1.y) > (e2.y - e1.y) * (p.x - e1.x); - } - - static_assert(pointLeftOfLine({1, 2}, {1, 1}, {2, 2})); - static_assert(pointLeftOfLine({2, 1}, {2, 2}, {1, 1})); - static_assert(pointLeftOfLine({2, 2}, {1, 2}, {2, 1})); - static_assert(pointLeftOfLine({1, 1}, {2, 1}, {1, 2})); - - [[nodiscard]] constexpr inline bool - linesCross(const glm::vec2 a1, const glm::vec2 a2, const glm::vec2 b1, const glm::vec2 b2) - { - return pointLeftOfLine(a2, b1, b2) && pointLeftOfLine(a1, b2, b1) && pointLeftOfLine(b1, a1, a2) - && pointLeftOfLine(b2, a2, a1); - } - - static_assert(linesCross({1, 1}, {2, 2}, {1, 2}, {2, 1})); -} - -OpenMesh::FaceHandle -TerrainMesh::findPoint(glm::vec2 p, OpenMesh::FaceHandle f) const -{ - ConstFaceVertexIter vertices; - while (f.is_valid() && !triangleContainsPoint(p, vertices = cfv_iter(f))) { - for (auto next = cfh_iter(f); next.is_valid(); ++next) { - f = opposite_face_handle(*next); - if (f.is_valid()) { - const auto e1 = point(to_vertex_handle(*next)); - const auto e2 = point(to_vertex_handle(opposite_halfedge_handle(*next))); - if (pointLeftOfLine(p, e1, e2)) { - break; - } - } - f.reset(); - } - } - return f; -} - -glm::vec3 -TerrainMesh::positionAt(const PointFace & p) const -{ - glm::vec3 out {}; - Triangle<3> t {this, fv_range(p.face(this))}; - glm::intersectLineTriangle(p.point ^ 0.F, up, t[0], t[1], t[2], out); - return p.point ^ out[0]; -} - -[[nodiscard]] std::optional -TerrainMesh::intersectRay(const Ray & ray) const -{ - return intersectRay(ray, findPoint(ray.start)); -} - -[[nodiscard]] std::optional -TerrainMesh::intersectRay(const Ray & ray, FaceHandle face) const -{ - std::optional out; - walkUntil(PointFace {ray.start, face}, ray.start + (ray.direction * 10000.F), [&out, &ray, this](FaceHandle face) { - glm::vec2 bari {}; - float dist {}; - Triangle<3> t {this, fv_range(face)}; - if (glm::intersectRayTriangle(ray.start, ray.direction, t[0], t[1], t[2], bari, dist)) { - out = t * bari; - return true; - } - return false; - }); - return out; -} - -void -TerrainMesh::walk(const PointFace & from, const glm::vec2 to, const std::function & op) const -{ - walkUntil(from, to, [&op](const auto & fh) { - op(fh); - return false; - }); -} - -void -TerrainMesh::walkUntil(const PointFace & from, const glm::vec2 to, const std::function & op) const -{ - assert(from.face(this).is_valid()); // TODO replace with a boundary search - auto f = from.face(this); - FaceHandle previousFace; - while (f.is_valid() && !op(f)) { - for (auto next = cfh_iter(f); next.is_valid(); ++next) { - f = opposite_face_handle(*next); - if (f.is_valid() && f != previousFace) { - const auto e1 = point(to_vertex_handle(*next)); - const auto e2 = point(to_vertex_handle(opposite_halfedge_handle(*next))); - if (linesCross(from.point, to, e1, e2)) { - previousFace = f; - break; - } - } - f.reset(); - } - } -} - -bool -TerrainMesh::triangleContainsPoint(const glm::vec2 p, const glm::vec2 a, const glm::vec2 b, const glm::vec2 c) -{ - const auto det = (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x); - - return det * ((b.x - a.x) * (p.y - a.y) - (b.y - a.y) * (p.x - a.x)) >= 0 - && det * ((c.x - b.x) * (p.y - b.y) - (c.y - b.y) * (p.x - b.x)) >= 0 - && det * ((a.x - c.x) * (p.y - c.y) - (a.y - c.y) * (p.x - c.x)) >= 0; -} - -bool -TerrainMesh::triangleContainsPoint(const glm::vec2 p, FaceHandle face) const -{ - return triangleContainsPoint(p, cfv_iter(face)); -} - -bool -TerrainMesh::triangleContainsPoint(const glm::vec2 p, ConstFaceVertexIter vertices) const -{ - return triangleContainsPoint(p, point(*vertices++), point(*vertices++), point(*vertices++)); -} diff --git a/game/terrain2.h b/game/terrain2.h deleted file mode 100644 index eda56d0..0000000 --- a/game/terrain2.h +++ /dev/null @@ -1,93 +0,0 @@ -#pragma once - -#include "collections.h" // IWYU pragma: keep IterableCollection -#include "ray.h" -#include -#include -#include -#include -#include - -struct TerrainTraits : public OpenMesh::DefaultTraits { - FaceAttributes(OpenMesh::Attributes::Normal | OpenMesh::Attributes::Status); - EdgeAttributes(OpenMesh::Attributes::Status); - VertexAttributes(OpenMesh::Attributes::Normal | OpenMesh::Attributes::Status); - HalfedgeAttributes(OpenMesh::Attributes::Normal | OpenMesh::Attributes::Status); - using Point = glm::vec3; - using Normal = glm::vec3; -}; - -class TerrainMesh : public OpenMesh::TriMesh_ArrayKernelT { -private: - TerrainMesh() = default; - -public: - static TerrainMesh loadFromAsciiGrid(const std::filesystem::path &); - - struct PointFace { - // NOLINTNEXTLINE(hicpp-explicit-conversions) - PointFace(const glm::vec2 p) : point {p} { } - - PointFace(const glm::vec2 p, FaceHandle face) : point {p}, _face {face} { } - - PointFace(const glm::vec2 p, const TerrainMesh *); - PointFace(const glm::vec2 p, const TerrainMesh *, FaceHandle start); - - const glm::vec2 point; - [[nodiscard]] FaceHandle face(const TerrainMesh *) const; - [[nodiscard]] FaceHandle face(const TerrainMesh *, FaceHandle start) const; - - [[nodiscard]] bool - isLocated() const - { - return _face.is_valid(); - } - - private: - mutable FaceHandle _face {}; - }; - - template struct Triangle : public glm::vec<3, glm::vec> { - using base = glm::vec<3, glm::vec>; - using base::base; - - template Triangle(const TerrainMesh * m, Range range) - { - assert(std::distance(range.begin(), range.end()) == 3); - std::transform(range.begin(), range.end(), &base::operator[](0), [m](auto vh) { - return m->point(vh); - }); - } - - glm::vec - operator*(glm::vec2 bari) const - { - const auto & t {*this}; - return t[0] + ((t[1] - t[0]) * bari.x) + ((t[2] - t[1]) * bari.y); - } - }; - - [[nodiscard]] FaceHandle findPoint(glm::vec2) const; - [[nodiscard]] FaceHandle findPoint(glm::vec2, FaceHandle start) const; - - [[nodiscard]] glm::vec3 positionAt(const PointFace &) const; - [[nodiscard]] std::optional intersectRay(const Ray &) const; - [[nodiscard]] std::optional intersectRay(const Ray &, FaceHandle start) const; - - void walk(const PointFace & from, const glm::vec2 to, const std::function & op) const; - void walkUntil(const PointFace & from, const glm::vec2 to, const std::function & op) const; - - [[nodiscard]] auto - getExtents() const - { - return std::tie(lowerExtent, upperExtent); - } - -protected: - [[nodiscard]] static bool triangleContainsPoint(const glm::vec2, const glm::vec2, const glm::vec2, const glm::vec2); - [[nodiscard]] bool triangleContainsPoint(const glm::vec2, FaceHandle) const; - [[nodiscard]] bool triangleContainsPoint(const glm::vec2, ConstFaceVertexIter) const; - -private: - glm::vec3 lowerExtent {}, upperExtent {}; -}; diff --git a/test/Jamfile.jam b/test/Jamfile.jam index d88a238..6f62056 100644 --- a/test/Jamfile.jam +++ b/test/Jamfile.jam @@ -46,7 +46,7 @@ lib test : [ glob *.cpp : test-*.cpp perf-*.cpp ] ; run test-collection.cpp ; run test-maths.cpp ; run test-lib.cpp ; -run test-geo.cpp ; +run test-geoData.cpp : -- : fixtures/height/SD19.asc : test ; run test-network.cpp : : : test ; run test-persistence.cpp : -- : [ sequence.insertion-sort [ glob-tree fixtures : *.json ] ] : test ; run test-text.cpp : : : test ; @@ -55,13 +55,12 @@ run test-render.cpp : -- : test-assetFactory : test ; run test-glContextBhvr.cpp ; run test-assetFactory.cpp : -- : [ sequence.insertion-sort [ glob-tree $(res) : *.* ] fixtures/rgb.txt test-instancing ] : test ; run perf-assetFactory.cpp : -- : test-assetFactory : benchmark test ; +run perf-geoData.cpp : : : test benchmark ; run perf-persistence.cpp : -- : test-persistence : benchmark test ; run test-worker.cpp ; run test-instancing.cpp : : : test ; run test-glContainer.cpp : : : test ; run test-pack.cpp : : : test ; -run test-terrain.cpp : -- : fixtures/height/SD19.asc : test ..//OpenMeshCore ; -run perf-terrain.cpp : : : test ..//OpenMeshCore benchmark ; compile test-static-enumDetails.cpp ; compile test-static-stream_support.cpp ; explicit perf-assetFactory ; diff --git a/test/perf-geoData.cpp b/test/perf-geoData.cpp new file mode 100644 index 0000000..e1546c1 --- /dev/null +++ b/test/perf-geoData.cpp @@ -0,0 +1,18 @@ +#include +#include + +namespace { + const GeoData tm {GeoData::loadFromAsciiGrid(FIXTURESDIR "height/SD19.asc")}; + + void + terrain_findPoint(benchmark::State & state) + { + for (auto _ : state) { + benchmark::DoNotOptimize(tm.findPoint({315555, 495556})); + } + } +} + +BENCHMARK(terrain_findPoint); + +BENCHMARK_MAIN(); diff --git a/test/perf-terrain.cpp b/test/perf-terrain.cpp deleted file mode 100644 index e998f60..0000000 --- a/test/perf-terrain.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include -#include - -namespace { - const TerrainMesh tm {FIXTURESDIR "height/SD19.asc"}; - - void - terrain_findPoint(benchmark::State & state) - { - for (auto _ : state) { - benchmark::DoNotOptimize(tm.findPoint({315555, 495556})); - } - } -} - -BENCHMARK(terrain_findPoint); - -BENCHMARK_MAIN(); diff --git a/test/test-geo.cpp b/test/test-geo.cpp deleted file mode 100644 index 9874fb7..0000000 --- a/test/test-geo.cpp +++ /dev/null @@ -1,225 +0,0 @@ -#define BOOST_TEST_MODULE test_geo - -#include "testHelpers.h" -#include -#include -#include - -#include -#include - -struct TestGeoData : public GeoData { - TestGeoData() : GeoData {{{-10, -5}, {30, 40}}, 5.F} { } -}; - -namespace std { - std::ostream & - operator<<(std::ostream & s, const Ray & r) - { - return (s << r.start << "->" << r.direction); - } -} - -BOOST_FIXTURE_TEST_SUITE(tgd, TestGeoData) - -BOOST_AUTO_TEST_CASE(initialize) -{ - BOOST_CHECK_EQUAL(limit.first, glm::ivec2(-10, -5)); - BOOST_CHECK_EQUAL(limit.second, glm::ivec2(30, 40)); - BOOST_CHECK_EQUAL(scale, 5.F); - BOOST_CHECK_EQUAL(size, glm::uvec2(41, 46)); - BOOST_CHECK_EQUAL(nodes.size(), 1886); - BOOST_CHECK(std::all_of(nodes.begin(), nodes.end(), [](const auto & n) { - return n.height == -1.5F; - })); -} - -BOOST_AUTO_TEST_CASE(coords) -{ - BOOST_CHECK_EQUAL(at(-10, -5), 0); - BOOST_CHECK_EQUAL(at(-9, -5), 1); - BOOST_CHECK_EQUAL(at(0, -5), 10); - BOOST_CHECK_EQUAL(at(30, -5), 40); - BOOST_CHECK_EQUAL(at(30, 40), 1885); -} - -BOOST_AUTO_TEST_CASE(coords_bad) -{ - BOOST_CHECK_THROW(std::ignore = at(-11, -5), std::range_error); - BOOST_CHECK_THROW(std::ignore = at(-10, -6), std::range_error); - BOOST_CHECK_THROW(std::ignore = at(-11, -6), std::range_error); - BOOST_CHECK_THROW(std::ignore = at(31, 40), std::range_error); - BOOST_CHECK_THROW(std::ignore = at(30, 41), std::range_error); - BOOST_CHECK_THROW(std::ignore = at(31, 41), std::range_error); -} - -BOOST_AUTO_TEST_CASE(gen_random) -{ - // Can only really its sanity - generateRandom(); - // Some terrain above sea level - BOOST_CHECK(std::any_of(nodes.begin(), nodes.end(), [](const auto & n) { - return n.height > 0; - })); - // Still an island - for (int x = limit.first.x; x <= limit.second.x; x += 1) { - BOOST_CHECK_EQUAL(nodes[at(x, limit.first.y)].height, -1.5F); - BOOST_CHECK_EQUAL(nodes[at(x, limit.second.y)].height, -1.5F); - } - for (int y = limit.first.y; y <= limit.second.y; y += 1) { - BOOST_CHECK_EQUAL(nodes[at(limit.first.x, y)].height, -1.5F); - BOOST_CHECK_EQUAL(nodes[at(limit.second.x, y)].height, -1.5F); - } -} - -BOOST_AUTO_TEST_CASE(load_uk_heightmap) -{ - loadFromImages(FIXTURESDIR "/height/V0txo.jpg", 100.F); - // Some terrain above sea level - BOOST_CHECK(std::any_of(nodes.begin(), nodes.end(), [](const auto & n) { - return n.height > 0; - })); -} - -BOOST_AUTO_TEST_CASE(get_height_at) -{ - // at(x,y) is index based - nodes[at(0, 0)].height = 1; - nodes[at(1, 0)].height = 2; - nodes[at(0, 1)].height = 3; - nodes[at(1, 1)].height = 4; - - // positionAt(x,y) is world based - // Corners - BOOST_CHECK_EQUAL(positionAt({0, 0}), glm::vec3(0, 0, 1)); - BOOST_CHECK_EQUAL(positionAt({5, 0}), glm::vec3(5, 0, 2)); - BOOST_CHECK_EQUAL(positionAt({0, 5}), glm::vec3(0, 5, 3)); - BOOST_CHECK_EQUAL(positionAt({5, 5}), glm::vec3(5, 5, 4)); - - // Edge midpoints - BOOST_CHECK_EQUAL(positionAt({0, 2.5F}), glm::vec3(0, 2.5F, 2)); - BOOST_CHECK_EQUAL(positionAt({5, 2.5F}), glm::vec3(5, 2.5F, 3)); - BOOST_CHECK_EQUAL(positionAt({2.5F, 0}), glm::vec3(2.5F, 0, 1.5F)); - BOOST_CHECK_EQUAL(positionAt({2.5F, 5}), glm::vec3(2.5F, 5, 3.5F)); - - // Centre - BOOST_CHECK_EQUAL(positionAt({2.5F, 2.5F}), glm::vec3(2.5F, 2.5F, 2.5F)); -} - -using TestRayTracerData = std::tuple>; -BOOST_TEST_DECORATOR(*boost::unit_test::timeout(1)) - -BOOST_DATA_TEST_CASE(raytracer, - boost::unit_test::data::make({ - {{1, 2}, {4, 5}, 4, - { - {0, 0}, - {0, 4}, - {4, 4}, - {4, 8}, - {8, 8}, - {8, 12}, - {12, 12}, - {12, 16}, - {12, 20}, - {16, 20}, - }}, - {{-1, -1}, {-4, -5}, 5, - { - {-5, -5}, - {-5, -10}, - {-10, -10}, - {-10, -15}, - {-15, -15}, - {-15, -20}, - {-20, -20}, - {-20, -25}, - }}, - }), - start, dir, scale, points) -{ - GeoData::RayTracer rt {start / scale, glm::normalize(dir)}; - for (const auto & point : points) { - BOOST_CHECK_CLOSE_VEC(point, rt.next() * scale); - } -} - -using TestRayData = std::tuple; -BOOST_TEST_DECORATOR(*boost::unit_test::timeout(1)) - -BOOST_DATA_TEST_CASE(intersect_ray, - boost::unit_test::data::make({ - {{-1, -1, 1.0}, {1, 1, 0}, {0, 0, 1}}, - {{-1, -1, 2.5}, {1, 1, 0}, {2.5F, 2.5F, 2.5F}}, - {{-20, -20, 2.5}, {1, 1, 0}, {2.5F, 2.5F, 2.5F}}, - // outside the map looking in - {{-205, -205, 4}, {1, 1, 0}, {5, 5, 4}}, - {{-205, 5, 4}, {1, 0, 0}, {5, 5, 4}}, - {{-205, 215, 4}, {1, -1, 0}, {5, 5, 4}}, - {{215, -205, 4}, {-1, 1, 0}, {5, 5, 4}}, - {{215, 5, 4}, {-1, 0, 0}, {5, 5, 4}}, - {{215, 215, 4}, {-1, -1, 0}, {5, 5, 4}}, - {{5, 215, 4}, {0, -1, 0}, {5, 5, 4}}, - {{5, -205, 4}, {0, 1, 0}, {5, 5, 4}}, - }), - start, dir, pos) -{ - // at(x,y) is index based - nodes[at(0, 0)].height = 1; - nodes[at(1, 0)].height = 2; - nodes[at(0, 1)].height = 3; - nodes[at(1, 1)].height = 4; - - const auto intersect = intersectRay({start, glm::normalize(dir)}); - - BOOST_CHECK_IF(has_intersect, intersect) { - BOOST_CHECK_CLOSE_VEC(*intersect, pos); - } -} - -auto xs = boost::unit_test::data::xrange(-20.F, 0.F, 0.6F), ys = boost::unit_test::data::xrange(-20.F, 0.F, 0.7F); -auto targetsx = boost::unit_test::data::xrange(0.2F, 4.9F, 1.3F), - targetsy = boost::unit_test::data::xrange(0.3F, 4.9F, 1.3F); -BOOST_TEST_DECORATOR(*boost::unit_test::timeout(1)) - -BOOST_DATA_TEST_CASE(intersect_ray_many, xs * ys * targetsx * targetsy, x, y, targetx, targety) -{ - // at(x,y) is index based - nodes[at(0, 0)].height = 1; - nodes[at(1, 0)].height = 2; - nodes[at(0, 1)].height = 3; - nodes[at(1, 1)].height = 4; - - const glm::vec3 start {x, y, 10}; - const auto target {this->positionAt({targetx, targety})}; - const Ray ray {start, glm::normalize(target - start)}; - - BOOST_TEST_CONTEXT(ray) { - const auto intersect = intersectRay(ray); - - BOOST_CHECK_IF(has_intersect, intersect) { - BOOST_CHECK_CLOSE_VEC(*intersect, target); - } - } -} - -BOOST_TEST_DECORATOR(*boost::unit_test::timeout(1)) - -BOOST_DATA_TEST_CASE(intersect_ray_miss, - boost::unit_test::data::make({ - {{3, 3, 5}, {-1, -1, 0}}, - {{0, 0, 5}, {0, 0, 1}}, - {{0, 0, 5}, {0, 0, -1}}, - }), - ray) -{ - // at(x,y) is index based - nodes[at(0, 0)].height = 1; - nodes[at(1, 0)].height = 2; - nodes[at(0, 1)].height = 3; - nodes[at(1, 1)].height = 4; - - BOOST_REQUIRE(!intersectRay(ray)); -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/test-geoData.cpp b/test/test-geoData.cpp new file mode 100644 index 0000000..d79f5b8 --- /dev/null +++ b/test/test-geoData.cpp @@ -0,0 +1,175 @@ +#define BOOST_TEST_MODULE terrain +#include "testHelpers.h" +#include +#include +#include + +#include + +class TestTerrainMesh : public GeoData { +public: + TestTerrainMesh() : GeoData {GeoData::loadFromAsciiGrid(FIXTURESDIR "height/SD19.asc")} { } +}; + +constexpr size_t ncols = 200, nrows = 200, xllcorner = 310000, yllcorner = 490000, cellsize = 50; + +BOOST_FIXTURE_TEST_SUITE(ttm, TestTerrainMesh); + +BOOST_AUTO_TEST_CASE(loadSuccess) +{ + BOOST_CHECK_EQUAL(ncols * nrows, n_vertices()); + BOOST_CHECK_EQUAL(2 * (ncols - 1) * (nrows - 1), n_faces()); + const auto [lower, upper] = getExtents(); + BOOST_CHECK_EQUAL(lower, glm::vec3(310000, 490000, -2.6)); + BOOST_CHECK_EQUAL(upper, glm::vec3(320000, 500000, 571.6)); +} + +BOOST_AUTO_TEST_CASE(normalsAllPointUp) +{ + BOOST_CHECK(std::all_of(faces_begin(), faces_end(), [this](auto && vh) { + return normal(vh).z > 0; + })); + BOOST_CHECK(std::all_of(vertices_begin(), vertices_end(), [this](auto && vh) { + return normal(vh).z > 0; + })); +} + +BOOST_AUTO_TEST_CASE(trianglesContainsPoints) +{ + const auto face = face_handle(0); + auto vertices = cfv_iter(face); + + BOOST_TEST_CONTEXT(point(*vertices++) << point(*vertices++) << point(*vertices++)) { + BOOST_CHECK(triangleContainsPoint(glm::vec2 {xllcorner, yllcorner}, face)); + BOOST_CHECK(triangleContainsPoint(glm::vec2 {xllcorner + cellsize, yllcorner + cellsize}, face)); + BOOST_CHECK(triangleContainsPoint(glm::vec2 {xllcorner, yllcorner + cellsize}, face)); + BOOST_CHECK(triangleContainsPoint(glm::vec2 {xllcorner + 1, yllcorner + 1}, face)); + BOOST_CHECK(triangleContainsPoint(glm::vec2 {xllcorner + 1, yllcorner + 2}, face)); + BOOST_CHECK(!triangleContainsPoint(glm::vec2 {xllcorner + 3, yllcorner + 2}, face)); + BOOST_CHECK(!triangleContainsPoint(glm::vec2 {xllcorner + cellsize, yllcorner}, face)); + } +} + +BOOST_AUTO_TEST_CASE(locatePointFace) +{ + const PointFace pf {{310002, 490003}}; + BOOST_CHECK(!pf.isLocated()); + BOOST_CHECK(pf.face(this).is_valid()); + BOOST_CHECK_EQUAL(pf.face(this).idx(), 0); +} + +BOOST_AUTO_TEST_CASE(preLocatePointFace) +{ + const PointFace pf {{310002, 490003}, this}; + BOOST_CHECK(pf.isLocated()); + BOOST_CHECK_EQUAL(pf.face(this).idx(), 0); +} + +BOOST_AUTO_TEST_SUITE_END(); + +using FindPointData = std::tuple; + +static const TestTerrainMesh fixedTerrtain; + +// No boundary cases as these can produce different valid results depending on starting point +BOOST_DATA_TEST_CASE(findPointOnTerrain, + boost::unit_test::data::make({ + {{0, 0}, -1}, {{xllcorner, 0}, -1}, {{0, yllcorner}, -1}, {{xllcorner + 1, yllcorner + 2}, 0}, + {{xllcorner + (cellsize * (nrows - 1)) - 2, yllcorner + (cellsize * (ncols - 1)) - 1}, 79200}, + {{315555, 495556}, 44400}, // perf test target + }) + * boost::unit_test::data::make( + {0, 1, 2, 3, 4, 5, 6, 10, 100, 150, 200, 1000, 1234, 17439, 79201, 79200, 79199}), + p, fh, start) +{ + BOOST_CHECK_EQUAL(fh, fixedTerrtain.findPoint(p, GeoData::FaceHandle(start)).idx()); +} + +using FindPositionData = std::tuple; + +BOOST_DATA_TEST_CASE(findPositionAt, + boost::unit_test::data::make({ + // corners + {{310000, 490000}, 32.8F}, + {{310050, 490050}, 33.0F}, + {{310000, 490050}, 32.7F}, + {{310050, 490000}, 33.2F}, + {{310750, 490150}, 58.4F}, + // midpoints + {{310025, 490025}, 32.9F}, + {{310025, 490050}, 32.85F}, + {{310000, 490025}, 32.75F}, + // other + {{310751, 490152}, 58.326F}, + }), + p, h) +{ + BOOST_CHECK_CLOSE_VEC(fixedTerrtain.positionAt(p), p ^ h); +} + +using FindRayIntersectData = std::tuple; + +BOOST_DATA_TEST_CASE(findRayIntersect, + boost::unit_test::data::make({ + {{310000, 490000, 50}, {1, 1, -2}, {310008.59, 490008.59, 32.834301}}, + {{310000, 490000, 50}, {1, 1, -1}, {310017.12, 490017.12, 32.868526}}, + }), + p, d, i) +{ + BOOST_CHECK_CLOSE_VEC(fixedTerrtain.intersectRay({p, d}).value(), i); +} + +using WalkTerrainData = std::tuple>; + +BOOST_DATA_TEST_CASE(walkTerrain, + boost::unit_test::data::make({ + {{310002, 490003}, {310002, 490003}, {0}}, + {{310003, 490002}, {310003, 490002}, {1}}, + {{310002, 490003}, {310003, 490002}, {0, 1}}, + {{310003, 490002}, {310002, 490003}, {1, 0}}, + {{310002, 490003}, {310202, 490003}, {0, 1, 2, 3, 4, 5, 6, 7, 8}}, + {{310202, 490003}, {310002, 490003}, {8, 7, 6, 5, 4, 3, 2, 1, 0}}, + {{310002, 490003}, {310002, 490203}, {0, 399, 398, 797, 796, 1195, 1194, 1593, 1592}}, + }), + from, to, visits) +{ + std::vector visited; + BOOST_CHECK_NO_THROW(fixedTerrtain.walk(from, to, [&visited](auto fh) { + visited.emplace_back(fh.idx()); + })); + BOOST_CHECK_EQUAL_COLLECTIONS(visited.begin(), visited.end(), visits.begin(), visits.end()); +} + +BOOST_DATA_TEST_CASE(walkTerrainSetsFromFace, + boost::unit_test::data::make({ + {{310002, 490003}, {310002, 490003}, {0}}, + {{310003, 490002}, {310003, 490002}, {1}}, + {{310002, 490003}, {310003, 490002}, {0, 1}}, + {{310003, 490002}, {310002, 490003}, {1, 0}}, + }), + from, to, visits) +{ + GeoData::PointFace pf {from}; + BOOST_CHECK_NO_THROW(fixedTerrtain.walk(pf, to, [](auto) {})); + BOOST_CHECK_EQUAL(pf.face(&fixedTerrtain).idx(), visits.front()); +} + +BOOST_DATA_TEST_CASE(walkTerrainUntil, + boost::unit_test::data::make({ + {{310002, 490003}, {310002, 490003}, {0}}, + {{310003, 490002}, {310003, 490002}, {1}}, + {{310002, 490003}, {310003, 490002}, {0, 1}}, + {{310003, 490002}, {310002, 490003}, {1, 0}}, + {{310002, 490003}, {310202, 490003}, {0, 1, 2, 3, 4}}, + {{310202, 490003}, {310002, 490003}, {8, 7, 6, 5, 4}}, + {{310002, 490003}, {310002, 490203}, {0, 399, 398, 797, 796}}, + }), + from, to, visits) +{ + std::vector visited; + BOOST_CHECK_NO_THROW(fixedTerrtain.walkUntil(from, to, [&visited](auto fh) { + visited.emplace_back(fh.idx()); + return visited.size() >= 5; + })); + BOOST_CHECK_EQUAL_COLLECTIONS(visited.begin(), visited.end(), visits.begin(), visits.end()); +} diff --git a/test/test-render.cpp b/test/test-render.cpp index b16f241..fb2a71b 100644 --- a/test/test-render.cpp +++ b/test/test-render.cpp @@ -26,8 +26,7 @@ class TestScene : public SceneProvider { std::shared_ptr train1, train2; Terrain terrain {[]() { - auto gd = std::make_shared(GeoData::Limits {{0, 0}, {100, 100}}); - gd->generateRandom(); + auto gd = std::make_shared(GeoData::createFlat({0, 0}, {1000, 1000}, 1)); return gd; }()}; diff --git a/test/test-terrain.cpp b/test/test-terrain.cpp deleted file mode 100644 index 71fc1ec..0000000 --- a/test/test-terrain.cpp +++ /dev/null @@ -1,175 +0,0 @@ -#define BOOST_TEST_MODULE terrain -#include "testHelpers.h" -#include -#include -#include - -#include - -class TestTerrainMesh : public TerrainMesh { -public: - TestTerrainMesh() : TerrainMesh {TerrainMesh::loadFromAsciiGrid(FIXTURESDIR "height/SD19.asc")} { } -}; - -constexpr size_t ncols = 200, nrows = 200, xllcorner = 310000, yllcorner = 490000, cellsize = 50; - -BOOST_FIXTURE_TEST_SUITE(ttm, TestTerrainMesh); - -BOOST_AUTO_TEST_CASE(loadSuccess) -{ - BOOST_CHECK_EQUAL(ncols * nrows, n_vertices()); - BOOST_CHECK_EQUAL(2 * (ncols - 1) * (nrows - 1), n_faces()); - const auto [lower, upper] = getExtents(); - BOOST_CHECK_EQUAL(lower, glm::vec3(310000, 490000, -2.6)); - BOOST_CHECK_EQUAL(upper, glm::vec3(320000, 500000, 571.6)); -} - -BOOST_AUTO_TEST_CASE(normalsAllPointUp) -{ - BOOST_CHECK(std::all_of(faces_begin(), faces_end(), [this](auto && vh) { - return normal(vh).z > 0; - })); - BOOST_CHECK(std::all_of(vertices_begin(), vertices_end(), [this](auto && vh) { - return normal(vh).z > 0; - })); -} - -BOOST_AUTO_TEST_CASE(trianglesContainsPoints) -{ - const auto face = face_handle(0); - auto vertices = cfv_iter(face); - - BOOST_TEST_CONTEXT(point(*vertices++) << point(*vertices++) << point(*vertices++)) { - BOOST_CHECK(triangleContainsPoint(glm::vec2 {xllcorner, yllcorner}, face)); - BOOST_CHECK(triangleContainsPoint(glm::vec2 {xllcorner + cellsize, yllcorner + cellsize}, face)); - BOOST_CHECK(triangleContainsPoint(glm::vec2 {xllcorner, yllcorner + cellsize}, face)); - BOOST_CHECK(triangleContainsPoint(glm::vec2 {xllcorner + 1, yllcorner + 1}, face)); - BOOST_CHECK(triangleContainsPoint(glm::vec2 {xllcorner + 1, yllcorner + 2}, face)); - BOOST_CHECK(!triangleContainsPoint(glm::vec2 {xllcorner + 3, yllcorner + 2}, face)); - BOOST_CHECK(!triangleContainsPoint(glm::vec2 {xllcorner + cellsize, yllcorner}, face)); - } -} - -BOOST_AUTO_TEST_CASE(locatePointFace) -{ - const PointFace pf {{310002, 490003}}; - BOOST_CHECK(!pf.isLocated()); - BOOST_CHECK(pf.face(this).is_valid()); - BOOST_CHECK_EQUAL(pf.face(this).idx(), 0); -} - -BOOST_AUTO_TEST_CASE(preLocatePointFace) -{ - const PointFace pf {{310002, 490003}, this}; - BOOST_CHECK(pf.isLocated()); - BOOST_CHECK_EQUAL(pf.face(this).idx(), 0); -} - -BOOST_AUTO_TEST_SUITE_END(); - -using FindPointData = std::tuple; - -static const TestTerrainMesh fixedTerrtain; - -// No boundary cases as these can produce different valid results depending on starting point -BOOST_DATA_TEST_CASE(findPointOnTerrain, - boost::unit_test::data::make({ - {{0, 0}, -1}, {{xllcorner, 0}, -1}, {{0, yllcorner}, -1}, {{xllcorner + 1, yllcorner + 2}, 0}, - {{xllcorner + (cellsize * (nrows - 1)) - 2, yllcorner + (cellsize * (ncols - 1)) - 1}, 79200}, - {{315555, 495556}, 44400}, // perf test target - }) - * boost::unit_test::data::make( - {0, 1, 2, 3, 4, 5, 6, 10, 100, 150, 200, 1000, 1234, 17439, 79201, 79200, 79199}), - p, fh, start) -{ - BOOST_CHECK_EQUAL(fh, fixedTerrtain.findPoint(p, TerrainMesh::FaceHandle(start)).idx()); -} - -using FindPositionData = std::tuple; - -BOOST_DATA_TEST_CASE(findPositionAt, - boost::unit_test::data::make({ - // corners - {{310000, 490000}, 32.8F}, - {{310050, 490050}, 33.0F}, - {{310000, 490050}, 32.7F}, - {{310050, 490000}, 33.2F}, - {{310750, 490150}, 58.4F}, - // midpoints - {{310025, 490025}, 32.9F}, - {{310025, 490050}, 32.85F}, - {{310000, 490025}, 32.75F}, - // other - {{310751, 490152}, 58.326F}, - }), - p, h) -{ - BOOST_CHECK_CLOSE_VEC(fixedTerrtain.positionAt(p), p ^ h); -} - -using FindRayIntersectData = std::tuple; - -BOOST_DATA_TEST_CASE(findRayIntersect, - boost::unit_test::data::make({ - {{310000, 490000, 50}, {1, 1, -2}, {310008.59, 490008.59, 32.834301}}, - {{310000, 490000, 50}, {1, 1, -1}, {310017.12, 490017.12, 32.868526}}, - }), - p, d, i) -{ - BOOST_CHECK_CLOSE_VEC(fixedTerrtain.intersectRay({p, d}).value(), i); -} - -using WalkTerrainData = std::tuple>; - -BOOST_DATA_TEST_CASE(walkTerrain, - boost::unit_test::data::make({ - {{310002, 490003}, {310002, 490003}, {0}}, - {{310003, 490002}, {310003, 490002}, {1}}, - {{310002, 490003}, {310003, 490002}, {0, 1}}, - {{310003, 490002}, {310002, 490003}, {1, 0}}, - {{310002, 490003}, {310202, 490003}, {0, 1, 2, 3, 4, 5, 6, 7, 8}}, - {{310202, 490003}, {310002, 490003}, {8, 7, 6, 5, 4, 3, 2, 1, 0}}, - {{310002, 490003}, {310002, 490203}, {0, 399, 398, 797, 796, 1195, 1194, 1593, 1592}}, - }), - from, to, visits) -{ - std::vector visited; - BOOST_CHECK_NO_THROW(fixedTerrtain.walk(from, to, [&visited](auto fh) { - visited.emplace_back(fh.idx()); - })); - BOOST_CHECK_EQUAL_COLLECTIONS(visited.begin(), visited.end(), visits.begin(), visits.end()); -} - -BOOST_DATA_TEST_CASE(walkTerrainSetsFromFace, - boost::unit_test::data::make({ - {{310002, 490003}, {310002, 490003}, {0}}, - {{310003, 490002}, {310003, 490002}, {1}}, - {{310002, 490003}, {310003, 490002}, {0, 1}}, - {{310003, 490002}, {310002, 490003}, {1, 0}}, - }), - from, to, visits) -{ - TerrainMesh::PointFace pf {from}; - BOOST_CHECK_NO_THROW(fixedTerrtain.walk(pf, to, [](auto) {})); - BOOST_CHECK_EQUAL(pf.face(&fixedTerrtain).idx(), visits.front()); -} - -BOOST_DATA_TEST_CASE(walkTerrainUntil, - boost::unit_test::data::make({ - {{310002, 490003}, {310002, 490003}, {0}}, - {{310003, 490002}, {310003, 490002}, {1}}, - {{310002, 490003}, {310003, 490002}, {0, 1}}, - {{310003, 490002}, {310002, 490003}, {1, 0}}, - {{310002, 490003}, {310202, 490003}, {0, 1, 2, 3, 4}}, - {{310202, 490003}, {310002, 490003}, {8, 7, 6, 5, 4}}, - {{310002, 490003}, {310002, 490203}, {0, 399, 398, 797, 796}}, - }), - from, to, visits) -{ - std::vector visited; - BOOST_CHECK_NO_THROW(fixedTerrtain.walkUntil(from, to, [&visited](auto fh) { - visited.emplace_back(fh.idx()); - return visited.size() >= 5; - })); - BOOST_CHECK_EQUAL_COLLECTIONS(visited.begin(), visited.end(), visits.begin(), visits.end()); -} diff --git a/ui/gameMainWindow.cpp b/ui/gameMainWindow.cpp index c35c9c6..6981c54 100644 --- a/ui/gameMainWindow.cpp +++ b/ui/gameMainWindow.cpp @@ -31,7 +31,7 @@ public: GameMainWindow::GameMainWindow(size_t w, size_t h) : Window {w, h, "I Like Trains", SDL_WINDOW_OPENGL}, SceneRenderer {Window::size, 0} { - uiComponents.create(glm::vec2 {-1150, -1150}); + uiComponents.create(glm::vec2 {315000, 495000}); auto gms = uiComponents.create(&camera, glm::vec2 {w, h}); uiComponents.create(gms.get()); } -- cgit v1.2.3 From 5ed36466b48aa347277c70422eb00bee264a5c8b Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 4 Nov 2023 17:07:58 +0000 Subject: Simplify some logic with the triangle construct --- game/geoData.cpp | 26 ++++++++++---------------- game/geoData.h | 10 ++++++++-- test/test-geoData.cpp | 3 +-- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/game/geoData.cpp b/game/geoData.cpp index d32bf8c..5e49c94 100644 --- a/game/geoData.cpp +++ b/game/geoData.cpp @@ -135,8 +135,7 @@ namespace { OpenMesh::FaceHandle GeoData::findPoint(glm::vec2 p, OpenMesh::FaceHandle f) const { - ConstFaceVertexIter vertices; - while (f.is_valid() && !triangleContainsPoint(p, vertices = cfv_iter(f))) { + while (f.is_valid() && !triangleContainsPoint(p, triangle<2>(f))) { for (auto next = cfh_iter(f); next.is_valid(); ++next) { f = opposite_face_handle(*next); if (f.is_valid()) { @@ -156,7 +155,7 @@ glm::vec3 GeoData::positionAt(const PointFace & p) const { glm::vec3 out {}; - Triangle<3> t {this, fv_range(p.face(this))}; + const auto t = triangle<3>(p.face(this)); glm::intersectLineTriangle(p.point ^ 0.F, up, t[0], t[1], t[2], out); return p.point ^ out[0]; } @@ -174,7 +173,7 @@ GeoData::intersectRay(const Ray & ray, FaceHandle face) const walkUntil(PointFace {ray.start, face}, ray.start + (ray.direction * 10000.F), [&out, &ray, this](FaceHandle face) { glm::vec2 bari {}; float dist {}; - Triangle<3> t {this, fv_range(face)}; + const auto t = triangle<3>(face); if (glm::intersectRayTriangle(ray.start, ray.direction, t[0], t[1], t[2], bari, dist)) { out = t * bari; return true; @@ -216,23 +215,18 @@ GeoData::walkUntil(const PointFace & from, const glm::vec2 to, const std::functi } bool -GeoData::triangleContainsPoint(const glm::vec2 p, const glm::vec2 a, const glm::vec2 b, const glm::vec2 c) +GeoData::triangleContainsPoint(const glm::vec2 p, const Triangle<2> & t) { - const auto det = (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x); + const auto mul = [](const glm::vec2 a, const glm::vec2 b, const glm::vec2 c) { + return (a.x - b.x) * (c.y - b.y) - (a.y - b.y) * (c.x - b.x); + }; + const auto det = mul(t[1], t[0], t[2]); - return det * ((b.x - a.x) * (p.y - a.y) - (b.y - a.y) * (p.x - a.x)) >= 0 - && det * ((c.x - b.x) * (p.y - b.y) - (c.y - b.y) * (p.x - b.x)) >= 0 - && det * ((a.x - c.x) * (p.y - c.y) - (a.y - c.y) * (p.x - c.x)) >= 0; + return det * mul(t[1], t[0], p) >= 0 && det * mul(t[2], t[1], p) >= 0 && det * mul(t[0], t[2], p) >= 0; } bool GeoData::triangleContainsPoint(const glm::vec2 p, FaceHandle face) const { - return triangleContainsPoint(p, cfv_iter(face)); -} - -bool -GeoData::triangleContainsPoint(const glm::vec2 p, ConstFaceVertexIter vertices) const -{ - return triangleContainsPoint(p, point(*vertices++), point(*vertices++), point(*vertices++)); + return triangleContainsPoint(p, triangle<2>(face)); } diff --git a/game/geoData.h b/game/geoData.h index 3a4f98e..b8561d0 100644 --- a/game/geoData.h +++ b/game/geoData.h @@ -85,9 +85,15 @@ public: } protected: - [[nodiscard]] static bool triangleContainsPoint(const glm::vec2, const glm::vec2, const glm::vec2, const glm::vec2); + template + [[nodiscard]] Triangle + triangle(FaceHandle f) const + { + return {this, fv_range(f)}; + } + + [[nodiscard]] static bool triangleContainsPoint(const glm::vec2, const Triangle<2> &); [[nodiscard]] bool triangleContainsPoint(const glm::vec2, FaceHandle) const; - [[nodiscard]] bool triangleContainsPoint(const glm::vec2, ConstFaceVertexIter) const; private: glm::vec3 lowerExtent {}, upperExtent {}; diff --git a/test/test-geoData.cpp b/test/test-geoData.cpp index d79f5b8..b33c61e 100644 --- a/test/test-geoData.cpp +++ b/test/test-geoData.cpp @@ -37,9 +37,8 @@ BOOST_AUTO_TEST_CASE(normalsAllPointUp) BOOST_AUTO_TEST_CASE(trianglesContainsPoints) { const auto face = face_handle(0); - auto vertices = cfv_iter(face); - BOOST_TEST_CONTEXT(point(*vertices++) << point(*vertices++) << point(*vertices++)) { + BOOST_TEST_CONTEXT(GeoData::Triangle<2>(this, fv_range(face))) { BOOST_CHECK(triangleContainsPoint(glm::vec2 {xllcorner, yllcorner}, face)); BOOST_CHECK(triangleContainsPoint(glm::vec2 {xllcorner + cellsize, yllcorner + cellsize}, face)); BOOST_CHECK(triangleContainsPoint(glm::vec2 {xllcorner, yllcorner + cellsize}, face)); -- cgit v1.2.3 From 9ab1214aca7d77e1083476b05c6ddc2bb351bbac Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 4 Nov 2023 19:09:58 +0000 Subject: More tests can just use the global fixed data --- test/test-geoData.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/test/test-geoData.cpp b/test/test-geoData.cpp index b33c61e..258bd9c 100644 --- a/test/test-geoData.cpp +++ b/test/test-geoData.cpp @@ -49,27 +49,27 @@ BOOST_AUTO_TEST_CASE(trianglesContainsPoints) } } +BOOST_AUTO_TEST_SUITE_END(); + +static const TestTerrainMesh fixedTerrtain; + BOOST_AUTO_TEST_CASE(locatePointFace) { - const PointFace pf {{310002, 490003}}; + const GeoData::PointFace pf {{310002, 490003}}; BOOST_CHECK(!pf.isLocated()); - BOOST_CHECK(pf.face(this).is_valid()); - BOOST_CHECK_EQUAL(pf.face(this).idx(), 0); + BOOST_CHECK(pf.face(&fixedTerrtain).is_valid()); + BOOST_CHECK_EQUAL(pf.face(&fixedTerrtain).idx(), 0); } BOOST_AUTO_TEST_CASE(preLocatePointFace) { - const PointFace pf {{310002, 490003}, this}; + const GeoData::PointFace pf {{310002, 490003}, &fixedTerrtain}; BOOST_CHECK(pf.isLocated()); - BOOST_CHECK_EQUAL(pf.face(this).idx(), 0); + BOOST_CHECK_EQUAL(pf.face(&fixedTerrtain).idx(), 0); } -BOOST_AUTO_TEST_SUITE_END(); - using FindPointData = std::tuple; -static const TestTerrainMesh fixedTerrtain; - // No boundary cases as these can produce different valid results depending on starting point BOOST_DATA_TEST_CASE(findPointOnTerrain, boost::unit_test::data::make({ -- cgit v1.2.3 From f53816a8fd9ec15ef03b5bf45472eda46e53c1ad Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 4 Nov 2023 21:05:35 +0000 Subject: Refactor to further simplify line/point operations Adds another perf test --- game/geoData.cpp | 18 +++++++++--------- test/perf-geoData.cpp | 13 +++++++++++++ 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/game/geoData.cpp b/game/geoData.cpp index 5e49c94..c58658a 100644 --- a/game/geoData.cpp +++ b/game/geoData.cpp @@ -111,12 +111,16 @@ GeoData::PointFace::face(const GeoData * mesh) const } namespace { - [[nodiscard]] constexpr inline bool - pointLeftOfLine(const glm::vec2 p, const glm::vec2 e1, const glm::vec2 e2) + template typename Op> + [[nodiscard]] constexpr inline auto + pointLineOp(const glm::vec2 p, const glm::vec2 e1, const glm::vec2 e2) { - return (e2.x - e1.x) * (p.y - e1.y) > (e2.y - e1.y) * (p.x - e1.x); + return Op {}((e2.x - e1.x) * (p.y - e1.y), (e2.y - e1.y) * (p.x - e1.x)); } + constexpr auto pointLeftOfLine = pointLineOp; + constexpr auto pointLeftOfOrOnLine = pointLineOp; + static_assert(pointLeftOfLine({1, 2}, {1, 1}, {2, 2})); static_assert(pointLeftOfLine({2, 1}, {2, 2}, {1, 1})); static_assert(pointLeftOfLine({2, 2}, {1, 2}, {2, 1})); @@ -217,12 +221,8 @@ GeoData::walkUntil(const PointFace & from, const glm::vec2 to, const std::functi bool GeoData::triangleContainsPoint(const glm::vec2 p, const Triangle<2> & t) { - const auto mul = [](const glm::vec2 a, const glm::vec2 b, const glm::vec2 c) { - return (a.x - b.x) * (c.y - b.y) - (a.y - b.y) * (c.x - b.x); - }; - const auto det = mul(t[1], t[0], t[2]); - - return det * mul(t[1], t[0], p) >= 0 && det * mul(t[2], t[1], p) >= 0 && det * mul(t[0], t[2], p) >= 0; + return pointLeftOfOrOnLine(p, t[0], t[1]) && pointLeftOfOrOnLine(p, t[1], t[2]) + && pointLeftOfOrOnLine(p, t[2], t[0]); } bool diff --git a/test/perf-geoData.cpp b/test/perf-geoData.cpp index e1546c1..2d79a90 100644 --- a/test/perf-geoData.cpp +++ b/test/perf-geoData.cpp @@ -11,8 +11,21 @@ namespace { benchmark::DoNotOptimize(tm.findPoint({315555, 495556})); } } + + void + terrain_walk(benchmark::State & state) + { + const glm::vec2 point {310001, 490000}; + const GeoData::PointFace start {point, tm.findPoint(point)}; + for (auto _ : state) { + tm.walk(start, {319999, 500000}, [](auto f) { + benchmark::DoNotOptimize(f); + }); + } + } } BENCHMARK(terrain_findPoint); +BENCHMARK(terrain_walk); BENCHMARK_MAIN(); -- cgit v1.2.3 From 04078dbb3fe4acd09d150e016c2b2e0d5d036950 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 5 Nov 2023 13:07:32 +0000 Subject: Add methods to walk the boundary of the terrain mesh --- game/geoData.cpp | 45 +++++++++++++++++++++++++++++++++++++++++++++ game/geoData.h | 6 ++++++ test/perf-geoData.cpp | 11 +++++++++++ test/test-geoData.cpp | 10 ++++++++++ 4 files changed, 72 insertions(+) diff --git a/game/geoData.cpp b/game/geoData.cpp index c58658a..f9c11bf 100644 --- a/game/geoData.cpp +++ b/game/geoData.cpp @@ -218,6 +218,43 @@ GeoData::walkUntil(const PointFace & from, const glm::vec2 to, const std::functi } } +void +GeoData::boundaryWalk(const std::function & op) const +{ + boundaryWalk(op, findBoundaryStart()); +} + +void +GeoData::boundaryWalk(const std::function & op, HalfedgeHandle start) const +{ + assert(is_boundary(start)); + boundaryWalkUntil( + [&op](auto heh) { + op(heh); + return false; + }, + start); +} + +void +GeoData::boundaryWalkUntil(const std::function & op) const +{ + boundaryWalkUntil(op, findBoundaryStart()); +} + +void +GeoData::boundaryWalkUntil(const std::function & op, HalfedgeHandle start) const +{ + assert(is_boundary(start)); + if (!op(start)) { + for (auto heh = next_halfedge_handle(start); heh != start; heh = next_halfedge_handle(heh)) { + if (op(heh)) { + break; + } + } + } +} + bool GeoData::triangleContainsPoint(const glm::vec2 p, const Triangle<2> & t) { @@ -230,3 +267,11 @@ GeoData::triangleContainsPoint(const glm::vec2 p, FaceHandle face) const { return triangleContainsPoint(p, triangle<2>(face)); } + +GeoData::HalfedgeHandle +GeoData::findBoundaryStart() const +{ + return *std::find_if(halfedges_begin(), halfedges_end(), [this](const auto heh) { + return is_boundary(heh); + }); +} diff --git a/game/geoData.h b/game/geoData.h index b8561d0..15d7e24 100644 --- a/game/geoData.h +++ b/game/geoData.h @@ -78,6 +78,11 @@ public: void walk(const PointFace & from, const glm::vec2 to, const std::function & op) const; void walkUntil(const PointFace & from, const glm::vec2 to, const std::function & op) const; + void boundaryWalk(const std::function &) const; + void boundaryWalk(const std::function &, HalfedgeHandle start) const; + void boundaryWalkUntil(const std::function &) const; + void boundaryWalkUntil(const std::function &, HalfedgeHandle start) const; + [[nodiscard]] auto getExtents() const { @@ -94,6 +99,7 @@ protected: [[nodiscard]] static bool triangleContainsPoint(const glm::vec2, const Triangle<2> &); [[nodiscard]] bool triangleContainsPoint(const glm::vec2, FaceHandle) const; + [[nodiscard]] HalfedgeHandle findBoundaryStart() const; private: glm::vec3 lowerExtent {}, upperExtent {}; diff --git a/test/perf-geoData.cpp b/test/perf-geoData.cpp index 2d79a90..4fed632 100644 --- a/test/perf-geoData.cpp +++ b/test/perf-geoData.cpp @@ -23,9 +23,20 @@ namespace { }); } } + + void + terrain_walkBoundary(benchmark::State & state) + { + for (auto _ : state) { + tm.boundaryWalk([](auto heh) { + benchmark::DoNotOptimize(heh); + }); + } + } } BENCHMARK(terrain_findPoint); BENCHMARK(terrain_walk); +BENCHMARK(terrain_walkBoundary); BENCHMARK_MAIN(); diff --git a/test/test-geoData.cpp b/test/test-geoData.cpp index 258bd9c..34c9cb6 100644 --- a/test/test-geoData.cpp +++ b/test/test-geoData.cpp @@ -118,6 +118,16 @@ BOOST_DATA_TEST_CASE(findRayIntersect, BOOST_CHECK_CLOSE_VEC(fixedTerrtain.intersectRay({p, d}).value(), i); } +BOOST_AUTO_TEST_CASE(boundaryWalk) +{ + size_t count {}; + fixedTerrtain.boundaryWalk([&count](auto heh) { + BOOST_CHECK(fixedTerrtain.is_boundary(heh)); + count++; + }); + BOOST_CHECK_EQUAL(count, 2 * (ncols + nrows - 2)); +} + using WalkTerrainData = std::tuple>; BOOST_DATA_TEST_CASE(walkTerrain, -- cgit v1.2.3 From eb5dea3d035c61327543d7ab527d897ef3768570 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 5 Nov 2023 14:21:14 +0000 Subject: Fix and split linesCross Previous tested they crossed in a specific direction, which is wrong but useful. Adds linesCrossLtR for this use case. --- game/geoData.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/game/geoData.cpp b/game/geoData.cpp index f9c11bf..78f753f 100644 --- a/game/geoData.cpp +++ b/game/geoData.cpp @@ -128,12 +128,23 @@ namespace { [[nodiscard]] constexpr inline bool linesCross(const glm::vec2 a1, const glm::vec2 a2, const glm::vec2 b1, const glm::vec2 b2) + { + return (pointLeftOfLine(a2, b1, b2) == pointLeftOfLine(a1, b2, b1)) + && (pointLeftOfLine(b1, a1, a2) == pointLeftOfLine(b2, a2, a1)); + } + + static_assert(linesCross({1, 1}, {2, 2}, {1, 2}, {2, 1})); + static_assert(linesCross({2, 2}, {1, 1}, {1, 2}, {2, 1})); + + [[nodiscard]] constexpr inline bool + linesCrossLtR(const glm::vec2 a1, const glm::vec2 a2, const glm::vec2 b1, const glm::vec2 b2) { return pointLeftOfLine(a2, b1, b2) && pointLeftOfLine(a1, b2, b1) && pointLeftOfLine(b1, a1, a2) && pointLeftOfLine(b2, a2, a1); } - static_assert(linesCross({1, 1}, {2, 2}, {1, 2}, {2, 1})); + static_assert(linesCrossLtR({1, 1}, {2, 2}, {1, 2}, {2, 1})); + static_assert(!linesCrossLtR({2, 2}, {1, 1}, {1, 2}, {2, 1})); } OpenMesh::FaceHandle @@ -208,7 +219,7 @@ GeoData::walkUntil(const PointFace & from, const glm::vec2 to, const std::functi if (f.is_valid() && f != previousFace) { const auto e1 = point(to_vertex_handle(*next)); const auto e2 = point(to_vertex_handle(opposite_halfedge_handle(*next))); - if (linesCross(from.point, to, e1, e2)) { + if (linesCrossLtR(from.point, to, e1, e2)) { previousFace = f; break; } -- cgit v1.2.3 From acca54f3a12225454633dca2d56506c0dcebb653 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 5 Nov 2023 15:37:13 +0000 Subject: Fix calculating extents --- game/geoData.cpp | 4 ++-- test/test-geoData.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/game/geoData.cpp b/game/geoData.cpp index 78f753f..781b41e 100644 --- a/game/geoData.cpp +++ b/game/geoData.cpp @@ -25,8 +25,8 @@ GeoData::loadFromAsciiGrid(const std::filesystem::path & input) vertices.reserve(ncols * nrows); GeoData mesh; mesh.lowerExtent = {xllcorner, yllcorner, std::numeric_limits::max()}; - mesh.upperExtent - = {xllcorner + (cellsize * ncols), yllcorner + (cellsize * nrows), std::numeric_limits::min()}; + mesh.upperExtent = {xllcorner + (cellsize * (ncols - 1)), yllcorner + (cellsize * (nrows - 1)), + std::numeric_limits::min()}; for (size_t row = 0; row < nrows; ++row) { for (size_t col = 0; col < ncols; ++col) { float height = 0; diff --git a/test/test-geoData.cpp b/test/test-geoData.cpp index 34c9cb6..2ea9b26 100644 --- a/test/test-geoData.cpp +++ b/test/test-geoData.cpp @@ -21,7 +21,7 @@ BOOST_AUTO_TEST_CASE(loadSuccess) BOOST_CHECK_EQUAL(2 * (ncols - 1) * (nrows - 1), n_faces()); const auto [lower, upper] = getExtents(); BOOST_CHECK_EQUAL(lower, glm::vec3(310000, 490000, -2.6)); - BOOST_CHECK_EQUAL(upper, glm::vec3(320000, 500000, 571.6)); + BOOST_CHECK_EQUAL(upper, glm::vec3(319950, 499950, 571.6)); } BOOST_AUTO_TEST_CASE(normalsAllPointUp) -- cgit v1.2.3 From 58402765133fab24d08b64f3752553bd2b8393b9 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 5 Nov 2023 15:52:02 +0000 Subject: Fix todo for handling a terrain walk from outside the mesh --- game/geoData.cpp | 22 ++++++++++++++++++++-- game/geoData.h | 2 ++ test/test-geoData.cpp | 5 +++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/game/geoData.cpp b/game/geoData.cpp index 781b41e..61dedda 100644 --- a/game/geoData.cpp +++ b/game/geoData.cpp @@ -210,8 +210,10 @@ GeoData::walk(const PointFace & from, const glm::vec2 to, const std::function & op) const { - assert(from.face(this).is_valid()); // TODO replace with a boundary search auto f = from.face(this); + if (!f.is_valid()) { + f = opposite_face_handle(findEntry(from.point, to)); + } FaceHandle previousFace; while (f.is_valid() && !op(f)) { for (auto next = cfh_iter(f); next.is_valid(); ++next) { @@ -241,7 +243,7 @@ GeoData::boundaryWalk(const std::function & op, HalfedgeHa assert(is_boundary(start)); boundaryWalkUntil( [&op](auto heh) { - op(heh); + op(heh); return false; }, start); @@ -266,6 +268,22 @@ GeoData::boundaryWalkUntil(const std::function & op, Halfe } } +GeoData::HalfedgeHandle +GeoData::findEntry(const glm::vec2 from, const glm::vec2 to) const +{ + HalfedgeHandle entry; + boundaryWalkUntil([this, from, to, &entry](auto he) { + const auto e1 = point(to_vertex_handle(he)); + const auto e2 = point(to_vertex_handle(opposite_halfedge_handle(he))); + if (linesCrossLtR(from, to, e1, e2)) { + entry = he; + return true; + } + return false; + }); + return entry; +} + bool GeoData::triangleContainsPoint(const glm::vec2 p, const Triangle<2> & t) { diff --git a/game/geoData.h b/game/geoData.h index 15d7e24..474731b 100644 --- a/game/geoData.h +++ b/game/geoData.h @@ -83,6 +83,8 @@ public: void boundaryWalkUntil(const std::function &) const; void boundaryWalkUntil(const std::function &, HalfedgeHandle start) const; + [[nodiscard]] HalfedgeHandle findEntry(const glm::vec2 from, const glm::vec2 to) const; + [[nodiscard]] auto getExtents() const { diff --git a/test/test-geoData.cpp b/test/test-geoData.cpp index 2ea9b26..447ab37 100644 --- a/test/test-geoData.cpp +++ b/test/test-geoData.cpp @@ -139,6 +139,11 @@ BOOST_DATA_TEST_CASE(walkTerrain, {{310002, 490003}, {310202, 490003}, {0, 1, 2, 3, 4, 5, 6, 7, 8}}, {{310202, 490003}, {310002, 490003}, {8, 7, 6, 5, 4, 3, 2, 1, 0}}, {{310002, 490003}, {310002, 490203}, {0, 399, 398, 797, 796, 1195, 1194, 1593, 1592}}, + {{310002, 490003}, {309999, 489999}, {0}}, + {{309999, 489999}, {310002, 490003}, {0}}, + {{320002, 500003}, {319949, 499948}, {79201}}, + {{309999, 490003}, {310004, 489997}, {0, 1}}, + {{310004, 489997}, {309999, 490003}, {1, 0}}, }), from, to, visits) { -- cgit v1.2.3 From d6e99a696aa582b81018078b68f6600c8030d643 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Tue, 7 Nov 2023 02:51:42 +0000 Subject: WIP typedefing all the things - headers --- application/main.cpp | 5 ++-- assetFactory/factoryMesh.h | 3 ++- assetFactory/mutation.h | 7 ++--- assetFactory/shape.h | 3 ++- assetFactory/texturePacker.cpp | 4 +-- assetFactory/texturePacker.h | 7 ++--- config/types.h | 34 +++++++++++++++++++++++ game/geoData.h | 33 ++++++++++++----------- game/network/link.h | 12 ++++----- game/network/network.h | 42 ++++++++++++++--------------- game/network/network.impl.h | 12 ++++----- game/network/rail.h | 10 +++---- game/selectable.h | 3 ++- game/vehicles/railVehicle.h | 2 +- game/vehicles/train.h | 2 +- gfx/gl/bufferedLocation.h | 14 +++++----- gfx/gl/camera.cpp | 4 +-- gfx/gl/camera.h | 25 ++++++++--------- gfx/gl/sceneRenderer.cpp | 2 +- gfx/gl/sceneRenderer.h | 10 +++---- gfx/gl/sceneShader.h | 5 ++-- gfx/gl/shadowMapper.cpp | 2 +- gfx/gl/shadowMapper.h | 9 ++++--- gfx/gl/uiShader.h | 3 ++- gfx/models/texture.cpp | 1 + gfx/models/texture.h | 5 ++-- gfx/models/tga.h | 3 ++- gfx/models/vertex.h | 12 ++++----- lib/geometricPlane.h | 10 ++++--- lib/location.h | 12 +++++---- lib/maths.h | 61 +++++++++++++++++++++--------------------- lib/ray.h | 15 ++++++----- test/test-assetFactory.cpp | 5 ++-- test/testRenderOutput.h | 7 ++--- test/testStructures.h | 5 ++-- ui/builders/freeExtend.h | 2 +- ui/builders/straight.h | 4 +-- ui/gameMainSelector.cpp | 2 +- ui/gameMainSelector.h | 3 ++- ui/manualCameraController.h | 4 +-- ui/window.h | 2 +- 41 files changed, 231 insertions(+), 175 deletions(-) create mode 100644 config/types.h diff --git a/application/main.cpp b/application/main.cpp index 0e880c0..ffdaf63 100644 --- a/application/main.cpp +++ b/application/main.cpp @@ -26,7 +26,6 @@ #include #include #include -#include static const int DISPLAY_WIDTH = 1280; static const int DISPLAY_HEIGHT = 1024; @@ -49,10 +48,10 @@ public: { auto rl = world.create(); - const glm::vec3 j {-1120, -1100, 3}, k {-1100, -1000, 15}, l {-1000, -800, 20}, m {-900, -600, 30}, + const Position3D j {-1120, -1100, 3}, k {-1100, -1000, 15}, l {-1000, -800, 20}, m {-900, -600, 30}, n {-600, -500, 32}, o {-500, -800, 30}, p {-600, -900, 25}, q {-1025, -1175, 10}, r {-925, -1075, 10}; - const glm::vec3 s {-1100, -500, 15}, t {-1100, -450, 15}, u {-1000, -400, 15}; + const Position3D s {-1100, -500, 15}, t {-1100, -450, 15}, u {-1000, -400, 15}; auto l3 = rl->addLinksBetween(j, k); rl->addLinksBetween(k, l); rl->addLinksBetween(l, m); diff --git a/assetFactory/factoryMesh.h b/assetFactory/factoryMesh.h index f71c737..b09b54f 100644 --- a/assetFactory/factoryMesh.h +++ b/assetFactory/factoryMesh.h @@ -1,5 +1,6 @@ #pragma once +#include "config/types.h" #include "gfx/models/mesh.h" #include "stdTypeDefs.h" #include "use.h" @@ -9,7 +10,7 @@ public: Mesh::Ptr createMesh() const; std::string id; - glm::vec3 size; + Size3D size; Use::Collection uses; private: diff --git a/assetFactory/mutation.h b/assetFactory/mutation.h index 2432174..b571dea 100644 --- a/assetFactory/mutation.h +++ b/assetFactory/mutation.h @@ -1,5 +1,6 @@ #pragma once +#include "config/types.h" #include "persistence.h" #include #include @@ -13,9 +14,9 @@ struct Mutation { float relativeLevelOfDetail() const; - glm::vec3 position {}; - glm::vec3 rotation {}; - glm::vec3 scale {1}; + Position3D position {}; + Rotation3D rotation {}; + Scale3D scale {1}; protected: bool persist(Persistence::PersistenceStore & store); diff --git a/assetFactory/shape.h b/assetFactory/shape.h index ea3e4e7..136e24f 100644 --- a/assetFactory/shape.h +++ b/assetFactory/shape.h @@ -1,5 +1,6 @@ #pragma once +#include "config/types.h" #include "modelFactoryMesh_fwd.h" #include "stdTypeDefs.h" #include @@ -21,5 +22,5 @@ public: virtual CreatedFaces createMesh(ModelFactoryMesh &, float levelOfDetailFactor) const = 0; static std::vector addToMesh( - ModelFactoryMesh & mesh, const std::span vertices); + ModelFactoryMesh & mesh, const std::span vertices); }; diff --git a/assetFactory/texturePacker.cpp b/assetFactory/texturePacker.cpp index dbafc4b..0d0fdb6 100644 --- a/assetFactory/texturePacker.cpp +++ b/assetFactory/texturePacker.cpp @@ -14,9 +14,7 @@ TexturePacker::TexturePacker(std::span in) : std::sort(sortedIndexes.rbegin(), sortedIndexes.rend(), [this](const auto a, const auto b) { return area(inputImages[a]) < area(inputImages[b]); }); - int mts; - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mts); - maxTextureSize = static_cast(mts); + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); } TexturePacker::Result diff --git a/assetFactory/texturePacker.h b/assetFactory/texturePacker.h index 93413eb..05e3204 100644 --- a/assetFactory/texturePacker.h +++ b/assetFactory/texturePacker.h @@ -1,13 +1,14 @@ #pragma once +#include "config/types.h" #include #include #include class TexturePacker { public: - using Position = glm::uvec2; - using Size = glm::uvec2; + using Position = TextureAbsCoord; + using Size = TextureAbsCoord; struct Area { #ifndef __cpp_aggregate_paren_init @@ -40,5 +41,5 @@ public: private: std::span inputImages; std::vector sortedIndexes; - unsigned int maxTextureSize; + GLsizei maxTextureSize; }; diff --git a/config/types.h b/config/types.h new file mode 100644 index 0000000..a84be90 --- /dev/null +++ b/config/types.h @@ -0,0 +1,34 @@ +#pragma once + +#include "glad/gl.h" +#include + +using Distance = float; +using Angle = float; + +template using Position = glm::vec; +template using Size = glm::vec; +template using Scale = glm::vec; +template using Direction = glm::vec; +template using Normal = Direction; +template using Rotation = glm::vec; +template using Colour = glm::vec; + +using Position2D = Position<2>; +using Position3D = Position<3>; +using Size2D = Size<2>; +using Size3D = Size<3>; +using Scale2D = Scale<2>; +using Scale3D = Scale<3>; +using Direction2D = Direction<2>; +using Direction3D = Direction<3>; +using Normal2D = Normal<2>; +using Normal3D = Normal<3>; +using Rotation2D = Rotation<2>; +using Rotation3D = Rotation<3>; +using TextureRelCoord = glm::vec<2, float>; +using TextureAbsCoord = glm::vec<2, GLsizei>; +using RGB = Colour<3>; +using RGBA = Colour<4>; +using ScreenRelCoord = glm::vec<2, float>; +using ScreenAbsCoord = glm::vec<2, uint16_t>; diff --git a/game/geoData.h b/game/geoData.h index f9a7d7b..b3ec51d 100644 --- a/game/geoData.h +++ b/game/geoData.h @@ -1,5 +1,6 @@ #pragma once +#include "config/types.h" #include #include #include @@ -16,47 +17,47 @@ public: float height {-1.5F}; }; - using Quad = std::array; + using Quad = std::array; - using Limits = std::pair; + using Limits = std::pair, glm::vec<2, int>>; explicit GeoData(Limits limit, float scale = 10.F); void generateRandom(); void loadFromImages(const std::filesystem::path &, float scale); - [[nodiscard]] glm::vec3 positionAt(glm::vec2) const; - [[nodiscard]] std::optional intersectRay(const Ray &) const; + [[nodiscard]] Position3D positionAt(Position2D) const; + [[nodiscard]] std::optional intersectRay(const Ray &) const; - [[nodiscard]] unsigned int at(glm::ivec2) const; + [[nodiscard]] unsigned int at(glm::vec<2, int>) const; [[nodiscard]] unsigned int at(int x, int y) const; - [[nodiscard]] Quad quad(glm::vec2) const; + [[nodiscard]] Quad quad(Position2D) const; [[nodiscard]] Limits getLimit() const; - [[nodiscard]] glm::uvec2 getSize() const; + [[nodiscard]] glm::vec<2, unsigned int> getSize() const; [[nodiscard]] float getScale() const; [[nodiscard]] std::span getNodes() const; class RayTracer { public: - RayTracer(glm::vec2 p0, glm::vec2 p1); + RayTracer(Position2D p0, Position2D p1); - glm::vec2 next(); + Position2D next(); private: - RayTracer(glm::vec2 p0, glm::vec2 p1, glm::vec2 d); - RayTracer(glm::vec2 p0, glm::vec2 d, std::pair, std::pair); - static std::pair byAxis(glm::vec2 p0, glm::vec2 p1, glm::vec2 d, glm::length_t); + RayTracer(Position2D p0, Position2D p1, Position2D d); + RayTracer(Position2D p0, Position2D d, std::pair, std::pair); + static std::pair byAxis(Position2D p0, Position2D p1, Position2D d, glm::length_t); - glm::vec2 p; - const glm::vec2 d; + Position2D p; + const Position2D d; float error; - glm::vec2 inc; + Position2D inc; }; protected: Limits limit {}; // Base grid limits first(x,y) -> second(x,y) - glm::uvec2 size {}; + glm::vec<2, unsigned> size {}; float scale {1}; std::vector nodes; }; diff --git a/game/network/link.h b/game/network/link.h index 0d66c42..78d3e91 100644 --- a/game/network/link.h +++ b/game/network/link.h @@ -17,12 +17,12 @@ class Ray; // it has location class Node : public StdTypeDefs { public: - explicit Node(glm::vec3 p) noexcept : pos(p) {}; + explicit Node(Position3D p) noexcept : pos(p) {}; virtual ~Node() noexcept = default; NO_COPY(Node); NO_MOVE(Node); - glm::vec3 pos; + Position3D pos; }; // Generic network link @@ -51,14 +51,14 @@ public: float length; protected: - [[nodiscard]] virtual glm::vec3 + [[nodiscard]] virtual Position3D vehiclePositionOffset() const { return {}; } }; -bool operator<(const glm::vec3 & a, const glm::vec3 & b); +bool operator<(const Position3D & a, const Position3D & b); bool operator<(const Node & a, const Node & b); class LinkStraight : public virtual Link { @@ -77,14 +77,14 @@ LinkStraight::~LinkStraight() = default; class LinkCurve : public virtual Link { public: inline ~LinkCurve() override = 0; - LinkCurve(glm::vec3, float, Arc); + LinkCurve(Position3D, float, Arc); NO_COPY(LinkCurve); NO_MOVE(LinkCurve); [[nodiscard]] Location positionAt(float dist, unsigned char start) const override; [[nodiscard]] bool intersectRay(const Ray &) const override; - glm::vec3 centreBase; + Position3D centreBase; float radius; Arc arc; }; diff --git a/game/network/network.h b/game/network/network.h index b9316eb..02f8c30 100644 --- a/game/network/network.h +++ b/game/network/network.h @@ -26,32 +26,32 @@ public: virtual ~Network() = default; DEFAULT_MOVE_NO_COPY(Network); - [[nodiscard]] Node::Ptr findNodeAt(glm::vec3) const; - [[nodiscard]] Node::Ptr nodeAt(glm::vec3); + [[nodiscard]] Node::Ptr findNodeAt(Position3D) const; + [[nodiscard]] Node::Ptr nodeAt(Position3D); enum class NodeIs { InNetwork, NotInNetwork }; using NodeInsertion = std::pair; - [[nodiscard]] NodeInsertion newNodeAt(glm::vec3); - [[nodiscard]] NodeInsertion candidateNodeAt(glm::vec3) const; + [[nodiscard]] NodeInsertion newNodeAt(Position3D); + [[nodiscard]] NodeInsertion candidateNodeAt(Position3D) const; [[nodiscard]] virtual Link::Ptr intersectRayLinks(const Ray &) const = 0; [[nodiscard]] virtual Node::Ptr intersectRayNodes(const Ray &) const; - [[nodiscard]] Link::Nexts routeFromTo(const Link::End &, glm::vec3) const; + [[nodiscard]] Link::Nexts routeFromTo(const Link::End &, Position3D) const; [[nodiscard]] Link::Nexts routeFromTo(const Link::End &, const Node::Ptr &) const; - virtual Link::CCollection candidateStraight(glm::vec3, glm::vec3) = 0; - virtual Link::CCollection candidateJoins(glm::vec3, glm::vec3) = 0; - virtual Link::CCollection candidateExtend(glm::vec3, glm::vec3) = 0; - virtual Link::CCollection addStraight(glm::vec3, glm::vec3) = 0; - virtual Link::CCollection addJoins(glm::vec3, glm::vec3) = 0; - virtual Link::CCollection addExtend(glm::vec3, glm::vec3) = 0; + virtual Link::CCollection candidateStraight(Position3D, Position3D) = 0; + virtual Link::CCollection candidateJoins(Position3D, Position3D) = 0; + virtual Link::CCollection candidateExtend(Position3D, Position3D) = 0; + virtual Link::CCollection addStraight(Position3D, Position3D) = 0; + virtual Link::CCollection addJoins(Position3D, Position3D) = 0; + virtual Link::CCollection addExtend(Position3D, Position3D) = 0; [[nodiscard]] virtual float findNodeDirection(Node::AnyCPtr) const = 0; protected: static void joinLinks(const Link::Ptr & l, const Link::Ptr & ol); - static GenCurveDef genCurveDef(const glm::vec3 & start, const glm::vec3 & end, float startDir); + static GenCurveDef genCurveDef(const Position3D & start, const Position3D & end, float startDir); static std::pair genCurveDef( - const glm::vec3 & start, const glm::vec3 & end, float startDir, float endDir); + const Position3D & start, const Position3D & end, float startDir, float endDir); using Nodes = std::set>; Nodes nodes; @@ -71,7 +71,7 @@ protected: public: template std::shared_ptr - candidateLink(glm::vec3 a, glm::vec3 b, Params &&... params) + candidateLink(Position3D a, Position3D b, Params &&... params) requires std::is_base_of_v { const auto node1 = candidateNodeAt(a).first, node2 = candidateNodeAt(b).first; @@ -80,7 +80,7 @@ public: template std::shared_ptr - addLink(glm::vec3 a, glm::vec3 b, Params &&... params) + addLink(Position3D a, Position3D b, Params &&... params) requires std::is_base_of_v { const auto node1 = nodeAt(a), node2 = nodeAt(b); @@ -89,12 +89,12 @@ public: return l; } - Link::CCollection candidateStraight(glm::vec3 n1, glm::vec3 n2) override; - Link::CCollection candidateJoins(glm::vec3, glm::vec3) override; - Link::CCollection candidateExtend(glm::vec3, glm::vec3) override; - Link::CCollection addStraight(glm::vec3 n1, glm::vec3 n2) override; - Link::CCollection addJoins(glm::vec3, glm::vec3) override; - Link::CCollection addExtend(glm::vec3, glm::vec3) override; + Link::CCollection candidateStraight(Position3D n1, Position3D n2) override; + Link::CCollection candidateJoins(Position3D, Position3D) override; + Link::CCollection candidateExtend(Position3D, Position3D) override; + Link::CCollection addStraight(Position3D n1, Position3D n2) override; + Link::CCollection addJoins(Position3D, Position3D) override; + Link::CCollection addExtend(Position3D, Position3D) override; [[nodiscard]] float findNodeDirection(Node::AnyCPtr) const override; diff --git a/game/network/network.impl.h b/game/network/network.impl.h index 045335f..8e9e85c 100644 --- a/game/network/network.impl.h +++ b/game/network/network.impl.h @@ -54,14 +54,14 @@ NetworkOf::findNodeDirection(Node::AnyCPtr n) const template Link::CCollection -NetworkOf::candidateStraight(glm::vec3 n1, glm::vec3 n2) +NetworkOf::candidateStraight(Position3D n1, Position3D n2) { return {candidateLink(n1, n2)}; } template Link::CCollection -NetworkOf::candidateJoins(glm::vec3 start, glm::vec3 end) +NetworkOf::candidateJoins(Position3D start, Position3D end) { if (glm::distance(start, end) < 2.F) { return {}; @@ -75,7 +75,7 @@ NetworkOf::candidateJoins(glm::vec3 start, glm::vec3 end) template Link::CCollection -NetworkOf::candidateExtend(glm::vec3 start, glm::vec3 end) +NetworkOf::candidateExtend(Position3D start, Position3D end) { const auto [cstart, cend, centre] = genCurveDef(start, end, findNodeDirection(candidateNodeAt(start).first)); return {candidateLink(cstart, cend, centre)}; @@ -83,14 +83,14 @@ NetworkOf::candidateExtend(glm::vec3 start, glm::vec3 end) template Link::CCollection -NetworkOf::addStraight(glm::vec3 n1, glm::vec3 n2) +NetworkOf::addStraight(Position3D n1, Position3D n2) { return {addLink(n1, n2)}; } template Link::CCollection -NetworkOf::addJoins(glm::vec3 start, glm::vec3 end) +NetworkOf::addJoins(Position3D start, Position3D end) { if (glm::distance(start, end) < 2.F) { return {}; @@ -103,7 +103,7 @@ NetworkOf::addJoins(glm::vec3 start, glm::vec3 end) template Link::CCollection -NetworkOf::addExtend(glm::vec3 start, glm::vec3 end) +NetworkOf::addExtend(Position3D start, Position3D end) { const auto [cstart, cend, centre] = genCurveDef(start, end, findNodeDirection(nodeAt(start))); return {addLink(cstart, cend, centre)}; diff --git a/game/network/rail.h b/game/network/rail.h index 6684801..4a1932f 100644 --- a/game/network/rail.h +++ b/game/network/rail.h @@ -32,7 +32,7 @@ public: NO_MOVE(RailLink); protected: - [[nodiscard]] glm::vec3 vehiclePositionOffset() const override; + [[nodiscard]] Position3D vehiclePositionOffset() const override; [[nodiscard]] static Mesh::Ptr defaultMesh(const std::span vertices); Mesh::Ptr mesh; @@ -45,22 +45,22 @@ public: RailLinkStraight(const Node::Ptr &, const Node::Ptr &); private: - RailLinkStraight(Node::Ptr, Node::Ptr, const glm::vec3 & diff); + RailLinkStraight(Node::Ptr, Node::Ptr, const Position3D & diff); }; class RailLinkCurve : public RailLink, public LinkCurve { public: - RailLinkCurve(const Node::Ptr &, const Node::Ptr &, glm::vec2); + RailLinkCurve(const Node::Ptr &, const Node::Ptr &, Position2D); private: - RailLinkCurve(const Node::Ptr &, const Node::Ptr &, glm::vec3, const Arc); + RailLinkCurve(const Node::Ptr &, const Node::Ptr &, Position3D, const Arc); }; class RailLinks : public NetworkOf, public WorldObject { public: RailLinks(); - std::shared_ptr addLinksBetween(glm::vec3 start, glm::vec3 end); + std::shared_ptr addLinksBetween(Position3D start, Position3D end); private: void tick(TickDuration elapsed) override; diff --git a/game/selectable.h b/game/selectable.h index 31287d8..9732dca 100644 --- a/game/selectable.h +++ b/game/selectable.h @@ -1,5 +1,6 @@ #pragma once +#include "config/types.h" #include #include @@ -11,5 +12,5 @@ public: virtual ~Selectable() = default; DEFAULT_MOVE_COPY(Selectable); - [[nodiscard]] virtual bool intersectRay(const Ray &, glm::vec2 *, float *) const = 0; + [[nodiscard]] virtual bool intersectRay(const Ray &, Position2D *, float *) const = 0; }; diff --git a/game/vehicles/railVehicle.h b/game/vehicles/railVehicle.h index be88142..e034852 100644 --- a/game/vehicles/railVehicle.h +++ b/game/vehicles/railVehicle.h @@ -17,7 +17,7 @@ public: void move(const Train *, float & trailBy); - [[nodiscard]] bool intersectRay(const Ray &, glm::vec2 *, float *) const override; + [[nodiscard]] bool intersectRay(const Ray &, Position2D *, float *) const override; RailVehicleClassPtr rvClass; using LV = RailVehicleClass::LocationVertex; diff --git a/game/vehicles/train.h b/game/vehicles/train.h index 20c3bc4..7f0bb99 100644 --- a/game/vehicles/train.h +++ b/game/vehicles/train.h @@ -27,7 +27,7 @@ public: return objects.front()->location; } - [[nodiscard]] bool intersectRay(const Ray &, glm::vec2 *, float *) const override; + [[nodiscard]] bool intersectRay(const Ray &, Position2D *, float *) const override; void tick(TickDuration elapsed) override; void doActivity(Go *, TickDuration) override; diff --git a/gfx/gl/bufferedLocation.h b/gfx/gl/bufferedLocation.h index 8096489..39d3139 100644 --- a/gfx/gl/bufferedLocation.h +++ b/gfx/gl/bufferedLocation.h @@ -8,7 +8,7 @@ class BufferedLocation { public: - BufferedLocation(glm::vec3 = {}, glm::vec3 = {}); + BufferedLocation(Position3D = {}, Rotation3D = {}); BufferedLocation(const Location &); virtual ~BufferedLocation() = default; @@ -16,13 +16,13 @@ public: operator const Location &() const; - glm::vec3 position() const; - glm::vec3 rotation() const; - void setPosition(glm::vec3, bool update = true); - void setRotation(glm::vec3, bool update = true); - void setLocation(glm::vec3, glm::vec3); + [[nodiscard]] Position3D position() const; + [[nodiscard]] Rotation3D rotation() const; + void setPosition(Position3D, bool update = true); + void setRotation(Rotation3D, bool update = true); + void setLocation(Position3D, Rotation3D); - glm::mat4 getTransform() const; + [[nodiscard]] glm::mat4 getTransform() const; private: virtual void updateBuffer() = 0; diff --git a/gfx/gl/camera.cpp b/gfx/gl/camera.cpp index c4c9544..80feab4 100644 --- a/gfx/gl/camera.cpp +++ b/gfx/gl/camera.cpp @@ -5,7 +5,7 @@ #include #include -Camera::Camera(glm::vec3 pos, float fov, float aspect, float zNear, float zFar) : +Camera::Camera(Position3D pos, Angle fov, Angle aspect, Distance zNear, Distance zFar) : position {pos}, forward {::north}, up {::up}, near {zNear}, far {zFar}, projection {glm::perspective(fov, aspect, zNear, zFar)}, viewProjection {projection * glm::lookAt(position, position + forward, up)}, @@ -14,7 +14,7 @@ Camera::Camera(glm::vec3 pos, float fov, float aspect, float zNear, float zFar) } Ray -Camera::unProject(const glm::vec2 & mouse) const +Camera::unProject(const ScreenRelCoord & mouse) const { static constexpr const glm::vec4 screen {0, 0, 1, 1}; const auto mouseProjection = glm::lookAt(::origin, forward, up); diff --git a/gfx/gl/camera.h b/gfx/gl/camera.h index 7956ec3..469df0d 100644 --- a/gfx/gl/camera.h +++ b/gfx/gl/camera.h @@ -1,12 +1,13 @@ #pragma once +#include "config/types.h" #include #include #include class Camera { public: - Camera(glm::vec3 pos, float fov, float aspect, float zNear, float zFar); + Camera(Position3D, Angle fov, Angle aspect, Distance zNear, Distance zFar); [[nodiscard]] glm::mat4 getViewProjection() const @@ -14,23 +15,23 @@ public: return viewProjection; } - [[nodiscard]] Ray unProject(const glm::vec2 &) const; + [[nodiscard]] Ray unProject(const ScreenRelCoord &) const; void - setPosition(const glm::vec3 & p) + setPosition(const Position3D & p) { position = p; updateView(); } void - setForward(const glm::vec3 & f) + setForward(const Direction3D & f) { setForward(f, upFromForward(f)); } void - setForward(const glm::vec3 & f, const glm::vec3 & u) + setForward(const Direction3D & f, const Direction3D & u) { forward = f; up = u; @@ -38,21 +39,21 @@ public: } void - setView(const glm::vec3 & p, const glm::vec3 & f) + setView(const Position3D & p, const Direction3D & f) { position = p; setForward(f); } void - setView(const glm::vec3 & p, const glm::vec3 & f, const glm::vec3 & u) + setView(const Position3D & p, const Direction3D & f, const Direction3D & u) { position = p; setView(f, u); } void - lookAt(const glm::vec3 & target) + lookAt(const Position3D & target) { setForward(glm::normalize(target - position)); } @@ -71,14 +72,14 @@ public: [[nodiscard]] std::array extentsAtDist(float) const; - [[nodiscard]] static glm::vec3 upFromForward(const glm::vec3 & forward); + [[nodiscard]] static Direction3D upFromForward(const Direction3D & forward); private: void updateView(); - glm::vec3 position; - glm::vec3 forward; - glm::vec3 up; + Position3D position; + Direction3D forward; + Direction3D up; float near, far; glm::mat4 projection; diff --git a/gfx/gl/sceneRenderer.cpp b/gfx/gl/sceneRenderer.cpp index 5799daf..218cf6d 100644 --- a/gfx/gl/sceneRenderer.cpp +++ b/gfx/gl/sceneRenderer.cpp @@ -14,7 +14,7 @@ static constexpr const std::array displayVAOdata {{ {1, -1, 1, 0}, }}; -SceneRenderer::SceneRenderer(glm::ivec2 s, GLuint o) : +SceneRenderer::SceneRenderer(ScreenAbsCoord s, GLuint o) : camera {{-1250.0F, -1250.0F, 35.0F}, quarter_pi, ratio(s), 0.1F, 10000.0F}, size {s}, output {o}, lighting {lighting_vs, lighting_fs}, shadowMapper {{2048, 2048}} { diff --git a/gfx/gl/sceneRenderer.h b/gfx/gl/sceneRenderer.h index 55df84d..87f474b 100644 --- a/gfx/gl/sceneRenderer.h +++ b/gfx/gl/sceneRenderer.h @@ -11,18 +11,18 @@ class SceneRenderer { public: - explicit SceneRenderer(glm::ivec2 size, GLuint output); + explicit SceneRenderer(ScreenAbsCoord size, GLuint output); void render(const SceneProvider &) const; - void setAmbientLight(const glm::vec3 & colour) const; - void setDirectionalLight(const glm::vec3 & colour, const glm::vec3 & direction, const SceneProvider &) const; + void setAmbientLight(const RGB & colour) const; + void setDirectionalLight(const RGB & colour, const Direction3D & direction, const SceneProvider &) const; Camera camera; private: void renderQuad() const; - glm::ivec2 size; + ScreenAbsCoord size; GLuint output; glFrameBuffer gBuffer; glTexture gPosition, gNormal, gAlbedoSpec, gIllumination; @@ -39,7 +39,7 @@ private: DirectionalLightProgram(); using Program::use; - void setDirectionalLight(const glm::vec3 &, const glm::vec3 &, const std::span, + void setDirectionalLight(const RGB &, const Direction3D &, const std::span, const std::span, std::size_t maps) const; private: diff --git a/gfx/gl/sceneShader.h b/gfx/gl/sceneShader.h index ead184e..d1c6ef2 100644 --- a/gfx/gl/sceneShader.h +++ b/gfx/gl/sceneShader.h @@ -1,5 +1,6 @@ #pragma once +#include "config/types.h" #include "program.h" #include @@ -52,7 +53,7 @@ class SceneShader { public: PointLightShader(); - void add(const glm::vec3 & position, const glm::vec3 & colour, const float kq) const; + void add(const Position3D & position, const RGB & colour, const float kq) const; private: UniformLocation colourLoc; @@ -65,7 +66,7 @@ class SceneShader { public: SpotLightShader(); - void add(const glm::vec3 & position, const glm::vec3 & direction, const glm::vec3 & colour, const float kq, + void add(const Position3D & position, const Direction3D & direction, const RGB & colour, const float kq, const float arc) const; private: diff --git a/gfx/gl/shadowMapper.cpp b/gfx/gl/shadowMapper.cpp index 79b39c0..58f65c4 100644 --- a/gfx/gl/shadowMapper.cpp +++ b/gfx/gl/shadowMapper.cpp @@ -15,7 +15,7 @@ #include #include -ShadowMapper::ShadowMapper(const glm::ivec2 & s) : +ShadowMapper::ShadowMapper(const TextureAbsCoord & s) : fixedPoint {shadowFixedPoint_vs}, dynamicPointInst {shadowDynamicPointInst_vs}, size {s} { glBindTexture(GL_TEXTURE_2D, depthMap); diff --git a/gfx/gl/shadowMapper.h b/gfx/gl/shadowMapper.h index cd1b975..e5272a3 100644 --- a/gfx/gl/shadowMapper.h +++ b/gfx/gl/shadowMapper.h @@ -1,5 +1,6 @@ #pragma once +#include "config/types.h" #include "lib/glArrays.h" #include "program.h" #include @@ -11,7 +12,7 @@ class Camera; class ShadowMapper { public: - explicit ShadowMapper(const glm::ivec2 & size); + explicit ShadowMapper(const TextureAbsCoord & size); static constexpr std::size_t SHADOW_BANDS {4}; @@ -21,7 +22,7 @@ public: size_t maps {}; }; - [[nodiscard]] Definitions update(const SceneProvider &, const glm::vec3 & direction, const Camera &) const; + [[nodiscard]] Definitions update(const SceneProvider &, const Direction3D & direction, const Camera &) const; class FixedPoint : public Program { public: @@ -55,9 +56,9 @@ public: } private: - [[nodiscard]] static std::vector> getBandViewExtents( + [[nodiscard]] static std::vector> getBandViewExtents( const Camera &, const glm::mat4 & lightView); glFrameBuffer depthMapFBO; glTexture depthMap; - glm::ivec2 size; + TextureAbsCoord size; }; diff --git a/gfx/gl/uiShader.h b/gfx/gl/uiShader.h index 2766af8..362e90c 100644 --- a/gfx/gl/uiShader.h +++ b/gfx/gl/uiShader.h @@ -1,5 +1,6 @@ #pragma once +#include "config/types.h" #include "program.h" #include #include @@ -33,7 +34,7 @@ private: class TextProgram : public UIProgram { public: explicit TextProgram(const glm::mat4 & vp); - void use(const glm::vec3 & colour) const; + void use(const RGB & colour) const; private: RequiredUniformLocation colorLoc; diff --git a/gfx/models/texture.cpp b/gfx/models/texture.cpp index b7f1bee..f60d158 100644 --- a/gfx/models/texture.cpp +++ b/gfx/models/texture.cpp @@ -1,4 +1,5 @@ #include "texture.h" +#include "config/types.h" #include "glArrays.h" #include "tga.h" #include diff --git a/gfx/models/texture.h b/gfx/models/texture.h index 1b66c64..5e1b440 100644 --- a/gfx/models/texture.h +++ b/gfx/models/texture.h @@ -1,5 +1,6 @@ #pragma once +#include "config/types.h" #include #include #include @@ -42,7 +43,7 @@ public: protected: static void save(const glTexture &, GLenum, GLenum, uint8_t channels, const char * path, uint8_t tgaFormat); - static glm::ivec2 getSize(const glTexture &); + static TextureAbsCoord getSize(const glTexture &); glTexture m_texture; GLenum type; @@ -53,7 +54,7 @@ public: TextureAtlas(GLsizei width, GLsizei height, GLuint count); void bind(GLenum unit = GL_TEXTURE0) const override; - GLuint add(glm::ivec2 position, glm::ivec2 size, void * data, TextureOptions = {}); + GLuint add(TextureAbsCoord position, TextureAbsCoord size, void * data, TextureOptions = {}); private: glTexture m_atlas; diff --git a/gfx/models/tga.h b/gfx/models/tga.h index 52db220..3d072fb 100644 --- a/gfx/models/tga.h +++ b/gfx/models/tga.h @@ -4,10 +4,11 @@ #include struct TGAHead { + using XY = glm::vec<2, uint16_t>; uint8_t idLength {}, colorMapType {}, format {}; uint16_t __attribute__((packed)) colorMapFirst {}, colorMapLength {}; uint8_t colorMapEntrySize {}; - glm::vec<2, uint16_t> origin {}, size {}; + XY origin {}, size {}; uint8_t pixelDepth {}; uint8_t descriptor {}; }; diff --git a/gfx/models/vertex.h b/gfx/models/vertex.h index 0464ea7..5635fa1 100644 --- a/gfx/models/vertex.h +++ b/gfx/models/vertex.h @@ -1,12 +1,12 @@ #pragma once +#include "config/types.h" #include -#include class Vertex { public: #ifndef __cpp_aggregate_paren_init - constexpr Vertex(glm::vec3 pos, glm::vec2 texCoord, glm::vec3 normal, glm::vec4 colour = {}, GLuint material = 0) : + constexpr Vertex(Position3D pos, TextureRelCoord texCoord, Normal3D normal, RGBA colour = {}, GLuint material = 0) : pos {std::move(pos)}, texCoord {std::move(texCoord)}, normal {std::move(normal)}, colour {std::move(colour)}, material {material} { @@ -15,9 +15,9 @@ public: bool operator==(const Vertex &) const = default; - glm::vec3 pos; - glm::vec2 texCoord; - glm::vec3 normal; - glm::vec4 colour {}; + Position3D pos {}; + TextureRelCoord texCoord {}; + Normal3D normal {}; + RGBA colour {}; GLuint material {}; }; diff --git a/lib/geometricPlane.h b/lib/geometricPlane.h index dc8df50..c74beff 100644 --- a/lib/geometricPlane.h +++ b/lib/geometricPlane.h @@ -1,5 +1,6 @@ #pragma once +#include "config/types.h" #include #include @@ -9,14 +10,15 @@ class GeometricPlane { public: struct DistAndPosition { float dist; - glm::vec3 position; + Position3D position; }; enum class PlaneRelation { Above, Below, On }; - glm::vec3 origin, normal; + Position3D origin; + Normal3D normal; - PlaneRelation getRelation(glm::vec3 point) const; - std::optional getRayIntersectPosition(const Ray &) const; + [[nodiscard]] PlaneRelation getRelation(Position3D point) const; + [[nodiscard]] std::optional getRayIntersectPosition(const Ray &) const; static bool isIntersect(PlaneRelation a, PlaneRelation b); }; diff --git a/lib/location.h b/lib/location.h index 078f5d3..7f2b44d 100644 --- a/lib/location.h +++ b/lib/location.h @@ -1,14 +1,16 @@ #pragma once +#include "config/types.h" #include -#include class Location { public: - explicit Location(glm::vec3 pos = {}, glm::vec3 rot = {}) : pos {pos}, rot {rot} { } +#ifndef __cpp_aggregate_paren_init + explicit Location(Position3D pos = {}, Rotation3D rot = {}) : pos {pos}, rot {rot} { } +#endif - glm::mat4 getTransform() const; + [[nodiscard]] glm::mat4 getTransform() const; - glm::vec3 pos; - glm::vec3 rot; + Position3D pos; + Rotation3D rot; }; diff --git a/lib/maths.h b/lib/maths.h index b95b706..67b2a15 100644 --- a/lib/maths.h +++ b/lib/maths.h @@ -1,5 +1,6 @@ #pragma once +#include "config/types.h" #include #include #include @@ -9,7 +10,7 @@ struct Arc : public std::pair { using std::pair::pair; - Arc(const glm::vec3 & centre3, const glm::vec3 & e0p, const glm::vec3 & e1p); + Arc(const Position3D & centre3, const Position3D & e0p, const Position3D & e1p); float operator[](unsigned int i) const @@ -18,19 +19,19 @@ struct Arc : public std::pair { } }; -constexpr const glm::vec3 origin {0, 0, 0}; -constexpr const glm::vec3 up {0, 0, 1}; -constexpr const glm::vec3 down {0, 0, -1}; -constexpr const glm::vec3 north {0, 1, 0}; -constexpr const glm::vec3 south {0, -1, 0}; -constexpr const glm::vec3 east {1, 0, 0}; -constexpr const glm::vec3 west {-1, 0, 0}; +constexpr const Position3D origin {0, 0, 0}; +constexpr const Position3D up {0, 0, 1}; +constexpr const Position3D down {0, 0, -1}; +constexpr const Position3D north {0, 1, 0}; +constexpr const Position3D south {0, -1, 0}; +constexpr const Position3D east {1, 0, 0}; +constexpr const Position3D west {-1, 0, 0}; constexpr auto half_pi {glm::half_pi()}; constexpr auto quarter_pi {half_pi / 2}; constexpr auto pi {glm::pi()}; constexpr auto two_pi {glm::two_pi()}; -glm::mat4 flat_orientation(const glm::vec3 & diff); +glm::mat4 flat_orientation(const Rotation3D & diff); // C++ wrapper for C's sincosf, but with references, not pointers inline auto @@ -39,10 +40,10 @@ sincosf(float a, float & s, float & c) return sincosf(a, &s, &c); } -inline glm::vec2 +inline Rotation2D sincosf(float a) { - glm::vec2 sc; + Rotation2D sc; sincosf(a, sc.x, sc.y); return sc; } @@ -51,11 +52,11 @@ glm::mat2 rotate_flat(float); glm::mat4 rotate_roll(float); glm::mat4 rotate_yaw(float); glm::mat4 rotate_pitch(float); -glm::mat4 rotate_yp(glm::vec2); -glm::mat4 rotate_ypr(glm::vec3); +glm::mat4 rotate_yp(Rotation2D); +glm::mat4 rotate_ypr(Rotation3D); -float vector_yaw(const glm::vec3 & diff); -float vector_pitch(const glm::vec3 & diff); +float vector_yaw(const Direction3D & diff); +float vector_pitch(const Direction3D & diff); float round_frac(const float & v, const float & frac); @@ -87,26 +88,26 @@ perspective_divide(glm::vec<4, T, Q> v) return v / v.w; } -constexpr inline glm::vec2 -operator!(const glm::vec3 & v) +constexpr inline Position2D +operator!(const Position3D & v) { return {v.x, v.y}; } -constexpr inline glm::vec3 -operator^(const glm::vec2 & v, float z) +constexpr inline Position3D +operator^(const Position2D & v, float z) { return {v.x, v.y, z}; } constexpr inline glm::vec4 -operator^(const glm::vec3 & v, float w) +operator^(const Position3D & v, float w) { return {v.x, v.y, v.z, w}; } -constexpr inline glm::vec3 -operator!(const glm::vec2 & v) +constexpr inline Position3D +operator!(const Position2D & v) { return v ^ 0.F; } @@ -125,15 +126,15 @@ operator||(const glm::vec v1, const T v2) return {v1, v2}; } -inline glm::vec3 -operator%(const glm::vec3 & p, const glm::mat4 & mutation) +inline Position3D +operator%(const Position3D & p, const glm::mat4 & mutation) { const auto p2 = mutation * (p ^ 1); return p2 / p2.w; } -inline glm::vec3 -operator%=(glm::vec3 & p, const glm::mat4 & mutation) +inline Position3D +operator%=(Position3D & p, const glm::mat4 & mutation) { return p = p % mutation; } @@ -146,10 +147,10 @@ arc_length(const Arc & arc) float normalize(float ang); -std::pair find_arc_centre(glm::vec2 start, float entrys, glm::vec2 end, float entrye); -std::pair find_arc_centre(glm::vec2 start, glm::vec2 ad, glm::vec2 end, glm::vec2 bd); -std::pair find_arcs_radius(glm::vec2 start, float entrys, glm::vec2 end, float entrye); -float find_arcs_radius(glm::vec2 start, glm::vec2 ad, glm::vec2 end, glm::vec2 bd); +std::pair find_arc_centre(Position2D start, float entrys, Position2D end, float entrye); +std::pair find_arc_centre(Position2D start, Position2D ad, Position2D end, Position2D bd); +std::pair find_arcs_radius(Position2D start, float entrys, Position2D end, float entrye); +float find_arcs_radius(Position2D start, Position2D ad, Position2D end, Position2D bd); template auto diff --git a/lib/ray.h b/lib/ray.h index 9bf47af..bc70c74 100644 --- a/lib/ray.h +++ b/lib/ray.h @@ -1,17 +1,20 @@ #pragma once +#include "config/types.h" #include #include class Ray { public: - Ray(glm::vec3 start, glm::vec3 direction) : start {start}, direction {direction} { } +#ifndef __cpp_aggregate_paren_init + Ray(Position3D start, Direction3D direction) : start {start}, direction {direction} { } +#endif - static Ray fromPoints(glm::vec3, glm::vec3); + static Ray fromPoints(Position3D, Position3D); - glm::vec3 start; - glm::vec3 direction; + Position3D start; + Direction3D direction; - float distanceToLine(const glm::vec3 & a, const glm::vec3 & b) const; - bool passesCloseToEdges(const std::span positions, float distance) const; + [[nodiscard]] float distanceToLine(const Position3D & a, const Position3D & b) const; + [[nodiscard]] bool passesCloseToEdges(const std::span positions, float distance) const; }; diff --git a/test/test-assetFactory.cpp b/test/test-assetFactory.cpp index 145481e..177ab6a 100644 --- a/test/test-assetFactory.cpp +++ b/test/test-assetFactory.cpp @@ -183,14 +183,15 @@ BOOST_AUTO_TEST_CASE(texturePacker_many, *boost::unit_test::timeout(5)) { std::vector images(256); std::fill(images.begin(), images.end(), TexturePacker::Image {32, 32}); - const auto totalSize = std::accumulate(images.begin(), images.end(), 0U, [](auto t, const auto & i) { + const auto totalSize = std::accumulate(images.begin(), images.end(), 0, [](auto t, const auto & i) { return t + TexturePacker::area(i); }); TexturePacker tp {images}; BOOST_CHECK_EQUAL(TexturePacker::Size(32, 32), tp.minSize()); const auto result = tp.pack(); BOOST_CHECK_EQUAL(result.first.size(), images.size()); - BOOST_CHECK_GE(TexturePacker::area(result.second), TexturePacker::area(images.front()) * images.size()); + BOOST_CHECK_GE(TexturePacker::area(result.second), + TexturePacker::area(images.front()) * static_cast(images.size())); BOOST_CHECK_EQUAL(totalSize, TexturePacker::area(result.second)); } diff --git a/test/testRenderOutput.h b/test/testRenderOutput.h index 13c380f..056d029 100644 --- a/test/testRenderOutput.h +++ b/test/testRenderOutput.h @@ -1,24 +1,25 @@ #pragma once +#include "config/types.h" #include "glArrays.h" #include #include class TestRenderOutput { public: - TestRenderOutput(glm::ivec2 size = {640, 480}); + explicit TestRenderOutput(TextureAbsCoord size = {640, 480}); virtual ~TestRenderOutput() = default; NO_MOVE(TestRenderOutput); NO_COPY(TestRenderOutput); - const glm::ivec2 size; + const TextureAbsCoord size; glFrameBuffer output; glRenderBuffer depth; glTexture outImage; }; -template class TestRenderOutputSize : public TestRenderOutput { +template class TestRenderOutputSize : public TestRenderOutput { public: TestRenderOutputSize() : TestRenderOutput {Size} { } }; diff --git a/test/testStructures.h b/test/testStructures.h index 6966052..aaaf940 100644 --- a/test/testStructures.h +++ b/test/testStructures.h @@ -1,5 +1,6 @@ #pragma once +#include "config/types.h" #include struct AbsObject : public Persistence::Persistable { @@ -31,9 +32,9 @@ struct TestObject : public Persistence::Persistable { float flt {}; std::string str {}; bool bl {}; - glm::vec3 pos {}; + Position3D pos {}; std::vector flts; - std::vector poss; + std::vector poss; std::vector>> nest; std::unique_ptr ptr; std::unique_ptr aptr; diff --git a/ui/builders/freeExtend.h b/ui/builders/freeExtend.h index 55fe7ff..b276426 100644 --- a/ui/builders/freeExtend.h +++ b/ui/builders/freeExtend.h @@ -9,5 +9,5 @@ class BuilderFreeExtend : public EditNetwork::Builder { void click(Network * network, const GeoData * geoData, const SDL_MouseButtonEvent & e, const Ray & ray) override; void move(Network * network, const GeoData * geoData, const SDL_MouseMotionEvent & e, const Ray & ray) override; - std::optional p1; + std::optional p1; }; diff --git a/ui/builders/straight.h b/ui/builders/straight.h index 1cde2b0..cf99a1d 100644 --- a/ui/builders/straight.h +++ b/ui/builders/straight.h @@ -9,7 +9,7 @@ class BuilderStraight : public EditNetwork::Builder { void click(Network * network, const GeoData * geoData, const SDL_MouseButtonEvent & e, const Ray & ray) override; void move(Network * network, const GeoData * geoData, const SDL_MouseMotionEvent & e, const Ray & ray) override; - void create(Network * network, glm::vec3 p1, glm::vec3 p2) const; + void create(Network * network, Position3D p1, Position3D p2) const; - std::optional p1; + std::optional p1; }; diff --git a/ui/gameMainSelector.cpp b/ui/gameMainSelector.cpp index 6c6935c..808e0e4 100644 --- a/ui/gameMainSelector.cpp +++ b/ui/gameMainSelector.cpp @@ -14,7 +14,7 @@ #include #include -GameMainSelector::GameMainSelector(const Camera * c, glm::vec2 size) : UIComponent {{{}, size}}, camera {c} { } +GameMainSelector::GameMainSelector(const Camera * c, ScreenAbsCoord size) : UIComponent {{{}, size}}, camera {c} { } constexpr glm::vec2 TargetPos {5, 45}; diff --git a/ui/gameMainSelector.h b/ui/gameMainSelector.h index 98cdf53..88db34b 100644 --- a/ui/gameMainSelector.h +++ b/ui/gameMainSelector.h @@ -1,6 +1,7 @@ #pragma once #include "SDL_events.h" +#include "config/types.h" #include "special_members.h" #include "uiComponent.h" #include "worldOverlay.h" @@ -26,7 +27,7 @@ public: virtual void render(const SceneShader &) const; }; - GameMainSelector(const Camera * c, glm::vec2 size); + GameMainSelector(const Camera * c, ScreenAbsCoord size); void render(const UIShader & shader, const Position & pos) const override; void render(const SceneShader & shader) const override; diff --git a/ui/manualCameraController.h b/ui/manualCameraController.h index d15fa76..46655bc 100644 --- a/ui/manualCameraController.h +++ b/ui/manualCameraController.h @@ -11,7 +11,7 @@ class Camera; class ManualCameraController : public CameraController, public UIComponent { public: - explicit ManualCameraController(glm::vec2 f) : UIComponent {{}}, focus {f} { } + explicit ManualCameraController(Position2D f) : UIComponent {{}}, focus {f} { } bool handleInput(const SDL_Event & e, const Position &) override; void render(const UIShader &, const Position & parentPos) const override; @@ -20,7 +20,7 @@ public: private: bool ctrl {false}, mrb {false}; - glm::vec2 focus; + Position2D focus; float direction {quarter_pi}; float dist {40}, pitch {quarter_pi}; }; diff --git a/ui/window.h b/ui/window.h index 183a65a..8f2b70b 100644 --- a/ui/window.h +++ b/ui/window.h @@ -36,7 +36,7 @@ protected: GLInitHelper(); }; - const glm::ivec2 size; + const ScreenAbsCoord size; SDL_WindowPtr m_window; SDL_GLContextPtr glContext; GLInitHelper glInithelper; -- cgit v1.2.3 From 9c2c3f71065c94a18c02440111b6ff8ca977b90e Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 9 Nov 2023 00:40:40 +0000 Subject: WIP typedefing all the things - sources --- assetFactory/cuboid.cpp | 2 +- assetFactory/cylinder.cpp | 6 +++--- assetFactory/plane.cpp | 2 +- assetFactory/shape.cpp | 4 +--- game/network/link.cpp | 14 +++++++------- game/network/network.cpp | 18 +++++++++--------- game/network/rail.cpp | 30 +++++++++++++++--------------- game/vehicles/railVehicle.cpp | 12 ++++++------ game/vehicles/train.cpp | 2 +- gfx/gl/bufferedLocation.cpp | 12 ++++++------ gfx/gl/camera.cpp | 11 ++++++----- gfx/gl/sceneRenderer.cpp | 7 +++---- gfx/gl/sceneShader.cpp | 14 +++++++------- gfx/gl/shadowMapper.cpp | 10 +++++----- gfx/gl/uiShader.cpp | 2 +- gfx/models/texture.cpp | 6 +++--- lib/geometricPlane.cpp | 4 ++-- lib/maths.cpp | 40 ++++++++++++++++++++-------------------- lib/ray.cpp | 8 ++++---- test/test-assetFactory.cpp | 2 +- test/testRenderOutput.cpp | 2 +- ui/builders/straight.cpp | 2 +- ui/gameMainSelector.cpp | 9 +++++---- ui/gameMainWindow.cpp | 4 ++-- ui/manualCameraController.cpp | 2 +- 25 files changed, 112 insertions(+), 113 deletions(-) diff --git a/assetFactory/cuboid.cpp b/assetFactory/cuboid.cpp index a8ddcd9..cfb6cfb 100644 --- a/assetFactory/cuboid.cpp +++ b/assetFactory/cuboid.cpp @@ -4,7 +4,7 @@ Cuboid::CreatedFaces Cuboid::createMesh(ModelFactoryMesh & mesh, float) const { - static constexpr std::array VERTICES {{ + static constexpr std::array VERTICES {{ // bottom {n, n, z}, {n, y, z}, diff --git a/assetFactory/cylinder.cpp b/assetFactory/cylinder.cpp index 7d22e36..ed034fd 100644 --- a/assetFactory/cylinder.cpp +++ b/assetFactory/cylinder.cpp @@ -9,8 +9,8 @@ Cylinder::createMesh(ModelFactoryMesh & mesh, float lodf) const const auto step = two_pi / static_cast(P); // Generate 2D circumference points - std::vector circumference(P); - std::generate(circumference.begin(), circumference.end(), [a = 0.f, step]() mutable { + std::vector circumference(P); + std::generate(circumference.begin(), circumference.end(), [a = 0.F, step]() mutable { return sincosf(a += step) * .5F; }); @@ -19,7 +19,7 @@ Cylinder::createMesh(ModelFactoryMesh & mesh, float lodf) const // Generate bottom face vertices std::vector bottom(P); std::transform(circumference.begin(), circumference.end(), bottom.begin(), [&mesh](const auto & xy) { - return mesh.add_vertex(xy ^ 0.f); + return mesh.add_vertex(xy ^ 0.F); }); surface.insert(mesh.add_namedFace("bottom", bottom)); } diff --git a/assetFactory/plane.cpp b/assetFactory/plane.cpp index c6e1b5a..28fb690 100644 --- a/assetFactory/plane.cpp +++ b/assetFactory/plane.cpp @@ -4,7 +4,7 @@ Plane::CreatedFaces Plane::createMesh(ModelFactoryMesh & mesh, float) const { - static constexpr std::array VERTICES {{ + static constexpr std::array VERTICES {{ {n, n, z}, {y, n, z}, {y, y, z}, diff --git a/assetFactory/shape.cpp b/assetFactory/shape.cpp index 1bfbdbb..0f83ee5 100644 --- a/assetFactory/shape.cpp +++ b/assetFactory/shape.cpp @@ -1,11 +1,9 @@ #include "shape.h" -#include "gfx/models/vertex.h" -#include "maths.h" #include "modelFactoryMesh.h" #include "shape.h" std::vector -Shape::addToMesh(ModelFactoryMesh & mesh, const std::span vertices) +Shape::addToMesh(ModelFactoryMesh & mesh, const std::span vertices) { std::vector vhs; std::transform(vertices.begin(), vertices.end(), std::back_inserter(vhs), [&mesh](const auto & p) { diff --git a/game/network/link.cpp b/game/network/link.cpp index bb27a52..498afe4 100644 --- a/game/network/link.cpp +++ b/game/network/link.cpp @@ -8,10 +8,10 @@ Link::Link(End a, End b, float l) : ends {{std::move(a), std::move(b)}}, length {l} { } -LinkCurve::LinkCurve(glm::vec3 c, float r, Arc a) : centreBase {c}, radius {r}, arc {std::move(a)} { } +LinkCurve::LinkCurve(Position3D c, float r, Arc a) : centreBase {c}, radius {r}, arc {std::move(a)} { } bool -operator<(const glm::vec3 & a, const glm::vec3 & b) +operator<(const Position3D & a, const Position3D & b) { // NOLINTNEXTLINE(hicpp-use-nullptr,modernize-use-nullptr) return std::tie(a.x, a.y, a.z) < std::tie(b.x, b.y, b.z); @@ -48,7 +48,7 @@ LinkCurve::positionAt(float dist, unsigned char start) const const auto ang {as.first + ((as.second - as.first) * frac)}; const auto relPos {!sincosf(ang) * radius}; const auto relClimb {vehiclePositionOffset() - + glm::vec3 {0, 0, es.first->pos.z - centreBase.z + ((es.second->pos.z - es.first->pos.z) * frac)}}; + + Position3D {0, 0, es.first->pos.z - centreBase.z + ((es.second->pos.z - es.first->pos.z) * frac)}}; const auto pitch {vector_pitch({0, 0, (es.second->pos.z - es.first->pos.z) / length})}; return Location {relPos + relClimb + centreBase, {pitch, normalize(ang + dirOffset[start]), 0}}; } @@ -60,14 +60,14 @@ LinkCurve::intersectRay(const Ray & ray) const const auto & e1p {ends[1].node->pos}; const auto slength = round_frac(length / 2.F, 5.F); const auto segs = std::round(15.F * slength / std::pow(radius, 0.7F)); - const auto step {glm::vec3 {arc_length(arc), e1p.z - e0p.z, slength} / segs}; + const auto step {Position3D {arc_length(arc), e1p.z - e0p.z, slength} / segs}; const auto trans {glm::translate(centreBase)}; auto segCount = static_cast(std::lround(segs)) + 1; - std::vector points; + std::vector points; points.reserve(segCount); - for (glm::vec3 swing = {arc.first, centreBase.z - e0p.z, 0.F}; segCount; swing += step, --segCount) { - const auto t {trans * glm::rotate(half_pi - swing.x, up) * glm::translate(glm::vec3 {radius, 0.F, swing.y})}; + for (Position3D swing = {arc.first, centreBase.z - e0p.z, 0.F}; segCount; swing += step, --segCount) { + const auto t {trans * glm::rotate(half_pi - swing.x, up) * glm::translate(Position3D {radius, 0.F, swing.y})}; points.emplace_back(t * glm::vec4 {0, 0, 0, 1}); } return ray.passesCloseToEdges(points, 1.F); diff --git a/game/network/network.cpp b/game/network/network.cpp index 083b08e..d18345c 100644 --- a/game/network/network.cpp +++ b/game/network/network.cpp @@ -14,13 +14,13 @@ Network::Network(const std::string & tn) : texture {Texture::cachedTexture.get(tn)} { } Node::Ptr -Network::nodeAt(glm::vec3 pos) +Network::nodeAt(Position3D pos) { return newNodeAt(pos).first; } Network::NodeInsertion -Network::newNodeAt(glm::vec3 pos) +Network::newNodeAt(Position3D pos) { if (auto [n, i] = candidateNodeAt(pos); i == NodeIs::NotInNetwork) { return {*nodes.insert(std::move(n)).first, i}; @@ -31,7 +31,7 @@ Network::newNodeAt(glm::vec3 pos) } Node::Ptr -Network::findNodeAt(glm::vec3 pos) const +Network::findNodeAt(Position3D pos) const { if (const auto n = nodes.find(pos); n != nodes.end()) { return *n; @@ -40,7 +40,7 @@ Network::findNodeAt(glm::vec3 pos) const } Network::NodeInsertion -Network::candidateNodeAt(glm::vec3 pos) const +Network::candidateNodeAt(Position3D pos) const { if (const auto n = nodes.find(pos); n != nodes.end()) { return {*n, NodeIs::InNetwork}; @@ -54,7 +54,7 @@ Network::intersectRayNodes(const Ray & ray) const // Click within 2m of a node if (const auto node = std::find_if(nodes.begin(), nodes.end(), [&ray](const Node::Ptr & node) { - glm::vec3 ipos, inorm; + Position3D ipos, inorm; return glm::intersectRaySphere(ray.start, ray.direction, node->pos, 2.F, ipos, inorm); }); node != nodes.end()) { @@ -79,7 +79,7 @@ Network::joinLinks(const Link::Ptr & l, const Link::Ptr & ol) } Link::Nexts -Network::routeFromTo(const Link::End & start, glm::vec3 dest) const +Network::routeFromTo(const Link::End & start, Position3D dest) const { auto destNode {findNodeAt(dest)}; if (!destNode) { @@ -95,7 +95,7 @@ Network::routeFromTo(const Link::End & end, const Node::Ptr & dest) const } GenCurveDef -Network::genCurveDef(const glm::vec3 & start, const glm::vec3 & end, float startDir) +Network::genCurveDef(const Position3D & start, const Position3D & end, float startDir) { const auto diff {end - start}; const auto vy {vector_yaw(diff)}; @@ -111,11 +111,11 @@ Network::genCurveDef(const glm::vec3 & start, const glm::vec3 & end, float start } std::pair -Network::genCurveDef(const glm::vec3 & start, const glm::vec3 & end, float startDir, float endDir) +Network::genCurveDef(const Position3D & start, const Position3D & end, float startDir, float endDir) { startDir += pi; endDir += pi; - const glm::vec2 flatStart {!start}, flatEnd {!end}; + const Position2D flatStart {!start}, flatEnd {!end}; auto midheight = [&](auto mid) { const auto sm = glm::distance(flatStart, mid), em = glm::distance(flatEnd, mid); return start.z + ((end.z - start.z) * (sm / (sm + em))); diff --git a/game/network/rail.cpp b/game/network/rail.cpp index 5a4f1e1..f46504b 100644 --- a/game/network/rail.cpp +++ b/game/network/rail.cpp @@ -18,7 +18,7 @@ template class NetworkOf; constexpr auto RAIL_CROSSSECTION_VERTICES {5U}; -constexpr glm::vec3 RAIL_HEIGHT {0, 0, .25F}; +constexpr Size3D RAIL_HEIGHT {0, 0, .25F}; RailLinks::RailLinks() : NetworkOf {"rails.jpg"} { } @@ -28,7 +28,7 @@ RailLinks::tick(TickDuration) } std::shared_ptr -RailLinks::addLinksBetween(glm::vec3 start, glm::vec3 end) +RailLinks::addLinksBetween(Position3D start, Position3D end) { auto node1ins = newNodeAt(start), node2ins = newNodeAt(end); if (node1ins.second == NodeIs::NotInNetwork && node2ins.second == NodeIs::NotInNetwork) { @@ -45,7 +45,7 @@ RailLinks::addLinksBetween(glm::vec3 start, glm::vec3 end) if (dir == vector_yaw(end - start)) { return addLink(start, end); } - const glm::vec2 flatStart {!start}, flatEnd {!end}; + const Position2D flatStart {!start}, flatEnd {!end}; if (node2ins.second == NodeIs::InNetwork) { auto midheight = [&](auto mid) { const auto sm = glm::distance(flatStart, mid), em = glm::distance(flatEnd, mid); @@ -100,7 +100,7 @@ RailLink::render(const SceneShader &) const mesh->Draw(); } -constexpr const std::array, RAIL_CROSSSECTION_VERTICES> railCrossSection {{ +constexpr const std::array, RAIL_CROSSSECTION_VERTICES> railCrossSection {{ // ___________ // _/ \_ // left to right @@ -122,7 +122,7 @@ RailLinkStraight::RailLinkStraight(const Node::Ptr & a, const Node::Ptr & b) : R { } -RailLinkStraight::RailLinkStraight(Node::Ptr a, Node::Ptr b, const glm::vec3 & diff) : +RailLinkStraight::RailLinkStraight(Node::Ptr a, Node::Ptr b, const Position3D & diff) : Link({std::move(a), vector_yaw(diff)}, {std::move(b), vector_yaw(-diff)}, glm::length(diff)) { if (glGenVertexArrays) { @@ -133,20 +133,20 @@ RailLinkStraight::RailLinkStraight(Node::Ptr a, Node::Ptr b, const glm::vec3 & d for (auto ei : {1U, 0U}) { const auto trans {glm::translate(ends[ei].node->pos) * e}; for (const auto & rcs : railCrossSection) { - const glm::vec3 m {(trans * glm::vec4 {rcs.first, 1})}; - vertices.emplace_back(m, glm::vec2 {rcs.second, len * static_cast(ei)}, up); + const Position3D m {(trans * glm::vec4 {rcs.first, 1})}; + vertices.emplace_back(m, Position2D {rcs.second, len * static_cast(ei)}, up); } } mesh = defaultMesh(vertices); } } -RailLinkCurve::RailLinkCurve(const Node::Ptr & a, const Node::Ptr & b, glm::vec2 c) : +RailLinkCurve::RailLinkCurve(const Node::Ptr & a, const Node::Ptr & b, Position2D c) : RailLinkCurve(a, b, c ^ a->pos.z, {!c, a->pos, b->pos}) { } -RailLinkCurve::RailLinkCurve(const Node::Ptr & a, const Node::Ptr & b, glm::vec3 c, const Arc arc) : +RailLinkCurve::RailLinkCurve(const Node::Ptr & a, const Node::Ptr & b, Position3D c, const Arc arc) : Link({a, normalize(arc.first + half_pi)}, {b, normalize(arc.second - half_pi)}, (glm::length(a->pos - c)) * arc_length(arc)), LinkCurve {c, glm::length(ends[0].node->pos - c), arc} @@ -156,25 +156,25 @@ RailLinkCurve::RailLinkCurve(const Node::Ptr & a, const Node::Ptr & b, glm::vec3 const auto & e1p {ends[1].node->pos}; const auto slength = round_sleepers(length / 2.F); const auto segs = std::round(15.F * slength / std::pow(radius, 0.7F)); - const auto step {glm::vec3 {arc_length(arc), e1p.z - e0p.z, slength} / segs}; + const auto step {Position3D {arc_length(arc), e1p.z - e0p.z, slength} / segs}; const auto trans {glm::translate(centreBase)}; auto segCount = static_cast(std::lround(segs)) + 1; std::vector vertices; vertices.reserve(segCount * railCrossSection.size()); - for (glm::vec3 swing = {arc.first, centreBase.z - e0p.z, 0.F}; segCount; swing += step, --segCount) { + for (Position3D swing = {arc.first, centreBase.z - e0p.z, 0.F}; segCount; swing += step, --segCount) { const auto t { - trans * glm::rotate(half_pi - swing.x, up) * glm::translate(glm::vec3 {radius, 0.F, swing.y})}; + trans * glm::rotate(half_pi - swing.x, up) * glm::translate(Position3D {radius, 0.F, swing.y})}; for (const auto & rcs : railCrossSection) { - const glm::vec3 m {(t * glm::vec4 {rcs.first, 1})}; - vertices.emplace_back(m, glm::vec2 {rcs.second, swing.z}, up); + const Position3D m {(t * glm::vec4 {rcs.first, 1})}; + vertices.emplace_back(m, Position2D {rcs.second, swing.z}, up); } } mesh = defaultMesh(vertices); } } -glm::vec3 +Position3D RailLink::vehiclePositionOffset() const { return RAIL_HEIGHT; diff --git a/game/vehicles/railVehicle.cpp b/game/vehicles/railVehicle.cpp index 2d820b6..fc43995 100644 --- a/game/vehicles/railVehicle.cpp +++ b/game/vehicles/railVehicle.cpp @@ -14,8 +14,8 @@ RailVehicle::RailVehicle(RailVehicleClassPtr rvc) : RailVehicleClass::Instance {rvc->instances.acquire()}, rvClass {std::move(rvc)}, location {&LV::body, *this}, bogies {{ - {&LV::front, *this, glm::vec3 {0, rvClass->wheelBase / 2.F, 0}}, - {&LV::back, *this, glm::vec3 {0, -rvClass->wheelBase / 2.F, 0}}, + {&LV::front, *this, Position3D {0, rvClass->wheelBase / 2.F, 0}}, + {&LV::back, *this, Position3D {0, -rvClass->wheelBase / 2.F, 0}}, }} { } @@ -32,13 +32,13 @@ RailVehicle::move(const Train * t, float & trailBy) } bool -RailVehicle::intersectRay(const Ray & ray, glm::vec2 * baryPos, float * distance) const +RailVehicle::intersectRay(const Ray & ray, Position2D * baryPos, float * distance) const { constexpr const auto X = 1.35F; const auto Y = this->rvClass->length / 2.F; constexpr const auto Z = 3.9F; const auto moveBy = location.getTransform(); - const std::array cornerVertices {{ + const std::array cornerVertices {{ moveBy * glm::vec4 {-X, Y, 0, 1}, // LFB moveBy * glm::vec4 {X, Y, 0, 1}, // RFB moveBy * glm::vec4 {-X, Y, Z, 1}, // LFT @@ -48,7 +48,7 @@ RailVehicle::intersectRay(const Ray & ray, glm::vec2 * baryPos, float * distance moveBy * glm::vec4 {-X, -Y, Z, 1}, // LBT moveBy * glm::vec4 {X, -Y, Z, 1}, // RBT }}; - static constexpr const std::array triangles {{ + static constexpr const std::array, 10> triangles {{ // Front {0, 1, 2}, {1, 2, 3}, @@ -66,7 +66,7 @@ RailVehicle::intersectRay(const Ray & ray, glm::vec2 * baryPos, float * distance {3, 6, 7}, }}; return std::any_of( - triangles.begin(), triangles.end(), [&cornerVertices, &ray, &baryPos, &distance](const glm::uvec3 idx) { + triangles.begin(), triangles.end(), [&cornerVertices, &ray, &baryPos, &distance](const auto & idx) { return glm::intersectRayTriangle(ray.start, ray.direction, cornerVertices[idx[0]], cornerVertices[idx[1]], cornerVertices[idx[2]], *baryPos, *distance); }); diff --git a/game/vehicles/train.cpp b/game/vehicles/train.cpp index 6f3b036..4aa24dc 100644 --- a/game/vehicles/train.cpp +++ b/game/vehicles/train.cpp @@ -20,7 +20,7 @@ Train::getBogiePosition(float linkDist, float dist) const } bool -Train::intersectRay(const Ray & ray, glm::vec2 * baryPos, float * distance) const +Train::intersectRay(const Ray & ray, Position2D * baryPos, float * distance) const { return applyOne(&RailVehicle::intersectRay, ray, baryPos, distance) != end(); } diff --git a/gfx/gl/bufferedLocation.cpp b/gfx/gl/bufferedLocation.cpp index eb3dac3..62cadef 100644 --- a/gfx/gl/bufferedLocation.cpp +++ b/gfx/gl/bufferedLocation.cpp @@ -3,7 +3,7 @@ #include "maths.h" #include -BufferedLocation::BufferedLocation(glm::vec3 p, glm::vec3 r) : BufferedLocation {Location {p, r}} { } +BufferedLocation::BufferedLocation(Position3D p, Rotation3D r) : BufferedLocation {Location {p, r}} { } BufferedLocation::BufferedLocation(const Location & l) : loc {l} { } @@ -20,20 +20,20 @@ BufferedLocation::operator=(const Location & l) return *this; } -glm::vec3 +Position3D BufferedLocation::position() const { return loc.pos; } -glm::vec3 +Position3D BufferedLocation::rotation() const { return loc.rot; } void -BufferedLocation::setPosition(glm::vec3 p, bool update) +BufferedLocation::setPosition(Position3D p, bool update) { loc.pos = p; if (update) { @@ -42,7 +42,7 @@ BufferedLocation::setPosition(glm::vec3 p, bool update) } void -BufferedLocation::setRotation(glm::vec3 r, bool update) +BufferedLocation::setRotation(Position3D r, bool update) { loc.rot = r; if (update) { @@ -51,7 +51,7 @@ BufferedLocation::setRotation(glm::vec3 r, bool update) } void -BufferedLocation::setLocation(glm::vec3 p, glm::vec3 r) +BufferedLocation::setLocation(Position3D p, Rotation3D r) { loc.pos = p; loc.rot = r; diff --git a/gfx/gl/camera.cpp b/gfx/gl/camera.cpp index 80feab4..6a0359c 100644 --- a/gfx/gl/camera.cpp +++ b/gfx/gl/camera.cpp @@ -2,6 +2,7 @@ #include #include // IWYU pragma: keep #include // IWYU pragma: keep +#include #include #include @@ -28,8 +29,8 @@ Camera::updateView() inverseViewProjection = glm::inverse(viewProjection); } -glm::vec3 -Camera::upFromForward(const glm::vec3 & forward) +Direction3D +Camera::upFromForward(const Direction3D & forward) { const auto right = glm::cross(forward, ::down); return glm::cross(forward, right); @@ -38,11 +39,11 @@ Camera::upFromForward(const glm::vec3 & forward) std::array Camera::extentsAtDist(const float dist) const { - const auto clampToSeaFloor = [this, dist](const glm::vec3 & target) { + const auto clampToSeaFloor = [this, dist](const Position3D & target) { if (target.z < -1.5F) { const auto vec = glm::normalize(target - position); - constexpr glm::vec3 seafloor {0, 0, -1.5F}; - float outdist; + constexpr Position3D seafloor {0, 0, -1.5F}; + float outdist {}; if (glm::intersectRayPlane(position, vec, seafloor, ::up, outdist)) { return (vec * outdist + position) ^ outdist; } diff --git a/gfx/gl/sceneRenderer.cpp b/gfx/gl/sceneRenderer.cpp index 218cf6d..6965175 100644 --- a/gfx/gl/sceneRenderer.cpp +++ b/gfx/gl/sceneRenderer.cpp @@ -97,7 +97,7 @@ SceneRenderer::render(const SceneProvider & scene) const } void -SceneRenderer::setAmbientLight(const glm::vec3 & colour) const +SceneRenderer::setAmbientLight(const RGB & colour) const { glBindFramebuffer(GL_FRAMEBUFFER, gBuffer); glClearColor(colour.r, colour.g, colour.b, 1.0F); @@ -105,8 +105,7 @@ SceneRenderer::setAmbientLight(const glm::vec3 & colour) const } void -SceneRenderer::setDirectionalLight( - const glm::vec3 & colour, const glm::vec3 & direction, const SceneProvider & scene) const +SceneRenderer::setDirectionalLight(const RGB & colour, const Direction3D & direction, const SceneProvider & scene) const { if (colour.r > 0 || colour.g > 0 || colour.b > 0) { const auto lvp = shadowMapper.update(scene, direction, camera); @@ -135,7 +134,7 @@ SceneRenderer::DirectionalLightProgram::DirectionalLightProgram() : } void -SceneRenderer::DirectionalLightProgram::setDirectionalLight(const glm::vec3 & c, const glm::vec3 & d, +SceneRenderer::DirectionalLightProgram::setDirectionalLight(const RGB & c, const Direction3D & d, const std::span lvp, const std::span shadowMapRegions, std::size_t maps) const { diff --git a/gfx/gl/sceneShader.cpp b/gfx/gl/sceneShader.cpp index 1354611..04b6d9e 100644 --- a/gfx/gl/sceneShader.cpp +++ b/gfx/gl/sceneShader.cpp @@ -81,25 +81,25 @@ void SceneShader::WaterProgram::use(float waveCycle) const { Program::use(); - glm::vec3 waves {waveCycle, 0.F, 0.F}; + Position3D waves {waveCycle, 0.F, 0.F}; glUniform3fv(waveLoc, 1, glm::value_ptr(waves)); } SceneShader::PointLightShader::PointLightShader() : SceneProgram {pointLight_vs, pointLight_gs, pointLight_fs}, colourLoc {*this, "colour"}, kqLoc {*this, "kq"} { - VertexArrayObject {va}.addAttribs(b); + VertexArrayObject {va}.addAttribs(b); } void -SceneShader::PointLightShader::add(const glm::vec3 & position, const glm::vec3 & colour, const float kq) const +SceneShader::PointLightShader::add(const Position3D & position, const RGB & colour, const float kq) const { Program::use(); glBindVertexArray(va); glBindBuffer(GL_ARRAY_BUFFER, b); glUniform3fv(colourLoc, 1, glm::value_ptr(colour)); glUniform1f(kqLoc, kq); - glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3), glm::value_ptr(position), GL_DYNAMIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, sizeof(Position3D), glm::value_ptr(position), GL_DYNAMIC_DRAW); glDrawArrays(GL_POINTS, 0, 1); } @@ -107,12 +107,12 @@ SceneShader::SpotLightShader::SpotLightShader() : SceneProgram {spotLight_vs, spotLight_gs, spotLight_fs}, directionLoc {*this, "v_direction"}, colourLoc {*this, "colour"}, kqLoc {*this, "kq"}, arcLoc {*this, "arc"} { - using v3pair = std::pair; + using v3pair = std::pair; VertexArrayObject {va}.addAttribs(b); } void -SceneShader::SpotLightShader::add(const glm::vec3 & position, const glm::vec3 & direction, const glm::vec3 & colour, +SceneShader::SpotLightShader::add(const Position3D & position, const Direction3D & direction, const RGB & colour, const float kq, const float arc) const { Program::use(); @@ -122,6 +122,6 @@ SceneShader::SpotLightShader::add(const glm::vec3 & position, const glm::vec3 & glUniform3fv(directionLoc, 1, glm::value_ptr(direction)); glUniform1f(kqLoc, kq); glUniform1f(arcLoc, arc); - glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3), glm::value_ptr(position), GL_DYNAMIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, sizeof(Position3D), glm::value_ptr(position), GL_DYNAMIC_DRAW); glDrawArrays(GL_POINTS, 0, 1); } diff --git a/gfx/gl/shadowMapper.cpp b/gfx/gl/shadowMapper.cpp index 58f65c4..aea5af3 100644 --- a/gfx/gl/shadowMapper.cpp +++ b/gfx/gl/shadowMapper.cpp @@ -104,14 +104,14 @@ struct DefinitionsInserter { ShadowMapper::Definitions & out; }; -std::vector> +std::vector> ShadowMapper::getBandViewExtents(const Camera & camera, const glm::mat4 & lightView) { - std::vector> bandViewExtents; + std::vector> bandViewExtents; for (const auto dist : shadowBands) { const auto extents = camera.extentsAtDist(dist); - bandViewExtents.emplace_back(extents * [&lightView](const auto & e) -> glm::vec3 { - return lightView * glm::vec4(glm::vec3 {e}, 1); + bandViewExtents.emplace_back(extents * [&lightView](const auto & e) -> Position3D { + return lightView * glm::vec4(Position3D {e}, 1); }); if (std::none_of(extents.begin(), extents.end(), [targetDist = dist * 0.99F](const glm::vec4 & e) { return e.w > targetDist; @@ -123,7 +123,7 @@ ShadowMapper::getBandViewExtents(const Camera & camera, const glm::mat4 & lightV } ShadowMapper::Definitions -ShadowMapper::update(const SceneProvider & scene, const glm::vec3 & dir, const Camera & camera) const +ShadowMapper::update(const SceneProvider & scene, const Direction3D & dir, const Camera & camera) const { glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO); glClear(GL_DEPTH_BUFFER_BIT); diff --git a/gfx/gl/uiShader.cpp b/gfx/gl/uiShader.cpp index 0b47211..dc4f4dc 100644 --- a/gfx/gl/uiShader.cpp +++ b/gfx/gl/uiShader.cpp @@ -23,7 +23,7 @@ UIShader::UIShader(size_t width, size_t height) : UIShader::UIShader(const glm::mat4 & viewProjection) : icon {viewProjection}, text {viewProjection} { } void -UIShader::TextProgram::use(const glm::vec3 & colour) const +UIShader::TextProgram::use(const RGB & colour) const { Program::use(); glUniform3fv(colorLoc, 1, glm::value_ptr(colour)); diff --git a/gfx/models/texture.cpp b/gfx/models/texture.cpp index f60d158..1685d34 100644 --- a/gfx/models/texture.cpp +++ b/gfx/models/texture.cpp @@ -61,10 +61,10 @@ Texture::bind(GLenum unit) const glBindTexture(type, m_texture); } -glm::ivec2 +TextureAbsCoord Texture::getSize(const glTexture & texture) { - glm::ivec2 size; + TextureAbsCoord size; glGetTextureLevelParameteriv(texture, 0, GL_TEXTURE_WIDTH, &size.x); glGetTextureLevelParameteriv(texture, 0, GL_TEXTURE_HEIGHT, &size.y); return size; @@ -137,7 +137,7 @@ TextureAtlas::bind(GLenum unit) const } GLuint -TextureAtlas::add(glm::ivec2 position, glm::ivec2 size, void * data, TextureOptions to) +TextureAtlas::add(TextureAbsCoord position, TextureAbsCoord size, void * data, TextureOptions to) { glTextureSubImage2D(m_texture, 0, position.x, position.y, size.x, size.y, GL_RGBA, GL_UNSIGNED_BYTE, data); diff --git a/lib/geometricPlane.cpp b/lib/geometricPlane.cpp index ea4f02d..567f98a 100644 --- a/lib/geometricPlane.cpp +++ b/lib/geometricPlane.cpp @@ -4,10 +4,10 @@ #include GeometricPlane::PlaneRelation -GeometricPlane::getRelation(glm::vec3 p) const +GeometricPlane::getRelation(Position3D p) const { const auto d = glm::dot(normal, p - origin); - return d < 0.f ? PlaneRelation::Below : d > 0.f ? PlaneRelation::Above : PlaneRelation::On; + return d < 0.F ? PlaneRelation::Below : d > 0.F ? PlaneRelation::Above : PlaneRelation::On; } bool diff --git a/lib/maths.cpp b/lib/maths.cpp index 7594b59..5430ef6 100644 --- a/lib/maths.cpp +++ b/lib/maths.cpp @@ -6,7 +6,7 @@ #include glm::mat4 -flat_orientation(const glm::vec3 & diff) +flat_orientation(const Direction3D & diff) { static const auto oneeighty {glm::rotate(pi, up)}; const auto flatdiff {glm::normalize(!!diff)}; @@ -16,17 +16,17 @@ flat_orientation(const glm::vec3 & diff) } // Helper to lookup into a matrix given an xy vector coordinate -template +template inline auto & -operator^(M & m, glm::ivec2 xy) +operator^(M & m, glm::vec<2, I> xy) { return m[xy.x][xy.y]; } // Create a matrix for the angle, given the targets into the matrix -template +template inline auto -rotation(typename M::value_type a, glm::ivec2 c1, glm::ivec2 s1, glm::ivec2 c2, glm::ivec2 ms2) +rotation(typename M::value_type a, glm::vec<2, I> c1, glm::vec<2, I> s1, glm::vec<2, I> c2, glm::vec<2, I> ms2) { M m(1); sincosf(a, m ^ s1, m ^ c1); @@ -39,51 +39,51 @@ rotation(typename M::value_type a, glm::ivec2 c1, glm::ivec2 s1, glm::ivec2 c2, glm::mat2 rotate_flat(float a) { - return rotation(a, {0, 0}, {0, 1}, {1, 1}, {1, 0}); + return rotation(a, {0, 0}, {0, 1}, {1, 1}, {1, 0}); } // Create a yaw transformation matrix glm::mat4 rotate_yaw(float a) { - return rotation(a, {0, 0}, {1, 0}, {1, 1}, {0, 1}); + return rotation(a, {0, 0}, {1, 0}, {1, 1}, {0, 1}); } // Create a roll transformation matrix glm::mat4 rotate_roll(float a) { - return rotation(a, {0, 0}, {2, 0}, {2, 2}, {0, 2}); + return rotation(a, {0, 0}, {2, 0}, {2, 2}, {0, 2}); } // Create a pitch transformation matrix glm::mat4 rotate_pitch(float a) { - return rotation(a, {1, 1}, {1, 2}, {2, 2}, {2, 1}); + return rotation(a, {1, 1}, {1, 2}, {2, 2}, {2, 1}); } // Create a combined yaw, pitch, roll transformation matrix glm::mat4 -rotate_ypr(glm::vec3 a) +rotate_ypr(Rotation3D a) { return rotate_yaw(a.y) * rotate_pitch(a.x) * rotate_roll(a.z); } glm::mat4 -rotate_yp(glm::vec2 a) +rotate_yp(Rotation2D a) { return rotate_yaw(a.y) * rotate_pitch(a.x); } float -vector_yaw(const glm::vec3 & diff) +vector_yaw(const Direction3D & diff) { return std::atan2(diff.x, diff.y); } float -vector_pitch(const glm::vec3 & diff) +vector_pitch(const Direction3D & diff) { return std::atan(diff.z); } @@ -106,7 +106,7 @@ normalize(float ang) return ang; } -Arc::Arc(const glm::vec3 & centre3, const glm::vec3 & e0p, const glm::vec3 & e1p) : +Arc::Arc(const Position3D & centre3, const Position3D & e0p, const Position3D & e1p) : Arc([&]() -> Arc { const auto diffa = e0p - centre3; const auto diffb = e1p - centre3; @@ -120,8 +120,8 @@ Arc::Arc(const glm::vec3 & centre3, const glm::vec3 & e0p, const glm::vec3 & e1p { } -std::pair -find_arc_centre(glm::vec2 as, float entrys, glm::vec2 bs, float entrye) +std::pair +find_arc_centre(Position2D as, float entrys, Position2D bs, float entrye) { if (as == bs) { return {as, false}; @@ -129,8 +129,8 @@ find_arc_centre(glm::vec2 as, float entrys, glm::vec2 bs, float entrye) return find_arc_centre(as, sincosf(entrys + half_pi), bs, sincosf(entrye - half_pi)); } -std::pair -find_arc_centre(glm::vec2 as, glm::vec2 ad, glm::vec2 bs, glm::vec2 bd) +std::pair +find_arc_centre(Position2D as, Position2D ad, Position2D bs, Position2D bd) { const auto det = bd.x * ad.y - bd.y * ad.x; if (det != 0) { // near parallel line will yield noisy results @@ -142,7 +142,7 @@ find_arc_centre(glm::vec2 as, glm::vec2 ad, glm::vec2 bs, glm::vec2 bd) } std::pair -find_arcs_radius(glm::vec2 start, float entrys, glm::vec2 end, float entrye) +find_arcs_radius(Position2D start, float entrys, Position2D end, float entrye) { const auto getrad = [&](float leftOrRight) { return find_arcs_radius(start, sincosf(entrys + leftOrRight), end, sincosf(entrye + leftOrRight)); @@ -151,7 +151,7 @@ find_arcs_radius(glm::vec2 start, float entrys, glm::vec2 end, float entrye) } float -find_arcs_radius(glm::vec2 start, glm::vec2 ad, glm::vec2 end, glm::vec2 bd) +find_arcs_radius(Position2D start, Position2D ad, Position2D end, Position2D bd) { // Short name functions for big forula auto sqrt = [](float v) { diff --git a/lib/ray.cpp b/lib/ray.cpp index c4e0d8c..9fb3648 100644 --- a/lib/ray.cpp +++ b/lib/ray.cpp @@ -2,13 +2,13 @@ #include Ray -Ray::fromPoints(glm::vec3 start, glm::vec3 p) +Ray::fromPoints(Position3D start, Position3D p) { return {start, glm::normalize(p - start)}; } float -Ray::distanceToLine(const glm::vec3 & p1, const glm::vec3 & e1) const +Ray::distanceToLine(const Position3D & p1, const Position3D & e1) const { // https://en.wikipedia.org/wiki/Skew_lines const auto diff = p1 - e1; @@ -25,10 +25,10 @@ Ray::distanceToLine(const glm::vec3 & p1, const glm::vec3 & e1) const } bool -Ray::passesCloseToEdges(const std::span positions, float distance) const +Ray::passesCloseToEdges(const std::span positions, float distance) const { return std::adjacent_find(positions.begin(), positions.end(), - [this, distance](const glm::vec3 & a, const glm::vec3 & b) { + [this, distance](const Position3D & a, const Position3D & b) { return distanceToLine(a, b) <= distance; }) != positions.end(); diff --git a/test/test-assetFactory.cpp b/test/test-assetFactory.cpp index 177ab6a..9af08cb 100644 --- a/test/test-assetFactory.cpp +++ b/test/test-assetFactory.cpp @@ -25,7 +25,7 @@ BOOST_GLOBAL_FIXTURE(TestMainWindow); const std::filesystem::path TMP {"/tmp"}; -class FactoryFixture : public TestRenderOutputSize, public SceneProvider { +class FactoryFixture : public TestRenderOutputSize, public SceneProvider { public: FactoryFixture() : sceneRenderer {size, output} { } diff --git a/test/testRenderOutput.cpp b/test/testRenderOutput.cpp index 464b0b3..9af4451 100644 --- a/test/testRenderOutput.cpp +++ b/test/testRenderOutput.cpp @@ -1,7 +1,7 @@ #include "testRenderOutput.h" #include -TestRenderOutput::TestRenderOutput(glm::ivec2 s) : size {s} +TestRenderOutput::TestRenderOutput(TextureAbsCoord s) : size {s} { glBindFramebuffer(GL_FRAMEBUFFER, output); const auto configuregdata diff --git a/ui/builders/straight.cpp b/ui/builders/straight.cpp index 4fa9585..9b262bb 100644 --- a/ui/builders/straight.cpp +++ b/ui/builders/straight.cpp @@ -47,7 +47,7 @@ BuilderStraight::click(Network * network, const GeoData * geoData, const SDL_Mou } void -BuilderStraight::create(Network * network, glm::vec3 p1, glm::vec3 p2) const +BuilderStraight::create(Network * network, Position3D p1, Position3D p2) const { network->addStraight(p1, p2); } diff --git a/ui/gameMainSelector.cpp b/ui/gameMainSelector.cpp index 808e0e4..a451ee1 100644 --- a/ui/gameMainSelector.cpp +++ b/ui/gameMainSelector.cpp @@ -8,6 +8,7 @@ #include #include // IWYU pragma: keep #include +#include #include #include #include @@ -16,7 +17,7 @@ GameMainSelector::GameMainSelector(const Camera * c, ScreenAbsCoord size) : UIComponent {{{}, size}}, camera {c} { } -constexpr glm::vec2 TargetPos {5, 45}; +constexpr ScreenAbsCoord TargetPos {5, 45}; void GameMainSelector::render(const UIShader & shader, const Position & parentPos) const @@ -41,7 +42,7 @@ bool GameMainSelector::handleInput(const SDL_Event & e, const Position & parentPos) { const auto getRay = [this](const auto & e) { - const auto mouse = glm::vec2 {e.x, e.y} / position.size; + const auto mouse = ScreenRelCoord {e.x, e.y} / position.size; return camera->unProject(mouse); }; if (target) { @@ -72,8 +73,8 @@ GameMainSelector::handleInput(const SDL_Event & e, const Position & parentPos) void GameMainSelector::defaultClick(const Ray & ray) { - glm::vec2 baryPos {}; - float distance; + Position2D baryPos {}; + float distance {}; if (const auto selected = gameState->world.applyOne(&Selectable::intersectRay, ray, &baryPos, &distance); diff --git a/ui/gameMainWindow.cpp b/ui/gameMainWindow.cpp index b94accd..15f1e07 100644 --- a/ui/gameMainWindow.cpp +++ b/ui/gameMainWindow.cpp @@ -31,8 +31,8 @@ public: GameMainWindow::GameMainWindow(size_t w, size_t h) : Window {w, h, "I Like Trains", SDL_WINDOW_OPENGL}, SceneRenderer {Window::size, 0} { - uiComponents.create(glm::vec2 {-1150, -1150}); - auto gms = uiComponents.create(&camera, glm::vec2 {w, h}); + uiComponents.create(Position2D {-1150, -1150}); + auto gms = uiComponents.create(&camera, ScreenAbsCoord {w, h}); uiComponents.create(gms.get()); } diff --git a/ui/manualCameraController.cpp b/ui/manualCameraController.cpp index 8e52b0e..05c1fc5 100644 --- a/ui/manualCameraController.cpp +++ b/ui/manualCameraController.cpp @@ -59,7 +59,7 @@ ManualCameraController::handleInput(const SDL_Event & e, const Position &) pitch = std::clamp(pitch - 0.01F * static_cast(e.motion.yrel), 0.1F, half_pi); } else { - focus += rotate_flat(-direction) * glm::vec2 {-e.motion.xrel, e.motion.yrel}; + focus += rotate_flat(-direction) * Position2D {-e.motion.xrel, e.motion.yrel}; } } return true; -- cgit v1.2.3 From d771fbda2c171cfbc36cc0eb3122c1a02ffbb081 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 9 Nov 2023 01:57:27 +0000 Subject: WIP typedefing just about everything else --- assetFactory/assetFactory.h | 5 ++--- assetFactory/modelFactoryMesh.h | 9 ++++---- assetFactory/style.cpp | 14 ++++++------ assetFactory/style.h | 6 ++---- config/types.h | 3 +++ game/network/network.h | 2 +- game/network/rail.cpp | 4 ++-- gfx/gl/sceneRenderer.cpp | 2 +- gfx/gl/sceneRenderer.h | 2 +- gfx/gl/sceneShader.cpp | 4 ++-- gfx/gl/sceneShader.h | 4 ++-- gfx/gl/shadowMapper.cpp | 47 +++++++++++++++++++++-------------------- gfx/gl/shadowMapper.h | 2 +- ui/editNetwork.h | 2 +- 14 files changed, 54 insertions(+), 52 deletions(-) diff --git a/assetFactory/assetFactory.h b/assetFactory/assetFactory.h index e449ce2..787f0a4 100644 --- a/assetFactory/assetFactory.h +++ b/assetFactory/assetFactory.h @@ -15,10 +15,9 @@ public: using Assets = std::map>; using AssImps = std::map>; using TextureFragments = std::map>; - using Colour = glm::vec3; - using ColourAlpha = glm::vec4; + using Colour = RGB; + using ColourAlpha = RGBA; using Colours = std::map>; - using TextureFragmentCoords = std::array; AssetFactory(); [[nodiscard]] static std::shared_ptr loadXML(const std::filesystem::path &); diff --git a/assetFactory/modelFactoryMesh.h b/assetFactory/modelFactoryMesh.h index 32e7ab5..480bf7f 100644 --- a/assetFactory/modelFactoryMesh.h +++ b/assetFactory/modelFactoryMesh.h @@ -1,5 +1,6 @@ #pragma once +#include "config/types.h" #include "modelFactoryMesh_fwd.h" #include #include @@ -38,10 +39,10 @@ struct ModelFactoryTraits : public OpenMesh::DefaultTraits { EdgeAttributes(OpenMesh::Attributes::Status); VertexAttributes(OpenMesh::Attributes::Normal | OpenMesh::Attributes::Status); HalfedgeAttributes(OpenMesh::Attributes::TexCoord2D); - using Point = glm::vec3; - using Normal = glm::vec3; - using Color = glm::vec4; - using TexCoord2D = glm::vec2; + using Point = Position3D; + using Normal = Normal3D; + using Color = RGBA; + using TexCoord2D = TextureRelCoord; }; struct ModelFactoryMesh : public OpenMesh::PolyMesh_ArrayKernelT { diff --git a/assetFactory/style.cpp b/assetFactory/style.cpp index 81a5441..265becb 100644 --- a/assetFactory/style.cpp +++ b/assetFactory/style.cpp @@ -33,10 +33,10 @@ Style::applyStyle( const auto material = mf->getMaterialIndex(texture); mesh.property(mesh.materialFaceProperty, face) = material; static constexpr std::array coords {{ - {0.f, 0.f}, - {1.f, 0.f}, - {1.f, 1.f}, - {0.f, 1.f}, + {0.F, 0.F}, + {1.F, 0.F}, + {1.F, 1.F}, + {0.F, 1.F}, }}; auto coord = coords.begin(); // Wild assumption that face is a quad and the texture should apply linearly @@ -58,9 +58,9 @@ Style::getColour(const StyleStack & parents) bool Style::persist(Persistence::PersistenceStore & store) { - struct ColourParser : public Persistence::SelectionV { - using Persistence::SelectionV::SelectionV; - using Persistence::SelectionV::setValue; + struct ColourParser : public Persistence::SelectionV { + using Persistence::SelectionV::SelectionV; + using Persistence::SelectionV::setValue; void setValue(std::string && str) override diff --git a/assetFactory/style.h b/assetFactory/style.h index d931f98..2a437aa 100644 --- a/assetFactory/style.h +++ b/assetFactory/style.h @@ -10,9 +10,7 @@ class Style { public: using StyleStack = std::vector; - using Colour = glm::vec3; - using ColourAlpha = glm::vec4; - using EffectiveColour = std::optional>; + using EffectiveColour = std::optional>; void applyStyle(ModelFactoryMesh &, const StyleStack & parents, const Shape::CreatedFaces &) const; void applyStyle(ModelFactoryMesh &, const StyleStack & parents, const ModelFactoryMesh::FaceHandle &) const; @@ -30,7 +28,7 @@ public: static EffectiveColour getColour(const StyleStack & parents); - ColourAlpha colour {}; + RGBA colour {}; std::optional smooth; std::string texture; std::string textureRotation; // Multiples of 90deg, no int/enum support diff --git a/config/types.h b/config/types.h index a84be90..d99735e 100644 --- a/config/types.h +++ b/config/types.h @@ -27,8 +27,11 @@ using Normal3D = Normal<3>; using Rotation2D = Rotation<2>; using Rotation3D = Rotation<3>; using TextureRelCoord = glm::vec<2, float>; +using TextureRelRegion = glm::vec<4, float>; using TextureAbsCoord = glm::vec<2, GLsizei>; +using TextureAbsRegion = glm::vec<4, GLsizei>; using RGB = Colour<3>; using RGBA = Colour<4>; using ScreenRelCoord = glm::vec<2, float>; using ScreenAbsCoord = glm::vec<2, uint16_t>; +using ViewPort = glm::vec<4, GLsizei>; diff --git a/game/network/network.h b/game/network/network.h index 02f8c30..8af06a9 100644 --- a/game/network/network.h +++ b/game/network/network.h @@ -16,7 +16,7 @@ class Texture; class SceneShader; class Ray; -template using GenDef = std::tuple...>; +template using GenDef = std::tuple...>; using GenCurveDef = GenDef<3, 3, 2>; class Network { diff --git a/game/network/rail.cpp b/game/network/rail.cpp index f46504b..cc61db9 100644 --- a/game/network/rail.cpp +++ b/game/network/rail.cpp @@ -133,7 +133,7 @@ RailLinkStraight::RailLinkStraight(Node::Ptr a, Node::Ptr b, const Position3D & for (auto ei : {1U, 0U}) { const auto trans {glm::translate(ends[ei].node->pos) * e}; for (const auto & rcs : railCrossSection) { - const Position3D m {(trans * glm::vec4 {rcs.first, 1})}; + const Position3D m {(trans * (rcs.first ^ 1))}; vertices.emplace_back(m, Position2D {rcs.second, len * static_cast(ei)}, up); } } @@ -166,7 +166,7 @@ RailLinkCurve::RailLinkCurve(const Node::Ptr & a, const Node::Ptr & b, Position3 const auto t { trans * glm::rotate(half_pi - swing.x, up) * glm::translate(Position3D {radius, 0.F, swing.y})}; for (const auto & rcs : railCrossSection) { - const Position3D m {(t * glm::vec4 {rcs.first, 1})}; + const Position3D m {(t * (rcs.first ^ 1))}; vertices.emplace_back(m, Position2D {rcs.second, swing.z}, up); } } diff --git a/gfx/gl/sceneRenderer.cpp b/gfx/gl/sceneRenderer.cpp index 6965175..4a3fec9 100644 --- a/gfx/gl/sceneRenderer.cpp +++ b/gfx/gl/sceneRenderer.cpp @@ -135,7 +135,7 @@ SceneRenderer::DirectionalLightProgram::DirectionalLightProgram() : void SceneRenderer::DirectionalLightProgram::setDirectionalLight(const RGB & c, const Direction3D & d, - const std::span lvp, const std::span shadowMapRegions, + const std::span lvp, const std::span shadowMapRegions, std::size_t maps) const { glUniform3fv(colourLoc, 1, glm::value_ptr(c)); diff --git a/gfx/gl/sceneRenderer.h b/gfx/gl/sceneRenderer.h index 87f474b..30fd8d3 100644 --- a/gfx/gl/sceneRenderer.h +++ b/gfx/gl/sceneRenderer.h @@ -40,7 +40,7 @@ private: using Program::use; void setDirectionalLight(const RGB &, const Direction3D &, const std::span, - const std::span, std::size_t maps) const; + const std::span, std::size_t maps) const; private: RequiredUniformLocation directionLoc, colourLoc, lightViewProjectionLoc, lightViewProjectionCountLoc, diff --git a/gfx/gl/sceneShader.cpp b/gfx/gl/sceneShader.cpp index 04b6d9e..2dc2e70 100644 --- a/gfx/gl/sceneShader.cpp +++ b/gfx/gl/sceneShader.cpp @@ -35,7 +35,7 @@ SceneShader::setViewProjection(const glm::mat4 & viewProjection) const } void -SceneShader::setViewPort(const glm::ivec4 & viewPort) const +SceneShader::setViewPort(const ViewPort & viewPort) const { for (const auto & prog : std::array { &basic, &basicInst, &water, &landmass, &absolute, &pointLight, &spotLight}) { @@ -51,7 +51,7 @@ SceneShader::SceneProgram::setViewProjection(const glm::mat4 & viewProjection) c } void -SceneShader::SceneProgram::setViewPort(const glm::ivec4 & viewPort) const +SceneShader::SceneProgram::setViewPort(const ViewPort & viewPort) const { if (viewPortLoc >= 0) { glUseProgram(*this); diff --git a/gfx/gl/sceneShader.h b/gfx/gl/sceneShader.h index d1c6ef2..f46b842 100644 --- a/gfx/gl/sceneShader.h +++ b/gfx/gl/sceneShader.h @@ -16,7 +16,7 @@ class SceneShader { } void setViewProjection(const glm::mat4 &) const; - void setViewPort(const glm::ivec4 &) const; + void setViewPort(const ViewPort &) const; private: RequiredUniformLocation viewProjectionLoc; @@ -88,5 +88,5 @@ public: SpotLightShader spotLight; void setViewProjection(const glm::mat4 & viewProjection) const; - void setViewPort(const glm::ivec4 & viewPort) const; + void setViewPort(const ViewPort & viewPort) const; }; diff --git a/gfx/gl/shadowMapper.cpp b/gfx/gl/shadowMapper.cpp index aea5af3..94a0791 100644 --- a/gfx/gl/shadowMapper.cpp +++ b/gfx/gl/shadowMapper.cpp @@ -24,7 +24,7 @@ ShadowMapper::ShadowMapper(const TextureAbsCoord & s) : glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - static constexpr glm::vec4 border {std::numeric_limits::infinity()}; + static constexpr RGBA border {std::numeric_limits::infinity()}; glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, glm::value_ptr(border)); glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO); @@ -37,7 +37,7 @@ ShadowMapper::ShadowMapper(const TextureAbsCoord & s) : glBindFramebuffer(GL_FRAMEBUFFER, 0); } -constexpr std::array, ShadowMapper::SHADOW_BANDS> viewports {{ +constexpr std::array, ShadowMapper::SHADOW_BANDS> viewports {{ {{ {31, 31, 0, 0}, // full }}, @@ -57,27 +57,28 @@ constexpr std::array, ShadowM {1, 1, 1, 1}, // upper right }}, }}; -constexpr std::array, ShadowMapper::SHADOW_BANDS> shadowMapRegions {{ - {{ - {0.5F, 0.5F, 0.5F, 0.5F}, // full - }}, - {{ - {0.5F, 0.25F, 0.5F, 0.25F}, // lower half - {0.5F, 0.25F, 0.5F, 0.75F}, // upper half - }}, - {{ - {0.5F, 0.25F, 0.5F, 0.25F}, // lower half - {0.25F, 0.25F, 0.25F, 0.75F}, // upper left - {0.25F, 0.25F, 0.75F, 0.75F}, // upper right - }}, - - {{ - {0.25F, 0.25F, 0.25F, 0.25F}, // lower left - {0.25F, 0.25F, 0.75F, 0.25F}, // lower right - {0.25F, 0.25F, 0.25F, 0.75F}, // upper left - {0.25F, 0.25F, 0.75F, 0.75F}, // upper right - }}, -}}; +constexpr std::array, ShadowMapper::SHADOW_BANDS> + shadowMapRegions {{ + {{ + {0.5F, 0.5F, 0.5F, 0.5F}, // full + }}, + {{ + {0.5F, 0.25F, 0.5F, 0.25F}, // lower half + {0.5F, 0.25F, 0.5F, 0.75F}, // upper half + }}, + {{ + {0.5F, 0.25F, 0.5F, 0.25F}, // lower half + {0.25F, 0.25F, 0.25F, 0.75F}, // upper left + {0.25F, 0.25F, 0.75F, 0.75F}, // upper right + }}, + + {{ + {0.25F, 0.25F, 0.25F, 0.25F}, // lower left + {0.25F, 0.25F, 0.75F, 0.25F}, // lower right + {0.25F, 0.25F, 0.25F, 0.75F}, // upper left + {0.25F, 0.25F, 0.75F, 0.75F}, // upper right + }}, + }}; constexpr std::array shadowBands { 1.F, 250.F, diff --git a/gfx/gl/shadowMapper.h b/gfx/gl/shadowMapper.h index e5272a3..d54734c 100644 --- a/gfx/gl/shadowMapper.h +++ b/gfx/gl/shadowMapper.h @@ -18,7 +18,7 @@ public: struct Definitions { std::array projections {}; - std::array regions {}; + std::array regions {}; size_t maps {}; }; diff --git a/ui/editNetwork.h b/ui/editNetwork.h index eb1677e..e1aaa61 100644 --- a/ui/editNetwork.h +++ b/ui/editNetwork.h @@ -21,7 +21,7 @@ public: void render(const SceneShader &) const override; void render(const UIShader & shader, const UIComponent::Position & pos) const override; - using NetworkClickPos = std::variant; + using NetworkClickPos = std::variant; class Builder { public: -- cgit v1.2.3 From b44d10c03299953104266f01f6415b945e6520b9 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 9 Nov 2023 17:38:39 +0000 Subject: Fix definition of shadowMapRegions --- gfx/gl/shadowMapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gfx/gl/shadowMapper.cpp b/gfx/gl/shadowMapper.cpp index 94a0791..e4ee47a 100644 --- a/gfx/gl/shadowMapper.cpp +++ b/gfx/gl/shadowMapper.cpp @@ -57,7 +57,7 @@ constexpr std::array, S {1, 1, 1, 1}, // upper right }}, }}; -constexpr std::array, ShadowMapper::SHADOW_BANDS> +constexpr std::array, ShadowMapper::SHADOW_BANDS> shadowMapRegions {{ {{ {0.5F, 0.5F, 0.5F, 0.5F}, // full -- cgit v1.2.3 From 5bc0462311ab4c691102f0bc39d6ae03c61a287b Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 11 Nov 2023 17:32:05 +0000 Subject: Add Location method for getting the rotation only transform --- lib/location.cpp | 6 ++++++ lib/location.h | 1 + 2 files changed, 7 insertions(+) diff --git a/lib/location.cpp b/lib/location.cpp index 732dd6d..9a31402 100644 --- a/lib/location.cpp +++ b/lib/location.cpp @@ -7,3 +7,9 @@ Location::getTransform() const { return glm::translate(pos) * rotate_ypr(rot); } + +glm::mat4 +Location::getRotationTransform() const +{ + return rotate_ypr(rot); +} diff --git a/lib/location.h b/lib/location.h index 7f2b44d..55737ae 100644 --- a/lib/location.h +++ b/lib/location.h @@ -10,6 +10,7 @@ public: #endif [[nodiscard]] glm::mat4 getTransform() const; + [[nodiscard]] glm::mat4 getRotationTransform() const; Position3D pos; Rotation3D rot; -- cgit v1.2.3 From ba4bca84808bebfc81be7df2cb536d1f73451bc6 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 11 Nov 2023 17:35:07 +0000 Subject: Add BufferedLocation method for getting the rotation only transform --- gfx/gl/bufferedLocation.cpp | 6 ++++++ gfx/gl/bufferedLocation.h | 1 + 2 files changed, 7 insertions(+) diff --git a/gfx/gl/bufferedLocation.cpp b/gfx/gl/bufferedLocation.cpp index 62cadef..6ba8812 100644 --- a/gfx/gl/bufferedLocation.cpp +++ b/gfx/gl/bufferedLocation.cpp @@ -63,3 +63,9 @@ BufferedLocation::getTransform() const { return loc.getTransform(); } + +glm::mat4 +BufferedLocation::getRotationTransform() const +{ + return loc.getRotationTransform(); +} diff --git a/gfx/gl/bufferedLocation.h b/gfx/gl/bufferedLocation.h index 39d3139..8302b3c 100644 --- a/gfx/gl/bufferedLocation.h +++ b/gfx/gl/bufferedLocation.h @@ -23,6 +23,7 @@ public: void setLocation(Position3D, Rotation3D); [[nodiscard]] glm::mat4 getTransform() const; + [[nodiscard]] glm::mat4 getRotationTransform() const; private: virtual void updateBuffer() = 0; -- cgit v1.2.3 From 5e25d79beef19c39537b0f15982a175fec45bb3e Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 11 Nov 2023 17:37:57 +0000 Subject: Refactor BufferedLocationT to use a callback Simplifies customisation in the face of multiple fields --- game/vehicles/railVehicle.cpp | 15 ++++++++++++--- game/vehicles/railVehicle.h | 5 ++--- gfx/gl/bufferedLocation.cpp | 7 ++++++- gfx/gl/bufferedLocation.h | 18 +++++++----------- 4 files changed, 27 insertions(+), 18 deletions(-) diff --git a/game/vehicles/railVehicle.cpp b/game/vehicles/railVehicle.cpp index fc43995..1ed904d 100644 --- a/game/vehicles/railVehicle.cpp +++ b/game/vehicles/railVehicle.cpp @@ -12,10 +12,19 @@ #include RailVehicle::RailVehicle(RailVehicleClassPtr rvc) : - RailVehicleClass::Instance {rvc->instances.acquire()}, rvClass {std::move(rvc)}, location {&LV::body, *this}, + RailVehicleClass::Instance {rvc->instances.acquire()}, rvClass {std::move(rvc)}, + location {[this](const BufferedLocation * l) { + this->get()->body = l->getTransform(); + }}, bogies {{ - {&LV::front, *this, Position3D {0, rvClass->wheelBase / 2.F, 0}}, - {&LV::back, *this, Position3D {0, -rvClass->wheelBase / 2.F, 0}}, + {[this](const BufferedLocation * l) { + this->get()->front = l->getTransform(); + }, + Position3D {0, rvClass->wheelBase / 2.F, 0}}, + {[this](const BufferedLocation * l) { + this->get()->back = l->getTransform(); + }, + Position3D {0, -rvClass->wheelBase / 2.F, 0}}, }} { } diff --git a/game/vehicles/railVehicle.h b/game/vehicles/railVehicle.h index e034852..20d1ea1 100644 --- a/game/vehicles/railVehicle.h +++ b/game/vehicles/railVehicle.h @@ -21,9 +21,8 @@ public: RailVehicleClassPtr rvClass; using LV = RailVehicleClass::LocationVertex; - using BLocation = BufferedLocationT; - BLocation location; - std::array bogies; + BufferedLocationUpdater location; + std::array bogies; }; using RailVehiclePtr = std::unique_ptr; diff --git a/gfx/gl/bufferedLocation.cpp b/gfx/gl/bufferedLocation.cpp index 6ba8812..412e3ab 100644 --- a/gfx/gl/bufferedLocation.cpp +++ b/gfx/gl/bufferedLocation.cpp @@ -1,6 +1,5 @@ #include "bufferedLocation.h" #include "location.h" -#include "maths.h" #include BufferedLocation::BufferedLocation(Position3D p, Rotation3D r) : BufferedLocation {Location {p, r}} { } @@ -69,3 +68,9 @@ BufferedLocation::getRotationTransform() const { return loc.getRotationTransform(); } + +void +BufferedLocationUpdater::updateBuffer() const +{ + onUpdate(this); +} diff --git a/gfx/gl/bufferedLocation.h b/gfx/gl/bufferedLocation.h index 8302b3c..a5cd23e 100644 --- a/gfx/gl/bufferedLocation.h +++ b/gfx/gl/bufferedLocation.h @@ -4,7 +4,7 @@ #include #include #include -#include +#include class BufferedLocation { public: @@ -26,16 +26,16 @@ public: [[nodiscard]] glm::mat4 getRotationTransform() const; private: - virtual void updateBuffer() = 0; + virtual void updateBuffer() const = 0; Location loc; }; -template class BufferedLocationT : public BufferedLocation { +class BufferedLocationUpdater : public BufferedLocation { public: template - BufferedLocationT(Target &&... target, LocationArgs &&... t) : - BufferedLocation {std::forward(t)...}, target {std::forward(target)...} + BufferedLocationUpdater(std::function onUpdate, LocationArgs &&... t) : + BufferedLocation {std::forward(t)...}, onUpdate {std::move(onUpdate)} { updateBuffer(); } @@ -43,11 +43,7 @@ public: using BufferedLocation::operator=; private: - void - updateBuffer() override - { - std::apply(std::invoke, target) = getTransform(); - } + void updateBuffer() const override; - std::tuple target; + std::function onUpdate; }; -- cgit v1.2.3 From 356e874050e5ad5af87b04a2bb01ce34a86640bb Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 13 Nov 2023 00:17:11 +0000 Subject: Send position and rotation matrix to GPU separately --- game/scenary/foliage.cpp | 3 ++- game/scenary/foliage.h | 3 ++- game/scenary/plant.cpp | 2 +- game/scenary/plant.h | 2 +- game/vehicles/railVehicle.cpp | 9 ++++++--- game/vehicles/railVehicleClass.cpp | 8 +++++--- game/vehicles/railVehicleClass.h | 1 + gfx/gl/camera.cpp | 9 ++++----- gfx/gl/sceneRenderer.cpp | 2 +- gfx/gl/sceneShader.cpp | 13 ++++++++----- gfx/gl/sceneShader.h | 11 +++++++---- gfx/gl/shaders/commonPoint.glsl | 2 +- gfx/gl/shaders/commonShadowPoint.glsl | 3 ++- gfx/gl/shaders/dynamicPoint.vs | 2 ++ gfx/gl/shaders/dynamicPointInst.vs | 2 ++ gfx/gl/shaders/fixedPoint.vs | 2 ++ gfx/gl/shaders/pointLight.gs | 1 + gfx/gl/shaders/pointLight.vs | 3 ++- gfx/gl/shaders/shadowDynamicPoint.vs | 2 ++ gfx/gl/shaders/shadowDynamicPointInst.vs | 2 ++ gfx/gl/shaders/shadowFixedPoint.vs | 2 ++ gfx/gl/shaders/spotLight.gs | 1 + gfx/gl/shaders/spotLight.vs | 3 ++- gfx/gl/shaders/water.vs | 7 ++++--- 24 files changed, 63 insertions(+), 32 deletions(-) diff --git a/game/scenary/foliage.cpp b/game/scenary/foliage.cpp index 702a52c..c258b77 100644 --- a/game/scenary/foliage.cpp +++ b/game/scenary/foliage.cpp @@ -15,7 +15,8 @@ void Foliage::postLoad() { texture = getTexture(); - bodyMesh->configureVAO(instanceVAO).addAttribs(instances.bufferName(), 1); + bodyMesh->configureVAO(instanceVAO) + .addAttribs(instances.bufferName(), 1); } void diff --git a/game/scenary/foliage.h b/game/scenary/foliage.h index b72a9c2..5a9d2de 100644 --- a/game/scenary/foliage.h +++ b/game/scenary/foliage.h @@ -15,7 +15,8 @@ class Foliage : public Asset, public Renderable, public StdTypeDefs { glVertexArray instanceVAO; public: - mutable InstanceVertices instances; + using LocationVertex = std::pair; + mutable InstanceVertices instances; void render(const SceneShader &) const override; void shadows(const ShadowMapper &) const override; diff --git a/game/scenary/plant.cpp b/game/scenary/plant.cpp index 4fb3cb5..b39c28b 100644 --- a/game/scenary/plant.cpp +++ b/game/scenary/plant.cpp @@ -2,6 +2,6 @@ #include "location.h" Plant::Plant(std::shared_ptr type, const Location & position) : - type {std::move(type)}, location {this->type->instances.acquire(position.getTransform())} + type {std::move(type)}, location {this->type->instances.acquire(position.getRotationTransform(), position.pos)} { } diff --git a/game/scenary/plant.h b/game/scenary/plant.h index 82ab0e5..77c9ff7 100644 --- a/game/scenary/plant.h +++ b/game/scenary/plant.h @@ -7,7 +7,7 @@ class Location; class Plant : public WorldObject { std::shared_ptr type; - InstanceVertices::InstanceProxy location; + InstanceVertices::InstanceProxy location; void tick(TickDuration) override diff --git a/game/vehicles/railVehicle.cpp b/game/vehicles/railVehicle.cpp index 1ed904d..6e6e18f 100644 --- a/game/vehicles/railVehicle.cpp +++ b/game/vehicles/railVehicle.cpp @@ -14,15 +14,18 @@ RailVehicle::RailVehicle(RailVehicleClassPtr rvc) : RailVehicleClass::Instance {rvc->instances.acquire()}, rvClass {std::move(rvc)}, location {[this](const BufferedLocation * l) { - this->get()->body = l->getTransform(); + this->get()->body = l->getRotationTransform(); + this->get()->bodyPos = l->position(); }}, bogies {{ {[this](const BufferedLocation * l) { - this->get()->front = l->getTransform(); + this->get()->front = l->getRotationTransform(); + this->get()->frontPos = l->position(); }, Position3D {0, rvClass->wheelBase / 2.F, 0}}, {[this](const BufferedLocation * l) { - this->get()->back = l->getTransform(); + this->get()->back = l->getRotationTransform(); + this->get()->backPos = l->position(); }, Position3D {0, -rvClass->wheelBase / 2.F, 0}}, }} diff --git a/game/vehicles/railVehicleClass.cpp b/game/vehicles/railVehicleClass.cpp index 324148c..7a6a9fe 100644 --- a/game/vehicles/railVehicleClass.cpp +++ b/game/vehicles/railVehicleClass.cpp @@ -35,13 +35,15 @@ void RailVehicleClass::postLoad() { texture = getTexture(); - bodyMesh->configureVAO(instanceVAO).addAttribs(instances.bufferName(), 1); + bodyMesh->configureVAO(instanceVAO) + .addAttribs(instances.bufferName(), 1); bogies.front() ->configureVAO(instancesBogiesVAO.front()) - .addAttribs(instances.bufferName(), 1); + .addAttribs(instances.bufferName(), 1); bogies.back() ->configureVAO(instancesBogiesVAO.back()) - .addAttribs(instances.bufferName(), 1); + .addAttribs(instances.bufferName(), 1); + static_assert(sizeof(LocationVertex) == 228UL); } void diff --git a/game/vehicles/railVehicleClass.h b/game/vehicles/railVehicleClass.h index 4668d7d..16dce01 100644 --- a/game/vehicles/railVehicleClass.h +++ b/game/vehicles/railVehicleClass.h @@ -20,6 +20,7 @@ public: struct LocationVertex { glm::mat4 body, front, back; + Position3D bodyPos, frontPos, backPos; }; std::array bogies; diff --git a/gfx/gl/camera.cpp b/gfx/gl/camera.cpp index 6a0359c..15f76c4 100644 --- a/gfx/gl/camera.cpp +++ b/gfx/gl/camera.cpp @@ -8,10 +8,9 @@ Camera::Camera(Position3D pos, Angle fov, Angle aspect, Distance zNear, Distance zFar) : position {pos}, forward {::north}, up {::up}, near {zNear}, far {zFar}, - projection {glm::perspective(fov, aspect, zNear, zFar)}, - viewProjection {projection * glm::lookAt(position, position + forward, up)}, - inverseViewProjection {glm::inverse(viewProjection)} + projection {glm::perspective(fov, aspect, zNear, zFar)}, viewProjection {}, inverseViewProjection {} { + updateView(); } Ray @@ -25,8 +24,8 @@ Camera::unProject(const ScreenRelCoord & mouse) const void Camera::updateView() { - viewProjection = projection * glm::lookAt(position, position + forward, up); - inverseViewProjection = glm::inverse(viewProjection); + viewProjection = projection * glm::lookAt(origin, forward, up); + inverseViewProjection = glm::inverse(projection * glm::lookAt(position, position + forward, up)); } Direction3D diff --git a/gfx/gl/sceneRenderer.cpp b/gfx/gl/sceneRenderer.cpp index 4a3fec9..9b5510e 100644 --- a/gfx/gl/sceneRenderer.cpp +++ b/gfx/gl/sceneRenderer.cpp @@ -52,7 +52,7 @@ SceneRenderer::SceneRenderer(ScreenAbsCoord s, GLuint o) : void SceneRenderer::render(const SceneProvider & scene) const { - shader.setViewProjection(camera.getViewProjection()); + shader.setViewProjection(camera.getPosition(), camera.getViewProjection()); glViewport(0, 0, size.x, size.y); // Geometry pass diff --git a/gfx/gl/sceneShader.cpp b/gfx/gl/sceneShader.cpp index 2dc2e70..2f391fd 100644 --- a/gfx/gl/sceneShader.cpp +++ b/gfx/gl/sceneShader.cpp @@ -26,11 +26,11 @@ SceneShader::SceneShader() : } void -SceneShader::setViewProjection(const glm::mat4 & viewProjection) const +SceneShader::setViewProjection(const Position3D & viewPoint, const glm::mat4 & viewProjection) const { for (const auto & prog : std::array { &basic, &basicInst, &water, &landmass, &absolute, &pointLight, &spotLight}) { - prog->setViewProjection(viewProjection); + prog->setViewProjection(viewPoint, viewProjection); } } @@ -44,10 +44,11 @@ SceneShader::setViewPort(const ViewPort & viewPort) const } void -SceneShader::SceneProgram::setViewProjection(const glm::mat4 & viewProjection) const +SceneShader::SceneProgram::setViewProjection(const Position3D & viewPoint, const glm::mat4 & viewProjection) const { glUseProgram(*this); glUniformMatrix4fv(viewProjectionLoc, 1, GL_FALSE, glm::value_ptr(viewProjection)); + glUniform3fv(viewPointLoc, 1, glm::value_ptr(viewPoint)); } void @@ -86,7 +87,8 @@ SceneShader::WaterProgram::use(float waveCycle) const } SceneShader::PointLightShader::PointLightShader() : - SceneProgram {pointLight_vs, pointLight_gs, pointLight_fs}, colourLoc {*this, "colour"}, kqLoc {*this, "kq"} + SceneProgram {pointLight_vs, pointLight_gs, pointLight_fs}, colourLoc {*this, "colour"}, kqLoc {*this, "kq"}, + viewPointLoc {*this, "viewPoint"} { VertexArrayObject {va}.addAttribs(b); } @@ -105,7 +107,8 @@ SceneShader::PointLightShader::add(const Position3D & position, const RGB & colo SceneShader::SpotLightShader::SpotLightShader() : SceneProgram {spotLight_vs, spotLight_gs, spotLight_fs}, directionLoc {*this, "v_direction"}, - colourLoc {*this, "colour"}, kqLoc {*this, "kq"}, arcLoc {*this, "arc"} + colourLoc {*this, "colour"}, kqLoc {*this, "kq"}, arcLoc {*this, "arc"}, viewPointLoc {*this, "viewPoint"} + { using v3pair = std::pair; VertexArrayObject {va}.addAttribs(b); diff --git a/gfx/gl/sceneShader.h b/gfx/gl/sceneShader.h index f46b842..154dc17 100644 --- a/gfx/gl/sceneShader.h +++ b/gfx/gl/sceneShader.h @@ -11,15 +11,16 @@ class SceneShader { public: template inline explicit SceneProgram(const S &... srcs) : - Program {srcs...}, viewProjectionLoc {*this, "viewProjection"}, viewPortLoc {*this, "viewPort"} + Program {srcs...}, viewProjectionLoc {*this, "viewProjection"}, viewPointLoc {*this, "viewPoint"}, + viewPortLoc {*this, "viewPort"} { } - void setViewProjection(const glm::mat4 &) const; + void setViewProjection(const Position3D &, const glm::mat4 &) const; void setViewPort(const ViewPort &) const; private: - RequiredUniformLocation viewProjectionLoc; + RequiredUniformLocation viewProjectionLoc, viewPointLoc; UniformLocation viewPortLoc; }; @@ -58,6 +59,7 @@ class SceneShader { private: UniformLocation colourLoc; UniformLocation kqLoc; + UniformLocation viewPointLoc; glVertexArray va; glBuffer b; }; @@ -74,6 +76,7 @@ class SceneShader { UniformLocation colourLoc; UniformLocation kqLoc; UniformLocation arcLoc; + UniformLocation viewPointLoc; glVertexArray va; glBuffer b; }; @@ -87,6 +90,6 @@ public: PointLightShader pointLight; SpotLightShader spotLight; - void setViewProjection(const glm::mat4 & viewProjection) const; + void setViewProjection(const Position3D & viewPoint, const glm::mat4 & viewProjection) const; void setViewPort(const ViewPort & viewPort) const; }; diff --git a/gfx/gl/shaders/commonPoint.glsl b/gfx/gl/shaders/commonPoint.glsl index 35510e1..046da27 100644 --- a/gfx/gl/shaders/commonPoint.glsl +++ b/gfx/gl/shaders/commonPoint.glsl @@ -24,5 +24,5 @@ main() Colour = colour; Material = getMaterialDetail(material); - gl_Position = viewProjection * worldPos; + gl_Position = viewProjection * vec4(FragPos - viewPoint + modelPos, 1); } diff --git a/gfx/gl/shaders/commonShadowPoint.glsl b/gfx/gl/shaders/commonShadowPoint.glsl index c7cbd3e..216642e 100644 --- a/gfx/gl/shaders/commonShadowPoint.glsl +++ b/gfx/gl/shaders/commonShadowPoint.glsl @@ -1,6 +1,7 @@ void main() { - gl_Position = viewProjection * model * vec4(position, 1.0); + vec4 worldPos = model * vec4(position, 1.0); + gl_Position = viewProjection * vec4(worldPos.xyz - viewPoint + modelPos, 1); gl_Position.z = max(gl_Position.z, -1); } diff --git a/gfx/gl/shaders/dynamicPoint.vs b/gfx/gl/shaders/dynamicPoint.vs index 961535c..9dd6a47 100644 --- a/gfx/gl/shaders/dynamicPoint.vs +++ b/gfx/gl/shaders/dynamicPoint.vs @@ -5,6 +5,8 @@ include(`meshIn.glsl') include(`materialInterface.glsl') uniform mat4 viewProjection; +uniform vec3 viewPoint; uniform mat4 model; +uniform vec3 modelPos; include(`commonPoint.glsl') diff --git a/gfx/gl/shaders/dynamicPointInst.vs b/gfx/gl/shaders/dynamicPointInst.vs index 2d6cee5..4ae6813 100644 --- a/gfx/gl/shaders/dynamicPointInst.vs +++ b/gfx/gl/shaders/dynamicPointInst.vs @@ -5,6 +5,8 @@ include(`meshIn.glsl') include(`materialInterface.glsl') uniform mat4 viewProjection; +uniform vec3 viewPoint; layout(location = 5) in mat4 model; +layout(location = 9) in vec3 modelPos; include(`commonPoint.glsl') diff --git a/gfx/gl/shaders/fixedPoint.vs b/gfx/gl/shaders/fixedPoint.vs index ed78c96..0adbb02 100644 --- a/gfx/gl/shaders/fixedPoint.vs +++ b/gfx/gl/shaders/fixedPoint.vs @@ -5,6 +5,8 @@ include(`meshIn.glsl') include(`materialInterface.glsl') uniform mat4 viewProjection; +uniform vec3 viewPoint; const mat4 model = mat4(1); +const vec3 modelPos = vec3(0); include(`commonPoint.glsl') diff --git a/gfx/gl/shaders/pointLight.gs b/gfx/gl/shaders/pointLight.gs index 03d131d..ec089f5 100644 --- a/gfx/gl/shaders/pointLight.gs +++ b/gfx/gl/shaders/pointLight.gs @@ -19,6 +19,7 @@ const vec3[] cube = vec3[]( // http://www.cs.umd.edu/gvil/papers/av_ts.pdf vec3(1, 1, -1) // Back-top-right ); uniform mat4 viewProjection; +uniform vec3 viewPoint; in vec3 centre[]; in float size[]; diff --git a/gfx/gl/shaders/pointLight.vs b/gfx/gl/shaders/pointLight.vs index 35682fa..b3fe7b9 100644 --- a/gfx/gl/shaders/pointLight.vs +++ b/gfx/gl/shaders/pointLight.vs @@ -4,6 +4,7 @@ layout(location = 0) in vec3 position; uniform vec3 colour; uniform float kq; +uniform vec3 viewPoint; out vec3 centre; out float size; @@ -13,5 +14,5 @@ main() { centre = position; size = (8 * sqrt(max(max(colour.r, colour.g), colour.b))) / sqrt(kq); - gl_Position = vec4(centre, 0); + gl_Position = vec4(centre - viewPoint, 0); } diff --git a/gfx/gl/shaders/shadowDynamicPoint.vs b/gfx/gl/shaders/shadowDynamicPoint.vs index f3ed533..eb25423 100644 --- a/gfx/gl/shaders/shadowDynamicPoint.vs +++ b/gfx/gl/shaders/shadowDynamicPoint.vs @@ -3,6 +3,8 @@ include(`meshIn.glsl') uniform mat4 viewProjection; +uniform vec3 viewPoint; uniform mat4 model; +uniform vec3 modelPos; include(`commonShadowPoint.glsl') diff --git a/gfx/gl/shaders/shadowDynamicPointInst.vs b/gfx/gl/shaders/shadowDynamicPointInst.vs index 1bf74ef..a0f51c3 100644 --- a/gfx/gl/shaders/shadowDynamicPointInst.vs +++ b/gfx/gl/shaders/shadowDynamicPointInst.vs @@ -3,6 +3,8 @@ include(`meshIn.glsl') uniform mat4 viewProjection; +uniform vec3 viewPoint; layout(location = 5) in mat4 model; +layout(location = 9) in vec3 modelPos; include(`commonShadowPoint.glsl') diff --git a/gfx/gl/shaders/shadowFixedPoint.vs b/gfx/gl/shaders/shadowFixedPoint.vs index 8921707..dfc5c42 100644 --- a/gfx/gl/shaders/shadowFixedPoint.vs +++ b/gfx/gl/shaders/shadowFixedPoint.vs @@ -3,6 +3,8 @@ include(`meshIn.glsl') uniform mat4 viewProjection; +uniform vec3 viewPoint; const mat4 model = mat4(1); +const vec3 modelPos = vec3(0); include(`commonShadowPoint.glsl') diff --git a/gfx/gl/shaders/spotLight.gs b/gfx/gl/shaders/spotLight.gs index ad65675..0529614 100644 --- a/gfx/gl/shaders/spotLight.gs +++ b/gfx/gl/shaders/spotLight.gs @@ -10,6 +10,7 @@ const vec3[] pyramid = vec3[]( // four-sided vec3(1, -1, 1) // Front-right ); uniform mat4 viewProjection; +uniform vec3 viewPoint; uniform float arc; in vec3 position[]; diff --git a/gfx/gl/shaders/spotLight.vs b/gfx/gl/shaders/spotLight.vs index dca0854..e61b641 100644 --- a/gfx/gl/shaders/spotLight.vs +++ b/gfx/gl/shaders/spotLight.vs @@ -6,6 +6,7 @@ uniform vec3 v_direction; uniform vec3 colour; uniform float kq; uniform float arc; +uniform vec3 viewPoint; out vec3 position; out vec3 direction; @@ -19,5 +20,5 @@ main() direction = normalize(v_direction); size = (8 * sqrt(max(max(colour.r, colour.g), colour.b))) / sqrt(kq); cosarc = cos(arc / 2); - gl_Position = vec4(position, 0); + gl_Position = vec4(position - viewPoint, 0); } diff --git a/gfx/gl/shaders/water.vs b/gfx/gl/shaders/water.vs index a21b49f..014499f 100644 --- a/gfx/gl/shaders/water.vs +++ b/gfx/gl/shaders/water.vs @@ -4,17 +4,18 @@ include(`meshIn.glsl') include(`materialInterface.glsl') uniform mat4 viewProjection; +uniform vec3 viewPoint; uniform vec3 waves; void main() { - vec4 wpos = vec4(position.x + cos(waves.x), position.y + cos(waves.x * waves.y / 2), - cos(waves.x + position.x + (position.y / 8)) * .3, 1.0); + vec3 wpos = vec3(position.x + cos(waves.x), position.y + cos(waves.x * waves.y / 2), + cos(waves.x + position.x + (position.y / 8)) * .3); FragPos = vec3(wpos.xy, position.z); TexCoords = texCoord; Normal = normal; - gl_Position = viewProjection * wpos; + gl_Position = viewProjection * vec4(wpos - viewPoint, 1.0); } -- cgit v1.2.3 From 685b33980cc7a346574b24732464f0cbe3115a1f Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Wed, 15 Nov 2023 01:29:24 +0000 Subject: Switch to millimeters for spatial units Mostly a case of changing far too many magic numbers, something else to fix I guess. I probably missed something. Also there's some hackery when loading 3D models, which are still assumed to be in metres. --- application/main.cpp | 17 +++++++++-------- assetFactory/factoryMesh.cpp | 2 +- game/geoData.cpp | 2 +- game/geoData.h | 2 +- game/network/rail.cpp | 18 +++++++++--------- game/vehicles/linkHistory.cpp | 2 +- game/vehicles/railVehicle.cpp | 4 ++-- gfx/gl/sceneRenderer.cpp | 2 +- gfx/gl/shaders/landmass.fs | 6 +++--- gfx/gl/shaders/pointLight.fs | 2 +- gfx/gl/shaders/pointLight.vs | 2 +- gfx/gl/shaders/spotLight.fs | 2 +- gfx/gl/shaders/spotLight.vs | 2 +- gfx/gl/shaders/water.fs | 2 +- gfx/gl/shaders/water.vs | 4 ++-- gfx/gl/shadowMapper.cpp | 10 +++++----- res/brush47.xml | 2 +- test/test-assetFactory.cpp | 14 +++++++------- test/test-geo.cpp | 10 +++++----- test/test-render.cpp | 26 +++++++++++++------------- ui/gameMainWindow.cpp | 2 +- ui/manualCameraController.cpp | 4 ++-- ui/manualCameraController.h | 2 +- 23 files changed, 70 insertions(+), 69 deletions(-) diff --git a/application/main.cpp b/application/main.cpp index ffdaf63..01e6561 100644 --- a/application/main.cpp +++ b/application/main.cpp @@ -37,7 +37,7 @@ public: int run() { - geoData = std::make_shared(GeoData::Limits {{-120, -120}, {120, 120}}, 10.F); + geoData = std::make_shared(GeoData::Limits {{-120, -120}, {120, 120}}, 10000.F); geoData->generateRandom(); Windows windows; @@ -48,10 +48,10 @@ public: { auto rl = world.create(); - const Position3D j {-1120, -1100, 3}, k {-1100, -1000, 15}, l {-1000, -800, 20}, m {-900, -600, 30}, - n {-600, -500, 32}, o {-500, -800, 30}, p {-600, -900, 25}, q {-1025, -1175, 10}, - r {-925, -1075, 10}; - const Position3D s {-1100, -500, 15}, t {-1100, -450, 15}, u {-1000, -400, 15}; + const Position3D j {-1120000, -1100000, 3000}, k {-1100000, -1000000, 15000}, l {-1000000, -800000, 20000}, + m {-900000, -600000, 30000}, n {-600000, -500000, 32000}, o {-500000, -800000, 30000}, + p {-600000, -900000, 25000}, q {-1025000, -1175000, 10000}, r {-925000, -1075000, 10000}; + const Position3D s {-1100000, -500000, 15000}, t {-1100000, -450000, 15000}, u {-1000000, -400000, 15000}; auto l3 = rl->addLinksBetween(j, k); rl->addLinksBetween(k, l); rl->addLinksBetween(l, m); @@ -75,12 +75,13 @@ public: train->create(b47); } train->orders.removeAll(); - train->orders.create(&train->orders, l3->ends[1], l3->length, rl->findNodeAt({-1100, -450, 15})); + train->orders.create( + &train->orders, l3->ends[1], l3->length, rl->findNodeAt({-1100000, -450000, 15000})); train->currentActivity = train->orders.current()->createActivity(); auto foliage = std::dynamic_pointer_cast(assets.at("Tree-01-1")); - for (float x = 900; x < 1100; x += 3) { - for (float y = 900; y < 1100; y += 3) { + for (float x = 900000; x < 1100000; x += 3000) { + for (float y = 900000; y < 1100000; y += 3000) { world.create(foliage, Location {geoData->positionAt({-x, -y})}); } } diff --git a/assetFactory/factoryMesh.cpp b/assetFactory/factoryMesh.cpp index 46bcf6f..3caf5e8 100644 --- a/assetFactory/factoryMesh.cpp +++ b/assetFactory/factoryMesh.cpp @@ -30,7 +30,7 @@ FactoryMesh::createMesh() const const auto & point = mesh.point(vertex); const auto & normal = useVertexNormals ? mesh.property(mesh.vertex_normals_pph(), vertex) : mesh.property(mesh.face_normals_pph(), face); - Vertex outVertex {point, textureUV, normal, colour, material}; + Vertex outVertex {point * 1000.F, textureUV, normal, colour, material}; if (const auto existingItr = std::find(vertices.rbegin(), vertices.rend(), outVertex); existingItr != vertices.rend()) { faceIndices.push_back(static_cast(std::distance(existingItr, vertices.rend()) - 1)); diff --git a/game/geoData.cpp b/game/geoData.cpp index 76550cc..da067f7 100644 --- a/game/geoData.cpp +++ b/game/geoData.cpp @@ -31,7 +31,7 @@ GeoData::generateRandom() std::uniform_int_distribution<> rxpos(limit.first.x + 2, limit.second.x - 2), rypos(limit.first.y + 2, limit.second.y - 2); std::uniform_int_distribution<> rsize(10, 30); - std::uniform_real_distribution rheight(1, 3); + std::uniform_real_distribution rheight(1000, 3000); for (int h = 0; h < 500;) { const glm::ivec2 hpos {rxpos(gen), rypos(gen)}; const glm::ivec2 hsize {rsize(gen), rsize(gen)}; diff --git a/game/geoData.h b/game/geoData.h index b3ec51d..3bceb9c 100644 --- a/game/geoData.h +++ b/game/geoData.h @@ -14,7 +14,7 @@ class Ray; class GeoData { public: struct Node { - float height {-1.5F}; + float height {-1500.F}; }; using Quad = std::array; diff --git a/game/network/rail.cpp b/game/network/rail.cpp index cc61db9..ff101d4 100644 --- a/game/network/rail.cpp +++ b/game/network/rail.cpp @@ -18,7 +18,7 @@ template class NetworkOf; constexpr auto RAIL_CROSSSECTION_VERTICES {5U}; -constexpr Size3D RAIL_HEIGHT {0, 0, .25F}; +constexpr Size3D RAIL_HEIGHT {0, 0, 250.F}; RailLinks::RailLinks() : NetworkOf {"rails.jpg"} { } @@ -104,11 +104,11 @@ constexpr const std::array, RAIL_CROSSSECTION_VERTI // ___________ // _/ \_ // left to right - {{-1.9F, 0.F, 0.F}, 0.F}, - {{-.608F, 0.F, RAIL_HEIGHT.z}, 0.34F}, - {{0, 0.F, RAIL_HEIGHT.z * .7F}, 0.5F}, - {{.608F, 0.F, RAIL_HEIGHT.z}, 0.66F}, - {{1.9F, 0.F, 0.F}, 1.F}, + {{-1900.F, 0.F, 0.F}, 0.F}, + {{-608.F, 0.F, RAIL_HEIGHT.z}, .34F}, + {{0, 0.F, RAIL_HEIGHT.z * .7F}, .5F}, + {{608.F, 0.F, RAIL_HEIGHT.z}, .66F}, + {{1900.F, 0.F, 0.F}, 1.F}, }}; constexpr auto sleepers {5.F}; // There are 5 repetitions of sleepers in the texture @@ -128,7 +128,7 @@ RailLinkStraight::RailLinkStraight(Node::Ptr a, Node::Ptr b, const Position3D & if (glGenVertexArrays) { std::vector vertices; vertices.reserve(2 * railCrossSection.size()); - const auto len = round_sleepers(length / 2.F); + const auto len = round_sleepers(length / 2000.F); const auto e {flat_orientation(diff)}; for (auto ei : {1U, 0U}) { const auto trans {glm::translate(ends[ei].node->pos) * e}; @@ -155,8 +155,8 @@ RailLinkCurve::RailLinkCurve(const Node::Ptr & a, const Node::Ptr & b, Position3 const auto & e0p {ends[0].node->pos}; const auto & e1p {ends[1].node->pos}; const auto slength = round_sleepers(length / 2.F); - const auto segs = std::round(15.F * slength / std::pow(radius, 0.7F)); - const auto step {Position3D {arc_length(arc), e1p.z - e0p.z, slength} / segs}; + const auto segs = std::round(slength / std::pow(radius, 0.7F)); + const auto step {Position3D {arc_length(arc), e1p.z - e0p.z, slength / 1000.F} / segs}; const auto trans {glm::translate(centreBase)}; auto segCount = static_cast(std::lround(segs)) + 1; diff --git a/game/vehicles/linkHistory.cpp b/game/vehicles/linkHistory.cpp index 2802109..e6bab36 100644 --- a/game/vehicles/linkHistory.cpp +++ b/game/vehicles/linkHistory.cpp @@ -8,7 +8,7 @@ LinkHistory::add(const Link::WPtr & l, unsigned char d) links.insert(links.begin(), {l, d}); const auto lp = l.lock(); totalLen += lp->length; - while (totalLen >= 1000.F && !links.empty()) { + while (totalLen >= 1000000.F && !links.empty()) { totalLen -= links.back().first.lock()->length; links.pop_back(); } diff --git a/game/vehicles/railVehicle.cpp b/game/vehicles/railVehicle.cpp index 6e6e18f..26536f5 100644 --- a/game/vehicles/railVehicle.cpp +++ b/game/vehicles/railVehicle.cpp @@ -46,9 +46,9 @@ RailVehicle::move(const Train * t, float & trailBy) bool RailVehicle::intersectRay(const Ray & ray, Position2D * baryPos, float * distance) const { - constexpr const auto X = 1.35F; + constexpr const auto X = 1350.F; const auto Y = this->rvClass->length / 2.F; - constexpr const auto Z = 3.9F; + constexpr const auto Z = 3900.F; const auto moveBy = location.getTransform(); const std::array cornerVertices {{ moveBy * glm::vec4 {-X, Y, 0, 1}, // LFB diff --git a/gfx/gl/sceneRenderer.cpp b/gfx/gl/sceneRenderer.cpp index 9b5510e..53178e5 100644 --- a/gfx/gl/sceneRenderer.cpp +++ b/gfx/gl/sceneRenderer.cpp @@ -15,7 +15,7 @@ static constexpr const std::array displayVAOdata {{ }}; SceneRenderer::SceneRenderer(ScreenAbsCoord s, GLuint o) : - camera {{-1250.0F, -1250.0F, 35.0F}, quarter_pi, ratio(s), 0.1F, 10000.0F}, size {s}, output {o}, + camera {{-1250000.0F, -1250000.0F, 35.0F}, quarter_pi, ratio(s), 100.F, 10000000.0F}, size {s}, output {o}, lighting {lighting_vs, lighting_fs}, shadowMapper {{2048, 2048}} { shader.setViewPort({0, 0, size.x, size.y}); diff --git a/gfx/gl/shaders/landmass.fs b/gfx/gl/shaders/landmass.fs index 4dc92bb..9865d11 100644 --- a/gfx/gl/shaders/landmass.fs +++ b/gfx/gl/shaders/landmass.fs @@ -11,9 +11,9 @@ const vec3 rock = vec3(.2, .2, .1); const vec3 sand = vec3(.76, .7, .5); const vec3 snow = vec3(.97, .97, .99); -const float beachline = .5; -const float snowline_low = 28; -const float snowline_high = 30; +const float beachline = 500; +const float snowline_low = 28000; +const float snowline_high = 30000; const float slope_min = .99; const float slope_mid = .95; diff --git a/gfx/gl/shaders/pointLight.fs b/gfx/gl/shaders/pointLight.fs index bd32c05..1a68df8 100644 --- a/gfx/gl/shaders/pointLight.fs +++ b/gfx/gl/shaders/pointLight.fs @@ -26,5 +26,5 @@ main() if (normalDot < 0) { discard; } - FragColor = (colour * normalDot) / (1 + (kq * pow(lightDist, 2))); + FragColor = (colour * normalDot) / (1 + (kq * pow(lightDist / 1000.0, 2))); } diff --git a/gfx/gl/shaders/pointLight.vs b/gfx/gl/shaders/pointLight.vs index b3fe7b9..7694a25 100644 --- a/gfx/gl/shaders/pointLight.vs +++ b/gfx/gl/shaders/pointLight.vs @@ -13,6 +13,6 @@ void main() { centre = position; - size = (8 * sqrt(max(max(colour.r, colour.g), colour.b))) / sqrt(kq); + size = (8000 * sqrt(max(max(colour.r, colour.g), colour.b))) / sqrt(kq); gl_Position = vec4(centre - viewPoint, 0); } diff --git a/gfx/gl/shaders/spotLight.fs b/gfx/gl/shaders/spotLight.fs index add86fd..78b8f72 100644 --- a/gfx/gl/shaders/spotLight.fs +++ b/gfx/gl/shaders/spotLight.fs @@ -30,5 +30,5 @@ main() if (normalDot < 0) { discard; } - FragColor = (colour * normalDot) / (1 + (kq * pow(lightDist, 2))); + FragColor = (colour * normalDot) / (1 + (kq * pow(lightDist / 1000.0, 2))); } diff --git a/gfx/gl/shaders/spotLight.vs b/gfx/gl/shaders/spotLight.vs index e61b641..08197a4 100644 --- a/gfx/gl/shaders/spotLight.vs +++ b/gfx/gl/shaders/spotLight.vs @@ -18,7 +18,7 @@ main() { position = v_position; direction = normalize(v_direction); - size = (8 * sqrt(max(max(colour.r, colour.g), colour.b))) / sqrt(kq); + size = (8000 * sqrt(max(max(colour.r, colour.g), colour.b))) / sqrt(kq); cosarc = cos(arc / 2); gl_Position = vec4(position - viewPoint, 0); } diff --git a/gfx/gl/shaders/water.fs b/gfx/gl/shaders/water.fs index 04aa94c..2ccc924 100644 --- a/gfx/gl/shaders/water.fs +++ b/gfx/gl/shaders/water.fs @@ -13,5 +13,5 @@ main() gPosition = vec4(FragPos, 1); gNormal = vec4(Normal, 1); gAlbedoSpec = texture(texture0, TexCoords); - gAlbedoSpec.a *= clamp(-FragPos.z * .7, .1, 1.0); + gAlbedoSpec.a *= clamp(-FragPos.z * .0007, .1, 1.0); } diff --git a/gfx/gl/shaders/water.vs b/gfx/gl/shaders/water.vs index 014499f..03eabb2 100644 --- a/gfx/gl/shaders/water.vs +++ b/gfx/gl/shaders/water.vs @@ -10,8 +10,8 @@ uniform vec3 waves; void main() { - vec3 wpos = vec3(position.x + cos(waves.x), position.y + cos(waves.x * waves.y / 2), - cos(waves.x + position.x + (position.y / 8)) * .3); + vec3 wpos = vec3(position.x + (cos(waves.x) * 1000.0), position.y + (cos(waves.x * waves.y / 2) * 1000.0), + cos(waves.x + (position.x / 1000.0) + (position.y * 125.0)) * 300.0); FragPos = vec3(wpos.xy, position.z); TexCoords = texCoord; diff --git a/gfx/gl/shadowMapper.cpp b/gfx/gl/shadowMapper.cpp index e4ee47a..190f20e 100644 --- a/gfx/gl/shadowMapper.cpp +++ b/gfx/gl/shadowMapper.cpp @@ -80,11 +80,11 @@ constexpr std::array, S }}, }}; constexpr std::array shadowBands { - 1.F, - 250.F, - 750.F, - 2500.F, - 10000.F, + 1000.F, + 250000.F, + 750000.F, + 2500000.F, + 10000000.F, }; static_assert(viewports.size() == shadowMapRegions.size()); static_assert(shadowBands.size() == shadowMapRegions.size() + 1); diff --git a/res/brush47.xml b/res/brush47.xml index 31518c8..dc33282 100644 --- a/res/brush47.xml +++ b/res/brush47.xml @@ -61,7 +61,7 @@ - + diff --git a/test/test-assetFactory.cpp b/test/test-assetFactory.cpp index 9af08cb..c8183df 100644 --- a/test/test-assetFactory.cpp +++ b/test/test-assetFactory.cpp @@ -64,7 +64,7 @@ public: } void - render(float dist = 10.f) + render(float dist) { sceneRenderer.camera.setView({-dist, dist * 1.2f, dist * 1.2f}, south + east + down); sceneRenderer.render(*this); @@ -104,7 +104,7 @@ BOOST_AUTO_TEST_CASE(brush47xml, *boost::unit_test::timeout(5)) auto railVehicle = std::make_shared(brush47rvc); objects.objects.push_back(brush47rvc); - render(); + render(10000); } BOOST_AUTO_TEST_CASE(foliage, *boost::unit_test::timeout(5)) @@ -116,13 +116,13 @@ BOOST_AUTO_TEST_CASE(foliage, *boost::unit_test::timeout(5)) auto tree_01_1_f = std::dynamic_pointer_cast(tree_01_1); BOOST_REQUIRE(tree_01_1_f); - auto plant1 = std::make_shared(tree_01_1_f, Location {{-2, 2, 0}, {0, 0, 0}}); - auto plant2 = std::make_shared(tree_01_1_f, Location {{3, -4, 0}, {0, 1, 0}}); - auto plant3 = std::make_shared(tree_01_1_f, Location {{-2, -4, 0}, {0, 2, 0}}); - auto plant4 = std::make_shared(tree_01_1_f, Location {{3, 2, 0}, {0, 3, 0}}); + auto plant1 = std::make_shared(tree_01_1_f, Location {{-2000, 2000, 0}, {0, 0, 0}}); + auto plant2 = std::make_shared(tree_01_1_f, Location {{3000, -4000, 0}, {0, 1, 0}}); + auto plant3 = std::make_shared(tree_01_1_f, Location {{-2000, -4000, 0}, {0, 2, 0}}); + auto plant4 = std::make_shared(tree_01_1_f, Location {{3000, 2000, 0}, {0, 3, 0}}); objects.objects.push_back(tree_01_1_f); - render(5); + render(6000); } BOOST_AUTO_TEST_SUITE_END(); diff --git a/test/test-geo.cpp b/test/test-geo.cpp index 9874fb7..7404d32 100644 --- a/test/test-geo.cpp +++ b/test/test-geo.cpp @@ -30,7 +30,7 @@ BOOST_AUTO_TEST_CASE(initialize) BOOST_CHECK_EQUAL(size, glm::uvec2(41, 46)); BOOST_CHECK_EQUAL(nodes.size(), 1886); BOOST_CHECK(std::all_of(nodes.begin(), nodes.end(), [](const auto & n) { - return n.height == -1.5F; + return n.height == -1500.F; })); } @@ -63,12 +63,12 @@ BOOST_AUTO_TEST_CASE(gen_random) })); // Still an island for (int x = limit.first.x; x <= limit.second.x; x += 1) { - BOOST_CHECK_EQUAL(nodes[at(x, limit.first.y)].height, -1.5F); - BOOST_CHECK_EQUAL(nodes[at(x, limit.second.y)].height, -1.5F); + BOOST_CHECK_EQUAL(nodes[at(x, limit.first.y)].height, -1500.F); + BOOST_CHECK_EQUAL(nodes[at(x, limit.second.y)].height, -1500.F); } for (int y = limit.first.y; y <= limit.second.y; y += 1) { - BOOST_CHECK_EQUAL(nodes[at(limit.first.x, y)].height, -1.5F); - BOOST_CHECK_EQUAL(nodes[at(limit.second.x, y)].height, -1.5F); + BOOST_CHECK_EQUAL(nodes[at(limit.first.x, y)].height, -1500.F); + BOOST_CHECK_EQUAL(nodes[at(limit.second.x, y)].height, -1500.F); } } diff --git a/test/test-render.cpp b/test/test-render.cpp index b16f241..766bb74 100644 --- a/test/test-render.cpp +++ b/test/test-render.cpp @@ -26,7 +26,7 @@ class TestScene : public SceneProvider { std::shared_ptr train1, train2; Terrain terrain {[]() { - auto gd = std::make_shared(GeoData::Limits {{0, 0}, {100, 100}}); + auto gd = std::make_shared(GeoData::Limits {{0, 0}, {100, 100}}, 10000); gd->generateRandom(); return gd; }()}; @@ -35,11 +35,11 @@ public: TestScene() { train1 = std::make_shared(brush47rvc); - train1->location.setPosition({52, 50, 2}); + train1->location.setPosition({52000, 50000, 2000}); train1->bogies.front().setPosition(train1->bogies.front().position() + train1->location.position()); train1->bogies.back().setPosition(train1->bogies.back().position() + train1->location.position()); train2 = std::make_shared(brush47rvc); - train2->location.setPosition({52, 30, 2}); + train2->location.setPosition({52000, 30000, 2000}); train2->bogies.front().setPosition(train2->bogies.front().position() + train2->location.position()); train2->bogies.back().setPosition(train2->bogies.back().position() + train2->location.position()); } @@ -88,7 +88,7 @@ BOOST_FIXTURE_TEST_SUITE(w, TestRenderOutput); BOOST_AUTO_TEST_CASE(basic) { SceneRenderer ss {size, output}; - ss.camera.setView({-10, -10, 60}, glm::normalize(glm::vec3 {1, 1, -0.5F})); + ss.camera.setView({-10000, -10000, 60000}, glm::normalize(glm::vec3 {1, 1, -0.5F})); const TestScene scene; ss.render(scene); Texture::save(outImage, "/tmp/basic.tga"); @@ -97,7 +97,7 @@ BOOST_AUTO_TEST_CASE(basic) BOOST_AUTO_TEST_CASE(pointlight) { SceneRenderer ss {size, output}; - ss.camera.setView({-10, -10, 60}, glm::normalize(glm::vec3 {1, 1, -0.5F})); + ss.camera.setView({-10000, -10000, 60000}, glm::normalize(glm::vec3 {1, 1, -0.5F})); class PointLightScene : public TestScene { public: @@ -111,9 +111,9 @@ BOOST_AUTO_TEST_CASE(pointlight) void lights(const SceneShader & shader) const override { - for (int x = 50; x < 100; x += 20) { - for (int y = 50; y < 2000; y += 20) { - shader.pointLight.add({x, y, 4}, {1.0, 1.0, 1.0}, 0.1F); + for (int x = 50000; x < 100000; x += 20000) { + for (int y = 50000; y < 2000000; y += 20000) { + shader.pointLight.add({x, y, 4000}, {1.0, 1.0, 1.0}, 0.1F); } } } @@ -127,7 +127,7 @@ BOOST_AUTO_TEST_CASE(pointlight) BOOST_AUTO_TEST_CASE(spotlight) { SceneRenderer ss {size, output}; - ss.camera.setView({-10, -10, 60}, glm::normalize(glm::vec3 {1, 1, -0.5F})); + ss.camera.setView({-10000, -10000, 60000}, glm::normalize(glm::vec3 {1, 1, -0.5F})); class PointLightScene : public TestScene { public: @@ -141,10 +141,10 @@ BOOST_AUTO_TEST_CASE(spotlight) void lights(const SceneShader & shader) const override { - shader.spotLight.add({50, 50, 15}, down, {1.0, 1.0, 1.0}, 0.01F, 1); - shader.spotLight.add({51, 59.5, 1}, north, {1.0, 1.0, 1.0}, 0.001F, .5); - shader.spotLight.add({53, 59.5, 1}, north, {1.0, 1.0, 1.0}, 0.001F, .5); - shader.spotLight.add({60, 50, 3}, north + east, {1.0, 1.0, 1.0}, 0.0001F, .7F); + shader.spotLight.add({50000, 50000, 15000}, down, {1.0, 1.0, 1.0}, 0.01F, 1); + shader.spotLight.add({51000, 59500, 1000}, north, {1.0, 1.0, 1.0}, 0.001F, .5); + shader.spotLight.add({53000, 59500, 1000}, north, {1.0, 1.0, 1.0}, 0.001F, .5); + shader.spotLight.add({60000, 50000, 3000}, north + east, {1.0, 1.0, 1.0}, 0.0001F, .7F); } }; diff --git a/ui/gameMainWindow.cpp b/ui/gameMainWindow.cpp index 15f1e07..7cf143a 100644 --- a/ui/gameMainWindow.cpp +++ b/ui/gameMainWindow.cpp @@ -31,7 +31,7 @@ public: GameMainWindow::GameMainWindow(size_t w, size_t h) : Window {w, h, "I Like Trains", SDL_WINDOW_OPENGL}, SceneRenderer {Window::size, 0} { - uiComponents.create(Position2D {-1150, -1150}); + uiComponents.create(Position2D {-1150000, -1150000}); auto gms = uiComponents.create(&camera, ScreenAbsCoord {w, h}); uiComponents.create(gms.get()); } diff --git a/ui/manualCameraController.cpp b/ui/manualCameraController.cpp index 05c1fc5..f6993a8 100644 --- a/ui/manualCameraController.cpp +++ b/ui/manualCameraController.cpp @@ -59,12 +59,12 @@ ManualCameraController::handleInput(const SDL_Event & e, const Position &) pitch = std::clamp(pitch - 0.01F * static_cast(e.motion.yrel), 0.1F, half_pi); } else { - focus += rotate_flat(-direction) * Position2D {-e.motion.xrel, e.motion.yrel}; + focus += rotate_flat(-direction) * (Position2D {-e.motion.xrel, e.motion.yrel} * dist / 2.0F); } } return true; case SDL_MOUSEWHEEL: - dist = std::clamp(dist - static_cast(e.wheel.y) * 4.F, 5.F, 200.F); + dist = std::clamp(dist - static_cast(e.wheel.y) * 400.F, 5.F, 200000.F); break; } return false; diff --git a/ui/manualCameraController.h b/ui/manualCameraController.h index 46655bc..1efaee1 100644 --- a/ui/manualCameraController.h +++ b/ui/manualCameraController.h @@ -22,5 +22,5 @@ private: bool ctrl {false}, mrb {false}; Position2D focus; float direction {quarter_pi}; - float dist {40}, pitch {quarter_pi}; + float dist {4000}, pitch {quarter_pi}; }; -- cgit v1.2.3 From 9bbaa4df842bf350a5d05233140bb4d631212a11 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 25 Nov 2023 13:57:33 +0000 Subject: Send position and rotation matrix to GPU separately in basic program Missed from earlier commit --- gfx/gl/sceneShader.cpp | 9 ++++++--- gfx/gl/sceneShader.h | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/gfx/gl/sceneShader.cpp b/gfx/gl/sceneShader.cpp index 2f391fd..de75814 100644 --- a/gfx/gl/sceneShader.cpp +++ b/gfx/gl/sceneShader.cpp @@ -60,13 +60,16 @@ SceneShader::SceneProgram::setViewPort(const ViewPort & viewPort) const } } -SceneShader::BasicProgram::BasicProgram() : SceneProgram {dynamicPoint_vs, material_fs}, modelLoc {*this, "model"} { } +SceneShader::BasicProgram::BasicProgram() : + SceneProgram {dynamicPoint_vs, material_fs}, modelLoc {*this, "model"}, modelPosLoc {*this, "modelPos"} +{ +} void SceneShader::BasicProgram::setModel(Location const & location) const { - const auto model {glm::translate(location.pos) * rotate_ypr(location.rot)}; - glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); + glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(rotate_ypr(location.rot))); + glUniform3fv(modelPosLoc, 1, glm::value_ptr(location.pos)); } void diff --git a/gfx/gl/sceneShader.h b/gfx/gl/sceneShader.h index 154dc17..83c234c 100644 --- a/gfx/gl/sceneShader.h +++ b/gfx/gl/sceneShader.h @@ -32,6 +32,7 @@ class SceneShader { private: RequiredUniformLocation modelLoc; + RequiredUniformLocation modelPosLoc; }; class AbsolutePosProgram : public SceneProgram { -- cgit v1.2.3 From 4c4328d6091ff467fd590c1cc1dc9435c920f6a7 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 25 Nov 2023 14:08:02 +0000 Subject: Spread the trees out --- application/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/main.cpp b/application/main.cpp index 01e6561..e4e71c7 100644 --- a/application/main.cpp +++ b/application/main.cpp @@ -80,8 +80,8 @@ public: train->currentActivity = train->orders.current()->createActivity(); auto foliage = std::dynamic_pointer_cast(assets.at("Tree-01-1")); - for (float x = 900000; x < 1100000; x += 3000) { - for (float y = 900000; y < 1100000; y += 3000) { + for (float x = 900000; x < 1100000; x += 5000) { + for (float y = 900000; y < 1100000; y += 5000) { world.create(foliage, Location {geoData->positionAt({-x, -y})}); } } -- cgit v1.2.3 From 916fafa028b0bc8c8b0abec8c072722907d85f43 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 25 Nov 2023 14:08:45 +0000 Subject: Send position and rotation matrix to GPU separately in shadowmapper dynamic --- gfx/gl/shadowMapper.cpp | 9 ++++----- gfx/gl/shadowMapper.h | 1 + 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/gfx/gl/shadowMapper.cpp b/gfx/gl/shadowMapper.cpp index 190f20e..4a8d7ec 100644 --- a/gfx/gl/shadowMapper.cpp +++ b/gfx/gl/shadowMapper.cpp @@ -179,7 +179,8 @@ ShadowMapper::FixedPoint::use() const } ShadowMapper::DynamicPoint::DynamicPoint() : - Program {shadowDynamicPoint_vs}, viewProjectionLoc {*this, "viewProjection"}, modelLoc {*this, "model"} + Program {shadowDynamicPoint_vs}, viewProjectionLoc {*this, "viewProjection"}, modelLoc {*this, "model"}, + modelPosLoc {*this, "modelPos"} { } @@ -195,13 +196,11 @@ ShadowMapper::DynamicPoint::use(const Location & location) const { glUseProgram(*this); setModel(location); - const auto model = glm::translate(location.pos) * rotate_ypr(location.rot); - glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); } void ShadowMapper::DynamicPoint::setModel(const Location & location) const { - const auto model = glm::translate(location.pos) * rotate_ypr(location.rot); - glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); + glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(rotate_ypr(location.rot))); + glUniform3fv(modelPosLoc, 1, glm::value_ptr(location.pos)); } diff --git a/gfx/gl/shadowMapper.h b/gfx/gl/shadowMapper.h index d54734c..b53a7f1 100644 --- a/gfx/gl/shadowMapper.h +++ b/gfx/gl/shadowMapper.h @@ -44,6 +44,7 @@ public: private: RequiredUniformLocation viewProjectionLoc; RequiredUniformLocation modelLoc; + RequiredUniformLocation modelPosLoc; }; FixedPoint fixedPoint, dynamicPointInst; -- cgit v1.2.3 From 3200eb41d60595813dca751fe15193ba0b44dddf Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 25 Nov 2023 14:32:56 +0000 Subject: Remove getTransform --- game/vehicles/railVehicle.cpp | 18 +++++++++--------- gfx/gl/bufferedLocation.cpp | 6 ------ gfx/gl/bufferedLocation.h | 1 - lib/location.cpp | 6 ------ lib/location.h | 1 - 5 files changed, 9 insertions(+), 23 deletions(-) diff --git a/game/vehicles/railVehicle.cpp b/game/vehicles/railVehicle.cpp index 26536f5..bee0dd0 100644 --- a/game/vehicles/railVehicle.cpp +++ b/game/vehicles/railVehicle.cpp @@ -49,16 +49,16 @@ RailVehicle::intersectRay(const Ray & ray, Position2D * baryPos, float * distanc constexpr const auto X = 1350.F; const auto Y = this->rvClass->length / 2.F; constexpr const auto Z = 3900.F; - const auto moveBy = location.getTransform(); + const auto moveBy = location.getRotationTransform(); const std::array cornerVertices {{ - moveBy * glm::vec4 {-X, Y, 0, 1}, // LFB - moveBy * glm::vec4 {X, Y, 0, 1}, // RFB - moveBy * glm::vec4 {-X, Y, Z, 1}, // LFT - moveBy * glm::vec4 {X, Y, Z, 1}, // RFT - moveBy * glm::vec4 {-X, -Y, 0, 1}, // LBB - moveBy * glm::vec4 {X, -Y, 0, 1}, // RBB - moveBy * glm::vec4 {-X, -Y, Z, 1}, // LBT - moveBy * glm::vec4 {X, -Y, Z, 1}, // RBT + location.position() + (moveBy * glm::vec4 {-X, Y, 0, 1}).xyz(), // LFB + location.position() + (moveBy * glm::vec4 {X, Y, 0, 1}).xyz(), // RFB + location.position() + (moveBy * glm::vec4 {-X, Y, Z, 1}).xyz(), // LFT + location.position() + (moveBy * glm::vec4 {X, Y, Z, 1}).xyz(), // RFT + location.position() + (moveBy * glm::vec4 {-X, -Y, 0, 1}).xyz(), // LBB + location.position() + (moveBy * glm::vec4 {X, -Y, 0, 1}).xyz(), // RBB + location.position() + (moveBy * glm::vec4 {-X, -Y, Z, 1}).xyz(), // LBT + location.position() + (moveBy * glm::vec4 {X, -Y, Z, 1}).xyz(), // RBT }}; static constexpr const std::array, 10> triangles {{ // Front diff --git a/gfx/gl/bufferedLocation.cpp b/gfx/gl/bufferedLocation.cpp index 412e3ab..2a2e723 100644 --- a/gfx/gl/bufferedLocation.cpp +++ b/gfx/gl/bufferedLocation.cpp @@ -57,12 +57,6 @@ BufferedLocation::setLocation(Position3D p, Rotation3D r) updateBuffer(); } -glm::mat4 -BufferedLocation::getTransform() const -{ - return loc.getTransform(); -} - glm::mat4 BufferedLocation::getRotationTransform() const { diff --git a/gfx/gl/bufferedLocation.h b/gfx/gl/bufferedLocation.h index a5cd23e..30967e3 100644 --- a/gfx/gl/bufferedLocation.h +++ b/gfx/gl/bufferedLocation.h @@ -22,7 +22,6 @@ public: void setRotation(Rotation3D, bool update = true); void setLocation(Position3D, Rotation3D); - [[nodiscard]] glm::mat4 getTransform() const; [[nodiscard]] glm::mat4 getRotationTransform() const; private: diff --git a/lib/location.cpp b/lib/location.cpp index 9a31402..ff7cfa6 100644 --- a/lib/location.cpp +++ b/lib/location.cpp @@ -2,12 +2,6 @@ #include "maths.h" #include -glm::mat4 -Location::getTransform() const -{ - return glm::translate(pos) * rotate_ypr(rot); -} - glm::mat4 Location::getRotationTransform() const { diff --git a/lib/location.h b/lib/location.h index 55737ae..85834a0 100644 --- a/lib/location.h +++ b/lib/location.h @@ -9,7 +9,6 @@ public: explicit Location(Position3D pos = {}, Rotation3D rot = {}) : pos {pos}, rot {rot} { } #endif - [[nodiscard]] glm::mat4 getTransform() const; [[nodiscard]] glm::mat4 getRotationTransform() const; Position3D pos; -- cgit v1.2.3 From 0aa665c3648d788755b00c9e431c872d57fddbb8 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 25 Nov 2023 16:28:39 +0000 Subject: Model positions as integers Introduces test failure in arcs due to rounding, but I don't want to create a complicated fix as link positions are still floats and hopefully that'll go away... somehow --- config/types.h | 19 +++++++++++++++---- game/geoData.cpp | 4 ++-- game/scenary/foliage.h | 2 +- game/vehicles/railVehicle.cpp | 22 +++++++++++----------- game/vehicles/railVehicleClass.h | 2 +- gfx/followCameraController.cpp | 4 ++-- gfx/gl/bufferedLocation.cpp | 8 ++++---- gfx/gl/bufferedLocation.h | 8 ++++---- gfx/gl/sceneShader.cpp | 2 +- gfx/gl/shaders/dynamicPoint.vs | 2 +- gfx/gl/shaders/dynamicPointInst.vs | 2 +- gfx/gl/shaders/fixedPoint.vs | 2 +- gfx/gl/shaders/shadowDynamicPoint.vs | 2 +- gfx/gl/shaders/shadowDynamicPointInst.vs | 2 +- gfx/gl/shaders/shadowFixedPoint.vs | 2 +- gfx/gl/shadowMapper.cpp | 2 +- lib/location.h | 4 ++-- test/test-maths.cpp | 12 ++++++------ 18 files changed, 56 insertions(+), 45 deletions(-) diff --git a/config/types.h b/config/types.h index d99735e..6fc7b61 100644 --- a/config/types.h +++ b/config/types.h @@ -3,10 +3,14 @@ #include "glad/gl.h" #include -using Distance = float; +using Distance = float; // deprecate +using RelativeDistance = float; +using GlobalDistance = int32_t; using Angle = float; -template using Position = glm::vec; +template using Position = glm::vec; // deprecate +template using RelativePosition = glm::vec; +template using GlobalPosition = glm::vec; template using Size = glm::vec; template using Scale = glm::vec; template using Direction = glm::vec; @@ -14,8 +18,15 @@ template using Normal = Direction; template using Rotation = glm::vec; template using Colour = glm::vec; -using Position2D = Position<2>; -using Position3D = Position<3>; +using Position2D = Position<2>; // deprecate +using Position3D = Position<3>; // deprecate +using BaryPosition = glm::vec<2, float>; +using RelativePosition2D = RelativePosition<2>; +using RelativePosition3D = RelativePosition<3>; +using RelativePosition4D = RelativePosition<4>; +using GlobalPosition2D = GlobalPosition<2>; +using GlobalPosition3D = GlobalPosition<3>; +using GlobalPosition4D = GlobalPosition<4>; using Size2D = Size<2>; using Size3D = Size<3>; using Scale2D = Scale<2>; diff --git a/game/geoData.cpp b/game/geoData.cpp index da067f7..ec990ea 100644 --- a/game/geoData.cpp +++ b/game/geoData.cpp @@ -73,7 +73,7 @@ GeoData::loadFromImages(const std::filesystem::path & fileName, float scale_) } GeoData::Quad -GeoData::quad(glm::vec2 wcoord) const +GeoData::quad(Position2D wcoord) const { constexpr static const std::array corners {{{0, 0}, {0, 1}, {1, 0}, {1, 1}}}; return transform_array(transform_array(corners, @@ -154,7 +154,7 @@ GeoData::intersectRay(const Ray & ray) const try { const auto point = quad(n); for (auto offset : {0U, 1U}) { - glm::vec2 bary; + BaryPosition bary; float distance; if (glm::intersectRayTriangle(ray.start, ray.direction, point[offset], point[offset + 1], point[offset + 2], bary, distance)) { diff --git a/game/scenary/foliage.h b/game/scenary/foliage.h index 5a9d2de..bbb6200 100644 --- a/game/scenary/foliage.h +++ b/game/scenary/foliage.h @@ -15,7 +15,7 @@ class Foliage : public Asset, public Renderable, public StdTypeDefs { glVertexArray instanceVAO; public: - using LocationVertex = std::pair; + using LocationVertex = std::pair; mutable InstanceVertices instances; void render(const SceneShader &) const override; void shadows(const ShadowMapper &) const override; diff --git a/game/vehicles/railVehicle.cpp b/game/vehicles/railVehicle.cpp index bee0dd0..30b615c 100644 --- a/game/vehicles/railVehicle.cpp +++ b/game/vehicles/railVehicle.cpp @@ -38,9 +38,9 @@ RailVehicle::move(const Train * t, float & trailBy) const auto overhang {(rvClass->length - rvClass->wheelBase) / 2}; const auto & b1Pos = bogies[0] = t->getBogiePosition(t->linkDist, trailBy += overhang); const auto & b2Pos = bogies[1] = t->getBogiePosition(t->linkDist, trailBy += rvClass->wheelBase); - const auto diff = glm::normalize(b2Pos.position() - b1Pos.position()); - location.setLocation((b1Pos.position() + b2Pos.position()) / 2.F, {vector_pitch(diff), vector_yaw(diff), 0}); - trailBy += 0.6F + overhang; + const auto diff = glm::normalize(RelativePosition3D(b2Pos.position() - b1Pos.position())); + location.setLocation((b1Pos.position() + b2Pos.position()) / 2, {vector_pitch(diff), vector_yaw(diff), 0}); + trailBy += 600.F + overhang; } bool @@ -51,14 +51,14 @@ RailVehicle::intersectRay(const Ray & ray, Position2D * baryPos, float * distanc constexpr const auto Z = 3900.F; const auto moveBy = location.getRotationTransform(); const std::array cornerVertices {{ - location.position() + (moveBy * glm::vec4 {-X, Y, 0, 1}).xyz(), // LFB - location.position() + (moveBy * glm::vec4 {X, Y, 0, 1}).xyz(), // RFB - location.position() + (moveBy * glm::vec4 {-X, Y, Z, 1}).xyz(), // LFT - location.position() + (moveBy * glm::vec4 {X, Y, Z, 1}).xyz(), // RFT - location.position() + (moveBy * glm::vec4 {-X, -Y, 0, 1}).xyz(), // LBB - location.position() + (moveBy * glm::vec4 {X, -Y, 0, 1}).xyz(), // RBB - location.position() + (moveBy * glm::vec4 {-X, -Y, Z, 1}).xyz(), // LBT - location.position() + (moveBy * glm::vec4 {X, -Y, Z, 1}).xyz(), // RBT + location.position() + GlobalPosition3D(moveBy * glm::vec4 {-X, Y, 0, 1}).xyz(), // LFB + location.position() + GlobalPosition3D(moveBy * glm::vec4 {X, Y, 0, 1}).xyz(), // RFB + location.position() + GlobalPosition3D(moveBy * glm::vec4 {-X, Y, Z, 1}).xyz(), // LFT + location.position() + GlobalPosition3D(moveBy * glm::vec4 {X, Y, Z, 1}).xyz(), // RFT + location.position() + GlobalPosition3D(moveBy * glm::vec4 {-X, -Y, 0, 1}).xyz(), // LBB + location.position() + GlobalPosition3D(moveBy * glm::vec4 {X, -Y, 0, 1}).xyz(), // RBB + location.position() + GlobalPosition3D(moveBy * glm::vec4 {-X, -Y, Z, 1}).xyz(), // LBT + location.position() + GlobalPosition3D(moveBy * glm::vec4 {X, -Y, Z, 1}).xyz(), // RBT }}; static constexpr const std::array, 10> triangles {{ // Front diff --git a/game/vehicles/railVehicleClass.h b/game/vehicles/railVehicleClass.h index 16dce01..913feea 100644 --- a/game/vehicles/railVehicleClass.h +++ b/game/vehicles/railVehicleClass.h @@ -20,7 +20,7 @@ public: struct LocationVertex { glm::mat4 body, front, back; - Position3D bodyPos, frontPos, backPos; + GlobalPosition3D bodyPos, frontPos, backPos; }; std::array bogies; diff --git a/gfx/followCameraController.cpp b/gfx/followCameraController.cpp index 5b08483..aee2187 100644 --- a/gfx/followCameraController.cpp +++ b/gfx/followCameraController.cpp @@ -24,11 +24,11 @@ FollowCameraController::updateCamera(Camera * camera) const break; case Mode::Ride: - camera->setView(pos + (up * 4.8F), !-sincosf(rot.y)); + camera->setView(pos + GlobalPosition3D(up * 4.8F), !-sincosf(rot.y)); break; case Mode::ISO: - camera->setView(pos + ((up + north + east) * 40.F), glm::normalize(down + south + west), + camera->setView(pos + GlobalPosition3D((up + north + east) * 40.F), glm::normalize(down + south + west), glm::normalize(up - north - east)); break; } diff --git a/gfx/gl/bufferedLocation.cpp b/gfx/gl/bufferedLocation.cpp index 2a2e723..d6a63b9 100644 --- a/gfx/gl/bufferedLocation.cpp +++ b/gfx/gl/bufferedLocation.cpp @@ -2,7 +2,7 @@ #include "location.h" #include -BufferedLocation::BufferedLocation(Position3D p, Rotation3D r) : BufferedLocation {Location {p, r}} { } +BufferedLocation::BufferedLocation(GlobalPosition3D p, Rotation3D r) : BufferedLocation {Location {p, r}} { } BufferedLocation::BufferedLocation(const Location & l) : loc {l} { } @@ -19,7 +19,7 @@ BufferedLocation::operator=(const Location & l) return *this; } -Position3D +GlobalPosition3D BufferedLocation::position() const { return loc.pos; @@ -32,7 +32,7 @@ BufferedLocation::rotation() const } void -BufferedLocation::setPosition(Position3D p, bool update) +BufferedLocation::setPosition(GlobalPosition3D p, bool update) { loc.pos = p; if (update) { @@ -50,7 +50,7 @@ BufferedLocation::setRotation(Position3D r, bool update) } void -BufferedLocation::setLocation(Position3D p, Rotation3D r) +BufferedLocation::setLocation(GlobalPosition3D p, Rotation3D r) { loc.pos = p; loc.rot = r; diff --git a/gfx/gl/bufferedLocation.h b/gfx/gl/bufferedLocation.h index 30967e3..87b957f 100644 --- a/gfx/gl/bufferedLocation.h +++ b/gfx/gl/bufferedLocation.h @@ -8,7 +8,7 @@ class BufferedLocation { public: - BufferedLocation(Position3D = {}, Rotation3D = {}); + BufferedLocation(GlobalPosition3D = {}, Rotation3D = {}); BufferedLocation(const Location &); virtual ~BufferedLocation() = default; @@ -16,11 +16,11 @@ public: operator const Location &() const; - [[nodiscard]] Position3D position() const; + [[nodiscard]] GlobalPosition3D position() const; [[nodiscard]] Rotation3D rotation() const; - void setPosition(Position3D, bool update = true); + void setPosition(GlobalPosition3D, bool update = true); void setRotation(Rotation3D, bool update = true); - void setLocation(Position3D, Rotation3D); + void setLocation(GlobalPosition3D, Rotation3D); [[nodiscard]] glm::mat4 getRotationTransform() const; diff --git a/gfx/gl/sceneShader.cpp b/gfx/gl/sceneShader.cpp index de75814..59a9748 100644 --- a/gfx/gl/sceneShader.cpp +++ b/gfx/gl/sceneShader.cpp @@ -69,7 +69,7 @@ void SceneShader::BasicProgram::setModel(Location const & location) const { glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(rotate_ypr(location.rot))); - glUniform3fv(modelPosLoc, 1, glm::value_ptr(location.pos)); + glUniform3iv(modelPosLoc, 1, glm::value_ptr(location.pos)); } void diff --git a/gfx/gl/shaders/dynamicPoint.vs b/gfx/gl/shaders/dynamicPoint.vs index 9dd6a47..667f247 100644 --- a/gfx/gl/shaders/dynamicPoint.vs +++ b/gfx/gl/shaders/dynamicPoint.vs @@ -7,6 +7,6 @@ include(`materialInterface.glsl') uniform mat4 viewProjection; uniform vec3 viewPoint; uniform mat4 model; -uniform vec3 modelPos; +uniform ivec3 modelPos; include(`commonPoint.glsl') diff --git a/gfx/gl/shaders/dynamicPointInst.vs b/gfx/gl/shaders/dynamicPointInst.vs index 4ae6813..adf39bd 100644 --- a/gfx/gl/shaders/dynamicPointInst.vs +++ b/gfx/gl/shaders/dynamicPointInst.vs @@ -7,6 +7,6 @@ include(`materialInterface.glsl') uniform mat4 viewProjection; uniform vec3 viewPoint; layout(location = 5) in mat4 model; -layout(location = 9) in vec3 modelPos; +layout(location = 9) in ivec3 modelPos; include(`commonPoint.glsl') diff --git a/gfx/gl/shaders/fixedPoint.vs b/gfx/gl/shaders/fixedPoint.vs index 0adbb02..6e1ab49 100644 --- a/gfx/gl/shaders/fixedPoint.vs +++ b/gfx/gl/shaders/fixedPoint.vs @@ -7,6 +7,6 @@ include(`materialInterface.glsl') uniform mat4 viewProjection; uniform vec3 viewPoint; const mat4 model = mat4(1); -const vec3 modelPos = vec3(0); +const vec3 modelPos = ivec3(0); include(`commonPoint.glsl') diff --git a/gfx/gl/shaders/shadowDynamicPoint.vs b/gfx/gl/shaders/shadowDynamicPoint.vs index eb25423..e20d31a 100644 --- a/gfx/gl/shaders/shadowDynamicPoint.vs +++ b/gfx/gl/shaders/shadowDynamicPoint.vs @@ -5,6 +5,6 @@ include(`meshIn.glsl') uniform mat4 viewProjection; uniform vec3 viewPoint; uniform mat4 model; -uniform vec3 modelPos; +uniform ivec3 modelPos; include(`commonShadowPoint.glsl') diff --git a/gfx/gl/shaders/shadowDynamicPointInst.vs b/gfx/gl/shaders/shadowDynamicPointInst.vs index a0f51c3..ab3e976 100644 --- a/gfx/gl/shaders/shadowDynamicPointInst.vs +++ b/gfx/gl/shaders/shadowDynamicPointInst.vs @@ -5,6 +5,6 @@ include(`meshIn.glsl') uniform mat4 viewProjection; uniform vec3 viewPoint; layout(location = 5) in mat4 model; -layout(location = 9) in vec3 modelPos; +layout(location = 9) in ivec3 modelPos; include(`commonShadowPoint.glsl') diff --git a/gfx/gl/shaders/shadowFixedPoint.vs b/gfx/gl/shaders/shadowFixedPoint.vs index dfc5c42..a9fb4a3 100644 --- a/gfx/gl/shaders/shadowFixedPoint.vs +++ b/gfx/gl/shaders/shadowFixedPoint.vs @@ -5,6 +5,6 @@ include(`meshIn.glsl') uniform mat4 viewProjection; uniform vec3 viewPoint; const mat4 model = mat4(1); -const vec3 modelPos = vec3(0); +const ivec3 modelPos = ivec3(0); include(`commonShadowPoint.glsl') diff --git a/gfx/gl/shadowMapper.cpp b/gfx/gl/shadowMapper.cpp index 4a8d7ec..07db6a1 100644 --- a/gfx/gl/shadowMapper.cpp +++ b/gfx/gl/shadowMapper.cpp @@ -202,5 +202,5 @@ void ShadowMapper::DynamicPoint::setModel(const Location & location) const { glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(rotate_ypr(location.rot))); - glUniform3fv(modelPosLoc, 1, glm::value_ptr(location.pos)); + glUniform3iv(modelPosLoc, 1, glm::value_ptr(location.pos)); } diff --git a/lib/location.h b/lib/location.h index 85834a0..8570fc2 100644 --- a/lib/location.h +++ b/lib/location.h @@ -6,11 +6,11 @@ class Location { public: #ifndef __cpp_aggregate_paren_init - explicit Location(Position3D pos = {}, Rotation3D rot = {}) : pos {pos}, rot {rot} { } + explicit Location(GlobalPosition3D pos = {}, Rotation3D rot = {}) : pos {pos}, rot {rot} { } #endif [[nodiscard]] glm::mat4 getRotationTransform() const; - Position3D pos; + GlobalPosition3D pos; Rotation3D rot; }; diff --git a/test/test-maths.cpp b/test/test-maths.cpp index 2560319..9eae918 100644 --- a/test/test-maths.cpp +++ b/test/test-maths.cpp @@ -196,12 +196,12 @@ BOOST_DATA_TEST_CASE(straight1, const TestLinkStraight l(v); { const auto p = l.positionAt(0, 0); - BOOST_CHECK_EQUAL(p.pos, origin); + BOOST_CHECK_EQUAL(p.pos, GlobalPosition3D {origin}); BOOST_CHECK_EQUAL(p.rot, glm::vec3(0, angFor, 0)); } { const auto p = l.positionAt(0, 1); - BOOST_CHECK_EQUAL(p.pos, v); + BOOST_CHECK_EQUAL(p.pos, GlobalPosition3D {v}); BOOST_CHECK_EQUAL(p.rot, glm::vec3(0, angBack, 0)); } } @@ -231,12 +231,12 @@ BOOST_DATA_TEST_CASE(curve1, BOOST_CHECK_EQUAL(l.radius, 1.F); { const auto p = l.positionAt(0, 0); - BOOST_CHECK_CLOSE_VEC(p.pos, origin); + BOOST_CHECK_CLOSE_VEC(RelativePosition3D {p.pos}, origin); BOOST_CHECK_CLOSE_VEC(p.rot, glm::vec3(0, angFor, 0)); } { const auto p = l.positionAt(0, 1); - BOOST_CHECK_CLOSE_VEC(p.pos, e1); + BOOST_CHECK_CLOSE_VEC(RelativePosition3D {p.pos}, e1); BOOST_CHECK_CLOSE_VEC(p.rot, glm::vec3(0, angBack, 0)); } } @@ -247,13 +247,13 @@ BOOST_DATA_TEST_CASE(curve1, { const auto p = l.positionAt(0, 0); const auto angForReversed = normalize(vector_yaw(origin - e1) * 2 - angFor); - BOOST_CHECK_CLOSE_VEC(p.pos, e1); + BOOST_CHECK_CLOSE_VEC(RelativePosition3D {p.pos}, e1); BOOST_CHECK_CLOSE_VEC(p.rot, glm::vec3(0, angForReversed, 0)); } { const auto p = l.positionAt(0, 1); const auto angBackReversed = normalize(vector_yaw(e1 - origin) * 2 - angBack); - BOOST_CHECK_CLOSE_VEC(p.pos, origin); + BOOST_CHECK_CLOSE_VEC(RelativePosition3D {p.pos}, origin); BOOST_CHECK_CLOSE_VEC(p.rot, glm::vec3(0, angBackReversed, 0)); } } -- cgit v1.2.3 From 3abe940a22d99939b666bd806214c8b986cb3ed9 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 26 Nov 2023 14:20:28 +0000 Subject: Calculate vertex normals only Doesn't require half edge normals or face normals, which uses Newell's method, which results in integer overflow... Not to mention we don't need all the other normals. --- game/geoData.cpp | 16 ++++++++++++---- game/geoData.h | 6 ++++-- test/test-geoData.cpp | 5 ----- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/game/geoData.cpp b/game/geoData.cpp index 7710efe..70133a9 100644 --- a/game/geoData.cpp +++ b/game/geoData.cpp @@ -57,8 +57,7 @@ GeoData::loadFromAsciiGrid(const std::filesystem::path & input) }); } } - mesh.update_face_normals(); - mesh.update_vertex_normals(); + mesh.update_vertex_normals_only(); return mesh; }; @@ -77,8 +76,7 @@ GeoData::createFlat(GlobalPosition2D lower, GlobalPosition2D upper, GlobalDistan mesh.add_face(ll, uu, lu); mesh.add_face(ll, ul, uu); - mesh.update_face_normals(); - mesh.update_vertex_normals(); + mesh.update_vertex_normals_only(); return mesh; } @@ -317,3 +315,13 @@ GeoData::findBoundaryStart() const return is_boundary(heh); }); } + +void +GeoData::update_vertex_normals_only() +{ + for (auto vh : all_vertices()) { + Normal3D n; + calc_vertex_normal_correct(vh, n); + this->set_normal(vh, glm::normalize(n)); + } +} diff --git a/game/geoData.h b/game/geoData.h index 3141dbe..d4d0fb3 100644 --- a/game/geoData.h +++ b/game/geoData.h @@ -10,10 +10,10 @@ #include struct GeoDataTraits : public OpenMesh::DefaultTraits { - FaceAttributes(OpenMesh::Attributes::Normal | OpenMesh::Attributes::Status); + FaceAttributes(OpenMesh::Attributes::Status); EdgeAttributes(OpenMesh::Attributes::Status); VertexAttributes(OpenMesh::Attributes::Normal | OpenMesh::Attributes::Status); - HalfedgeAttributes(OpenMesh::Attributes::Normal | OpenMesh::Attributes::Status); + HalfedgeAttributes(OpenMesh::Attributes::Status); using Point = GlobalPosition3D; using Normal = Normal3D; }; @@ -105,6 +105,8 @@ protected: [[nodiscard]] bool triangleContainsPoint(const GlobalPosition2D, FaceHandle) const; [[nodiscard]] HalfedgeHandle findBoundaryStart() const; + void update_vertex_normals_only(); + private: GlobalPosition3D lowerExtent {}, upperExtent {}; }; diff --git a/test/test-geoData.cpp b/test/test-geoData.cpp index 4e85f73..cb0466e 100644 --- a/test/test-geoData.cpp +++ b/test/test-geoData.cpp @@ -26,11 +26,6 @@ BOOST_AUTO_TEST_CASE(loadSuccess) BOOST_AUTO_TEST_CASE(normalsAllPointUp) { - BOOST_CHECK_EQUAL(std::count_if(faces_begin(), faces_end(), - [this](auto && vh) { - return normal(vh).z > 0; - }), - n_faces()); BOOST_CHECK_EQUAL(std::count_if(vertices_begin(), vertices_end(), [this](auto && vh) { return normal(vh).z > 0; -- cgit v1.2.3 From 0c97f72d6f3feab22a37f8d33e2d98080d52dab7 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 26 Nov 2023 18:50:56 +0000 Subject: Fix terrain texture tiling --- game/terrain.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/game/terrain.cpp b/game/terrain.cpp index 5bb8abd..3778f3d 100644 --- a/game/terrain.cpp +++ b/game/terrain.cpp @@ -35,8 +35,8 @@ Terrain::generateMeshes() std::transform(geoData->vertices_begin(), geoData->vertices_end(), std::back_inserter(vertices), [this, &vertexIndex](const GeoData::VertexHandle v) { vertexIndex.emplace(v, vertexIndex.size()); - const glm::vec3 p = geoData->point(v); - return Vertex {p, p / 10.F, geoData->normal(v)}; + const auto p = geoData->point(v); + return Vertex {p, p / 10000, geoData->normal(v)}; }); std::for_each( geoData->faces_begin(), geoData->faces_end(), [this, &vertexIndex, &indices](const GeoData::FaceHandle f) { -- cgit v1.2.3 From 8b5dc3a7faaf0e00135f30ddf96fd4d0cdac324e Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 26 Nov 2023 19:02:17 +0000 Subject: Restore some trees --- application/main.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/application/main.cpp b/application/main.cpp index 5db2539..600bbe3 100644 --- a/application/main.cpp +++ b/application/main.cpp @@ -78,12 +78,12 @@ public: &train->orders, l3->ends[1], l3->length, rl->findNodeAt({-1100000, -450000, 15000})); train->currentActivity = train->orders.current()->createActivity(); - // auto foliage = std::dynamic_pointer_cast(assets.at("Tree-01-1")); - // for (float x = 900000; x < 1100000; x += 5000) { - // for (float y = 900000; y < 1100000; y += 5000) { - // world.create(foliage, Location {geoData->positionAt({{-x, -y}})}); - //} - //} + auto foliage = std::dynamic_pointer_cast(assets.at("Tree-01-1")); + for (auto x = 311000000; x < 311830000; x += 5000) { + for (auto y = 491100000; y < 491130000; y += 5000) { + world.create(foliage, Location {geoData->positionAt({{x, y}})}); + } + } } auto t_start = std::chrono::high_resolution_clock::now(); -- cgit v1.2.3 From 0a5d23ce263551bab3759e4ac65ecb6cfebdc892 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 2 Dec 2023 12:23:52 +0000 Subject: Add crossInt - cross product for integer vectors --- lib/maths.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/maths.h b/lib/maths.h index 67b2a15..cf369a7 100644 --- a/lib/maths.h +++ b/lib/maths.h @@ -67,6 +67,17 @@ sq(T v) return v * v; } +template +inline constexpr glm::vec<3, T, Q> +crossInt(const glm::vec<3, T, Q> a, const glm::vec<3, T, Q> b) +{ + return { + (a.y * b.z) - (a.z * b.y), + (a.z * b.x) - (a.x * b.z), + (a.x * b.y) - (a.y * b.x), + }; +} + template inline constexpr auto ratio(Ta a, Tb b) -- cgit v1.2.3 From 0f56b13766fc6d8b45dabc4febf378756620ab32 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 2 Dec 2023 12:26:36 +0000 Subject: Replace positionAt with pure integer version --- game/geoData.cpp | 15 +++++++++++---- test/test-geoData.cpp | 2 +- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/game/geoData.cpp b/game/geoData.cpp index 70133a9..d092d00 100644 --- a/game/geoData.cpp +++ b/game/geoData.cpp @@ -155,6 +155,16 @@ namespace { static_assert(linesCrossLtR({1, 1}, {2, 2}, {1, 2}, {2, 1})); static_assert(!linesCrossLtR({2, 2}, {1, 1}, {1, 2}, {2, 1})); + + constexpr GlobalPosition3D + positionOnTriangle(const GlobalPosition2D point, const GeoData::Triangle<3> & t) + { + const glm::vec<3, int64_t> a = t[1] - t[0], b = t[2] - t[0]; + const auto n = crossInt(a, b); + return {point, ((n.x * t[0].x) + (n.y * t[0].y) + (n.z * t[0].z) - (n.x * point.x) - (n.y * point.y)) / n.z}; + } + + static_assert(positionOnTriangle({7, -2}, {{1, 2, 3}, {1, 0, 1}, {-2, 1, 0}}) == GlobalPosition3D {7, -2, 3}); } OpenMesh::FaceHandle @@ -179,10 +189,7 @@ GeoData::findPoint(GlobalPosition2D p, OpenMesh::FaceHandle f) const GlobalPosition3D GeoData::positionAt(const PointFace & p) const { - RelativePosition3D out {}; - const auto t = triangle<3>(p.face(this)); - glm::intersectLineTriangle({p.point, 0}, up, t[0], t[1], t[2], out); - return {p.point, out[0]}; + return positionOnTriangle(p.point, triangle<3>(p.face(this))); } [[nodiscard]] std::optional diff --git a/test/test-geoData.cpp b/test/test-geoData.cpp index cb0466e..164a6a5 100644 --- a/test/test-geoData.cpp +++ b/test/test-geoData.cpp @@ -92,7 +92,7 @@ BOOST_DATA_TEST_CASE(findPositionAt, {{310050000, 490050000}, 33000}, {{310000000, 490050000}, 32700}, {{310050000, 490000000}, 33200}, - {{310750000, 490150000}, 58399}, + {{310750000, 490150000}, 58400}, // midpoints {{310025000, 490025000}, 32900}, {{310025000, 490050000}, 32850}, -- cgit v1.2.3 From 0ec5b3f7ee049a45fa6a87101813ea9717eecbbb Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 2 Dec 2023 16:25:27 +0000 Subject: Extend ray for intersect walk to cover the extents of the map --- game/geoData.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/game/geoData.cpp b/game/geoData.cpp index d092d00..6c6f1df 100644 --- a/game/geoData.cpp +++ b/game/geoData.cpp @@ -202,17 +202,19 @@ GeoData::intersectRay(const Ray & ray) const GeoData::intersectRay(const Ray & ray, FaceHandle face) const { std::optional out; - walkUntil(PointFace {ray.start, face}, ray.start + (ray.direction * 10000.F), [&out, &ray, this](FaceHandle face) { - BaryPosition bari {}; - float dist {}; - const auto t = triangle<3>(face); - if (glm::intersectRayTriangle( - ray.start, ray.direction, t[0], t[1], t[2], bari, dist)) { - out = t * bari; - return true; - } - return false; - }); + walkUntil(PointFace {ray.start, face}, + ray.start.xy() + (ray.direction.xy() * RelativePosition2D(upperExtent.xy() - lowerExtent.xy())), + [&out, &ray, this](FaceHandle face) { + BaryPosition bari {}; + float dist {}; + const auto t = triangle<3>(face); + if (glm::intersectRayTriangle( + ray.start, ray.direction, t[0], t[1], t[2], bari, dist)) { + out = t * bari; + return true; + } + return false; + }); return out; } -- cgit v1.2.3 From 826a380710261961eb339d12d44f1c45fc384131 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 2 Dec 2023 16:36:11 +0000 Subject: Handle the case where the ray never enters the map --- game/geoData.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/game/geoData.cpp b/game/geoData.cpp index 6c6f1df..e2b7f66 100644 --- a/game/geoData.cpp +++ b/game/geoData.cpp @@ -232,7 +232,11 @@ GeoData::walkUntil(const PointFace & from, const GlobalPosition2D to, const std: { auto f = from.face(this); if (!f.is_valid()) { - f = opposite_face_handle(findEntry(from.point, to)); + const auto entryEdge = findEntry(from.point, to); + if (!entryEdge.is_valid()) { + return; + } + f = opposite_face_handle(entryEdge); } FaceHandle previousFace; while (f.is_valid() && !op(f)) { -- cgit v1.2.3 From 9ae29335b72b6db037a78428ff8493d1fb587103 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 2 Dec 2023 16:38:12 +0000 Subject: Test case for finding ray entry points --- test/test-geoData.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/test-geoData.cpp b/test/test-geoData.cpp index 164a6a5..d1c6b8b 100644 --- a/test/test-geoData.cpp +++ b/test/test-geoData.cpp @@ -186,3 +186,16 @@ BOOST_DATA_TEST_CASE(walkTerrainUntil, })); BOOST_CHECK_EQUAL_COLLECTIONS(visited.begin(), visited.end(), visits.begin(), visits.end()); } + +using FindEntiesData = std::tuple; + +BOOST_DATA_TEST_CASE(findEntries, + boost::unit_test::data::make({ + {{307739360, 494851616}, {314056992, 500079744}, 160667}, + {{308597952, 498417056}, {315154144, 504671456}, 233623}, + {{302690592, 502270912}, {311585184, 497868064}, 207311}, + }), + from, to, heh) +{ + BOOST_CHECK_EQUAL(fixedTerrtain.findEntry(from, to).idx(), heh); +} -- cgit v1.2.3 From 4e6f8db35ddc8fd3f310bb5616d257b5f9996d94 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 3 Dec 2023 12:37:46 +0000 Subject: Shader viewPoint now an integer --- gfx/gl/sceneShader.cpp | 6 +++--- gfx/gl/sceneShader.h | 4 ++-- gfx/gl/shaders/dynamicPoint.vs | 2 +- gfx/gl/shaders/dynamicPointInst.vs | 2 +- gfx/gl/shaders/fixedPoint.vs | 2 +- gfx/gl/shaders/pointLight.gs | 2 +- gfx/gl/shaders/pointLight.vs | 2 +- gfx/gl/shaders/shadowDynamicPoint.vs | 2 +- gfx/gl/shaders/shadowDynamicPointInst.vs | 2 +- gfx/gl/shaders/shadowFixedPoint.vs | 2 +- gfx/gl/shaders/spotLight.gs | 2 +- gfx/gl/shaders/spotLight.vs | 2 +- gfx/gl/shaders/water.vs | 2 +- 13 files changed, 16 insertions(+), 16 deletions(-) diff --git a/gfx/gl/sceneShader.cpp b/gfx/gl/sceneShader.cpp index 59a9748..57c8bb7 100644 --- a/gfx/gl/sceneShader.cpp +++ b/gfx/gl/sceneShader.cpp @@ -26,7 +26,7 @@ SceneShader::SceneShader() : } void -SceneShader::setViewProjection(const Position3D & viewPoint, const glm::mat4 & viewProjection) const +SceneShader::setViewProjection(const GlobalPosition3D & viewPoint, const glm::mat4 & viewProjection) const { for (const auto & prog : std::array { &basic, &basicInst, &water, &landmass, &absolute, &pointLight, &spotLight}) { @@ -44,11 +44,11 @@ SceneShader::setViewPort(const ViewPort & viewPort) const } void -SceneShader::SceneProgram::setViewProjection(const Position3D & viewPoint, const glm::mat4 & viewProjection) const +SceneShader::SceneProgram::setViewProjection(const GlobalPosition3D & viewPoint, const glm::mat4 & viewProjection) const { glUseProgram(*this); glUniformMatrix4fv(viewProjectionLoc, 1, GL_FALSE, glm::value_ptr(viewProjection)); - glUniform3fv(viewPointLoc, 1, glm::value_ptr(viewPoint)); + glUniform3iv(viewPointLoc, 1, glm::value_ptr(viewPoint)); } void diff --git a/gfx/gl/sceneShader.h b/gfx/gl/sceneShader.h index 83c234c..7ffaacd 100644 --- a/gfx/gl/sceneShader.h +++ b/gfx/gl/sceneShader.h @@ -16,7 +16,7 @@ class SceneShader { { } - void setViewProjection(const Position3D &, const glm::mat4 &) const; + void setViewProjection(const GlobalPosition3D &, const glm::mat4 &) const; void setViewPort(const ViewPort &) const; private: @@ -91,6 +91,6 @@ public: PointLightShader pointLight; SpotLightShader spotLight; - void setViewProjection(const Position3D & viewPoint, const glm::mat4 & viewProjection) const; + void setViewProjection(const GlobalPosition3D & viewPoint, const glm::mat4 & viewProjection) const; void setViewPort(const ViewPort & viewPort) const; }; diff --git a/gfx/gl/shaders/dynamicPoint.vs b/gfx/gl/shaders/dynamicPoint.vs index 667f247..097cd11 100644 --- a/gfx/gl/shaders/dynamicPoint.vs +++ b/gfx/gl/shaders/dynamicPoint.vs @@ -5,7 +5,7 @@ include(`meshIn.glsl') include(`materialInterface.glsl') uniform mat4 viewProjection; -uniform vec3 viewPoint; +uniform ivec3 viewPoint; uniform mat4 model; uniform ivec3 modelPos; diff --git a/gfx/gl/shaders/dynamicPointInst.vs b/gfx/gl/shaders/dynamicPointInst.vs index adf39bd..529fe1d 100644 --- a/gfx/gl/shaders/dynamicPointInst.vs +++ b/gfx/gl/shaders/dynamicPointInst.vs @@ -5,7 +5,7 @@ include(`meshIn.glsl') include(`materialInterface.glsl') uniform mat4 viewProjection; -uniform vec3 viewPoint; +uniform ivec3 viewPoint; layout(location = 5) in mat4 model; layout(location = 9) in ivec3 modelPos; diff --git a/gfx/gl/shaders/fixedPoint.vs b/gfx/gl/shaders/fixedPoint.vs index 6e1ab49..3cea737 100644 --- a/gfx/gl/shaders/fixedPoint.vs +++ b/gfx/gl/shaders/fixedPoint.vs @@ -5,7 +5,7 @@ include(`meshIn.glsl') include(`materialInterface.glsl') uniform mat4 viewProjection; -uniform vec3 viewPoint; +uniform ivec3 viewPoint; const mat4 model = mat4(1); const vec3 modelPos = ivec3(0); diff --git a/gfx/gl/shaders/pointLight.gs b/gfx/gl/shaders/pointLight.gs index ec089f5..9c41ed4 100644 --- a/gfx/gl/shaders/pointLight.gs +++ b/gfx/gl/shaders/pointLight.gs @@ -19,7 +19,7 @@ const vec3[] cube = vec3[]( // http://www.cs.umd.edu/gvil/papers/av_ts.pdf vec3(1, 1, -1) // Back-top-right ); uniform mat4 viewProjection; -uniform vec3 viewPoint; +uniform ivec3 viewPoint; in vec3 centre[]; in float size[]; diff --git a/gfx/gl/shaders/pointLight.vs b/gfx/gl/shaders/pointLight.vs index 7694a25..00a34a3 100644 --- a/gfx/gl/shaders/pointLight.vs +++ b/gfx/gl/shaders/pointLight.vs @@ -4,7 +4,7 @@ layout(location = 0) in vec3 position; uniform vec3 colour; uniform float kq; -uniform vec3 viewPoint; +uniform ivec3 viewPoint; out vec3 centre; out float size; diff --git a/gfx/gl/shaders/shadowDynamicPoint.vs b/gfx/gl/shaders/shadowDynamicPoint.vs index e20d31a..f21b3b6 100644 --- a/gfx/gl/shaders/shadowDynamicPoint.vs +++ b/gfx/gl/shaders/shadowDynamicPoint.vs @@ -3,7 +3,7 @@ include(`meshIn.glsl') uniform mat4 viewProjection; -uniform vec3 viewPoint; +uniform ivec3 viewPoint; uniform mat4 model; uniform ivec3 modelPos; diff --git a/gfx/gl/shaders/shadowDynamicPointInst.vs b/gfx/gl/shaders/shadowDynamicPointInst.vs index ab3e976..28a62d9 100644 --- a/gfx/gl/shaders/shadowDynamicPointInst.vs +++ b/gfx/gl/shaders/shadowDynamicPointInst.vs @@ -3,7 +3,7 @@ include(`meshIn.glsl') uniform mat4 viewProjection; -uniform vec3 viewPoint; +uniform ivec3 viewPoint; layout(location = 5) in mat4 model; layout(location = 9) in ivec3 modelPos; diff --git a/gfx/gl/shaders/shadowFixedPoint.vs b/gfx/gl/shaders/shadowFixedPoint.vs index a9fb4a3..168d5f1 100644 --- a/gfx/gl/shaders/shadowFixedPoint.vs +++ b/gfx/gl/shaders/shadowFixedPoint.vs @@ -3,7 +3,7 @@ include(`meshIn.glsl') uniform mat4 viewProjection; -uniform vec3 viewPoint; +uniform ivec3 viewPoint; const mat4 model = mat4(1); const ivec3 modelPos = ivec3(0); diff --git a/gfx/gl/shaders/spotLight.gs b/gfx/gl/shaders/spotLight.gs index 0529614..b58c169 100644 --- a/gfx/gl/shaders/spotLight.gs +++ b/gfx/gl/shaders/spotLight.gs @@ -10,7 +10,7 @@ const vec3[] pyramid = vec3[]( // four-sided vec3(1, -1, 1) // Front-right ); uniform mat4 viewProjection; -uniform vec3 viewPoint; +uniform ivec3 viewPoint; uniform float arc; in vec3 position[]; diff --git a/gfx/gl/shaders/spotLight.vs b/gfx/gl/shaders/spotLight.vs index 08197a4..ac1d1db 100644 --- a/gfx/gl/shaders/spotLight.vs +++ b/gfx/gl/shaders/spotLight.vs @@ -6,7 +6,7 @@ uniform vec3 v_direction; uniform vec3 colour; uniform float kq; uniform float arc; -uniform vec3 viewPoint; +uniform ivec3 viewPoint; out vec3 position; out vec3 direction; diff --git a/gfx/gl/shaders/water.vs b/gfx/gl/shaders/water.vs index 03eabb2..f609d9e 100644 --- a/gfx/gl/shaders/water.vs +++ b/gfx/gl/shaders/water.vs @@ -4,7 +4,7 @@ include(`meshIn.glsl') include(`materialInterface.glsl') uniform mat4 viewProjection; -uniform vec3 viewPoint; +uniform ivec3 viewPoint; uniform vec3 waves; void -- cgit v1.2.3 From 9fc82f2dd5aaa6f858ba22c92946e8cadfd7d79b Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 3 Dec 2023 13:50:24 +0000 Subject: Render correct VAO for rail vehicle shadows --- game/vehicles/railVehicleClass.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/game/vehicles/railVehicleClass.cpp b/game/vehicles/railVehicleClass.cpp index 7a6a9fe..3ca42db 100644 --- a/game/vehicles/railVehicleClass.cpp +++ b/game/vehicles/railVehicleClass.cpp @@ -66,7 +66,7 @@ RailVehicleClass::shadows(const ShadowMapper & mapper) const if (const auto count = static_cast(instances.size())) { mapper.dynamicPointInst.use(); bodyMesh->DrawInstanced(instanceVAO, count); - bogies.front()->DrawInstanced(instanceVAO, count); - bogies.back()->DrawInstanced(instanceVAO, count); + bogies.front()->DrawInstanced(instancesBogiesVAO.front(), count); + bogies.back()->DrawInstanced(instancesBogiesVAO.back(), count); } } -- cgit v1.2.3 From 57d02ec977e04003aadbca8fc18ed0f4b98b3288 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 3 Dec 2023 14:22:06 +0000 Subject: Set the viewPoint uniform in shadow shaders --- gfx/gl/shadowMapper.cpp | 30 +++++++++++++++++++----------- gfx/gl/shadowMapper.h | 8 ++++---- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/gfx/gl/shadowMapper.cpp b/gfx/gl/shadowMapper.cpp index 07db6a1..66905df 100644 --- a/gfx/gl/shadowMapper.cpp +++ b/gfx/gl/shadowMapper.cpp @@ -131,12 +131,15 @@ ShadowMapper::update(const SceneProvider & scene, const Direction3D & dir, const glCullFace(GL_FRONT); const auto lightView = glm::lookAt(camera.getPosition(), camera.getPosition() + dir, up); + const auto lightViewDir = glm::lookAt(origin, dir, up); + const auto lightViewPoint = camera.getPosition(); const auto bandViewExtents = getBandViewExtents(camera, lightView); Definitions out; std::transform(bandViewExtents.begin(), std::prev(bandViewExtents.end()), std::next(bandViewExtents.begin()), DefinitionsInserter {out}, - [&scene, this, &lightView, bands = bandViewExtents.size() - 2, &out](const auto & near, const auto & far) { + [&scene, this, &lightView, bands = bandViewExtents.size() - 2, &out, &lightViewPoint, &lightViewDir]( + const auto & near, const auto & far) { const auto extents_minmax = [extents = std::span {near.begin(), far.end()}](auto && comp) { const auto mm = std::minmax_element(extents.begin(), extents.end(), comp); return std::make_pair(comp.get(*mm.first), comp.get(*mm.second)); @@ -146,16 +149,16 @@ ShadowMapper::update(const SceneProvider & scene, const Direction3D & dir, const return glm::ortho(x.first, x.second, y.first, y.second, -z.second, -z.first); }(extents_minmax(CompareBy {0}), extents_minmax(CompareBy {1}), extents_minmax(CompareBy {2})); - const auto lightViewProjection = lightProjection * lightView; - fixedPoint.setViewProjection(lightViewProjection); - dynamicPoint.setViewProjection(lightViewProjection); - dynamicPointInst.setViewProjection(lightViewProjection); + const auto lightViewDirProjection = lightProjection * lightViewDir; + fixedPoint.setViewProjection(lightViewPoint, lightViewDirProjection); + dynamicPoint.setViewProjection(lightViewPoint, lightViewDirProjection); + dynamicPointInst.setViewProjection(lightViewPoint, lightViewDirProjection); const auto & viewport = viewports[bands][out.maps]; glViewport(size.x >> viewport.x, size.y >> viewport.y, size.x >> viewport.z, size.y >> viewport.w); scene.shadows(*this); - return std::make_pair(lightViewProjection, shadowMapRegions[bands][out.maps]); + return std::make_pair(lightProjection * lightView, shadowMapRegions[bands][out.maps]); }); glCullFace(GL_BACK); @@ -163,13 +166,17 @@ ShadowMapper::update(const SceneProvider & scene, const Direction3D & dir, const return out; } -ShadowMapper::FixedPoint::FixedPoint(const Shader & vs) : Program {vs}, viewProjectionLoc {*this, "viewProjection"} { } +ShadowMapper::FixedPoint::FixedPoint(const Shader & vs) : + Program {vs}, viewProjectionLoc {*this, "viewProjection"}, viewPointLoc {*this, "viewPoint"} +{ +} void -ShadowMapper::FixedPoint::setViewProjection(const glm::mat4 & viewProjection) const +ShadowMapper::FixedPoint::setViewProjection(const GlobalPosition3D viewPoint, const glm::mat4 & viewProjection) const { use(); glUniformMatrix4fv(viewProjectionLoc, 1, GL_FALSE, glm::value_ptr(viewProjection)); + glUniform3iv(viewPointLoc, 1, glm::value_ptr(viewPoint)); } void @@ -179,16 +186,17 @@ ShadowMapper::FixedPoint::use() const } ShadowMapper::DynamicPoint::DynamicPoint() : - Program {shadowDynamicPoint_vs}, viewProjectionLoc {*this, "viewProjection"}, modelLoc {*this, "model"}, - modelPosLoc {*this, "modelPos"} + Program {shadowDynamicPoint_vs}, viewProjectionLoc {*this, "viewProjection"}, viewPointLoc {*this, "viewPoint"}, + modelLoc {*this, "model"}, modelPosLoc {*this, "modelPos"} { } void -ShadowMapper::DynamicPoint::setViewProjection(const glm::mat4 & viewProjection) const +ShadowMapper::DynamicPoint::setViewProjection(const GlobalPosition3D viewPoint, const glm::mat4 & viewProjection) const { glUseProgram(*this); glUniformMatrix4fv(viewProjectionLoc, 1, GL_FALSE, glm::value_ptr(viewProjection)); + glUniform3iv(viewPointLoc, 1, glm::value_ptr(viewPoint)); } void diff --git a/gfx/gl/shadowMapper.h b/gfx/gl/shadowMapper.h index b53a7f1..01520ca 100644 --- a/gfx/gl/shadowMapper.h +++ b/gfx/gl/shadowMapper.h @@ -27,22 +27,22 @@ public: class FixedPoint : public Program { public: FixedPoint(const Shader & vs); - void setViewProjection(const glm::mat4 &) const; + void setViewProjection(const GlobalPosition3D, const glm::mat4 &) const; void use() const; private: - RequiredUniformLocation viewProjectionLoc; + RequiredUniformLocation viewProjectionLoc, viewPointLoc; }; class DynamicPoint : public Program { public: DynamicPoint(); - void setViewProjection(const glm::mat4 &) const; + void setViewProjection(const GlobalPosition3D, const glm::mat4 &) const; void use(const Location &) const; void setModel(const Location &) const; private: - RequiredUniformLocation viewProjectionLoc; + RequiredUniformLocation viewProjectionLoc, viewPointLoc; RequiredUniformLocation modelLoc; RequiredUniformLocation modelPosLoc; }; -- cgit v1.2.3 From 0b3460d0ad0ea9976f3919a2f2befe16f8f35f19 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 3 Dec 2023 17:22:18 +0000 Subject: Render test using loaded terrain --- test/test-render.cpp | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/test/test-render.cpp b/test/test-render.cpp index f15e51e..cb6b1b4 100644 --- a/test/test-render.cpp +++ b/test/test-render.cpp @@ -93,6 +93,43 @@ BOOST_AUTO_TEST_CASE(basic) Texture::save(outImage, "/tmp/basic.tga"); } +BOOST_AUTO_TEST_CASE(terrain) +{ + SceneRenderer ss {size, output}; + ss.camera.setView({310000000, 490000000, 600000}, glm::normalize(glm::vec3 {1, 1, -0.5F})); + + class TestTerrain : public SceneProvider { + Terrain terrain {std::make_shared(GeoData::loadFromAsciiGrid(FIXTURESDIR "height/SD19.asc"))}; + + void + content(const SceneShader & shader) const override + { + terrain.render(shader); + } + + void + environment(const SceneShader &, const SceneRenderer & sr) const override + { + sr.setAmbientLight({0.1, 0.1, 0.1}); + sr.setDirectionalLight({1, 1, 1}, south + down, *this); + } + + void + lights(const SceneShader &) const override + { + } + + void + shadows(const ShadowMapper & shadowMapper) const override + { + terrain.shadows(shadowMapper); + } + }; + + ss.render(TestTerrain {}); + Texture::save(outImage, "/tmp/terrain.tga"); +} + BOOST_AUTO_TEST_CASE(pointlight) { SceneRenderer ss {size, output}; -- cgit v1.2.3 From 504d345e24e3be54d90f8bdd107c5bfbb38e57af Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 9 Dec 2023 12:04:07 +0000 Subject: Helper for testing integer vector approximations --- test/test-maths.cpp | 8 ++++---- test/testHelpers.h | 10 ++++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/test/test-maths.cpp b/test/test-maths.cpp index 9eae918..cc97250 100644 --- a/test/test-maths.cpp +++ b/test/test-maths.cpp @@ -236,8 +236,8 @@ BOOST_DATA_TEST_CASE(curve1, } { const auto p = l.positionAt(0, 1); - BOOST_CHECK_CLOSE_VEC(RelativePosition3D {p.pos}, e1); - BOOST_CHECK_CLOSE_VEC(p.rot, glm::vec3(0, angBack, 0)); + BOOST_CHECK_CLOSE_VECI(RelativePosition3D {p.pos}, e1); + BOOST_CHECK_CLOSE_VECI(p.rot, glm::vec3(0, angBack, 0)); } } @@ -247,8 +247,8 @@ BOOST_DATA_TEST_CASE(curve1, { const auto p = l.positionAt(0, 0); const auto angForReversed = normalize(vector_yaw(origin - e1) * 2 - angFor); - BOOST_CHECK_CLOSE_VEC(RelativePosition3D {p.pos}, e1); - BOOST_CHECK_CLOSE_VEC(p.rot, glm::vec3(0, angForReversed, 0)); + BOOST_CHECK_CLOSE_VECI(RelativePosition3D {p.pos}, e1); + BOOST_CHECK_CLOSE_VECI(p.rot, glm::vec3(0, angForReversed, 0)); } { const auto p = l.positionAt(0, 1); diff --git a/test/testHelpers.h b/test/testHelpers.h index 79e966a..f2b0901 100644 --- a/test/testHelpers.h +++ b/test/testHelpers.h @@ -15,6 +15,16 @@ std::unique_ptr uasprintf(const char * fmt, ...) __attrib } \ } +#define BOOST_CHECK_CLOSE_VECI(a_, b_) \ + { \ + const auto a {a_}, b {b_}; \ + BOOST_TEST_CONTEXT("BOOST_CHECK_CLOSE_VEC(" << std::setprecision(8) << a << ", " << b << ")") { \ + BOOST_CHECK_LE(std::abs(a.x - b.x), 1); \ + BOOST_CHECK_LE(std::abs(a.y - b.y), 1); \ + BOOST_CHECK_LE(std::abs(a.z - b.z), 1); \ + } \ + } + #define BOOST_CHECK_BETWEEN(a_, b_, c_) \ { \ const auto a {a_}, b {b_}, c {c_}; \ -- cgit v1.2.3 From daed922f23daa8a8e2659d8aea7864cccd5e08c7 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 11 Dec 2023 20:11:23 +0000 Subject: Integer camera --- gfx/gl/camera.cpp | 36 ++++++++++++++++++------------------ gfx/gl/camera.h | 18 +++++++++--------- gfx/gl/sceneRenderer.cpp | 2 +- gfx/gl/shadowMapper.cpp | 16 ++++++++-------- test/test-maths.cpp | 2 +- test/test-render.cpp | 14 +++++++------- 6 files changed, 44 insertions(+), 44 deletions(-) diff --git a/gfx/gl/camera.cpp b/gfx/gl/camera.cpp index 15f76c4..a0d76ab 100644 --- a/gfx/gl/camera.cpp +++ b/gfx/gl/camera.cpp @@ -1,14 +1,14 @@ #include "camera.h" #include -#include // IWYU pragma: keep -#include // IWYU pragma: keep -#include +#include #include #include -Camera::Camera(Position3D pos, Angle fov, Angle aspect, Distance zNear, Distance zFar) : +Camera::Camera(GlobalPosition3D pos, Angle fov, Angle aspect, GlobalDistance zNear, GlobalDistance zFar) : position {pos}, forward {::north}, up {::up}, near {zNear}, far {zFar}, - projection {glm::perspective(fov, aspect, zNear, zFar)}, viewProjection {}, inverseViewProjection {} + projection { + glm::perspective(fov, aspect, static_cast(zNear), static_cast(zFar))}, + viewProjection {}, inverseViewProjection {} { updateView(); } @@ -25,7 +25,7 @@ void Camera::updateView() { viewProjection = projection * glm::lookAt(origin, forward, up); - inverseViewProjection = glm::inverse(projection * glm::lookAt(position, position + forward, up)); + inverseViewProjection = glm::inverse(viewProjection); } Direction3D @@ -35,21 +35,21 @@ Camera::upFromForward(const Direction3D & forward) return glm::cross(forward, right); } -std::array -Camera::extentsAtDist(const float dist) const +std::array +Camera::extentsAtDist(const GlobalDistance dist) const { - const auto clampToSeaFloor = [this, dist](const Position3D & target) { - if (target.z < -1.5F) { - const auto vec = glm::normalize(target - position); - constexpr Position3D seafloor {0, 0, -1.5F}; - float outdist {}; - if (glm::intersectRayPlane(position, vec, seafloor, ::up, outdist)) { - return (vec * outdist + position) ^ outdist; - } + const auto clampToSeaFloor = [this, dist](GlobalPosition3D target) -> GlobalPosition4D { + target += position; + if (target.z < -1500) { + const auto diff = (target - position); + const auto something = (-1500 - position.z) / diff.z; + return {position + diff * something, dist}; } - return target ^ dist; + return {target, dist}; }; - const auto depth = -(2.F * (dist - near) * far) / (dist * (near - far)) - 1.F; + const auto depth = -(2.F * (static_cast(dist - near)) * static_cast(far)) + / (static_cast(dist) * (static_cast(near - far))) + - 1.F; static constexpr const std::array extents {-1.F, 1.F}; static constexpr const auto cartesianExtents = extents * extents; return cartesianExtents * [&depth, this, &clampToSeaFloor](const auto & extent) { diff --git a/gfx/gl/camera.h b/gfx/gl/camera.h index 469df0d..eca7b8f 100644 --- a/gfx/gl/camera.h +++ b/gfx/gl/camera.h @@ -7,7 +7,7 @@ class Camera { public: - Camera(Position3D, Angle fov, Angle aspect, Distance zNear, Distance zFar); + Camera(GlobalPosition3D, Angle fov, Angle aspect, GlobalDistance zNear, GlobalDistance zFar); [[nodiscard]] glm::mat4 getViewProjection() const @@ -18,7 +18,7 @@ public: [[nodiscard]] Ray unProject(const ScreenRelCoord &) const; void - setPosition(const Position3D & p) + setPosition(const GlobalPosition3D & p) { position = p; updateView(); @@ -39,23 +39,23 @@ public: } void - setView(const Position3D & p, const Direction3D & f) + setView(const GlobalPosition3D & p, const Direction3D & f) { position = p; setForward(f); } void - setView(const Position3D & p, const Direction3D & f, const Direction3D & u) + setView(const GlobalPosition3D & p, const Direction3D & f, const Direction3D & u) { position = p; setView(f, u); } void - lookAt(const Position3D & target) + lookAt(const GlobalPosition3D & target) { - setForward(glm::normalize(target - position)); + setForward(glm::normalize(RelativePosition3D(target - position))); } [[nodiscard]] auto @@ -70,18 +70,18 @@ public: return position; } - [[nodiscard]] std::array extentsAtDist(float) const; + [[nodiscard]] std::array extentsAtDist(GlobalDistance) const; [[nodiscard]] static Direction3D upFromForward(const Direction3D & forward); private: void updateView(); - Position3D position; + GlobalPosition3D position; Direction3D forward; Direction3D up; - float near, far; + GlobalDistance near, far; glm::mat4 projection; glm::mat4 viewProjection, inverseViewProjection; }; diff --git a/gfx/gl/sceneRenderer.cpp b/gfx/gl/sceneRenderer.cpp index 53178e5..582c28c 100644 --- a/gfx/gl/sceneRenderer.cpp +++ b/gfx/gl/sceneRenderer.cpp @@ -15,7 +15,7 @@ static constexpr const std::array displayVAOdata {{ }}; SceneRenderer::SceneRenderer(ScreenAbsCoord s, GLuint o) : - camera {{-1250000.0F, -1250000.0F, 35.0F}, quarter_pi, ratio(s), 100.F, 10000000.0F}, size {s}, output {o}, + camera {{-1250000, -1250000, 35.0F}, quarter_pi, ratio(s), 100, 10000000}, size {s}, output {o}, lighting {lighting_vs, lighting_fs}, shadowMapper {{2048, 2048}} { shader.setViewPort({0, 0, size.x, size.y}); diff --git a/gfx/gl/shadowMapper.cpp b/gfx/gl/shadowMapper.cpp index 66905df..deb0630 100644 --- a/gfx/gl/shadowMapper.cpp +++ b/gfx/gl/shadowMapper.cpp @@ -79,12 +79,12 @@ constexpr std::array, S {0.25F, 0.25F, 0.75F, 0.75F}, // upper right }}, }}; -constexpr std::array shadowBands { - 1000.F, - 250000.F, - 750000.F, - 2500000.F, - 10000000.F, +constexpr std::array shadowBands { + 1000, + 250000, + 750000, + 2500000, + 10000000, }; static_assert(viewports.size() == shadowMapRegions.size()); static_assert(shadowBands.size() == shadowMapRegions.size() + 1); @@ -114,7 +114,7 @@ ShadowMapper::getBandViewExtents(const Camera & camera, const glm::mat4 & lightV bandViewExtents.emplace_back(extents * [&lightView](const auto & e) -> Position3D { return lightView * glm::vec4(Position3D {e}, 1); }); - if (std::none_of(extents.begin(), extents.end(), [targetDist = dist * 0.99F](const glm::vec4 & e) { + if (std::none_of(extents.begin(), extents.end(), [targetDist = dist - 1](const auto & e) { return e.w > targetDist; })) { break; @@ -130,8 +130,8 @@ ShadowMapper::update(const SceneProvider & scene, const Direction3D & dir, const glClear(GL_DEPTH_BUFFER_BIT); glCullFace(GL_FRONT); - const auto lightView = glm::lookAt(camera.getPosition(), camera.getPosition() + dir, up); const auto lightViewDir = glm::lookAt(origin, dir, up); + const auto lightView = lightViewDir * glm::translate(RelativePosition3D {-camera.getPosition()}); const auto lightViewPoint = camera.getPosition(); const auto bandViewExtents = getBandViewExtents(camera, lightView); diff --git a/test/test-maths.cpp b/test/test-maths.cpp index cc97250..3f8c2a0 100644 --- a/test/test-maths.cpp +++ b/test/test-maths.cpp @@ -261,7 +261,7 @@ BOOST_DATA_TEST_CASE(curve1, BOOST_AUTO_TEST_CASE(camera_clicks) { - Camera camera {::origin, ::half_pi, 1.25F, .1F, 10000.F}; + Camera camera {::origin, ::half_pi, 1.25F, 1000, 10000000}; constexpr float centre {0.5F}, right {0.9F}, left {0.1F}, top {1.F}, bottom {0.F}; camera.setForward(::north); BOOST_CHECK_EQUAL(camera.unProject({centre, centre}).start, ::origin); diff --git a/test/test-render.cpp b/test/test-render.cpp index cb6b1b4..22da73b 100644 --- a/test/test-render.cpp +++ b/test/test-render.cpp @@ -67,19 +67,19 @@ BOOST_GLOBAL_FIXTURE(ApplicationBase); BOOST_GLOBAL_FIXTURE(TestMainWindow); BOOST_DATA_TEST_CASE(cam, - boost::unit_test::data::xrange(0.5F, 30.F, 1.3F) * boost::unit_test::data::xrange(0.5F, 10.F, 0.3F) - * boost::unit_test::data::xrange(50.F, 500.F, 70.F), + boost::unit_test::data::xrange(500, 30000, 1300) * boost::unit_test::data::xrange(500, 10000, 300) + * boost::unit_test::data::xrange(50000, 500000, 70000), dist, near, far) { - static constexpr glm::vec4 pos {-10, -10, 60, 0}; + static constexpr GlobalPosition4D pos {-10, -10, 60000, 0}; const Camera cam {pos, half_pi, 1.F, near, far}; const auto e = cam.extentsAtDist(dist); - BOOST_CHECK_CLOSE_VEC(e[0], pos + glm::vec4(-dist, dist, -dist, dist)); - BOOST_CHECK_CLOSE_VEC(e[1], pos + glm::vec4(-dist, dist, dist, dist)); - BOOST_CHECK_CLOSE_VEC(e[2], pos + glm::vec4(dist, dist, -dist, dist)); - BOOST_CHECK_CLOSE_VEC(e[3], pos + glm::vec4(dist, dist, dist, dist)); + BOOST_CHECK_CLOSE_VECI(e[0], pos + GlobalPosition4D(-dist, dist, -dist, dist)); + BOOST_CHECK_CLOSE_VECI(e[1], pos + GlobalPosition4D(-dist, dist, dist, dist)); + BOOST_CHECK_CLOSE_VECI(e[2], pos + GlobalPosition4D(dist, dist, -dist, dist)); + BOOST_CHECK_CLOSE_VECI(e[3], pos + GlobalPosition4D(dist, dist, dist, dist)); } BOOST_FIXTURE_TEST_SUITE(w, TestRenderOutput); -- cgit v1.2.3 From 04f42212ba67ec7d8160bf4a19c0b1283aec69bc Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 11 Dec 2023 20:49:52 +0000 Subject: Fix clamping to seafloor and add specific test --- gfx/gl/camera.cpp | 6 +++--- test/test-render.cpp | 12 ++++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/gfx/gl/camera.cpp b/gfx/gl/camera.cpp index a0d76ab..ff4c91e 100644 --- a/gfx/gl/camera.cpp +++ b/gfx/gl/camera.cpp @@ -41,9 +41,9 @@ Camera::extentsAtDist(const GlobalDistance dist) const const auto clampToSeaFloor = [this, dist](GlobalPosition3D target) -> GlobalPosition4D { target += position; if (target.z < -1500) { - const auto diff = (target - position); - const auto something = (-1500 - position.z) / diff.z; - return {position + diff * something, dist}; + const auto diff = target - position; + const auto limit = -1500 - position.z; + return {position + (limit * diff) / diff.z, (limit * dist) / diff.z}; } return {target, dist}; }; diff --git a/test/test-render.cpp b/test/test-render.cpp index 22da73b..37bacdd 100644 --- a/test/test-render.cpp +++ b/test/test-render.cpp @@ -82,6 +82,18 @@ BOOST_DATA_TEST_CASE(cam, BOOST_CHECK_CLOSE_VECI(e[3], pos + GlobalPosition4D(dist, dist, dist, dist)); } +BOOST_AUTO_TEST_CASE(camSeaFloor) +{ + const Camera cam {{100, 200, 300}, half_pi, 1.F, 100, 2000}; + + const auto e = cam.extentsAtDist(2000); + + BOOST_CHECK_CLOSE_VECI(e[0], GlobalPosition4D(-1700, 2000, -1500, 1800)); + BOOST_CHECK_CLOSE_VECI(e[1], GlobalPosition4D(-1900, 2200, 2300, 2000)); + BOOST_CHECK_CLOSE_VECI(e[2], GlobalPosition4D(1900, 2000, -1500, 1800)); + BOOST_CHECK_CLOSE_VECI(e[3], GlobalPosition4D(2100, 2200, 2300, 2000)); +} + BOOST_FIXTURE_TEST_SUITE(w, TestRenderOutput); BOOST_AUTO_TEST_CASE(basic) -- cgit v1.2.3 From e4b85a5f84f73548def2162fc534625470404df1 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Wed, 13 Dec 2023 01:46:36 +0000 Subject: Basic support for saving intermediate render buffers --- gfx/gl/sceneRenderer.h | 2 +- test/test-render.cpp | 20 ++++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/gfx/gl/sceneRenderer.h b/gfx/gl/sceneRenderer.h index 30fd8d3..7f72d76 100644 --- a/gfx/gl/sceneRenderer.h +++ b/gfx/gl/sceneRenderer.h @@ -19,7 +19,7 @@ public: Camera camera; -private: +protected: void renderQuad() const; ScreenAbsCoord size; diff --git a/test/test-render.cpp b/test/test-render.cpp index 37bacdd..e2797a4 100644 --- a/test/test-render.cpp +++ b/test/test-render.cpp @@ -98,11 +98,27 @@ BOOST_FIXTURE_TEST_SUITE(w, TestRenderOutput); BOOST_AUTO_TEST_CASE(basic) { - SceneRenderer ss {size, output}; + class TestSceneRenderer : public SceneRenderer { + using SceneRenderer::SceneRenderer; + + public: + void + saveBuffers(const std::filesystem::path & prefix) const + { + std::filesystem::create_directories(prefix); + Texture::save(gAlbedoSpec, (prefix / "albedo.tga").c_str()); + Texture::save(gPosition, (prefix / "position.tga").c_str()); + Texture::saveNormal(gNormal, (prefix / "normal.tga").c_str()); + Texture::save(gIllumination, (prefix / "illumination.tga").c_str()); + } + }; + + TestSceneRenderer ss {size, output}; ss.camera.setView({-10000, -10000, 60000}, glm::normalize(glm::vec3 {1, 1, -0.5F})); const TestScene scene; ss.render(scene); - Texture::save(outImage, "/tmp/basic.tga"); + ss.saveBuffers("/tmp/basic"); + Texture::save(outImage, "/tmp/basic/final.tga"); } BOOST_AUTO_TEST_CASE(terrain) -- cgit v1.2.3 From 582b43ff308eecbdcaf0ab14994a0ddbdba1b701 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 15 Dec 2023 01:20:53 +0000 Subject: Support setting framebuffer texture format Renames format to iformat to differentiate internal format from format --- gfx/gl/sceneRenderer.cpp | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/gfx/gl/sceneRenderer.cpp b/gfx/gl/sceneRenderer.cpp index 582c28c..541af43 100644 --- a/gfx/gl/sceneRenderer.cpp +++ b/gfx/gl/sceneRenderer.cpp @@ -22,25 +22,25 @@ SceneRenderer::SceneRenderer(ScreenAbsCoord s, GLuint o) : VertexArrayObject {displayVAO}.addAttribs(displayVBO, displayVAOdata); glBindFramebuffer(GL_FRAMEBUFFER, gBuffer); - const auto configuregdata - = [this](const GLuint data, const std::initializer_list formats, const GLenum attachment) { - glBindTexture(GL_TEXTURE_2D, data); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - for (const auto format : formats) { - glTexImage2D(GL_TEXTURE_2D, 0, format, size.x, size.y, 0, GL_RGB, GL_BYTE, nullptr); + const auto configuregdata = [this](const GLuint data, const std::initializer_list iformats, + const GLenum format, const GLenum attachment) { + glBindTexture(GL_TEXTURE_2D, data); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + for (const auto iformat : iformats) { + glTexImage2D(GL_TEXTURE_2D, 0, iformat, size.x, size.y, 0, format, GL_BYTE, nullptr); - glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, data, 0); - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) { - return format; - } - } - throw std::runtime_error("Framebuffer could not be completed!"); - }; - configuregdata(gPosition, {GL_RGB32F}, GL_COLOR_ATTACHMENT0); - configuregdata(gNormal, {GL_RGB8_SNORM, GL_RGB16F}, GL_COLOR_ATTACHMENT1); - configuregdata(gAlbedoSpec, {GL_RGB8}, GL_COLOR_ATTACHMENT2); - configuregdata(gIllumination, {GL_RGB8}, GL_COLOR_ATTACHMENT3); + glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, data, 0); + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) { + return iformat; + } + } + throw std::runtime_error("Framebuffer could not be completed!"); + }; + configuregdata(gPosition, {GL_RGB32F}, GL_RGB, GL_COLOR_ATTACHMENT0); + configuregdata(gNormal, {GL_RGB8_SNORM, GL_RGB16F}, GL_RGB, GL_COLOR_ATTACHMENT1); + configuregdata(gAlbedoSpec, {GL_RGB8}, GL_RGB, GL_COLOR_ATTACHMENT2); + configuregdata(gIllumination, {GL_RGB8}, GL_RGB, GL_COLOR_ATTACHMENT3); glBindRenderbuffer(GL_RENDERBUFFER, depth); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, size.x, size.y); -- cgit v1.2.3 From 14aa604389110f5da25e0c06ca4c6a753c497248 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 15 Dec 2023 01:46:22 +0000 Subject: Basic support for saving integer position buffer --- gfx/models/texture.cpp | 6 ++++++ gfx/models/texture.h | 1 + 2 files changed, 7 insertions(+) diff --git a/gfx/models/texture.cpp b/gfx/models/texture.cpp index 1685d34..35f8d35 100644 --- a/gfx/models/texture.cpp +++ b/gfx/models/texture.cpp @@ -103,6 +103,12 @@ Texture::save(const glTexture & texture, const char * path) save(texture, GL_BGR, GL_UNSIGNED_BYTE, 3, path, 2); } +void +Texture::savePosition(const glTexture & texture, const char * path) +{ + save(texture, GL_BGR_INTEGER, GL_UNSIGNED_BYTE, 3, path, 2); +} + void Texture::saveDepth(const glTexture & texture, const char * path) { diff --git a/gfx/models/texture.h b/gfx/models/texture.h index 5e1b440..5d40b39 100644 --- a/gfx/models/texture.h +++ b/gfx/models/texture.h @@ -40,6 +40,7 @@ public: static void save(const glTexture &, const char * path); static void saveDepth(const glTexture &, const char * path); static void saveNormal(const glTexture &, const char * path); + static void savePosition(const glTexture &, const char * path); protected: static void save(const glTexture &, GLenum, GLenum, uint8_t channels, const char * path, uint8_t tgaFormat); -- cgit v1.2.3 From 467ef27cafa072bac1c9df633a99e33c0bbf0299 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 17 Dec 2023 12:13:19 +0000 Subject: Use a separate framebuffer for illumination phase --- gfx/gl/sceneRenderer.cpp | 20 ++++++++++++-------- gfx/gl/sceneRenderer.h | 2 +- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/gfx/gl/sceneRenderer.cpp b/gfx/gl/sceneRenderer.cpp index 541af43..b88fb71 100644 --- a/gfx/gl/sceneRenderer.cpp +++ b/gfx/gl/sceneRenderer.cpp @@ -21,7 +21,6 @@ SceneRenderer::SceneRenderer(ScreenAbsCoord s, GLuint o) : shader.setViewPort({0, 0, size.x, size.y}); VertexArrayObject {displayVAO}.addAttribs(displayVBO, displayVAOdata); - glBindFramebuffer(GL_FRAMEBUFFER, gBuffer); const auto configuregdata = [this](const GLuint data, const std::initializer_list iformats, const GLenum format, const GLenum attachment) { glBindTexture(GL_TEXTURE_2D, data); @@ -37,15 +36,23 @@ SceneRenderer::SceneRenderer(ScreenAbsCoord s, GLuint o) : } throw std::runtime_error("Framebuffer could not be completed!"); }; + + glBindFramebuffer(GL_FRAMEBUFFER, gBuffer); configuregdata(gPosition, {GL_RGB32F}, GL_RGB, GL_COLOR_ATTACHMENT0); configuregdata(gNormal, {GL_RGB8_SNORM, GL_RGB16F}, GL_RGB, GL_COLOR_ATTACHMENT1); configuregdata(gAlbedoSpec, {GL_RGB8}, GL_RGB, GL_COLOR_ATTACHMENT2); - configuregdata(gIllumination, {GL_RGB8}, GL_RGB, GL_COLOR_ATTACHMENT3); + constexpr std::array attachments { + GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2}; + glDrawBuffers(attachments.size(), attachments.data()); glBindRenderbuffer(GL_RENDERBUFFER, depth); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, size.x, size.y); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth); + glBindFramebuffer(GL_FRAMEBUFFER, gBufferIll); + configuregdata(gIllumination, {GL_RGB8}, GL_RGB, GL_COLOR_ATTACHMENT0); + glDrawBuffer(GL_COLOR_ATTACHMENT0); + glBindFramebuffer(GL_FRAMEBUFFER, output); } @@ -57,9 +64,6 @@ SceneRenderer::render(const SceneProvider & scene) const // Geometry pass glBindFramebuffer(GL_FRAMEBUFFER, gBuffer); - static constexpr std::array attachments { - GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2}; - glDrawBuffers(attachments.size(), attachments.data()); glEnable(GL_BLEND); glEnable(GL_CULL_FACE); glCullFace(GL_BACK); @@ -70,7 +74,7 @@ SceneRenderer::render(const SceneProvider & scene) const scene.content(shader); // Illumination pass - glDrawBuffer(GL_COLOR_ATTACHMENT3); + glBindFramebuffer(GL_FRAMEBUFFER, gBufferIll); glBlendFunc(GL_ONE, GL_ONE); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, gPosition); @@ -99,7 +103,7 @@ SceneRenderer::render(const SceneProvider & scene) const void SceneRenderer::setAmbientLight(const RGB & colour) const { - glBindFramebuffer(GL_FRAMEBUFFER, gBuffer); + glBindFramebuffer(GL_FRAMEBUFFER, gBufferIll); glClearColor(colour.r, colour.g, colour.b, 1.0F); glClear(GL_COLOR_BUFFER_BIT); } @@ -109,7 +113,7 @@ SceneRenderer::setDirectionalLight(const RGB & colour, const Direction3D & direc { if (colour.r > 0 || colour.g > 0 || colour.b > 0) { const auto lvp = shadowMapper.update(scene, direction, camera); - glBindFramebuffer(GL_FRAMEBUFFER, gBuffer); + glBindFramebuffer(GL_FRAMEBUFFER, gBufferIll); glViewport(0, 0, size.x, size.y); dirLight.use(); dirLight.setDirectionalLight(colour, direction, lvp.projections, lvp.regions, lvp.maps); diff --git a/gfx/gl/sceneRenderer.h b/gfx/gl/sceneRenderer.h index 7f72d76..c935f93 100644 --- a/gfx/gl/sceneRenderer.h +++ b/gfx/gl/sceneRenderer.h @@ -24,7 +24,7 @@ protected: ScreenAbsCoord size; GLuint output; - glFrameBuffer gBuffer; + glFrameBuffer gBuffer, gBufferIll; glTexture gPosition, gNormal, gAlbedoSpec, gIllumination; glRenderBuffer depth; -- cgit v1.2.3 From cbc94ed8572cd4ea4e22ad5437b54eea055235d9 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 17 Dec 2023 12:14:35 +0000 Subject: Use 32bit integer texture for position render data --- gfx/gl/sceneRenderer.cpp | 2 +- gfx/gl/shaders/directionalLight.fs | 6 +++--- gfx/gl/shaders/landmass.fs | 2 +- gfx/gl/shaders/material.fs | 2 +- gfx/gl/shaders/materialOut.glsl | 2 +- gfx/gl/shaders/pointLight.fs | 2 +- gfx/gl/shaders/spotLight.fs | 2 +- gfx/gl/shaders/water.fs | 2 +- test/test-render.cpp | 2 +- 9 files changed, 11 insertions(+), 11 deletions(-) diff --git a/gfx/gl/sceneRenderer.cpp b/gfx/gl/sceneRenderer.cpp index b88fb71..2854dea 100644 --- a/gfx/gl/sceneRenderer.cpp +++ b/gfx/gl/sceneRenderer.cpp @@ -38,7 +38,7 @@ SceneRenderer::SceneRenderer(ScreenAbsCoord s, GLuint o) : }; glBindFramebuffer(GL_FRAMEBUFFER, gBuffer); - configuregdata(gPosition, {GL_RGB32F}, GL_RGB, GL_COLOR_ATTACHMENT0); + configuregdata(gPosition, {GL_RGB32I}, GL_RGB_INTEGER, GL_COLOR_ATTACHMENT0); configuregdata(gNormal, {GL_RGB8_SNORM, GL_RGB16F}, GL_RGB, GL_COLOR_ATTACHMENT1); configuregdata(gAlbedoSpec, {GL_RGB8}, GL_RGB, GL_COLOR_ATTACHMENT2); constexpr std::array attachments { diff --git a/gfx/gl/shaders/directionalLight.fs b/gfx/gl/shaders/directionalLight.fs index ca10ef5..3756db7 100644 --- a/gfx/gl/shaders/directionalLight.fs +++ b/gfx/gl/shaders/directionalLight.fs @@ -7,7 +7,7 @@ out vec3 FragColor; in vec2 TexCoords; -layout(binding = 0) uniform sampler2D gPosition; +layout(binding = 0) uniform isampler2D gPosition; layout(binding = 1) uniform sampler2D gNormal; layout(binding = 2) uniform sampler2D shadowMap; @@ -27,7 +27,7 @@ insideShadowCube(vec3 v) } float -isShaded(vec3 Position) +isShaded(ivec3 Position) { for (uint m = 0u; m < lightViewProjectionCount; m++) { vec3 PositionInLightSpace = (lightViewProjection[m] * vec4(Position, 1.0f)).xyz; @@ -44,7 +44,7 @@ isShaded(vec3 Position) void main() { - const vec3 Position = texture(gPosition, TexCoords).xyz; + const ivec3 Position = texture(gPosition, TexCoords).xyz; const vec3 Normal = texture(gNormal, TexCoords).rgb; const float shaded = isShaded(Position); FragColor = (1 - shaded) * max(dot(-lightDirection, Normal) * lightColour, 0); diff --git a/gfx/gl/shaders/landmass.fs b/gfx/gl/shaders/landmass.fs index 9865d11..fc43bf2 100644 --- a/gfx/gl/shaders/landmass.fs +++ b/gfx/gl/shaders/landmass.fs @@ -60,7 +60,7 @@ main() } } - gPosition = vec4(FragPos, 1); + gPosition = ivec4(FragPos, 1); gNormal = vec4(Normal, 1); gAlbedoSpec = vec4(color, 1); } diff --git a/gfx/gl/shaders/material.fs b/gfx/gl/shaders/material.fs index 20fa8ab..5b93707 100644 --- a/gfx/gl/shaders/material.fs +++ b/gfx/gl/shaders/material.fs @@ -42,7 +42,7 @@ main() { vec4 textureColour = getTextureColour(Material, TexCoords); float opaque = step(0.5, mix(textureColour.a, 1, Colour.a)); - gPosition = vec4(FragPos, opaque); + gPosition = ivec4(FragPos, opaque); gNormal = vec4(Normal, opaque); gl_FragDepth = mix(1.0, gl_FragCoord.z, opaque); gAlbedoSpec = mix(textureColour, vec4(Colour.rgb, 1), Colour.a); diff --git a/gfx/gl/shaders/materialOut.glsl b/gfx/gl/shaders/materialOut.glsl index dc5f8e8..846825e 100644 --- a/gfx/gl/shaders/materialOut.glsl +++ b/gfx/gl/shaders/materialOut.glsl @@ -1,3 +1,3 @@ -layout(location = 0) out vec4 gPosition; +layout(location = 0) out ivec4 gPosition; layout(location = 1) out vec4 gNormal; layout(location = 2) out vec4 gAlbedoSpec; diff --git a/gfx/gl/shaders/pointLight.fs b/gfx/gl/shaders/pointLight.fs index 1a68df8..ba327b6 100644 --- a/gfx/gl/shaders/pointLight.fs +++ b/gfx/gl/shaders/pointLight.fs @@ -3,7 +3,7 @@ out vec3 FragColor; -layout(binding = 0) uniform sampler2D gPosition; +layout(binding = 0) uniform isampler2D gPosition; layout(binding = 1) uniform sampler2D gNormal; uniform ivec4 viewPort; uniform vec3 colour; diff --git a/gfx/gl/shaders/spotLight.fs b/gfx/gl/shaders/spotLight.fs index 78b8f72..937f922 100644 --- a/gfx/gl/shaders/spotLight.fs +++ b/gfx/gl/shaders/spotLight.fs @@ -3,7 +3,7 @@ out vec3 FragColor; -layout(binding = 0) uniform sampler2D gPosition; +layout(binding = 0) uniform isampler2D gPosition; layout(binding = 1) uniform sampler2D gNormal; uniform ivec4 viewPort; uniform vec3 colour; diff --git a/gfx/gl/shaders/water.fs b/gfx/gl/shaders/water.fs index 2ccc924..a0daa17 100644 --- a/gfx/gl/shaders/water.fs +++ b/gfx/gl/shaders/water.fs @@ -10,7 +10,7 @@ uniform vec3 waves; void main() { - gPosition = vec4(FragPos, 1); + gPosition = ivec4(FragPos, 1); gNormal = vec4(Normal, 1); gAlbedoSpec = texture(texture0, TexCoords); gAlbedoSpec.a *= clamp(-FragPos.z * .0007, .1, 1.0); diff --git a/test/test-render.cpp b/test/test-render.cpp index e2797a4..66b4d46 100644 --- a/test/test-render.cpp +++ b/test/test-render.cpp @@ -107,7 +107,7 @@ BOOST_AUTO_TEST_CASE(basic) { std::filesystem::create_directories(prefix); Texture::save(gAlbedoSpec, (prefix / "albedo.tga").c_str()); - Texture::save(gPosition, (prefix / "position.tga").c_str()); + Texture::savePosition(gPosition, (prefix / "position.tga").c_str()); Texture::saveNormal(gNormal, (prefix / "normal.tga").c_str()); Texture::save(gIllumination, (prefix / "illumination.tga").c_str()); } -- cgit v1.2.3 From 41fb7a02d7b24c88f91164670a5bf2973fd666f1 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 17 Dec 2023 12:42:41 +0000 Subject: Fix output of position data to include model position --- gfx/gl/shaders/commonPoint.glsl | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/gfx/gl/shaders/commonPoint.glsl b/gfx/gl/shaders/commonPoint.glsl index 046da27..a9817fb 100644 --- a/gfx/gl/shaders/commonPoint.glsl +++ b/gfx/gl/shaders/commonPoint.glsl @@ -16,13 +16,11 @@ getMaterialDetail(uint midx) void main() { - vec4 worldPos = model * vec4(position, 1.0); - - FragPos = worldPos.xyz; + FragPos = (model * vec4(position, 1.0)).xyz + modelPos; TexCoords = texCoord; Normal = (model * vec4(normal, 0.0)).xyz; Colour = colour; Material = getMaterialDetail(material); - gl_Position = viewProjection * vec4(FragPos - viewPoint + modelPos, 1); + gl_Position = viewProjection * vec4(FragPos - viewPoint, 1); } -- cgit v1.2.3 From 442e226dbdfbe8f281f1f23805695ebb1a5fedc3 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 17 Dec 2023 18:55:26 +0000 Subject: Add 64bit integer types for calculations --- config/types.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/config/types.h b/config/types.h index 6fc7b61..aff0390 100644 --- a/config/types.h +++ b/config/types.h @@ -6,11 +6,13 @@ using Distance = float; // deprecate using RelativeDistance = float; using GlobalDistance = int32_t; +using CalcDistance = int64_t; using Angle = float; template using Position = glm::vec; // deprecate template using RelativePosition = glm::vec; template using GlobalPosition = glm::vec; +template using CalcPosition = glm::vec; template using Size = glm::vec; template using Scale = glm::vec; template using Direction = glm::vec; @@ -27,6 +29,9 @@ using RelativePosition4D = RelativePosition<4>; using GlobalPosition2D = GlobalPosition<2>; using GlobalPosition3D = GlobalPosition<3>; using GlobalPosition4D = GlobalPosition<4>; +using CalcPosition2D = CalcPosition<2>; +using CalcPosition3D = CalcPosition<3>; +using CalcPosition4D = CalcPosition<4>; using Size2D = Size<2>; using Size3D = Size<3>; using Scale2D = Scale<2>; -- cgit v1.2.3 From f3f926c97efe365afecd54d06d830961376bae30 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 17 Dec 2023 18:56:23 +0000 Subject: Use new calc types in geoData --- game/geoData.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/game/geoData.cpp b/game/geoData.cpp index e2b7f66..97f4a26 100644 --- a/game/geoData.cpp +++ b/game/geoData.cpp @@ -120,7 +120,8 @@ namespace { [[nodiscard]] constexpr inline auto pointLineOp(const GlobalPosition2D p, const GlobalPosition2D e1, const GlobalPosition2D e2) { - return Op {}(int64_t(e2.x - e1.x) * int64_t(p.y - e1.y), int64_t(e2.y - e1.y) * int64_t(p.x - e1.x)); + return Op {}(CalcDistance(e2.x - e1.x) * CalcDistance(p.y - e1.y), + CalcDistance(e2.y - e1.y) * CalcDistance(p.x - e1.x)); } constexpr auto pointLeftOfLine = pointLineOp; @@ -159,7 +160,7 @@ namespace { constexpr GlobalPosition3D positionOnTriangle(const GlobalPosition2D point, const GeoData::Triangle<3> & t) { - const glm::vec<3, int64_t> a = t[1] - t[0], b = t[2] - t[0]; + const CalcPosition3D a = t[1] - t[0], b = t[2] - t[0]; const auto n = crossInt(a, b); return {point, ((n.x * t[0].x) + (n.y * t[0].y) + (n.z * t[0].z) - (n.x * point.x) - (n.y * point.y)) / n.z}; } -- cgit v1.2.3 From 512a47b2b8a7248b640441a828c2ea5f97dc385f Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 17 Dec 2023 18:57:15 +0000 Subject: Use new calc types in camera extents to address overflow --- gfx/gl/camera.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gfx/gl/camera.cpp b/gfx/gl/camera.cpp index ff4c91e..06e409e 100644 --- a/gfx/gl/camera.cpp +++ b/gfx/gl/camera.cpp @@ -41,9 +41,9 @@ Camera::extentsAtDist(const GlobalDistance dist) const const auto clampToSeaFloor = [this, dist](GlobalPosition3D target) -> GlobalPosition4D { target += position; if (target.z < -1500) { - const auto diff = target - position; - const auto limit = -1500 - position.z; - return {position + (limit * diff) / diff.z, (limit * dist) / diff.z}; + const CalcPosition3D diff = target - position; + const CalcDistance limit = -1500 - position.z; + return {position + GlobalPosition3D((limit * diff) / diff.z), (limit * dist) / diff.z}; } return {target, dist}; }; -- cgit v1.2.3 From edb63bcb5fd140d0d4db71e170a43f767a4b70be Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 17 Dec 2023 18:58:53 +0000 Subject: Run shadow mapper in camera relative space --- gfx/gl/sceneRenderer.cpp | 10 ++++++---- gfx/gl/sceneRenderer.h | 8 ++++---- gfx/gl/shaders/directionalLight.fs | 7 ++++--- gfx/gl/shadowMapper.cpp | 16 ++++++++-------- 4 files changed, 22 insertions(+), 19 deletions(-) diff --git a/gfx/gl/sceneRenderer.cpp b/gfx/gl/sceneRenderer.cpp index 2854dea..c856279 100644 --- a/gfx/gl/sceneRenderer.cpp +++ b/gfx/gl/sceneRenderer.cpp @@ -116,7 +116,7 @@ SceneRenderer::setDirectionalLight(const RGB & colour, const Direction3D & direc glBindFramebuffer(GL_FRAMEBUFFER, gBufferIll); glViewport(0, 0, size.x, size.y); dirLight.use(); - dirLight.setDirectionalLight(colour, direction, lvp.projections, lvp.regions, lvp.maps); + dirLight.setDirectionalLight(colour, direction, camera.getPosition(), lvp.projections, lvp.regions, lvp.maps); renderQuad(); } } @@ -131,7 +131,8 @@ SceneRenderer::renderQuad() const SceneRenderer::DirectionalLightProgram::DirectionalLightProgram() : Program {lighting_vs, directionalLight_fs}, directionLoc {*this, "lightDirection"}, - colourLoc {*this, "lightColour"}, lightViewProjectionLoc {*this, "lightViewProjection"}, + colourLoc {*this, "lightColour"}, lightPointLoc {*this, "lightPoint"}, + lightViewProjectionLoc {*this, "lightViewProjection"}, lightViewProjectionCountLoc {*this, "lightViewProjectionCount"}, lightViewShadowMapRegionLoc {*this, "shadowMapRegion"} { @@ -139,12 +140,13 @@ SceneRenderer::DirectionalLightProgram::DirectionalLightProgram() : void SceneRenderer::DirectionalLightProgram::setDirectionalLight(const RGB & c, const Direction3D & d, - const std::span lvp, const std::span shadowMapRegions, - std::size_t maps) const + const GlobalPosition3D & p, const std::span lvp, + const std::span shadowMapRegions, std::size_t maps) const { glUniform3fv(colourLoc, 1, glm::value_ptr(c)); const auto nd = glm::normalize(d); glUniform3fv(directionLoc, 1, glm::value_ptr(nd)); + glUniform3iv(lightPointLoc, 1, glm::value_ptr(p)); glUniform1ui(lightViewProjectionCountLoc, static_cast(maps)); glUniformMatrix4fv(lightViewProjectionLoc, static_cast(maps), GL_FALSE, glm::value_ptr(lvp.front())); glUniform4fv(lightViewShadowMapRegionLoc, static_cast(maps), glm::value_ptr(shadowMapRegions.front())); diff --git a/gfx/gl/sceneRenderer.h b/gfx/gl/sceneRenderer.h index c935f93..797ecf1 100644 --- a/gfx/gl/sceneRenderer.h +++ b/gfx/gl/sceneRenderer.h @@ -39,12 +39,12 @@ protected: DirectionalLightProgram(); using Program::use; - void setDirectionalLight(const RGB &, const Direction3D &, const std::span, - const std::span, std::size_t maps) const; + void setDirectionalLight(const RGB &, const Direction3D &, const GlobalPosition3D &, + const std::span, const std::span, std::size_t maps) const; private: - RequiredUniformLocation directionLoc, colourLoc, lightViewProjectionLoc, lightViewProjectionCountLoc, - lightViewShadowMapRegionLoc; + RequiredUniformLocation directionLoc, colourLoc, lightPointLoc, lightViewProjectionLoc, + lightViewProjectionCountLoc, lightViewShadowMapRegionLoc; }; DeferredLightProgram lighting; diff --git a/gfx/gl/shaders/directionalLight.fs b/gfx/gl/shaders/directionalLight.fs index 3756db7..f36d83f 100644 --- a/gfx/gl/shaders/directionalLight.fs +++ b/gfx/gl/shaders/directionalLight.fs @@ -13,6 +13,7 @@ layout(binding = 2) uniform sampler2D shadowMap; uniform vec3 lightDirection; uniform vec3 lightColour; +uniform ivec3 lightPoint; uniform mat4 lightViewProjection[MAX_MAPS]; uniform vec4 shadowMapRegion[MAX_MAPS]; uniform uint lightViewProjectionCount; @@ -27,10 +28,10 @@ insideShadowCube(vec3 v) } float -isShaded(ivec3 Position) +isShaded(vec4 Position) { for (uint m = 0u; m < lightViewProjectionCount; m++) { - vec3 PositionInLightSpace = (lightViewProjection[m] * vec4(Position, 1.0f)).xyz; + const vec3 PositionInLightSpace = (lightViewProjection[m] * Position).xyz; const float inside = insideShadowCube(PositionInLightSpace); if (inside > 0) { const float lightSpaceDepth @@ -44,7 +45,7 @@ isShaded(ivec3 Position) void main() { - const ivec3 Position = texture(gPosition, TexCoords).xyz; + const vec4 Position = vec4(texture(gPosition, TexCoords).xyz - lightPoint, 1); const vec3 Normal = texture(gNormal, TexCoords).rgb; const float shaded = isShaded(Position); FragColor = (1 - shaded) * max(dot(-lightDirection, Normal) * lightColour, 0); diff --git a/gfx/gl/shadowMapper.cpp b/gfx/gl/shadowMapper.cpp index deb0630..74d93bd 100644 --- a/gfx/gl/shadowMapper.cpp +++ b/gfx/gl/shadowMapper.cpp @@ -106,14 +106,15 @@ struct DefinitionsInserter { }; std::vector> -ShadowMapper::getBandViewExtents(const Camera & camera, const glm::mat4 & lightView) +ShadowMapper::getBandViewExtents(const Camera & camera, const glm::mat4 & lightViewDir) { std::vector> bandViewExtents; for (const auto dist : shadowBands) { const auto extents = camera.extentsAtDist(dist); - bandViewExtents.emplace_back(extents * [&lightView](const auto & e) -> Position3D { - return lightView * glm::vec4(Position3D {e}, 1); - }); + bandViewExtents.emplace_back( + extents * [&lightViewDir, cameraPos = camera.getPosition()](const auto & e) -> Position3D { + return lightViewDir * RelativePosition4D(e.xyz() - cameraPos, 1); + }); if (std::none_of(extents.begin(), extents.end(), [targetDist = dist - 1](const auto & e) { return e.w > targetDist; })) { @@ -131,14 +132,13 @@ ShadowMapper::update(const SceneProvider & scene, const Direction3D & dir, const glCullFace(GL_FRONT); const auto lightViewDir = glm::lookAt(origin, dir, up); - const auto lightView = lightViewDir * glm::translate(RelativePosition3D {-camera.getPosition()}); const auto lightViewPoint = camera.getPosition(); - const auto bandViewExtents = getBandViewExtents(camera, lightView); + const auto bandViewExtents = getBandViewExtents(camera, lightViewDir); Definitions out; std::transform(bandViewExtents.begin(), std::prev(bandViewExtents.end()), std::next(bandViewExtents.begin()), DefinitionsInserter {out}, - [&scene, this, &lightView, bands = bandViewExtents.size() - 2, &out, &lightViewPoint, &lightViewDir]( + [&scene, this, bands = bandViewExtents.size() - 2, &out, &lightViewPoint, &lightViewDir]( const auto & near, const auto & far) { const auto extents_minmax = [extents = std::span {near.begin(), far.end()}](auto && comp) { const auto mm = std::minmax_element(extents.begin(), extents.end(), comp); @@ -158,7 +158,7 @@ ShadowMapper::update(const SceneProvider & scene, const Direction3D & dir, const glViewport(size.x >> viewport.x, size.y >> viewport.y, size.x >> viewport.z, size.y >> viewport.w); scene.shadows(*this); - return std::make_pair(lightProjection * lightView, shadowMapRegions[bands][out.maps]); + return std::make_pair(lightViewDirProjection, shadowMapRegions[bands][out.maps]); }); glCullFace(GL_BACK); -- cgit v1.2.3 From 0841ead91c49a212134f19f7c0b411984b0fda29 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 29 Dec 2023 13:20:55 +0000 Subject: Remove weird operator! on vec2/3 --- game/network/link.cpp | 2 +- game/network/network.cpp | 4 ++-- game/network/rail.cpp | 4 ++-- gfx/followCameraController.cpp | 2 +- lib/maths.cpp | 2 +- lib/maths.h | 12 ------------ ui/manualCameraController.cpp | 2 +- 7 files changed, 8 insertions(+), 20 deletions(-) diff --git a/game/network/link.cpp b/game/network/link.cpp index 498afe4..d8479dd 100644 --- a/game/network/link.cpp +++ b/game/network/link.cpp @@ -46,7 +46,7 @@ LinkCurve::positionAt(float dist, unsigned char start) const const auto es {std::make_pair(ends[start].node.get(), ends[1 - start].node.get())}; const auto as {std::make_pair(arc[start], arc[1 - start])}; const auto ang {as.first + ((as.second - as.first) * frac)}; - const auto relPos {!sincosf(ang) * radius}; + const auto relPos {sincosf(ang) ^ 0.F * radius}; const auto relClimb {vehiclePositionOffset() + Position3D {0, 0, es.first->pos.z - centreBase.z + ((es.second->pos.z - es.first->pos.z) * frac)}}; const auto pitch {vector_pitch({0, 0, (es.second->pos.z - es.first->pos.z) / length})}; diff --git a/game/network/network.cpp b/game/network/network.cpp index d18345c..5de2f5d 100644 --- a/game/network/network.cpp +++ b/game/network/network.cpp @@ -100,7 +100,7 @@ Network::genCurveDef(const Position3D & start, const Position3D & end, float sta const auto diff {end - start}; const auto vy {vector_yaw(diff)}; const auto dir = pi + startDir; - const auto flatStart {!start}, flatEnd {!end}; + const auto flatStart {start.xy()}, flatEnd {end.xy()}; const auto n2ed {(vy * 2) - dir - pi}; const auto centre {find_arc_centre(flatStart, dir, flatEnd, n2ed)}; @@ -115,7 +115,7 @@ Network::genCurveDef(const Position3D & start, const Position3D & end, float sta { startDir += pi; endDir += pi; - const Position2D flatStart {!start}, flatEnd {!end}; + const Position2D flatStart {start.xy()}, flatEnd {end.xy()}; auto midheight = [&](auto mid) { const auto sm = glm::distance(flatStart, mid), em = glm::distance(flatEnd, mid); return start.z + ((end.z - start.z) * (sm / (sm + em))); diff --git a/game/network/rail.cpp b/game/network/rail.cpp index ff101d4..545a728 100644 --- a/game/network/rail.cpp +++ b/game/network/rail.cpp @@ -45,7 +45,7 @@ RailLinks::addLinksBetween(Position3D start, Position3D end) if (dir == vector_yaw(end - start)) { return addLink(start, end); } - const Position2D flatStart {!start}, flatEnd {!end}; + const Position2D flatStart {start.xy()}, flatEnd {end.xy()}; if (node2ins.second == NodeIs::InNetwork) { auto midheight = [&](auto mid) { const auto sm = glm::distance(flatStart, mid), em = glm::distance(flatEnd, mid); @@ -142,7 +142,7 @@ RailLinkStraight::RailLinkStraight(Node::Ptr a, Node::Ptr b, const Position3D & } RailLinkCurve::RailLinkCurve(const Node::Ptr & a, const Node::Ptr & b, Position2D c) : - RailLinkCurve(a, b, c ^ a->pos.z, {!c, a->pos, b->pos}) + RailLinkCurve(a, b, c ^ a->pos.z, {c ^ 0.F, a->pos, b->pos}) { } diff --git a/gfx/followCameraController.cpp b/gfx/followCameraController.cpp index aee2187..9b23173 100644 --- a/gfx/followCameraController.cpp +++ b/gfx/followCameraController.cpp @@ -24,7 +24,7 @@ FollowCameraController::updateCamera(Camera * camera) const break; case Mode::Ride: - camera->setView(pos + GlobalPosition3D(up * 4.8F), !-sincosf(rot.y)); + camera->setView(pos + GlobalPosition3D(up * 4.8F), -sincosf(rot.y) ^ 0.F); break; case Mode::ISO: diff --git a/lib/maths.cpp b/lib/maths.cpp index 5430ef6..0c25820 100644 --- a/lib/maths.cpp +++ b/lib/maths.cpp @@ -9,7 +9,7 @@ glm::mat4 flat_orientation(const Direction3D & diff) { static const auto oneeighty {glm::rotate(pi, up)}; - const auto flatdiff {glm::normalize(!!diff)}; + const auto flatdiff {glm::normalize(diff.xy() ^ 0.F)}; auto e {glm::orientation(flatdiff, north)}; // Handle if diff is exactly opposite to north return (std::isnan(e[0][0])) ? oneeighty : e; diff --git a/lib/maths.h b/lib/maths.h index cf369a7..dd83c4b 100644 --- a/lib/maths.h +++ b/lib/maths.h @@ -99,12 +99,6 @@ perspective_divide(glm::vec<4, T, Q> v) return v / v.w; } -constexpr inline Position2D -operator!(const Position3D & v) -{ - return {v.x, v.y}; -} - constexpr inline Position3D operator^(const Position2D & v, float z) { @@ -117,12 +111,6 @@ operator^(const Position3D & v, float w) return {v.x, v.y, v.z, w}; } -constexpr inline Position3D -operator!(const Position2D & v) -{ - return v ^ 0.F; -} - template inline constexpr glm::vec operator||(const glm::vec v1, const glm::vec v2) diff --git a/ui/manualCameraController.cpp b/ui/manualCameraController.cpp index f6993a8..1f6b510 100644 --- a/ui/manualCameraController.cpp +++ b/ui/manualCameraController.cpp @@ -79,5 +79,5 @@ void ManualCameraController::updateCamera(Camera * camera) const { const auto forward = glm::normalize(sincosf(direction) ^ -sin(pitch)); - camera->setView(!focus - forward * 3.F * std::pow(dist, 1.3F), forward); + camera->setView((focus ^ 0.F) - forward * 3.F * std::pow(dist, 1.3F), forward); } -- cgit v1.2.3 From 048f18e2a0b32044525cef41fa053984433c74b9 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 29 Dec 2023 14:12:40 +0000 Subject: Remove misleading power operator^ on vec2/3 --- assetFactory/cylinder.cpp | 6 +++--- game/network/link.cpp | 2 +- game/network/network.cpp | 4 ++-- game/network/rail.cpp | 10 +++++----- gfx/followCameraController.cpp | 2 +- gfx/gl/camera.cpp | 2 +- lib/maths.cpp | 2 +- lib/maths.h | 24 +++++++----------------- ui/manualCameraController.cpp | 4 ++-- 9 files changed, 23 insertions(+), 33 deletions(-) diff --git a/assetFactory/cylinder.cpp b/assetFactory/cylinder.cpp index ed034fd..58980cf 100644 --- a/assetFactory/cylinder.cpp +++ b/assetFactory/cylinder.cpp @@ -19,7 +19,7 @@ Cylinder::createMesh(ModelFactoryMesh & mesh, float lodf) const // Generate bottom face vertices std::vector bottom(P); std::transform(circumference.begin(), circumference.end(), bottom.begin(), [&mesh](const auto & xy) { - return mesh.add_vertex(xy ^ 0.F); + return mesh.add_vertex(xy || 0.F); }); surface.insert(mesh.add_namedFace("bottom", bottom)); } @@ -27,7 +27,7 @@ Cylinder::createMesh(ModelFactoryMesh & mesh, float lodf) const // Generate top face vertices std::vector top(P); std::transform(circumference.rbegin(), circumference.rend(), top.begin(), [&mesh](const auto & xy) { - return mesh.add_vertex(xy ^ 1); + return mesh.add_vertex(xy || 1.F); }); surface.insert(mesh.add_namedFace("top", top)); } @@ -35,7 +35,7 @@ Cylinder::createMesh(ModelFactoryMesh & mesh, float lodf) const // Generate edge vertices std::vector> edge(P + 1); std::transform(circumference.begin(), circumference.end(), edge.begin(), [&mesh](const auto & xy) { - return std::make_pair(mesh.add_vertex(xy ^ 0), mesh.add_vertex(xy ^ 1)); + return std::make_pair(mesh.add_vertex(xy || 0.F), mesh.add_vertex(xy || 1.F)); }); // Wrap around edge.back() = edge.front(); diff --git a/game/network/link.cpp b/game/network/link.cpp index d8479dd..703a1ca 100644 --- a/game/network/link.cpp +++ b/game/network/link.cpp @@ -46,7 +46,7 @@ LinkCurve::positionAt(float dist, unsigned char start) const const auto es {std::make_pair(ends[start].node.get(), ends[1 - start].node.get())}; const auto as {std::make_pair(arc[start], arc[1 - start])}; const auto ang {as.first + ((as.second - as.first) * frac)}; - const auto relPos {sincosf(ang) ^ 0.F * radius}; + const auto relPos {(sincosf(ang) || 0.F) * radius}; const auto relClimb {vehiclePositionOffset() + Position3D {0, 0, es.first->pos.z - centreBase.z + ((es.second->pos.z - es.first->pos.z) * frac)}}; const auto pitch {vector_pitch({0, 0, (es.second->pos.z - es.first->pos.z) / length})}; diff --git a/game/network/network.cpp b/game/network/network.cpp index 5de2f5d..1ff5b26 100644 --- a/game/network/network.cpp +++ b/game/network/network.cpp @@ -125,7 +125,7 @@ Network::genCurveDef(const Position3D & start, const Position3D & end, float sta const auto c1 = flatStart + sincosf(startDir + half_pi) * radius; const auto c2 = flatEnd + sincosf(endDir + half_pi) * radius; const auto mid = (c1 + c2) / 2.F; - const auto midh = mid ^ midheight(mid); + const auto midh = mid || midheight(mid); return {{start, midh, c1}, {end, midh, c2}}; } else { @@ -133,7 +133,7 @@ Network::genCurveDef(const Position3D & start, const Position3D & end, float sta const auto c1 = flatStart + sincosf(startDir - half_pi) * radius; const auto c2 = flatEnd + sincosf(endDir - half_pi) * radius; const auto mid = (c1 + c2) / 2.F; - const auto midh = mid ^ midheight(mid); + const auto midh = mid || midheight(mid); return {{midh, start, c1}, {midh, end, c2}}; } } diff --git a/game/network/rail.cpp b/game/network/rail.cpp index 545a728..303f1c8 100644 --- a/game/network/rail.cpp +++ b/game/network/rail.cpp @@ -57,7 +57,7 @@ RailLinks::addLinksBetween(Position3D start, Position3D end) const auto c1 = flatStart + sincosf(dir + half_pi) * radius; const auto c2 = flatEnd + sincosf(dir2 + half_pi) * radius; const auto mid = (c1 + c2) / 2.F; - const auto midh = mid ^ midheight(mid); + const auto midh = mid || midheight(mid); addLink(start, midh, c1); return addLink(end, midh, c2); } @@ -66,7 +66,7 @@ RailLinks::addLinksBetween(Position3D start, Position3D end) const auto c1 = flatStart + sincosf(dir - half_pi) * radius; const auto c2 = flatEnd + sincosf(dir2 - half_pi) * radius; const auto mid = (c1 + c2) / 2.F; - const auto midh = mid ^ midheight(mid); + const auto midh = mid || midheight(mid); addLink(midh, start, c1); return addLink(midh, end, c2); } @@ -133,7 +133,7 @@ RailLinkStraight::RailLinkStraight(Node::Ptr a, Node::Ptr b, const Position3D & for (auto ei : {1U, 0U}) { const auto trans {glm::translate(ends[ei].node->pos) * e}; for (const auto & rcs : railCrossSection) { - const Position3D m {(trans * (rcs.first ^ 1))}; + const Position3D m {(trans * (rcs.first || 1.F))}; vertices.emplace_back(m, Position2D {rcs.second, len * static_cast(ei)}, up); } } @@ -142,7 +142,7 @@ RailLinkStraight::RailLinkStraight(Node::Ptr a, Node::Ptr b, const Position3D & } RailLinkCurve::RailLinkCurve(const Node::Ptr & a, const Node::Ptr & b, Position2D c) : - RailLinkCurve(a, b, c ^ a->pos.z, {c ^ 0.F, a->pos, b->pos}) + RailLinkCurve(a, b, c || a->pos.z, {c || 0.F, a->pos, b->pos}) { } @@ -166,7 +166,7 @@ RailLinkCurve::RailLinkCurve(const Node::Ptr & a, const Node::Ptr & b, Position3 const auto t { trans * glm::rotate(half_pi - swing.x, up) * glm::translate(Position3D {radius, 0.F, swing.y})}; for (const auto & rcs : railCrossSection) { - const Position3D m {(t * (rcs.first ^ 1))}; + const Position3D m {(t * (rcs.first || 1.F))}; vertices.emplace_back(m, Position2D {rcs.second, swing.z}, up); } } diff --git a/gfx/followCameraController.cpp b/gfx/followCameraController.cpp index 9b23173..5114840 100644 --- a/gfx/followCameraController.cpp +++ b/gfx/followCameraController.cpp @@ -24,7 +24,7 @@ FollowCameraController::updateCamera(Camera * camera) const break; case Mode::Ride: - camera->setView(pos + GlobalPosition3D(up * 4.8F), -sincosf(rot.y) ^ 0.F); + camera->setView(pos + GlobalPosition3D(up * 4.8F), -sincosf(rot.y) || 0.F); break; case Mode::ISO: diff --git a/gfx/gl/camera.cpp b/gfx/gl/camera.cpp index 06e409e..9f40998 100644 --- a/gfx/gl/camera.cpp +++ b/gfx/gl/camera.cpp @@ -18,7 +18,7 @@ Camera::unProject(const ScreenRelCoord & mouse) const { static constexpr const glm::vec4 screen {0, 0, 1, 1}; const auto mouseProjection = glm::lookAt(::origin, forward, up); - return {position, glm::normalize(glm::unProject(mouse ^ 1, mouseProjection, projection, screen))}; + return {position, glm::normalize(glm::unProject(mouse || 1.F, mouseProjection, projection, screen))}; } void diff --git a/lib/maths.cpp b/lib/maths.cpp index 0c25820..17082d4 100644 --- a/lib/maths.cpp +++ b/lib/maths.cpp @@ -9,7 +9,7 @@ glm::mat4 flat_orientation(const Direction3D & diff) { static const auto oneeighty {glm::rotate(pi, up)}; - const auto flatdiff {glm::normalize(diff.xy() ^ 0.F)}; + const auto flatdiff {glm::normalize(diff.xy() || 0.F)}; auto e {glm::orientation(flatdiff, north)}; // Handle if diff is exactly opposite to north return (std::isnan(e[0][0])) ? oneeighty : e; diff --git a/lib/maths.h b/lib/maths.h index dd83c4b..f7ff148 100644 --- a/lib/maths.h +++ b/lib/maths.h @@ -99,18 +99,6 @@ perspective_divide(glm::vec<4, T, Q> v) return v / v.w; } -constexpr inline Position3D -operator^(const Position2D & v, float z) -{ - return {v.x, v.y, z}; -} - -constexpr inline glm::vec4 -operator^(const Position3D & v, float w) -{ - return {v.x, v.y, v.z, w}; -} - template inline constexpr glm::vec operator||(const glm::vec v1, const glm::vec v2) @@ -125,15 +113,17 @@ operator||(const glm::vec v1, const T v2) return {v1, v2}; } -inline Position3D -operator%(const Position3D & p, const glm::mat4 & mutation) +template +inline constexpr glm::vec +operator%(const glm::vec & p, const glm::mat & mutation) { - const auto p2 = mutation * (p ^ 1); + const auto p2 = mutation * (p || T(1)); return p2 / p2.w; } -inline Position3D -operator%=(Position3D & p, const glm::mat4 & mutation) +template +inline constexpr glm::vec +operator%=(glm::vec & p, const glm::mat & mutation) { return p = p % mutation; } diff --git a/ui/manualCameraController.cpp b/ui/manualCameraController.cpp index 1f6b510..ef26e81 100644 --- a/ui/manualCameraController.cpp +++ b/ui/manualCameraController.cpp @@ -78,6 +78,6 @@ ManualCameraController::render(const UIShader &, const Position &) const void ManualCameraController::updateCamera(Camera * camera) const { - const auto forward = glm::normalize(sincosf(direction) ^ -sin(pitch)); - camera->setView((focus ^ 0.F) - forward * 3.F * std::pow(dist, 1.3F), forward); + const auto forward = glm::normalize(sincosf(direction) || -sin(pitch)); + camera->setView((focus || 0.F) - forward * 3.F * std::pow(dist, 1.3F), forward); } -- cgit v1.2.3 From dc672a3488ec1d665fa898ced401e40ebc609bf8 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 29 Dec 2023 16:46:48 +0000 Subject: Templatise functions in maths.h using PositionND --- lib/maths.cpp | 72 --------------------------------------------- lib/maths.h | 84 ++++++++++++++++++++++++++++++++++++++++++++++++----- test/test-maths.cpp | 3 +- 3 files changed, 79 insertions(+), 80 deletions(-) diff --git a/lib/maths.cpp b/lib/maths.cpp index 17082d4..68662fc 100644 --- a/lib/maths.cpp +++ b/lib/maths.cpp @@ -3,7 +3,6 @@ #include #include #include -#include glm::mat4 flat_orientation(const Direction3D & diff) @@ -106,77 +105,6 @@ normalize(float ang) return ang; } -Arc::Arc(const Position3D & centre3, const Position3D & e0p, const Position3D & e1p) : - Arc([&]() -> Arc { - const auto diffa = e0p - centre3; - const auto diffb = e1p - centre3; - const auto anga = vector_yaw(diffa); - const auto angb = [&diffb, &anga]() { - const auto angb = vector_yaw(diffb); - return (angb < anga) ? angb + two_pi : angb; - }(); - return {anga, angb}; - }()) -{ -} - -std::pair -find_arc_centre(Position2D as, float entrys, Position2D bs, float entrye) -{ - if (as == bs) { - return {as, false}; - } - return find_arc_centre(as, sincosf(entrys + half_pi), bs, sincosf(entrye - half_pi)); -} - -std::pair -find_arc_centre(Position2D as, Position2D ad, Position2D bs, Position2D bd) -{ - const auto det = bd.x * ad.y - bd.y * ad.x; - if (det != 0) { // near parallel line will yield noisy results - const auto d = bs - as; - const auto u = (d.y * bd.x - d.x * bd.y) / det; - return {as + ad * u, u < 0}; - } - throw std::runtime_error("no intersection"); -} - -std::pair -find_arcs_radius(Position2D start, float entrys, Position2D end, float entrye) -{ - const auto getrad = [&](float leftOrRight) { - return find_arcs_radius(start, sincosf(entrys + leftOrRight), end, sincosf(entrye + leftOrRight)); - }; - return {getrad(-half_pi), getrad(half_pi)}; -} - -float -find_arcs_radius(Position2D start, Position2D ad, Position2D end, Position2D bd) -{ - // Short name functions for big forula - auto sqrt = [](float v) { - return std::sqrt(v); - }; - - // Calculates path across both arcs along the normals... pythagorean theorem... for some known radius r - // (2r)^2 = ((m + (X*r)) - (o + (Z*r)))^2 + ((n + (Y*r)) - (p + (W*r)))^2 - // According to symbolabs.com equation tool, that solves for r to give: - // r=(-2 m X+2 X o+2 m Z-2 o Z-2 n Y+2 Y p+2 n W-2 p W-sqrt((2 m X-2 X o-2 m Z+2 o Z+2 n Y-2 Y p-2 n W+2 p W)^(2)-4 - // (X^(2)-2 X Z+Z^(2)+Y^(2)-2 Y W+W^(2)-4) (m^(2)-2 m o+o^(2)+n^(2)-2 n p+p^(2))))/(2 (X^(2)-2 X Z+Z^(2)+Y^(2)-2 Y - // W+W^(2)-4)) - - // These exist cos limitations of online formula rearrangement, and I'm OK with that. - const auto &m {start.x}, &n {start.y}, &o {end.x}, &p {end.y}; - const auto &X {ad.x}, &Y {ad.y}, &Z {bd.x}, &W {bd.y}; - - return (2 * m * X - 2 * X * o - 2 * m * Z + 2 * o * Z + 2 * n * Y - 2 * Y * p - 2 * n * W + 2 * p * W - - sqrt(sq(-2 * m * X + 2 * X * o + 2 * m * Z - 2 * o * Z - 2 * n * Y + 2 * Y * p + 2 * n * W - - 2 * p * W) - - (4 * (sq(X) - 2 * X * Z + sq(Z) + sq(Y) - 2 * Y * W + sq(W) - 4) - * (sq(m) - 2 * m * o + sq(o) + sq(n) - 2 * n * p + sq(p))))) - / (2 * (sq(X) - 2 * X * Z + sq(Z) + sq(Y) - 2 * Y * W + sq(W) - 4)); -} - float operator"" _mph(const long double v) { diff --git a/lib/maths.h b/lib/maths.h index f7ff148..ba8c0e6 100644 --- a/lib/maths.h +++ b/lib/maths.h @@ -5,15 +5,17 @@ #include #include #include +#include #include struct Arc : public std::pair { using std::pair::pair; - Arc(const Position3D & centre3, const Position3D & e0p, const Position3D & e1p); + template + Arc(const glm::vec<3, T, Q> & centre3, const glm::vec<3, T, Q> & e0p, const glm::vec<3, T, Q> & e1p); - float - operator[](unsigned int i) const + auto + operator[](bool i) const { return i ? second : first; } @@ -136,10 +138,63 @@ arc_length(const Arc & arc) float normalize(float ang); -std::pair find_arc_centre(Position2D start, float entrys, Position2D end, float entrye); -std::pair find_arc_centre(Position2D start, Position2D ad, Position2D end, Position2D bd); -std::pair find_arcs_radius(Position2D start, float entrys, Position2D end, float entrye); -float find_arcs_radius(Position2D start, Position2D ad, Position2D end, Position2D bd); +template +std::pair, bool> +find_arc_centre(glm::vec<2, T, Q> start, Rotation2D startDir, glm::vec<2, T, Q> end, Rotation2D endDir) +{ + const auto det = endDir.x * startDir.y - endDir.y * startDir.x; + if (det != 0) { // near parallel line will yield noisy results + const auto d = end - start; + const auto u = (d.y * endDir.x - d.x * endDir.y) / det; + return {start + startDir * u, u < 0}; + } + throw std::runtime_error("no intersection"); +} + +template +std::pair, bool> +find_arc_centre(glm::vec<2, T, Q> start, Angle entrys, glm::vec<2, T, Q> end, Angle entrye) +{ + if (start == end) { + return {start, false}; + } + return find_arc_centre(start, sincosf(entrys + half_pi), end, sincosf(entrye - half_pi)); +} + +template +Angle +find_arcs_radius(glm::vec<2, T, Q> start, Rotation2D ad, glm::vec<2, T, Q> end, Rotation2D bd) +{ + using std::sqrt; + + // Calculates path across both arcs along the normals... pythagorean theorem... for some known radius r + // (2r)^2 = ((m + (X*r)) - (o + (Z*r)))^2 + ((n + (Y*r)) - (p + (W*r)))^2 + // According to symbolabs.com equation tool, that solves for r to give: + // r=(-2 m X+2 X o+2 m Z-2 o Z-2 n Y+2 Y p+2 n W-2 p W-sqrt((2 m X-2 X o-2 m Z+2 o Z+2 n Y-2 Y p-2 n W+2 p W)^(2)-4 + // (X^(2)-2 X Z+Z^(2)+Y^(2)-2 Y W+W^(2)-4) (m^(2)-2 m o+o^(2)+n^(2)-2 n p+p^(2))))/(2 (X^(2)-2 X Z+Z^(2)+Y^(2)-2 Y + // W+W^(2)-4)) + + // These exist cos limitations of online formula rearrangement, and I'm OK with that. + const auto &m {start.x}, &n {start.y}, &o {end.x}, &p {end.y}; + const auto &X {ad.x}, &Y {ad.y}, &Z {bd.x}, &W {bd.y}; + + return (2 * m * X - 2 * X * o - 2 * m * Z + 2 * o * Z + 2 * n * Y - 2 * Y * p - 2 * n * W + 2 * p * W + - sqrt(sq(-2 * m * X + 2 * X * o + 2 * m * Z - 2 * o * Z - 2 * n * Y + 2 * Y * p + 2 * n * W + - 2 * p * W) + - (4 * (sq(X) - 2 * X * Z + sq(Z) + sq(Y) - 2 * Y * W + sq(W) - 4) + * (sq(m) - 2 * m * o + sq(o) + sq(n) - 2 * n * p + sq(p))))) + / (2 * (sq(X) - 2 * X * Z + sq(Z) + sq(Y) - 2 * Y * W + sq(W) - 4)); +} + +template +std::pair +find_arcs_radius(glm::vec<2, T, Q> start, Angle entrys, glm::vec<2, T, Q> end, Angle entrye) +{ + const auto getrad = [&](auto leftOrRight) { + return find_arcs_radius(start, sincosf(entrys + leftOrRight), end, sincosf(entrye + leftOrRight)); + }; + return {getrad(-half_pi), getrad(half_pi)}; +} template auto @@ -148,6 +203,21 @@ midpoint(const std::pair & v) return std::midpoint(v.first, v.second); } +template +Arc::Arc(const glm::vec<3, T, Q> & centre3, const glm::vec<3, T, Q> & e0p, const glm::vec<3, T, Q> & e1p) : + Arc([&]() -> Arc { + const auto diffa = e0p - centre3; + const auto diffb = e1p - centre3; + const auto anga = vector_yaw(diffa); + const auto angb = [&diffb, &anga]() { + const auto angb = vector_yaw(diffb); + return (angb < anga) ? angb + two_pi : angb; + }(); + return {anga, angb}; + }()) +{ +} + // Conversions template inline constexpr auto diff --git a/test/test-maths.cpp b/test/test-maths.cpp index 3f8c2a0..ede884d 100644 --- a/test/test-maths.cpp +++ b/test/test-maths.cpp @@ -171,7 +171,8 @@ BOOST_DATA_TEST_CASE(test_find_arc_centre, BOOST_AUTO_TEST_CASE(test_find_arcs_radius) { - BOOST_CHECK_CLOSE(find_arcs_radius({10.32, 26.71}, {0.4, .92}, {2.92, 22.41}, {-0.89, -0.45}), 2.29, 1); + BOOST_CHECK_CLOSE( + find_arcs_radius(RelativePosition2D {10.32, 26.71}, {0.4, .92}, {2.92, 22.41}, {-0.89, -0.45}), 2.29, 1); } struct TestLinkStraight : public LinkStraight { -- cgit v1.2.3 From 8635bb43078dec951da63e3a4442f6a2f70ac686 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 1 Jan 2024 11:36:26 +0000 Subject: Simplify and 'fix' the wave cycle --- gfx/gl/sceneShader.cpp | 3 +-- gfx/gl/shaders/water.fs | 1 - gfx/gl/shaders/water.vs | 6 +++--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/gfx/gl/sceneShader.cpp b/gfx/gl/sceneShader.cpp index 57c8bb7..ccc1a1d 100644 --- a/gfx/gl/sceneShader.cpp +++ b/gfx/gl/sceneShader.cpp @@ -85,8 +85,7 @@ void SceneShader::WaterProgram::use(float waveCycle) const { Program::use(); - Position3D waves {waveCycle, 0.F, 0.F}; - glUniform3fv(waveLoc, 1, glm::value_ptr(waves)); + glUniform1f(waveLoc, waveCycle); } SceneShader::PointLightShader::PointLightShader() : diff --git a/gfx/gl/shaders/water.fs b/gfx/gl/shaders/water.fs index a0daa17..8891733 100644 --- a/gfx/gl/shaders/water.fs +++ b/gfx/gl/shaders/water.fs @@ -5,7 +5,6 @@ include(`materialInterface.glsl') include(`materialOut.glsl') uniform sampler2D texture0; -uniform vec3 waves; void main() diff --git a/gfx/gl/shaders/water.vs b/gfx/gl/shaders/water.vs index f609d9e..f6c7c8f 100644 --- a/gfx/gl/shaders/water.vs +++ b/gfx/gl/shaders/water.vs @@ -5,13 +5,13 @@ include(`materialInterface.glsl') uniform mat4 viewProjection; uniform ivec3 viewPoint; -uniform vec3 waves; +uniform float waves; void main() { - vec3 wpos = vec3(position.x + (cos(waves.x) * 1000.0), position.y + (cos(waves.x * waves.y / 2) * 1000.0), - cos(waves.x + (position.x / 1000.0) + (position.y * 125.0)) * 300.0); + vec3 wpos = vec3(position.x + (cos(waves) * 1000.0), position.y + (cos(waves * 0 / 2) * 1000.0), + cos(waves + (position.x / 1000000.0) + (position.y / 8000.0)) * 300.0); FragPos = vec3(wpos.xy, position.z); TexCoords = texCoord; -- cgit v1.2.3 From fe8f9775cce008465fcca2d6783bd7be0d64f77c Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 1 Jan 2024 11:49:46 +0000 Subject: Remove legacy Position types from shadowMapper --- gfx/gl/shadowMapper.cpp | 11 +++++------ gfx/gl/shadowMapper.h | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/gfx/gl/shadowMapper.cpp b/gfx/gl/shadowMapper.cpp index 74d93bd..6c8400e 100644 --- a/gfx/gl/shadowMapper.cpp +++ b/gfx/gl/shadowMapper.cpp @@ -105,16 +105,15 @@ struct DefinitionsInserter { ShadowMapper::Definitions & out; }; -std::vector> +std::vector> ShadowMapper::getBandViewExtents(const Camera & camera, const glm::mat4 & lightViewDir) { - std::vector> bandViewExtents; + std::vector> bandViewExtents; for (const auto dist : shadowBands) { const auto extents = camera.extentsAtDist(dist); - bandViewExtents.emplace_back( - extents * [&lightViewDir, cameraPos = camera.getPosition()](const auto & e) -> Position3D { - return lightViewDir * RelativePosition4D(e.xyz() - cameraPos, 1); - }); + bandViewExtents.emplace_back(extents * [&lightViewDir, cameraPos = camera.getPosition()](const auto & e) { + return glm::mat3(lightViewDir) * (e.xyz() - cameraPos); + }); if (std::none_of(extents.begin(), extents.end(), [targetDist = dist - 1](const auto & e) { return e.w > targetDist; })) { diff --git a/gfx/gl/shadowMapper.h b/gfx/gl/shadowMapper.h index 01520ca..bf571f8 100644 --- a/gfx/gl/shadowMapper.h +++ b/gfx/gl/shadowMapper.h @@ -57,7 +57,7 @@ public: } private: - [[nodiscard]] static std::vector> getBandViewExtents( + [[nodiscard]] static std::vector> getBandViewExtents( const Camera &, const glm::mat4 & lightView); glFrameBuffer depthMapFBO; glTexture depthMap; -- cgit v1.2.3 From 69e6b7d2d349dcc42d2d415a72181ba729d5a19d Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 1 Jan 2024 15:53:54 +0000 Subject: Remove more use of legacy types --- application/main.cpp | 9 +++++---- game/vehicles/railVehicle.cpp | 2 +- game/vehicles/railVehicle.h | 2 +- game/vehicles/train.cpp | 2 +- game/vehicles/train.h | 2 +- gfx/gl/bufferedLocation.cpp | 4 ++-- gfx/gl/camera.cpp | 4 ++-- gfx/gl/shadowMapper.cpp | 2 +- gfx/models/vertex.h | 9 +++++---- lib/maths.h | 13 ++++++------- test/test-maths.cpp | 20 ++++++++++---------- 11 files changed, 35 insertions(+), 34 deletions(-) diff --git a/application/main.cpp b/application/main.cpp index 600bbe3..adaec9b 100644 --- a/application/main.cpp +++ b/application/main.cpp @@ -47,10 +47,11 @@ public: { auto rl = world.create(); - const Position3D j {-1120000, -1100000, 3000}, k {-1100000, -1000000, 15000}, l {-1000000, -800000, 20000}, - m {-900000, -600000, 30000}, n {-600000, -500000, 32000}, o {-500000, -800000, 30000}, - p {-600000, -900000, 25000}, q {-1025000, -1175000, 10000}, r {-925000, -1075000, 10000}; - const Position3D s {-1100000, -500000, 15000}, t {-1100000, -450000, 15000}, u {-1000000, -400000, 15000}; + const GlobalPosition3D j {-1120000, -1100000, 3000}, k {-1100000, -1000000, 15000}, + l {-1000000, -800000, 20000}, m {-900000, -600000, 30000}, n {-600000, -500000, 32000}, + o {-500000, -800000, 30000}, p {-600000, -900000, 25000}, q {-1025000, -1175000, 10000}, + r {-925000, -1075000, 10000}, s {-1100000, -500000, 15000}, t {-1100000, -450000, 15000}, + u {-1000000, -400000, 15000}; auto l3 = rl->addLinksBetween(j, k); rl->addLinksBetween(k, l); rl->addLinksBetween(l, m); diff --git a/game/vehicles/railVehicle.cpp b/game/vehicles/railVehicle.cpp index 30b615c..7e4b1ee 100644 --- a/game/vehicles/railVehicle.cpp +++ b/game/vehicles/railVehicle.cpp @@ -44,7 +44,7 @@ RailVehicle::move(const Train * t, float & trailBy) } bool -RailVehicle::intersectRay(const Ray & ray, Position2D * baryPos, float * distance) const +RailVehicle::intersectRay(const Ray & ray, BaryPosition * baryPos, float * distance) const { constexpr const auto X = 1350.F; const auto Y = this->rvClass->length / 2.F; diff --git a/game/vehicles/railVehicle.h b/game/vehicles/railVehicle.h index 20d1ea1..8cbc49d 100644 --- a/game/vehicles/railVehicle.h +++ b/game/vehicles/railVehicle.h @@ -17,7 +17,7 @@ public: void move(const Train *, float & trailBy); - [[nodiscard]] bool intersectRay(const Ray &, Position2D *, float *) const override; + [[nodiscard]] bool intersectRay(const Ray &, BaryPosition *, float *) const override; RailVehicleClassPtr rvClass; using LV = RailVehicleClass::LocationVertex; diff --git a/game/vehicles/train.cpp b/game/vehicles/train.cpp index 4aa24dc..13905a3 100644 --- a/game/vehicles/train.cpp +++ b/game/vehicles/train.cpp @@ -20,7 +20,7 @@ Train::getBogiePosition(float linkDist, float dist) const } bool -Train::intersectRay(const Ray & ray, Position2D * baryPos, float * distance) const +Train::intersectRay(const Ray & ray, BaryPosition * baryPos, float * distance) const { return applyOne(&RailVehicle::intersectRay, ray, baryPos, distance) != end(); } diff --git a/game/vehicles/train.h b/game/vehicles/train.h index 7f0bb99..c77cd23 100644 --- a/game/vehicles/train.h +++ b/game/vehicles/train.h @@ -27,7 +27,7 @@ public: return objects.front()->location; } - [[nodiscard]] bool intersectRay(const Ray &, Position2D *, float *) const override; + [[nodiscard]] bool intersectRay(const Ray &, BaryPosition *, float *) const override; void tick(TickDuration elapsed) override; void doActivity(Go *, TickDuration) override; diff --git a/gfx/gl/bufferedLocation.cpp b/gfx/gl/bufferedLocation.cpp index d6a63b9..f1bedfe 100644 --- a/gfx/gl/bufferedLocation.cpp +++ b/gfx/gl/bufferedLocation.cpp @@ -25,7 +25,7 @@ BufferedLocation::position() const return loc.pos; } -Position3D +Rotation3D BufferedLocation::rotation() const { return loc.rot; @@ -41,7 +41,7 @@ BufferedLocation::setPosition(GlobalPosition3D p, bool update) } void -BufferedLocation::setRotation(Position3D r, bool update) +BufferedLocation::setRotation(Rotation3D r, bool update) { loc.rot = r; if (update) { diff --git a/gfx/gl/camera.cpp b/gfx/gl/camera.cpp index 9f40998..d362b94 100644 --- a/gfx/gl/camera.cpp +++ b/gfx/gl/camera.cpp @@ -17,14 +17,14 @@ Ray Camera::unProject(const ScreenRelCoord & mouse) const { static constexpr const glm::vec4 screen {0, 0, 1, 1}; - const auto mouseProjection = glm::lookAt(::origin, forward, up); + const auto mouseProjection = glm::lookAt({}, forward, up); return {position, glm::normalize(glm::unProject(mouse || 1.F, mouseProjection, projection, screen))}; } void Camera::updateView() { - viewProjection = projection * glm::lookAt(origin, forward, up); + viewProjection = projection * glm::lookAt({}, forward, up); inverseViewProjection = glm::inverse(viewProjection); } diff --git a/gfx/gl/shadowMapper.cpp b/gfx/gl/shadowMapper.cpp index 6c8400e..1498bb0 100644 --- a/gfx/gl/shadowMapper.cpp +++ b/gfx/gl/shadowMapper.cpp @@ -130,7 +130,7 @@ ShadowMapper::update(const SceneProvider & scene, const Direction3D & dir, const glClear(GL_DEPTH_BUFFER_BIT); glCullFace(GL_FRONT); - const auto lightViewDir = glm::lookAt(origin, dir, up); + const auto lightViewDir = glm::lookAt({}, dir, up); const auto lightViewPoint = camera.getPosition(); const auto bandViewExtents = getBandViewExtents(camera, lightViewDir); diff --git a/gfx/models/vertex.h b/gfx/models/vertex.h index 5635fa1..3c6215f 100644 --- a/gfx/models/vertex.h +++ b/gfx/models/vertex.h @@ -6,16 +6,17 @@ class Vertex { public: #ifndef __cpp_aggregate_paren_init - constexpr Vertex(Position3D pos, TextureRelCoord texCoord, Normal3D normal, RGBA colour = {}, GLuint material = 0) : - pos {std::move(pos)}, texCoord {std::move(texCoord)}, normal {std::move(normal)}, colour {std::move(colour)}, - material {material} + constexpr Vertex( + RelativePosition3D pos, TextureRelCoord texCoord, Normal3D normal, RGBA colour = {}, GLuint material = 0) : + pos {std::move(pos)}, + texCoord {std::move(texCoord)}, normal {std::move(normal)}, colour {std::move(colour)}, material {material} { } #endif bool operator==(const Vertex &) const = default; - Position3D pos {}; + RelativePosition3D pos {}; TextureRelCoord texCoord {}; Normal3D normal {}; RGBA colour {}; diff --git a/lib/maths.h b/lib/maths.h index ba8c0e6..c1bf61a 100644 --- a/lib/maths.h +++ b/lib/maths.h @@ -21,13 +21,12 @@ struct Arc : public std::pair { } }; -constexpr const Position3D origin {0, 0, 0}; -constexpr const Position3D up {0, 0, 1}; -constexpr const Position3D down {0, 0, -1}; -constexpr const Position3D north {0, 1, 0}; -constexpr const Position3D south {0, -1, 0}; -constexpr const Position3D east {1, 0, 0}; -constexpr const Position3D west {-1, 0, 0}; +constexpr const RelativePosition3D up {0, 0, 1}; +constexpr const RelativePosition3D down {0, 0, -1}; +constexpr const RelativePosition3D north {0, 1, 0}; +constexpr const RelativePosition3D south {0, -1, 0}; +constexpr const RelativePosition3D east {1, 0, 0}; +constexpr const RelativePosition3D west {-1, 0, 0}; constexpr auto half_pi {glm::half_pi()}; constexpr auto quarter_pi {half_pi / 2}; constexpr auto pi {glm::pi()}; diff --git a/test/test-maths.cpp b/test/test-maths.cpp index ede884d..b363c17 100644 --- a/test/test-maths.cpp +++ b/test/test-maths.cpp @@ -177,7 +177,7 @@ BOOST_AUTO_TEST_CASE(test_find_arcs_radius) struct TestLinkStraight : public LinkStraight { explicit TestLinkStraight(glm::vec3 v) : - Link {{std::make_shared(origin), vector_yaw(v)}, {std::make_shared(v), vector_yaw(-v)}, + Link {{std::make_shared(Position3D {}), vector_yaw(v)}, {std::make_shared(v), vector_yaw(-v)}, glm::length(v)} { } @@ -197,7 +197,7 @@ BOOST_DATA_TEST_CASE(straight1, const TestLinkStraight l(v); { const auto p = l.positionAt(0, 0); - BOOST_CHECK_EQUAL(p.pos, GlobalPosition3D {origin}); + BOOST_CHECK_EQUAL(p.pos, GlobalPosition3D {}); BOOST_CHECK_EQUAL(p.rot, glm::vec3(0, angFor, 0)); } { @@ -228,11 +228,11 @@ BOOST_DATA_TEST_CASE(curve1, e1, ctr, angFor, angBack) { { // One-way... - const TestLinkCurve l(origin, e1, ctr); + const TestLinkCurve l({}, e1, ctr); BOOST_CHECK_EQUAL(l.radius, 1.F); { const auto p = l.positionAt(0, 0); - BOOST_CHECK_CLOSE_VEC(RelativePosition3D {p.pos}, origin); + BOOST_CHECK_CLOSE_VEC(RelativePosition3D {p.pos}, RelativePosition3D {}); BOOST_CHECK_CLOSE_VEC(p.rot, glm::vec3(0, angFor, 0)); } { @@ -243,18 +243,18 @@ BOOST_DATA_TEST_CASE(curve1, } { // The other way... - const TestLinkCurve l(e1, origin, ctr); + const TestLinkCurve l(e1, {}, ctr); BOOST_CHECK_EQUAL(l.radius, 1.F); { const auto p = l.positionAt(0, 0); - const auto angForReversed = normalize(vector_yaw(origin - e1) * 2 - angFor); + const auto angForReversed = normalize(vector_yaw(-e1) * 2 - angFor); BOOST_CHECK_CLOSE_VECI(RelativePosition3D {p.pos}, e1); BOOST_CHECK_CLOSE_VECI(p.rot, glm::vec3(0, angForReversed, 0)); } { const auto p = l.positionAt(0, 1); - const auto angBackReversed = normalize(vector_yaw(e1 - origin) * 2 - angBack); - BOOST_CHECK_CLOSE_VEC(RelativePosition3D {p.pos}, origin); + const auto angBackReversed = normalize(vector_yaw(e1) * 2 - angBack); + BOOST_CHECK_CLOSE_VEC(RelativePosition3D {p.pos}, Position3D {}); BOOST_CHECK_CLOSE_VEC(p.rot, glm::vec3(0, angBackReversed, 0)); } } @@ -262,10 +262,10 @@ BOOST_DATA_TEST_CASE(curve1, BOOST_AUTO_TEST_CASE(camera_clicks) { - Camera camera {::origin, ::half_pi, 1.25F, 1000, 10000000}; + Camera camera {{}, ::half_pi, 1.25F, 1000, 10000000}; constexpr float centre {0.5F}, right {0.9F}, left {0.1F}, top {1.F}, bottom {0.F}; camera.setForward(::north); - BOOST_CHECK_EQUAL(camera.unProject({centre, centre}).start, ::origin); + BOOST_CHECK_EQUAL(camera.unProject({centre, centre}).start, RelativePosition3D {}); BOOST_CHECK_CLOSE_VEC(camera.unProject({centre, centre}).direction, ::north); BOOST_CHECK_CLOSE_VEC(camera.unProject({left, centre}).direction, glm::normalize(::north + ::west)); BOOST_CHECK_CLOSE_VEC(camera.unProject({right, centre}).direction, glm::normalize(::north + ::east)); -- cgit v1.2.3