1025{
1026
1028
1029 bool outside = offset_distance > 0;
1030 if (! outside)
1031 offset_distance = - offset_distance;
1032 assert(offset_distance > 0.);
1033
1036 static constexpr double nan = std::numeric_limits<double>::quiet_NaN();
1037
1039
1041 size_t edge_idx = &edge - first_edge;
1043
1044 continue;
1045
1048 if (v0 == nullptr) {
1050 continue;
1051 }
1052
1053 double d0 = (v0 == nullptr) ? std::numeric_limits<double>::max() : vertex_distances[v0 - first_vertex];
1054 double d1 = (v1 == nullptr) ? std::numeric_limits<double>::max() : vertex_distances[v1 - first_vertex];
1055 assert(d0 * d1 >= 0.);
1056 if (! outside) {
1057 d0 = - d0;
1058 d1 = - d1;
1059 }
1060#ifndef NDEBUG
1061 {
1066 if (v1 != nullptr) {
1071 }
1072 }
1073#endif
1074 double dmin, dmax;
1075 if (d0 < d1)
1076 dmin = d0, dmax = d1;
1077 else
1078 dmax = d0, dmin = d1;
1079
1080
1081
1082
1083
1084 if (offset_distance >= dmax)
1085 continue;
1086
1087
1088 assert(v0 != nullptr);
1091 const Line &line0 = lines[cell->source_index()];
1092 const Line &line1 = lines[cell2->source_index()];
1093 size_t edge_idx2 = edge.twin() - first_edge;
1094 if (v1 == nullptr) {
1095 assert(edge.is_infinite());
1096 assert(edge.is_linear());
1097
1098 assert(d0 != d1);
1099 if (offset_distance > dmin) {
1100
1101 if (cell->contains_point() && cell2->contains_point()) {
1102 assert(! edge.is_secondary());
1105
1106 Vec2d dir =
Vec2d(
double(pt0.y() - pt1.y()),
double(pt1.x() - pt0.x())) * (2. * offset_distance);
1107 Vec2d pt(v0->x(), v0->y());
1109 assert(t > 0.);
1110 out[edge_idx] = pt + t * dir;
1111 } else {
1112
1113 assert(cell->contains_point() != cell2->contains_point());
1114
1115 assert(edge.is_secondary());
1117 #ifndef NDEBUG
1118 if (cell->contains_segment()) {
1119 const Point &pt1 = contour_point(*cell2, line1);
1120 assert(pt1 == line0.a || pt1 == line0.b);
1121 } else {
1122 const Point &pt0 = contour_point(*cell, line0);
1123 assert(pt0 == line1.a || pt0 == line1.b);
1124 }
1126 #endif
1127
1128 const Line &line = cell->contains_segment() ? line0 : line1;
1129 assert(line.a == ipt || line.b == ipt);
1130 out[edge_idx] = ipt.cast<
double>() + offset_distance *
Vec2d(line.b.y() - line.a.y(), line.a.x() - line.b.x()).normalized();
1131 }
1132 } else if (offset_distance == dmin)
1134
1135 out[edge_idx2].y() = 1.;
1136 } else {
1137 assert(edge.is_finite());
1138 bool done = false;
1139
1140 bool bisector = cell->contains_segment() && cell2->contains_segment();
1141 assert(edge.is_finite());
1142
1143 if (bisector || edge.is_secondary()) {
1144 assert(edge.is_linear());
1145#ifndef NDEBUG
1146 if (edge.is_secondary()) {
1147 assert(cell->contains_point() != cell2->contains_point());
1148
1151 assert(dmin == 0.);
1152 }
1153#endif
1154 if (! bisector || (dmin != dmax && offset_distance >= dmin)) {
1155 double t = (offset_distance - dmin) / (dmax - dmin);
1156 t = std::clamp(t, 0., 1.);
1157 if (d1 < d0) {
1159
1160 out[edge_idx].y() = 1.;
1161 } else {
1163
1164 out[edge_idx2].y() = 1.;
1165 }
1166 done = true;
1167 }
1168 } else {
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188 assert(cell->contains_point() || cell2->contains_point());
1189 size_t num_intersections = 0;
1190 bool point_vs_segment = cell->contains_point() != cell2->contains_point();
1192
1193 Vec2d p0(v0->x(), v0->y());
1194 Vec2d p1(v1->x(), v1->y());
1196 const Point *pt1 =
nullptr;
1198 if (point_vs_segment) {
1199 const Line &line = cell->contains_segment() ? line0 : line1;
1201 } else {
1203
1204 dir =
Vec2d(
double(pt0.y() - pt1->y()),
double(pt1->x() - pt0.x()));
1205 }
1206 double s0 = (p0 -
px).
dot(dir);
1207 double s1 = (p1 -
px).
dot(dir);
1208 if (offset_distance >= dmin) {
1209
1210
1211 num_intersections = 1;
1212 } else {
1213
1214
1215 double dmin_new;
1216 bool found = false;
1217 if (point_vs_segment) {
1218 if (s0 * s1 <= 0.) {
1219
1220
1221
1222
1223 const Line &line = cell->contains_segment() ? line0 : line1;
1225 found = true;
1226 }
1227 } else {
1228
1229 if (s0 * s1 <= 0.) {
1230
1231 dmin_new = 0.5 * (pt1->cast<
double>() -
px).norm();
1232 found = true;
1233 }
1234 }
1235 if (found) {
1238 if (dmin_new <= offset_distance) {
1239
1240
1241
1242
1243
1244 dmin = dmin_new;
1245 num_intersections = (offset_distance > dmin) + 1;
1246 }
1247 }
1248 }
1249 if (num_intersections > 0) {
1251 if (point_vs_segment) {
1252 assert(cell->contains_point() || cell2->contains_point());
1254 } else {
1256 }
1257
1258
1259
1260 if (num_intersections == 2) {
1261 switch (intersections.count) {
1262 case 0:
1263
1264
1265
1266 break;
1267 case 1:
1268
1269
1270 break;
1271 default:
1272 {
1273
1274 assert(intersections.count == 2);
1275 double q0 = (intersections.pts[0] -
px).
dot(dir);
1276 double q1 = (intersections.pts[1] -
px).
dot(dir);
1277
1278 assert(q0 * q1 <= 0.);
1279 assert(s0 * s1 <= 0.);
1280
1281 if ((q0 < q1) != (s0 < s1))
1282 std::swap(intersections.pts[0], intersections.pts[1]);
1283 }
1284 }
1285 } else {
1286 assert(num_intersections == 1);
1287 switch (intersections.count) {
1288 case 0:
1289
1290
1291
1292 intersections.pts[0] = (dmin == d0) ? p0 : p1;
1293 intersections.count = 1;
1294 break;
1295 case 1:
1296
1297 break;
1298 default:
1299
1300
1301 assert(intersections.count == 2);
1302 double q0 = (intersections.pts[0] -
px).
dot(dir);
1303 double q1 = (intersections.pts[1] -
px).
dot(dir);
1304
1305 assert(q0 * q1 <= 0);
1306 double s = (dmax == d0) ? s0 : s1;
1307 bool take_2nd = (s > 0.) ? q1 > q0 : q1 < q0;
1308 if (take_2nd)
1309 intersections.pts[0] = intersections.pts[1];
1310 -- intersections.count;
1311 }
1312 }
1313 assert(intersections.count > 0);
1314 if (intersections.count == 2) {
1315 out[edge_idx] = intersections.pts[1];
1316 out[edge_idx2] = intersections.pts[0];
1317 done = true;
1318 } else if (intersections.count == 1) {
1319 if (d1 < d0)
1320 std::swap(edge_idx, edge_idx2);
1321 out[edge_idx] = intersections.pts[0];
1322 out[edge_idx2].y() = 1.;
1323 done = true;
1324 }
1325 }
1326 }
1327 if (! done)
1328 out[edge_idx].y() = out[edge_idx2].y() = 1.;
1329 }
1330 }
1331
1333
1334 return out;
1335}
const vertex_container_type & vertices() const
Definition Voronoi.hpp:81
std::size_t num_edges() const
Definition Voronoi.hpp:89
#define SCALED_EPSILON
Definition libslic3r.h:109
T foot_pt(const T &line_pt, const T &line_dir, const T &pt)
Definition Geometry.hpp:186
bool verify_offset_intersection_points(const VD &vd, const Lines &lines, const double offset_distance, const std::vector< Vec2d > &offset_intersection_points)
Definition VoronoiOffset.cpp:631
double dist_to_site(const Lines &lines, const VD::cell_type &cell, const Vec2d &point)
Definition VoronoiOffset.cpp:238
double first_circle_segment_intersection_parameter(const Vec2d ¢er, const double r, const Vec2d &pt, const Vec2d &v)
Definition VoronoiOffset.cpp:33
Intersections point_point_equal_distance_points(const Point &pt1, const Point &pt2, const double d)
Definition VoronoiOffset.cpp:78
Intersections line_point_equal_distance_points(const Line &line, const Point &ipt, const double d)
Definition VoronoiOffset.cpp:129
Definition VoronoiOffset.cpp:72
static bool edge_offset_has_intersection(const Vec2d &intersection_point)
Definition VoronoiOffset.hpp:117
int64_t px(const Point &pt)
Definition ClipperUtils.cpp:207
ColorRGB lerp(const ColorRGB &a, const ColorRGB &b, float t)
Definition Color.cpp:244
T dot(const boost::geometry::model::d2::point_xy< T > &v1, const boost::geometry::model::d2::point_xy< T > &v2)
Definition ExtrusionSimulator.cpp:154