Add allignable inner support island point

This commit is contained in:
Filip Sykala 2021-05-03 08:16:42 +02:00 committed by Lukas Matena
parent 10c05ca01e
commit 0c9dedcffa
5 changed files with 217 additions and 44 deletions

View File

@ -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()

View File

@ -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;

View File

@ -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);
}

View File

@ -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_

View File

@ -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);