mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-31 20:02:00 +08:00
Searching for center thin part as start point for sampling
This commit is contained in:
parent
fcd7462403
commit
e664dd802c
@ -1087,14 +1087,15 @@ using Neighbor = VoronoiGraph::Node::Neighbor;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
struct ThinPart
|
struct ThinPart
|
||||||
{
|
{
|
||||||
// Transition from thick to thin part (one of the ends)
|
// Ceneter of longest path inside island part
|
||||||
// NOTE: When start.ratio <= 0 than island do not contain thick part
|
// longest path is choosen from:
|
||||||
Position start;
|
// shortest connection path between ends
|
||||||
|
// OR farest path to node from end
|
||||||
|
// OR farest path between nodes(only when ends are empty)
|
||||||
|
Position center;
|
||||||
|
|
||||||
// Transition from tiny to thick part (without start position)
|
// Transition from tiny to thick part (without start position)
|
||||||
Positions ends;
|
Positions ends;
|
||||||
|
|
||||||
bool is_only_thin_part() const { return ends.empty() && start.ratio <= 0.f; }
|
|
||||||
};
|
};
|
||||||
using ThinParts = std::vector<ThinPart>;
|
using ThinParts = std::vector<ThinPart>;
|
||||||
|
|
||||||
@ -1114,14 +1115,25 @@ struct ThickPart
|
|||||||
};
|
};
|
||||||
using ThickParts = std::vector<ThickPart>;
|
using ThickParts = std::vector<ThickPart>;
|
||||||
|
|
||||||
|
void create_thin_supports(const ThinParts &parts, SupportIslandPoints &results,
|
||||||
|
const Lines &lines, const SampleConfig &config) {
|
||||||
|
assert(!parts.empty());
|
||||||
|
/////////////////////// continue here
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// Search for interfaces
|
// Search for interfaces
|
||||||
// 1. thin to min_wide
|
// 1. thin to min_wide
|
||||||
// 2. min_wide to max_center
|
// 2. min_wide to max_center
|
||||||
// 3. max_center to Thick
|
// 3. max_center to Thick
|
||||||
enum class IslandPartType { thin, middle, thick };
|
enum class IslandPartType { thin, middle, thick };
|
||||||
|
|
||||||
|
// transition into neighbor part
|
||||||
struct IslandPartChange {
|
struct IslandPartChange {
|
||||||
Position position;
|
// position on the way out of island part
|
||||||
|
// Position::Neighbor::node is target(twin neighbor has source)
|
||||||
|
// Position::ration define position on connection between nodes
|
||||||
|
Position position;
|
||||||
size_t part_index;
|
size_t part_index;
|
||||||
};
|
};
|
||||||
using IslandPartChanges = std::vector<IslandPartChange>;
|
using IslandPartChanges = std::vector<IslandPartChange>;
|
||||||
@ -1137,7 +1149,8 @@ struct IslandPart {
|
|||||||
IslandPartChanges changes;
|
IslandPartChanges changes;
|
||||||
|
|
||||||
// sum of all lengths inside of part
|
// sum of all lengths inside of part
|
||||||
// IMPROVE: better will be length of longest path
|
// IMPROVE1: Separate calculation localy into function merge_middle_parts_into_biggest_neighbor
|
||||||
|
// IMPROVE2: better will be length of longest path
|
||||||
// Used as rule to connect(merge) middle part of island to its biggest neighbour
|
// Used as rule to connect(merge) middle part of island to its biggest neighbour
|
||||||
// NOTE: No solution for island with 2 biggest neighbors with same sum_lengths.
|
// NOTE: No solution for island with 2 biggest neighbors with same sum_lengths.
|
||||||
coord_t sum_lengths = 0;
|
coord_t sum_lengths = 0;
|
||||||
@ -1351,9 +1364,9 @@ void merge_middle_parts_into_biggest_neighbor(IslandParts& island_parts) {
|
|||||||
void merge_same_neighbor_type_parts(IslandParts &island_parts) {
|
void merge_same_neighbor_type_parts(IslandParts &island_parts) {
|
||||||
// connect neighbor parts with same type
|
// connect neighbor parts with same type
|
||||||
for (size_t island_part_index = 0; island_part_index < island_parts.size(); ++island_part_index) {
|
for (size_t island_part_index = 0; island_part_index < island_parts.size(); ++island_part_index) {
|
||||||
assert(island_part.type != IslandPartType::middle); // only thin or thick parts
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const IslandPart &island_part = island_parts[island_part_index];
|
const IslandPart &island_part = island_parts[island_part_index];
|
||||||
|
assert(island_part.type != IslandPartType::middle); // only thin or thick parts
|
||||||
const IslandPartChanges &changes = island_part.changes;
|
const IslandPartChanges &changes = island_part.changes;
|
||||||
auto change_it = std::find_if(changes.begin(), changes.end(),
|
auto change_it = std::find_if(changes.begin(), changes.end(),
|
||||||
[&island_parts, type = island_part.type](const IslandPartChange &change) {
|
[&island_parts, type = island_part.type](const IslandPartChange &change) {
|
||||||
@ -1364,8 +1377,327 @@ void merge_same_neighbor_type_parts(IslandParts &island_parts) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Find shortest distances between changes (combination of changes)
|
||||||
|
/// and choose the longest distance or farest node distance from changes
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="changes">transition into different part island</param>
|
||||||
|
/// <param name="center">[optional]Center of longest path</param>
|
||||||
|
/// <returns>Length of island part defined as longest distance on graph inside part</returns>
|
||||||
|
coord_t get_longest_distance(const IslandPartChanges& changes, Position* center = nullptr) {
|
||||||
|
const Neighbor *front_twin = VoronoiGraphUtils::get_twin(*changes.front().position.neighbor);
|
||||||
|
if (changes.size() == 2 && front_twin == changes.back().position.neighbor) {
|
||||||
|
// Special case when part lay only on one neighbor
|
||||||
|
if (center != nullptr){
|
||||||
|
*center = changes.front().position;// copy
|
||||||
|
center->ratio = (center->ratio + changes.back().position.ratio)/2;
|
||||||
|
}
|
||||||
|
return static_cast<coord_t>(changes.front().position.neighbor->length() *
|
||||||
|
(1 - changes.front().position.ratio - changes.back().position.ratio));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ShortestDistance{
|
||||||
|
coord_t distance;
|
||||||
|
size_t prev_node_distance_index;
|
||||||
|
};
|
||||||
|
using ShortestDistances = std::vector<ShortestDistance>;
|
||||||
|
// for each island part node find distance to changes
|
||||||
|
struct NodeDistance {
|
||||||
|
// island part node
|
||||||
|
const VoronoiGraph::Node *node;
|
||||||
|
// shortest distance to node from change
|
||||||
|
ShortestDistances shortest_distances; // size == changes.size()
|
||||||
|
};
|
||||||
|
using NodeDistances = std::vector<NodeDistance>;
|
||||||
|
NodeDistances node_distances;
|
||||||
|
|
||||||
|
const coord_t no_distance = std::numeric_limits<coord_t>::max();
|
||||||
|
const size_t no_index = std::numeric_limits<size_t>::max();
|
||||||
|
size_t count = changes.size();
|
||||||
|
for (const IslandPartChange &change : changes) {
|
||||||
|
const VoronoiGraph::Node *node = VoronoiGraphUtils::get_twin(*change.position.neighbor)->node;
|
||||||
|
ShortestDistances shortest_distances(count, ShortestDistance{no_distance, no_index});
|
||||||
|
shortest_distances[&change - &changes.front()].distance = change.position.calc_distance();
|
||||||
|
node_distances.push_back(NodeDistance{node, std::move(shortest_distances)});
|
||||||
|
}
|
||||||
|
|
||||||
|
// use sorted changes for faster check of neighbors
|
||||||
|
IslandPartChanges sorted_changes = changes; // copy
|
||||||
|
std::sort(sorted_changes.begin(), sorted_changes.end(),
|
||||||
|
[](const IslandPartChange &a, const IslandPartChange &b) {
|
||||||
|
return a.position.neighbor < b.position.neighbor;
|
||||||
|
});
|
||||||
|
auto exist_part_change_for_neighbor = [&sorted_changes](const Neighbor *neighbor) {
|
||||||
|
auto it = std::lower_bound(sorted_changes.begin(), sorted_changes.end(), neighbor,
|
||||||
|
[](const IslandPartChange &change, const Neighbor *neighbor_) {
|
||||||
|
return change.position.neighbor < neighbor_; });
|
||||||
|
if (it == sorted_changes.end()) return false;
|
||||||
|
return it->position.neighbor == neighbor;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Queue of island nodes to propagate shortest distance into their neigbors
|
||||||
|
// contain indices into node_distances
|
||||||
|
std::vector<size_t> process;
|
||||||
|
for (size_t i = 1; i < count; i++) process.push_back(i); // zero index is start
|
||||||
|
size_t next_distance_index = 0; // zero index is start
|
||||||
|
const Neighbor *prev_neighbor = front_twin;
|
||||||
|
// propagate distances into neighbors
|
||||||
|
while (true /* next_distance_index < node_distances.size()*/) {
|
||||||
|
const NodeDistance &node_distance = node_distances[next_distance_index];
|
||||||
|
next_distance_index = -1; // set to no value ... index > node_distances.size()
|
||||||
|
for (const Neighbor &neighbor : node_distance.node->neighbors) {
|
||||||
|
if (&neighbor == prev_neighbor) continue;
|
||||||
|
if (exist_part_change_for_neighbor(&neighbor))
|
||||||
|
continue; // change is search graph limit
|
||||||
|
|
||||||
|
// IMPROVE: use binary search
|
||||||
|
auto node_distance_it = std::find_if(node_distances.begin(), node_distances.end(),
|
||||||
|
[node = neighbor.node](const NodeDistance& d) {
|
||||||
|
return d.node == node;} );
|
||||||
|
if (node_distance_it == node_distances.end()) {
|
||||||
|
// create new node distance
|
||||||
|
ShortestDistances new_shortest_distances = node_distance.shortest_distances; // copy
|
||||||
|
for (ShortestDistance &d : new_shortest_distances)
|
||||||
|
if (d.distance != no_distance) {
|
||||||
|
d.distance += neighbor.length();
|
||||||
|
d.prev_node_distance_index = &node_distance - &node_distances.front();
|
||||||
|
}
|
||||||
|
if (next_distance_index < node_distances.size())
|
||||||
|
process.push_back(next_distance_index); // store for next processing
|
||||||
|
next_distance_index = node_distances.size();
|
||||||
|
prev_neighbor = VoronoiGraphUtils::get_twin(neighbor);
|
||||||
|
node_distances.push_back(NodeDistance{neighbor.node, new_shortest_distances});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool exist_distance_change = false;
|
||||||
|
// update distances
|
||||||
|
for (size_t i = 0; i < count; ++i) {
|
||||||
|
const ShortestDistance &d = node_distance.shortest_distances[i];
|
||||||
|
if (d.distance == no_distance) continue;
|
||||||
|
coord_t new_distance = d.distance + static_cast<coord_t>(neighbor.length());
|
||||||
|
if (ShortestDistance ¤t_distance = node_distance_it->shortest_distances[i];
|
||||||
|
current_distance.distance > new_distance) {
|
||||||
|
current_distance.distance = new_distance;
|
||||||
|
current_distance.prev_node_distance_index = i;
|
||||||
|
exist_distance_change = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!exist_distance_change)
|
||||||
|
continue; // no change in distances
|
||||||
|
|
||||||
|
size_t item_index = node_distance_it - node_distances.begin();
|
||||||
|
// process store unique indices into node_distances
|
||||||
|
if(std::find(process.begin(), process.end(), item_index) != process.end())
|
||||||
|
continue; // already in process
|
||||||
|
|
||||||
|
if (next_distance_index < node_distances.size())
|
||||||
|
process.push_back(next_distance_index); // store for next processing
|
||||||
|
next_distance_index = item_index;
|
||||||
|
prev_neighbor = VoronoiGraphUtils::get_twin(neighbor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next_distance_index >= node_distances.size()){
|
||||||
|
if (process.empty())
|
||||||
|
break; // no more nodes to process
|
||||||
|
next_distance_index = process.back();
|
||||||
|
process.pop_back();
|
||||||
|
prev_neighbor = nullptr; // do not know previous neighbor
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// find farest distance node from changes
|
||||||
|
coord_t farest_from_change = 0;
|
||||||
|
size_t change_index = 0;
|
||||||
|
NodeDistance &farest_distnace = node_distances.front();
|
||||||
|
for (const NodeDistance &node_distance : node_distances)
|
||||||
|
for (const ShortestDistance& d : node_distance.shortest_distances)
|
||||||
|
if (farest_from_change < d.distance) {
|
||||||
|
farest_from_change = d.distance;
|
||||||
|
change_index = &d - &node_distance.shortest_distances.front();
|
||||||
|
farest_distnace = node_distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
// farest distance between changes
|
||||||
|
// till node distances do not change order than index of change is index of closest node of change
|
||||||
|
size_t source_change = count;
|
||||||
|
for (size_t i = 0; i < (count-1); ++i) {
|
||||||
|
const NodeDistance &node_distance = node_distances[i];
|
||||||
|
const ShortestDistance &distance_to_change = node_distance.shortest_distances[i];
|
||||||
|
for (size_t j = i+1; j < count; ++j) {
|
||||||
|
coord_t distance = node_distance.shortest_distances[j].distance + distance_to_change.distance;
|
||||||
|
if (farest_from_change < distance) {
|
||||||
|
// this change is farest from other changes
|
||||||
|
farest_from_change = distance;
|
||||||
|
change_index = j;
|
||||||
|
source_change = i;
|
||||||
|
farest_distnace = node_distance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// center is not needed so return only farest distance
|
||||||
|
if (center == nullptr)
|
||||||
|
return farest_from_change;
|
||||||
|
|
||||||
|
// Next lines are for calculation of center for longest path
|
||||||
|
coord_t half_distance = farest_from_change / 2;
|
||||||
|
|
||||||
|
// check if center is on change neighbor
|
||||||
|
auto is_ceneter_on_change_neighbor = [&changes, center, half_distance](size_t change_index) {
|
||||||
|
const Position &position = changes[change_index].position;
|
||||||
|
if (position.calc_distance() < half_distance)
|
||||||
|
return false;
|
||||||
|
// center lay on neighbour with change
|
||||||
|
center->neighbor = position.neighbor;
|
||||||
|
center->ratio = position.ratio - half_distance / position.neighbor->length();
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
if (is_ceneter_on_change_neighbor(source_change) ||
|
||||||
|
is_ceneter_on_change_neighbor(change_index))
|
||||||
|
return farest_from_change;
|
||||||
|
|
||||||
|
NodeDistance *prev_node_distance = &farest_distnace;
|
||||||
|
NodeDistance *node_distance = nullptr;
|
||||||
|
// iterate over longest path to find center(half distance)
|
||||||
|
while (prev_node_distance->shortest_distances[change_index].distance > half_distance) {
|
||||||
|
node_distance = prev_node_distance;
|
||||||
|
size_t prev_index = node_distance->shortest_distances[change_index].prev_node_distance_index;
|
||||||
|
// case with center on change neighbor is already handled, so prev_index should be valid
|
||||||
|
assert(prev_index != no_index);
|
||||||
|
prev_node_distance = &node_distances[prev_index];
|
||||||
|
}
|
||||||
|
|
||||||
|
// case with center on change neighbor should be already handled
|
||||||
|
assert(node_distance != nullptr);
|
||||||
|
assert(node_distance->shortest_distances[change_index].distance >= half_distance);
|
||||||
|
assert(prev_node_distance->shortest_distances[change_index].distance <= half_distance);
|
||||||
|
coord_t to_half_distance = half_distance - node_distance->shortest_distances[change_index].distance;
|
||||||
|
// find neighbor between node_distance and prev_node_distance
|
||||||
|
for (const Neighbor &n : node_distance->node->neighbors) {
|
||||||
|
if (n.node != prev_node_distance->node)
|
||||||
|
continue;
|
||||||
|
center->neighbor = &n;
|
||||||
|
center->ratio = to_half_distance / n.length();
|
||||||
|
return farest_from_change;
|
||||||
|
}
|
||||||
|
|
||||||
|
// weird situation when center is not found
|
||||||
|
assert(false);
|
||||||
|
return farest_from_change;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Remove island part with index
|
||||||
|
/// Merge all neighbors of deleted part together and create merged part on lowest index of merged parts
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="island_parts">All existing island parts with type only thin OR thick</param>
|
||||||
|
/// <param name="index">index of island part to remove</param>
|
||||||
|
/// <returns>modified part index and all removed part indices</returns>
|
||||||
|
std::pair<size_t, std::vector<size_t>> merge_negihbor(IslandParts &island_parts, size_t index) {
|
||||||
|
// merge all neighbors into one part
|
||||||
|
std::vector<size_t> remove_indices;
|
||||||
|
const IslandPartChanges &changes = island_parts[index].changes;
|
||||||
|
// all neighbor should be the same type which is different to current one.
|
||||||
|
assert(std::find_if(changes.begin(), changes.end(), [&island_parts, type = island_parts[index].type]
|
||||||
|
(const IslandPartChange &c) { return island_parts[c.part_index].type == type; }) == changes.end());
|
||||||
|
remove_indices.reserve(changes.size());
|
||||||
|
|
||||||
|
// collect changes from neighbors for result part
|
||||||
|
IslandPartChanges modified_changes;
|
||||||
|
size_t modified_index = index; // smallest index of merged parts
|
||||||
|
for (const IslandPartChange &change : changes) {
|
||||||
|
size_t remove_index = change.part_index;
|
||||||
|
if (remove_index < modified_index) // remove part with bigger index
|
||||||
|
std::swap(remove_index, modified_index);
|
||||||
|
remove_indices.push_back(remove_index);
|
||||||
|
// iterate neighbor changes and collect only changes to other neighbors
|
||||||
|
for (const IslandPartChange &n_change : island_parts[change.part_index].changes) {
|
||||||
|
if (n_change.part_index == index)
|
||||||
|
continue; // skip back to removed part
|
||||||
|
if(std::find_if(changes.begin(), changes.end(), [i = n_change.part_index]
|
||||||
|
(const IslandPartChange &change){ return change.part_index == i;}) == changes.end())
|
||||||
|
continue; // skip removed part changes
|
||||||
|
modified_changes.push_back(n_change);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set result part after merge
|
||||||
|
IslandPart& island_part = island_parts[modified_index];
|
||||||
|
island_part.type = island_parts[changes.front().part_index].type; // type of neighbor
|
||||||
|
island_part.changes = modified_changes;
|
||||||
|
island_part.sum_lengths = 0; // invalid value after merge
|
||||||
|
|
||||||
|
std::sort(remove_indices.begin(), remove_indices.end());
|
||||||
|
// remove parts from island parts
|
||||||
|
for (size_t i = 1; i <= remove_indices.size(); i++)
|
||||||
|
island_parts.erase(island_parts.begin() + remove_indices[remove_indices.size() - i]);
|
||||||
|
|
||||||
|
// Set neighbors neighbors to point on modified_index
|
||||||
|
std::vector<size_t> neighbors_neighbors_indices;
|
||||||
|
for (const IslandPartChange &change : modified_changes)
|
||||||
|
neighbors_neighbors_indices.push_back(change.part_index);
|
||||||
|
std::sort(neighbors_neighbors_indices.begin(), neighbors_neighbors_indices.end());
|
||||||
|
neighbors_neighbors_indices.erase(std::unique(neighbors_neighbors_indices.begin(),
|
||||||
|
neighbors_neighbors_indices.end()), neighbors_neighbors_indices.end());
|
||||||
|
for (size_t part_index : neighbors_neighbors_indices)
|
||||||
|
for (IslandPartChange &change : island_parts[part_index].changes)
|
||||||
|
if (std::lower_bound(remove_indices.begin(), remove_indices.end(),
|
||||||
|
change.part_index) != remove_indices.end())
|
||||||
|
change.part_index = modified_index;
|
||||||
|
|
||||||
|
return std::make_pair(index, remove_indices);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calculate all distances between changes(combination of changes)
|
||||||
|
/// Choose the longest distance between change for each island part(part_length).
|
||||||
|
/// Merge island parts in order from shortest path_length
|
||||||
|
/// Till path_length is smaller than config::min_part_length
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="island_parts">Only thin or thick parts</param>
|
||||||
|
/// <param name="min_part_length">Minimal length of part to not be merged into neighbors</param>
|
||||||
|
void merge_short_parts(IslandParts &island_parts, coord_t min_part_length) {
|
||||||
|
// should be called only for multiple island parts, at least 2
|
||||||
|
assert(island_parts.size() > 1);
|
||||||
|
if (island_parts.size() <= 1) return; // nothing to merge
|
||||||
|
|
||||||
|
// only thin OR thick parts
|
||||||
|
assert(std::find_if(island_parts.begin(), island_parts.end(), [](const IslandPart &i)
|
||||||
|
{return i.type != IslandPartType::thin && i.type != IslandPartType::thick; }) == island_parts.end());
|
||||||
|
|
||||||
|
// same size as island_parts
|
||||||
|
std::vector<coord_t> part_lengths;
|
||||||
|
part_lengths.reserve(island_parts.size());
|
||||||
|
for (const IslandPart& island_part: island_parts)
|
||||||
|
part_lengths.push_back(get_longest_distance(island_part.changes));
|
||||||
|
|
||||||
|
// Merge island parts in order from shortest length
|
||||||
|
while(true){
|
||||||
|
// find smallest part
|
||||||
|
size_t smallest_part_index = std::min_element(part_lengths.begin(), part_lengths.end()) - part_lengths.begin();
|
||||||
|
if (part_lengths[smallest_part_index] >= min_part_length)
|
||||||
|
break; // all parts are long enough
|
||||||
|
|
||||||
|
auto [index, remove_indices] = merge_negihbor(island_parts, smallest_part_index);
|
||||||
|
|
||||||
|
// update part lengths
|
||||||
|
part_lengths[index] = get_longest_distance(island_parts[index].changes);
|
||||||
|
for (size_t remove_index : remove_indices) // remove lengths for removed parts
|
||||||
|
part_lengths.erase(part_lengths.begin() + remove_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ThinPart create_only_thin_part(const VoronoiGraph::ExPath &path) {
|
||||||
|
std::optional<Position> path_center_opt =
|
||||||
|
SampleIslandUtils::create_position_on_path(path.nodes, path.length / 2);
|
||||||
|
assert(path_center_opt.has_value());
|
||||||
|
return ThinPart{*path_center_opt, /*ends*/ {}};
|
||||||
|
}
|
||||||
|
|
||||||
std::pair<ThinParts, ThickParts> convert_island_parts_to_thin_thick(
|
std::pair<ThinParts, ThickParts> convert_island_parts_to_thin_thick(
|
||||||
const IslandParts& island_parts, const Neighbor* start_neighbor)
|
const IslandParts& island_parts, const Neighbor* start_neighbor, const VoronoiGraph::ExPath &path)
|
||||||
{
|
{
|
||||||
// always must be at least one island part
|
// always must be at least one island part
|
||||||
assert(!island_parts.empty());
|
assert(!island_parts.empty());
|
||||||
@ -1374,7 +1706,7 @@ std::pair<ThinParts, ThickParts> convert_island_parts_to_thin_thick(
|
|||||||
// convert island parts into result
|
// convert island parts into result
|
||||||
if (island_parts.size() == 1)
|
if (island_parts.size() == 1)
|
||||||
return island_parts.front().type == IslandPartType::thin ?
|
return island_parts.front().type == IslandPartType::thin ?
|
||||||
std::make_pair(ThinParts{ThinPart{Position{start_neighbor, -1.f}, /*ends*/ {}}}, ThickParts{}) :
|
std::make_pair(ThinParts{create_only_thin_part(path)}, ThickParts{}) :
|
||||||
std::make_pair(ThinParts{}, ThickParts{ThickPart{Position{start_neighbor, -1.f}, /*ends*/ {}}});
|
std::make_pair(ThinParts{}, ThickParts{ThickPart{Position{start_neighbor, -1.f}, /*ends*/ {}}});
|
||||||
|
|
||||||
std::pair<ThinParts, ThickParts> result;
|
std::pair<ThinParts, ThickParts> result;
|
||||||
@ -1383,9 +1715,10 @@ std::pair<ThinParts, ThickParts> convert_island_parts_to_thin_thick(
|
|||||||
for (const IslandPart& i:island_parts) {
|
for (const IslandPart& i:island_parts) {
|
||||||
if (i.type == IslandPartType::thin) {
|
if (i.type == IslandPartType::thin) {
|
||||||
ThinPart thin_part;
|
ThinPart thin_part;
|
||||||
thin_part.start = i.changes.front().position;
|
// discard distance, only center is needed
|
||||||
|
get_longest_distance(i.changes, &thin_part.center);
|
||||||
thin_parts.reserve(i.changes.size() - 1);
|
thin_parts.reserve(i.changes.size() - 1);
|
||||||
std::transform(i.changes.begin()+1, i.changes.end(), std::back_inserter(thin_part.ends),
|
std::transform(i.changes.begin() + 1, i.changes.end(), std::back_inserter(thin_part.ends),
|
||||||
[](const IslandPartChange &change) { return change.position; });
|
[](const IslandPartChange &change) { return change.position; });
|
||||||
thin_parts.push_back(thin_part);
|
thin_parts.push_back(thin_part);
|
||||||
} else {
|
} else {
|
||||||
@ -1406,7 +1739,8 @@ std::pair<ThinParts, ThickParts> convert_island_parts_to_thin_thick(
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="path">Longest path over island</param>
|
/// <param name="path">Longest path over island</param>
|
||||||
/// <param name="lines">Island border</param>
|
/// <param name="lines">Island border</param>
|
||||||
/// <param name="config">Define border between thin and thick part</param>
|
/// <param name="config">Define border between thin and thick part
|
||||||
|
/// and minimal length of separable part</param>
|
||||||
/// <returns>Thin and thick parts</returns>
|
/// <returns>Thin and thick parts</returns>
|
||||||
std::pair<ThinParts, ThickParts> separate_thin_thick(
|
std::pair<ThinParts, ThickParts> separate_thin_thick(
|
||||||
const VoronoiGraph::ExPath &path, const Lines &lines, const SampleConfig &config
|
const VoronoiGraph::ExPath &path, const Lines &lines, const SampleConfig &config
|
||||||
@ -1414,7 +1748,6 @@ std::pair<ThinParts, ThickParts> separate_thin_thick(
|
|||||||
// Check input
|
// Check input
|
||||||
assert(!path.nodes.empty());
|
assert(!path.nodes.empty());
|
||||||
assert(lines.size() >= 3); // at least triangle
|
assert(lines.size() >= 3); // at least triangle
|
||||||
assert(SampleConfigFactory::verify(config));
|
|
||||||
|
|
||||||
// Start dividing on some border of island
|
// Start dividing on some border of island
|
||||||
const VoronoiGraph::Node *start_node = path.nodes.front();
|
const VoronoiGraph::Node *start_node = path.nodes.front();
|
||||||
@ -1449,7 +1782,7 @@ std::pair<ThinParts, ThickParts> separate_thin_thick(
|
|||||||
if (auto process_it = std::find_if(process.begin(), process.end(), is_oposit_item);
|
if (auto process_it = std::find_if(process.begin(), process.end(), is_oposit_item);
|
||||||
process_it != process.end()) {
|
process_it != process.end()) {
|
||||||
// solve loop back
|
// solve loop back
|
||||||
next_item.node = nullptr;
|
next_item.node = nullptr; // do not use item as next one
|
||||||
merge_parts_and_fix_process(island_parts, item, process_it->i, next_item.i, process);
|
merge_parts_and_fix_process(island_parts, item, process_it->i, next_item.i, process);
|
||||||
// branch is already processed
|
// branch is already processed
|
||||||
process.erase(process_it);
|
process.erase(process_it);
|
||||||
@ -1469,8 +1802,9 @@ std::pair<ThinParts, ThickParts> separate_thin_thick(
|
|||||||
|
|
||||||
merge_middle_parts_into_biggest_neighbor(island_parts);
|
merge_middle_parts_into_biggest_neighbor(island_parts);
|
||||||
merge_same_neighbor_type_parts(island_parts);
|
merge_same_neighbor_type_parts(island_parts);
|
||||||
|
merge_short_parts(island_parts, config.min_part_length);
|
||||||
|
|
||||||
return convert_island_parts_to_thin_thick(island_parts, start_neighbor);
|
return convert_island_parts_to_thin_thick(island_parts, start_neighbor, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
@ -1514,7 +1848,11 @@ SupportIslandPoints SampleIslandUtils::sample_expath(
|
|||||||
// TODO: 3) Triangle of points
|
// TODO: 3) Triangle of points
|
||||||
// eval outline and find three point create almost equilateral triangle
|
// eval outline and find three point create almost equilateral triangle
|
||||||
|
|
||||||
|
// 4) Thin and thick support
|
||||||
|
SupportIslandPoints result;
|
||||||
auto [thin, thick] = separate_thin_thick(path, lines, config);
|
auto [thin, thick] = separate_thin_thick(path, lines, config);
|
||||||
|
if (!thin.empty()) create_thin_supports(thin, result, lines, config);
|
||||||
|
//if (!thick.empty()) create_thick_supports(thick, lines, config);
|
||||||
|
|
||||||
// IMPROVE: Erase continous sampling: Extract ExPath and than sample uniformly whole ExPath
|
// IMPROVE: Erase continous sampling: Extract ExPath and than sample uniformly whole ExPath
|
||||||
CenterStarts center_starts;
|
CenterStarts center_starts;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user