diff --git a/sandboxes/slabasebed/slabasebed.cpp b/sandboxes/slabasebed/slabasebed.cpp index 569af4faa..323741609 100644 --- a/sandboxes/slabasebed/slabasebed.cpp +++ b/sandboxes/slabasebed/slabasebed.cpp @@ -15,9 +15,9 @@ const std::string USAGE_STR = { namespace Slic3r { namespace sla { Contour3D convert(const Polygons& triangles, coord_t z, bool dir); -Contour3D walls(const ExPolygon& floor_plate, const ExPolygon& ceiling, +Contour3D walls(const Polygon& floor_plate, const Polygon& ceiling, double floor_z_mm, double ceiling_z_mm, - ThrowOnCancel thr, double offset_difference_mm = 0.0); + double offset_difference_mm, ThrowOnCancel thr); void offset(ExPolygon& sh, coord_t distance); @@ -64,7 +64,7 @@ int main(const int argc, const char *argv[]) { mesh.merge(bottom_plate_mesh); mesh.merge(top_plate_mesh); - sla::Contour3D w = sla::walls(bottom_plate, top_plate, 0, 3, [](){}, 2.0); + sla::Contour3D w = sla::walls(bottom_plate.contour, top_plate.contour, 0, 3, 2.0, [](){}); mesh.merge(w); // sla::create_base_pool(ground_slice, basepool); diff --git a/src/libslic3r/SLA/SLABasePool.cpp b/src/libslic3r/SLA/SLABasePool.cpp index b24203556..83735ea16 100644 --- a/src/libslic3r/SLA/SLABasePool.cpp +++ b/src/libslic3r/SLA/SLABasePool.cpp @@ -5,10 +5,7 @@ #include "SLABoostAdapter.hpp" #include "ClipperUtils.hpp" - -#include - -#include "SVG.hpp" +//#include "SVG.hpp" //#include "benchmark.h" namespace Slic3r { namespace sla { @@ -33,302 +30,132 @@ Contour3D convert(const Polygons& triangles, coord_t z, bool dir) { return {points, indices}; } - -// // step 1: find the leftmost bottom vertex of each plate. - -//// auto vcmp = [](const Point& v1, const Point& v2) { -//// if(v1.y() == v2.y()) return v1.x() < v2.x(); -//// return v1.y() < v2.y(); -//// }; - -// // lb stands for Leftmost Bottom -// //auto iit = inner.points.begin(); //std::min_element(inner.points.begin(), inner.points.end(), vcmp); -// //auto oit = outer.points.begin();//std::min_element(outer.points.begin(), outer.points.end(), vcmp); - -// // step 2: find the centroid of the inner polygon -// auto bb = inner.bounding_box(); -// Point center = bb.center(); - -// const double Pi_2 = 2*PI; - -// // This will return the angle of a segment (p1, p2) to the X axis -// // from 0 to 2*PI -// auto anglefn = [Pi_2, center](const Point& p) { -// coord_t dx = p.x() - center.x(), dy = p.y() - center.y(); -// double a = std::atan2(dy, dx); -// auto s = std::signbit(a); -// if(s) a += Pi_2; -// return a; -// }; - -// ret.points.reserve(inner.points.size() + outer.points.size()); -// for(auto& p : inner.points) -// ret.points.emplace_back(unscale(p.x(), p.y(), mm(ceiling_z_mm))); - -// for(auto& p : outer.points) -// ret.points.emplace_back(unscale(p.x(), p.y(), mm(floor_z_mm))); - -// std::vector> anglediagram; -// anglediagram.reserve(inner.size() + outer.size()); - -// for(size_t i = 0; i < inner.size(); ++i) -// anglediagram.emplace_back( -// std::make_pair(long(i), anglefn(inner.points[i]) ) -// ); - -// const auto offs = long(inner.points.size()); - -// for(size_t i = 0; i < outer.size(); ++i) -// anglediagram.emplace_back( -// std::make_pair(offs + long(i), anglefn(outer.points[i]) ) -// ); - -// std::sort(anglediagram.begin(), anglediagram.end(), -// [](const std::pair& v1, -// const std::pair& v2) -// { -// return v1.second < v2.second; -// }); - - -// for(size_t i = 0; i < anglediagram.size() - 3; ++i) { -// long t1 = anglediagram[i].first; -// long t2 = anglediagram[i + 1].first; - -// if(t1 >= offs && t2 >= offs) { -// // search for an inner vertex -// size_t jd = i; -// size_t ju = i + 1; -// while(anglediagram[jd].first >= offs) { -// if(jd == 0) jd = anglediagram.size() - 1; -// else --jd; -// } -// while(anglediagram[ju].first >= offs) { -// if(ju >= anglediagram.size() - 1) ju = 0; -// else ++ju; - -// if(ju > anglediagram.size()) { -// std::cout << "mi eeez????" << std::endl; -// } -// } - -// assert(jd != i || ju != i + 1); - -// long t3 = -1; - -// if(ju > anglediagram.size() || jd > anglediagram.size()) { -// std::cout << "baj van" << std::endl; -// } - -// if(jd == i) t3 = anglediagram[ju].first; -// else if(ju == i + 1) t3 = anglediagram[jd].first; -// else { - -// double ad = anglediagram[jd].second; -// double au = anglediagram[ju].second; - -// double dd = std::abs(ad - anglediagram[i].second); -// if(dd > PI) dd = Pi_2 - dd; - -// double du = std::abs(au - anglediagram[i + 1].second); -// if(du > PI) du = Pi_2 - du; - -// t3 = dd < du ? anglediagram[jd].first: anglediagram[ju].first; -// } - -// ret.indices.emplace_back(t1, t3, t2); -// } -// } - // This function will return a triangulation of a sheet connecting an upper // and a lower plate given as input polygons. It will not triangulate the plates // themselves only the robe. -Contour3D walls(const ExPolygon& floor_plate, const ExPolygon& ceiling, +Contour3D walls(const Polygon& lower, const Polygon& upper, double floor_z_mm, double ceiling_z_mm, - ThrowOnCancel thr, double offset_difference_mm = 0) + double offset_difference_mm, ThrowOnCancel thr) { Contour3D ret; - const Polygon& inner = ceiling.contour; - const Polygon& outer = floor_plate.contour; + if(upper.points.size() < 3 || lower.size() < 3) return ret; - if(inner.points.size() < 3 || outer.size() < 3) return ret; + // Offset in the index array for the ceiling + const auto offs = long(upper.points.size()); - const auto offs = long(inner.points.size()); - - ret.points.reserve(inner.points.size() + outer.points.size()); - for(auto& p : inner.points) + ret.points.reserve(upper.points.size() + lower.points.size()); + for(auto& p : upper.points) ret.points.emplace_back(unscale(p.x(), p.y(), mm(ceiling_z_mm))); - for(auto& p : outer.points) + for(auto& p : lower.points) ret.points.emplace_back(unscale(p.x(), p.y(), mm(floor_z_mm))); - auto iit = inner.points.begin(); - auto oit = outer.points.begin(); + auto uit = upper.points.begin(); + auto lit = lower.points.begin(); // We need to find the closest point on outer polygon to the first point on // the inner polygon. These will be our starting points. double distmin = std::numeric_limits::max(); - for(auto ot = outer.points.begin(); ot != outer.points.end(); ++ot) { - Vec2d p = (*ot - *iit).cast(); + for(auto lt = lower.points.begin(); lt != lower.points.end(); ++lt) { + thr(); + Vec2d p = (*lt - *uit).cast(); double d = p.transpose() * p; - if(d < distmin) { oit = ot; distmin = d; } + if(d < distmin) { lit = lt; distmin = d; } } - auto inext = std::next(iit); - auto onext = std::next(oit); - if(onext == outer.points.end()) onext = outer.points.begin(); + auto unext = std::next(uit); + auto lnext = std::next(lit); + if(lnext == lower.points.end()) lnext = lower.points.begin(); - auto iidx = iit - inner.points.begin(); - auto inextidx = inext - inner.points.begin(); - auto oidx = offs + oit - outer.points.begin(); - auto onextidx = offs + onext - outer.points.begin(); + auto uidx = uit - upper.points.begin(); + auto unextidx = unext - upper.points.begin(); + auto lidx = offs + lit - lower.points.begin(); + auto lnextidx = offs + lnext - lower.points.begin(); - auto nextinp = [&iit, &inext, &inner, &iidx, &inextidx] () { - ++iit; ++inext; - if(inext == inner.points.end()) inext = inner.points.begin(); - if(iit == inner.points.end()) iit = inner.points.begin(); - inextidx = inext - inner.points.begin(); - iidx = iit - inner.points.begin(); - }; + enum class Proceed { + UPPER, LOWER + } proceed = Proceed::UPPER; - auto nextoutp = [&oit, &onext, &outer, &onextidx, &oidx, offs] () { - ++oit; ++onext; - if(onext == outer.points.end()) onext = outer.points.begin(); - if(oit == outer.points.end()) oit = outer.points.begin(); - onextidx = offs + onext - outer.points.begin(); - oidx = offs + oit - outer.points.begin(); - }; + bool ustarted = false, lstarted = false; + double current_fit = 0; + double prev_fit = 0; - bool isinsider = true; - bool idirty = false, odirty = false; - double obtusity = 0; - double prev_obtusity = 0; - - auto distfn = [](const Vec2d& p1, const Vec2d& p2) { + auto distfn = [](const Vec3d& p1, const Vec3d& p2) { auto p = p1 - p2; - return p.transpose() * p; + return std::sqrt(p.transpose() * p); }; - double cd = ceiling_z_mm - floor_z_mm; - double slope = offset_difference_mm / std::sqrt(std::pow(offset_difference_mm, 2) + std::pow(cd, 2)); + const double required_fit = offset_difference_mm / + std::sqrt( std::pow(offset_difference_mm, 2) + + std::pow(ceiling_z_mm - floor_z_mm, 2)); - auto obtusityfn = [distfn](const Vec2d& p1, const Vec2d& p2, const Vec2d& p3) - { - double a = distfn(p1, p2); - double b = distfn(p2, p3); - double c = distfn(p1, p3); - double aa = std::sqrt(a); - double bb = std::sqrt(b); - double cc = std::sqrt(c); - -// std::array sides = {aa, bb, cc}; -// std::sort(sides.begin(), sides.end()); -// double thinness = -1 + 2 * std::pow(sides.front() / sides.back(), 2); - -// assert(thinness <= 1.0 && thinness >= -1.0); - - std::array coses; - coses[0] = (a + b - c) / (2*aa*bb); - coses[1] = (a + c - b) / (2*aa*cc); - coses[2] = (c + b - a) / (2*cc*bb); - - bool isobt = a + b < c || b + c < a || c + a < b; - double minval = *std::min_element(coses.begin(), coses.end()); - - assert(isobt && minval <= 0 || !isobt && minval >= 0); - - return minval; -// return 0.5 * (minval + thinness); - }; - -#ifndef NDEBUG - Polygons top_plate_triangles, bottom_plate_triangles; - ceiling.triangulate_p2t(&top_plate_triangles); - floor_plate.triangulate_p2t(&bottom_plate_triangles); - - auto top_plate_mesh = sla::convert(top_plate_triangles, coord_t(3.0/SCALING_FACTOR), false); - auto bottom_plate_mesh = sla::convert(bottom_plate_triangles, 0, true); - Contour3D dmesh; - dmesh.merge(top_plate_mesh); - dmesh.merge(bottom_plate_mesh); -#endif - - double idist = 0, odist = 0; - double ilen = inner.length(), olen = outer.length(); - double doffs = offset_difference_mm; - - auto iend = iit; auto oend = oit; + auto uend = uit; auto lend = lit; do { -#ifndef NDEBUG - std::fstream fout("dout.obj", std::fstream::out); - Contour3D dmeshout = dmesh; -#endif - prev_obtusity = obtusity; - double distfactor = idist/ilen - odist/olen; + thr(); - if(isinsider) { - Vec3d p1(iit->x()*SCALING_FACTOR, iit->y()*SCALING_FACTOR, ceiling_z_mm); - Vec3d p2(oit->x()*SCALING_FACTOR, oit->y()*SCALING_FACTOR, floor_z_mm); - Vec3d p3(inext->x()*SCALING_FACTOR, inext->y()*SCALING_FACTOR, ceiling_z_mm); + prev_fit = current_fit; + Vec2d ip = unscale(uit->x(), uit->y()); + Vec2d inextp = unscale(unext->x(), unext->y()); + Vec2d op = unscale(lit->x(), lit->y()); + Vec2d onextp = unscale(lnext->x(), lnext->y()); - if(idirty && iit == iend) { isinsider = false; continue; } + switch(proceed) { + case Proceed::UPPER: + if(!ustarted || uit != uend) { + Vec3d p1(ip.x(), ip.y(), ceiling_z_mm); + Vec3d p2(op.x(), op.y(), floor_z_mm); + Vec3d p3(inextp.x(), inextp.y(), ceiling_z_mm); - double t1 = doffs / std::sqrt((p1 - p2).transpose() * (p1 - p2)); - t1 = slope - t1; - double t2 = doffs / std::sqrt((p3 - p2).transpose() * (p3 - p2)); - t2 = slope - t2; - double t = std::max(std::abs(t1), std::abs(t2)); + double a = required_fit - offset_difference_mm / distfn(p1, p2); + double b = required_fit - offset_difference_mm / distfn(p3, p2); + current_fit = std::max(std::abs(a), std::abs(b)); - obtusity = t; -// obtusity = obtusityfn(p1, p2, p3); -// obtusity = 0.9 * obtusity - 0.1 * distfactor; + if(current_fit > prev_fit) { + proceed = Proceed::LOWER; + } else { + ret.indices.emplace_back(uidx, lidx, unextidx); - if(obtusity > prev_obtusity) { - isinsider = false; - } else { - ret.indices.emplace_back(iidx, oidx, inextidx); - nextinp(); - Vec2d tmp = (*iit - *inext).cast(); - idist += std::sqrt(tmp.transpose() * tmp); - idirty = true; - } - } else { - Vec3d p1(oit->x()*SCALING_FACTOR, oit->y()*SCALING_FACTOR, floor_z_mm); - Vec3d p2(onext->x()*SCALING_FACTOR, onext->y()*SCALING_FACTOR, floor_z_mm); - Vec3d p3(iit->x()*SCALING_FACTOR, iit->y()*SCALING_FACTOR, ceiling_z_mm); + ++uit; ++unext; + if(unext == upper.points.end()) unext = upper.points.begin(); + if(uit == upper.points.end()) uit = upper.points.begin(); + unextidx = unext - upper.points.begin(); + uidx = uit - upper.points.begin(); - if(odirty && oit == oend) { isinsider = true; continue; } + ustarted = true; + } + } else proceed = Proceed::LOWER; - double t1 = slope - doffs / std::sqrt((p3 - p1).transpose() * (p3 - p1)); - double t2 = slope - doffs / std::sqrt((p3 - p2).transpose() * (p3 - p2)); - double t = std::max(std::abs(t1), std::abs(t2)); + break; + case Proceed::LOWER: + if(!lstarted || lit != lend) { + Vec3d p1(op.x(), op.y(), floor_z_mm); + Vec3d p2(onextp.x(), onextp.y(), floor_z_mm); + Vec3d p3(ip.x(), ip.y(), ceiling_z_mm); - obtusity = t; + double a = required_fit - offset_difference_mm / distfn(p3, p1); + double b = required_fit - offset_difference_mm / distfn(p3, p2); + current_fit = std::max(std::abs(a), std::abs(b)); -// obtusity = obtusityfn(p1, p2, p3); -// obtusity = 0.9 * obtusity + 0.1 * distfactor; + if(current_fit > prev_fit) { + proceed = Proceed::UPPER; + } else { + ret.indices.emplace_back(lidx, lnextidx, uidx); - if(obtusity > prev_obtusity) { - isinsider = true; - } else { - ret.indices.emplace_back(oidx, onextidx, iidx); - nextoutp(); - Vec2d tmp = (*oit - *onext).cast(); - odist += std::sqrt(tmp.transpose() * tmp); - odirty = true; - } - } + ++lit; ++lnext; + if(lnext == lower.points.end()) lnext = lower.points.begin(); + if(lit == lower.points.end()) lit = lower.points.begin(); + lnextidx = offs + lnext - lower.points.begin(); + lidx = offs + lit - lower.points.begin(); -#ifndef NDEBUG - dmeshout.merge(ret); - dmeshout.to_obj(fout); - fout.close(); - std::cout << "triangle written" << std::endl; -#endif + lstarted = true; + } + } else proceed = Proceed::UPPER; - } while(!idirty || !odirty || iit != iend || oit != oend); + break; + } // switch + } while(!ustarted || !lstarted || uit != uend || lit != lend); return ret; @@ -377,121 +204,13 @@ Contour3D walls(const ExPolygon& floor_plate, const ExPolygon& ceiling, } -// const auto offs = long(inner.points.size()); +Contour3D walls(const ExPolygon& floor_plate, const ExPolygon& ceiling, + double floor_z_mm, double ceiling_z_mm, ThrowOnCancel thr) +{ + return walls(floor_plate.contour, ceiling.contour, floor_z_mm, ceiling_z_mm, + 0, thr); +} -// auto inext = std::next(iit); -// auto onext = std::next(oit); - -// auto nextinp = [&iit, &inext, &inner] () { -// ++iit; ++inext; -// if(inext == inner.points.end()) inext = inner.points.begin(); -// if(iit == inner.points.end()) iit = inner.points.begin(); -// }; - -// auto nextoutp = [&oit, &onext, &outer] () { -// ++oit; ++onext; -// if(onext == outer.points.end()) onext = outer.points.begin(); -// if(oit == outer.points.end()) oit = outer.points.begin(); -// }; - -// double aonext = anglefn(*onext); -// size_t n = 0; -// while(n < inner.size()) { -// double a1 = anglefn(*iit); -// double a2 = anglefn(*inext); -// if(inext < iit) a2 += Pi_2; - -// double amin = std::min(a1, a2); -// double amax = std::max(a1, a2); - -// // We have to dial the outer vertex pair to the range of the inner -// // pair -// size_t i = 0; -// while((aonext <= amin || aonext > amax) && i < outer.size()) -// { // search for the first outer vertex that is suitable -// nextoutp(); -// aonext = anglefn(*onext); -// if(inext < iit) aonext += Pi_2; -// ++i; -// } - -// // If we arrived at the end of the outer ring, and the inner is not -// // completed, we will rotate the outer. -// if(i == outer.size()) { -// nextinp(); ++n; -// continue; -// } - -// auto iidx = iit - inner.points.begin(); -// auto inextidx = inext - inner.points.begin(); -// auto oidx = offs + oit - outer.points.begin(); -// auto onextidx = offs + onext - outer.points.begin(); - -// ret.indices.emplace_back(onextidx, iidx, oidx); -// ret.indices.emplace_back(onextidx, inextidx, iidx); - -// while(true) -// { -// nextoutp(); - -// onextidx = offs + onext - outer.points.begin(); -// oidx = offs + oit - outer.points.begin(); - -// aonext = anglefn(*onext); - -// if(aonext > amin && aonext <= amax) { -// ret.indices.emplace_back(onextidx, inextidx, oidx); -// } else break; -// } - -// nextinp(); ++n; -// } - - - - -// using std::transform; using std::back_inserter; - -// ExPolygon poly; -// poly.contour.points = floor_plate.contour.points; -// poly.holes.emplace_back(ceiling.contour); -// auto& h = poly.holes.front(); -// std::reverse(h.points.begin(), h.points.end()); -// Polygons tri = triangulate(poly); - -// Contour3D ret; -// ret.points.reserve(tri.size() * 3); - -// double fz = floor_z_mm; -// double cz = ceiling_z_mm; -// auto& rp = ret.points; -// auto& rpi = ret.indices; -// ret.indices.reserve(tri.size() * 3); - -// coord_t idx = 0; - -// auto hlines = h.lines(); -// auto is_upper = [&hlines](const Point& p) { -// return std::any_of(hlines.begin(), hlines.end(), -// [&p](const Line& l) { -// return l.distance_to(p) < mm(1e-6); -// }); -// }; - -// for(const Polygon& pp : tri) { -// thr(); // may throw if cancellation was requested - -// for(auto& p : pp.points) -// if(is_upper(p)) -// rp.emplace_back(unscale(x(p), y(p), mm(cz))); -// else rp.emplace_back(unscale(x(p), y(p), mm(fz))); - -// coord_t a = idx++, b = idx++, c = idx++; -// if(fz > cz) rpi.emplace_back(c, b, a); -// else rpi.emplace_back(a, b, c); -// } - -// return ret; /// Offsetting with clipper and smoothing the edges into a curvature. void offset(ExPolygon& sh, coord_t distance) { @@ -665,7 +384,7 @@ Contour3D round_edges(const ExPolygon& base_plate, wh = ceilheight_mm - radius_mm + stepy; Contour3D pwalls; - pwalls = walls(ob, ob_prev, wh, wh_prev, throw_on_cancel); + pwalls = walls(ob.contour, ob_prev.contour, wh, wh_prev, xx, throw_on_cancel); curvedwalls.merge(pwalls); ob_prev = ob; @@ -688,7 +407,7 @@ Contour3D round_edges(const ExPolygon& base_plate, wh = ceilheight_mm - radius_mm - stepy; Contour3D pwalls; - pwalls = walls(ob_prev, ob, wh_prev, wh, throw_on_cancel); + pwalls = walls(ob_prev.contour, ob.contour, wh_prev, wh, xx, throw_on_cancel); curvedwalls.merge(pwalls); ob_prev = ob; @@ -981,7 +700,7 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out, // Now that we have the rounded edge connencting the top plate with // the outer side walls, we can generate and merge the sidewall geometry - auto pwalls = walls(ob, inner_base, wh, -fullheight, thrcl); + auto pwalls = walls(ob.contour, inner_base.contour, wh, -fullheight, (s_thickness + s_wingdist) * SCALING_FACTOR, thrcl); pool.merge(pwalls); if(wingheight > 0) { @@ -997,7 +716,7 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out, // Next is the cavity walls connecting to the top plate's // artificially created hole. - auto cavitywalls = walls(inner_base, ob, -wingheight, wh, thrcl); + auto cavitywalls = walls(inner_base.contour, ob.contour, -wingheight, wh, s_safety_dist * SCALING_FACTOR,thrcl); pool.merge(cavitywalls); }