OrcaSlicer latest
OrcaSlicer
Loading...
Searching...
No Matches
Slic3r::SeamContour::Resolver Class Reference

#include </home/runner/work/OrcaSlicer/OrcaSlicer/src/libslic3r/GCode/SeamContour.hpp>

Collaboration diagram for Slic3r::SeamContour::Resolver:

Public Member Functions

 Resolver (Layers layers, Options options={}, std::function< void()> throw_if_canceled={})
Result resolve (size_t layer, size_t contour, size_t vertex, int direction, double radius=-1.0) const

Private Types

using Key = std::tuple<size_t, size_t, size_t, int, double>

Private Member Functions

std::vector< size_t > query (size_t layer, const Vec2d &point, double reach) const
bool in_material (size_t layer, const Vec2d &point) const
bool near_boundary (size_t layer, const Vec2d &point, double noise) const
Result select (size_t layer, size_t contour, const Vec2d &point, int direction, double radius, bool check_reverse) const

Private Attributes

Layers m_layers
std::vector< AABBTreeIndirect::Tree2d > m_indices
Options m_options
std::map< Key, Result > m_cache

Detailed Description

Member Typedef Documentation

◆ Key

using Slic3r::SeamContour::Resolver::Key = std::tuple<size_t, size_t, size_t, int, double>
private

Constructor & Destructor Documentation

◆ Resolver()

Slic3r::SeamContour::Resolver::Resolver ( Layers layers,
Options options = {},
std::function< void()> throw_if_canceled = {} )
explicit
117 :
118 m_layers(std::move(layers)), m_options(options) {
119 m_indices.resize(m_layers.size());
120 for (size_t i = 0; i < m_layers.size(); ++i) {
121 if (throw_if_canceled) throw_if_canceled(); // Index construction on dense objects remains cancellable.
122 std::vector<BoxEntry> boxes;
123 for (size_t j = 0; j < m_layers[i].size(); ++j) {
124 Contour &c = m_layers[i][j];
125 c.min = Vec2d::Constant(std::numeric_limits<double>::infinity());
126 c.max = -c.min;
127 for (const Vec2d &p : c.points) { c.min = c.min.cwiseMin(p); c.max = c.max.cwiseMax(p); }
128 if (!c.points.empty()) boxes.push_back({j, AABBTreeIndirect::Tree2d::BoundingBox(c.min, c.max)});
129 }
130 // Build once per layer; all seeds, reverse matches and material probes reuse the boxes.
131 m_indices[i].build(std::move(boxes));
132 }
133}
Eigen::AlignedBox< CoordType, NumDimensions > BoundingBox
Definition AABBTreeIndirect.hpp:50
Options m_options
Definition SeamContour.hpp:52
std::vector< AABBTreeIndirect::Tree2d > m_indices
Definition SeamContour.hpp:51
Layers m_layers
Definition SeamContour.hpp:50
Eigen::Matrix< double, 2, 1, Eigen::DontAlign > Vec2d
Definition Point.hpp:67

References m_indices, m_layers, m_options, Slic3r::SeamContour::Contour::max, Slic3r::SeamContour::Contour::min, and Slic3r::SeamContour::Contour::points.

Member Function Documentation

◆ in_material()

bool Slic3r::SeamContour::Resolver::in_material ( size_t layer,
const Vec2d & point ) const
private
93 {
94 bool inside = false;
95 for (size_t index : query(layer, p, 0.0)) {
96 const Contour &c = m_layers[layer][index];
97 if (!c.reliable) continue; // select() already falls back wherever unknown geometry can affect a probe.
98 if ((p.array() < c.min.array()).any() || (p.array() > c.max.array()).any()) continue;
99 for (size_t i = 0; i < c.points.size(); ++i) {
100 const Vec2d &a = c.points[i], &b = c.points[(i + 1) % c.points.size()];
101 if ((a.y() > p.y()) != (b.y() > p.y()) &&
102 p.x() < a.x() + (p.y() - a.y()) * (b.x() - a.x()) / (b.y() - a.y()))
103 inside = !inside;
104 }
105 }
106 return inside;
107}
std::vector< size_t > query(size_t layer, const Vec2d &point, double reach) const
Definition SeamContour.cpp:82
bool inside(const Polygons &polygons, const Point &p)
Definition TreeNode.cpp:160

References m_layers, Slic3r::SeamContour::Contour::max, Slic3r::SeamContour::Contour::min, Slic3r::SeamContour::Contour::points, query(), and Slic3r::SeamContour::Contour::reliable.

Referenced by select().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ near_boundary()

bool Slic3r::SeamContour::Resolver::near_boundary ( size_t layer,
const Vec2d & point,
double noise ) const
private
109 {
110 for (size_t index : query(layer, p, noise)) {
111 const Contour &c = m_layers[layer][index];
112 if (box_distance(c, p) <= noise && closest(c, p, noise).distance <= noise) return true;
113 }
114 return false;
115}
Foot closest(const Contour &c, const Vec2d &p, double stop=-1.0, const std::vector< Vec2d > *source_normals=nullptr, double normal_cosine=0.0)
Definition SeamContour.cpp:36
double box_distance(const Contour &c, const Vec2d &p)
Definition SeamContour.cpp:32

References m_layers, and query().

Referenced by select().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ query()

std::vector< size_t > Slic3r::SeamContour::Resolver::query ( size_t layer,
const Vec2d & point,
double reach ) const
private
82 {
83 std::vector<size_t> result;
84 const Vec2d margin = Vec2d::Constant(reach);
87 [&](const auto &node) { result.push_back(node.idx); return true; });
88 // Tree traversal order must not alter tie-breaking in the existing contour predicates.
89 std::sort(result.begin(), result.end());
90 return result;
91}
auto intersecting(const G &g)
Definition AABBTreeIndirect.hpp:925
void traverse(const Tree< Dims, T > &tree, Predicate &&pred, Fn &&callback)
Definition AABBTreeIndirect.hpp:986

References Slic3r::AABBTreeIndirect::intersecting(), m_indices, and Slic3r::AABBTreeIndirect::traverse().

Referenced by in_material(), near_boundary(), and select().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ resolve()

Result Slic3r::SeamContour::Resolver::resolve ( size_t layer,
size_t contour,
size_t vertex,
int direction,
double radius = -1.0 ) const
241 {
242 Result result;
243 if (direction != -1 && direction != 1) return result;
244 const Contour &source = m_layers.at(layer).at(contour);
245 if (!source.reliable) return {Outcome::None, Method::Local, {}, true};
246 if (radius < 0.0) radius = source.width * m_options.radius_width_factor;
247 if (!std::isfinite(radius)) return result;
248 // Alternative seeds may have different widths; their actual KD search radii cannot share a cache entry.
249 const Key key(layer, contour, vertex, direction, radius);
250 const auto cached = m_cache.find(key);
251 if (cached != m_cache.end()) return cached->second;
252 const ptrdiff_t target = ptrdiff_t(layer) + direction;
253 if (target >= 0 && size_t(target) < m_layers.size() && source.points.size() >= 3) {
254 const Vec2d &p = source.points.at(vertex);
255 result = select(layer, contour, p, direction, radius, true);
256 }
257 m_cache.emplace(key, result);
258 return result;
259}
std::map< Key, Result > m_cache
Definition SeamContour.hpp:53
std::tuple< size_t, size_t, size_t, int, double > Key
Definition SeamContour.hpp:49
Result select(size_t layer, size_t contour, const Vec2d &point, int direction, double radius, bool check_reverse) const
Definition SeamContour.cpp:135
@ Local
Definition SeamContour.hpp:35
@ None
Definition SeamContour.hpp:34
const Polygon & contour(const ExPolygon &p)
Definition AGGRaster.hpp:30

References Slic3r::contour(), Slic3r::SeamContour::Local, m_cache, m_layers, m_options, Slic3r::SeamContour::None, Slic3r::SeamContour::Contour::points, Slic3r::SeamContour::Contour::reliable, select(), and Slic3r::SeamContour::Contour::width.

Referenced by Slic3r::SeamPlacer::find_next_seam_in_layer().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ select()

Result Slic3r::SeamContour::Resolver::select ( size_t layer,
size_t contour,
const Vec2d & point,
int direction,
double radius,
bool check_reverse ) const
private
136 {
137 const size_t target = size_t(ptrdiff_t(layer) + direction);
138 const Contour &source = m_layers[layer][contour];
139 const auto &next = m_layers[target];
140 const double bounds = source.nozzle * m_options.bounds_nozzle_factor;
141 const double noise = source.width * m_options.noise_width_factor;
142 const double reach = std::max({radius, bounds, noise});
143 const auto candidates = query(target, p, reach);
144 // An open path near either end or a material probe makes the geometric restriction uncertain.
145 for (size_t i : query(layer, p, reach))
146 if (!m_layers[layer][i].reliable) return {Outcome::None, Method::Local, {}, true};
147 for (size_t i : candidates)
148 if (!next[i].reliable) return {Outcome::None, Method::Local, {}, true};
149 std::vector<size_t> fast, nearby;
150 for (size_t i : candidates) {
151 const Contour &c = next[i];
152 if (c.points.size() < 3) continue;
153 // A wall can become a hole when an opening closes; local geometry decides that continuation.
154 if (box_distance(c, p) <= radius) nearby.push_back(i);
155 if (c.hole == source.hole && (c.min - source.min).cwiseAbs().maxCoeff() <= bounds &&
156 (c.max - source.max).cwiseAbs().maxCoeff() <= bounds) fast.push_back(i);
157 }
158 const auto source_normals = normals(source, p);
159 const auto compatible_foot = [&](const Contour &c) {
160 // Across a type change, use the closest patch itself: another side can mimic a shifted annulus.
161 return closest(c, p, -1.0, c.hole == source.hole ? &source_normals : nullptr,
162 m_options.normal_cosine);
163 };
164 const auto normal_agreement = [&](const Contour &c, const Vec2d &foot) {
165 double agreement = -1.0;
166 const auto target_normals = normals(c, foot);
167 for (const Vec2d &a : source_normals)
168 for (const Vec2d &b : target_normals) agreement = std::max(agreement, a.dot(b));
169 return agreement;
170 };
171 if (fast.size() == 1) {
172 const size_t index = fast.front();
173 const Foot foot = compatible_foot(next[index]);
174 // Bounds alone cannot certify a wall: only a near-coincident, consistently oriented patch can.
175 if (foot.distance <= noise && normal_agreement(next[index], foot.point) >= m_options.normal_cosine) {
176 bool competing = false;
177 for (size_t other : nearby) {
178 if (other == index || box_distance(next[other], p) > noise) continue;
179 const Foot alternative = compatible_foot(next[other]);
180 if (alternative.distance <= noise &&
181 normal_agreement(next[other], alternative.point) >= m_options.normal_cosine) {
182 competing = true;
183 break;
184 }
185 }
186 // A competing local wall or failed reverse match must reach the full fallback.
187 if (!competing) {
188 if (!check_reverse) return {Outcome::Unique, Method::Bounds, {index}};
189 const Result back = select(target, index, foot.point, -direction, radius, false);
190 // An uncertain certificate must leave the entire legacy candidate set unrestricted.
191 if (back.uncertain) return back;
192 if (std::find(back.contours.begin(), back.contours.end(), contour) != back.contours.end())
193 return {Outcome::Unique, Method::Bounds, {index}};
194 }
195 }
196 }
197 std::vector<Witness> witnessed;
198 for (size_t i : nearby) {
199 const Foot foot = compatible_foot(next[i]);
200 if (foot.distance > radius) continue;
201 const double agreement = normal_agreement(next[i], foot.point);
202 if (agreement < m_options.normal_cosine) continue;
203 bool band = true;
204 if (foot.distance > noise) {
205 // Three witnesses reject connectors through material (or air) shared by both layers.
206 for (double t : std::array<double, 3>{0.25, 0.5, 0.75}) {
207 const Vec2d probe = p + t * (foot.point - p);
208 if (in_material(layer, probe) == in_material(target, probe) &&
209 !near_boundary(layer, probe, noise) && !near_boundary(target, probe, noise)) {
210 band = false;
211 break;
212 }
213 }
214 }
215 if (!band) continue;
216 if (check_reverse) {
217 const Result back = select(target, i, foot.point, -direction, radius, false);
218 if (back.uncertain) return back;
219 // Several reverse continuations are valid if they still include the source wall.
220 if (std::find(back.contours.begin(), back.contours.end(), contour) == back.contours.end()) continue;
221 }
222 witnessed.push_back({i, foot.distance, std::acos(std::clamp(agreement, -1.0, 1.0)) *
223 180.0 / std::acos(-1.0)});
224 }
225 Result result;
226 const double distance_margin = std::max(1e-6, source.width * m_options.dominance_width_factor);
227 const double angle_margin = std::max(1e-6, m_options.dominance_angle_degrees);
228 for (const Witness &candidate : witnessed) {
229 // A contour is discarded only with a meaningful advantage in every scored criterion.
230 const bool dominated = std::any_of(witnessed.begin(), witnessed.end(), [&](const Witness &other) {
231 return other.distance + distance_margin <= candidate.distance &&
232 other.angle_degrees + angle_margin <= candidate.angle_degrees;
233 });
234 if (!dominated) result.contours.push_back(candidate.contour);
235 }
236 result.outcome = result.contours.empty() ? Outcome::None :
237 result.contours.size() == 1 ? Outcome::Unique : Outcome::Multiple;
238 return result;
239}
bool near_boundary(size_t layer, const Vec2d &point, double noise) const
Definition SeamContour.cpp:109
bool in_material(size_t layer, const Vec2d &point) const
Definition SeamContour.cpp:93
std::vector< Vec2d > normals(const Contour &c, const Vec2d &p)
Definition SeamContour.cpp:63
@ Bounds
Definition SeamContour.hpp:35
@ Multiple
Definition SeamContour.hpp:34
@ Unique
Definition SeamContour.hpp:34
void bounds(const NSVGimage &image, Vec2f &min, Vec2f &max)
Definition NSVGUtils.cpp:91

References Slic3r::SeamContour::Bounds, Slic3r::bounds(), Slic3r::contour(), Slic3r::SeamContour::Result::contours, Slic3r::SeamContour::Contour::hole, in_material(), Slic3r::SeamContour::Local, m_layers, m_options, Slic3r::SeamContour::Contour::max, Slic3r::SeamContour::Contour::min, Slic3r::SeamContour::Multiple, near_boundary(), Slic3r::SeamContour::None, Slic3r::SeamContour::Contour::nozzle, Slic3r::SeamContour::Result::outcome, Slic3r::SeamContour::Contour::points, query(), select(), Slic3r::SeamContour::Result::uncertain, Slic3r::SeamContour::Unique, and Slic3r::SeamContour::Contour::width.

Referenced by resolve(), and select().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ m_cache

std::map<Key, Result> Slic3r::SeamContour::Resolver::m_cache
mutableprivate

Referenced by resolve().

◆ m_indices

std::vector<AABBTreeIndirect::Tree2d> Slic3r::SeamContour::Resolver::m_indices
private

Referenced by Resolver(), and query().

◆ m_layers

Layers Slic3r::SeamContour::Resolver::m_layers
private

◆ m_options

Options Slic3r::SeamContour::Resolver::m_options
private

Referenced by Resolver(), resolve(), and select().


The documentation for this class was generated from the following files:
  • /home/runner/work/OrcaSlicer/OrcaSlicer/src/libslic3r/GCode/SeamContour.hpp
  • /home/runner/work/OrcaSlicer/OrcaSlicer/src/libslic3r/GCode/SeamContour.cpp