Skip to content

Commit

Permalink
Add unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
casperlamboo committed Nov 20, 2023
1 parent 6b6dd0f commit 245be98
Show file tree
Hide file tree
Showing 29 changed files with 11,937 additions and 7 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ target_compile_definitions(CuraEngine PRIVATE VERSION=\"${CURA_ENGINE_VERSION}\"

# Compiling the test environment.
if (ENABLE_TESTING OR ENABLE_BENCHMARKS)
set(TESTS_HELPERS_SRC tests/ReadTestPolygons.cpp)
set(TESTS_HELPERS_SRC tests/ReadTestPolygons.cpp tests/ReadTestSettings.cpp)

set(TESTS_SRC_ARCUS)
if (ENABLE_ARCUS)
Expand Down
62 changes: 56 additions & 6 deletions src/SkeletalTrapezoidation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <sstream>
#include <stack>
#include <unordered_set>
#include <fmt/format.h>

#define SKELETAL_TRAPEZOIDATION_BEAD_SEARCH_MAX \
1000 // A limit to how long it'll keep searching for adjacent beads. Increasing will re-use beadings more often (saving performance), but search longer for beading (costing
Expand Down Expand Up @@ -395,27 +396,61 @@ SkeletalTrapezoidation::SkeletalTrapezoidation(
constructFromPolygons(polys);
}

static int file_index = 0;

void SkeletalTrapezoidation::constructFromPolygons(const Polygons& polys)
{
Polygons polys2;
{
std::stringstream buffer;
polys.writeWkt(buffer);
if (buffer.str().empty())
{
polys2 = polys;
}
else
{
polys2 = Polygons::fromWkt(buffer.str());
}
}

vd_edge_to_he_edge.clear();
vd_node_to_he_node.clear();

std::vector<Point> points; // Remains empty

std::vector<Segment> segments;
for (size_t poly_idx = 0; poly_idx < polys.size(); poly_idx++)
for (size_t poly_idx = 0; poly_idx < polys2.size(); poly_idx++)
{
ConstPolygonRef poly = polys[poly_idx];
ConstPolygonRef poly = polys2[poly_idx];
for (size_t point_idx = 0; point_idx < poly.size(); point_idx++)
{
segments.emplace_back(&polys, poly_idx, point_idx);
segments.emplace_back(&polys2, poly_idx, point_idx);
}
}

vd_t vonoroi_diagram;
construct_voronoi(segments.begin(), segments.end(), &vonoroi_diagram);
vd_t voronoi_diagram;
construct_voronoi(segments.begin(), segments.end(), &voronoi_diagram);

for (vd_t::cell_type cell : vonoroi_diagram.cells())
{
AABB aabb;
for (const auto& poly: polys2)
{
for (const auto& p: poly)
{
aabb.include(p);
}
}
aabb.expand(1000);
SVG svg("filename" + std::to_string(file_index) + ".svg", aabb);
svg.writePolygons(polys);
svg.writeVoronoiDiagram(voronoi_diagram);
}


file_index ++;

for (vd_t::cell_type cell : voronoi_diagram.cells())
{
if (! cell.incident_edge())
{ // There is no spoon
Expand Down Expand Up @@ -478,6 +513,21 @@ void SkeletalTrapezoidation::constructFromPolygons(const Polygons& polys)

separatePointyQuadEndNodes();

// {
// AABB aabb;
// for (const auto& poly: polys2)
// {
// for (const auto& p: poly)
// {
// aabb.include(p);
// }
// }
// aabb.expand(1000);
// SVG svg("filename_skeltal_trapezoidation_graph" + std::to_string(file_index) + ".svg", aabb);
// svg.writePolygons(polys);
// svg.writeSkeletalTrapezoidationGraph(graph);
// }

graph.collapseSmallEdges();

// Set [incident_edge] the the first possible edge that way we can iterate over all reachable edges from node.incident_edge,
Expand Down
59 changes: 59 additions & 0 deletions src/WallsComputation.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
// Copyright (c) 2023 UltiMaker
// CuraEngine is released under the terms of the AGPLv3 or higher

#include <iostream>
#include <fstream>

#include <fmt/format.h>
#include <range/v3/to_container.hpp>
#include <range/v3/view/c_str.hpp>
#include <range/v3/view/join.hpp>
#include <range/v3/view/transform.hpp>

#include "WallsComputation.h"
#include "Application.h"
#include "ExtruderTrain.h"
Expand Down Expand Up @@ -84,6 +93,56 @@ void WallsComputation::generateWalls(SliceLayerPart* part, SectionType section_t
*/
void WallsComputation::generateWalls(SliceLayer* layer, SectionType section)
{
// TODO remove this block before merging PR!
// This code exists to generate the test wkt, and setting files
{
std::ofstream SettingsFile("settings.txt");
SettingsFile.clear();
for (auto [key, value]: settings.getFlattendSettings())
{
if (value == "")
{
continue;
}
SettingsFile << key << "=" << value << std::endl;
}
SettingsFile.close();

std::ofstream PolygonFile("slice_polygon.wkt");
PolygonFile.clear();

std::vector<Polygons> multi_polygons;
for (const auto& part : layer->parts)
{
multi_polygons.push_back(part.outline);
}

PolygonFile << "MULTIPOLYGON (";
const auto paths_str
= multi_polygons
| ranges::views::transform([](const auto& path) {
const auto path_str
= path
| ranges::views::transform([](const auto& path) {
const auto path_str
= path
| ranges::views::transform([](const auto& point) { return fmt::format("{} {}", point.X, point.Y); })
| ranges::views::join(ranges::views::c_str(", ")) | ranges::to<std::string>();
return "(" + path_str + ")";
})
| ranges::views::join(ranges::views::c_str(" "))
| ranges::to<std::string>();
return "(" + path_str + ")";
})
| ranges::views::join(ranges::views::c_str(", "))
| ranges::to<std::string>();

PolygonFile << paths_str;
PolygonFile << ")";

PolygonFile.close();
}

for(SliceLayerPart& part : layer->parts)
{
generateWalls(&part, section);
Expand Down
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ set(TESTS_SRC_BASE
PathOrderMonotonicTest
TimeEstimateCalculatorTest
WallsComputationTest
VoronoiCrashTest
)

set(TESTS_SRC_INTEGRATION
Expand Down
43 changes: 43 additions & 0 deletions tests/ReadTestSettings.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (c) 2023 UltiMaker
// CuraEngine is released under the terms of the AGPLv3 or higher.

#include "ReadTestSettings.h"
#include <cstdio>
#include <spdlog/spdlog.h>

namespace cura
{

bool readTestSettings(const std::string& filename, Settings& settings)
{
spdlog::info("filename: {}", filename);

FILE* handle = std::fopen(filename.c_str(), "r");
if (! handle)
{
spdlog::error("Failed to open file: {}", filename);
return false;
}

while (true)
{
char key[100];
char value[100];

int read = std::fscanf(handle, "%[a-zA-Z0-9_]=%[][a-zA-Z0-9_-.,:()/; ]\n", key, value);

if (read == EOF)
{
break;
}
else if (read <= 0)
{
return false;
}

settings.add(std::string(key), std::string(value));
}

return true;
}
} // namespace cura
13 changes: 13 additions & 0 deletions tests/ReadTestSettings.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

// Copyright (c) 2023 UltiMaker
// CuraEngine is released under the terms of the AGPLv3 or higher.


#include "settings/Settings.h"
#include <string>
#include <vector>

namespace cura
{
bool readTestSettings(const std::string& filename, Settings& settings_out);
}
137 changes: 137 additions & 0 deletions tests/VoronoiCrashTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
// Copyright (c) 2023 UltiMaker
// CuraEngine is released under the terms of the AGPLv3 or higher

#include <boost/geometry/io/wkt/read.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/geometries/multi_polygon.hpp>

#include "WallsComputation.h" //Unit under test.
#include "ReadTestSettings.h"
#include "settings/Settings.h" //Settings to generate walls with.
#include "sliceDataStorage.h" //Sl
#include "utils/polygon.h" //To create example polygons.

#include <fstream>
#include <filesystem>
#include <gtest/gtest.h>
#include <unordered_set>

#include <scripta/logger.h>
#include <spdlog/spdlog.h>

namespace cura
{

class VoronoiCrashTest : public testing::TestWithParam<std::tuple<std::string, std::string>>
{
public:
};

std::vector<Polygons> multiPolygonsFromWkt(const std::string& wkt)
{
typedef boost::geometry::model::d2::point_xy<double> point_type;
typedef boost::geometry::model::polygon<point_type> polygon_type;
typedef boost::geometry::model::multi_polygon<polygon_type> multi_polygon_type;

multi_polygon_type boost_polygons {};
boost::geometry::read_wkt(wkt, boost_polygons);

std::vector<Polygons> polygons;

for (const auto& boost_polygon: boost_polygons)
{
Polygons polygon;

Polygon outer;
for (const auto& point: boost_polygon.outer())
{
outer.add(Point(point.x(), point.y()));
}
polygon.add(outer);

for (const auto& hole: boost_polygon.inners())
{
Polygon inner;
for (const auto& point: hole)
{
inner.add(Point(point.x(), point.y()));
}
polygon.add(inner);
}

polygons.push_back(polygon);
}
return polygons;
}

/*!
*
*/
TEST_P(VoronoiCrashTest, SectionsTest)
{
const auto params = GetParam();
const std::string polygon_file = std::get<0>(params);
const std::string setting_file = std::get<1>(params);

spdlog::info("Testing polygon: {}", polygon_file);
spdlog::info("Testing with settings: {}", setting_file);

std::ifstream file(polygon_file);
std::ostringstream ss;
ss << file.rdbuf();
const auto shapes = multiPolygonsFromWkt(ss.str());

Settings settings;
auto read_settings = readTestSettings(setting_file, settings);
ASSERT_TRUE(read_settings);

size_t wall_count = settings.get<size_t>("wall_line_count");
spdlog::info("wall_count: {}", wall_count);

SliceLayer layer;
for (const Polygons& shape : shapes)
{
layer.parts.emplace_back();
SliceLayerPart& part = layer.parts.back();
part.outline.add(shape);
}

LayerIndex layer_idx(100);
WallsComputation walls_computation(settings, layer_idx);

walls_computation.generateWalls(&layer, SectionType::WALL);
}


const std::vector<std::string> polygon_filenames = {
std::filesystem::path(__FILE__).parent_path().append("voronoi_crash_resources/slice_polygon_001.wkt").string(),
std::filesystem::path(__FILE__).parent_path().append("voronoi_crash_resources/slice_polygon_002.wkt").string(),
std::filesystem::path(__FILE__).parent_path().append("voronoi_crash_resources/slice_polygon_003.wkt").string(),
std::filesystem::path(__FILE__).parent_path().append("voronoi_crash_resources/slice_polygon_004.wkt").string(),
std::filesystem::path(__FILE__).parent_path().append("voronoi_crash_resources/slice_polygon_005.wkt").string(),
std::filesystem::path(__FILE__).parent_path().append("voronoi_crash_resources/slice_polygon_006.wkt").string(),
std::filesystem::path(__FILE__).parent_path().append("voronoi_crash_resources/slice_polygon_007.wkt").string(),
std::filesystem::path(__FILE__).parent_path().append("voronoi_crash_resources/slice_polygon_008.wkt").string(),
std::filesystem::path(__FILE__).parent_path().append("voronoi_crash_resources/slice_polygon_009.wkt").string(),
std::filesystem::path(__FILE__).parent_path().append("voronoi_crash_resources/slice_polygon_010.wkt").string(),
std::filesystem::path(__FILE__).parent_path().append("voronoi_crash_resources/slice_polygon_011.wkt").string(),
};

const std::vector<std::string> setting_filenames = {
std::filesystem::path(__FILE__).parent_path().append("voronoi_crash_resources/settings_001.txt").string(),
std::filesystem::path(__FILE__).parent_path().append("voronoi_crash_resources/settings_002.txt").string(),
std::filesystem::path(__FILE__).parent_path().append("voronoi_crash_resources/settings_003.txt").string(),
std::filesystem::path(__FILE__).parent_path().append("voronoi_crash_resources/settings_004.txt").string(),
std::filesystem::path(__FILE__).parent_path().append("voronoi_crash_resources/settings_005.txt").string(),
std::filesystem::path(__FILE__).parent_path().append("voronoi_crash_resources/settings_006.txt").string(),
std::filesystem::path(__FILE__).parent_path().append("voronoi_crash_resources/settings_007.txt").string(),
std::filesystem::path(__FILE__).parent_path().append("voronoi_crash_resources/settings_008.txt").string(),
std::filesystem::path(__FILE__).parent_path().append("voronoi_crash_resources/settings_009.txt").string(),
std::filesystem::path(__FILE__).parent_path().append("voronoi_crash_resources/settings_010.txt").string(),
std::filesystem::path(__FILE__).parent_path().append("voronoi_crash_resources/settings_011.txt").string(),
};

INSTANTIATE_TEST_SUITE_P(TestCrashingPolygons, VoronoiCrashTest, testing::Combine(testing::ValuesIn(polygon_filenames), testing::ValuesIn(setting_filenames)));

} // namespace cura
Loading

0 comments on commit 245be98

Please sign in to comment.