801{
803 size_t poly_idx = 0;
804
805
806 const float scaled_offset = float(
scale_(spacing) * 0.81);
807
808 const float scaled_trim_distance = float(
scale_(spacing) * 0.5 * 0.75);
809
810
811 std::vector<std::pair<rtree_segment_t, size_t>> closest;
812
813 std::vector<std::pair<const Polyline*, const Polyline*>> lines_touching_at_endpoints;
814 {
815
816
819 assert(poly.points.size() == 2);
820 if (&poly != lines.data()) {
821
822 auto collinear_segment = [&rtree, &closest, &lines, &lines_touching_at_endpoints, r2_close](
const Point& pt,
const Point& pt_other,
const Polyline* polyline) -> std::pair<Polyline*, bool> {
823 closest.clear();
824 rtree.query(bgi::nearest(
mk_rtree_point(pt), 1), std::back_inserter(closest));
825 const Polyline *other = &lines[closest.front().second];
826 double dist2_front = (other->
points.front() - pt).cast<double>().squaredNorm();
827 double dist2_back = (other->
points.back() - pt).cast<double>().squaredNorm();
828 double dist2_min = std::min(dist2_front, dist2_back);
829 if (dist2_min < r2_close) {
830
831 double dist2_min_other = std::min((other->
points.front() - pt_other).cast<
double>().squaredNorm(), (other->
points.back() - pt_other).cast<
double>().squaredNorm());
832 if (dist2_min_other > dist2_min) {
833
834 Vec2d v1 = (pt_other - pt).cast<double>();
836 Vec2d v1n = v1.normalized();
837 Vec2d v2n = v2.normalized();
838
839 double d = v1n.dot(v2n);
840 if (std::abs(d) > 0.99f) {
841
842 rtree.remove(closest.front());
843 return std::make_pair(
const_cast<Polyline*
>(other), dist2_min == dist2_front);
844 } else {
845 if (polyline > other)
846 std::swap(polyline, other);
847 lines_touching_at_endpoints.emplace_back(polyline, other);
848 }
849 }
850 }
851 return std::make_pair(static_cast<Polyline*>(nullptr), false);
852 };
853 auto collinear_front = collinear_segment(poly.points.front(), poly.points.back(), &poly);
854 auto collinear_back = collinear_segment(poly.points.back(), poly.points.front(), &poly);
855 assert(! collinear_front.first || ! collinear_back.first || collinear_front.first != collinear_back.first);
856 if (collinear_front.first) {
857 Polyline &other = *collinear_front.first;
858 assert(&other != &poly);
859 poly.points.front() = collinear_front.second ? other.points.back() : other.points.front();
860 other.points.clear();
861 }
862 if (collinear_back.first) {
863 Polyline &other = *collinear_back.first;
864 assert(&other != &poly);
865 poly.points.back() = collinear_back.second ? other.points.back() : other.points.front();
866 other.points.clear();
867 }
868 }
869 rtree.insert(std::make_pair(
mk_rtree_seg(poly.points.front(), poly.points.back()), poly_idx++));
870 }
871 }
872
873
875 lines_src.reserve(lines.size());
876 std::transform(lines.begin(), lines.end(), std::back_inserter(lines_src), [](const Polyline &pl) {
877 return pl.empty() ? Line(Point(0, 0), Point(0, 0)) : Line(pl.points.front(), pl.points.back()); });
878
880
881 std::vector<Intersection> intersections;
882 {
883
884
885
886 assert(scaled_offset > scaled_trim_distance);
887 const double line_len_threshold_drop_both_sides = scaled_offset * (2. /
cos(
PI / 6.) + 0.5) +
SCALED_EPSILON;
888 const double line_len_threshold_anchor_both_sides = line_len_threshold_drop_both_sides + scaled_offset;
889 const double line_len_threshold_drop_single_side = scaled_offset * (1. /
cos(
PI / 6.) + 1.5) +
SCALED_EPSILON;
890 const double line_len_threshold_anchor_single_side = line_len_threshold_drop_single_side + scaled_offset;
891 for (size_t line_idx = 0; line_idx < lines.size(); ++ line_idx) {
892 Polyline &line = lines[line_idx];
893 if (line.points.empty())
894 continue;
895
896 Point &front_point = line.points.front();
897 Point &back_point = line.points.back();
898
899
900 std::optional<size_t> tjoint_front, tjoint_back;
901 {
902 auto has_tjoint = [&closest, line_idx, &rtree, &lines, &lines_src](
const Point &pt) {
903 auto filter_t_joint = [line_idx, &lines_src, pt](const auto &item) {
904 if (item.second != line_idx) {
905
906 const Line &line = lines_src[item.second];
907 const Vec2d v = (line.b - line.a).cast<double>();
908 const Vec2d va = (pt - line.a).cast<double>();
909 const double l2 = v.squaredNorm();
910 if (l2 > 0.) {
911 const double t = va.dot(v);
913 }
914 }
915 return false;
916 };
917 closest.clear();
918 rtree.query(bgi::nearest(
mk_rtree_point(pt), 1) && bgi::satisfies(filter_t_joint), std::back_inserter(closest));
919 std::optional<size_t> out;
920 if (! closest.empty()) {
921 const Polyline &pl = lines[closest.front().second];
922 if (pl.points.empty()) {
923
924
925 #if 0
926 const auto &seg = closest.front().first;
928 Linef l { { bg::get<0, 0>(seg), bg::get<0, 1>(seg) }, { bg::get<1, 0>(seg), bg::get<1, 1>(seg) } };
929 assert(line_alg::distance_to_squared(l,
Vec2d(pt.cast<
double>())) > 1000 * 1000);
930 #endif
931 } else if (pl.size() >= 2 &&
932
933 Line{ pl.front(), pl.back() }.distance_to_squared(pt) <= 1000 * 1000)
934 out = closest.front().second;
935 }
936 return out;
937 };
938
939 auto filter_end_point_connections = [&lines_touching_at_endpoints, &lines, &line](std::optional<size_t> in) {
940 std::optional<size_t> out;
941 if (in) {
942 const Polyline *lo = &line;
943 const Polyline *hi = &lines[*in];
944 if (lo > hi)
945 std::swap(lo, hi);
946 if (! std::binary_search(lines_touching_at_endpoints.begin(), lines_touching_at_endpoints.end(), std::make_pair(lo, hi)))
947
948 out = in;
949 }
950 return out;
951 };
952 tjoint_front = filter_end_point_connections(has_tjoint(front_point));
953 tjoint_back = filter_end_point_connections(has_tjoint(back_point));
954 }
955
956 int num_tjoints = int(tjoint_front.has_value()) + int(tjoint_back.has_value());
957 if (num_tjoints > 0) {
958 double line_len = line.length();
959 bool drop = false;
960 bool anchor = false;
961 if (num_tjoints == 1) {
962
963 drop = line_len < line_len_threshold_drop_single_side;
964 anchor = line_len > line_len_threshold_anchor_single_side;
965 } else {
966
967 assert(num_tjoints == 2);
968 drop = line_len < line_len_threshold_drop_both_sides;
969 anchor = line_len > line_len_threshold_anchor_both_sides;
970 }
971 if (drop) {
972
973
974
975 line.points.clear();
976 } else if (anchor) {
977 if (tjoint_front) {
978
979 intersections.emplace_back(lines_src[*tjoint_front], lines_src[line_idx], &line, front_point, true);
981 }
982 if (tjoint_back) {
983
984 intersections.emplace_back(lines_src[*tjoint_back], lines_src[line_idx], &line, back_point, false);
986 }
987 } else {
988 if (tjoint_front)
989
990
991 front_point += ((scaled_trim_distance * 1.155) * (back_point - front_point).cast<double>().normalized()).cast<coord_t>();
992 if (tjoint_back)
993
994
995 back_point += ((scaled_trim_distance * 1.155) * (front_point - back_point).cast<double>().normalized()).cast<coord_t>();
996 }
997 }
998 }
999
1000 for (auto it = intersections.begin(); it != intersections.end(); ) {
1001 assert(! lines[it->intersect_line - lines_src.data()].points.empty());
1002 if (lines[it->closest_line - lines_src.data()].points.empty()) {
1003 *it = intersections.back();
1004 intersections.pop_back();
1005 } else
1006 ++ it;
1007 }
1008 }
1010
1011#ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
1012 static int iRun = 0;
1013 int iStep = 0;
1014 {
1016 for (const Intersection &i : intersections)
1017 pts.emplace_back(i.intersect_point);
1018 export_infill_lines_to_svg(boundary, lines,
debug_out_path(
"FillAdaptive-Tjoints-%d.svg", iRun++), pts);
1019 }
1020#endif
1021
1022
1023 std::sort(intersections.begin(), intersections.end(),
1024 [](const Intersection &i1, const Intersection &i2) {
1025 return (i1.closest_line == i2.closest_line) ?
1026 int(i1.left) < int(i2.left) :
1027 i1.closest_line < i2.closest_line;
1028 });
1029
1030 std::vector<size_t> merged_with(lines.size());
1031 std::iota(merged_with.begin(), merged_with.end(), 0);
1032
1033
1034 {
1037 rtree.insert(std::make_pair(
mk_rtree_seg(prev, point), poly_idx++));
1038 prev = point;
1039 }
1040 for (
const Polygon &polygon : boundary.
holes) {
1041 Point prev = polygon.points.back();
1042 for (
const Point &point : polygon.points) {
1043 rtree.insert(std::make_pair(
mk_rtree_seg(prev, point), poly_idx++));
1044 prev = point;
1045 }
1046 }
1047 }
1048
1049 auto update_merged_polyline_idx = [&merged_with](size_t pl_idx) {
1050
1051 for (size_t last = pl_idx;;) {
1052 size_t lower = merged_with[last];
1053 if (lower == last) {
1054 merged_with[pl_idx] = lower;
1055 return lower;
1056 }
1057 last = lower;
1058 }
1059 assert(false);
1060 return size_t(0);
1061 };
1063
1064 size_t intersect_pl_idx = update_merged_polyline_idx(
intersection.intersect_pl - lines.data());
1066
1071 }
1072 };
1073
1074
1075 for (auto it = lines_touching_at_endpoints.rbegin(); it != lines_touching_at_endpoints.rend(); ++ it) {
1076 Polyline *pl1 = const_cast<Polyline*>(it->first);
1077 Polyline *pl2 = const_cast<Polyline*>(it->second);
1078 assert(pl1 < pl2);
1079
1080
1081 pl2 = &lines[update_merged_polyline_idx(pl2 - lines.data())];
1082 assert(pl1 <= pl2);
1083
1084 if (pl1 != pl2 && ! pl1->points.empty() && ! pl2->points.empty()) {
1085
1086 assert(pl1 < pl2);
1087 assert(pl1->points.size() >= 2);
1088 assert(pl2->points.size() >= 2);
1089 double d11 = (pl1->points.front() - pl2->points.front()).cast<double>().squaredNorm();
1090 double d12 = (pl1->points.front() - pl2->points.back()) .cast<double>().squaredNorm();
1091 double d21 = (pl1->points.back() - pl2->points.front()).cast<double>().squaredNorm();
1092 double d22 = (pl1->points.back() - pl2->points.back()) .cast<double>().squaredNorm();
1093 double d1min = std::min(d11, d12);
1094 double d2min = std::min(d21, d22);
1095 if (d1min < d2min) {
1096 pl1->reverse();
1097 if (d12 == d1min)
1098 pl2->reverse();
1099 } else if (d22 == d2min)
1100 pl2->reverse();
1101 pl1->points.back() = (pl1->points.back() + pl2->points.front()) / 2;
1102 pl1->append(pl2->points.begin() + 1, pl2->points.end());
1103 pl2->points.clear();
1104 merged_with[pl2 - lines.data()] = pl1 - lines.data();
1105 }
1106 }
1107
1108
1109 std::vector<std::pair<Intersection*, double>> intersect_line;
1110 for (size_t min_idx = 0; min_idx < intersections.size();) {
1111 intersect_line.clear();
1112
1113 {
1114 const Vec2d line_dir = intersections[min_idx].closest_line->vector().cast<
double>();
1115 size_t max_idx = min_idx;
1116 for (; max_idx < intersections.size() &&
1117 intersections[min_idx].closest_line == intersections[max_idx].closest_line &&
1118 intersections[min_idx].left == intersections[max_idx].left;
1119 ++ max_idx)
1120 intersect_line.emplace_back(&intersections[max_idx], line_dir.dot(intersections[max_idx].intersect_point.cast<double>()));
1121 min_idx = max_idx;
1122 assert(intersect_line.size() > 0);
1123
1124 std::sort(intersect_line.begin(), intersect_line.end(), [](const auto &i1, const auto &i2) { return i1.second < i2.second; });
1125 }
1126
1127 if (intersect_line.size() == 1) {
1128
1130 update_merged_polyline(first_i);
1131 if (first_i.fresh()) {
1132
1133#ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
1134 export_infill_lines_to_svg(boundary, lines,
debug_out_path(
"FillAdaptive-add_hook0-pre-%d-%d.svg", iRun, iStep), { first_i.intersect_point });
1135#endif
1136 add_hook(first_i, scaled_offset, hook_length, scaled_trim_distance, rtree, lines_src);
1137#ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
1138 export_infill_lines_to_svg(boundary, lines,
debug_out_path(
"FillAdaptive-add_hook0-pre-%d-%d.svg", iRun, iStep), { first_i.intersect_point });
1139 ++ iStep;
1140#endif
1141 first_i.used = true;
1142 }
1143 continue;
1144 }
1145
1146 for (size_t first_idx = 0; first_idx < intersect_line.size(); ++ first_idx) {
1147 Intersection &first_i = *intersect_line[first_idx].first;
1148 update_merged_polyline(first_i);
1149 if (! first_i.fresh())
1150
1151 continue;
1152
1153
1154 if (first_idx > 0)
1155 update_merged_polyline(*intersect_line[first_idx - 1].first);
1156 if (first_idx + 1 < intersect_line.size())
1157 update_merged_polyline(*intersect_line[first_idx + 1].first);
1159 assert(first_i.closest_line == nearest_i.closest_line);
1160 assert(first_i.intersect_line != nearest_i.intersect_line);
1161 assert(first_i.intersect_line != first_i.closest_line);
1162 assert(nearest_i.intersect_line != first_i.closest_line);
1163
1164 Line offset_line =
create_offset_line(Line(first_i.intersect_point, nearest_i.intersect_point), first_i, scaled_offset);
1165
1166
1167 Point first_i_point, nearest_i_point;
1168 bool could_connect = false;
1169 if (nearest_i.fresh()) {
1170 could_connect = first_i.intersect_line->intersection(offset_line, &first_i_point) &&
1171 nearest_i.intersect_line->intersection(offset_line, &nearest_i_point);
1172 assert(could_connect);
1173 }
1174 Points &first_points = first_i.intersect_pl->points;
1175 Points &second_points = nearest_i.intersect_pl->points;
1176 could_connect &= (nearest_i_point - first_i_point).cast<double>().squaredNorm() <=
Slic3r::sqr(hook_length_max);
1177 if (could_connect) {
1178
1179
1180 closest.clear();
1181 rtree.query(
1182 bgi::intersects(
mk_rtree_seg(first_i_point, nearest_i_point)) &&
1183 bgi::satisfies([&first_i, &nearest_i, &lines_src](const auto &item)
1184 { return item.second != (long unsigned int)(first_i.intersect_line - lines_src.data())
1185 && item.second != (long unsigned int)(nearest_i.intersect_line - lines_src.data()); }),
1186 std::back_inserter(closest));
1187 could_connect = closest.empty();
1188#if 0
1189
1190 if (could_connect && first_i.intersect_pl != nearest_i.intersect_pl) {
1191 Line l(first_i_point, nearest_i_point);
1192 could_connect = ! first_i.other_hook_intersects(l) && ! nearest_i.other_hook_intersects(l);
1193 }
1194#endif
1195 }
1196 bool connected = false;
1197 if (could_connect) {
1198#ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
1199 export_infill_lines_to_svg(boundary, lines,
debug_out_path(
"FillAdaptive-connecting-pre-%d-%d.svg", iRun, iStep), { first_i.intersect_point, nearest_i.intersect_point });
1200#endif
1201
1202 if (first_i.intersect_pl == nearest_i.intersect_pl) {
1203
1204 assert(first_i.front != nearest_i.front);
1205 if (! first_i.front)
1206 std::swap(first_i_point, nearest_i_point);
1207 first_points.front() = first_i_point;
1208 first_points.back() = nearest_i_point;
1209
1210 first_points.emplace(first_points.begin(), nearest_i_point);
1211 } else {
1212
1213 Line l(first_i_point, nearest_i_point);
1214 l.translate((
perp(first_i.closest_line->vector().cast<
double>().normalized()) * (first_i.left ? scaled_trim_distance : - scaled_trim_distance)).
cast<
coord_t>());
1215 Point pt_start, pt_end;
1216 bool trim_start = first_i .intersect_pl->points.size() == 3 && first_i .other_hook_intersects(l, pt_start);
1217 bool trim_end = nearest_i.intersect_pl->points.size() == 3 && nearest_i.other_hook_intersects(l, pt_end);
1218 first_points.reserve(first_points.size() + second_points.size());
1219 if (first_i.front)
1220 std::reverse(first_points.begin(), first_points.end());
1221 if (trim_start)
1222 first_points.front() = pt_start;
1223 first_points.back() = first_i_point;
1224 first_points.emplace_back(nearest_i_point);
1225 if (nearest_i.front)
1226 first_points.insert(first_points.end(), second_points.begin() + 1, second_points.end());
1227 else
1228 first_points.insert(first_points.end(), second_points.rbegin() + 1, second_points.rend());
1229 if (trim_end)
1230 first_points.back() = pt_end;
1231
1232 if (first_i.intersect_pl < nearest_i.intersect_pl) {
1233 second_points.clear();
1234 merged_with[nearest_i.intersect_pl - lines.data()] = first_i.intersect_pl - lines.data();
1235 } else {
1236 second_points = std::move(first_points);
1237 first_points.clear();
1238 merged_with[first_i.intersect_pl - lines.data()] = nearest_i.intersect_pl - lines.data();
1239 }
1240 }
1241 nearest_i.used = true;
1242 connected = true;
1243#ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
1244 export_infill_lines_to_svg(boundary, lines,
debug_out_path(
"FillAdaptive-connecting-post-%d-%d.svg", iRun, iStep), { first_i.intersect_point, nearest_i.intersect_point });
1245#endif
1246 }
1247 if (! connected) {
1248
1249#ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
1250 export_infill_lines_to_svg(boundary, lines,
debug_out_path(
"FillAdaptive-add_hook-pre-%d-%d.svg", iRun, iStep), { first_i.intersect_point });
1251#endif
1252 add_hook(first_i, scaled_offset, hook_length, scaled_trim_distance, rtree, lines_src);
1253#ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
1254 export_infill_lines_to_svg(boundary, lines,
debug_out_path(
"FillAdaptive-add_hook-post-%d-%d.svg", iRun, iStep), { first_i.intersect_point });
1255#endif
1256 }
1257#ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
1258 ++ iStep;
1259#endif
1260 first_i.used = true;
1261 }
1262 }
1263
1265 polylines_out.reserve(polylines_out.size() + std::count_if(lines.begin(), lines.end(), [](const Polyline &pl) { return !pl.empty(); }));
1266 for (Polyline &pl : lines)
1267 if (!pl.
empty()) polylines_out.emplace_back(
std::move(pl));
1268 return polylines_out;
1269}
EIGEN_DEVICE_FUNC const CosReturnType cos() const
Definition ArrayCwiseUnaryOps.h:202
EIGEN_DEVICE_FUNC CastXpr< NewType >::Type cast() const
Definition CommonCwiseUnaryOps.h:62
Polygon contour
Definition ExPolygon.hpp:35
Points points
Definition MultiPoint.hpp:18
Definition Polyline.hpp:17
if(!(yy_init))
Definition lexer.c:1190
static constexpr double PI
Definition libslic3r.h:58
#define scale_(val)
Definition libslic3r.h:69
bool validate_intersections(const std::vector< Intersection > &intersections)
Definition FillAdaptive.cpp:792
bool validate_intersection_t_joint(const Intersection &intersection)
Definition FillAdaptive.cpp:780
static rtree_point_t mk_rtree_point(const Point &pt)
Definition FillAdaptive.cpp:658
static Line create_offset_line(Line offset_line, const Intersection &intersection, const double scaled_offset)
Definition FillAdaptive.cpp:641
static void add_hook(const Intersection &intersection, const double scaled_offset, const coordf_t hook_length, double scaled_trim_distance, const rtree_t &rtree, const Lines &lines_src)
Definition FillAdaptive.cpp:669
static Intersection * get_nearest_intersection(std::vector< std::pair< Intersection *, double > > &intersect_line, const size_t first_idx)
Definition FillAdaptive.cpp:619
bgi::rtree< std::pair< rtree_segment_t, size_t >, bgi::rstar< 16, 4 > > rtree_t
Definition FillAdaptive.cpp:656
std::vector< Line > Lines
Definition Line.hpp:17
std::string debug_out_path(const char *name,...)
Definition utils.cpp:218
std::vector< Polyline > Polylines
Definition Polyline.hpp:14
constexpr T sqr(T x)
Definition libslic3r.h:258
void sort_remove_duplicates(std::vector< T > &vec)
Definition libslic3r.h:188
bool empty(const BoundingBoxBase< PointType, PointsType > &bb)
Definition BoundingBox.hpp:229
Pt perp(const Pt &p)
Definition geometry_traits.hpp:335
Slic3r::Polygon & contour(Slic3r::ExPolygon &sh)
Definition geometries.hpp:216
const THolesContainer< PolygonImpl > & holes(const Slic3r::ExPolygon &sh)
Definition geometries.hpp:189