mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-14 22:55:57 +08:00
Add allignable inner support island point
This commit is contained in:
parent
10c05ca01e
commit
0c9dedcffa
@ -257,8 +257,8 @@ double LineUtils::perp_distance(const Linef &line, Vec2d p)
|
||||
|
||||
bool LineUtils::is_parallel(const Line &first, const Line &second)
|
||||
{
|
||||
Point dir1 = first.b - first.a;
|
||||
Point dir2 = second.b - second.a;
|
||||
Point dir1 = direction(first);
|
||||
Point dir2 = direction(second);
|
||||
coord_t cross(
|
||||
static_cast<int64_t>(dir1.x()) * dir2.y() -
|
||||
static_cast<int64_t>(dir2.x()) * dir1.y()
|
||||
|
@ -853,16 +853,18 @@ void SampleIslandUtils::sample_field(VoronoiGraph::Position &field_start,
|
||||
Polygons polygons = offset(field.border, -2.f * config.minimal_distance_from_outline,
|
||||
ClipperLib::jtSquare);
|
||||
if (polygons.empty()) return;
|
||||
ExPolygon inner(polygons.front());
|
||||
|
||||
auto inner = std::make_shared<ExPolygon>(polygons.front());
|
||||
for (size_t i = 1; i < polygons.size(); ++i) {
|
||||
Polygon &hole = polygons[i];
|
||||
inner.holes.push_back(hole);
|
||||
inner->holes.push_back(hole);
|
||||
}
|
||||
Points inner_points = sample_expolygon(inner, config.max_distance);
|
||||
|
||||
Points inner_points = sample_expolygon(*inner, config.max_distance);
|
||||
std::transform(inner_points.begin(), inner_points.end(), std::back_inserter(points),
|
||||
[](const Point &point) {
|
||||
return std::make_unique<SupportIslandPoint>(
|
||||
point, SupportIslandPoint::Type::inner);
|
||||
[&](const Point &point) {
|
||||
return std::make_unique<SupportIslandInnerPoint>(
|
||||
point, inner, SupportIslandPoint::Type::inner);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1231,11 +1233,14 @@ SampleIslandUtils::outline_offset(const Slic3r::ExPolygon &island,
|
||||
std::map<size_t, size_t> converter;
|
||||
for (size_t island_line_index = 0; island_line_index < island_lines.size(); ++island_line_index) {
|
||||
const Line &island_line = island_lines[island_line_index];
|
||||
Vec2f dir1 = LineUtils::direction(island_line).cast<float>();
|
||||
Vec2d dir1 = LineUtils::direction(island_line).cast<double>();
|
||||
dir1.normalize();
|
||||
for (size_t offset_line_index = 0; offset_line_index < offset_lines.size(); ++offset_line_index) {
|
||||
const Line &offset_line = offset_lines[offset_line_index];
|
||||
Vec2f dir2 = LineUtils::direction(offset_line).cast<float>();
|
||||
if (fabs(dir1.dot(dir2)) < 1e-4) { // in similar direction
|
||||
Vec2d dir2 = LineUtils::direction(offset_line).cast<double>();
|
||||
dir2.normalize();
|
||||
double angle = acos(dir1.dot(dir2));
|
||||
if (fabs(angle) < 1e-4) { // in similar direction
|
||||
Point middle = offset_line.a / 2 + offset_line.b / 2;
|
||||
double distance = island_line.perp_distance_to(middle);
|
||||
if (fabs(distance - offset_distance) < 20) {
|
||||
@ -1308,24 +1313,25 @@ SupportIslandPoints SampleIslandUtils::sample_outline(
|
||||
// sample line sequence
|
||||
auto add_lines_samples = [&](const Lines &inner_lines,
|
||||
size_t first_index,
|
||||
size_t last_index) {
|
||||
size_t last_index) {
|
||||
++last_index; // index after last item
|
||||
Lines lines;
|
||||
// is over start ?
|
||||
if (first_index > last_index) {
|
||||
size_t count = first_index + inner_lines.size() - last_index;
|
||||
size_t count = last_index + (inner_lines.size() - first_index);
|
||||
lines.reserve(count);
|
||||
std::copy(inner_lines.begin() + last_index,
|
||||
std::copy(inner_lines.begin() + first_index,
|
||||
inner_lines.end(),
|
||||
std::back_inserter(lines));
|
||||
std::copy(inner_lines.begin(),
|
||||
inner_lines.begin() + first_index,
|
||||
inner_lines.begin() + last_index,
|
||||
std::back_inserter(lines));
|
||||
} else {
|
||||
size_t count = last_index - first_index;
|
||||
lines.reserve(count);
|
||||
std::copy(inner_lines.begin() + first_index,
|
||||
inner_lines.begin() + last_index,
|
||||
std::back_inserter(lines));
|
||||
inner_lines.begin() + last_index,
|
||||
std::back_inserter(lines));
|
||||
}
|
||||
|
||||
// IMPROVE: find interesting points to start sampling
|
||||
@ -1376,8 +1382,11 @@ SupportIslandPoints SampleIslandUtils::sample_outline(
|
||||
// first and last index to inner lines
|
||||
size_t inner_first = inner_invalid;
|
||||
size_t inner_last = inner_invalid;
|
||||
size_t stop_index = first_change_index;
|
||||
if (stop_index == 0)
|
||||
stop_index = polygon.size();
|
||||
for (size_t polygon_index = first_change_index + 1;
|
||||
polygon_index != first_change_index; ++polygon_index) {
|
||||
polygon_index != stop_index; ++polygon_index) {
|
||||
if (polygon_index == polygon.size()) polygon_index = 0;
|
||||
size_t index = polygon_index + index_offset;
|
||||
assert(index < field.source_indexes.size());
|
||||
@ -1390,7 +1399,7 @@ SupportIslandPoints SampleIslandUtils::sample_outline(
|
||||
inner_last = inner_invalid;
|
||||
continue;
|
||||
}
|
||||
auto convert_index_item = field_2_inner.find(polygon_index);
|
||||
auto convert_index_item = field_2_inner.find(index);
|
||||
// check if exist inner line
|
||||
if (convert_index_item == field_2_inner.end()) continue;
|
||||
inner_last = convert_index_item->second - index_offset;
|
||||
|
@ -145,10 +145,11 @@ SupportOutlineIslandPoint::MoveResult SupportOutlineIslandPoint::create_result(
|
||||
const Line &line = restriction->lines[index];
|
||||
double line_ratio_full = LineUtils::foot(line, destination);
|
||||
double line_ratio = std::clamp(line_ratio_full, 0., 1.);
|
||||
Position new_position(index, line_ratio);
|
||||
Point new_point = calc_point(new_position, *restriction);
|
||||
double point_distance = (new_point - destination).cast<double>().norm();
|
||||
return MoveResult(new_position, new_point, point_distance);
|
||||
Position position(index, line_ratio);
|
||||
Point point = calc_point(position, *restriction);
|
||||
double distance_double = (point - destination).cast<double>().norm();
|
||||
coord_t distance = static_cast<coord_t>(distance_double);
|
||||
return MoveResult(position, point, distance);
|
||||
}
|
||||
|
||||
void SupportOutlineIslandPoint::update_result(MoveResult & result,
|
||||
@ -158,15 +159,61 @@ void SupportOutlineIslandPoint::update_result(MoveResult & result,
|
||||
const Line &line = restriction->lines[index];
|
||||
double line_ratio_full = LineUtils::foot(line, destination);
|
||||
double line_ratio = std::clamp(line_ratio_full, 0., 1.);
|
||||
Position new_position(index, line_ratio);
|
||||
Point new_point = calc_point(new_position, *restriction);
|
||||
Point diff = new_point - destination;
|
||||
Position position(index, line_ratio);
|
||||
Point point = calc_point(position, *restriction);
|
||||
Point diff = point - destination;
|
||||
if (abs(diff.x()) > result.distance) return;
|
||||
if (abs(diff.y()) > result.distance) return;
|
||||
double point_distance = diff.cast<double>().norm();
|
||||
if (result.distance > point_distance) {
|
||||
result.distance = point_distance;
|
||||
result.position = new_position;
|
||||
result.point = new_point;
|
||||
double distance_double = diff.cast<double>().norm();
|
||||
coord_t distance = static_cast<coord_t>(distance_double);
|
||||
if (result.distance > distance) {
|
||||
result.distance = distance;
|
||||
result.position = position;
|
||||
result.point = point;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////
|
||||
/// Inner Point
|
||||
///////////////////////
|
||||
|
||||
SupportIslandInnerPoint::SupportIslandInnerPoint(
|
||||
Point point, std::shared_ptr<ExPolygon> inner, Type type)
|
||||
: SupportIslandPoint(point, type), inner(std::move(inner))
|
||||
{}
|
||||
|
||||
coord_t SupportIslandInnerPoint::move(const Point &destination) {
|
||||
|
||||
// IMPROVE: Do not move over island hole if there is no connected island.
|
||||
// Can cause bad supported area in very special case.
|
||||
|
||||
if (inner->contains(destination))
|
||||
return SupportIslandPoint::move(destination);
|
||||
|
||||
// find closest line cross area border
|
||||
Vec2d v1 = (destination-point).cast<double>();
|
||||
double closest_ratio = 1.;
|
||||
Lines lines = to_lines(*inner);
|
||||
for (const Line &line : lines) {
|
||||
// line intersection
|
||||
const Vec2d v2 = LineUtils::direction(line).cast<double>();
|
||||
double denom = cross2(v1, v2);
|
||||
// is line parallel
|
||||
if (fabs(denom) < std::numeric_limits<float>::epsilon()) continue;
|
||||
|
||||
const Vec2d v12 = (point - line.a).cast<double>();
|
||||
double nume1 = cross2(v2, v12);
|
||||
double t1 = nume1 / denom;
|
||||
if (t1 < 0. || t1 > closest_ratio) continue; // out of line
|
||||
|
||||
double nume2 = cross2(v1, v12);
|
||||
double t2 = nume2 / denom;
|
||||
if (t2 < 0. || t2 > 1.0) continue; // out of contour
|
||||
|
||||
closest_ratio = t1;
|
||||
}
|
||||
// no correct closest point --> almost parallel cross
|
||||
if (closest_ratio >= 1.) return 0;
|
||||
Point new_point = point + (closest_ratio * v1).cast<coord_t>();
|
||||
return SupportIslandPoint::move(new_point);
|
||||
}
|
@ -83,6 +83,30 @@ public:
|
||||
using SupportIslandPointPtr = std::unique_ptr<SupportIslandPoint>;
|
||||
using SupportIslandPoints = std::vector<SupportIslandPointPtr>;
|
||||
|
||||
/// <summary>
|
||||
/// Support point with no move during aligning
|
||||
/// </summary>
|
||||
class SupportIslandNoMovePoint : public SupportIslandPoint
|
||||
{
|
||||
public:
|
||||
//constructor
|
||||
using SupportIslandPoint::SupportIslandPoint;
|
||||
|
||||
/// <summary>
|
||||
/// Can move?
|
||||
/// </summary>
|
||||
/// <returns>FALSE</returns>
|
||||
virtual bool can_move() const override { return false; }
|
||||
|
||||
/// <summary>
|
||||
/// No move!
|
||||
/// Should not be call.
|
||||
/// </summary>
|
||||
/// <param name="destination">Wanted position</param>
|
||||
/// <returns>No move means zero distance</returns>
|
||||
virtual coord_t move(const Point &destination) { return 0; }
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// DTO Support point laying on voronoi graph edge
|
||||
/// Restriction to move only on Voronoi graph
|
||||
@ -250,9 +274,9 @@ private:
|
||||
// point laying on restricted line
|
||||
Point point;
|
||||
// distance point on restricted line from destination point
|
||||
double distance;
|
||||
coord_t distance;
|
||||
|
||||
MoveResult(Position position, Point point, double distance)
|
||||
MoveResult(Position position, Point point, coord_t distance)
|
||||
: position(position), point(point), distance(distance)
|
||||
{}
|
||||
};
|
||||
@ -260,5 +284,30 @@ private:
|
||||
void update_result(MoveResult& result, size_t index, const Point &destination);
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Store pointer to inner ExPolygon for allowed move across island area
|
||||
/// Give an option to move with point
|
||||
/// </summary>
|
||||
class SupportIslandInnerPoint: public SupportIslandPoint
|
||||
{
|
||||
// define inner area of island where inner point could move during aligning
|
||||
std::shared_ptr<ExPolygon> inner;
|
||||
public:
|
||||
SupportIslandInnerPoint(Point point,
|
||||
std::shared_ptr<ExPolygon> inner,
|
||||
Type type = Type::inner);
|
||||
|
||||
bool can_move() const override { return true; };
|
||||
|
||||
/// <summary>
|
||||
/// Move nearest to destination point
|
||||
/// only inside inner area
|
||||
/// + change current position
|
||||
/// </summary>
|
||||
/// <param name="destination">Wanted support position</param>
|
||||
/// <returns>move distance euclidean</returns>
|
||||
coord_t move(const Point &destination) override;
|
||||
};
|
||||
|
||||
} // namespace Slic3r::sla
|
||||
#endif // slic3r_SLA_SuppotstIslands_SupportIslandPoint_hpp_
|
||||
|
@ -16,7 +16,7 @@
|
||||
using namespace Slic3r;
|
||||
using namespace Slic3r::sla;
|
||||
|
||||
//#define STORE_SAMPLE_INTO_SVG_FILES
|
||||
#define STORE_SAMPLE_INTO_SVG_FILES
|
||||
|
||||
TEST_CASE("Overhanging point should be supported", "[SupGen]") {
|
||||
|
||||
@ -273,17 +273,40 @@ ExPolygon create_tiny_wide_test_2(double wide, double tiny)
|
||||
return result;
|
||||
}
|
||||
|
||||
ExPolygon create_tiny_between_holes(double wide, double tiny)
|
||||
{
|
||||
double hole_size = wide;
|
||||
double width = 2 * wide + 2*hole_size + tiny;
|
||||
double height = 2 * wide + hole_size;
|
||||
auto outline = PolygonUtils::create_rect(width, height);
|
||||
auto holeL = PolygonUtils::create_rect(hole_size, hole_size);
|
||||
holeL.reverse();
|
||||
auto holeR = holeL;
|
||||
int hole_move_x = (hole_size + tiny)/2;
|
||||
holeL.translate(-hole_move_x, 0);
|
||||
holeR.translate(hole_move_x, 0);
|
||||
|
||||
ExPolygon result(outline);
|
||||
result.holes = {holeL, holeR};
|
||||
return result;
|
||||
}
|
||||
|
||||
// stress test for longest path
|
||||
// needs reshape
|
||||
ExPolygon create_mountains(double size) {
|
||||
return ExPolygon({{0., 0.},
|
||||
{size, 0.},
|
||||
{5 * size / 6, size},
|
||||
{4 * size / 6, size / 6},
|
||||
{3 * size / 7, 2 * size},
|
||||
{2 * size / 7, size / 6},
|
||||
{size / 7, size}});
|
||||
}
|
||||
|
||||
ExPolygons createTestIslands(double size)
|
||||
{
|
||||
bool useFrogLeg = false;
|
||||
// need post reorganization of longest path
|
||||
ExPolygon mountains({{0., 0.},
|
||||
{size, 0.},
|
||||
{5 * size / 6, size},
|
||||
{4 * size / 6, size / 6},
|
||||
{3 * size / 7, 2 * size},
|
||||
{2 * size / 7, size / 6},
|
||||
{size / 7, size}});
|
||||
ExPolygons result = {
|
||||
// one support point
|
||||
ExPolygon(PolygonUtils::create_equilateral_triangle(size)),
|
||||
@ -311,13 +334,14 @@ ExPolygons createTestIslands(double size)
|
||||
ExPolygon(PolygonUtils::create_isosceles_triangle(5. * size, 40. * size)),
|
||||
create_tiny_wide_test_1(3 * size, 2 / 3. * size),
|
||||
create_tiny_wide_test_2(3 * size, 2 / 3. * size),
|
||||
create_tiny_between_holes(3 * size, 2 / 3. * size),
|
||||
|
||||
// still problem
|
||||
// three support points
|
||||
ExPolygon(PolygonUtils::create_equilateral_triangle(3 * size)),
|
||||
ExPolygon(PolygonUtils::create_circle(size, 20)),
|
||||
|
||||
mountains,
|
||||
create_mountains(size),
|
||||
create_trinagle_with_hole(size),
|
||||
create_square_with_hole(size, size / 2),
|
||||
create_square_with_hole(size, size / 3)
|
||||
@ -661,7 +685,7 @@ TEST_CASE("Compare sampling test", "[hide]")
|
||||
enum class Sampling {
|
||||
old,
|
||||
filip
|
||||
} sample_type = Sampling::filip;
|
||||
} sample_type = Sampling::old;
|
||||
|
||||
std::function<std::vector<Vec2f>(const ExPolygon &)> sample =
|
||||
(sample_type == Sampling::old) ? sample_old :
|
||||
@ -689,7 +713,7 @@ TEST_CASE("Compare sampling test", "[hide]")
|
||||
}
|
||||
|
||||
#include <libslic3r/SLA/SupportIslands/VectorUtils.hpp>
|
||||
TEST_CASE("Reorder destructive", "[hide]"){
|
||||
TEST_CASE("Reorder destructive", "[Utils]"){
|
||||
std::vector<int> data {0, 1, 3, 2, 4, 7, 6, 5, 8};
|
||||
std::vector<int> order{0, 1, 3, 2, 4, 7, 6, 5, 8};
|
||||
|
||||
@ -699,6 +723,50 @@ TEST_CASE("Reorder destructive", "[hide]"){
|
||||
}
|
||||
}
|
||||
|
||||
#include <libslic3r/SLA/SupportIslands/LineUtils.hpp>
|
||||
TEST_CASE("Intersection point", "[Utils]")
|
||||
{
|
||||
Point a1(0, 0);
|
||||
Point b1(3, 6);
|
||||
Line l1(a1, b1);
|
||||
auto intersection = LineUtils::intersection(l1, Line(Point(0, 4), Point(5, 4)));
|
||||
CHECK(intersection.has_value());
|
||||
Point i_point = intersection->cast<coord_t>();
|
||||
CHECK(PointUtils::is_equal(i_point, Point(2, 4)));
|
||||
|
||||
// same line
|
||||
auto bad_intersection = LineUtils::intersection(l1, l1);
|
||||
CHECK(!bad_intersection.has_value());
|
||||
|
||||
// oposit direction
|
||||
bad_intersection = LineUtils::intersection(l1, Line(b1,a1));
|
||||
CHECK(!bad_intersection.has_value());
|
||||
|
||||
// parallel line
|
||||
bad_intersection = LineUtils::intersection(l1, Line(a1 + Point(0, 1),
|
||||
b1 + Point(0, 1)));
|
||||
CHECK(!bad_intersection.has_value());
|
||||
|
||||
// out of line segment, but ray has intersection
|
||||
Line l2(Point(0, 8), Point(6, 8));
|
||||
intersection = LineUtils::intersection(l1, l2);
|
||||
auto intersection2 = LineUtils::intersection(l2, l1);
|
||||
CHECK(intersection.has_value());
|
||||
CHECK(intersection2.has_value());
|
||||
i_point = intersection->cast<coord_t>();
|
||||
CHECK(PointUtils::is_equal(i_point, Point(4, 8)));
|
||||
CHECK(PointUtils::is_equal(i_point, intersection2->cast<coord_t>()));
|
||||
|
||||
Line l3(Point(-2, -2), Point(1, -2));
|
||||
intersection = LineUtils::intersection(l1, l3);
|
||||
intersection2 = LineUtils::intersection(l3, l1);
|
||||
CHECK(intersection.has_value());
|
||||
CHECK(intersection2.has_value());
|
||||
i_point = intersection->cast<coord_t>();
|
||||
CHECK(PointUtils::is_equal(i_point, Point(-1, -2)));
|
||||
CHECK(PointUtils::is_equal(i_point, intersection2->cast<coord_t>()));
|
||||
}
|
||||
|
||||
TEST_CASE("Disable visualization", "[hide]")
|
||||
{
|
||||
CHECK(true);
|
||||
|
Loading…
x
Reference in New Issue
Block a user