Fix calculation of width on VD

This commit is contained in:
Filip Sykala 2021-04-07 17:11:42 +02:00 committed by Lukas Matena
parent 51ce8fbd62
commit 214f1acea6
8 changed files with 183 additions and 78 deletions

View File

@ -316,7 +316,8 @@ LineUtils::LineConnection LineUtils::create_line_connection(const Slic3r::Lines
if (!inserts(prev_index, index)) {
bool found_index = false;
bool found_prev_index = false;
std::remove_if(not_finished.begin(), not_finished.end(),
not_finished.erase(std::remove_if(not_finished.begin(),
not_finished.end(),
[&](const size_t &not_finished_index) {
if (!found_index && inserts(index, not_finished_index)) {
found_index = true;
@ -327,7 +328,8 @@ LineUtils::LineConnection LineUtils::create_line_connection(const Slic3r::Lines
return true;
}
return false;
});
}),
not_finished.end());
if (!found_index) not_finished.push_back(index);
if (!found_prev_index) not_finished.push_back(prev_index);
}
@ -337,6 +339,16 @@ LineUtils::LineConnection LineUtils::create_line_connection(const Slic3r::Lines
return line_connection;
}
Slic3r::BoundingBox LineUtils::create_bounding_box(const Lines &lines) {
Points pts;
pts.reserve(lines.size()*2);
for (const Line &line : lines) {
pts.push_back(line.a);
pts.push_back(line.b);
}
return BoundingBox(pts);
}
std::map<size_t, size_t> LineUtils::create_line_connection_over_b(const Lines &lines)
{
static const size_t bad_index = -1;
@ -352,24 +364,37 @@ std::map<size_t, size_t> LineUtils::create_line_connection_over_b(const Lines &l
return true;
};
std::vector<size_t> not_finished;
std::vector<size_t> not_finished_a;
std::vector<size_t> not_finished_b;
size_t prev_index = lines.size() - 1;
for (size_t index = 0; index < lines.size(); ++index) {
if (!inserts(prev_index, index)) {
bool found = false;
std::remove_if(not_finished.begin(), not_finished.end(),
bool found_b = false;
not_finished_b.erase(std::remove_if(not_finished_b.begin(), not_finished_b.end(),
[&](const size_t &not_finished_index) {
if (!found && inserts(prev_index, not_finished_index)) {
found = true;
if (!found_b && inserts(prev_index, not_finished_index)) {
found_b = true;
return true;
}
return false;
});
if(!found) not_finished.push_back(prev_index);
}),not_finished_b.end());
if (!found_b) not_finished_a.push_back(prev_index);
bool found_a = false;
not_finished_a.erase(std::remove_if(not_finished_a.begin(), not_finished_a.end(),
[&](const size_t &not_finished_index) {
if (!found_a && inserts(not_finished_index, index)) {
found_a = true;
return true;
}
return false;
}),not_finished_a.end());
if (!found_a) not_finished_b.push_back(index);
}
prev_index = index;
}
assert(not_finished.empty());
assert(not_finished_a.empty());
assert(not_finished_b.empty());
return line_connection;
}

View File

@ -128,6 +128,13 @@ public:
/// <returns>map of connected lines.</returns>
static LineConnection create_line_connection(const Lines &lines);
/// <summary>
/// create bounding box around lines
/// </summary>
/// <param name="lines">input lines</param>
/// <returns>Bounding box</returns>
static BoundingBox create_bounding_box(const Lines &lines);
/// <summary>
/// Create data structure from exPolygon lines to store connected line indexes
/// </summary>

View File

@ -18,7 +18,7 @@ bool PointUtils::is_majorit_x(const Vec2d &point)
Slic3r::Point PointUtils::perp(const Point &vector)
{
return Point(-vector.x(), vector.y());
return Point(-vector.y(), vector.x());
}
bool PointUtils::is_same_direction(const Point &dir1, const Point &dir2)

View File

@ -783,18 +783,19 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
auto add_wide_tiny_change = [&](const VoronoiGraph::Node::Neighbor *neighbor){
VoronoiGraph::Position position =
VoronoiGraphUtils::get_position_with_distance(neighbor, min_width, lines);
Point p1, p2;
std::tie(p1, p2) = VoronoiGraphUtils::point_on_lines(position, lines);
const VD::edge_type *edge = neighbor->edge;
size_t i1 = edge->cell()->source_index();
size_t i2 = edge->twin()->cell()->source_index();
const Line &l1 = lines[i1];
const Line &l2 = lines[i2];
Point p1, p2;
std::tie(p1, p2) = VoronoiGraphUtils::point_on_lines(position, l1, l2);
if (VoronoiGraphUtils::is_opposit_direction(edge, l1)) {
// line1 is shorten on side line1.a --> line2 is shorten on side line2.b
assert(wide_tiny_changes.find(i2) == wide_tiny_changes.end());
wide_tiny_changes.insert({i2, WideTinyChange(p2, p1, i1)});
} else {
// line1 is shorten on side line1.b
assert(wide_tiny_changes.find(i1) == wide_tiny_changes.end());
wide_tiny_changes.insert({i1, WideTinyChange(p1, p2, i2)});
}
};
@ -811,30 +812,32 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
std::set<size_t> field_line_indexes;
while (!process.empty()) {
const VoronoiGraph::Node *node = process.front();
const VoronoiGraph::Node *prev_node = nullptr;
process.pop();
if (done.find(node) != done.end()) continue;
do {
done.insert(node);
const auto &neighbors = node->neighbors;
node = nullptr;
for (const VoronoiGraph::Node::Neighbor &neighbor : neighbors) {
if (done.find(neighbor.node) != done.end()) continue;
const VD::edge_type *edge = neighbor.edge;
const VoronoiGraph::Node *next_node = nullptr;
for (const VoronoiGraph::Node::Neighbor &neighbor: node->neighbors) {
if (neighbor.node == prev_node) continue;
const VD::edge_type *edge = neighbor.edge;
size_t index1 = edge->cell()->source_index();
size_t index2 = edge->twin()->cell()->source_index();
field_line_indexes.insert(index1);
field_line_indexes.insert(index2);
if (neighbor.max_width <
config.min_width_for_outline_support) {
if (neighbor.max_width < config.min_width_for_outline_support) {
add_wide_tiny_change(&neighbor);
continue;
}
if (node == nullptr) {
node = neighbor.node;
if (done.find(neighbor.node) != done.end()) continue; // loop back
if (next_node == nullptr) {
next_node = neighbor.node;
} else {
process.push(neighbor.node);
}
}
prev_node = node;
node = next_node;
} while (node != nullptr);
}

View File

@ -0,0 +1,32 @@
#include "SupportIslandPoint.hpp"
#include "VoronoiGraphUtils.hpp"
using namespace Slic3r::sla;
SupportIslandPoint::SupportIslandPoint(Slic3r::Point point, Type type)
: point(std::move(point)), type(type)
{}
coord_t SupportIslandPoint::move(const Point &destination)
{
Point diff = destination - point;
point = destination;
// TODO: check move out of island !!
// + need island ExPolygon
return diff.x() + diff.y(); // Manhatn distance
}
coord_t SupportCenterIslandPoint::move(const Point &destination)
{
// TODO: For decide of move need information about
// + search distance for allowed move over VG(count or distance)
// move only along VD
position = VoronoiGraphUtils::align(position, destination, max_distance);
Point new_point = VoronoiGraphUtils::create_edge_point(position);
Point move = new_point - point;
point = new_point;
return abs(move.x()) + abs(move.y());
}

View File

@ -377,8 +377,17 @@ double VoronoiGraphUtils::calculate_length(
double VoronoiGraphUtils::calculate_max_width(
const VD::edge_type &edge, const Lines &lines)
{
Point v0 = to_point(edge.vertex0());
Point v1 = to_point(edge.vertex1());
auto get_squared_distance = [&](const VD::vertex_type *vertex,
const Point &point) -> double {
Point point_v = to_point(vertex);
Vec2d vector = (point - point_v).cast<double>();
return vector.x() * vector.x() + vector.y() * vector.y();
};
auto max_width = [&](const Point& point)->double{
return 2. *
sqrt(std::max(get_squared_distance(edge.vertex0(), point),
get_squared_distance(edge.vertex1(), point)));
};
if (edge.is_linear()) {
// edge line could be initialized by 2 points
@ -393,11 +402,7 @@ double VoronoiGraphUtils::calculate_max_width(
boost::polygon::SOURCE_CATEGORY_SEGMENT_END_POINT);
source_point = source_line.b;
}
Point vec0 = source_point - v0;
Point vec1 = source_point - v1;
double distance0 = sqrt(vec0.x() * vec0.x() + vec0.y() * vec0.y());
double distance1 = sqrt(vec0.x() * vec0.x() + vec0.y() * vec0.y());
return 2 * std::max(distance0, distance1);
return max_width(source_point);
}
assert(edge.cell()->contains_segment());
assert(!edge.twin()->cell()->contains_point());
@ -405,6 +410,8 @@ double VoronoiGraphUtils::calculate_max_width(
const Line &line = lines[edge.cell()->source_index()];
Point v0 = to_point(edge.vertex0());
Point v1 = to_point(edge.vertex1());
double distance0 = line.perp_distance_to(v0);
double distance1 = line.perp_distance_to(v1);
return 2 * std::max(distance0, distance1);
@ -413,11 +420,7 @@ double VoronoiGraphUtils::calculate_max_width(
Parabola parabola = get_parabola(edge, lines);
// distance to point and line is same
// vector from edge vertex to parabola focus point
Point vec0 = parabola.focus - v0;
Point vec1 = parabola.focus - v1;
double distance0 = sqrt(vec0.x() * vec0.x() + vec0.y() * vec0.y());
double distance1 = sqrt(vec0.x() * vec0.x() + vec0.y() * vec0.y());
return 2 * std::max(distance0, distance1);
return max_width(parabola.focus);
}
VoronoiGraph VoronoiGraphUtils::create_skeleton(const VD &vd, const Lines &lines)
@ -881,35 +884,39 @@ VoronoiGraph::Position VoronoiGraphUtils::get_position_with_distance(
return result;
}
Slic3r::Point VoronoiGraphUtils::point_on_line(
const VoronoiGraph::Position &position, const Line &line)
{
const VD::edge_type* edge = position.neighbor->edge;
assert(edge->is_linear());
Point edge_point = create_edge_point(position);
Point dir = to_point(edge->vertex0()) - to_point(edge->vertex1());
Line edge_line(edge_point, edge_point + PointUtils::perp(dir));
std::optional<Vec2d> intersection = LineUtils::intersection(line, edge_line);
assert(intersection.has_value());
return intersection->cast<coord_t>();
}
std::pair<Slic3r::Point, Slic3r::Point> VoronoiGraphUtils::point_on_lines(
const VoronoiGraph::Position &position,
const Line & first,
const Line & second)
const VoronoiGraph::Position &position, const Lines &lines)
{
const VD::edge_type *edge = position.neighbor->edge;
assert(edge->is_linear());
// TODO: solve point on parabola
//assert(edge->is_linear());
bool is_linear = edge->is_linear();
Point edge_point = create_edge_point(position);
Point dir = to_point(edge->vertex0()) - to_point(edge->vertex1());
Line edge_line(edge_point, edge_point + PointUtils::perp(dir));
std::optional<Vec2d> first_intersection = LineUtils::intersection(first, edge_line);
assert(first_intersection.has_value());
std::optional<Vec2d> second_intersection = LineUtils::intersection(second, edge_line);
assert(second_intersection.has_value());
return {first_intersection->cast<coord_t>(),
second_intersection->cast<coord_t>()};
Line intersecting_line(edge_point, edge_point + PointUtils::perp(dir));
auto point_on_line = [&](const VD::edge_type *edge) -> Point {
assert(edge->is_finite());
const VD::cell_type *cell = edge->cell();
size_t line_index = cell->source_index();
const Line &line = lines[line_index];
using namespace boost::polygon;
bool is_single_point = cell->source_category() ==
SOURCE_CATEGORY_SINGLE_POINT;
if (cell->source_category() == SOURCE_CATEGORY_SEGMENT_START_POINT) {
return line.a;
}
if (cell->source_category() == SOURCE_CATEGORY_SEGMENT_END_POINT) {
return line.b;
}
std::optional<Vec2d> intersection = LineUtils::intersection(line, intersecting_line);
assert(intersection.has_value());
return intersection->cast<coord_t>();
};
return {point_on_line(edge), point_on_line(edge->twin())};
}
VoronoiGraph::Position VoronoiGraphUtils::align(
@ -1074,18 +1081,34 @@ double VoronoiGraphUtils::get_max_width(const VoronoiGraph::Node *node)
void VoronoiGraphUtils::draw(SVG & svg,
const VoronoiGraph &graph,
coord_t width)
coord_t width,
bool pointer_caption)
{
auto print_address = [&](const Point& p, const char* prefix, void * addr, const char* color){
if (pointer_caption) {
std::stringstream ss;
ss << prefix << std::hex << (int) addr;
std::string s = ss.str();
svg.draw_text(p, s.c_str(), color);
}
};
for (const auto &[key, value] : graph.data) {
svg.draw(Point(key->x(), key->y()), "lightgray", width);
Point p(key->x(), key->y());
svg.draw(p, "lightgray", width);
print_address(p, "v_",(void*)key, "lightgray");
for (const auto &n : value.neighbors) {
if (n.edge->vertex0() > n.edge->vertex1()) continue;
Point from = to_point(n.edge->vertex0());
Point to = to_point(n.edge->vertex1());
bool is_second = n.edge->vertex0() > n.edge->vertex1();
Point center = (from + to) / 2;
Point p = center + ((is_second) ? Point(0., -2e6) :
Point(0., 2e6));
print_address(p, "n_", (void *) &n, "gray");
if (is_second) continue;
svg.draw_text(center + Point(-6e6, 0.), ("w="+std::to_string(n.max_width)).c_str(), "gray");
svg.draw(Line(from, to), "gray", width);
Point center = from + to;
center *= .5;
// svg.draw_text(center,
// (std::to_string(std::round(n.edge_length/3e5)/100.)).c_str(), "gray");
}

View File

@ -359,26 +359,18 @@ public:
coord_t width,
const Lines & lines);
/// <summary>
/// Calculate point on line correspond to edge position
/// </summary>
/// <param name="position">Position on edge</param>
/// <param name="line">Line must be source of edge</param>
/// <returns>Point lay on line defined by position on edge</returns>
static Point point_on_line(const VoronoiGraph::Position& position, const Line& line);
/// <summary>
/// calculate both point on source lines correspond to edge postion
/// Faster way to get both point_on_line
/// </summary>
/// <param name="position">Position on edge</param>
/// <param name="line">Line must be source of edge</param>
/// <param name="line">Line must be source of edge</param>
/// <returns>pair of point lay on lines cirrespond to position</returns>
/// <param name="lines">Source lines of VD</param>
/// <returns>pair of point lay on outline lines correspond to position on edge
/// first -> source line of edge cell
/// second -> source line of edge twin cell </returns>
static std::pair<Point, Point> point_on_lines(
const VoronoiGraph::Position &position,
const Line & first,
const Line & second);
const Lines & lines);
/// <summary>
/// align "position" close to point "to"
@ -418,7 +410,7 @@ public:
static double get_max_width(const VoronoiGraph::Node *node);
public: // draw function for debug
static void draw(SVG &svg, const VoronoiGraph &graph, coord_t width);
static void draw(SVG &svg, const VoronoiGraph &graph, coord_t width, bool pointer_caption = false);
static void draw(SVG & svg,
const VoronoiGraph::Nodes &path,
coord_t width,

View File

@ -218,6 +218,29 @@ Slic3r::Polygon create_V_shape(double height, double line_width, double angle =
return polygons.front();
}
ExPolygon create_tiny_wide_test(double wide, double tiny)
{
double hole_size = wide;
double width = (2 + 1) * wide + 2 * hole_size;
double height = wide + 2*tiny + 2*hole_size;
auto outline = PolygonUtils::create_rect( width, height);
auto hole = PolygonUtils::create_rect(hole_size, hole_size);
hole.reverse();
auto hole2 = hole;// copy
auto hole3 = hole; // copy
auto hole4 = hole; // copy
int hole_move_x = wide / 2 + hole_size / 2;
int hole_move_y = wide / 2 + hole_size / 2;
hole.translate({hole_move_x, hole_move_y});
hole2.translate({-hole_move_x, hole_move_y});
hole3.translate({hole_move_x, -hole_move_y});
hole4.translate({-hole_move_x, -hole_move_y});
ExPolygon result(outline);
result.holes = {hole, hole2, hole3, hole4};
return result;
}
ExPolygons createTestIslands(double size)
{
bool useFrogLeg = false;