Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ink/strokes/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ cc_library(
"//ink/brush:brush_coat",
"//ink/brush:brush_family",
"//ink/color",
"//ink/geometry:affine_transform",
"//ink/geometry:mutable_mesh",
"//ink/geometry:partitioned_mesh",
"//ink/strokes/input:stroke_input_batch",
Expand Down
1 change: 1 addition & 0 deletions ink/strokes/internal/jni/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ cc_library(
":stroke_jni_helper",
"//ink/brush",
"//ink/brush/internal/jni:brush_native_helper",
"//ink/geometry:affine_transform",
"//ink/geometry:partitioned_mesh",
"//ink/geometry/internal/jni:partitioned_mesh_native_helper",
"//ink/jni/internal:jni_defines",
Expand Down
25 changes: 25 additions & 0 deletions ink/strokes/internal/jni/stroke_jni.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <jni.h>

#include "ink/brush/internal/jni/brush_native_helper.h"
#include "ink/geometry/affine_transform.h"
#include "ink/geometry/internal/jni/partitioned_mesh_native_helper.h"
#include "ink/jni/internal/jni_defines.h"
#include "ink/strokes/internal/jni/stroke_input_jni_helper.h"
Expand Down Expand Up @@ -81,4 +82,28 @@ JNI_METHOD(strokes, StrokeNative, void, free)
DeleteNativeStroke(native_pointer_to_stroke);
}

JNI_METHOD(strokes, StrokeNative, jlongArray, partialErase)
(JNIEnv* env, jobject object, jlong target_stroke_ptr, jlong eraser_shape_ptr,
jfloat eraser_a, jfloat eraser_b, jfloat eraser_c, jfloat eraser_d,
jfloat eraser_e, jfloat eraser_f, jfloat stroke_a, jfloat stroke_b,
jfloat stroke_c, jfloat stroke_d, jfloat stroke_e, jfloat stroke_f) {
ink::AffineTransform eraser_transform(eraser_a, eraser_b, eraser_c, eraser_d,
eraser_e, eraser_f);
ink::AffineTransform stroke_transform(stroke_a, stroke_b, stroke_c, stroke_d,
stroke_e, stroke_f);

std::vector<ink::Stroke> fragments =
CastToStroke(target_stroke_ptr)
.PartialErase(CastToPartitionedMesh(eraser_shape_ptr),
eraser_transform, stroke_transform);

jlongArray result = env->NewLongArray(fragments.size());
jlong* elements = env->GetLongArrayElements(result, nullptr);
for (size_t i = 0; i < fragments.size(); ++i) {
elements[i] = NewNativeStroke(fragments[i]);
}
env->ReleaseLongArrayElements(result, elements, 0);
return result;
}

} // extern "C"
8 changes: 8 additions & 0 deletions ink/strokes/stroke.cc
Original file line number Diff line number Diff line change
Expand Up @@ -212,4 +212,12 @@ void Stroke::RegenerateShape() {
ABSL_DCHECK_EQ(shape_.RenderGroupCount(), brush_.CoatCount());
}

std::vector<Stroke> Stroke::PartialErase(
const PartitionedMesh& eraser_shape,
const AffineTransform& eraser_transform,
const AffineTransform& stroke_transform) const {
// TODO(b/504681427): Implement mesh subtraction.
return {*this};
}

} // namespace ink
14 changes: 14 additions & 0 deletions ink/strokes/stroke.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "ink/brush/brush.h"
#include "ink/brush/brush_family.h"
#include "ink/color/color.h"
#include "ink/geometry/affine_transform.h"
#include "ink/geometry/partitioned_mesh.h"
#include "ink/strokes/input/stroke_input_batch.h"
#include "ink/types/duration.h"
Expand Down Expand Up @@ -108,6 +109,19 @@ class Stroke {
// shape if `inputs` is empty.
void SetInputs(const StrokeInputBatch& inputs);

// Erases the `eraser_shape` from this stroke geometry using the given
// `eraser_transform` and `stroke_transform` that map the eraser and stroke
// to common coordinates.
//
// Each resulting fragment retains the original brush and inputs, but has a
// newly computed shape representing the portion remaining after erasure. The
// order of the fragments in the returned vector is arbitrary and carries no
// guarantee.
std::vector<Stroke> PartialErase(
const PartitionedMesh& eraser_shape,
const AffineTransform& eraser_transform,
const AffineTransform& stroke_transform) const;

private:
// Regenerates the PartitionedMesh.
void RegenerateShape();
Expand Down
14 changes: 14 additions & 0 deletions ink/strokes/stroke_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -608,5 +608,19 @@ void CanConstructStrokeFromAnyInputBatch(const Brush& brush,
FUZZ_TEST(DISABLED_StrokeTest, CanConstructStrokeFromAnyInputBatch)
.WithDomains(ValidBrush(), ArbitraryStrokeInputBatch());

TEST(StrokeTest, PartialEraseWithEmptyEraserShapeReturnsStroke) {
Brush brush = CreateBrush();
Stroke stroke(brush);
PartitionedMesh empty_eraser_shape;
AffineTransform identity = AffineTransform::Identity();

std::vector<Stroke> result =
stroke.PartialErase(empty_eraser_shape, identity, identity);

ASSERT_THAT(result, SizeIs(1));
EXPECT_THAT(result[0].GetBrush(), BrushEq(stroke.GetBrush()));
EXPECT_THAT(result[0].GetInputs(), StrokeInputBatchEq(stroke.GetInputs()));
}

} // namespace
} // namespace ink
Loading