Merge remote-tracking branch 'remote/main' into dev/h2d-2
# Conflicts: # src/libslic3r/PrintConfig.cpp # src/slic3r/GUI/ConfigManipulation.cpp
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
#include "ShortestPath.hpp"
|
||||
#include "libslic3r.h"
|
||||
#include "PrintConfig.hpp"
|
||||
#include "MaterialType.hpp"
|
||||
#include "Model.hpp"
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
@@ -590,13 +591,10 @@ double getadhesionCoeff(const PrintObject* printObject)
|
||||
for (auto iter = extrudersFirstLayer.begin(); iter != extrudersFirstLayer.end(); iter++) {
|
||||
if (modelVolume->extruder_id() == *iter) {
|
||||
if (Model::extruderParamsMap.find(modelVolume->extruder_id()) != Model::extruderParamsMap.end()) {
|
||||
if (Model::extruderParamsMap.at(modelVolume->extruder_id()).materialName == "PETG" ||
|
||||
Model::extruderParamsMap.at(modelVolume->extruder_id()).materialName == "PCTG") {
|
||||
adhesionCoeff = 2;
|
||||
}
|
||||
else if (Model::extruderParamsMap.at(modelVolume->extruder_id()).materialName == "TPU") {
|
||||
adhesionCoeff = 0.5;
|
||||
}
|
||||
std::string filament_type = Model::extruderParamsMap.at(modelVolume->extruder_id()).materialName;
|
||||
double adhesion_coefficient = 1.0; // Default value
|
||||
MaterialType::get_adhesion_coefficient(filament_type, adhesion_coefficient);
|
||||
adhesionCoeff = adhesion_coefficient;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,6 +344,8 @@ set(lisbslic3r_sources
|
||||
PrintApply.cpp
|
||||
PrintBase.cpp
|
||||
PrintBase.hpp
|
||||
MaterialType.cpp
|
||||
MaterialType.hpp
|
||||
PrintConfig.cpp
|
||||
PrintConfig.hpp
|
||||
Print.cpp
|
||||
|
||||
@@ -305,8 +305,8 @@ ConfigSubstitutions import_sla_archive(
|
||||
std::function<bool(int)> progr)
|
||||
{
|
||||
// Ensure minimum window size for marching squares
|
||||
windowsize.x() = std::max(2, windowsize.x());
|
||||
windowsize.y() = std::max(2, windowsize.y());
|
||||
windowsize.x() = std::max(1, windowsize.x());
|
||||
windowsize.y() = std::max(1, windowsize.y());
|
||||
|
||||
std::string exclude_entries{"thumbnail"};
|
||||
ArchiveData arch = extract_sla_archive(zipfname, exclude_entries);
|
||||
|
||||
@@ -1,49 +1,160 @@
|
||||
#ifndef MARCHINGSQUARES_HPP
|
||||
#define MARCHINGSQUARES_HPP
|
||||
|
||||
#include "Execution/ExecutionTBB.hpp"
|
||||
#include <type_traits>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
// Marching squares
|
||||
//
|
||||
// This algorithm generates 2D contour rings for a 2D scalar field (height
|
||||
// map). See https://en.wikipedia.org/wiki/Marching_squares for details.
|
||||
//
|
||||
// This algorithm uses square cells (tiles) with corner tags that are set
|
||||
// depending on which vertices are inside an ROI (higher than the selected
|
||||
// isovalue threshold). We label the vertices counter-clockwise, and for ease
|
||||
// of extraction from the m_tags bitmap we put them into a four bit bitmap in
|
||||
// little-endian row-column order <cbda>;
|
||||
//
|
||||
// ^ u (up) ----> column "c" direction
|
||||
// |
|
||||
// a ----- d
|
||||
// | | |
|
||||
// l <--| |--> r | increasing row "r" direction
|
||||
// (left) | | (right) \/
|
||||
// b ----- c
|
||||
// |
|
||||
// \/ d (down)
|
||||
//
|
||||
// The m_tags bitmap has the top-left "a" corner of each cell packed
|
||||
// into uint32_t values stored in little-endian order, with the "a" tag for
|
||||
// the first cell (r=0,c=0) in the LSB bit0 of the first 32bit word of the
|
||||
// first row. The grid has a one cell border round the raster area that is
|
||||
// always clear so lines never extend out of the grid.
|
||||
//
|
||||
// From this grid of points we can get the <cbda> tags bitmap for the four
|
||||
// corners of each cell with "a" in the LSB bit0 and "c" in bit3. Note the
|
||||
// bits b,c,d are also the "a" bits of the cell's next-colum/row neighbour
|
||||
// cells. Cells in the right-most column get their cleared right-side border
|
||||
// <c_b_> tags by wrapping around the grid and getting the cleared values
|
||||
// from the left-side border. Note the grid bitmap always includes at least
|
||||
// one extra cleared boarder bit for the wrap-around of the last tag in the
|
||||
// last cell. Cells in the bottom row get their cleared bottom-side border
|
||||
// <cb__> tags by leaving them clear because their grid index exceeds the
|
||||
// grid size.
|
||||
//
|
||||
// These tag bits are then translated into up/down/left/right cell-exit
|
||||
// directions indicating the cell edge(s) that any lines will cross and exit
|
||||
// the cell. As you walk counter-clock-wise around the cell corners in the
|
||||
// order a->b->c->d, any edge from a unset-corner-tag to an set-corner-tag is
|
||||
// where a line will cross, exiting the cell into the next cell.
|
||||
//
|
||||
// Note any set-to-unset-transition edge is where a line will enter a cell,
|
||||
// but for marching the lines through the cells we only need to keep the next
|
||||
// cell exit directions. The exit directions are stored as 4bit <urdl>
|
||||
// left/down/right/up flags packed into uint32_t values in m_dirs, in
|
||||
// counter-clockwise little-endian order.
|
||||
//
|
||||
// To build the line-rings we scan through the m_dirs directions for the
|
||||
// cells until we find one with a set-edge. We then start a line and "march"
|
||||
// it through the cells following the directions in each cell, recording each
|
||||
// edge the line crosses that will become a point in the ring.
|
||||
//
|
||||
// Note that the outside-edge of the grid extends one cell past the raster
|
||||
// grid, and this outer edge is always cleared. This means no line will cross
|
||||
// out of the grid, and they will all eventually connect back to their
|
||||
// starting cell to become a ring around an island of set tag bits, possibly
|
||||
// containing rings around lakes of unset tag bits within them.
|
||||
//
|
||||
// As we march through the cells and build the lines, we clear the direction
|
||||
// bits to indicate the edge-transition has been processed. After completing
|
||||
// a ring we return to scanning for the next non-zeroed starting cell for the
|
||||
// next ring. Eventually all rings will be found and completed, and the
|
||||
// m_dirs map will be completely cleared.
|
||||
//
|
||||
// Note there are two ambigous cases when the diagonally opposite corner tags
|
||||
// are set. In these cases two lines will enter and exit the cell. To avoid
|
||||
// messy lines, we consistently choose the exit direction based on what edge
|
||||
// the line entered the cell from. This also means when we start scanning for
|
||||
// the next ring we should start checking at the same cell the last ring
|
||||
// started from, because it could have a second ring passing through it.
|
||||
//
|
||||
namespace marchsq {
|
||||
|
||||
// Marks a square in the grid
|
||||
struct Coord {
|
||||
// Marks a square or point in grid or raster coordintes.
|
||||
struct Coord
|
||||
{
|
||||
long r = 0, c = 0;
|
||||
|
||||
|
||||
Coord() = default;
|
||||
explicit Coord(long s) : r(s), c(s) {}
|
||||
Coord(long _r, long _c): r(_r), c(_c) {}
|
||||
|
||||
size_t seq(const Coord &res) const { return r * res.c + c; }
|
||||
Coord& operator+=(const Coord& b) { r += b.r; c += b.c; return *this; }
|
||||
Coord operator+(const Coord& b) const { Coord a = *this; a += b; return a; }
|
||||
Coord(long _r, long _c) : r(_r), c(_c) {}
|
||||
|
||||
size_t seq(const Coord& res) const { return r * res.c + c; }
|
||||
Coord& operator+=(const Coord& b)
|
||||
{
|
||||
r += b.r;
|
||||
c += b.c;
|
||||
return *this;
|
||||
}
|
||||
Coord operator+(const Coord& b) const
|
||||
{
|
||||
Coord a = *this;
|
||||
a += b;
|
||||
return a;
|
||||
}
|
||||
bool operator==(const Coord& o) const { return (r == o.r) && (c == o.c); }
|
||||
bool operator!=(const Coord& o) const { return !(*this == o); }
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const Coord& o) { return os << "(r=" << o.r << ",c=" << o.c << ")"; }
|
||||
|
||||
// Closed ring of cell coordinates
|
||||
using Ring = std::vector<Coord>;
|
||||
|
||||
// Specialize this struct to register a raster type for the Marching squares alg
|
||||
template<class T, class Enable = void> struct _RasterTraits {
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const Ring& r)
|
||||
{
|
||||
os << "[" << r.size() << "]:";
|
||||
for (Coord c : r)
|
||||
os << " " << c;
|
||||
return os << "\n";
|
||||
}
|
||||
|
||||
// Specialize this struct to register a raster type for MarchingSquares.
|
||||
template<class T, class Enable = void> struct _RasterTraits
|
||||
{
|
||||
// The type of pixel cell in the raster
|
||||
using ValueType = typename T::ValueType;
|
||||
|
||||
|
||||
// Value at a given position
|
||||
static ValueType get(const T &raster, size_t row, size_t col);
|
||||
|
||||
static ValueType get(const T& raster, size_t row, size_t col);
|
||||
|
||||
// Number of rows and cols of the raster
|
||||
static size_t rows(const T &raster);
|
||||
static size_t cols(const T &raster);
|
||||
static size_t rows(const T& raster);
|
||||
static size_t cols(const T& raster);
|
||||
};
|
||||
|
||||
// Specialize this to use parellel loops within the algorithm
|
||||
template<class ExecutionPolicy, class Enable = void> struct _Loop {
|
||||
template<class It, class Fn> static void for_each(It from, It to, Fn &&fn)
|
||||
template<class ExecutionPolicy, class Enable = void> struct _Loop
|
||||
{
|
||||
template<class It, class Fn> static void for_each_idx(It from, It to, Fn&& fn)
|
||||
{
|
||||
for (auto it = from; it < to; ++it) fn(*it, size_t(it - from));
|
||||
for (auto it = from; it < to; ++it)
|
||||
fn(*it, size_t(it - from));
|
||||
}
|
||||
};
|
||||
|
||||
// Add Specialization for using ExecutionTBB for parallel loops.
|
||||
using namespace Slic3r;
|
||||
template<> struct _Loop<ExecutionTBB>
|
||||
{
|
||||
template<class It, class Fn> static void for_each_idx(It from, It to, Fn&& fn)
|
||||
{
|
||||
execution::for_each(
|
||||
ex_tbb, size_t(0), size_t(to - from), [&from, &fn](size_t i) { fn(from[i], i); }, execution::max_concurrency(ex_tbb));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -52,388 +163,481 @@ namespace __impl {
|
||||
template<class T> using RasterTraits = _RasterTraits<std::decay_t<T>>;
|
||||
template<class T> using TRasterValue = typename RasterTraits<T>::ValueType;
|
||||
|
||||
template<class T> size_t rows(const T &raster)
|
||||
template<class T> size_t rows(const T& raster) { return RasterTraits<T>::rows(raster); }
|
||||
|
||||
template<class T> size_t cols(const T& raster) { return RasterTraits<T>::cols(raster); }
|
||||
|
||||
template<class T> TRasterValue<T> isoval(const T& rst, const Coord& crd) { return RasterTraits<T>::get(rst, crd.r, crd.c); }
|
||||
|
||||
template<class ExecutionPolicy, class It, class Fn> void for_each_idx(ExecutionPolicy&& policy, It from, It to, Fn&& fn)
|
||||
{
|
||||
return RasterTraits<T>::rows(raster);
|
||||
_Loop<ExecutionPolicy>::for_each_idx(from, to, fn);
|
||||
}
|
||||
|
||||
template<class T> size_t cols(const T &raster)
|
||||
{
|
||||
return RasterTraits<T>::cols(raster);
|
||||
}
|
||||
template<class E> constexpr std::underlying_type_t<E> _t(E e) noexcept { return static_cast<std::underlying_type_t<E>>(e); }
|
||||
|
||||
template<class T> TRasterValue<T> isoval(const T &rst, const Coord &crd)
|
||||
{
|
||||
return RasterTraits<T>::get(rst, crd.r, crd.c);
|
||||
}
|
||||
|
||||
template<class ExecutionPolicy, class It, class Fn>
|
||||
void for_each(ExecutionPolicy&& policy, It from, It to, Fn &&fn)
|
||||
{
|
||||
_Loop<ExecutionPolicy>::for_each(from, to, fn);
|
||||
}
|
||||
|
||||
// Type of squares (tiles) depending on which vertices are inside an ROI
|
||||
// The vertices would be marked a, b, c, d in counter clockwise order from the
|
||||
// bottom left vertex of a square.
|
||||
// d --- c
|
||||
// | |
|
||||
// | |
|
||||
// a --- b
|
||||
enum class SquareTag : uint8_t {
|
||||
// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
|
||||
none, a, b, ab, c, ac, bc, abc, d, ad, bd, abd, cd, acd, bcd, full
|
||||
// A set of next direction flags for a cell to indicate what sides(s)
|
||||
// any yet-to-be-marched line(s) will cross to leave the cell.
|
||||
enum class Dir : uint8_t {
|
||||
none = 0b0000,
|
||||
left = 0b0001, /* exit through a-b edge */
|
||||
down = 0b0010, /* exit through b-c edge */
|
||||
right = 0b0100, /* exit through c-d edge */
|
||||
leftright = left | right,
|
||||
up = 0b1000, /* exit through d-a edge */
|
||||
updown = up | down,
|
||||
all = 0b1111
|
||||
};
|
||||
|
||||
template<class E> constexpr std::underlying_type_t<E> _t(E e) noexcept
|
||||
inline std::ostream& operator<<(std::ostream& os, const Dir& d) { return os << ".<v#>x##^#X#####"[_t(d)]; }
|
||||
|
||||
// This maps square tag column/row order <cbda> bitmaps to the next
|
||||
// direction(s) a line will exit the cell. The directions ensure the
|
||||
// line-rings circle counter-clock-wise around the clusters of set tags.
|
||||
static const constexpr std::array<uint32_t, 16> NEXT_CCW = [] {
|
||||
auto map = decltype(NEXT_CCW){};
|
||||
for (uint32_t cbda = 0; cbda < 16; cbda++) {
|
||||
const uint32_t dcba = (cbda & 0b0001) | ((cbda >> 1) & 0b0110) | ((cbda << 2) & 0b1000);
|
||||
const uint32_t adcb = (dcba >> 1) | ((dcba << 3) & 0b1000);
|
||||
map[cbda] = ~dcba & adcb;
|
||||
}
|
||||
return map;
|
||||
}();
|
||||
|
||||
// Step a point in a direction, optionally by n steps.
|
||||
inline void step(Coord& crd, const Dir d, const long n = 1)
|
||||
{
|
||||
return static_cast<std::underlying_type_t<E>>(e);
|
||||
switch (d) {
|
||||
case Dir::left: crd.c -= n; break;
|
||||
case Dir::down: crd.r += n; break;
|
||||
case Dir::right: crd.c += n; break;
|
||||
case Dir::up: crd.r -= n; break;
|
||||
}
|
||||
}
|
||||
|
||||
enum class Dir: uint8_t { left, down, right, up, none};
|
||||
|
||||
static const constexpr Dir NEXT_CCW[] = {
|
||||
/* 00 */ Dir::none, // SquareTag::none (empty square, nowhere to go)
|
||||
/* 01 */ Dir::left, // SquareTag::a
|
||||
/* 02 */ Dir::down, // SquareTag::b
|
||||
/* 03 */ Dir::left, // SquareTag::ab
|
||||
/* 04 */ Dir::right, // SquareTag::c
|
||||
/* 05 */ Dir::none, // SquareTag::ac (ambiguous case)
|
||||
/* 06 */ Dir::down, // SquareTag::bc
|
||||
/* 07 */ Dir::left, // SquareTag::abc
|
||||
/* 08 */ Dir::up, // SquareTag::d
|
||||
/* 09 */ Dir::up, // SquareTag::ad
|
||||
/* 10 */ Dir::none, // SquareTag::bd (ambiguous case)
|
||||
/* 11 */ Dir::up, // SquareTag::abd
|
||||
/* 12 */ Dir::right, // SquareTag::cd
|
||||
/* 13 */ Dir::right, // SquareTag::acd
|
||||
/* 14 */ Dir::down, // SquareTag::bcd
|
||||
/* 15 */ Dir::none // SquareTag::full (full covered, nowhere to go)
|
||||
};
|
||||
|
||||
static const constexpr uint8_t PREV_CCW[] = {
|
||||
/* 00 */ 1 << _t(Dir::none),
|
||||
/* 01 */ 1 << _t(Dir::up),
|
||||
/* 02 */ 1 << _t(Dir::left),
|
||||
/* 03 */ 1 << _t(Dir::left),
|
||||
/* 04 */ 1 << _t(Dir::down),
|
||||
/* 05 */ 1 << _t(Dir::up) | 1 << _t(Dir::down),
|
||||
/* 06 */ 1 << _t(Dir::down),
|
||||
/* 07 */ 1 << _t(Dir::down),
|
||||
/* 08 */ 1 << _t(Dir::right),
|
||||
/* 09 */ 1 << _t(Dir::up),
|
||||
/* 10 */ 1 << _t(Dir::left) | 1 << _t(Dir::right),
|
||||
/* 11 */ 1 << _t(Dir::left),
|
||||
/* 12 */ 1 << _t(Dir::right),
|
||||
/* 13 */ 1 << _t(Dir::up),
|
||||
/* 14 */ 1 << _t(Dir::right),
|
||||
/* 15 */ 1 << _t(Dir::none)
|
||||
};
|
||||
|
||||
const constexpr uint8_t DIRMASKS[] = {
|
||||
/*left: */ 0x01, /*down*/ 0x12, /*right */0x21, /*up*/ 0x10, /*none*/ 0x00
|
||||
};
|
||||
|
||||
inline Coord step(const Coord &crd, Dir d)
|
||||
template<class Rst> class Grid
|
||||
{
|
||||
uint8_t dd = DIRMASKS[uint8_t(d)];
|
||||
return {crd.r - 1 + (dd & 0x0f), crd.c - 1 + (dd >> 4)};
|
||||
}
|
||||
const Rst* m_rst = nullptr;
|
||||
Coord m_window, m_rastsize, m_gridsize;
|
||||
size_t m_gridlen; // The number of cells in the grid.
|
||||
std::vector<uint32_t> m_tags; // bit-packed squaretags for each corner.
|
||||
std::vector<uint32_t> m_dirs; // bit-packed next directions for each cell.
|
||||
|
||||
template<class Rst> class Grid {
|
||||
const Rst * m_rst = nullptr;
|
||||
Coord m_cellsize, m_res_1, m_window, m_gridsize, m_grid_1;
|
||||
std::vector<uint8_t> m_tags; // Assign tags to each square
|
||||
|
||||
Coord rastercoord(const Coord &crd) const
|
||||
// Convert a grid coordinate point into raster coordinates.
|
||||
inline Coord rastercoord(const Coord& crd) const
|
||||
{
|
||||
// Note the -1 offset for the grid border around the raster area.
|
||||
return {(crd.r - 1) * m_window.r, (crd.c - 1) * m_window.c};
|
||||
}
|
||||
|
||||
Coord bl(const Coord &crd) const { return tl(crd) + Coord{m_res_1.r, 0}; }
|
||||
Coord br(const Coord &crd) const { return tl(crd) + Coord{m_res_1.r, m_res_1.c}; }
|
||||
Coord tr(const Coord &crd) const { return tl(crd) + Coord{0, m_res_1.c}; }
|
||||
Coord tl(const Coord &crd) const { return rastercoord(crd); }
|
||||
|
||||
bool is_within(const Coord &crd)
|
||||
{
|
||||
long R = rows(*m_rst), C = cols(*m_rst);
|
||||
return crd.r >= 0 && crd.r < R && crd.c >= 0 && crd.c < C;
|
||||
};
|
||||
// Get the 4 corners of a grid coordinate cell in raster coordinates.
|
||||
Coord bl(const Coord& crd) const { return tl(crd) + Coord{m_window.r, 0}; }
|
||||
Coord br(const Coord& crd) const { return tl(crd) + Coord{m_window.r, m_window.c}; }
|
||||
Coord tr(const Coord& crd) const { return tl(crd) + Coord{0, m_window.c}; }
|
||||
Coord tl(const Coord& crd) const { return rastercoord(crd); }
|
||||
|
||||
// Calculate the tag for a cell (or square). The cell coordinates mark the
|
||||
// top left vertex of a square in the raster. v is the isovalue
|
||||
uint8_t get_tag_for_cell(const Coord &cell, TRasterValue<Rst> v)
|
||||
{
|
||||
Coord sqr[] = {bl(cell), br(cell), tr(cell), tl(cell)};
|
||||
|
||||
uint8_t t = ((is_within(sqr[0]) && isoval(*m_rst, sqr[0]) >= v)) +
|
||||
((is_within(sqr[1]) && isoval(*m_rst, sqr[1]) >= v) << 1) +
|
||||
((is_within(sqr[2]) && isoval(*m_rst, sqr[2]) >= v) << 2) +
|
||||
((is_within(sqr[3]) && isoval(*m_rst, sqr[3]) >= v) << 3);
|
||||
|
||||
assert(t < 16);
|
||||
return t;
|
||||
}
|
||||
|
||||
// Get a cell coordinate from a sequential index
|
||||
Coord coord(size_t i) const
|
||||
{
|
||||
return {long(i) / m_gridsize.c, long(i) % m_gridsize.c};
|
||||
}
|
||||
// Test if a raster coordinate point is within the raster area.
|
||||
inline bool is_within(const Coord& crd) const { return crd.r >= 0 && crd.r < m_rastsize.r && crd.c >= 0 && crd.c < m_rastsize.c; }
|
||||
|
||||
size_t seq(const Coord &crd) const { return crd.seq(m_gridsize); }
|
||||
|
||||
bool is_visited(size_t idx, Dir d = Dir::none) const
|
||||
// Get a block of 32 tags for a block index from the raster isovals.
|
||||
uint32_t get_tags_block32(const size_t bidx, const TRasterValue<Rst> v) const
|
||||
{
|
||||
SquareTag t = get_tag(idx);
|
||||
uint8_t ref = d == Dir::none ? PREV_CCW[_t(t)] : uint8_t(1 << _t(d));
|
||||
return t == SquareTag::full || t == SquareTag::none ||
|
||||
((m_tags[idx] & 0xf0) >> 4) == ref;
|
||||
}
|
||||
|
||||
void set_visited(size_t idx, Dir d = Dir::none)
|
||||
{
|
||||
m_tags[idx] |= (1 << (_t(d)) << 4);
|
||||
}
|
||||
|
||||
bool is_ambiguous(size_t idx) const
|
||||
{
|
||||
SquareTag t = get_tag(idx);
|
||||
return t == SquareTag::ac || t == SquareTag::bd;
|
||||
}
|
||||
|
||||
// Search for a new starting square
|
||||
size_t search_start_cell(size_t i = 0) const
|
||||
{
|
||||
// Skip ambiguous tags as starting tags due to unknown previous
|
||||
// direction.
|
||||
while ((i < m_tags.size()) && (is_visited(i) || is_ambiguous(i))) ++i;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
SquareTag get_tag(size_t idx) const { return SquareTag(m_tags[idx] & 0x0f); }
|
||||
|
||||
Dir next_dir(Dir prev, SquareTag tag) const
|
||||
{
|
||||
// Treat ambiguous cases as two separate regions in one square.
|
||||
switch (tag) {
|
||||
case SquareTag::ac:
|
||||
switch (prev) {
|
||||
case Dir::down: return Dir::right;
|
||||
case Dir::up: return Dir::left;
|
||||
default: assert(false); return Dir::none;
|
||||
Coord gcrd = coord(bidx * 32); // position in grid coordinates of the block.
|
||||
Coord rcrd = rastercoord(gcrd); // position in raster coordinates.
|
||||
uint32_t tags = 0;
|
||||
// Set a bit for each corner that has osoval > v.
|
||||
for (uint32_t b = 1; b; b <<= 1) {
|
||||
if (is_within(rcrd) && isoval(*m_rst, rcrd) > v)
|
||||
tags |= b;
|
||||
gcrd.c += 1;
|
||||
rcrd.c += m_window.c;
|
||||
// If we hit the end of the row, start on the next row.
|
||||
if (gcrd.c >= m_gridsize.c) {
|
||||
gcrd = Coord(gcrd.r + 1, 0);
|
||||
rcrd = rastercoord(gcrd);
|
||||
}
|
||||
case SquareTag::bd:
|
||||
switch (prev) {
|
||||
case Dir::right: return Dir::up;
|
||||
case Dir::left: return Dir::down;
|
||||
default: assert(false); return Dir::none;
|
||||
}
|
||||
default:
|
||||
return NEXT_CCW[uint8_t(tag)];
|
||||
}
|
||||
|
||||
return Dir::none;
|
||||
return tags;
|
||||
}
|
||||
|
||||
struct CellIt {
|
||||
Coord crd; Dir dir= Dir::none; const Rst *grid = nullptr;
|
||||
|
||||
TRasterValue<Rst> operator*() const { return isoval(*grid, crd); }
|
||||
CellIt& operator++() { crd = step(crd, dir); return *this; }
|
||||
CellIt operator++(int) { CellIt it = *this; ++(*this); return it; }
|
||||
bool operator!=(const CellIt &it) { return crd.r != it.crd.r || crd.c != it.crd.c; }
|
||||
|
||||
|
||||
// Get a block of 8 directions for a block index from the tags.
|
||||
uint32_t get_dirs_block8(const size_t bidx) const
|
||||
{
|
||||
size_t gidx = bidx * 8;
|
||||
uint32_t dirs = 0;
|
||||
|
||||
// Get the next 9 top-row tags at this grid index into the bottom 16
|
||||
// bits, and the 9 bottom-row tags into the top 16 bits.
|
||||
uint32_t tags9 = get_tags9(gidx) | (get_tags9(gidx + m_gridsize.c) << 16);
|
||||
// Skip generating dirs if the tags are all 1's or all 0's.
|
||||
if ((tags9 != 0) && (tags9 != 0x01ff01ff)) {
|
||||
for (auto s = 0; s < 32; s += 4) {
|
||||
uint8_t tags = (tags9 & 0b11) | ((tags9 >> 14) & 0b1100);
|
||||
dirs |= NEXT_CCW[tags] << s;
|
||||
tags9 >>= 1;
|
||||
}
|
||||
}
|
||||
return dirs;
|
||||
}
|
||||
|
||||
// Get the next 9 corner tags on a row for building a dirs block at a grid index.
|
||||
uint32_t get_tags9(size_t gidx) const
|
||||
{
|
||||
uint32_t tags = 0; // the tags value.
|
||||
size_t i = gidx / 32; // the tags block index
|
||||
int o = gidx % 32; // the tags block offset
|
||||
|
||||
if (gidx < m_gridlen) {
|
||||
// get the next 9 tags in the row.
|
||||
tags = (m_tags[i] >> o) & 0x1ff;
|
||||
// Some of the tags are in the next tags block.
|
||||
if ((o > (32 - 9)) && ((i + 1) < m_tags.size())) {
|
||||
tags |= (m_tags[i + 1] << (32 - o)) & 0x1ff;
|
||||
}
|
||||
}
|
||||
return tags;
|
||||
}
|
||||
|
||||
// Clear directions in a cell's <urdl> dirs for a grid index.
|
||||
void clr_dirs(const size_t gidx, const Dir d)
|
||||
{
|
||||
assert(gidx < m_gridlen);
|
||||
size_t i = gidx / 8; // the dirs block index
|
||||
int o = (gidx % 8); // the dirs block offset
|
||||
|
||||
m_dirs[i] &= ~(static_cast<uint32_t>(d) << (o * 4));
|
||||
}
|
||||
|
||||
// Get directions in a cell's <uldr> dirs from the m_dirs store.
|
||||
Dir get_dirs(const size_t gidx) const
|
||||
{
|
||||
assert(gidx < m_gridlen);
|
||||
size_t i = gidx / 8; // the dirs block index
|
||||
int o = (gidx % 8); // the dirs block offset
|
||||
|
||||
return Dir((m_dirs[i] >> (o * 4)) & 0b1111);
|
||||
}
|
||||
|
||||
// Get a cell coordinate from a sequential grid index.
|
||||
Coord coord(size_t i) const { return {long(i) / m_gridsize.c, long(i) % m_gridsize.c}; }
|
||||
|
||||
// Get a sequential index from a cell coordinate.
|
||||
size_t seq(const Coord& crd) const { return crd.seq(m_gridsize); }
|
||||
|
||||
// Step a sequential grid index in a direction.
|
||||
size_t stepidx(const size_t idx, const Dir d) const
|
||||
{
|
||||
assert(idx < m_gridlen);
|
||||
switch (d) {
|
||||
case Dir::left: return idx - 1;
|
||||
case Dir::down: return idx + m_gridsize.c;
|
||||
case Dir::right: return idx + 1;
|
||||
case Dir::up: return idx - m_gridsize.c;
|
||||
default: return idx;
|
||||
}
|
||||
}
|
||||
|
||||
// Search for a new starting square.
|
||||
size_t search_start_cell(size_t gidx = 0) const
|
||||
{
|
||||
size_t i = gidx / 8; // The dirs block index.
|
||||
int o = gidx % 8; // The dirs block offset.
|
||||
|
||||
// Skip cells without any unvisited edges.
|
||||
while (i < m_dirs.size()) {
|
||||
if (!m_dirs[i]) {
|
||||
// Whole block is clear, advance to the next block;
|
||||
i++;
|
||||
o = 0;
|
||||
} else {
|
||||
// Block not clear, find the next non-zero tags in the block. Note
|
||||
// all dirs before gidx are cleared, so any set bits must be in
|
||||
// block offsets >= o, not before.
|
||||
for (uint32_t m = 0b1111 << (o * 4); !(m_dirs[i] & m); m <<= 4)
|
||||
o++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i * 8 + o;
|
||||
}
|
||||
|
||||
// Get the next direction for a cell index after the prev direction.
|
||||
Dir next_dir(size_t idx, Dir prev = Dir::all) const
|
||||
{
|
||||
Dir next = get_dirs(idx);
|
||||
|
||||
// Treat ambiguous cases as two separate regions in one square. If
|
||||
// there are two possible next directions, pick based on the prev
|
||||
// direction. If prev=all we are starting a new line so pick the one
|
||||
// that leads "forwards" (right or down) in the search.
|
||||
switch (next) {
|
||||
case Dir::leftright:
|
||||
// We must be coming from up, down, or starting a new line.
|
||||
assert(prev == Dir::up || prev == Dir::down || prev == Dir::all);
|
||||
return (prev == Dir::up) ? Dir::left : Dir::right;
|
||||
case Dir::updown:
|
||||
// We must be coming from left, right, or starting a new line.
|
||||
assert(prev == Dir::left || prev == Dir::right || prev == Dir::all);
|
||||
return (prev == Dir::right) ? Dir::up : Dir::down;
|
||||
default:
|
||||
// Next must be a single direction or none to stop.
|
||||
assert(next == Dir::none || next == Dir::left || next == Dir::down || next == Dir::right || next == Dir::up);
|
||||
return next;
|
||||
}
|
||||
}
|
||||
|
||||
struct CellIt
|
||||
{
|
||||
using iterator_category = std::random_access_iterator_tag;
|
||||
using value_type = TRasterValue<Rst>;
|
||||
using pointer = TRasterValue<Rst> *;
|
||||
using reference = TRasterValue<Rst> &;
|
||||
using pointer = TRasterValue<Rst>*;
|
||||
using reference = TRasterValue<Rst>&;
|
||||
using difference_type = long;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
Coord crd;
|
||||
Dir dir = Dir::none;
|
||||
const Rst* grid = nullptr;
|
||||
|
||||
inline TRasterValue<Rst> operator*() const { return isoval(*grid, crd); }
|
||||
inline TRasterValue<Rst>& operator[](long n) const { return *((*this) + n); }
|
||||
inline CellIt& operator++()
|
||||
{
|
||||
step(crd, dir);
|
||||
return *this;
|
||||
}
|
||||
inline CellIt operator++(int)
|
||||
{
|
||||
CellIt o = *this;
|
||||
++(*this);
|
||||
return o;
|
||||
}
|
||||
inline CellIt& operator--()
|
||||
{
|
||||
step(crd, dir, -1);
|
||||
return *this;
|
||||
}
|
||||
inline CellIt operator--(int)
|
||||
{
|
||||
CellIt o = *this;
|
||||
--(*this);
|
||||
return o;
|
||||
}
|
||||
inline CellIt& operator+=(long n)
|
||||
{
|
||||
step(crd, dir, n);
|
||||
return *this;
|
||||
}
|
||||
inline CellIt& operator-=(long n)
|
||||
{
|
||||
step(crd, dir, -n);
|
||||
return *this;
|
||||
}
|
||||
inline CellIt operator+(long n) const
|
||||
{
|
||||
CellIt o = *this;
|
||||
o += n;
|
||||
return o;
|
||||
}
|
||||
inline CellIt operator-(long n) const
|
||||
{
|
||||
CellIt o = *this;
|
||||
o -= n;
|
||||
return o;
|
||||
}
|
||||
inline long operator-(const CellIt& o) const
|
||||
{
|
||||
switch (dir) {
|
||||
case Dir::left: return o.crd.c - crd.c;
|
||||
case Dir::down: return crd.r - o.crd.r;
|
||||
case Dir::right: return crd.c - o.crd.c;
|
||||
case Dir::up: return o.crd.r - crd.r;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
inline bool operator==(const CellIt& o) const { return crd == o.crd; }
|
||||
inline bool operator!=(const CellIt& o) const { return crd != o.crd; }
|
||||
inline bool operator<(const CellIt& o) const { return (*this - o) < 0; }
|
||||
inline bool operator>(const CellIt& o) const { return (*this - o) > 0; }
|
||||
inline bool operator<=(const CellIt& o) const { return (*this - o) <= 0; }
|
||||
inline bool operator>=(const CellIt& o) const { return (*this - o) >= 0; }
|
||||
};
|
||||
|
||||
|
||||
// Two cell iterators representing an edge of a square. This is then
|
||||
// used for binary search for the first active pixel on the edge.
|
||||
struct Edge { CellIt from, to; };
|
||||
|
||||
Edge _edge(const Coord &ringvertex) const
|
||||
struct Edge
|
||||
{
|
||||
size_t idx = ringvertex.r;
|
||||
Coord cell = coord(idx);
|
||||
uint8_t tg = m_tags[ringvertex.r];
|
||||
SquareTag t = SquareTag(tg & 0x0f);
|
||||
|
||||
switch (t) {
|
||||
case SquareTag::a:
|
||||
case SquareTag::ab:
|
||||
case SquareTag::abc:
|
||||
return {{tl(cell), Dir::down, m_rst}, {bl(cell)}};
|
||||
case SquareTag::b:
|
||||
case SquareTag::bc:
|
||||
case SquareTag::bcd:
|
||||
return {{bl(cell), Dir::right, m_rst}, {br(cell)}};
|
||||
case SquareTag::c:
|
||||
return {{br(cell), Dir::up, m_rst}, {tr(cell)}};
|
||||
case SquareTag::ac:
|
||||
switch (Dir(ringvertex.c)) {
|
||||
case Dir::left: return {{tl(cell), Dir::down, m_rst}, {bl(cell)}};
|
||||
case Dir::right: return {{br(cell), Dir::up, m_rst}, {tr(cell)}};
|
||||
default: assert(false);
|
||||
}
|
||||
case SquareTag::d:
|
||||
case SquareTag::ad:
|
||||
case SquareTag::abd:
|
||||
return {{tr(cell), Dir::left, m_rst}, {tl(cell)}};
|
||||
case SquareTag::bd:
|
||||
switch (Dir(ringvertex.c)) {
|
||||
case Dir::down: return {{bl(cell), Dir::right, m_rst}, {br(cell)}};
|
||||
case Dir::up: return {{tr(cell), Dir::left, m_rst}, {tl(cell)}};
|
||||
default: assert(false);
|
||||
}
|
||||
case SquareTag::cd:
|
||||
case SquareTag::acd:
|
||||
return {{br(cell), Dir::up, m_rst}, {tr(cell)}};
|
||||
case SquareTag::full:
|
||||
case SquareTag::none: {
|
||||
Coord crd{tl(cell) + Coord{m_cellsize.r / 2, m_cellsize.c / 2}};
|
||||
return {{crd, Dir::none, m_rst}, {crd}};
|
||||
CellIt from, to;
|
||||
};
|
||||
|
||||
Edge _edge(const Coord& ringvertex) const
|
||||
{
|
||||
size_t idx = ringvertex.r;
|
||||
Coord cell = coord(idx);
|
||||
Dir d = Dir(ringvertex.c);
|
||||
|
||||
switch (d) {
|
||||
case Dir::left: return {{tl(cell), Dir::down, m_rst}, {bl(cell)}};
|
||||
case Dir::down: return {{bl(cell), Dir::right, m_rst}, {br(cell)}};
|
||||
case Dir::right: return {{br(cell), Dir::up, m_rst}, {tr(cell)}};
|
||||
case Dir::up: return {{tr(cell), Dir::left, m_rst}, {tl(cell)}};
|
||||
default: assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
return {};
|
||||
}
|
||||
|
||||
Edge edge(const Coord &ringvertex) const
|
||||
|
||||
Edge edge(const Coord& ringvertex) const
|
||||
{
|
||||
const long R = rows(*m_rst), C = cols(*m_rst);
|
||||
const long R_1 = R - 1, C_1 = C - 1;
|
||||
|
||||
Edge e = _edge(ringvertex);
|
||||
Edge e = _edge(ringvertex);
|
||||
e.to.dir = e.from.dir;
|
||||
++e.to;
|
||||
|
||||
e.from.crd.r = std::min(e.from.crd.r, R_1);
|
||||
e.from.crd.r = std::max(e.from.crd.r, 0l);
|
||||
e.from.crd.c = std::min(e.from.crd.c, C_1);
|
||||
e.from.crd.c = std::max(e.from.crd.c, 0l);
|
||||
|
||||
e.to.crd.r = std::min(e.to.crd.r, R);
|
||||
e.to.crd.r = std::max(e.to.crd.r, 0l);
|
||||
e.to.crd.c = std::min(e.to.crd.c, C);
|
||||
e.to.crd.c = std::max(e.to.crd.c, 0l);
|
||||
|
||||
|
||||
e.from.crd.r = std::clamp(e.from.crd.r, 0l, m_rastsize.r - 1);
|
||||
e.from.crd.c = std::clamp(e.from.crd.c, 0l, m_rastsize.c - 1);
|
||||
e.to.crd.r = std::clamp(e.to.crd.r, 0l, m_rastsize.r);
|
||||
e.to.crd.c = std::clamp(e.to.crd.c, 0l, m_rastsize.c);
|
||||
return e;
|
||||
}
|
||||
|
||||
public:
|
||||
explicit Grid(const Rst &rst, const Coord &cellsz, const Coord &overlap)
|
||||
: m_rst{&rst}
|
||||
, m_cellsize{cellsz}
|
||||
, m_res_1{m_cellsize.r - 1, m_cellsize.c - 1}
|
||||
, m_window{overlap.r < cellsz.r ? cellsz.r - overlap.r : cellsz.r,
|
||||
overlap.c < cellsz.c ? cellsz.c - overlap.c : cellsz.c}
|
||||
, m_gridsize{2 + (long(rows(rst)) - overlap.r) / m_window.r,
|
||||
2 + (long(cols(rst)) - overlap.c) / m_window.c}
|
||||
, m_tags(m_gridsize.r * m_gridsize.c, 0)
|
||||
{}
|
||||
|
||||
// Go through the cells and mark them with the appropriate tag.
|
||||
template<class ExecutionPolicy>
|
||||
void tag_grid(ExecutionPolicy &&policy, TRasterValue<Rst> isoval)
|
||||
{
|
||||
// parallel for r
|
||||
for_each (std::forward<ExecutionPolicy>(policy),
|
||||
m_tags.begin(), m_tags.end(),
|
||||
[this, isoval](uint8_t& tag, size_t idx) {
|
||||
tag = get_tag_for_cell(coord(idx), isoval);
|
||||
});
|
||||
|
||||
void interpolate_edge(Coord& ecrd, TRasterValue<Rst> isoval) const
|
||||
{
|
||||
// The ecrd must have a grid index in r and a direction in c.
|
||||
assert((0 <= ecrd.r) && (ecrd.r < m_gridlen));
|
||||
assert((ecrd.c == long(Dir::left)) || (ecrd.c == long(Dir::down)) || (ecrd.c == long(Dir::right)) || (ecrd.c == long(Dir::up)));
|
||||
Edge e = edge(ecrd);
|
||||
ecrd = std::lower_bound(e.from, e.to, isoval).crd;
|
||||
// Shift bottom and right side points "out" by one to account for
|
||||
// raster pixel width. Note "dir" is the direction of interpolation
|
||||
// along the cell edge, not the next move direction.
|
||||
if (e.from.dir == Dir::up)
|
||||
ecrd.r += 1;
|
||||
else if (e.from.dir == Dir::left)
|
||||
ecrd.c += 1;
|
||||
}
|
||||
|
||||
// Scan for the rings on the tagged grid. Each ring vertex stores the
|
||||
// sequential index of the cell and the next direction (Dir).
|
||||
// This info can be used later to calculate the exact raster coordinate.
|
||||
|
||||
public:
|
||||
explicit Grid(const Rst& rst, const Coord& window)
|
||||
: m_rst{&rst}
|
||||
, m_window{window}
|
||||
, m_rastsize{static_cast<long>(rows(rst)), static_cast<long>(cols(rst))}
|
||||
, m_gridsize{2 + m_rastsize.r / m_window.r, 2 + m_rastsize.c / m_window.c}
|
||||
, m_gridlen{static_cast<size_t>(m_gridsize.r * m_gridsize.c)}
|
||||
, m_tags(m_gridlen / 32 + 1, 0) // 1 bit per tag means 32 per uint32_t.
|
||||
, m_dirs(m_gridlen / 8 + 1, 0) // 4 bits per cell means 32/4=8 per uint32_t.
|
||||
{}
|
||||
|
||||
// Go through the cells getting their tags and dirs.
|
||||
template<class ExecutionPolicy> void tag_grid(ExecutionPolicy&& policy, TRasterValue<Rst> isoval)
|
||||
{
|
||||
// Get all the tags. parallel?
|
||||
for_each_idx(std::forward<ExecutionPolicy>(policy), m_tags.begin(), m_tags.end(),
|
||||
[this, isoval](uint32_t& tag_block, size_t bidx) { tag_block = get_tags_block32(bidx, isoval); });
|
||||
// streamtags(std::cerr);
|
||||
// Get all the dirs. parallel?
|
||||
for_each_idx(std::forward<ExecutionPolicy>(policy), m_dirs.begin(), m_dirs.end(),
|
||||
[this](uint32_t& dirs_block, size_t bidx) { dirs_block = get_dirs_block8(bidx); });
|
||||
// streamdirs(std::cerr);
|
||||
}
|
||||
|
||||
// Scan for the rings on the tagged grid. Each ring vertex uses the Coord
|
||||
// to store the sequential cell index (idx in r) and next direction (Dir
|
||||
// in c) for the next point of the ring. This info can be used later to
|
||||
// calculate the exact raster coordinate of the point.
|
||||
std::vector<Ring> scan_rings()
|
||||
{
|
||||
std::vector<Ring> rings;
|
||||
size_t startidx = 0;
|
||||
while ((startidx = search_start_cell(startidx)) < m_tags.size()) {
|
||||
size_t startidx = 0;
|
||||
while ((startidx = search_start_cell(startidx)) < m_gridlen) {
|
||||
Ring ring;
|
||||
|
||||
size_t idx = startidx;
|
||||
Dir prev = Dir::none, next = next_dir(prev, get_tag(idx));
|
||||
|
||||
while (next != Dir::none && !is_visited(idx, prev)) {
|
||||
|
||||
size_t idx = startidx;
|
||||
Dir next = next_dir(idx);
|
||||
do {
|
||||
// We should never touch a cell with no remaining directions
|
||||
// until we get back to the start cell.
|
||||
assert(next != Dir::none);
|
||||
Coord ringvertex{long(idx), long(next)};
|
||||
ring.emplace_back(ringvertex);
|
||||
set_visited(idx, prev);
|
||||
|
||||
idx = seq(step(coord(idx), next));
|
||||
prev = next;
|
||||
next = next_dir(next, get_tag(idx));
|
||||
}
|
||||
|
||||
// To prevent infinite loops in case of degenerate input
|
||||
if (next == Dir::none) m_tags[startidx] = _t(SquareTag::none);
|
||||
|
||||
if (ring.size() > 1) {
|
||||
ring.pop_back();
|
||||
clr_dirs(idx, next);
|
||||
idx = stepidx(idx, next);
|
||||
next = next_dir(idx, next);
|
||||
assert(idx < m_gridlen);
|
||||
} while (idx != startidx);
|
||||
// The start cell on returning should either have its directions
|
||||
// cleared or have the second ambiguous direction.
|
||||
assert(next == Dir::none || next == Dir::left || next == Dir::up);
|
||||
if (ring.size() > 1)
|
||||
rings.emplace_back(ring);
|
||||
}
|
||||
}
|
||||
|
||||
return rings;
|
||||
}
|
||||
|
||||
|
||||
// Calculate the exact raster position from the cells which store the
|
||||
// sequantial index of the square and the next direction
|
||||
template<class ExecutionPolicy>
|
||||
void interpolate_rings(ExecutionPolicy && policy,
|
||||
std::vector<Ring> &rings,
|
||||
TRasterValue<Rst> isov)
|
||||
// sequential index of the square and the next direction
|
||||
template<class ExecutionPolicy> void interpolate_rings(ExecutionPolicy&& policy, std::vector<Ring>& rings, TRasterValue<Rst> isov)
|
||||
{
|
||||
for_each(std::forward<ExecutionPolicy>(policy),
|
||||
rings.begin(), rings.end(), [this, isov] (Ring &ring, size_t)
|
||||
{
|
||||
for (Coord &ringvertex : ring) {
|
||||
Edge e = edge(ringvertex);
|
||||
|
||||
CellIt found = std::lower_bound(e.from, e.to, isov);
|
||||
ringvertex = found.crd;
|
||||
}
|
||||
for_each_idx(std::forward<ExecutionPolicy>(policy), rings.begin(), rings.end(), [this, isov](Ring& ring, size_t) {
|
||||
for (Coord& e : ring)
|
||||
interpolate_edge(e, isov);
|
||||
});
|
||||
}
|
||||
|
||||
std::ostream& streamtags(std::ostream& os)
|
||||
{
|
||||
os << " :";
|
||||
for (auto c = 0; c < m_gridsize.c; c++)
|
||||
os << (c % 10);
|
||||
os << "\n";
|
||||
for (auto r = 0; r < m_gridsize.r; r++) {
|
||||
os << std::setw(3) << r << ":";
|
||||
for (auto c = 0; c < m_gridsize.c; c++)
|
||||
os << ((get_tags9(seq(Coord(r, c))) & 1) ? "H" : ".");
|
||||
os << "\n";
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream& streamdirs(std::ostream& os)
|
||||
{
|
||||
os << " :";
|
||||
for (auto c = 0; c < m_gridsize.c; c++)
|
||||
os << (c % 10);
|
||||
os << "\n";
|
||||
for (auto r = 0; r < m_gridsize.r; r++) {
|
||||
os << std::setw(3) << r << ":";
|
||||
for (auto c = 0; c < m_gridsize.c; c++)
|
||||
os << get_dirs(seq(Coord(r, c)));
|
||||
os << std::endl;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
};
|
||||
|
||||
template<class Raster, class ExecutionPolicy>
|
||||
std::vector<marchsq::Ring> execute_with_policy(ExecutionPolicy && policy,
|
||||
const Raster & raster,
|
||||
std::vector<marchsq::Ring> execute_with_policy(ExecutionPolicy&& policy,
|
||||
const Raster& raster,
|
||||
TRasterValue<Raster> isoval,
|
||||
Coord windowsize = {})
|
||||
Coord windowsize = {})
|
||||
{
|
||||
if (!rows(raster) || !cols(raster)) return {};
|
||||
|
||||
if (!rows(raster) || !cols(raster))
|
||||
return {};
|
||||
|
||||
size_t ratio = cols(raster) / rows(raster);
|
||||
|
||||
if (!windowsize.r) windowsize.r = 2;
|
||||
|
||||
if (!windowsize.r)
|
||||
windowsize.r = 2;
|
||||
if (!windowsize.c)
|
||||
windowsize.c = std::max(2l, long(windowsize.r * ratio));
|
||||
|
||||
Coord overlap{1};
|
||||
|
||||
Grid<Raster> grid{raster, windowsize, overlap};
|
||||
|
||||
|
||||
Grid<Raster> grid{raster, windowsize};
|
||||
|
||||
grid.tag_grid(std::forward<ExecutionPolicy>(policy), isoval);
|
||||
std::vector<marchsq::Ring> rings = grid.scan_rings();
|
||||
grid.interpolate_rings(std::forward<ExecutionPolicy>(policy), rings, isoval);
|
||||
|
||||
|
||||
return rings;
|
||||
}
|
||||
|
||||
template<class Raster>
|
||||
std::vector<marchsq::Ring> execute(const Raster &raster,
|
||||
TRasterValue<Raster> isoval,
|
||||
Coord windowsize = {})
|
||||
template<class Raster> std::vector<marchsq::Ring> execute(const Raster& raster, TRasterValue<Raster> isoval, Coord windowsize = {})
|
||||
{
|
||||
return execute_with_policy(nullptr, raster, isoval, windowsize);
|
||||
}
|
||||
|
||||
169
src/libslic3r/MaterialType.cpp
Normal file
169
src/libslic3r/MaterialType.cpp
Normal file
@@ -0,0 +1,169 @@
|
||||
#include "MaterialType.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace Slic3r {
|
||||
namespace {
|
||||
constexpr int DEFAULT_MIN_TEMP = 190;
|
||||
constexpr int DEFAULT_MAX_TEMP = 300;
|
||||
constexpr int DEFAULT_CHAMBER_MIN_TEMP = 0;
|
||||
constexpr int DEFAULT_CHAMBER_MAX_TEMP = 100;
|
||||
constexpr double DEFAULT_ADHESION_COEFFICIENT = 1.0;
|
||||
constexpr double DEFAULT_YIELD_STRENGTH = 0.02;
|
||||
constexpr double DEFAULT_THERMAL_LENGTH = 200.0;
|
||||
} // namespace
|
||||
|
||||
const std::vector<MaterialTypeInfo>& MaterialType::all()
|
||||
{
|
||||
static const std::vector<MaterialTypeInfo> material_types = {
|
||||
{"ABS", 190, 300, 50, 65, 1, 0.1 , 100},
|
||||
{"ABS-CF", 220, 300, 50, 65, 1, 0.1 , 100},
|
||||
{"ABS-GF", 240, 280, 50, 65, 1, 0.1 , 100},
|
||||
{"ASA", 220, 300, 50, 65, 1, 0.1 , 100},
|
||||
{"ASA-CF", 230, 300, 50, 65, 1, 0.1 , 100},
|
||||
{"ASA-GF", 240, 300, 50, 65, 1, 0.1 , 100},
|
||||
{"ASA-AERO", 240, 280, 50, 65, 1, 0.1 , 100},
|
||||
{"BVOH", 190, 240, 0, 70, 1, 0.02, 200},
|
||||
{"EVA", 175, 220, 0, 50, 1, 0.02, 200},
|
||||
{"FLEX", 210, 230, 0, 50, 0.5, 0.02, 1000},
|
||||
{"HIPS", 220, 270, 50, 60, 1, 0.02, 200},
|
||||
{"PA", 235, 280, 50, 60, 1, 0.02, 100},
|
||||
{"PA-CF", 240, 315, 50, 60, 1, 0.02, 100},
|
||||
{"PA-GF", 240, 290, 50, 60, 1, 0.02, 100},
|
||||
{"PA6", 260, 300, 50, 60, 1, 0.02, 100},
|
||||
{"PA6-CF", 230, 300, 50, 60, 1, 0.02, 100},
|
||||
{"PA6-GF", 260, 300, 50, 60, 1, 0.02, 100},
|
||||
{"PA11", 275, 295, 50, 60, 1, 0.02, 100},
|
||||
{"PA11-CF", 275, 295, 50, 60, 1, 0.02, 100},
|
||||
{"PA11-GF", 275, 295, 50, 60, 1, 0.02, 100},
|
||||
{"PA12", 250, 270, 50, 60, 1, 0.02, 100},
|
||||
{"PA12-CF", 250, 300, 50, 60, 1, 0.02, 100},
|
||||
{"PA12-GF", 255, 270, 50, 60, 1, 0.02, 100},
|
||||
{"PAHT", 260, 310, 55, 65, 1, 0.02, 200},
|
||||
{"PAHT-CF", 270, 310, 55, 65, 1, 0.02, 200},
|
||||
{"PAHT-GF", 270, 310, 55, 65, 1, 0.02, 200},
|
||||
{"PC", 240, 300, 60, 70, 1, 0.02, 40},
|
||||
{"PC-ABS", 230, 270, 60, 70, 1, 0.02, 80},
|
||||
{"PC-CF", 270, 295, 60, 70, 1, 0.02, 80},
|
||||
{"PC-PBT", 260, 300, 60, 70, 1, 0.02, 40},
|
||||
{"PCL", 130, 170, 0, 45, 1, 0.02, 200},
|
||||
{"PCTG", 220, 300, 0, 55, 2, 0.02, 200},
|
||||
{"PE", 175, 260, 45, 60, 1, 0.02, 200},
|
||||
{"PE-CF", 175, 260, 45, 60, 1, 0.02, 200},
|
||||
{"PE-GF", 230, 270, 45, 60, 1, 0.02, 200},
|
||||
{"PEI-1010", 370, 430, 80, 100, 1, 0.02, 200},
|
||||
{"PEI-1010-CF", 380, 430, 80, 100, 1, 0.02, 200},
|
||||
{"PEI-1010-GF", 380, 430, 80, 100, 1, 0.02, 200},
|
||||
{"PEI-9085", 350, 390, 80, 100, 1, 0.02, 200},
|
||||
{"PEI-9085-CF", 365, 390, 80, 100, 1, 0.02, 200},
|
||||
{"PEI-9085-GF", 370, 390, 80, 100, 1, 0.02, 200},
|
||||
{"PEEK", 350, 460, 80, 100, 1, 0.02, 200},
|
||||
{"PEEK-CF", 380, 410, 80, 100, 1, 0.02, 200},
|
||||
{"PEEK-GF", 375, 410, 80, 100, 1, 0.02, 200},
|
||||
{"PEKK", 325, 400, 80, 100, 1, 0.02, 200},
|
||||
{"PEKK-CF", 360, 400, 80, 100, 1, 0.02, 200},
|
||||
{"PES", 340, 390, 80, 100, 1, 0.02, 200},
|
||||
{"PET", 200, 290, 0, 55, 2, 0.3 , 100},
|
||||
{"PET-CF", 240, 320, 0, 55, 2, 0.3 , 100},
|
||||
{"PET-GF", 280, 320, 0, 55, 2, 0.3 , 100},
|
||||
{"PETG", 190, 260, 0, 55, 2, 0.3 , 100},
|
||||
{"PETG-CF", 230, 290, 0, 55, 1, 0.3 , 100},
|
||||
{"PETG-GF", 210, 270, 0, 55, 1, 0.3 , 100},
|
||||
{"PHA", 190, 250, 0, 55, 1, 0.02, 200},
|
||||
{"PI", 390, 410, 90, 100, 1, 0.02, 200},
|
||||
{"PLA", 180, 240, 0, 45, 1, 0.02, 200},
|
||||
{"PLA-AERO", 220, 270, 0, 55, 1, 0.02, 200},
|
||||
{"PLA-CF", 190, 250, 0, 50, 1, 0.02, 200},
|
||||
{"POM", 210, 250, 50, 65, 1, 0.02, 200},
|
||||
{"PP", 200, 240, 45, 60, 1, 0.02, 200},
|
||||
{"PP-CF", 210, 250, 45, 60, 1, 0.02, 200},
|
||||
{"PP-GF", 220, 260, 45, 60, 1, 0.02, 200},
|
||||
{"PPA-CF", 260, 300, 55, 70, 1, 0.02, 200},
|
||||
{"PPA-GF", 260, 290, 55, 70, 1, 0.02, 200},
|
||||
{"PPS", 300, 345, 90, 100, 1, 0.02, 200},
|
||||
{"PPS-CF", 295, 350, 90, 100, 1, 0.02, 200},
|
||||
{"PPSU", 360, 420, 90, 100, 1, 0.02, 200},
|
||||
{"PSU", 350, 380, 90, 100, 1, 0.02, 200},
|
||||
{"PVA", 185, 250, 0, 60, 1, 0.02, 200},
|
||||
{"PVB", 190, 250, 0, 55, 1, 0.02, 200},
|
||||
{"PVDF", 245, 265, 40, 60, 1, 0.02, 200},
|
||||
{"SBS", 195, 250, 0, 55, 1, 0.02, 200},
|
||||
{"TPI", 420, 445, 90, 100, 1, 0.02, 200},
|
||||
{"TPU", 175, 260, 0, 50, 0.5, 0.02, 1000}
|
||||
};
|
||||
|
||||
return material_types;
|
||||
}
|
||||
|
||||
const MaterialTypeInfo* MaterialType::find(const std::string& name)
|
||||
{
|
||||
const auto& types = all();
|
||||
const auto it = std::find_if(types.begin(), types.end(), [&name](const MaterialTypeInfo& info) { return info.name == name; });
|
||||
return it != types.end() ? &(*it) : nullptr;
|
||||
}
|
||||
|
||||
bool MaterialType::get_temperature_range(const std::string& type, int& min_temp, int& max_temp)
|
||||
{
|
||||
min_temp = DEFAULT_MIN_TEMP;
|
||||
max_temp = DEFAULT_MAX_TEMP;
|
||||
|
||||
if (const auto* info = find(type)) {
|
||||
min_temp = info->min_temp;
|
||||
max_temp = info->max_temp;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MaterialType::get_chamber_temperature_range(const std::string& type, int& chamber_min_temp, int& chamber_max_temp)
|
||||
{
|
||||
chamber_min_temp = DEFAULT_CHAMBER_MIN_TEMP;
|
||||
chamber_max_temp = DEFAULT_CHAMBER_MAX_TEMP;
|
||||
|
||||
if (const auto* info = find(type)) {
|
||||
chamber_min_temp = info->chamber_min_temp;
|
||||
chamber_max_temp = info->chamber_max_temp;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MaterialType::get_adhesion_coefficient(const std::string& type, double& adhesion_coefficient)
|
||||
{
|
||||
adhesion_coefficient = DEFAULT_ADHESION_COEFFICIENT;
|
||||
|
||||
if (const auto* info = find(type)) {
|
||||
adhesion_coefficient = info->adhesion_coefficient;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MaterialType::get_yield_strength(const std::string& type, double& yield_strength)
|
||||
{
|
||||
yield_strength = DEFAULT_YIELD_STRENGTH;
|
||||
|
||||
if (const auto* info = find(type)) {
|
||||
yield_strength = info->yield_strength;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MaterialType::get_thermal_length(const std::string& type, double& thermal_length)
|
||||
{
|
||||
thermal_length = DEFAULT_THERMAL_LENGTH;
|
||||
|
||||
if (const auto* info = find(type)) {
|
||||
thermal_length = info->thermal_length;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
32
src/libslic3r/MaterialType.hpp
Normal file
32
src/libslic3r/MaterialType.hpp
Normal file
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
struct MaterialTypeInfo {
|
||||
std::string name;
|
||||
int min_temp;
|
||||
int max_temp;
|
||||
int chamber_min_temp;
|
||||
int chamber_max_temp;
|
||||
double adhesion_coefficient;
|
||||
double yield_strength;
|
||||
double thermal_length;
|
||||
};
|
||||
|
||||
class MaterialType {
|
||||
public:
|
||||
static const std::vector<MaterialTypeInfo>& all();
|
||||
|
||||
static const MaterialTypeInfo* find(const std::string& name);
|
||||
|
||||
static bool get_temperature_range(const std::string& type, int& min_temp, int& max_temp);
|
||||
static bool get_chamber_temperature_range(const std::string& type, int& chamber_min_temp, int& chamber_max_temp);
|
||||
static bool get_adhesion_coefficient(const std::string& type, double& adhesion_coefficient);
|
||||
static bool get_yield_strength(const std::string& type, double& yield_strength);
|
||||
static bool get_thermal_length(const std::string& type, double& thermal_length);
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "MTUtils.hpp"
|
||||
#include "TriangleMeshSlicer.hpp"
|
||||
#include "TriangleSelector.hpp"
|
||||
#include "MaterialType.hpp"
|
||||
|
||||
#include "Format/AMF.hpp"
|
||||
#include "Format/svg.hpp"
|
||||
@@ -3163,18 +3164,10 @@ double Model::getThermalLength(const ModelVolume* modelVolumePtr) {
|
||||
double thermalLength = 200.;
|
||||
auto aa = modelVolumePtr->extruder_id();
|
||||
if (Model::extruderParamsMap.find(aa) != Model::extruderParamsMap.end()) {
|
||||
if (Model::extruderParamsMap.at(aa).materialName == "ABS" ||
|
||||
Model::extruderParamsMap.at(aa).materialName == "PA-CF" ||
|
||||
Model::extruderParamsMap.at(aa).materialName == "PET-CF") {
|
||||
thermalLength = 100;
|
||||
double thermal_length = 200.0;
|
||||
if (MaterialType::get_thermal_length(Model::extruderParamsMap.at(aa).materialName, thermal_length)) {
|
||||
return thermal_length;
|
||||
}
|
||||
if (Model::extruderParamsMap.at(aa).materialName == "PC") {
|
||||
thermalLength = 40;
|
||||
}
|
||||
if (Model::extruderParamsMap.at(aa).materialName == "TPU") {
|
||||
thermalLength = 1000;
|
||||
}
|
||||
|
||||
}
|
||||
return thermalLength;
|
||||
}
|
||||
@@ -3237,16 +3230,10 @@ void ModelInstance::invalidate_convex_hull_2d()
|
||||
//BBS adhesion coefficients from model object class
|
||||
double getadhesionCoeff(const ModelVolumePtrs objectVolumes)
|
||||
{
|
||||
double adhesionCoeff = 1;
|
||||
double adhesionCoeff = 1.0;
|
||||
for (const ModelVolume* modelVolume : objectVolumes) {
|
||||
if (Model::extruderParamsMap.find(modelVolume->extruder_id()) != Model::extruderParamsMap.end()) {
|
||||
if (Model::extruderParamsMap.at(modelVolume->extruder_id()).materialName == "PETG" ||
|
||||
Model::extruderParamsMap.at(modelVolume->extruder_id()).materialName == "PCTG") {
|
||||
adhesionCoeff = 2;
|
||||
}
|
||||
else if (Model::extruderParamsMap.at(modelVolume->extruder_id()).materialName == "TPU") {
|
||||
adhesionCoeff = 0.5;
|
||||
}
|
||||
MaterialType::get_adhesion_coefficient(Model::extruderParamsMap.at(modelVolume->extruder_id()).materialName, adhesionCoeff);
|
||||
}
|
||||
}
|
||||
return adhesionCoeff;
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "GCode/WipeTower2.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "PrintConfig.hpp"
|
||||
#include "MaterialType.hpp"
|
||||
#include "Model.hpp"
|
||||
#include "format.hpp"
|
||||
#include <float.h>
|
||||
@@ -57,6 +58,13 @@ PrintRegion::PrintRegion(PrintRegionConfig &&config) : PrintRegion(std::move(con
|
||||
// ORCA: Now this is a parameter
|
||||
//float Print::min_skirt_length = 0;
|
||||
|
||||
struct FilamentType {
|
||||
std::string name;
|
||||
int min_temp;
|
||||
int max_temp;
|
||||
std::string temp_type;
|
||||
};
|
||||
|
||||
void Print::clear()
|
||||
{
|
||||
std::scoped_lock<std::mutex> lock(this->state_mutex());
|
||||
@@ -2707,6 +2715,14 @@ Vec2d Print::translate_to_print_space(const Point &point) const {
|
||||
|
||||
FilamentTempType Print::get_filament_temp_type(const std::string& filament_type)
|
||||
{
|
||||
// FilamentTempType Temperature-based logic
|
||||
int min_temp, max_temp;
|
||||
if (MaterialType::get_temperature_range(filament_type, min_temp, max_temp)) {
|
||||
if (max_temp <= 250) return FilamentTempType::LowTemp;
|
||||
else if (max_temp < 280) return FilamentTempType::HighLowCompatible;
|
||||
else return FilamentTempType::HighTemp;
|
||||
}
|
||||
|
||||
const static std::string HighTempFilamentStr = "high_temp_filament";
|
||||
const static std::string LowTempFilamentStr = "low_temp_filament";
|
||||
const static std::string HighLowCompatibleFilamentStr = "high_low_compatible_filament";
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "PrintConfig.hpp"
|
||||
#include "ClipperUtils.hpp"
|
||||
#include "Config.hpp"
|
||||
#include "MaterialType.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "format.hpp"
|
||||
|
||||
@@ -54,6 +55,8 @@ namespace Slic3r {
|
||||
#define L(s) (s)
|
||||
#define _(s) Slic3r::I18N::translate(s)
|
||||
|
||||
// Filament types are defined in MaterialType.
|
||||
|
||||
|
||||
const std::vector<std::string> filament_extruder_override_keys = {
|
||||
// floats
|
||||
@@ -2503,46 +2506,11 @@ void PrintConfigDef::init_fff_params()
|
||||
def->gui_type = ConfigOptionDef::GUIType::f_enum_open;
|
||||
def->gui_flags = "show_value";
|
||||
|
||||
def->enum_values.push_back("ABS");
|
||||
def->enum_values.push_back("ABS-GF");
|
||||
def->enum_values.push_back("ASA");
|
||||
def->enum_values.push_back("ASA-AERO");
|
||||
def->enum_values.push_back("ASA-CF");
|
||||
def->enum_values.push_back("BVOH");
|
||||
def->enum_values.push_back("PCTG");
|
||||
def->enum_values.push_back("EVA");
|
||||
def->enum_values.push_back("FLEX");
|
||||
def->enum_values.push_back("HIPS");
|
||||
def->enum_values.push_back("PA");
|
||||
def->enum_values.push_back("PA-CF");
|
||||
def->enum_values.push_back("PA-GF");
|
||||
def->enum_values.push_back("PA6-CF");
|
||||
def->enum_values.push_back("PA11-CF");
|
||||
def->enum_values.push_back("PC");
|
||||
def->enum_values.push_back("PC-CF");
|
||||
def->enum_values.push_back("PCTG");
|
||||
def->enum_values.push_back("PE");
|
||||
def->enum_values.push_back("PE-CF");
|
||||
def->enum_values.push_back("PET-CF");
|
||||
def->enum_values.push_back("PETG");
|
||||
def->enum_values.push_back("PETG-CF");
|
||||
def->enum_values.push_back("PETG-CF10");
|
||||
def->enum_values.push_back("PETG-GF");
|
||||
def->enum_values.push_back("PHA");
|
||||
def->enum_values.push_back("PLA");
|
||||
def->enum_values.push_back("PLA-AERO");
|
||||
def->enum_values.push_back("PLA-CF");
|
||||
def->enum_values.push_back("PP");
|
||||
def->enum_values.push_back("PP-CF");
|
||||
def->enum_values.push_back("PP-GF");
|
||||
def->enum_values.push_back("PPA-CF");
|
||||
def->enum_values.push_back("PPA-GF");
|
||||
def->enum_values.push_back("PPS");
|
||||
def->enum_values.push_back("PPS-CF");
|
||||
def->enum_values.push_back("PVA");
|
||||
def->enum_values.push_back("PVB");
|
||||
def->enum_values.push_back("SBS");
|
||||
def->enum_values.push_back("TPU");
|
||||
// Populate the enum values using the shared material type database
|
||||
for (const auto& filament : MaterialType::all()) {
|
||||
def->enum_values.push_back(filament.name);
|
||||
}
|
||||
|
||||
def->mode = comSimple;
|
||||
def->set_default_value(new ConfigOptionStrings { "PLA" });
|
||||
|
||||
|
||||
@@ -10,13 +10,13 @@ namespace marchsq {
|
||||
// Specialize this struct to register a raster type for the Marching squares alg
|
||||
template<> struct _RasterTraits<Slic3r::sla::RasterGrayscaleAA> {
|
||||
using Rst = Slic3r::sla::RasterGrayscaleAA;
|
||||
|
||||
|
||||
// The type of pixel cell in the raster
|
||||
using ValueType = uint8_t;
|
||||
|
||||
|
||||
// Value at a given position
|
||||
static uint8_t get(const Rst &rst, size_t row, size_t col) { return rst.read_pixel(col, row); }
|
||||
|
||||
|
||||
// Number of rows and cols of the raster
|
||||
static size_t rows(const Rst &rst) { return rst.resolution().height_px; }
|
||||
static size_t cols(const Rst &rst) { return rst.resolution().width_px; }
|
||||
@@ -34,57 +34,55 @@ template<class Fn> void foreach_vertex(ExPolygon &poly, Fn &&fn)
|
||||
}
|
||||
|
||||
ExPolygons raster_to_polygons(const RasterGrayscaleAA &rst, Vec2i32 windowsize)
|
||||
{
|
||||
{
|
||||
size_t rows = rst.resolution().height_px, cols = rst.resolution().width_px;
|
||||
|
||||
|
||||
if (rows < 2 || cols < 2) return {};
|
||||
|
||||
|
||||
Polygons polys;
|
||||
long w_rows = std::max(2l, long(windowsize.y()));
|
||||
long w_cols = std::max(2l, long(windowsize.x()));
|
||||
|
||||
long w_rows = std::max(1l, long(windowsize.y()));
|
||||
long w_cols = std::max(1l, long(windowsize.x()));
|
||||
|
||||
std::vector<marchsq::Ring> rings =
|
||||
marchsq::execute(rst, 128, {w_rows, w_cols});
|
||||
|
||||
|
||||
polys.reserve(rings.size());
|
||||
|
||||
|
||||
auto pxd = rst.pixel_dimensions();
|
||||
pxd.w_mm = (rst.resolution().width_px * pxd.w_mm) / (rst.resolution().width_px - 1);
|
||||
pxd.h_mm = (rst.resolution().height_px * pxd.h_mm) / (rst.resolution().height_px - 1);
|
||||
|
||||
|
||||
for (const marchsq::Ring &ring : rings) {
|
||||
Polygon poly; Points &pts = poly.points;
|
||||
pts.reserve(ring.size());
|
||||
|
||||
|
||||
for (const marchsq::Coord &crd : ring)
|
||||
pts.emplace_back(scaled(crd.c * pxd.w_mm), scaled(crd.r * pxd.h_mm));
|
||||
|
||||
|
||||
polys.emplace_back(poly);
|
||||
}
|
||||
|
||||
|
||||
// reverse the raster transformations
|
||||
ExPolygons unioned = union_ex(polys);
|
||||
coord_t width = scaled(cols * pxd.h_mm), height = scaled(rows * pxd.w_mm);
|
||||
|
||||
|
||||
auto tr = rst.trafo();
|
||||
for (ExPolygon &expoly : unioned) {
|
||||
if (tr.mirror_y)
|
||||
foreach_vertex(expoly, [height](Point &p) {p.y() = height - p.y(); });
|
||||
|
||||
|
||||
if (tr.mirror_x)
|
||||
foreach_vertex(expoly, [width](Point &p) {p.x() = width - p.x(); });
|
||||
|
||||
|
||||
expoly.translate(-tr.center_x, -tr.center_y);
|
||||
|
||||
|
||||
if (tr.flipXY)
|
||||
foreach_vertex(expoly, [](Point &p) { std::swap(p.x(), p.y()); });
|
||||
|
||||
|
||||
if ((tr.mirror_x + tr.mirror_y + tr.flipXY) % 2) {
|
||||
expoly.contour.reverse();
|
||||
for (auto &h : expoly.holes) h.reverse();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return unioned;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace sla {
|
||||
|
||||
class RasterGrayscaleAA;
|
||||
|
||||
ExPolygons raster_to_polygons(const RasterGrayscaleAA &rst, Vec2i32 windowsize = {2, 2});
|
||||
ExPolygons raster_to_polygons(const RasterGrayscaleAA &rst, Vec2i32 windowsize = {1, 1});
|
||||
|
||||
}} // namespace Slic3r::sla
|
||||
|
||||
|
||||
60
src/libslic3r/StreamUtils.hpp
Normal file
60
src/libslic3r/StreamUtils.hpp
Normal file
@@ -0,0 +1,60 @@
|
||||
#ifndef slic3r_StreamUtils_hpp_
|
||||
#define slic3r_StreamUtils_hpp_
|
||||
|
||||
#include "Point.hpp"
|
||||
#include "libslic3r.h"
|
||||
#include "Polygon.hpp"
|
||||
#include "Polyline.hpp"
|
||||
#include "ExPolygon.hpp"
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const Points& pts)
|
||||
{
|
||||
os << "[" << pts.size() << "]:";
|
||||
for (Point p : pts)
|
||||
os << " (" << p << ")";
|
||||
os << "\n";
|
||||
return os;
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const MultiPoint& mpts)
|
||||
{
|
||||
os << "Multipoint" << mpts.points;
|
||||
return os;
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const Polygon& poly)
|
||||
{
|
||||
os << "Polygon" << poly.points;
|
||||
return os;
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const Polygons& polys)
|
||||
{
|
||||
os << "Polygons[" << polys.size() << "]:" << "\n";
|
||||
for (Polygon p : polys)
|
||||
os << " " << p;
|
||||
return os;
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const ExPolygon& epoly)
|
||||
{
|
||||
os << "ExPolygon:\n";
|
||||
os << " contour: " << epoly.contour;
|
||||
os << " holes: " << epoly.holes;
|
||||
return os;
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const ExPolygons& epolys)
|
||||
{
|
||||
os << "ExPolygons[" << epolys.size() << "]:" << "\n";
|
||||
for (ExPolygon p : epolys)
|
||||
os << " " << p;
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
#endif // slic3r_StreamUtils_hpp_
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "Line.hpp"
|
||||
#include "PrintBase.hpp"
|
||||
#include "PrintConfig.hpp"
|
||||
#include "MaterialType.hpp"
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
@@ -64,15 +65,9 @@ struct Params
|
||||
return get_support_spots_adhesion_strength() * 2.0;
|
||||
}
|
||||
|
||||
if (filament_type == "PLA") {
|
||||
return 0.02 * 1e6;
|
||||
} else if (filament_type == "PET" || filament_type == "PETG") {
|
||||
return 0.3 * 1e6;
|
||||
} else if (filament_type == "ABS" || filament_type == "ASA") {
|
||||
return 0.1 * 1e6; //TODO do measurements
|
||||
} else { //PLA default value - defensive approach, PLA has quite low adhesion
|
||||
return 0.02 * 1e6;
|
||||
}
|
||||
double yield_strength = 0.02;
|
||||
MaterialType::get_yield_strength(filament_type, yield_strength);
|
||||
return yield_strength * 1e6;
|
||||
}
|
||||
|
||||
double get_support_spots_adhesion_strength() const {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
#include "libslic3r/MaterialType.hpp"
|
||||
#include "MsgDialog.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include "Plater.hpp"
|
||||
@@ -60,10 +61,29 @@ void ConfigManipulation::check_nozzle_recommended_temperature_range(DynamicPrint
|
||||
int temperature_range_low, temperature_range_high;
|
||||
if (!get_temperature_range(config, temperature_range_low, temperature_range_high)) return;
|
||||
|
||||
// Get the selected filament type
|
||||
std::string filament_type = "";
|
||||
if (config->has("filament_type") && config->option<ConfigOptionStrings>("filament_type")->values.size() > 0) {
|
||||
filament_type = config->option<ConfigOptionStrings>("filament_type")->values[0];
|
||||
}
|
||||
|
||||
int min_recommended_temp = 190;
|
||||
int max_recommended_temp = 300;
|
||||
|
||||
if (!MaterialType::get_temperature_range(filament_type, min_recommended_temp, max_recommended_temp)){
|
||||
filament_type = "Unknown";
|
||||
}
|
||||
|
||||
wxString msg_text;
|
||||
bool need_check = false;
|
||||
if (temperature_range_low < 190 || temperature_range_high > 300) {
|
||||
msg_text += _L("The recommended minimum temperature is less than 190°C or the recommended maximum temperature is greater than 300°C.\n");
|
||||
if (temperature_range_low < min_recommended_temp) {
|
||||
msg_text += wxString::Format(_L("A minimum temperature above %d\u2103 is recommended for %s.\n"),
|
||||
min_recommended_temp, filament_type);
|
||||
need_check = true;
|
||||
}
|
||||
if (temperature_range_high > max_recommended_temp) {
|
||||
msg_text += wxString::Format(_L("A maximum temperature below %d\u2103 is recommended for %s.\n"),
|
||||
max_recommended_temp, filament_type);
|
||||
need_check = true;
|
||||
}
|
||||
if (temperature_range_low > temperature_range_high) {
|
||||
@@ -146,23 +166,14 @@ void ConfigManipulation::check_filament_max_volumetric_speed(DynamicPrintConfig
|
||||
|
||||
void ConfigManipulation::check_chamber_temperature(DynamicPrintConfig* config)
|
||||
{
|
||||
const static std::map<std::string, int>recommend_temp_map = {
|
||||
{"PLA",45},
|
||||
{"PLA-CF",45},
|
||||
{"PVA",45},
|
||||
{"TPU",50},
|
||||
{"PETG",55},
|
||||
{"PCTG",55},
|
||||
{"PETG-CF",55}
|
||||
};
|
||||
bool support_chamber_temp_control=GUI::wxGetApp().preset_bundle->printers.get_selected_preset().config.opt_bool("support_chamber_temp_control");
|
||||
if (support_chamber_temp_control&&config->has("chamber_temperature")) {
|
||||
std::string filament_type = config->option<ConfigOptionStrings>("filament_type")->get_at(0);
|
||||
auto iter = recommend_temp_map.find(filament_type);
|
||||
if (iter!=recommend_temp_map.end()) {
|
||||
if (iter->second < config->option<ConfigOptionInts>("chamber_temperature")->get_at(0)) {
|
||||
int chamber_min_temp, chamber_max_temp;
|
||||
if (MaterialType::get_chamber_temperature_range(filament_type, chamber_min_temp, chamber_max_temp)) {
|
||||
if (chamber_max_temp < config->option<ConfigOptionInts>("chamber_temperature")->get_at(0)) {
|
||||
wxString msg_text = wxString::Format(_L("Current chamber temperature is higher than the material's safe temperature, this may result in material softening and clogging. "
|
||||
"The maximum safe temperature for the material is %d"), iter->second);
|
||||
"The maximum safe temperature for the material is %d"), chamber_max_temp);
|
||||
MessageDialog dialog(m_msg_dlg_parent, msg_text, "", wxICON_WARNING | wxOK);
|
||||
is_msg_dlg_already_exist = true;
|
||||
dialog.ShowModal();
|
||||
|
||||
Reference in New Issue
Block a user