Distance of support point are modified by svg file.

- Support points are stored in separate list(no need to collect from grid + no duplicit support points)
 - Grid contain only indices into result vector of support points
 - Each layer is made update of radiuses for existing support points
 - Each support point knows support radius for current processed layer
 - Layers knows z coordinate soo heights in preparation are copied into layer.
This commit is contained in:
Filip Sykala - NTB T15p 2024-09-17 17:58:41 +02:00 committed by Lukas Matena
parent 3906b7dafc
commit 40d52994db
4 changed files with 586 additions and 116 deletions

View File

@ -0,0 +1,361 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="50mm"
height="50mm"
viewBox="0 0 50 50"
version="1.1"
id="svg3403"
inkscape:version="1.2 (dc2aedaf03, 2022-05-15)"
sodipodi:docname="sla_support.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview3405"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="true"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="false"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
showgrid="false"
showborder="true"
borderlayer="true"
inkscape:zoom="3.3638608"
inkscape:cx="92.601929"
inkscape:cy="110.88449"
inkscape:window-width="1920"
inkscape:window-height="1129"
inkscape:window-x="1912"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs3400">
<marker
style="overflow:visible"
id="Arrow2"
refX="0"
refY="0"
orient="auto-start-reverse"
inkscape:stockid="Arrow2"
markerWidth="7.6999998"
markerHeight="5.5999999"
viewBox="0 0 7.7 5.6"
inkscape:isstock="true"
inkscape:collect="always"
preserveAspectRatio="xMidYMid">
<path
transform="scale(0.7)"
d="M -2,-4 9,0 -2,4 c 2,-2.33 2,-5.66 0,-8 z"
style="fill:context-stroke;fill-rule:evenodd;stroke:none"
id="arrow2L" />
</marker>
<marker
style="overflow:visible"
id="Arrow2-5"
refX="0"
refY="0"
orient="auto-start-reverse"
inkscape:stockid="Arrow2"
markerWidth="7.6999998"
markerHeight="5.5999999"
viewBox="0 0 7.7 5.6"
inkscape:isstock="true"
inkscape:collect="always"
preserveAspectRatio="xMidYMid">
<path
transform="scale(0.7)"
d="M -2,-4 9,0 -2,4 c 2,-2.33 2,-5.66 0,-8 z"
style="fill:context-stroke;fill-rule:evenodd;stroke:none"
id="arrow2L-4" />
</marker>
</defs>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:#cccccc;stroke:#cccccc;stroke-width:2.5;stroke-linejoin:round;stroke-dasharray:none;stop-color:#000000"
d="M 0,11.25 H 46.858514 50"
id="path13101"
sodipodi:nodetypes="ccc" />
<text
xml:space="preserve"
style="font-size:0.25494px;line-height:0;font-family:'Cascadia Code';-inkscape-font-specification:'Cascadia Code';text-align:start;text-decoration-color:#000000;text-anchor:start;fill:#ffffff;stroke:none;stroke-width:0.25;stroke-linejoin:round;stroke-dasharray:none;stop-color:#000000"
x="46.68829"
y="11.313486"
id="text13105"><tspan
sodipodi:role="line"
id="tspan13103"
style="fill:#ffffff;stroke:none;stroke-width:0.25"
x="46.68829"
y="11.313486">201. - 250. layer</tspan></text>
<path
style="fill:#cccccc;stroke:#cccccc;stroke-width:2.5;stroke-linejoin:round;stroke-dasharray:none;stop-color:#000000"
d="M 0,6.25 H 50"
id="path13095" />
<path
style="fill:#cccccc;stroke:#cccccc;stroke-width:0.25;stroke-linejoin:round;stroke-dasharray:none;stop-color:#000000"
d="M 0,1.3745207 H 50"
id="path13003" />
<path
style="fill:#cccccc;stroke:#cccccc;stroke-width:0.25;stroke-linejoin:round;stroke-dasharray:none;stop-color:#000000"
d="M 0,1.875 H 50"
id="path13005" />
<path
style="fill:#cccccc;stroke:#cccccc;stroke-width:0.25;stroke-linejoin:round;stroke-dasharray:none;stop-color:#000000"
d="M 0,2.375 H 50"
id="path13007" />
<path
style="fill:#cccccc;stroke:#cccccc;stroke-width:0.25;stroke-linejoin:round;stroke-dasharray:none;stop-color:#000000"
d="M 0,0.87396551 H 50"
id="path12741" />
<path
style="fill:#cccccc;stroke:#cccccc;stroke-width:0.25;stroke-linejoin:round;stroke-dasharray:none;stop-color:#000000"
d="M 0,0.375 H 50"
id="path12739" />
<path
style="fill:#cccccc;stroke:#cccccc;stroke-width:0.05;stroke-linejoin:round;stroke-dasharray:none;stop-color:#000000"
d="M 0,0.075 H 50"
id="path9670-6" />
<path
style="fill:#cccccc;stroke:#cccccc;stroke-width:0.05;stroke-linejoin:round;stroke-dasharray:none;stop-color:#000000"
d="M 0,0.175 H 50"
id="path12735" />
<path
style="fill:none;stroke:#b50000;stroke-width:0.4;stroke-linejoin:round;stroke-dasharray:none;stop-color:#000000"
d="M 5,0 6,3.8987591 8,15 10,40"
id="path3587"
sodipodi:nodetypes="cccc" />
<text
xml:space="preserve"
style="font-size:1.05833px;line-height:0;font-family:'Cascadia Code';-inkscape-font-specification:'Cascadia Code';text-align:center;text-decoration-color:#000000;text-anchor:middle;fill:#364e59;stroke:none;stroke-width:0.4;stroke-linejoin:round;stroke-dasharray:none;stop-color:#000000"
x="16.386877"
y="-7.5019774"
id="text4929"><tspan
sodipodi:role="line"
id="tspan4927"
style="font-size:1.05833px;fill:#364e59;stroke:none;stroke-width:0.4"
x="16.386877"
y="-7.5019774">island supports</tspan></text>
<text
xml:space="preserve"
style="font-size:2.11667px;line-height:1.3;font-family:'Cascadia Code';-inkscape-font-specification:'Cascadia Code';text-align:center;text-decoration-color:#000000;text-anchor:middle;fill:#364e59;stroke:none;stroke-width:0.4;stroke-linejoin:round;stroke-dasharray:none;stop-color:#000000"
x="24.711193"
y="52.296951"
id="text4985"><tspan
sodipodi:role="line"
id="tspan4983"
style="font-weight:normal;font-size:2.11667px;stroke-width:0.4"
x="24.711193"
y="52.296951">For loading is used only first red curve</tspan><tspan
sodipodi:role="line"
style="font-weight:normal;font-size:2.11667px;stroke-width:0.4"
x="24.711193"
y="55.048622"
id="tspan9281">Use only line segments (no curve)</tspan><tspan
sodipodi:role="line"
style="font-weight:normal;font-size:2.11667px;stroke-width:0.4"
x="24.711193"
y="57.800293"
id="tspan15589">Y coordinate of points must only increase.</tspan><tspan
sodipodi:role="line"
style="font-weight:normal;font-size:2.11667px;stroke-width:0.4"
x="24.711193"
y="60.551964"
id="tspan17460">First point.y must be zero</tspan><tspan
sodipodi:role="line"
style="font-weight:normal;font-size:2.11667px;stroke-width:0.4"
x="24.711193"
y="63.303635"
id="tspan9676" /></text>
<text
xml:space="preserve"
style="font-size:2.11667px;line-height:1.3;font-family:'Cascadia Code';-inkscape-font-specification:'Cascadia Code';text-align:center;text-decoration-color:#000000;text-anchor:middle;fill:#364e59;stroke:none;stroke-width:0.4;stroke-linejoin:round;stroke-dasharray:none;stop-color:#000000"
x="33.019527"
y="-2.8043785"
id="text4985-7"><tspan
sodipodi:role="line"
style="font-weight:bold;font-size:2.11667px;stroke-width:0.4"
x="33.019527"
y="-2.8043785"
id="tspan9281-8">Supported radius[in mm]</tspan></text>
<rect
style="fill:#ba00ff;stroke:none;stroke-width:0.4;stroke-linejoin:round;stroke-dasharray:none;stop-color:#000000"
id="rect6552"
width="0.39999992"
height="1"
x="-0.2"
y="0" />
<text
xml:space="preserve"
style="font-size:1.05833px;line-height:1.2;font-family:'Cascadia Code';-inkscape-font-specification:'Cascadia Code';text-align:center;text-decoration-color:#000000;text-anchor:middle;fill:#ba00ff;stroke:none;stroke-width:0.4;stroke-linejoin:round;stroke-dasharray:none;stop-color:#000000"
x="-0.38932067"
y="-1.6407087"
id="text6608"><tspan
sodipodi:role="line"
style="font-size:1.05833px;text-align:center;text-anchor:middle;stroke-width:0.4"
x="-0.38932067"
y="-1.6407087"
id="tspan7386">Head</tspan><tspan
sodipodi:role="line"
style="font-size:1.05833px;text-align:center;text-anchor:middle;stroke-width:0.4"
x="-0.38932067"
y="-0.3707087"
id="tspan7390">interface</tspan></text>
<path
style="fill:#ba00ff;stroke:#364e59;stroke-width:0.1;stroke-linejoin:round;stroke-dasharray:none;marker-end:url(#Arrow2);stop-color:#000000"
d="M 13.379759,-7.2418186 10.65352,-0.96342022"
id="path7457"
sodipodi:nodetypes="cc" />
<text
xml:space="preserve"
style="font-size:1.67576px;line-height:0;font-family:'Cascadia Code';-inkscape-font-specification:'Cascadia Code';text-align:center;text-decoration-color:#000000;text-anchor:middle;fill:#364e59;stroke:none;stroke-width:0.1;stroke-linejoin:round;stroke-dasharray:none;stop-color:#000000"
x="15.351564"
y="55.742996"
id="text9279"><tspan
sodipodi:role="line"
id="tspan9277"
style="fill:#364e59;stroke:none;stroke-width:0.1"
x="15.351564"
y="55.742996" /></text>
<path
style="fill:#364e59;stroke:#364e59;stroke-width:0.4;stroke-linejoin:round;stroke-dasharray:none;stop-color:#000000;marker-end:url(#Arrow2)"
d="M 29.365905,-1.4460483 H 48.609472"
id="path9401" />
<text
xml:space="preserve"
style="font-size:2.06203px;line-height:1.3;font-family:'Cascadia Code';-inkscape-font-specification:'Cascadia Code';text-align:center;text-decoration-color:#000000;text-anchor:middle;fill:#364e59;stroke:none;stroke-width:0.4;stroke-linejoin:round;stroke-dasharray:none;stop-color:#000000"
x="-8.5609999"
y="41.920982"
id="text4985-7-3"><tspan
sodipodi:role="line"
style="font-weight:bold;font-size:2.11667px;stroke-width:0.4"
x="-8.5609999"
y="41.920982"
id="tspan9281-8-8">z [in mm]</tspan><tspan
sodipodi:role="line"
style="font-weight:normal;font-size:1.05833px;stroke-width:0.4"
x="-8.5609999"
y="44.620838"
id="tspan9668"
dy="-1.0011104">Print Direction</tspan></text>
<path
style="fill:#364e59;stroke:#364e59;stroke-width:0.4;stroke-linejoin:round;stroke-dasharray:none;marker-end:url(#Arrow2-5);stop-color:#000000"
d="M -2.7788881,27.725679 V 46.969247"
id="path9401-5" />
<path
style="fill:#364e59;stroke:#364e59;stroke-width:0.1;stroke-linejoin:round;stroke-dasharray:none;stop-color:#000000"
d="m 10.778332,39.821948 48.064712,0"
id="path9670"
sodipodi:nodetypes="cc" />
<text
xml:space="preserve"
style="font-size:1.05833px;line-height:1.3;font-family:'Cascadia Code';-inkscape-font-specification:'Cascadia Code';text-align:start;text-decoration-color:#000000;text-anchor:start;fill:#364e59;stroke:#364e59;stroke-width:0.1;stroke-linejoin:round;stroke-dasharray:none;stop-color:#000000"
x="50.865135"
y="39.457973"
id="text9674"><tspan
sodipodi:role="line"
id="tspan9672"
style="font-weight:normal;font-size:1.05833px;stroke:none;stroke-width:0.1;text-anchor:start;text-align:start"
x="59.791695"
y="39.457973">Last curve point</tspan><tspan
sodipodi:role="line"
style="font-weight:normal;font-size:1.05833px;stroke:none;stroke-width:0.1;text-anchor:start;text-align:start"
x="59.791695"
y="40.833801"
id="tspan9678">define stability requirements</tspan></text>
<text
xml:space="preserve"
style="font-size:0.25494px;line-height:0;font-family:'Cascadia Code';-inkscape-font-specification:'Cascadia Code';text-align:start;text-decoration-color:#000000;text-anchor:start;fill:#ffffff;stroke:none;stroke-width:0.25;stroke-linejoin:round;stroke-dasharray:none;stop-color:#000000"
x="47.136429"
y="0.44968146"
id="text12797"><tspan
sodipodi:role="line"
id="tspan12795"
style="fill:#ffffff;stroke:none;stroke-width:0.25"
x="47.136429"
y="0.44968146">6. - 10. layer</tspan></text>
<text
xml:space="preserve"
style="font-size:1.05833px;line-height:0;font-family:'Cascadia Code';-inkscape-font-specification:'Cascadia Code';text-align:start;text-decoration-color:#000000;text-anchor:start;fill:#ffffff;stroke:none;stroke-width:0.25;stroke-linejoin:round;stroke-dasharray:none;stop-color:#000000"
x="50.574947"
y="0.98318326"
id="text13011"><tspan
sodipodi:role="line"
style="stroke-width:0.25"
x="50.574947"
y="0.98318326"
id="tspan13013">Guid for layers height 0.05mm</tspan></text>
<text
xml:space="preserve"
style="font-size:0.25494px;line-height:0;font-family:'Cascadia Code';-inkscape-font-specification:'Cascadia Code';text-align:start;text-decoration-color:#000000;text-anchor:start;fill:#ffffff;stroke:none;stroke-width:0.25;stroke-linejoin:round;stroke-dasharray:none;stop-color:#000000"
x="46.987049"
y="0.9476288"
id="text13029"><tspan
sodipodi:role="line"
id="tspan13027"
style="fill:#ffffff;stroke:none;stroke-width:0.25"
x="46.987049"
y="0.9476288">16. - 20. layer</tspan></text>
<text
xml:space="preserve"
style="font-size:0.25494px;line-height:0;font-family:'Cascadia Code';-inkscape-font-specification:'Cascadia Code';text-align:start;text-decoration-color:#000000;text-anchor:start;fill:#ffffff;stroke:none;stroke-width:0.25;stroke-linejoin:round;stroke-dasharray:none;stop-color:#000000"
x="46.987049"
y="1.448184"
id="text13033"><tspan
sodipodi:role="line"
id="tspan13031"
style="fill:#ffffff;stroke:none;stroke-width:0.25"
x="46.987049"
y="1.448184">26. - 30. layer</tspan></text>
<text
xml:space="preserve"
style="font-size:0.25494px;line-height:0;font-family:'Cascadia Code';-inkscape-font-specification:'Cascadia Code';text-align:start;text-decoration-color:#000000;text-anchor:start;fill:#ffffff;stroke:none;stroke-width:0.25;stroke-linejoin:round;stroke-dasharray:none;stop-color:#000000"
x="46.987049"
y="1.941787"
id="text13037"><tspan
sodipodi:role="line"
id="tspan13035"
style="fill:#ffffff;stroke:none;stroke-width:0.25"
x="46.987049"
y="1.941787">36. - 40. layer</tspan></text>
<text
xml:space="preserve"
style="font-size:0.25494px;line-height:0;font-family:'Cascadia Code';-inkscape-font-specification:'Cascadia Code';text-align:start;text-decoration-color:#000000;text-anchor:start;fill:#ffffff;stroke:none;stroke-width:0.25;stroke-linejoin:round;stroke-dasharray:none;stop-color:#000000"
x="46.987049"
y="2.4423423"
id="text13041"><tspan
sodipodi:role="line"
id="tspan13039"
style="fill:#ffffff;stroke:none;stroke-width:0.25"
x="46.987049"
y="2.4423423">46. - 50. layer</tspan></text>
<text
xml:space="preserve"
style="font-size:0.25494px;line-height:0;font-family:'Cascadia Code';-inkscape-font-specification:'Cascadia Code';text-align:start;text-decoration-color:#000000;text-anchor:start;fill:#ffffff;stroke:none;stroke-width:0.25;stroke-linejoin:round;stroke-dasharray:none;stop-color:#000000"
x="46.68829"
y="6.3134861"
id="text13099"><tspan
sodipodi:role="line"
id="tspan13097"
style="fill:#ffffff;stroke:none;stroke-width:0.25"
x="46.68829"
y="6.3134861">101. - 150. layer</tspan></text>
<text
xml:space="preserve"
style="font-size:1.05833px;line-height:0;font-family:'Cascadia Code';-inkscape-font-specification:'Cascadia Code';text-align:start;text-decoration-color:#000000;text-anchor:start;fill:#ffffff;stroke:none;stroke-width:2.5;stroke-linejoin:round;stroke-dasharray:none;stop-color:#000000"
x="14.708422"
y="-6.6856461"
id="text17458"><tspan
sodipodi:role="line"
id="tspan17456"
style="stroke-width:2.5"></tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -22,21 +22,24 @@ class Grid2D
coord_t m_cell_size; // Squar: x and y are same
coord_t m_cell_size_half;
using Key = Point;
using Key = Point; // scaled point
using Value = size_t; // index into m_supports_ptr
struct GridHash{std::size_t operator()(const Key &cell_id) const {
return std::hash<int>()(cell_id.x()) ^ std::hash<int>()(cell_id.y() * 593);
}};
using Grid = std::unordered_multimap<Key, LayerSupportPoint, GridHash>;
using Grid = std::unordered_multimap<Key, Value, GridHash>;
Grid m_grid;
// multiple grids points into same data storage of support points
LayerSupportPoints *m_supports_ptr;
public:
/// <summary>
/// Set cell size for grid
/// </summary>
/// <param name="cell_size">Granularity of stored points
/// Must be bigger than maximal used radius</param>
explicit Grid2D(const coord_t &cell_size)
: m_cell_size(cell_size), m_cell_size_half(cell_size / 2) {}
/// <param name="supports_ptr">Pointer on Support vector</param>
explicit Grid2D(const coord_t &cell_size, LayerSupportPoints* supports_ptr)
: m_cell_size(cell_size), m_cell_size_half(cell_size / 2), m_supports_ptr(supports_ptr) {}
Key cell_id(const Point &point) const {
Key::coord_type x = point.x() / m_cell_size;
@ -48,11 +51,19 @@ public:
}
void add(LayerSupportPoint &&point) {
m_grid.emplace(cell_id(point.position_on_layer), std::move(point));
size_t index = m_supports_ptr->size();
m_supports_ptr->emplace_back(std::move(point));
m_grid.emplace(cell_id(point.position_on_layer), index);
}
using CheckFnc = std::function<bool(const LayerSupportPoint &, const Point&)>;
bool exist_true_in_4cell_neighbor(const Point &pos, const CheckFnc& fnc) const {
// TODO: remove - test all support points without grid speed up
for (const auto &[key, value]: m_grid)
if(fnc(m_supports_ptr->at(value), pos))
return true;
return false;
Key key = cell_id(pos);
if (exist_true_for_cell(key, pos, fnc)) return true;
Point un_cell_pos(
@ -72,19 +83,11 @@ public:
assert(m_cell_size == grid.m_cell_size);
m_grid.merge(std::move(grid.m_grid));
}
LayerSupportPoints get_points() const {
LayerSupportPoints result;
result.reserve(m_grid.size());
for (const auto& [key, support] : m_grid)
result.push_back(support);
return result;
}
private:
bool exist_true_for_cell(const Key &key, const Point &pos, const CheckFnc& fnc) const{
auto [begin_it, end_it] = m_grid.equal_range(key);
for (Grid::const_iterator it = begin_it; it != end_it; ++it) {
const LayerSupportPoint &support_point = it->second;
const LayerSupportPoint &support_point = m_supports_ptr->at(it->second);
if (fnc(support_point, pos))
return true;
}
@ -135,34 +138,25 @@ Point intersection(const Point &p1, const Point &p2, const Point &cnt, double r2
return {};
}
coord_t get_supported_radius(const LayerSupportPoint &p, float z_distance, const SupportPointGeneratorConfig &config
) {
// TODO: calculate support radius
return scale_(5.);
}
void sample_part(
/// <summary>
/// Move grid from previous layer to current one
/// for given part
/// </summary>
/// <param name="prev_layer_parts">Grids generated in previous layer</param>
/// <param name="part">Current layer part to process</param>
/// <param name="prev_grids">Grids which will be moved to current grid</param>
/// <returns>Grid for given part</returns>
Grid2D create_part_grid(
const LayerParts &prev_layer_parts,
const LayerPart &part,
size_t layer_id,
const SupportPointGeneratorData &data,
const SupportPointGeneratorConfig &config,
std::vector<Grid2D> &grids,
std::vector<Grid2D> &prev_grids
) {
// NOTE: first layer do not have prev part
assert(layer_id != 0);
const Layers &layers = data.layers;
const LayerParts &prev_layer_parts = layers[layer_id - 1].parts;
const LayerParts::const_iterator &prev_part_it = part.prev_parts.front().part_it;
size_t index_of_prev_part = prev_part_it - prev_layer_parts.begin();
if (prev_part_it->next_parts.size() == 1) {
grids.push_back(std::move(prev_grids[index_of_prev_part]));
} else { // Need a copy there are multiple parts above previus one
grids.push_back(prev_grids[index_of_prev_part]); // copy
}
// current part grid
Grid2D &part_grid = grids.back();
Grid2D part_grid = (prev_part_it->next_parts.size() == 1)?
std::move(prev_grids[index_of_prev_part]) :
// Need a copy there are multiple parts above previus one
prev_grids[index_of_prev_part]; // copy
// merge other grid in case of multiple previous parts
for (size_t i = 1; i < part.prev_parts.size(); ++i) {
@ -175,16 +169,32 @@ void sample_part(
part_grid.merge(std::move(grid_));
}
}
return part_grid;
}
float part_z = data.heights[layer_id];
Grid2D::CheckFnc is_supported = [part_z, &config]
/// <summary>
/// Add support point to part_grid when it is neccessary
/// </summary>
/// <param name="part">Current part - keep samples</param>
/// <param name="config">Configuration to sample</param>
/// <param name="part_grid">Keep previous sampled suppport points</param>
/// <param name="part_z">current z coordinate of part</param>
void support_part_overhangs(
const LayerPart &part,
const SupportPointGeneratorConfig &config,
Grid2D &part_grid,
float part_z
) {
Grid2D::CheckFnc is_supported = []
(const LayerSupportPoint &support_point, const Point &p) -> bool {
float diff_height = part_z - support_point.pos.z();
coord_t r_ = get_supported_radius(support_point, diff_height, config);
// Debug visualization of all sampled outline
//return false;
coord_t r = support_point.current_radius;
Point dp = support_point.position_on_layer - p;
if (std::abs(dp.x()) > r_) return false;
if (std::abs(dp.y()) > r_) return false;
double r2 = static_cast<double>(r_);
if (std::abs(dp.x()) > r) return false;
if (std::abs(dp.y()) > r) return false;
double r2 = static_cast<double>(r);
r2 *= r2;
return dp.cast<double>().squaredNorm() < r2;
};
@ -201,7 +211,9 @@ void sample_part(
SupportPointType::slope
},
/* position_on_layer */ p,
/* direction_to_mass */ Point(1,0)
/* direction_to_mass */ Point(1,0), // TODO: change direction
/* radius_curve_index */ 0,
/* current_radius */ static_cast<coord_t>(scale_(config.support_curve.front().x()))
});
}
}
@ -212,14 +224,16 @@ Points uniformly_sample(const ExPolygon &island, const SupportPointGeneratorConf
return Points{island.contour.centroid()};
}
Grid2D support_island(const LayerPart &part, float part_z, const SupportPointGeneratorConfig &cfg) {
// Maximal radius of supported area of one support point
double max_support_radius = 10.; // cfg.cell_size;
// maximal radius of support
coord_t cell_size = scale_(max_support_radius);
Grid2D part_grid(cell_size);
/// <summary>
/// Sample part as Island
/// Result store to grid
/// </summary>
/// <param name="part">Island to support</param>
/// <param name="part_grid">OUT place to store new supports</param>
/// <param name="part_z">z coordinate of part</param>
/// <param name="cfg"></param>
void support_island(const LayerPart &part, Grid2D& part_grid, float part_z,
const SupportPointGeneratorConfig &cfg) {
Points pts = uniformly_sample(*part.shape, cfg);
for (const Point &pt : pts)
part_grid.add(LayerSupportPoint{
@ -229,9 +243,10 @@ Grid2D support_island(const LayerPart &part, float part_z, const SupportPointGen
SupportPointType::island
},
/* position_on_layer */ pt,
/* direction_to_mass */ Point(0,0) // direction from bottom
/* direction_to_mass */ Point(0,0), // direction from bottom
/* radius_curve_index */ 0,
/* current_radius */ static_cast<coord_t>(scale_(cfg.support_curve.front().x()))
});
return part_grid;
}
/// <summary>
@ -274,18 +289,19 @@ Slic3r::Points sample(Points::const_iterator b, Points::const_iterator e, double
Slic3r::Points r;
r.push_back(*b);
Points::const_iterator prev_pt = e;
//Points::const_iterator prev_pt = e;
const Point *prev_pt = nullptr;
for (Points::const_iterator it = b; it+1 < e; ++it){
const Point &pt = *(it+1);
double p_dist2 = (r.back() - pt).cast<double>().squaredNorm();
while (p_dist2 > dist2) { // line segment goes out of radius
if (prev_pt == e)
prev_pt = it;
if (prev_pt == nullptr)
prev_pt = &(*it);
r.push_back(intersection(*prev_pt, pt, r.back(), dist2));
p_dist2 = (r.back() - pt).cast<double>().squaredNorm();
prev_pt = r.end()-1; // r.back()
prev_pt = &r.back();
}
prev_pt = e;
prev_pt = nullptr;
}
return r;
}
@ -382,13 +398,43 @@ Points sample_overhangs(const LayerPart& part, double dist2) {
return samples;
}
void prepare_supports_for_layer(LayerSupportPoints &supports, float layer_z,
const SupportPointGeneratorConfig &config) {
const std::vector<Vec2f>& curve = config.support_curve;
// calculate support area for each support point as radius
// IMPROVE: use some offsets of previous supported island
for (LayerSupportPoint &support : supports) {
size_t &index = support.radius_curve_index;
if (index + 1 >= curve.size())
continue; // already contain maximal radius
// find current segment
float diff_z = layer_z - support.pos.z();
while ((index + 1) < curve.size() && diff_z > curve[index + 1].y())
++index;
if ((index+1) >= curve.size()) {
// set maximal radius
support.current_radius = static_cast<coord_t>(scale_(curve.back().x()));
continue;
}
// interpolate radius on input curve
Vec2f a = curve[index];
Vec2f b = curve[index+1];
assert(a.y() <= diff_z && diff_z <= b.y());
float t = (diff_z - a.y()) / (b.y() - a.y());
assert(0 <= t && t <= 1);
support.current_radius = static_cast<coord_t>(scale_(a.x() + t * (b.x() - a.x())));
}
}
} // namespace
#include "libslic3r/Execution/ExecutionSeq.hpp"
SupportPointGeneratorData Slic3r::sla::prepare_generator_data(
std::vector<ExPolygons> &&slices,
std::vector<float> &&heights,
const std::vector<float> &heights,
ThrowOnCancel throw_on_cancel,
StatusFunction statusfn
) {
@ -401,20 +447,20 @@ SupportPointGeneratorData Slic3r::sla::prepare_generator_data(
// Move input into result
SupportPointGeneratorData result;
result.slices = std::move(slices);
result.heights = std::move(heights);
// Allocate empty layers.
result.layers = Layers(result.slices.size(), {});
// Generate Extents and SampleLayers
execution::for_each(ex_tbb, size_t(0), result.slices.size(),
[&result, throw_on_cancel](size_t layer_id) {
[&result, &heights, throw_on_cancel](size_t layer_id) {
if ((layer_id % 8) == 0)
// Don't call the following function too often as it flushes
// CPU write caches due to synchronization primitves.
throw_on_cancel();
Layer &layer = result.layers[layer_id];
layer.print_z = heights[layer_id]; // copy
const ExPolygons &islands = result.slices[layer_id];
layer.parts.reserve(islands.size());
for (const ExPolygon &island : islands) {
@ -467,6 +513,42 @@ SupportPointGeneratorData Slic3r::sla::prepare_generator_data(
return result;
}
#include "libslic3r/NSVGUtils.hpp"
#include "libslic3r/Utils.hpp"
std::vector<Vec2f> load_curve_from_file() {
std::string filePath = Slic3r::resources_dir() + "/data/sla_support.svg";
EmbossShape::SvgFile svg_file{filePath};
NSVGimage *image = init_image(svg_file);
for (NSVGshape *shape_ptr = image->shapes; shape_ptr != NULL; shape_ptr = shape_ptr->next) {
const NSVGshape &shape = *shape_ptr;
if (!(shape.flags & NSVG_FLAGS_VISIBLE)) continue; // is visible
if (shape.fill.type != NSVG_PAINT_NONE) continue; // is not used fill
if (shape.stroke.type == NSVG_PAINT_NONE) continue; // exist stroke
if (shape.strokeWidth < 1e-5f) continue; // is visible stroke width
if (shape.stroke.color != 4278190261) continue; // is red
// use only first path
const NSVGpath *path = shape.paths;
size_t count_points = path->npts;
assert(count_points > 1);
--count_points;
std::vector<Vec2f> points;
points.reserve(count_points/3+1);
points.push_back({path->pts[0], path->pts[1]});
for (size_t i = 0; i < count_points; i += 3) {
const float *p = &path->pts[i * 2];
points.push_back({p[6], p[7]});
}
assert(points.size() >= 2);
return points;
}
// red curve line is not found
assert(false);
return {};
}
LayerSupportPoints Slic3r::sla::generate_support_points(
const SupportPointGeneratorData &data,
const SupportPointGeneratorConfig &config,
@ -478,30 +560,41 @@ LayerSupportPoints Slic3r::sla::generate_support_points(
double status = 0; // current progress
int status_int = 0;
// Hack to set curve for testing
if (config.support_curve.empty())
const_cast<SupportPointGeneratorConfig &>(config).support_curve = load_curve_from_file();
// Maximal radius of supported area of one support point
double max_support_radius = config.support_curve.back().x(); // cfg.cell_size;
// maximal radius of support
coord_t cell_size = scale_(2*max_support_radius);
// Storage for support points used by grid
LayerSupportPoints result;
// grid index == part in layer index
std::vector<Grid2D> prev_grids; // same count as previous layer item size
for (size_t layer_id = 0; layer_id < layers.size(); ++layer_id) {
const Layer &layer = layers[layer_id];
prepare_supports_for_layer(result, layer.print_z, config);
// grid index == part in layer index
std::vector<Grid2D> grids;
grids.reserve(layer.parts.size());
for (const LayerPart &part : layer.parts) {
if (part.prev_parts.empty()) {
// only island add new grid
grids.emplace_back(cell_size, &result);
// new island - needs support no doubt
float part_z = data.heights[layer_id];
grids.push_back(support_island(part, part_z, config));
support_island(part, grids.back(), layer.print_z, config);
} else {
sample_part(part, layer_id, data, config, grids, prev_grids);
}
// collect result from grid of top part
if (part.next_parts.empty()) {
const Grid2D &part_grid = grids.back();
LayerSupportPoints sps = part_grid.get_points();
result.insert(result.end(),
std::make_move_iterator(sps.begin()),
std::make_move_iterator(sps.end()));
// first layer should have empty prev_part
assert(layer_id != 0);
const LayerParts &prev_layer_parts = layers[layer_id - 1].parts;
grids.push_back(create_part_grid(prev_layer_parts, part, prev_grids));
support_part_overhangs(part, config, grids.back(), layer.print_z);
}
}
prev_grids = std::move(grids);

View File

@ -40,6 +40,12 @@ struct SupportPointGeneratorConfig{
// Minimal island Area to print - TODO: Should be modifiable from UI
// !! Filter should be out of sampling algorithm !!
float minimal_island_area = pow(0.047f, 2.f); // [in mm^2] pixel_area
// maximal distance to nearest support point(define radiuses per layer)
// x axis .. mean distance on layer(XY)
// y axis .. mean difference of height(Z)
// Points of lines [in mm]
std::vector<Vec2f> support_curve;
};
struct LayerPart; // forward decl.
@ -93,6 +99,15 @@ struct LayerSupportPoint: public SupportPoint
// used as ray to positioning 3d point on mesh surface
// Island has direction [0,0] - should be placed on surface from bottom
Point direction_to_mass;
// index into curve to faster found radius for current layer
size_t radius_curve_index = 0;
coord_t current_radius = 0; // [in scaled mm]
// information whether support point is active in current investigated layer
// Flagged false when no part on layer in Radius 'r' around support point
// Tool to support overlapped overhang area multiple times
bool active_in_part = true;
};
using LayerSupportPoints = std::vector<LayerSupportPoint>;
@ -106,8 +121,7 @@ struct Layer
size_t layer_id;
// Absolute distance from Zero - copy value from heights<float>
// [[deprecated]] Use index to layers insted of adress from item
double print_z; // [in mm]
float print_z; // [in mm]
// data for one expolygon
LayerParts parts;
@ -122,10 +136,10 @@ struct SupportPointGeneratorData
{
// Input slices of mesh
std::vector<ExPolygons> slices;
// Same size as slices
std::vector<float> heights;
// link to slices
// Keep information about layer and its height
// and connection between layers for its part
// NOTE: contain links into slices
Layers layers;
};
@ -147,7 +161,7 @@ using StatusFunction= std::function<void(int)>;
/// <returns>Data prepared for generate support points</returns>
SupportPointGeneratorData prepare_generator_data(
std::vector<ExPolygons> &&slices,
std::vector<float> &&heights,
const std::vector<float> &heights,
ThrowOnCancel throw_on_cancel,
StatusFunction statusfn
);

View File

@ -678,45 +678,47 @@ RENDER_AGAIN:
else { // not in editing mode:
m_imgui->disabled_begin(!is_input_enabled());
ImGui::AlignTextToFramePadding();
ImGuiPureWrap::text(m_desc.at("minimal_distance"));
ImGui::SameLine(settings_sliders_left);
ImGui::PushItemWidth(window_width - settings_sliders_left);
ImGui::Text("Distribution depends on './resources/data/sla_support.svg'\ninstruction for edit are in file");
std::vector<const ConfigOption*> opts = get_config_options({"support_points_density_relative", "support_points_minimal_distance"});
float density = static_cast<const ConfigOptionInt*>(opts[0])->value;
float minimal_point_distance = static_cast<const ConfigOptionFloat*>(opts[1])->value;
//ImGui::AlignTextToFramePadding();
//ImGuiPureWrap::text(m_desc.at("minimal_distance"));
//ImGui::SameLine(settings_sliders_left);
//ImGui::PushItemWidth(window_width - settings_sliders_left);
m_imgui->slider_float("##minimal_point_distance", &minimal_point_distance, 0.f, 20.f, "%.f mm");
bool slider_clicked = m_imgui->get_last_slider_status().clicked; // someone clicked the slider
bool slider_edited = m_imgui->get_last_slider_status().edited; // someone is dragging the slider
bool slider_released = m_imgui->get_last_slider_status().deactivated_after_edit; // someone has just released the slider
//std::vector<const ConfigOption*> opts = get_config_options({"support_points_density_relative", "support_points_minimal_distance"});
//float density = static_cast<const ConfigOptionInt*>(opts[0])->value;
//float minimal_point_distance = static_cast<const ConfigOptionFloat*>(opts[1])->value;
ImGui::AlignTextToFramePadding();
ImGuiPureWrap::text(m_desc.at("points_density"));
ImGui::SameLine(settings_sliders_left);
//m_imgui->slider_float("##minimal_point_distance", &minimal_point_distance, 0.f, 20.f, "%.f mm");
//bool slider_clicked = m_imgui->get_last_slider_status().clicked; // someone clicked the slider
//bool slider_edited = m_imgui->get_last_slider_status().edited; // someone is dragging the slider
//bool slider_released = m_imgui->get_last_slider_status().deactivated_after_edit; // someone has just released the slider
m_imgui->slider_float("##points_density", &density, 0.f, 200.f, "%.f %%");
slider_clicked |= m_imgui->get_last_slider_status().clicked;
slider_edited |= m_imgui->get_last_slider_status().edited;
slider_released |= m_imgui->get_last_slider_status().deactivated_after_edit;
//ImGui::AlignTextToFramePadding();
//ImGuiPureWrap::text(m_desc.at("points_density"));
//ImGui::SameLine(settings_sliders_left);
if (slider_clicked) { // stash the values of the settings so we know what to revert to after undo
m_minimal_point_distance_stash = minimal_point_distance;
m_density_stash = density;
}
if (slider_edited) {
mo->config.set("support_points_minimal_distance", minimal_point_distance);
mo->config.set("support_points_density_relative", (int)density);
}
if (slider_released) {
mo->config.set("support_points_minimal_distance", m_minimal_point_distance_stash);
mo->config.set("support_points_density_relative", (int)m_density_stash);
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Support parameter change"));
mo->config.set("support_points_minimal_distance", minimal_point_distance);
mo->config.set("support_points_density_relative", (int)density);
wxGetApp().obj_list()->update_and_show_object_settings_item();
}
//m_imgui->slider_float("##points_density", &density, 0.f, 200.f, "%.f %%");
//slider_clicked |= m_imgui->get_last_slider_status().clicked;
//slider_edited |= m_imgui->get_last_slider_status().edited;
//slider_released |= m_imgui->get_last_slider_status().deactivated_after_edit;
//if (slider_clicked) { // stash the values of the settings so we know what to revert to after undo
// m_minimal_point_distance_stash = minimal_point_distance;
// m_density_stash = density;
//}
//if (slider_edited) {
// mo->config.set("support_points_minimal_distance", minimal_point_distance);
// mo->config.set("support_points_density_relative", (int)density);
//}
//if (slider_released) {
// mo->config.set("support_points_minimal_distance", m_minimal_point_distance_stash);
// mo->config.set("support_points_density_relative", (int)m_density_stash);
// Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Support parameter change"));
// mo->config.set("support_points_minimal_distance", minimal_point_distance);
// mo->config.set("support_points_density_relative", (int)density);
// wxGetApp().obj_list()->update_and_show_object_settings_item();
//}
bool generate = ImGuiPureWrap::button(m_desc.at("auto_generate"));