FIX: brim generation error in XY compensation and first layer fixing
now, when XY compensation with negative value is assigned, the brim can be generated correctly (Studio-2222). In addition, one can add brim to a model whose first layer is empty while second layer is not empty (studio-1286). Change-Id: I28443dc6e28bc6fff8c92d3cc35ab7a416d43138 (cherry picked from commit cb62afcfd295ca93962d99350d1dfaf3441c4759)
This commit is contained in:
parent
e994cd02e2
commit
4536ed9ae2
3 changed files with 170 additions and 133 deletions
|
@ -1519,10 +1519,10 @@ Polygons tryExPolygonOffset(const ExPolygons islandAreaEx, const Print& print)
|
|||
for (ExPolygon& poly_ex : islands_ex)
|
||||
poly_ex.douglas_peucker(resolution);
|
||||
polygons_append(loops, to_polygons(islands_ex));
|
||||
islands_ex = offset_ex(std::move(islands_ex), -1.4f*float(flow.scaled_spacing()), jtRound, resolution);
|
||||
islands_ex = offset_ex(std::move(islands_ex), -1.3f*float(flow.scaled_spacing()), jtRound, resolution);
|
||||
for (ExPolygon& poly_ex : islands_ex)
|
||||
poly_ex.douglas_peucker(resolution);
|
||||
islands_ex = offset_ex(std::move(islands_ex), 0.4f*float(flow.scaled_spacing()), jtRound, resolution);
|
||||
islands_ex = offset_ex(std::move(islands_ex), 0.3f*float(flow.scaled_spacing()), jtRound, resolution);
|
||||
}
|
||||
return loops;
|
||||
}
|
||||
|
|
|
@ -317,7 +317,9 @@ public:
|
|||
// BBS
|
||||
void generate_support_preview();
|
||||
const std::vector<VolumeSlices>& firstLayerObjSlice() const { return firstLayerObjSliceByVolume; }
|
||||
std::vector<VolumeSlices>& firstLayerObjSliceMod() { return firstLayerObjSliceByVolume; }
|
||||
const std::vector<groupedVolumeSlices>& firstLayerObjGroups() const { return firstLayerObjSliceByGroups; }
|
||||
std::vector<groupedVolumeSlices>& firstLayerObjGroupsMod() { return firstLayerObjSliceByGroups; }
|
||||
|
||||
bool has_brim() const {
|
||||
return ((this->config().brim_type != btNoBrim && this->config().brim_width.value > 0.) || this->config().brim_type == btAutoBrim)
|
||||
|
|
|
@ -440,6 +440,151 @@ static std::vector<std::vector<ExPolygons>> slices_to_regions(
|
|||
return slices_by_region;
|
||||
}
|
||||
|
||||
//BBS: justify whether a volume is connected to another one
|
||||
bool doesVolumeIntersect(VolumeSlices& vs1, VolumeSlices& vs2)
|
||||
{
|
||||
if (vs1.volume_id == vs2.volume_id) return true;
|
||||
if (vs1.slices.size() != vs2.slices.size()) return false;
|
||||
|
||||
for (int i = 0; i != vs1.slices.size(); ++i) {
|
||||
|
||||
if (vs1.slices[i].empty()) continue;
|
||||
if (!vs2.slices[i].empty() && !intersection_ex(vs1.slices[i], vs2.slices[i]).empty()) return true;
|
||||
if (i + 1 != vs2.slices.size() && !vs2.slices[i + 1].empty()) {
|
||||
if (!intersection_ex(vs1.slices[i], vs2.slices[i + 1]).empty()) return true;
|
||||
}
|
||||
if (i - 1 >= 0 && !vs2.slices[i - 1].empty()) {
|
||||
if (!intersection_ex(vs1.slices[i], vs2.slices[i - 1]).empty()) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//BBS: grouping the volumes of an object according to their connection relationship
|
||||
bool groupingVolumes(std::vector<VolumeSlices> objSliceByVolume, std::vector<groupedVolumeSlices>& groups, double resolution, int firstLayerReplacedBy)
|
||||
{
|
||||
std::vector<int> groupIndex(objSliceByVolume.size(), -1);
|
||||
double offsetValue = 0.05 / SCALING_FACTOR;
|
||||
|
||||
for (int i = 0; i != objSliceByVolume.size(); ++i) {
|
||||
for (int j = 0; j != objSliceByVolume[i].slices.size(); ++j) {
|
||||
objSliceByVolume[i].slices[j] = offset_ex(objSliceByVolume[i].slices[j], offsetValue);
|
||||
for (ExPolygon& poly_ex : objSliceByVolume[i].slices[j])
|
||||
poly_ex.douglas_peucker(resolution);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i != objSliceByVolume.size(); ++i) {
|
||||
if (groupIndex[i] < 0) {
|
||||
groupIndex[i] = i;
|
||||
}
|
||||
for (int j = i + 1; j != objSliceByVolume.size(); ++j) {
|
||||
if (doesVolumeIntersect(objSliceByVolume[i], objSliceByVolume[j])) {
|
||||
if (groupIndex[j] < 0) groupIndex[j] = groupIndex[i];
|
||||
if (groupIndex[j] != groupIndex[i]) {
|
||||
int retain = std::min(groupIndex[i], groupIndex[j]);
|
||||
int cover = std::max(groupIndex[i], groupIndex[j]);
|
||||
for (int k = 0; k != objSliceByVolume.size(); ++k) {
|
||||
if (groupIndex[k] == cover) groupIndex[k] = retain;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<int> groupVector{};
|
||||
for (int gi : groupIndex) {
|
||||
bool exist = false;
|
||||
for (int gv : groupVector) {
|
||||
if (gv == gi) {
|
||||
exist = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!exist) groupVector.push_back(gi);
|
||||
}
|
||||
|
||||
// group volumes and their slices according to the grouping Vector
|
||||
groups.clear();
|
||||
|
||||
for (int gv : groupVector) {
|
||||
groupedVolumeSlices gvs;
|
||||
gvs.groupId = gv;
|
||||
for (int i = 0; i != objSliceByVolume.size(); ++i) {
|
||||
if (groupIndex[i] == gv) {
|
||||
gvs.volume_ids.push_back(objSliceByVolume[i].volume_id);
|
||||
append(gvs.slices, objSliceByVolume[i].slices[firstLayerReplacedBy]);
|
||||
}
|
||||
}
|
||||
|
||||
// the slices of a group should be unioned
|
||||
gvs.slices = offset_ex(union_ex(gvs.slices), -offsetValue);
|
||||
for (ExPolygon& poly_ex : gvs.slices)
|
||||
poly_ex.douglas_peucker(resolution);
|
||||
|
||||
groups.push_back(gvs);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//BBS: filter the members of "objSliceByVolume" such that only "model_part" are included
|
||||
std::vector<VolumeSlices> findPartVolumes(const std::vector<VolumeSlices>& objSliceByVolume, ModelVolumePtrs model_volumes) {
|
||||
std::vector<VolumeSlices> outPut;
|
||||
for (const auto& vs : objSliceByVolume) {
|
||||
for (const auto& mv : model_volumes) {
|
||||
if (vs.volume_id == mv->id() && mv->is_model_part()) outPut.push_back(vs);
|
||||
}
|
||||
}
|
||||
return outPut;
|
||||
}
|
||||
|
||||
void applyNegtiveVolumes(ModelVolumePtrs model_volumes, const std::vector<VolumeSlices>& objSliceByVolume, std::vector<groupedVolumeSlices>& groups, double resolution) {
|
||||
ExPolygons negTotal;
|
||||
for (const auto& vs : objSliceByVolume) {
|
||||
for (const auto& mv : model_volumes) {
|
||||
if (vs.volume_id == mv->id() && mv->is_negative_volume()) {
|
||||
if (vs.slices.size() > 0) {
|
||||
append(negTotal, vs.slices.front());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& g : groups) {
|
||||
g.slices = diff_ex(g.slices, negTotal);
|
||||
for (ExPolygon& poly_ex : g.slices)
|
||||
poly_ex.douglas_peucker(resolution);
|
||||
}
|
||||
}
|
||||
|
||||
void reGroupingLayerPolygons(std::vector<groupedVolumeSlices>& gvss, ExPolygons eps)
|
||||
{
|
||||
std::vector<int> epsIndex;
|
||||
epsIndex.resize(eps.size(), -1);
|
||||
for (int ie = 0; ie != eps.size(); ie++) {
|
||||
for (int iv = 0; iv != gvss.size(); iv++) {
|
||||
auto clipedExPolys = diff_ex(eps[ie], gvss[iv].slices);
|
||||
double area = 0;
|
||||
for (const auto& ce : clipedExPolys) {
|
||||
area += ce.area();
|
||||
}
|
||||
if (eps[ie].area() > 0 && area / eps[ie].area() < 0.3) {
|
||||
epsIndex[ie] = iv;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int iv = 0; iv != gvss.size(); iv++)
|
||||
gvss[iv].slices.clear();
|
||||
|
||||
for (int ie = 0; ie != eps.size(); ie++) {
|
||||
if (epsIndex[ie] >= 0)
|
||||
gvss[epsIndex[ie]].slices.push_back(eps[ie]);
|
||||
}
|
||||
}
|
||||
|
||||
std::string fix_slicing_errors(PrintObject* object, LayerPtrs &layers, const std::function<void()> &throw_if_canceled)
|
||||
{
|
||||
std::string error_msg;//BBS
|
||||
|
@ -549,6 +694,21 @@ std::string fix_slicing_errors(PrintObject* object, LayerPtrs &layers, const std
|
|||
//BBS
|
||||
if(error_msg.empty() && !buggy_layers.empty())
|
||||
error_msg = L("The model has too many empty layers.");
|
||||
|
||||
// BBS: first layer slices are sorted by volume group, if the first layer is empty and replaced by the 2nd layer
|
||||
// the later will be stored in "object->firstLayerObjGroupsMod()"
|
||||
int firstLayerReplacedBy = 0;
|
||||
if (!buggy_layers.empty() && buggy_layers.front() == 0)
|
||||
firstLayerReplacedBy = 1;
|
||||
|
||||
const auto scaled_resolution = scaled<double>(object->print()->config().resolution.value);
|
||||
auto partsObjSliceByVolume = findPartVolumes(object->firstLayerObjSliceMod(), object->model_object()->volumes);
|
||||
groupingVolumes(partsObjSliceByVolume, object->firstLayerObjGroupsMod(), scaled_resolution, firstLayerReplacedBy);
|
||||
applyNegtiveVolumes(object->model_object()->volumes, object->firstLayerObjSliceMod(), object->firstLayerObjGroupsMod(), scaled_resolution);
|
||||
|
||||
// BBS: the actual first layer slices stored in layers are re-sorted by volume group and will be used to generate brim
|
||||
reGroupingLayerPolygons(object->firstLayerObjGroupsMod(), layers.front()->lslices);
|
||||
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
|
@ -731,127 +891,7 @@ static inline void apply_mm_segmentation(PrintObject &print_object, ThrowOnCance
|
|||
});
|
||||
}
|
||||
|
||||
//BBS: justify whether a volume is connected to another one
|
||||
bool doesVolumeIntersect(VolumeSlices& vs1, VolumeSlices& vs2)
|
||||
{
|
||||
if (vs1.volume_id == vs2.volume_id) return true;
|
||||
if (vs1.slices.size() != vs2.slices.size()) return false;
|
||||
|
||||
for (int i = 0; i != vs1.slices.size(); ++i) {
|
||||
|
||||
if (vs1.slices[i].empty()) continue;
|
||||
if (!vs2.slices[i].empty() && !intersection_ex(vs1.slices[i], vs2.slices[i]).empty()) return true;
|
||||
if (i + 1 != vs2.slices.size() && !vs2.slices[i + 1].empty()) {
|
||||
if (!intersection_ex(vs1.slices[i], vs2.slices[i + 1]).empty()) return true;
|
||||
}
|
||||
if (i - 1 >= 0 && !vs2.slices[i - 1].empty()) {
|
||||
if (!intersection_ex(vs1.slices[i], vs2.slices[i - 1]).empty()) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//BBS: grouping the volumes of an object according to their connection relationship
|
||||
bool groupingVolumes(std::vector<VolumeSlices> objSliceByVolume, std::vector<groupedVolumeSlices>& groups, double resolution)
|
||||
{
|
||||
int existGroups = 0;
|
||||
std::vector<int> groupIndex(objSliceByVolume.size(), -1);
|
||||
|
||||
double offsetValue = 0.15 / SCALING_FACTOR;
|
||||
|
||||
for (int i = 0; i != objSliceByVolume.size(); ++i) {
|
||||
for (int j = 0; j != objSliceByVolume[i].slices.size(); ++j) {
|
||||
objSliceByVolume[i].slices[j] = offset_ex(objSliceByVolume[i].slices[j], offsetValue);
|
||||
for (ExPolygon& poly_ex : objSliceByVolume[i].slices[j])
|
||||
poly_ex.douglas_peucker(resolution);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i != objSliceByVolume.size(); ++i) {
|
||||
if (groupIndex[i] < 0) {
|
||||
groupIndex[i] = i;
|
||||
++existGroups;
|
||||
}
|
||||
for (int j = i + 1; j != objSliceByVolume.size(); ++j) {
|
||||
if (doesVolumeIntersect(objSliceByVolume[i], objSliceByVolume[j])) {
|
||||
if (groupIndex[j] < 0) groupIndex[j] = groupIndex[i];
|
||||
if (groupIndex[j] != groupIndex[i]) {
|
||||
int retain = std::min(groupIndex[i], groupIndex[j]);
|
||||
int cover = std::max(groupIndex[i], groupIndex[j]);
|
||||
for (int k = 0; k != objSliceByVolume.size(); ++k) {
|
||||
if (groupIndex[k] == cover) groupIndex[k] = retain;
|
||||
}
|
||||
--existGroups;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<int> groupVector{};
|
||||
for (int gi : groupIndex) {
|
||||
bool exist = false;
|
||||
for (int gv : groupVector) {
|
||||
if (gv == gi) {
|
||||
exist = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!exist) groupVector.push_back(gi);
|
||||
}
|
||||
|
||||
// group volumes and their slices according to the grouping Vector
|
||||
groups.clear();
|
||||
|
||||
for (int gv : groupVector) {
|
||||
groupedVolumeSlices gvs;
|
||||
gvs.groupId = gv;
|
||||
for (int i = 0; i != objSliceByVolume.size(); ++i) {
|
||||
if (groupIndex[i] == gv) {
|
||||
gvs.volume_ids.push_back(objSliceByVolume[i].volume_id);
|
||||
append(gvs.slices, objSliceByVolume[i].slices.front());
|
||||
}
|
||||
}
|
||||
|
||||
// the slices of a group should be unioned
|
||||
gvs.slices = offset_ex(union_ex(gvs.slices), -offsetValue);
|
||||
for (ExPolygon& poly_ex : gvs.slices)
|
||||
poly_ex.douglas_peucker(resolution);
|
||||
|
||||
groups.push_back(gvs);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//BBS: filter the members of "objSliceByVolume" such that only "model_part" are included
|
||||
std::vector<VolumeSlices> findPartVolumes(const std::vector<VolumeSlices>& objSliceByVolume, ModelVolumePtrs model_volumes) {
|
||||
std::vector<VolumeSlices> outPut;
|
||||
for (const auto& vs : objSliceByVolume) {
|
||||
for (const auto& mv : model_volumes) {
|
||||
if (vs.volume_id == mv->id() && mv->is_model_part()) outPut.push_back(vs);
|
||||
}
|
||||
}
|
||||
return outPut;
|
||||
}
|
||||
|
||||
void applyNegtiveVolumes(ModelVolumePtrs model_volumes, const std::vector<VolumeSlices>& objSliceByVolume, std::vector<groupedVolumeSlices>& groups, double resolution) {
|
||||
ExPolygons negTotal;
|
||||
for (const auto& vs : objSliceByVolume) {
|
||||
for (const auto& mv : model_volumes) {
|
||||
if (vs.volume_id == mv->id() && mv->is_negative_volume()) {
|
||||
if (vs.slices.size() > 0) {
|
||||
append(negTotal, vs.slices.front());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& g : groups) {
|
||||
g.slices = diff_ex(g.slices, negTotal);
|
||||
for (ExPolygon& poly_ex : g.slices)
|
||||
poly_ex.douglas_peucker(resolution);
|
||||
}
|
||||
}
|
||||
// 1) Decides Z positions of the layers,
|
||||
// 2) Initializes layers and their regions
|
||||
// 3) Slices the object meshes
|
||||
|
@ -879,14 +919,8 @@ void PrintObject::slice_volumes()
|
|||
for (const std::unique_ptr<PrintRegion> &pr : m_shared_regions->all_regions)
|
||||
layer->m_regions.emplace_back(new LayerRegion(layer, pr.get()));
|
||||
}
|
||||
// BBS: first layer slices are sorted by volume
|
||||
std::vector<float> slice_zs = zs_from_layers(m_layers);
|
||||
if (!slice_zs.empty()) {
|
||||
firstLayerObjSliceByVolume = slice_volumes_inner(
|
||||
print->config(), this->config(), this->trafo_centered(),
|
||||
this->model_object()->volumes, m_shared_regions->layer_ranges, {slice_zs.front()}, throw_on_cancel_callback);
|
||||
}
|
||||
|
||||
std::vector<float> slice_zs = zs_from_layers(m_layers);
|
||||
std::vector<VolumeSlices> objSliceByVolume;
|
||||
if (!slice_zs.empty()) {
|
||||
objSliceByVolume = slice_volumes_inner(
|
||||
|
@ -895,10 +929,11 @@ void PrintObject::slice_volumes()
|
|||
}
|
||||
|
||||
//BBS: "model_part" volumes are grouded according to their connections
|
||||
const auto scaled_resolution = scaled<double>(print->config().resolution.value);
|
||||
std::vector<VolumeSlices> objSliceByVolumeParts = findPartVolumes(objSliceByVolume, this->model_object()->volumes);
|
||||
groupingVolumes(objSliceByVolumeParts, firstLayerObjSliceByGroups, scaled_resolution);
|
||||
applyNegtiveVolumes(this->model_object()->volumes, objSliceByVolume, firstLayerObjSliceByGroups, scaled_resolution);
|
||||
//const auto scaled_resolution = scaled<double>(print->config().resolution.value);
|
||||
//firstLayerObjSliceByVolume = findPartVolumes(objSliceByVolume, this->model_object()->volumes);
|
||||
//groupingVolumes(objSliceByVolumeParts, firstLayerObjSliceByGroups, scaled_resolution);
|
||||
//applyNegtiveVolumes(this->model_object()->volumes, objSliceByVolume, firstLayerObjSliceByGroups, scaled_resolution);
|
||||
firstLayerObjSliceByVolume = objSliceByVolume;
|
||||
|
||||
std::vector<std::vector<ExPolygons>> region_slices = slices_to_regions(this->model_object()->volumes, *m_shared_regions, slice_zs,
|
||||
std::move(objSliceByVolume),
|
||||
|
|
Loading…
Reference in a new issue