mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-11 14:59:00 +08:00
Revisited scheduling of object instances via object gluing, added object gluing across multple beds.
This commit is contained in:
parent
78c6ed2c6b
commit
1259d59098
@ -331,7 +331,20 @@ std::vector<ScheduledPlate> schedule_ObjectsForSequentialPrint(const SolverConfi
|
||||
return scheduled_plates;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool is_scheduled(int i, const std::vector<int> &decided_polygons)
|
||||
{
|
||||
for (unsigned int j = 0; j < decided_polygons.size(); ++j)
|
||||
{
|
||||
if (decided_polygons[j] == i)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void schedule_ObjectsForSequentialPrint(const SolverConfiguration &solver_configuration,
|
||||
const PrinterGeometry &printer_geometry,
|
||||
const std::vector<ObjectToPrint> &objects_to_print,
|
||||
@ -350,8 +363,6 @@ void schedule_ObjectsForSequentialPrint(const SolverConfiguration &solver
|
||||
#endif
|
||||
|
||||
std::map<int, int> original_index_map;
|
||||
std::vector<bool> lepox_to_next;
|
||||
|
||||
std::vector<SolvableObject> solvable_objects;
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -410,6 +421,8 @@ void schedule_ObjectsForSequentialPrint(const SolverConfiguration &solver
|
||||
int progress_object_phases_done = 0;
|
||||
int progress_object_phases_total = SEQ_MAKE_EXTRA_PROGRESS((objects_to_print.size() * SEQ_PROGRESS_PHASES_PER_OBJECT));
|
||||
|
||||
bool trans_bed_lepox = false;
|
||||
|
||||
do
|
||||
{
|
||||
ScheduledPlate scheduled_plate;
|
||||
@ -430,6 +443,7 @@ void schedule_ObjectsForSequentialPrint(const SolverConfiguration &solver
|
||||
poly_positions_Y,
|
||||
times_T,
|
||||
solvable_objects,
|
||||
trans_bed_lepox,
|
||||
decided_polygons,
|
||||
remaining_polygons,
|
||||
progress_object_phases_done,
|
||||
@ -464,9 +478,30 @@ void schedule_ObjectsForSequentialPrint(const SolverConfiguration &solver
|
||||
}
|
||||
#endif
|
||||
|
||||
std::map<double, int> scheduled_polygons;
|
||||
bool split = false;
|
||||
for (unsigned int i = 0; i < decided_polygons.size(); ++i)
|
||||
{
|
||||
if (solvable_objects[i].lepox_to_next && !is_scheduled(i + 1, decided_polygons))
|
||||
{
|
||||
split = true;
|
||||
}
|
||||
}
|
||||
if (split)
|
||||
{
|
||||
trans_bed_lepox = true;
|
||||
#ifdef DEBUG
|
||||
{
|
||||
printf("Lopoxed group split, implies trans-bed lepox\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
trans_bed_lepox = false;
|
||||
}
|
||||
std::map<double, int> scheduled_polygons;
|
||||
for (unsigned int i = 0; i < decided_polygons.size(); ++i)
|
||||
{
|
||||
scheduled_polygons.insert(std::pair<double, int>(times_T[decided_polygons[i]].as_double(), decided_polygons[i]));
|
||||
}
|
||||
|
||||
@ -802,6 +837,8 @@ int schedule_ObjectsForSequentialPrint(const SolverConfiguration &solver_
|
||||
int progress_object_phases_done = 0;
|
||||
int progress_object_phases_total = SEQ_MAKE_EXTRA_PROGRESS((objects_to_print.size() * SEQ_PROGRESS_PHASES_PER_OBJECT));
|
||||
|
||||
bool trans_bed_lepox = false;
|
||||
|
||||
do
|
||||
{
|
||||
ScheduledPlate scheduled_plate;
|
||||
@ -822,6 +859,7 @@ int schedule_ObjectsForSequentialPrint(const SolverConfiguration &solver_
|
||||
poly_positions_Y,
|
||||
times_T,
|
||||
solvable_objects,
|
||||
trans_bed_lepox,
|
||||
decided_polygons,
|
||||
remaining_polygons,
|
||||
progress_object_phases_done,
|
||||
@ -856,6 +894,27 @@ int schedule_ObjectsForSequentialPrint(const SolverConfiguration &solver_
|
||||
}
|
||||
#endif
|
||||
|
||||
bool split = false;
|
||||
for (unsigned int i = 0; i < decided_polygons.size(); ++i)
|
||||
{
|
||||
if (solvable_objects[i].lepox_to_next && !is_scheduled(i + 1, decided_polygons))
|
||||
{
|
||||
split = true;
|
||||
}
|
||||
}
|
||||
if (split)
|
||||
{
|
||||
trans_bed_lepox = true;
|
||||
#ifdef DEBUG
|
||||
{
|
||||
printf("Lopoxed group split, implies trans-bed lepox\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
trans_bed_lepox = false;
|
||||
}
|
||||
std::map<double, int> scheduled_polygons;
|
||||
for (unsigned int i = 0; i < decided_polygons.size(); ++i)
|
||||
{
|
||||
@ -1115,6 +1174,8 @@ int schedule_ObjectsForSequentialPrint(const SolverConfiguration
|
||||
int progress_object_phases_done = 0;
|
||||
int progress_object_phases_total = SEQ_MAKE_EXTRA_PROGRESS((objects_to_print.size() * SEQ_PROGRESS_PHASES_PER_OBJECT));
|
||||
|
||||
bool trans_bed_lepox = false;
|
||||
|
||||
do
|
||||
{
|
||||
ScheduledPlate scheduled_plate;
|
||||
@ -1135,6 +1196,7 @@ int schedule_ObjectsForSequentialPrint(const SolverConfiguration
|
||||
poly_positions_Y,
|
||||
times_T,
|
||||
solvable_objects,
|
||||
trans_bed_lepox,
|
||||
decided_polygons,
|
||||
remaining_polygons,
|
||||
progress_object_phases_done,
|
||||
@ -1170,6 +1232,27 @@ int schedule_ObjectsForSequentialPrint(const SolverConfiguration
|
||||
}
|
||||
#endif
|
||||
|
||||
bool split = false;
|
||||
for (unsigned int i = 0; i < decided_polygons.size(); ++i)
|
||||
{
|
||||
if (solvable_objects[i].lepox_to_next && !is_scheduled(i + 1, decided_polygons))
|
||||
{
|
||||
split = true;
|
||||
}
|
||||
}
|
||||
if (split)
|
||||
{
|
||||
trans_bed_lepox = true;
|
||||
#ifdef DEBUG
|
||||
{
|
||||
printf("Lopoxed group split, implies trans-bed lepox\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
trans_bed_lepox = false;
|
||||
}
|
||||
std::map<double, int> scheduled_polygons;
|
||||
for (unsigned int i = 0; i < decided_polygons.size(); ++i)
|
||||
{
|
||||
|
@ -377,6 +377,44 @@ void introduce_ConsequentialTemporalOrderingAgainstFixed(z3::solver
|
||||
}
|
||||
|
||||
|
||||
bool is_undecided(int i, const std::vector<int> &undecided)
|
||||
{
|
||||
for (unsigned int j = 0; j < undecided.size(); ++j)
|
||||
{
|
||||
if (undecided[j] == i)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool is_fixed(int i, const std::vector<int> &fixed)
|
||||
{
|
||||
for (unsigned int j = 0; j < fixed.size(); ++j)
|
||||
{
|
||||
if (fixed[j] == i)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool is_targeted_by_undecided(int i, const std::vector<int> &fixed, const std::vector<bool> &lepox_to_next)
|
||||
{
|
||||
return (i > 0 && lepox_to_next[i - 1] && is_undecided(i - 1, fixed));
|
||||
}
|
||||
|
||||
|
||||
bool is_targeted_by_fixed(int i, const std::vector<int> &fixed, const std::vector<bool> &lepox_to_next)
|
||||
{
|
||||
return (i > 0 && lepox_to_next[i - 1] && is_fixed(i - 1, fixed));
|
||||
}
|
||||
|
||||
|
||||
void introduce_ConsequentialTemporalLepoxAgainstFixed(z3::solver &Solver,
|
||||
z3::context &Context,
|
||||
const z3::expr_vector &dec_vars_T,
|
||||
@ -385,48 +423,147 @@ void introduce_ConsequentialTemporalLepoxAgainstFixed(z3::solver
|
||||
const std::vector<int> &undecided,
|
||||
int temporal_spread,
|
||||
const std::vector<Slic3r::Polygon> &SEQ_UNUSED(polygons),
|
||||
const std::vector<bool> &lepox_to_next)
|
||||
const std::vector<bool> &lepox_to_next,
|
||||
bool trans_bed_lepox)
|
||||
{
|
||||
for (unsigned int i = 0; i < undecided.size(); ++i)
|
||||
#ifdef DEBUG
|
||||
{
|
||||
if (i == 0)
|
||||
if (trans_bed_lepox)
|
||||
{
|
||||
if ((undecided[0] - 1) >= 0)
|
||||
printf("Trans bed lepox.\n");
|
||||
}
|
||||
printf("Undecided:\n");
|
||||
for (unsigned int i = 0; i < undecided.size(); ++i)
|
||||
{
|
||||
printf("%d", undecided[i]);
|
||||
if (lepox_to_next[undecided[i]])
|
||||
{
|
||||
if (lepox_to_next[undecided[0] - 1])
|
||||
{
|
||||
for (unsigned int j = 1; j < undecided.size(); ++j)
|
||||
{
|
||||
Solver.add(dec_vars_T[undecided[0]] + temporal_spread < dec_vars_T[undecided[j]]);
|
||||
}
|
||||
if (!fixed.empty())
|
||||
{
|
||||
int prev_fix_i = fixed[fixed.size() - 1];
|
||||
Solver.add(Context.real_val(dec_values_T[prev_fix_i].numerator, dec_values_T[prev_fix_i].denominator) + temporal_spread < dec_vars_T[undecided[0]]);
|
||||
}
|
||||
}
|
||||
printf("-> ");
|
||||
}
|
||||
printf(" ");
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("Fixed:\n");
|
||||
for (unsigned int i = 0; i < fixed.size(); ++i)
|
||||
{
|
||||
printf("%d", fixed[i]);
|
||||
if (lepox_to_next[fixed[i]])
|
||||
{
|
||||
printf("-> ");
|
||||
}
|
||||
printf(" ");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Bed --> Bed */
|
||||
if (trans_bed_lepox)
|
||||
{
|
||||
if (is_undecided(0, undecided))
|
||||
{
|
||||
#ifdef DEBUG
|
||||
{
|
||||
printf("Bed --> Bed: undecided 0 first\n");
|
||||
}
|
||||
#endif
|
||||
for (unsigned int j = 1; j < undecided.size(); ++j)
|
||||
{
|
||||
Solver.add(dec_vars_T[0] + temporal_spread < dec_vars_T[undecided[j]]);
|
||||
}
|
||||
}
|
||||
else if (is_fixed(0, fixed))
|
||||
{
|
||||
#ifdef DEBUG
|
||||
{
|
||||
printf("Bed --> Bed: fixed 0 still first\n");
|
||||
}
|
||||
#endif
|
||||
for (unsigned int j = 0; j < undecided.size(); ++j)
|
||||
{
|
||||
Solver.add(Context.real_val(dec_values_T[0].numerator, dec_values_T[0].denominator) + temporal_spread < dec_vars_T[undecided[j]]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// should not happen
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < undecided.size(); ++i)
|
||||
{
|
||||
if (lepox_to_next[undecided[i]])
|
||||
{
|
||||
if (undecided.size() > i + 1)
|
||||
int next_i = undecided[i] + 1;
|
||||
|
||||
/* Undecided --> Undecided */
|
||||
if (is_undecided(next_i, undecided))
|
||||
{
|
||||
int next_i = undecided[i + 1];
|
||||
#ifdef DEBUG
|
||||
{
|
||||
printf("Undecided --> Undecided: %d --> %d standard\n", undecided[i], next_i);
|
||||
}
|
||||
#endif
|
||||
Solver.add(dec_vars_T[undecided[i]] + temporal_spread < dec_vars_T[next_i] && dec_vars_T[undecided[i]] + temporal_spread + temporal_spread / 2 > dec_vars_T[next_i]);
|
||||
}
|
||||
/* Undecided --> missing */
|
||||
else
|
||||
{
|
||||
if (!undecided.empty())
|
||||
#ifdef DEBUG
|
||||
{
|
||||
for (unsigned int j = 0; j < undecided.size() - 1; ++j)
|
||||
printf("Undecided --> Undecided: %d missing\n", undecided[i]);
|
||||
}
|
||||
#endif
|
||||
for (unsigned int j = 0; j < undecided.size(); ++j)
|
||||
{
|
||||
if (i != j)
|
||||
{
|
||||
Solver.add(dec_vars_T[undecided[j]] + temporal_spread < dec_vars_T[undecided[i]]);
|
||||
}
|
||||
}
|
||||
for (unsigned int j = 0; j < fixed.size(); ++j)
|
||||
{
|
||||
Solver.add(Context.real_val(dec_values_T[fixed[j]].numerator, dec_values_T[fixed[j]].denominator) + temporal_spread < dec_vars_T[undecided[i]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (unsigned int i = 0; i < fixed.size(); ++i)
|
||||
{
|
||||
if (lepox_to_next[fixed[i]])
|
||||
{
|
||||
int next_i = fixed[i] + 1;
|
||||
|
||||
/* Fixed --> Undecided */
|
||||
if (is_undecided(next_i, undecided))
|
||||
{
|
||||
#ifdef DEBUG
|
||||
{
|
||||
printf("Fixed --> Undecided: %d --> %d standard\n", fixed[i], next_i);
|
||||
}
|
||||
#endif
|
||||
Solver.add( Context.real_val(dec_values_T[fixed[i]].numerator, dec_values_T[fixed[i]].denominator) + temporal_spread < dec_vars_T[next_i]
|
||||
&& Context.real_val(dec_values_T[fixed[i]].numerator, dec_values_T[fixed[i]].denominator) + temporal_spread + temporal_spread / 2 > dec_vars_T[next_i]);
|
||||
}
|
||||
/* Fixed --> Fixed */
|
||||
else if (is_fixed(next_i, fixed))
|
||||
{
|
||||
#ifdef DEBUG
|
||||
{
|
||||
printf("All out of the link: %d --> %d\n", fixed[i], next_i);
|
||||
}
|
||||
#endif
|
||||
for (unsigned int j = 0; j < undecided.size(); ++j)
|
||||
{
|
||||
Solver.add( Context.real_val(dec_values_T[fixed[i]].numerator, dec_values_T[fixed[i]].denominator) > dec_vars_T[undecided[j]] + temporal_spread
|
||||
|| Context.real_val(dec_values_T[next_i].numerator, dec_values_T[next_i].denominator) < dec_vars_T[undecided[j]] + temporal_spread);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
printf("Origo\n");
|
||||
@ -10902,6 +11039,7 @@ bool optimize_SubglobalConsequentialPolygonNonoverlappingBinaryCentered(const So
|
||||
const std::vector<Slic3r::Polygon> &polygons,
|
||||
const std::vector<Slic3r::Polygon> &unreachable_polygons,
|
||||
const std::vector<bool> &lepox_to_next,
|
||||
bool trans_bed_lepox,
|
||||
const std::vector<int> &undecided_polygons,
|
||||
std::vector<int> &decided_polygons,
|
||||
std::vector<int> &remaining_polygons,
|
||||
@ -10924,6 +11062,7 @@ bool optimize_SubglobalConsequentialPolygonNonoverlappingBinaryCentered(const So
|
||||
polygons,
|
||||
_unreachable_polygons,
|
||||
lepox_to_next,
|
||||
trans_bed_lepox,
|
||||
undecided_polygons,
|
||||
decided_polygons,
|
||||
remaining_polygons,
|
||||
@ -10940,6 +11079,7 @@ bool optimize_SubglobalConsequentialPolygonNonoverlappingBinaryCentered(const So
|
||||
const std::vector<Slic3r::Polygon> &polygons,
|
||||
const std::vector<std::vector<Slic3r::Polygon> > &unreachable_polygons,
|
||||
const std::vector<bool> &lepox_to_next,
|
||||
bool trans_bed_lepox,
|
||||
const std::vector<int> &undecided_polygons,
|
||||
std::vector<int> &decided_polygons,
|
||||
std::vector<int> &remaining_polygons,
|
||||
@ -11039,7 +11179,8 @@ bool optimize_SubglobalConsequentialPolygonNonoverlappingBinaryCentered(const So
|
||||
undecided,
|
||||
solver_configuration.temporal_spread,
|
||||
polygons,
|
||||
lepox_to_next);
|
||||
lepox_to_next,
|
||||
trans_bed_lepox);
|
||||
|
||||
std::vector<int> missing;
|
||||
std::vector<int> remaining_local;
|
||||
@ -11195,16 +11336,17 @@ bool optimize_SubglobalConsequentialPolygonNonoverlappingBinaryCentered(const So
|
||||
}
|
||||
|
||||
|
||||
bool optimize_SubglobalConsequentialPolygonNonoverlappingBinaryCentered(const SolverConfiguration &solver_configuration,
|
||||
std::vector<Rational> &dec_values_X,
|
||||
std::vector<Rational> &dec_values_Y,
|
||||
std::vector<Rational> &dec_values_T,
|
||||
const std::vector<SolvableObject> &solvable_objects,
|
||||
std::vector<int> &decided_polygons,
|
||||
std::vector<int> &remaining_polygons,
|
||||
int &progress_object_phases_done,
|
||||
int progress_total_object_phases,
|
||||
std::function<void(int)> progress_callback)
|
||||
bool optimize_SubglobalConsequentialPolygonNonoverlappingBinaryCentered(const SolverConfiguration &solver_configuration,
|
||||
std::vector<Rational> &dec_values_X,
|
||||
std::vector<Rational> &dec_values_Y,
|
||||
std::vector<Rational> &dec_values_T,
|
||||
const std::vector<SolvableObject> &solvable_objects,
|
||||
bool trans_bed_lepox,
|
||||
std::vector<int> &decided_polygons,
|
||||
std::vector<int> &remaining_polygons,
|
||||
int &progress_object_phases_done,
|
||||
int progress_total_object_phases,
|
||||
std::function<void(int)> progress_callback)
|
||||
{
|
||||
std::vector<int> undecided;
|
||||
|
||||
@ -11333,7 +11475,8 @@ bool optimize_SubglobalConsequentialPolygonNonoverlappingBinaryCentered(const So
|
||||
undecided,
|
||||
solver_configuration.temporal_spread,
|
||||
polygons,
|
||||
lepox_to_next);
|
||||
lepox_to_next,
|
||||
trans_bed_lepox);
|
||||
|
||||
std::vector<int> missing;
|
||||
std::vector<int> remaining_local;
|
||||
|
@ -344,7 +344,8 @@ void introduce_ConsequentialTemporalLepoxAgainstFixed(z3::solver
|
||||
const std::vector<int> &undecided,
|
||||
int temporal_spread,
|
||||
const std::vector<Slic3r::Polygon> &SEQ_UNUSED(polygons),
|
||||
const std::vector<bool> &lepox_to_next);
|
||||
const std::vector<bool> &lepox_to_next,
|
||||
bool trans_bed_lepox);
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
@ -1642,6 +1643,7 @@ bool optimize_SubglobalConsequentialPolygonNonoverlappingBinaryCentered(const So
|
||||
const std::vector<Slic3r::Polygon> &polygons,
|
||||
const std::vector<Slic3r::Polygon> &unreachable_polygons,
|
||||
const std::vector<bool> &lepox_to_next,
|
||||
bool trans_bed_lepox,
|
||||
const std::vector<int> &undecided_polygons,
|
||||
std::vector<int> &decided_polygons,
|
||||
std::vector<int> &remaining_polygons,
|
||||
@ -1656,6 +1658,7 @@ bool optimize_SubglobalConsequentialPolygonNonoverlappingBinaryCentered(const So
|
||||
const std::vector<Slic3r::Polygon> &polygons,
|
||||
const std::vector<std::vector<Slic3r::Polygon> > &unreachable_polygons,
|
||||
const std::vector<bool> &lepox_to_next,
|
||||
bool trans_bed_lepox,
|
||||
const std::vector<int> &undecided_polygons,
|
||||
std::vector<int> &decided_polygons,
|
||||
std::vector<int> &remaining_polygons,
|
||||
@ -1668,6 +1671,7 @@ bool optimize_SubglobalConsequentialPolygonNonoverlappingBinaryCentered(const So
|
||||
std::vector<Rational> &dec_values_Y,
|
||||
std::vector<Rational> &dec_values_T,
|
||||
const std::vector<SolvableObject> &solvable_objects,
|
||||
bool trans_bed_lepox,
|
||||
std::vector<int> &decided_polygons,
|
||||
std::vector<int> &remaining_polygons,
|
||||
int &progress_object_phases_done,
|
||||
|
@ -185,6 +185,19 @@ string convert_Index2Suffix(int index)
|
||||
}
|
||||
|
||||
|
||||
bool is_scheduled(int i, const std::vector<int> &decided_polygons)
|
||||
{
|
||||
for (unsigned int j = 0; j < decided_polygons.size(); ++j)
|
||||
{
|
||||
if (decided_polygons[j] == i)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int solve_SequentialPrint(const CommandParameters &command_parameters)
|
||||
{
|
||||
clock_t start, finish;
|
||||
@ -383,7 +396,9 @@ int solve_SequentialPrint(const CommandParameters &command_parameters)
|
||||
int plate_index = 0;
|
||||
|
||||
int progress_objects_done = 0;
|
||||
int progress_objects_total = objects_to_print.size();
|
||||
int progress_objects_total = objects_to_print.size();
|
||||
|
||||
bool trans_bed_lepox = false;
|
||||
|
||||
do
|
||||
{
|
||||
@ -402,6 +417,7 @@ int solve_SequentialPrint(const CommandParameters &command_parameters)
|
||||
polygons,
|
||||
unreachable_polygons,
|
||||
lepox_to_next,
|
||||
trans_bed_lepox,
|
||||
polygon_index_map,
|
||||
decided_polygons,
|
||||
remaining_polygons,
|
||||
@ -443,6 +459,23 @@ int solve_SequentialPrint(const CommandParameters &command_parameters)
|
||||
printf(" ID:%d\n", original_index_map[remaining_polygons[i]]);
|
||||
}
|
||||
|
||||
bool split = false;
|
||||
for (unsigned int i = 0; i < decided_polygons.size(); ++i)
|
||||
{
|
||||
if (lepox_to_next[i] && !is_scheduled(i + 1, decided_polygons))
|
||||
{
|
||||
split = true;
|
||||
}
|
||||
}
|
||||
if (split)
|
||||
{
|
||||
trans_bed_lepox = true;
|
||||
printf("Lopoxed group split, potential danger!!!\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
trans_bed_lepox = false;
|
||||
}
|
||||
std::map<double, int> scheduled_polygons;
|
||||
for (unsigned int i = 0; i < decided_polygons.size(); ++i)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user