diff --git a/src/admesh/stl.h b/src/admesh/stl.h index 117090dd82..43999d365b 100644 --- a/src/admesh/stl.h +++ b/src/admesh/stl.h @@ -89,33 +89,34 @@ struct stl_neighbors { }; struct stl_stats { - stl_stats() { this->reset(); } - void reset() { memset(this, 0, sizeof(stl_stats)); this->volume = -1.0; } - char header[81]; - stl_type type; - uint32_t number_of_facets; - stl_vertex max; - stl_vertex min; - stl_vertex size; - float bounding_diameter; - float shortest_edge; - float volume; - int connected_edges; - int connected_facets_1_edge; - int connected_facets_2_edge; - int connected_facets_3_edge; - int facets_w_1_bad_edge; - int facets_w_2_bad_edge; - int facets_w_3_bad_edge; - int original_num_facets; - int edges_fixed; - int degenerate_facets; - int facets_removed; - int facets_added; - int facets_reversed; - int backwards_edges; - int normals_fixed; - int number_of_parts; + stl_stats() { memset(&header, 0, 81); } + char header[81] = ""; + stl_type type = (stl_type)0; + uint32_t number_of_facets = 0; + stl_vertex max = stl_vertex::Zero(); + stl_vertex min = stl_vertex::Zero(); + stl_vertex size = stl_vertex::Zero(); + float bounding_diameter = 0.f; + float shortest_edge = 0.f; + float volume = -1.f; + int connected_edges = 0; + int connected_facets_1_edge = 0; + int connected_facets_2_edge = 0; + int connected_facets_3_edge = 0; + int facets_w_1_bad_edge = 0; + int facets_w_2_bad_edge = 0; + int facets_w_3_bad_edge = 0; + int original_num_facets = 0; + int edges_fixed = 0; + int degenerate_facets = 0; + int facets_removed = 0; + int facets_added = 0; + int facets_reversed = 0; + int backwards_edges = 0; + int normals_fixed = 0; + int number_of_parts = 0; + + void clear() { *this = stl_stats(); } }; struct stl_file { @@ -124,7 +125,7 @@ struct stl_file { void clear() { this->facet_start.clear(); this->neighbors_start.clear(); - this->stats.reset(); + this->stats.clear(); } size_t memsize() const { diff --git a/src/admesh/stlinit.cpp b/src/admesh/stlinit.cpp index 693aad0866..390fe56a40 100644 --- a/src/admesh/stlinit.cpp +++ b/src/admesh/stlinit.cpp @@ -36,6 +36,10 @@ #error "SEEK_SET not defined" #endif +#ifndef BOOST_LITTLE_ENDIAN +extern void stl_internal_reverse_quads(char *buf, size_t cnt); +#endif /* BOOST_LITTLE_ENDIAN */ + static FILE* stl_open_count_facets(stl_file *stl, const char *file) { // Open the file in binary mode first. @@ -238,10 +242,6 @@ bool stl_open(stl_file *stl, const char *file) return result; } -#ifndef BOOST_LITTLE_ENDIAN -extern void stl_internal_reverse_quads(char *buf, size_t cnt); -#endif /* BOOST_LITTLE_ENDIAN */ - void stl_allocate(stl_file *stl) { // Allocate memory for the entire .STL file. diff --git a/src/avrdude/ChangeLog b/src/avrdude/ChangeLog index 975f523172..879fbf9576 100644 --- a/src/avrdude/ChangeLog +++ b/src/avrdude/ChangeLog @@ -1,3 +1,12 @@ +2018-01-17 Joerg Wunsch +(cherry-picked) + Submitted by Reinhard Max + patch #8311: Add IPv6 support to the -Pnet:host:port option + * ser_posix.c (net_open): Rewrite to use getaddrinfo() + rather than gethostbyname() + * avrdude.1: Document IPv6 feature + * doc/avrdude.texi: (Dito) + 2016-05-10 Joerg Wunsch Submitted by Hannes Jochriem: diff --git a/src/avrdude/avrdude.1 b/src/avrdude/avrdude.1 index 65fc7b1d62..47ca4eddec 100644 --- a/src/avrdude/avrdude.1 +++ b/src/avrdude/avrdude.1 @@ -505,12 +505,19 @@ network connection to (TCP) on .Ar host is established. +Square brackets may be placed around +.Ar host +to improve readability, for numeric IPv6 addresses (e.g. +.Li net:[2001:db8::42]:1337 ) . The remote endpoint is assumed to be a terminal or console server that connects the network stream to a local serial port where the actual programmer has been attached to. The port is assumed to be properly configured, for example using a transparent 8-bit data connection without parity at 115200 Baud for a STK500. +.Pp +Note: The ability to handle IPv6 hostnames and addresses is limited to +Posix systems (by now). .It Fl q Disable (or quell) output of the progress bar while reading or writing to the device. Specify it a second time for even quieter operation. diff --git a/src/avrdude/configure.ac b/src/avrdude/configure.ac index a23a959f23..d14fc545f2 100644 --- a/src/avrdude/configure.ac +++ b/src/avrdude/configure.ac @@ -214,7 +214,7 @@ AC_HEADER_TIME AC_CHECK_LIB([ws2_32], [puts]) # Checks for library functions. -AC_CHECK_FUNCS([memset select strcasecmp strdup strerror strncasecmp strtol strtoul gettimeofday usleep]) +AC_CHECK_FUNCS([memset select strcasecmp strdup strerror strncasecmp strtol strtoul gettimeofday usleep getaddrinfo]) AC_MSG_CHECKING([for a Win32 HID libray]) SAVED_LIBS="${LIBS}" diff --git a/src/avrdude/doc/avrdude.texi b/src/avrdude/doc/avrdude.texi index 6941389dfc..7062a9920b 100644 --- a/src/avrdude/doc/avrdude.texi +++ b/src/avrdude/doc/avrdude.texi @@ -557,6 +557,9 @@ higher level protocol (as opposed to bit-bang style programmers), In this case, instead of trying to open a local device, a TCP network connection to (TCP) @var{port} on @var{host} is established. +Square brackets may be placed around @var{host} to improve +readability for numeric IPv6 addresses (e.g. +@code{net:[2001:db8::42]:1337}). The remote endpoint is assumed to be a terminal or console server that connects the network stream to a local serial port where the actual programmer has been attached to. @@ -564,6 +567,8 @@ The port is assumed to be properly configured, for example using a transparent 8-bit data connection without parity at 115200 Baud for a STK500. +Note: The ability to handle IPv6 hostnames and addresses is limited to +Posix systems (by now). @item -q Disable (or quell) output of the progress bar while reading or writing diff --git a/src/avrdude/ser_posix.c b/src/avrdude/ser_posix.c index 9992f78e3d..dfa02f9fe4 100644 --- a/src/avrdude/ser_posix.c +++ b/src/avrdude/ser_posix.c @@ -150,6 +150,7 @@ static int ser_setspeed(union filedescriptor *fd, long baud) return 0; } +#include "ac_cfg.h" // Timeout read & write variants // Additionally to the regular -1 on I/O error, they return -2 on timeout @@ -221,23 +222,35 @@ ssize_t write_timeout(int fd, const void *buf, size_t count, long timeout) static int net_open(const char *port, union filedescriptor *fdp) { - char *hstr, *pstr, *end; - unsigned int pnum; - int fd; - struct sockaddr_in sockaddr; - struct hostent *hp; +#ifdef HAVE_GETADDRINFO + char *hp, *hstr, *pstr; + int s, fd, ret = -1; + struct addrinfo hints; + struct addrinfo *result, *rp; - if ((hstr = strdup(port)) == NULL) { + if ((hstr = hp = strdup(port)) == NULL) { avrdude_message(MSG_INFO, "%s: net_open(): Out of memory!\n", progname); return -1; } - if (((pstr = strchr(hstr, ':')) == NULL) || (pstr == hstr)) { + /* + * As numeric IPv6 addresses use colons as separators, we need to + * look for the last colon here, which separates the port number or + * service name from the host or IP address. + */ + if (((pstr = strrchr(hstr, ':')) == NULL) || (pstr == hstr)) { avrdude_message(MSG_INFO, "%s: net_open(): Mangled host:port string \"%s\"\n", progname, hstr); - free(hstr); - return -1; + goto error; + } + + /* + * Remove brackets from the host part, if present. + */ + if (*hstr == '[' && *(pstr-1) == ']') { + hstr++; + *(pstr-1) = '\0'; } /* @@ -245,43 +258,49 @@ net_open(const char *port, union filedescriptor *fdp) */ *pstr++ = '\0'; - pnum = strtoul(pstr, &end, 10); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + s = getaddrinfo(hstr, pstr, &hints, &result); - if ((*pstr == '\0') || (*end != '\0') || (pnum == 0) || (pnum > 65535)) { - avrdude_message(MSG_INFO, "%s: net_open(): Bad port number \"%s\"\n", - progname, pstr); - free(hstr); - return -1; + if (s != 0) { + avrdude_message(MSG_INFO, + "%s: net_open(): Cannot resolve " + "host=\"%s\", port=\"%s\": %s\n", + progname, hstr, pstr, gai_strerror(s)); + goto error; } - - if ((hp = gethostbyname(hstr)) == NULL) { - avrdude_message(MSG_INFO, "%s: net_open(): unknown host \"%s\"\n", - progname, hstr); - free(hstr); - return -1; + for (rp = result; rp != NULL; rp = rp->ai_next) { + fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (fd == -1) { + /* This one failed, loop over */ + continue; + } + if (connect(fd, rp->ai_addr, rp->ai_addrlen) != -1) { + /* Success, we are connected */ + break; + } + close(fd); } - - free(hstr); - - if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { - avrdude_message(MSG_INFO, "%s: net_open(): Cannot open socket: %s\n", - progname, strerror(errno)); - return -1; + if (rp == NULL) { + avrdude_message(MSG_INFO, "%s: net_open(): Cannot connect: %s\n", + progname, strerror(errno)); } - - memset(&sockaddr, 0, sizeof(struct sockaddr_in)); - sockaddr.sin_family = AF_INET; - sockaddr.sin_port = htons(pnum); - memcpy(&(sockaddr.sin_addr.s_addr), hp->h_addr, sizeof(struct in_addr)); - - if (connect(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) { - avrdude_message(MSG_INFO, "%s: net_open(): Connect failed: %s\n", - progname, strerror(errno)); - return -1; + else { + fdp->ifd = fd; + ret = 0; } + freeaddrinfo(result); - fdp->ifd = fd; - return 0; +error: + free(hp); + return ret; +#else + avrdude_message(MSG_INFO, + "%s: Networking is not supported on your platform.\n" + "If you need it, please open a bug report.\n", progname); + return -1; +#endif /* HAVE_GETADDRINFO */ } diff --git a/src/clipper/clipper_z.hpp b/src/clipper/clipper_z.hpp index 0f31ac11c5..e5e7d48ce1 100644 --- a/src/clipper/clipper_z.hpp +++ b/src/clipper/clipper_z.hpp @@ -15,4 +15,4 @@ #undef clipper_hpp #undef use_xyz -#endif clipper_z_hpp +#endif // clipper_z_hpp diff --git a/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp b/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp index 56330e15e7..57da6ec12e 100644 --- a/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp +++ b/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp @@ -81,17 +81,16 @@ inline void offset(PolygonImpl& sh, TCoord distance, const PolygonTag using ClipperLib::etClosedPolygon; using ClipperLib::Paths; - // If the input is not at least a triangle, we can not do this algorithm - if(sh.Contour.size() <= 3 || - std::any_of(sh.Holes.begin(), sh.Holes.end(), - [](const PathImpl& p) { return p.size() <= 3; }) - ) throw GeometryException(GeomErr::OFFSET); - - ClipperOffset offs; Paths result; - offs.AddPath(sh.Contour, jtMiter, etClosedPolygon); - offs.AddPaths(sh.Holes, jtMiter, etClosedPolygon); - offs.Execute(result, static_cast(distance)); + + try { + ClipperOffset offs; + offs.AddPath(sh.Contour, jtMiter, etClosedPolygon); + offs.AddPaths(sh.Holes, jtMiter, etClosedPolygon); + offs.Execute(result, static_cast(distance)); + } catch (ClipperLib::clipperException &) { + throw GeometryException(GeomErr::OFFSET); + } // Offsetting reverts the orientation and also removes the last vertex // so boost will not have a closed polygon. diff --git a/src/libnest2d/include/libnest2d/geometry_traits.hpp b/src/libnest2d/include/libnest2d/geometry_traits.hpp index 827e2d8ba3..72e239a707 100644 --- a/src/libnest2d/include/libnest2d/geometry_traits.hpp +++ b/src/libnest2d/include/libnest2d/geometry_traits.hpp @@ -1144,7 +1144,7 @@ inline bool isInside(const TBGuest& ibb, const TBHost& box, auto minY = getY(box.minCorner()); auto maxY = getY(box.maxCorner()); - return iminX > minX && imaxX < maxX && iminY > minY && imaxY < maxY; + return iminX >= minX && imaxX <= maxX && iminY >= minY && imaxY <= maxY; } template diff --git a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp index 1a341d6915..686857a87f 100644 --- a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp +++ b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp @@ -3,9 +3,6 @@ #include -// For caching nfps -#include - // For parallel for #include #include @@ -76,55 +73,6 @@ inline void enumerate( } -namespace __itemhash { - -using Key = size_t; - -template -Key hash(const _Item& item) { - using Point = TPoint; - using Segment = _Segment; - - static const int N = 26; - static const int M = N*N - 1; - - std::string ret; - auto& rhs = item.rawShape(); - auto& ctr = sl::contour(rhs); - auto it = ctr.begin(); - auto nx = std::next(it); - - double circ = 0; - while(nx != ctr.end()) { - Segment seg(*it++, *nx++); - Radians a = seg.angleToXaxis(); - double deg = Degrees(a); - int ms = 'A', ls = 'A'; - while(deg > N) { ms++; deg -= N; } - ls += int(deg); - ret.push_back(char(ms)); ret.push_back(char(ls)); - circ += std::sqrt(seg.template sqlength()); - } - - it = ctr.begin(); nx = std::next(it); - - while(nx != ctr.end()) { - Segment seg(*it++, *nx++); - auto l = int(M * std::sqrt(seg.template sqlength()) / circ); - int ms = 'A', ls = 'A'; - while(l > N) { ms++; l -= N; } - ls += l; - ret.push_back(char(ms)); ret.push_back(char(ls)); - } - - return std::hash()(ret); -} - -template -using Hash = std::unordered_map>; - -} - namespace placers { template @@ -529,17 +477,9 @@ class _NofitPolyPlacer: public PlacerBoilerplate<_NofitPolyPlacer; - using ItemKeys = std::vector<__itemhash::Key>; - // Norming factor for the optimization function const double norm_; - // Caching calculated nfps - __itemhash::Hash nfpcache_; - - // Storing item hash keys - ItemKeys item_keys_; - public: using Pile = nfp::Shapes; @@ -636,15 +576,12 @@ public: private: using Shapes = TMultiShape; - using ItemRef = std::reference_wrapper; - using ItemWithHash = const std::pair; - Shapes calcnfp(const ItemWithHash itsh, Lvl) + Shapes calcnfp(const Item &trsh, Lvl) { using namespace nfp; Shapes nfps(items_.size()); - const Item& trsh = itsh.first; // ///////////////////////////////////////////////////////////////////// // TODO: this is a workaround and should be solved in Item with mutexes @@ -678,12 +615,11 @@ private: template - Shapes calcnfp( const ItemWithHash itsh, Level) + Shapes calcnfp(const Item &trsh, Level) { // Function for arbitrary level of nfp implementation using namespace nfp; Shapes nfps; - const Item& trsh = itsh.first; auto& orb = trsh.transformedShape(); bool orbconvex = trsh.isContourConvex(); @@ -849,8 +785,6 @@ private: remlist.insert(remlist.end(), remaining.from, remaining.to); } - size_t itemhash = __itemhash::hash(item); - if(items_.empty()) { setInitialPosition(item); best_overfit = overfit(item.transformedShape(), bin_); @@ -875,7 +809,7 @@ private: // it is disjunct from the current merged pile placeOutsideOfBin(item); - nfps = calcnfp({item, itemhash}, Lvl()); + nfps = calcnfp(item, Lvl()); auto iv = item.referenceVertex(); @@ -1112,7 +1046,6 @@ private: if(can_pack) { ret = PackResult(item); - item_keys_.emplace_back(itemhash); } else { ret = PackResult(best_overfit); } diff --git a/src/libnest2d/include/libnest2d/selections/selection_boilerplate.hpp b/src/libnest2d/include/libnest2d/selections/selection_boilerplate.hpp index 2df9a26c34..36fec71647 100644 --- a/src/libnest2d/include/libnest2d/selections/selection_boilerplate.hpp +++ b/src/libnest2d/include/libnest2d/selections/selection_boilerplate.hpp @@ -43,7 +43,7 @@ protected: Placer p{bin}; p.configure(pcfg); - if (!p.pack(cpy)) it = c.erase(it); + if (itm.area() <= 0 || !p.pack(cpy)) it = c.erase(it); else it++; } } diff --git a/src/libnest2d/tests/test.cpp b/src/libnest2d/tests/test.cpp index 4a6691415f..5ba28228a2 100644 --- a/src/libnest2d/tests/test.cpp +++ b/src/libnest2d/tests/test.cpp @@ -40,7 +40,7 @@ struct NfpImpl } } -std::vector& prusaParts() { +static std::vector& prusaParts() { static std::vector ret; if(ret.empty()) { @@ -51,7 +51,7 @@ std::vector& prusaParts() { return ret; } -TEST(BasicFunctionality, Angles) +TEST(GeometryAlgorithms, Angles) { using namespace libnest2d; @@ -109,7 +109,7 @@ TEST(BasicFunctionality, Angles) } // Simple test, does not use gmock -TEST(BasicFunctionality, creationAndDestruction) +TEST(Nesting, ItemCreationAndDestruction) { using namespace libnest2d; @@ -572,26 +572,74 @@ TEST(GeometryAlgorithms, convexHull) { } -TEST(GeometryAlgorithms, NestTest) { +TEST(Nesting, NestPrusaPartsShouldFitIntoTwoBins) { + + // Get the input items and define the bin. std::vector input = prusaParts(); - - libnest2d::nest(input, Box(250000000, 210000000), [](unsigned cnt) { - std::cout << "parts left: " << cnt << std::endl; + auto bin = Box(250000000, 210000000); + + // Do the nesting. Check in each step if the remaining items are less than + // in the previous step. (Some algorithms can place more items in one step) + size_t pcount = input.size(); + libnest2d::nest(input, bin, [&pcount](unsigned cnt) { + ASSERT_TRUE(cnt < pcount); + pcount = cnt; }); - + + // Get the number of logical bins: search for the max binId... auto max_binid_it = std::max_element(input.begin(), input.end(), [](const Item &i1, const Item &i2) { return i1.binId() < i2.binId(); }); - - size_t bins = max_binid_it == input.end() ? 0 : max_binid_it->binId() + 1; - ASSERT_EQ(bins, 2u); - + auto bins = size_t(max_binid_it == input.end() ? 0 : + max_binid_it->binId() + 1); + + // For prusa parts, 2 bins should be enough... + ASSERT_LE(bins, 2u); + + // All parts should be processed by the algorithm ASSERT_TRUE( std::all_of(input.begin(), input.end(), [](const Item &itm) { return itm.binId() != BIN_ID_UNSET; })); + + // Gather the items into piles of arranged polygons... + using Pile = TMultiShape; + std::vector piles(bins); + + for (auto &itm : input) + piles[size_t(itm.binId())].emplace_back(itm.transformedShape()); + + // Now check all the piles, the bounding box of each pile should be inside + // the defined bin. + for (auto &pile : piles) { + auto bb = sl::boundingBox(pile); + ASSERT_TRUE(sl::isInside(bb, bin)); + } +} + +TEST(Nesting, NestEmptyItemShouldBeUntouched) { + auto bin = Box(250000000, 210000000); // dummy bin + + std::vector items; + items.emplace_back(Item{}); // Emplace empty item + items.emplace_back(Item{0, 200, 0}); // Emplace zero area item + + libnest2d::nest(items, bin); + + for (auto &itm : items) ASSERT_EQ(itm.binId(), BIN_ID_UNSET); +} + +TEST(Nesting, NestLargeItemShouldBeUntouched) { + auto bin = Box(250000000, 210000000); // dummy bin + + std::vector items; + items.emplace_back(Rectangle{250000001, 210000001}); // Emplace large item + + libnest2d::nest(items, bin); + + ASSERT_EQ(items.front().binId(), BIN_ID_UNSET); } namespace { @@ -966,26 +1014,20 @@ using Ratio = boost::rational; } -TEST(RotatingCalipers, MinAreaBBCClk) { - auto u = [](ClipperLib::cInt n) { return n*1000000; }; - PolygonImpl poly({ {u(0), u(0)}, {u(4), u(1)}, {u(2), u(4)}}); +//TEST(GeometryAlgorithms, MinAreaBBCClk) { +// auto u = [](ClipperLib::cInt n) { return n*1000000; }; +// PolygonImpl poly({ {u(0), u(0)}, {u(4), u(1)}, {u(2), u(4)}}); - long double arearef = refMinAreaBox(poly); - long double area = minAreaBoundingBox(poly).area(); +// long double arearef = refMinAreaBox(poly); +// long double area = minAreaBoundingBox(poly).area(); - ASSERT_LE(std::abs(area - arearef), 500e6 ); -} +// ASSERT_LE(std::abs(area - arearef), 500e6 ); +//} -TEST(RotatingCalipers, AllPrusaMinBB) { - // /size_t idx = 0; +TEST(GeometryAlgorithms, MinAreaBBWithRotatingCalipers) { long double err_epsilon = 500e6l; for(ClipperLib::Path rinput : PRINTER_PART_POLYGONS) { - // ClipperLib::Path rinput = PRINTER_PART_POLYGONS[idx]; - // rinput.pop_back(); - // std::reverse(rinput.begin(), rinput.end()); - - // PolygonImpl poly(removeCollinearPoints(rinput, 1000000)); PolygonImpl poly(rinput); long double arearef = refMinAreaBox(poly); @@ -993,8 +1035,6 @@ TEST(RotatingCalipers, AllPrusaMinBB) { long double area = cast(bb.area()); bool succ = std::abs(arearef - area) < err_epsilon; - // std::cout << idx++ << " " << (succ? "ok" : "failed") << " ref: " -// << arearef << " actual: " << area << std::endl; ASSERT_TRUE(succ); } @@ -1011,8 +1051,6 @@ TEST(RotatingCalipers, AllPrusaMinBB) { bool succ = std::abs(arearef - area) < err_epsilon; - // std::cout << idx++ << " " << (succ? "ok" : "failed") << " ref: " -// << arearef << " actual: " << area << std::endl; ASSERT_TRUE(succ); } diff --git a/src/libslic3r/Arrange.cpp b/src/libslic3r/Arrange.cpp index 52168c9299..20dfd8926f 100644 --- a/src/libslic3r/Arrange.cpp +++ b/src/libslic3r/Arrange.cpp @@ -618,19 +618,21 @@ void arrange(ArrangePolygons & arrangables, items.reserve(arrangables.size()); // Create Item from Arrangeable - auto process_arrangeable = - [](const ArrangePolygon &arrpoly, std::vector &outp) + auto process_arrangeable = [](const ArrangePolygon &arrpoly, + std::vector & outp) { - Polygon p = arrpoly.poly.contour; - const Vec2crd & offs = arrpoly.translation; - double rotation = arrpoly.rotation; + Polygon p = arrpoly.poly.contour; + const Vec2crd &offs = arrpoly.translation; + double rotation = arrpoly.rotation; if (p.is_counter_clockwise()) p.reverse(); clppr::Polygon clpath(Slic3rMultiPoint_to_ClipperPath(p)); - - auto firstp = clpath.Contour.front(); - clpath.Contour.emplace_back(firstp); + + if (!clpath.Contour.empty()) { + auto firstp = clpath.Contour.front(); + clpath.Contour.emplace_back(firstp); + } outp.emplace_back(std::move(clpath)); outp.back().rotation(rotation); diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp index 5776980714..9aab3a0eb7 100644 --- a/src/libslic3r/Config.cpp +++ b/src/libslic3r/Config.cpp @@ -249,7 +249,7 @@ ConfigOption* ConfigOptionDef::create_default_option() const // Special case: For a DynamicConfig, convert a templated enum to a generic enum. new ConfigOptionEnumGeneric(this->enum_keys_map, this->default_value->getInt()) : this->default_value->clone(); - return this->create_empty_option(); + return this->create_empty_option(); } // Assignment of the serialization IDs is not thread safe. The Defs shall be initialized from the main thread! diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index c349ad3e18..334593ab5f 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -353,7 +353,7 @@ public: bool apply_override(const ConfigOption *rhs) override { if (this->nullable()) throw std::runtime_error("Cannot override a nullable ConfigOption."); - if (rhs->type() != this->type()) + if (rhs->type() != this->type()) throw std::runtime_error("ConfigOptionVector.apply_override() applied to different types."); auto rhs_vec = static_cast*>(rhs); if (! rhs->nullable()) { @@ -461,7 +461,7 @@ public: for (const double &v : this->values) { if (&v != &this->values.front()) ss << ","; - serialize_single_value(ss, v); + serialize_single_value(ss, v); } return ss.str(); } @@ -607,7 +607,7 @@ public: for (const int &v : this->values) { if (&v != &this->values.front()) ss << ","; - serialize_single_value(ss, v); + serialize_single_value(ss, v); } return ss.str(); } diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index ad308adab3..ab20bbddb9 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -15,40 +15,39 @@ namespace Slic3r { struct SurfaceFillParams { - SurfaceFillParams() : flow(0.f, 0.f, 0.f, false) { memset(this, 0, sizeof(*this)); } // Zero based extruder ID. - unsigned int extruder; + unsigned int extruder = 0; // Infill pattern, adjusted for the density etc. - InfillPattern pattern; + InfillPattern pattern = InfillPattern(0); // FillBase // in unscaled coordinates - coordf_t spacing; + coordf_t spacing = 0.; // infill / perimeter overlap, in unscaled coordinates - coordf_t overlap; + coordf_t overlap = 0.; // Angle as provided by the region config, in radians. - float angle; + float angle = 0.f; // Non-negative for a bridge. - float bridge_angle; + float bridge_angle = 0.f; // FillParams - float density; + float density = 0.f; // Don't connect the fill lines around the inner perimeter. - bool dont_connect; + bool dont_connect = false; // Don't adjust spacing to fill the space evenly. - bool dont_adjust; + bool dont_adjust = false; // width, height of extrusion, nozzle diameter, is bridge // For the output, for fill generator. - Flow flow; + Flow flow = Flow(0.f, 0.f, 0.f, false); // For the output - ExtrusionRole extrusion_role; + ExtrusionRole extrusion_role = ExtrusionRole(0); // Various print settings? // Index of this entry in a linear vector. - size_t idx; + size_t idx = 0; bool operator<(const SurfaceFillParams &rhs) const { diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp index 92c958d8ab..8989487ccc 100644 --- a/src/libslic3r/Format/AMF.cpp +++ b/src/libslic3r/Format/AMF.cpp @@ -979,7 +979,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config) stream << layer_height_profile.front(); for (size_t i = 1; i < layer_height_profile.size(); ++i) stream << ";" << layer_height_profile[i]; - stream << "\n \n"; + stream << "\n \n"; } // Export layer height ranges including the layer range specific config overrides. diff --git a/src/libslic3r/Format/PRUS.cpp b/src/libslic3r/Format/PRUS.cpp index 03ea71a83e..d6f87197df 100644 --- a/src/libslic3r/Format/PRUS.cpp +++ b/src/libslic3r/Format/PRUS.cpp @@ -246,7 +246,7 @@ static void extract_model_from_archive( sscanf(normal_buf[2], "%f", &facet.normal(2)) != 1) { // Normal was mangled. Maybe denormals or "not a number" were stored? // Just reset the normal and silently ignore it. - memset(&facet.normal, 0, sizeof(facet.normal)); + facet.normal = stl_normal::Zero(); } facets.emplace_back(facet); } @@ -278,7 +278,7 @@ static void extract_model_from_archive( instance->set_rotation(instance_rotation); instance->set_scaling_factor(instance_scaling_factor); instance->set_offset(instance_offset); - if (group_id != (size_t)-1) + if (group_id != (unsigned int)(-1)) group_to_model_object[group_id] = model_object; } else { // This is not the 1st mesh of a group. Add it to the ModelObject. diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 82a4995c51..348834b3c4 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -660,7 +660,7 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_ if (print->is_step_done(psGCodeExport) && boost::filesystem::exists(boost::filesystem::path(path))) return; - print->set_started(psGCodeExport); + print->set_started(psGCodeExport); BOOST_LOG_TRIVIAL(info) << "Exporting G-code..." << log_memory_info(); @@ -1412,7 +1412,7 @@ static bool custom_gcode_sets_temperature(const std::string &gcode, const int mc // Skip the rest of the line. for (; *ptr != 0 && *ptr != '\r' && *ptr != '\n'; ++ ptr); // Skip the end of line indicators. - for (; *ptr == '\r' || *ptr == '\n'; ++ ptr); + for (; *ptr == '\r' || *ptr == '\n'; ++ ptr); } return temp_set_by_gcode; } diff --git a/src/libslic3r/GCode/PreviewData.cpp b/src/libslic3r/GCode/PreviewData.cpp index 74de2f532c..76f21daeb5 100644 --- a/src/libslic3r/GCode/PreviewData.cpp +++ b/src/libslic3r/GCode/PreviewData.cpp @@ -359,7 +359,7 @@ std::string GCodePreviewData::get_legend_title() const case Extrusion::Feedrate: return L("Speed (mm/s)"); case Extrusion::VolumetricRate: - return L("Volumetric flow rate (mm3/s)"); + return L("Volumetric flow rate (mm³/s)"); case Extrusion::Tool: return L("Tool"); case Extrusion::ColorPrint: diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index 0a9ec320ef..b7d1d57dfa 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -308,7 +308,7 @@ void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_ LayerTools lt_new(0.5f * (lt.print_z + lt_object.print_z)); // Find the 1st layer above lt_new. for (j = i + 1; j < m_layer_tools.size() && m_layer_tools[j].print_z < lt_new.print_z - EPSILON; ++ j); - if (std::abs(m_layer_tools[j].print_z - lt_new.print_z) < EPSILON) { + if (std::abs(m_layer_tools[j].print_z - lt_new.print_z) < EPSILON) { m_layer_tools[j].has_wipe_tower = true; } else { LayerTools <_extra = *m_layer_tools.insert(m_layer_tools.begin() + j, lt_new); diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index b35761b5f3..ea8465f225 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -698,7 +698,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool last_in_lay writer.append(std::string("; material : " + (m_current_tool < m_filpar.size() ? m_filpar[m_current_tool].material : "(NONE)") + " -> " + m_filpar[tool].material + "\n").c_str()) .append(";--------------------\n"); - writer.speed_override_backup(); + writer.speed_override_backup(); writer.speed_override(100); Vec2f initial_position = cleaning_box.ld + Vec2f(0.f, m_depth_traversed); @@ -748,7 +748,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool last_in_lay if (m_current_tool < m_used_filament_length.size()) m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length(); - ToolChangeResult result; + ToolChangeResult result; result.priming = false; result.initial_tool = int(old_tool); result.new_tool = int(m_current_tool); @@ -806,7 +806,7 @@ WipeTower::ToolChangeResult WipeTower::toolchange_Brim(bool sideOnly, float y_of if (m_current_tool < m_used_filament_length.size()) m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length(); - ToolChangeResult result; + ToolChangeResult result; result.priming = false; result.initial_tool = int(old_tool); result.new_tool = int(m_current_tool); @@ -1163,7 +1163,7 @@ WipeTower::ToolChangeResult WipeTower::finish_layer() writer.extrude(box.rd.x() - m_perimeter_width / 2.f, writer.y() + 0.5f * step); writer.extrude(box.ld.x() + m_perimeter_width / 2.f, writer.y()); } - writer.travel(box.rd.x()-m_perimeter_width/2.f,writer.y()); // wipe the nozzle + writer.travel(box.rd.x()-m_perimeter_width/2.f,writer.y()); // wipe the nozzle } else { // Extrude a sparse infill to support the material to be printed above. const float dy = (fill_box.lu.y() - fill_box.ld.y() - m_perimeter_width); @@ -1196,7 +1196,7 @@ WipeTower::ToolChangeResult WipeTower::finish_layer() if (m_current_tool < m_used_filament_length.size()) m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length(); - ToolChangeResult result; + ToolChangeResult result; result.priming = false; result.initial_tool = int(old_tool); result.new_tool = int(m_current_tool); diff --git a/src/libslic3r/LayerRegion.cpp b/src/libslic3r/LayerRegion.cpp index 6fc0b4e37f..bfe96d311c 100644 --- a/src/libslic3r/LayerRegion.cpp +++ b/src/libslic3r/LayerRegion.cpp @@ -144,7 +144,7 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly } if (! lower_layer_covered->empty()) voids = diff(voids, *lower_layer_covered); - fill_boundaries = diff(fill_boundaries, voids); + fill_boundaries = diff(fill_boundaries, voids); } } @@ -473,4 +473,4 @@ void LayerRegion::export_region_fill_surfaces_to_svg_debug(const char *name) con } } - \ No newline at end of file + diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 7526dd16aa..1e06f0703e 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1462,7 +1462,7 @@ stl_stats ModelObject::get_object_stl_stats() const return this->volumes[0]->mesh().stl.stats; stl_stats full_stats; - memset(&full_stats, 0, sizeof(stl_stats)); + full_stats.volume = 0.f; // fill full_stats from all objet's meshes for (ModelVolume* volume : this->volumes) diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 347cfa2ce2..f5601276f0 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -253,7 +253,7 @@ bool Print::is_step_done(PrintObjectStep step) const { if (m_objects.empty()) return false; - tbb::mutex::scoped_lock lock(this->state_mutex()); + tbb::mutex::scoped_lock lock(this->state_mutex()); for (const PrintObject *object : m_objects) if (! object->is_step_done_unguarded(step)) return false; diff --git a/src/libslic3r/PrintBase.hpp b/src/libslic3r/PrintBase.hpp index aebc879044..05d884cc88 100644 --- a/src/libslic3r/PrintBase.hpp +++ b/src/libslic3r/PrintBase.hpp @@ -268,8 +268,7 @@ public: std::string text; // Bitmap of flags. enum FlagBits { - DEFAULT, - NO_RELOAD_SCENE = 0, + DEFAULT = 0, RELOAD_SCENE = 1 << 1, RELOAD_SLA_SUPPORT_POINTS = 1 << 2, RELOAD_SLA_PREVIEW = 1 << 3, diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 4559df8b76..c4f77b6d7e 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1475,7 +1475,7 @@ SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig& full if (object_max_z <= 0.f) object_max_z = (float)model_object.raw_bounding_box().size().z(); - return SlicingParameters::create_from_config(print_config, object_config, object_max_z, object_extruders); + return SlicingParameters::create_from_config(print_config, object_config, object_max_z, object_extruders); } // returns 0-based indices of extruders used to print the object (without brim, support and other helper extrusions) diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp index 505fdcaf58..c0c8e9ea0a 100644 --- a/src/libslic3r/SupportMaterial.cpp +++ b/src/libslic3r/SupportMaterial.cpp @@ -783,7 +783,7 @@ namespace SupportMaterialInternal { for (const ExtrusionPath &ep : loop.paths) if (ep.role() == erOverhangPerimeter && ! ep.polyline.empty()) return ep.size() >= (ep.is_closed() ? 3 : 2); - return false; + return false; } static bool has_bridging_perimeters(const ExtrusionEntityCollection &perimeters) { @@ -2125,7 +2125,7 @@ void PrintObjectSupportMaterial::trim_support_layers_by_object( } // $layer->slices contains the full shape of layer, thus including // perimeter's width. $support contains the full shape of support - // material, thus including the width of its foremost extrusion. + // material, thus including the width of its foremost extrusion. // We leave a gap equal to a full extrusion width. support_layer.polygons = diff(support_layer.polygons, polygons_trimming); } @@ -2934,20 +2934,13 @@ void PrintObjectSupportMaterial::generate_toolpaths( // Prepare fillers. SupportMaterialPattern support_pattern = m_object_config->support_material_pattern; bool with_sheath = m_object_config->support_material_with_sheath; - InfillPattern infill_pattern; + InfillPattern infill_pattern = (support_pattern == smpHoneycomb ? ipHoneycomb : ipRectilinear); std::vector angles; angles.push_back(base_angle); - switch (support_pattern) { - case smpRectilinearGrid: + + if (support_pattern == smpRectilinearGrid) angles.push_back(interface_angle); - // fall through - case smpRectilinear: - infill_pattern = ipRectilinear; - break; - case smpHoneycomb: - infill_pattern = ipHoneycomb; - break; - } + BoundingBox bbox_object(Point(-scale_(1.), -scale_(1.0)), Point(scale_(1.), scale_(1.))); // const coordf_t link_max_length_factor = 3.; @@ -3217,7 +3210,7 @@ void PrintObjectSupportMaterial::generate_toolpaths( density = 0.5f; flow = m_first_layer_flow; // use the proper spacing for first layer as we don't need to align - // its pattern to the other layers + // its pattern to the other layers //FIXME When paralellizing, each thread shall have its own copy of the fillers. filler->spacing = flow.spacing(); filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / density)); diff --git a/src/slic3r/Config/Snapshot.cpp b/src/slic3r/Config/Snapshot.cpp index 622b31a178..80b6521b6f 100644 --- a/src/slic3r/Config/Snapshot.cpp +++ b/src/slic3r/Config/Snapshot.cpp @@ -342,7 +342,7 @@ static void copy_config_dir_single_level(const boost::filesystem::path &path_src ! boost::filesystem::create_directory(path_dst)) throw std::runtime_error(std::string("Slic3r was unable to create a directory at ") + path_dst.string()); - for (auto &dir_entry : boost::filesystem::directory_iterator(path_src)) + for (auto &dir_entry : boost::filesystem::directory_iterator(path_src)) if (Slic3r::is_ini_file(dir_entry)) boost::filesystem::copy_file(dir_entry.path(), path_dst / dir_entry.path().filename(), boost::filesystem::copy_option::overwrite_if_exists); } @@ -351,7 +351,7 @@ static void delete_existing_ini_files(const boost::filesystem::path &path) { if (! boost::filesystem::is_directory(path)) return; - for (auto &dir_entry : boost::filesystem::directory_iterator(path)) + for (auto &dir_entry : boost::filesystem::directory_iterator(path)) if (boost::filesystem::is_regular_file(dir_entry.status()) && boost::algorithm::iends_with(dir_entry.path().filename().string(), ".ini")) boost::filesystem::remove(dir_entry.path()); } @@ -378,7 +378,7 @@ const Snapshot& SnapshotDB::take_snapshot(const AppConfig &app_config, Snapshot: sprintf(name, "filament_%u", i); if (! app_config.has("presets", name)) break; - snapshot.filaments.emplace_back(app_config.get("presets", name)); + snapshot.filaments.emplace_back(app_config.get("presets", name)); } // Vendor specific config bundles and installed printers. for (const std::pair>> &vendor : app_config.vendors()) { @@ -417,7 +417,7 @@ const Snapshot& SnapshotDB::take_snapshot(const AppConfig &app_config, Snapshot: // Backup the presets. for (const char *subdir : { "print", "filament", "printer", "vendor" }) copy_config_dir_single_level(data_dir / subdir, snapshot_dir / subdir); - snapshot.save_ini((snapshot_dir / "snapshot.ini").string()); + snapshot.save_ini((snapshot_dir / "snapshot.ini").string()); assert(m_snapshots.empty() || m_snapshots.back().time_captured <= snapshot.time_captured); m_snapshots.emplace_back(std::move(snapshot)); return m_snapshots.back(); diff --git a/src/slic3r/Config/Version.cpp b/src/slic3r/Config/Version.cpp index 175abff69a..3f8f960f10 100644 --- a/src/slic3r/Config/Version.cpp +++ b/src/slic3r/Config/Version.cpp @@ -227,9 +227,9 @@ size_t Index::load(const boost::filesystem::path &path) // End of semver or keyword. break; } - if (*key_end != 0 && *key_end != ' ' && *key_end != '\t' && *key_end != '=') + if (*key_end != 0 && *key_end != ' ' && *key_end != '\t' && *key_end != '=') throw file_parser_error("Invalid keyword or semantic version", path, idx_line); - char *value = left_trim(key_end); + char *value = left_trim(key_end); bool key_value_pair = *value == '='; if (key_value_pair) value = left_trim(value + 1); @@ -245,11 +245,11 @@ size_t Index::load(const boost::filesystem::path &path) if (strcmp(key, "min_slic3r_version") == 0 || strcmp(key, "max_slic3r_version") == 0) { if (! svalue.empty()) semver = Semver::parse(svalue); - if (! semver) + if (! semver) throw file_parser_error(std::string(key) + " must referece a valid semantic version", path, idx_line); - if (strcmp(key, "min_slic3r_version") == 0) + if (strcmp(key, "min_slic3r_version") == 0) ver.min_slic3r_version = *semver; - else + else ver.max_slic3r_version = *semver; } else { // Ignore unknown keys, as there may come new keys in the future. diff --git a/src/slic3r/GUI/BedShapeDialog.cpp b/src/slic3r/GUI/BedShapeDialog.cpp index 90fc0ff80b..5624ada9d2 100644 --- a/src/slic3r/GUI/BedShapeDialog.cpp +++ b/src/slic3r/GUI/BedShapeDialog.cpp @@ -455,7 +455,7 @@ void BedShapePanel::update_shape() else if (page_idx == SHAPE_CUSTOM) m_shape = m_loaded_shape; - update_preview(); + update_preview(); } // Loads an stl file, projects it to the XY plane and calculates a polygon. diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index 0115ff5f9c..4e7aff0280 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -1225,13 +1225,16 @@ bool ConfigWizard::run(PresetBundle *preset_bundle, const PresetUpdater *updater const wxString& ConfigWizard::name(const bool from_menu/* = false*/) { - // A different naming convention is used for the Wizard on Windows vs. OSX & GTK. + // A different naming convention is used for the Wizard on Windows & GTK vs. OSX. + // Note: Don't call _() macro here. + // This function just return the current name according to the OS. + // Translation is implemented inside GUI_App::add_config_menu() #if __APPLE__ - static const wxString config_wizard_name = _(L("Configuration Assistant")); - static const wxString config_wizard_name_menu = _(L("Configuration &Assistant")); + static const wxString config_wizard_name = L("Configuration Assistant"); + static const wxString config_wizard_name_menu = L("Configuration &Assistant"); #else - static const wxString config_wizard_name = _(L("Configuration Wizard")); - static const wxString config_wizard_name_menu = _(L("Configuration &Wizard")); + static const wxString config_wizard_name = L("Configuration Wizard"); + static const wxString config_wizard_name_menu = L("Configuration &Wizard"); #endif return from_menu ? config_wizard_name_menu : config_wizard_name; } diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 715d9f806a..5b1188169e 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -928,8 +928,8 @@ bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, c if (items_count > 1) m_original_height += (items_count - 1) * scaled_square_contour; - m_width = (int)next_highest_power_of_2((uint32_t)m_original_width); - m_height = (int)next_highest_power_of_2((uint32_t)m_original_height); + m_width = (int)next_highest_power_of_2((uint32_t)m_original_width); + m_height = (int)next_highest_power_of_2((uint32_t)m_original_height); // generates bitmap wxBitmap bitmap(m_width, m_height); @@ -1882,7 +1882,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re if (m_reload_delayed) return; - bool update_object_list = false; + bool update_object_list = false; if (m_volumes.volumes != glvolumes_new) update_object_list = true; @@ -3389,10 +3389,9 @@ void GLCanvas3D::handle_sidebar_focus_event(const std::string& opt_key, bool foc m_sidebar_field = focus_on ? opt_key : ""; if (!m_sidebar_field.empty()) - { m_gizmos.reset_all_states(); - m_dirty = true; - } + + m_dirty = true; } void GLCanvas3D::handle_layers_data_focus_event(const t_layer_height_range range, const EditorType type) @@ -5070,14 +5069,14 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat for (const GCodePreviewData::Extrusion::Layer &layer : preview_data.extrusion.layers) for (const ExtrusionPath &path : layer.paths) ++ num_paths_per_role[size_t(path.role())]; - std::vector> roles_values; + std::vector> roles_values; roles_values.assign(size_t(erCount), std::vector()); for (size_t i = 0; i < roles_values.size(); ++ i) roles_values[i].reserve(num_paths_per_role[i]); - for (const GCodePreviewData::Extrusion::Layer& layer : preview_data.extrusion.layers) + for (const GCodePreviewData::Extrusion::Layer& layer : preview_data.extrusion.layers) for (const ExtrusionPath& path : layer.paths) roles_values[size_t(path.role())].emplace_back(Helper::path_filter(preview_data.extrusion.view_type, path)); - roles_filters.reserve(size_t(erCount)); + roles_filters.reserve(size_t(erCount)); size_t num_buffers = 0; for (std::vector &values : roles_values) { sort_remove_duplicates(values); diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp index f94372667c..6e8c361c82 100644 --- a/src/slic3r/GUI/GUI.cpp +++ b/src/slic3r/GUI/GUI.cpp @@ -125,7 +125,7 @@ void config_wizard(int reason) if (! wxGetApp().check_unsaved_changes()) return; - try { + try { ConfigWizard wizard(nullptr, static_cast(reason)); wizard.run(wxGetApp().preset_bundle, wxGetApp().preset_updater); } diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 80c02ea78e..86523cb88a 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -725,7 +725,7 @@ bool GUI_App::load_language(wxString language, bool initial) #endif if (initial) message + "\n\nApplication will close."; - wxMessageBox(message, "PrusaSlicer - Switching language failed", wxOK | wxICON_ERROR); + wxMessageBox(message, "PrusaSlicer - Switching language failed", wxOK | wxICON_ERROR); if (initial) std::exit(EXIT_FAILURE); else diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 1d5d8f1a56..19dedc7b0e 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -273,6 +273,8 @@ void ObjectList::create_objects_ctrl() AppendBitmapColumn(_(L("Editing")), colEditing, wxDATAVIEW_CELL_INERT, 3*em, wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE); + // For some reason under OSX on 4K(5K) monitors in wxDataViewColumn constructor doesn't set width of column. + // Therefore, force set column width. if (wxOSX) { GetColumn(colName)->SetWidth(20*em); @@ -751,9 +753,9 @@ void ObjectList::paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& vol } select_items(items); -#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME +//#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME selection_changed(); -#endif //no __WXOSX__ //__WXMSW__ +//#endif //no __WXOSX__ //__WXMSW__ } void ObjectList::paste_objects_into_list(const std::vector& object_idxs) @@ -771,9 +773,9 @@ void ObjectList::paste_objects_into_list(const std::vector& object_idxs) wxGetApp().plater()->changed_objects(object_idxs); select_items(items); -#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME +//#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME selection_changed(); -#endif //no __WXOSX__ //__WXMSW__ +//#endif //no __WXOSX__ //__WXMSW__ } #ifdef __WXOSX__ @@ -810,8 +812,15 @@ void ObjectList::list_manipulation(bool evt_context_menu/* = false*/) */ if (!item) { - if (wxOSX && col == nullptr) - UnselectAll(); + if (col == nullptr) { + if (wxOSX) + UnselectAll(); + else if (!evt_context_menu) + // Case, when last item was deleted and under GTK was called wxEVT_DATAVIEW_SELECTION_CHANGED, + // which invoked next list_manipulation(false) + return; + } + if (evt_context_menu) { show_context_menu(evt_context_menu); return; @@ -1330,7 +1339,7 @@ wxMenu* ObjectList::append_submenu_add_generic(wxMenu* menu, const ModelVolumeTy for (auto& item : { L("Box"), L("Cylinder"), L("Sphere"), L("Slab") }) { - if (type == ModelVolumeType::INVALID && item == "Slab") + if (type == ModelVolumeType::INVALID && strncmp(item, "Slab", 4) == 0) continue; append_menu_item(sub_menu, wxID_ANY, _(item), "", [this, type, item](wxCommandEvent&) { load_generic_subobject(item, type); }, "", menu); @@ -1713,9 +1722,9 @@ void ObjectList::load_subobject(ModelVolumeType type) if (sel_item) select_item(sel_item); -#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME +//#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME selection_changed(); -#endif //no __WXOSX__ //__WXMSW__ +//#endif //no __WXOSX__ //__WXMSW__ } void ObjectList::load_part( ModelObject* model_object, @@ -1851,9 +1860,9 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const Mode const auto object_item = m_objects_model->GetTopParent(GetSelection()); select_item(m_objects_model->AddVolumeChild(object_item, name, type, new_volume->get_mesh_errors_count()>0)); -#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME +//#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME selection_changed(); -#endif //no __WXOSX__ //__WXMSW__ +//#endif //no __WXOSX__ //__WXMSW__ } void ObjectList::load_shape_object(const std::string& type_name) @@ -1892,6 +1901,9 @@ void ObjectList::load_shape_object(const std::string& type_name) new_volume->config.set_key_value("extruder", new ConfigOptionInt(0)); new_object->invalidate_bounding_box(); + new_object->center_around_origin(); + new_object->ensure_on_bed(); + const BoundingBoxf bed_shape = wxGetApp().plater()->bed_shape_bb(); new_object->instances[0]->set_offset(Slic3r::to_3d(bed_shape.center().cast(), -new_object->origin_translation(2))); @@ -3677,10 +3689,10 @@ void ObjectList::msw_rescale() // update min size !!! A width of control shouldn't be a wxDefaultCoord SetMinSize(wxSize(1, 15 * em)); - GetColumn(colName)->SetWidth(19 * em); - GetColumn(colPrint)->SetWidth( 2 * em); + GetColumn(colName )->SetWidth(20 * em); + GetColumn(colPrint )->SetWidth( 3 * em); GetColumn(colExtruder)->SetWidth( 8 * em); - GetColumn(colEditing)->SetWidth( 2 * em); + GetColumn(colEditing )->SetWidth( 3 * em); // rescale all icons, used by ObjectList msw_rescale_icons(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 992f4912a1..000ddf8c95 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -252,7 +252,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) const sla::SupportPoint& support_point = m_editing_mode ? m_editing_cache[i].support_point : m_normal_cache[i]; const bool& point_selected = m_editing_mode ? m_editing_cache[i].selected : false; - if (is_point_clipped(support_point.pos.cast())) + if (is_mesh_point_clipped(support_point.pos.cast())) continue; // First decide about the color of the point. @@ -335,14 +335,14 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) -bool GLGizmoSlaSupports::is_point_clipped(const Vec3d& point) const +bool GLGizmoSlaSupports::is_mesh_point_clipped(const Vec3d& point) const { if (m_clipping_plane_distance == 0.f) return false; Vec3d transformed_point = m_model_object->instances.front()->get_transformation().get_matrix() * point; transformed_point(2) += m_z_shift; - return m_clipping_plane->distance(transformed_point) < 0.; + return m_clipping_plane->is_point_clipped(transformed_point); } @@ -391,27 +391,15 @@ bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pair hits; - std::vector normals; - m_mesh_raycaster->unproject_on_mesh(mouse_pos, trafo.get_matrix(), camera, &hits, &normals); - - // We must also take care of the clipping plane (if active) - unsigned i = 0; - if (m_clipping_plane_distance != 0.f) { - for (i=0; i())) - break; + Vec3f hit; + Vec3f normal; + if (m_mesh_raycaster->unproject_on_mesh(mouse_pos, trafo.get_matrix(), camera, hit, normal, m_clipping_plane.get())) { + // Return both the point and the facet normal. + pos_and_normal = std::make_pair(hit, normal); + return true; } - - if (i==hits.size() || (hits.size()-i) % 2 != 0) { - // All hits are either clipped, or there is an odd number of unclipped - // hits - meaning the nearest must be from inside the mesh. + else return false; - } - - // Calculate and return both the point and the facet normal. - pos_and_normal = std::make_pair(hits[i], normals[i]); - return true; } // Following function is called from GLCanvas3D to inform the gizmo about a mouse/keyboard event. @@ -481,19 +469,15 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous std::vector points_inside; std::vector points_idxs = m_selection_rectangle.stop_dragging(m_parent, points); for (size_t idx : points_idxs) - points_inside.push_back((trafo.get_matrix() * points[idx]).cast()); + points_inside.push_back(points[idx].cast()); // Only select/deselect points that are actually visible - for (size_t idx : m_mesh_raycaster->get_unobscured_idxs(trafo, m_parent.get_camera(), points_inside, - [this](const Vec3f& pt) { return is_point_clipped(pt.cast()); })) + for (size_t idx : m_mesh_raycaster->get_unobscured_idxs(trafo, m_parent.get_camera(), points_inside, m_clipping_plane.get())) { - const sla::SupportPoint &support_point = m_editing_cache[points_idxs[idx]].support_point; - if (! is_point_clipped(support_point.pos.cast())) { - if (rectangle_status == GLSelectionRectangle::Deselect) - unselect_point(points_idxs[idx]); - else - select_point(points_idxs[idx]); - } + if (rectangle_status == GLSelectionRectangle::Deselect) + unselect_point(points_idxs[idx]); + else + select_point(points_idxs[idx]); } return true; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index cf5245f194..15b2df80ea 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -125,7 +125,7 @@ private: mutable std::unique_ptr m_supports_clipper; std::vector get_config_options(const std::vector& keys) const; - bool is_point_clipped(const Vec3d& point) const; + bool is_mesh_point_clipped(const Vec3d& point) const; //void find_intersecting_facets(const igl::AABB* aabb, const Vec3f& normal, double offset, std::vector& out) const; // Methods that do the model_object and editing cache synchronization, diff --git a/src/slic3r/GUI/LambdaObjectDialog.cpp b/src/slic3r/GUI/LambdaObjectDialog.cpp index 4d1cb06584..63c8d329c5 100644 --- a/src/slic3r/GUI/LambdaObjectDialog.cpp +++ b/src/slic3r/GUI/LambdaObjectDialog.cpp @@ -192,7 +192,7 @@ ConfigOptionsGroupShp LambdaObjectDialog::init_modificator_options_page(const wx else panel->SetSizer(optgroup->sizer); - return optgroup; + return optgroup; } diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index dfe3a9cf92..7c36f3665d 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -917,7 +917,7 @@ void MainFrame::load_config_file() wxString file; if (dlg.ShowModal() == wxID_OK) file = dlg.GetPath(); - if (! file.IsEmpty() && this->load_config_file(file.ToUTF8().data())) { + if (! file.IsEmpty() && this->load_config_file(file.ToUTF8().data())) { wxGetApp().app_config->update_config_dir(get_dir_name(file)); m_last_config = file; } diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp index e559020e97..62a6813a66 100644 --- a/src/slic3r/GUI/MeshUtils.cpp +++ b/src/slic3r/GUI/MeshUtils.cpp @@ -152,8 +152,8 @@ Vec3f MeshRaycaster::AABBWrapper::get_hit_normal(const igl::Hit& hit) const } -bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, - const Camera& camera, std::vector* positions, std::vector* normals) const +bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, + Vec3f& position, Vec3f& normal, const ClippingPlane* clipping_plane) const { const std::array& viewport = camera.get_viewport(); const Transform3d& model_mat = camera.get_view_matrix(); @@ -179,25 +179,30 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& std::sort(hits.begin(), hits.end(), [](const igl::Hit& a, const igl::Hit& b) { return a.t < b.t; }); - // Now stuff the points in the provided vector and calculate normals if asked about them: - if (positions != nullptr) { - positions->clear(); - if (normals != nullptr) - normals->clear(); - for (const igl::Hit& hit : hits) { - positions->push_back(m_AABB_wrapper->get_hit_pos(hit)); + unsigned i = 0; - if (normals != nullptr) - normals->push_back(m_AABB_wrapper->get_hit_normal(hit)); + // Remove points that are obscured or cut by the clipping plane + if (clipping_plane) { + for (i=0; iis_point_clipped(trafo * m_AABB_wrapper->get_hit_pos(hits[i]).cast())) + break; + + if (i==hits.size() || (hits.size()-i) % 2 != 0) { + // All hits are either clipped, or there is an odd number of unclipped + // hits - meaning the nearest must be from inside the mesh. + return false; } } + // Now stuff the points in the provided vector and calculate normals if asked about them: + position = m_AABB_wrapper->get_hit_pos(hits[i]); + normal = m_AABB_wrapper->get_hit_normal(hits[i]); return true; } std::vector MeshRaycaster::get_unobscured_idxs(const Geometry::Transformation& trafo, const Camera& camera, const std::vector& points, - std::function fn_ignore_hit) const + const ClippingPlane* clipping_plane) const { std::vector out; @@ -206,19 +211,24 @@ std::vector MeshRaycaster::get_unobscured_idxs(const Geometry::Transfo Vec3f direction_to_camera_mesh = (instance_matrix_no_translation_no_scaling.inverse().cast() * direction_to_camera).normalized().eval(); Vec3f scaling = trafo.get_scaling_factor().cast(); direction_to_camera_mesh = Vec3f(direction_to_camera_mesh(0)*scaling(0), direction_to_camera_mesh(1)*scaling(1), direction_to_camera_mesh(2)*scaling(2)); + const Transform3f inverse_trafo = trafo.get_matrix().inverse().cast(); for (size_t i=0; iis_point_clipped(pt.cast())) + continue; + bool is_obscured = false; // Cast a ray in the direction of the camera and look for intersection with the mesh: std::vector hits; - // Offset the start of the ray to the front of the ball + EPSILON to account for numerical inaccuracies. + // Offset the start of the ray by EPSILON to account for numerical inaccuracies. if (m_AABB_wrapper->m_AABB.intersect_ray( AABBWrapper::MapMatrixXfUnaligned(m_mesh->its.vertices.front().data(), m_mesh->its.vertices.size(), 3), AABBWrapper::MapMatrixXiUnaligned(m_mesh->its.indices.front().data(), m_mesh->its.indices.size(), 3), - pt + direction_to_camera_mesh * EPSILON, direction_to_camera_mesh, hits)) { + inverse_trafo * pt + direction_to_camera_mesh * EPSILON, direction_to_camera_mesh, hits)) { std::sort(hits.begin(), hits.end(), [](const igl::Hit& h1, const igl::Hit& h2) { return h1.t < h2.t; }); + // If the closest hit facet normal points in the same direction as the ray, // we are looking through the mesh and should therefore discard the point: if (m_AABB_wrapper->get_hit_normal(hits.front()).dot(direction_to_camera_mesh) > 0.f) @@ -227,11 +237,12 @@ std::vector MeshRaycaster::get_unobscured_idxs(const Geometry::Transfo // Eradicate all hits that the caller wants to ignore for (unsigned j=0; jget_hit_pos(hit))) { + if (clipping_plane && clipping_plane->is_point_clipped(trafo.get_matrix() * m_AABB_wrapper->get_hit_pos(hit).cast())) { hits.erase(hits.begin()+j); --j; } } + // FIXME: the intersection could in theory be behind the camera, but as of now we only have camera direction. // Also, the threshold is in mesh coordinates, not in actual dimensions. if (! hits.empty()) diff --git a/src/slic3r/GUI/MeshUtils.hpp b/src/slic3r/GUI/MeshUtils.hpp index a2be2677bd..e4c4c20d22 100644 --- a/src/slic3r/GUI/MeshUtils.hpp +++ b/src/slic3r/GUI/MeshUtils.hpp @@ -50,6 +50,7 @@ public: return (-get_normal().dot(pt) + m_data[3]); } + bool is_point_clipped(const Vec3d& point) const { return distance(point) < 0.; } void set_normal(const Vec3d& normal) { for (size_t i=0; i<3; ++i) m_data[i] = normal(i); } void set_offset(double offset) { m_data[3] = offset; } Vec3d get_normal() const { return Vec3d(m_data[0], m_data[1], m_data[2]); } @@ -98,10 +99,10 @@ public: void set_camera(const Camera& camera); bool unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, - std::vector* positions = nullptr, std::vector* normals = nullptr) const; + Vec3f& position, Vec3f& normal, const ClippingPlane* clipping_plane = nullptr) const; std::vector get_unobscured_idxs(const Geometry::Transformation& trafo, const Camera& camera, - const std::vector& points, std::function fn_ignore_hit) const; + const std::vector& points, const ClippingPlane* clipping_plane = nullptr) const; Vec3f get_closest_point(const Vec3f& point, Vec3f* normal = nullptr) const; diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index c032aac729..698c1e0348 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -133,7 +133,7 @@ void OptionsGroup::append_line(const Line& line, wxStaticText** full_Label/* = n m_options_mode.push_back(option_set[0].opt.mode); // if we have a single option with no label, no sidetext just add it directly to sizer - if (option_set.size() == 1 && label_width == 0 && option_set.front().opt.full_width && + if (option_set.size() == 1 && label_width == 0 && option_set.front().opt.full_width && option_set.front().opt.label.empty() && option_set.front().opt.sidetext.size() == 0 && option_set.front().side_widget == nullptr && line.get_extra_widgets().size() == 0) { diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 28474cac93..97c292703a 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3322,7 +3322,7 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt) this->statusbar()->set_progress(evt.status.percent); this->statusbar()->set_status_text(_(evt.status.text) + wxString::FromUTF8("…")); } - if (evt.status.flags & (PrintBase::SlicingStatus::RELOAD_SCENE || PrintBase::SlicingStatus::RELOAD_SLA_SUPPORT_POINTS)) { + if (evt.status.flags & (PrintBase::SlicingStatus::RELOAD_SCENE | PrintBase::SlicingStatus::RELOAD_SLA_SUPPORT_POINTS)) { switch (this->printer_technology) { case ptFFF: this->update_fff_scene(); @@ -4288,11 +4288,10 @@ void Plater::increase_instances(size_t num) sidebar().obj_list()->increase_object_instances(obj_idx, was_one_instance ? num + 1 : num); - if (p->get_config("autocenter") == "1") { + if (p->get_config("autocenter") == "1") p->arrange(); - } else { - p->update(); - } + + p->update(); p->get_selection().add_instance(obj_idx, (int)model_object->instances.size() - 1); diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp index d9e90333c6..5785fd8507 100644 --- a/src/slic3r/GUI/PresetBundle.cpp +++ b/src/slic3r/GUI/PresetBundle.cpp @@ -279,7 +279,7 @@ std::string PresetBundle::load_system_presets() errors_cummulative += "\n"; } } - if (first) { + if (first) { // No config bundle loaded, reset. this->reset(false); } diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 40fbbbac63..13d4a73602 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -410,7 +410,7 @@ void Selection::set_deserialized(EMode mode, const std::vectorselected = false; m_list.clear(); diff --git a/src/slic3r/GUI/WipeTowerDialog.cpp b/src/slic3r/GUI/WipeTowerDialog.cpp index 460683f772..5394225456 100644 --- a/src/slic3r/GUI/WipeTowerDialog.cpp +++ b/src/slic3r/GUI/WipeTowerDialog.cpp @@ -371,7 +371,7 @@ void WipingPanel::toggle_advanced(bool user_action) { else m_advanced = !advanced_matches_simple(); // if called from constructor, show what is appropriate - (m_advanced ? m_page_advanced : m_page_simple)->Show(); + (m_advanced ? m_page_advanced : m_page_simple)->Show(); (!m_advanced ? m_page_advanced : m_page_simple)->Hide(); m_widget_button->SetLabel(m_advanced ? _(L("Show simplified settings")) : _(L("Show advanced settings"))); diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index bf5500cf45..59406b6e97 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -669,7 +669,7 @@ wxDataViewItem ObjectDataViewModel::Add(const wxString &name, if (has_errors) root->m_bmp = *m_warning_bmp; - m_objects.push_back(root); + m_objects.push_back(root); // notify control wxDataViewItem child((void*)root); wxDataViewItem parent((void*)NULL); @@ -720,7 +720,7 @@ wxDataViewItem ObjectDataViewModel::AddVolumeChild( const wxDataViewItem &parent root->SetBitmap(*m_warning_bmp); // notify control - const wxDataViewItem child((void*)node); + const wxDataViewItem child((void*)node); ItemAdded(parent_item, child); root->m_volumes_cnt++;