Added more limits to eraser to decrease chance of generating bad geometry

This commit is contained in:
Yousef Khadadeh 2026-05-29 18:20:06 +03:00
parent d901597391
commit 121a6b05aa
3 changed files with 10 additions and 7 deletions

View file

@ -148,12 +148,14 @@ void CanvasComponentContainer::commit_transform_dont_invalidate_cache() {
calculate_world_bounds();
}
CanvasComponentEraseDetailResult CanvasComponentContainer::collides_with_erase_detail(const CoordSpaceHelper& camCoords, const SkPath& checkAgainstCam) const {
// camCoordsScaleToCheckAgainst is different from camCoords.inverseScale if we locked the eraser's scale.
CanvasComponentEraseDetailResult CanvasComponentContainer::collides_with_erase_detail(const CoordSpaceHelper& camCoords, const WorldScalar& camCoordsScaleToCheckAgainst, const SkPath& checkAgainstCam) const {
constexpr static int COMP_MAX_SHIFT_BEFORE_STOP_ERASE = 3;
if(!worldAABB.has_value())
return CanvasComponentEraseDetailResult::NO_CHANGE;
if((camCoords.inverseScale << COMP_MAX_SHIFT_BEFORE_STOP_ERASE) < coords.inverseScale) // Object is too large, just dismiss the collision
if((camCoordsScaleToCheckAgainst << COMP_MAX_SHIFT_BEFORE_STOP_ERASE) < coords.inverseScale) // Object is too large, just dismiss the collision
return CanvasComponentEraseDetailResult::NO_CHANGE;
else if(coords.inverseScale < (camCoords.inverseScale >> COMP_COLLIDE_MIN_SHIFT_TINY)) {
else if(coords.inverseScale < (camCoordsScaleToCheckAgainst >> COMP_COLLIDE_MIN_SHIFT_TINY)) {
if(checkAgainstCam.contains(convert_vec2<SkPoint>(camCoords.to_space(worldAABB.value().min))))
return CanvasComponentEraseDetailResult::REMOVED;
return CanvasComponentEraseDetailResult::NO_CHANGE;
@ -170,7 +172,6 @@ CanvasComponentEraseDetailResult CanvasComponentContainer::collides_with_erase_d
return CanvasComponentEraseDetailResult::NO_CHANGE;
}
// We could just send one of the checkAgainst colliders, since they represent the same thing, but sending both saves on redundant transformations, since we can save both of the versions on the executor side
bool CanvasComponentContainer::collides_with(const CoordSpaceHelper& camCoords, const SkPath& checkAgainstCam) const {
if(!worldAABB.has_value())
return false;

View file

@ -44,7 +44,6 @@ class CanvasComponentContainer {
typedef NetworkingObjects::NetObjOrderedListObjectInfo<CanvasComponentContainer> ObjInfo;
typedef NetworkingObjects::NetObjOrderedListIterator<CanvasComponentContainer> ObjInfoIterator;
constexpr static int COMP_MAX_SHIFT_BEFORE_STOP_ERASE = 7;
constexpr static int COMP_MAX_SHIFT_BEFORE_STOP_COLLISIONS = 14;
constexpr static int COMP_MAX_SHIFT_BEFORE_STOP_SCALING = 14;
constexpr static float COMP_MAX_BEFORE_STOP_SCALING = 1 << COMP_MAX_SHIFT_BEFORE_STOP_SCALING;
@ -91,7 +90,7 @@ class CanvasComponentContainer {
void commit_transform(DrawingProgram& drawP);
void commit_update_dont_invalidate_cache(DrawingProgram& drawP); // Must be thread safe
bool should_draw(const DrawData& drawData) const;
CanvasComponentEraseDetailResult collides_with_erase_detail(const CoordSpaceHelper& camCoords, const SkPath& checkAgainstCam) const;
CanvasComponentEraseDetailResult collides_with_erase_detail(const CoordSpaceHelper& camCoords, const WorldScalar& camCoordsScaleToCheckAgainst, const SkPath& checkAgainstCam) const;
bool collides_with(const CoordSpaceHelper& camCoords, const SkPath& checkAgainstCam) const;
bool collides_with_point(const CoordSpaceHelper& camCoords, const Vector2f& checkAgainstCam) const;
void send_comp_update(DrawingProgram& drawP, bool finalUpdate);

View file

@ -124,6 +124,9 @@ void EraserTool::input_pen_axis_callback(const InputManager::PenAxisCallbackArgs
void EraserTool::erase_on_path() {
auto cCWorldBounds = genData.coords.collider_to_world<SCollision::AABB<WorldScalar>, SCollision::AABB<float>>(erasePath.getBounds());
WorldScalar eraseScaleToCheckAgainst = WorldScalar(drawP.world.main.toolConfig.get_relative_width_stroke_size(drawP, genData.coords.inverseScale).first.value()) * genData.coords.inverseScale;
if(eraseScaleToCheckAgainst == WorldScalar(0))
return;
drawP.drawCache.traverse_bvh_run_function(cCWorldBounds, [&](const auto& bvhNode) {
if(bvhNode &&
erasePath.contains(convert_vec2<SkPoint>(genData.coords.to_space(bvhNode->bounds.min))) &&
@ -152,7 +155,7 @@ void EraserTool::erase_on_path() {
if(drawP.world.main.toolConfig.eraser.eraseDetail) {
if(drawP.layerMan.component_passes_layer_selector(c, drawP.controls.layerSelector)) {
auto dataCopy = c->obj->get_comp().get_data_copy();
CanvasComponentEraseDetailResult result = c->obj->collides_with_erase_detail(genData.coords, erasePath);
CanvasComponentEraseDetailResult result = c->obj->collides_with_erase_detail(genData.coords, eraseScaleToCheckAgainst, erasePath);
switch(result) {
case CanvasComponentEraseDetailResult::NO_CHANGE:
return false;