1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
|
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
//#include <CGAL/Exact_predicates_exact_constructions_kernel_with_sqrt.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/draw_straight_skeleton_2.h>
#include <CGAL/draw_surface_mesh.h>
#include "CGAL/input_helpers.h" // polygon reading, random polygon with weights generation
#include <CGAL/extrude_skeleton.h>
#include <CGAL/IO/polygon_mesh_io.h>
#include <CGAL/Polygon_2.h>
#include <CGAL/Real_timer.h>
#include <CGAL/Random.h>
#include <iostream>
#include <unordered_map>
#include <vector>
#include <memory>
namespace SS = CGAL::CGAL_SS_i;
namespace PMP = CGAL::Polygon_mesh_processing;
// Kernel choice:
// EPICK: Robust and fast
// EPECK_with_sqrt: Exact and slow
// EPECK: More robust, and less slow than EPECK_with_sqrt
using K = CGAL::Exact_predicates_inexact_constructions_kernel;
// using K = CGAL::Exact_predicates_exact_constructions_kernel;
// using K = CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt;
using FT = K::FT;
using Point_2 = K::Point_2;
using Segment_2 = K::Segment_2;
using Line_2 = K::Line_2;
using Point_3 = K::Point_3;
using Vector_3 = K::Vector_3;
using Polygon_2 = CGAL::Polygon_2<K>;
using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2<K>;
using Straight_skeleton_2 = CGAL::Straight_skeleton_2<K>;
using Straight_skeleton_2_ptr = std::shared_ptr<Straight_skeleton_2>;
using Mesh = CGAL::Surface_mesh<Point_3>;
int main(int argc, char** argv)
{
std::cout.precision(17);
std::cerr.precision(17);
const int argc_check = argc - 1;
char* poly_filename = nullptr;
char* speeds_filename = nullptr;
FT height = FT{(std::numeric_limits<double>::max)()};
bool use_angles = false; // whether the input is SLS edge weights, or taper angles
bool flip_weights = false; // takes the opposite for weights, and the complement for angles
// below is only used for random weight generation
double min_weight = 1., max_weight = 10.;
int seed = CGAL::get_default_random().get_seed();
for(int i = 1; i < argc; ++i)
{
if(!strcmp("-h", argv[i]) || !strcmp("--help", argv[i]) || !strcmp("-?", argv[i]))
{
std::cout << "Usage: " << argv[0] << "[options].\n"
"Options:\n"
" -i <input_filename>: input polygon filename.\n"
" -t <value>: height. Must be non-zero.\n"
" -a <angles_filename>: angles. Format: one angle per line, a space to separate borders.\n"
" -w <weights_filename>: weights. Format: one weight per line, a space to separate borders.\n"
" Note: -w and -a are exclusive.\n"
<< std::endl;
return EXIT_FAILURE;
} else if(!strcmp("-i", argv[i]) && i < argc_check) {
poly_filename = argv[++i];
} else if(!strcmp("-w", argv[i])) {
if(speeds_filename != nullptr)
{
std::cerr << "Error: -w and -a are exclusive." << std::endl;
return EXIT_FAILURE;
}
speeds_filename = argv[++i];
use_angles = false;
} else if(!strcmp("-a", argv[i])) {
if(speeds_filename != nullptr)
{
std::cerr << "Error: -w and -a are exclusive." << std::endl;
return EXIT_FAILURE;
}
speeds_filename = argv[++i];
use_angles = true;
} else if(!strcmp("-t", argv[i]) && i < argc_check) {
height = std::stod(argv[++i]);
} else if(!strcmp("-mw", argv[i]) && i < argc_check) {
min_weight = std::stod(argv[++i]);
} else if(!strcmp("-Mw", argv[i]) && i < argc_check) {
max_weight = std::stod(argv[++i]);
} else if(!strcmp("-f", argv[i]) && i < argc) {
flip_weights = true;
} else if(!strcmp("-s", argv[i]) && i < argc_check) {
seed = std::stoi(argv[++i]);
}
}
if(CGAL::is_zero(height))
{
std::cerr << "Error: height must be non-zero" << std::endl;
return EXIT_FAILURE;
}
CGAL::Real_timer timer;
timer.start();
Polygon_with_holes_2 pwh;
if(poly_filename == nullptr)
{
pwh = generate_random_polygon<Polygon_with_holes_2>(seed);
}
else if(!read_input_polygon(poly_filename, pwh) || pwh.outer_boundary().is_empty())
{
std::cerr << "Error: failure during polygon read" << std::endl;
return EXIT_FAILURE;
}
#ifdef CGAL_SLS_OUTPUT_FILES
std::ofstream out_poly("input.dat");
out_poly.precision(17);
out_poly << pwh;
out_poly.close();
#endif
// read segment speeds (angles or weights)
std::vector<std::vector<FT> > speeds;
if(speeds_filename == nullptr)
generate_random_weights(pwh, min_weight, max_weight, seed, speeds);
else
read_segment_speeds(speeds_filename, speeds);
if(flip_weights)
{
if(use_angles)
{
for(auto& contour_speeds : speeds)
for(FT& a : contour_speeds)
a = 180 - a;
}
else
{
for(auto& contour_speeds : speeds)
for(FT& w : contour_speeds)
w = -w;
}
}
timer.stop();
std::cout << "Reading input(s) took " << timer.time() << " s." << std::endl;
// End of I/O, do some slope preprocessing and check the validity of the input(s)
// -----------------------------------------------------------------------------------------------
timer.reset();
timer.start();
Mesh sm;
if(use_angles)
CGAL::extrude_skeleton(pwh, sm, CGAL::parameters::angles(speeds).maximum_height(height));
else
CGAL::extrude_skeleton(pwh, sm, CGAL::parameters::weights(speeds).maximum_height(height));
timer.stop();
std::cout << "Extrusion computation took " << timer.time() << " s." << std::endl;
CGAL::draw(sm);
CGAL::IO::write_polygon_mesh("extruded_skeleton.off", sm, CGAL::parameters::stream_precision(17));
return EXIT_SUCCESS;
}
|