5 #include "flutter/testing/testing.h"
6 #include "gtest/gtest.h"
17 TEST(TessellatorTest, TessellatorBuilderReturnsCorrectResultStatus) {
24 [](
const float* vertices,
size_t vertices_count,
25 const uint16_t* indices,
size_t indices_count) {
return true; });
36 [](
const float* vertices,
size_t vertices_count,
37 const uint16_t* indices,
size_t indices_count) {
return true; });
48 [](
const float* vertices,
size_t vertices_count,
49 const uint16_t* indices,
size_t indices_count) {
return true; });
58 for (
int i = 0; i < 1000; i++) {
59 auto coord = i * 1.0f;
60 builder.
AddLine({coord, coord}, {coord + 1, coord + 1});
65 [](
const float* vertices,
size_t vertices_count,
66 const uint16_t* indices,
size_t indices_count) {
return true; });
77 [](
const float* vertices,
size_t vertices_count,
78 const uint16_t* indices,
size_t indices_count) {
return false; });
84 TEST(TessellatorTest, TessellateConvex) {
86 std::vector<Point> points;
87 std::vector<uint16_t> indices;
95 std::vector<Point> expected = {{0, 0}, {10, 0}, {10, 10}, {0, 10}, {0, 0}};
96 std::vector<uint16_t> expected_indices = {0, 1, 3, 2};
97 EXPECT_EQ(points, expected);
98 EXPECT_EQ(indices, expected_indices);
102 std::vector<Point> points;
103 std::vector<uint16_t> indices;
109 points, indices, 1.0);
111 std::vector<Point> expected = {{0, 0}, {10, 0}, {10, 10}, {0, 10},
112 {0, 0}, {20, 20}, {30, 20}, {30, 30},
114 std::vector<uint16_t> expected_indices = {0, 1, 3, 2, 2, 5, 5, 6, 8, 7};
115 EXPECT_EQ(points, expected);
116 EXPECT_EQ(indices, expected_indices);
121 TEST(TessellatorTest, TessellateConvexUnclosedPath) {
122 std::vector<Point> points;
123 std::vector<uint16_t> indices;
133 std::vector<Point> expected = {{0, 0}, {100, 0}, {100, 100}, {0, 100}};
134 std::vector<uint16_t> expected_indices = {0, 1, 3, 2};
135 EXPECT_EQ(points, expected);
136 EXPECT_EQ(indices, expected_indices);
139 TEST(TessellatorTest, CircleVertexCounts) {
140 auto tessellator = std::make_shared<Tessellator>();
143 auto generator = tessellator->FilledCircle(
transform, {}, radius);
144 size_t quadrant_divisions = generator.GetVertexCount() / 4;
149 double angle =
kPiOver2 / quadrant_divisions;
150 Point first = {radius, 0};
151 Point next = {
static_cast<Scalar>(cos(angle) * radius),
152 static_cast<Scalar>(sin(angle) * radius)};
153 Point midpoint = (first + next) * 0.5;
156 <<
", transform = " <<
transform <<
", radius = " << radius
157 <<
", divisions = " << quadrant_divisions;
170 for (
int i = 36; i < 10000; i += 4) {
175 TEST(TessellatorTest, FilledCircleTessellationVertices) {
176 auto tessellator = std::make_shared<Tessellator>();
180 auto generator = tessellator->FilledCircle(
transform, center, radius);
183 auto vertex_count = generator.GetVertexCount();
184 auto vertices = std::vector<Point>();
185 generator.GenerateVertices([&vertices](
const Point& p) {
186 vertices.push_back(p);
188 EXPECT_EQ(vertices.size(), vertex_count);
189 ASSERT_EQ(vertex_count % 4, 0u);
191 auto quadrant_count = vertex_count / 4;
192 for (
size_t i = 0; i < quadrant_count; i++) {
193 double angle =
kPiOver2 * i / (quadrant_count - 1);
194 double degrees = angle * 180.0 /
kPi;
195 double rsin = sin(angle) * radius;
197 double rcos = (i == quadrant_count - 1) ? 0.0f : cos(angle) * radius;
199 Point(center.x - rcos, center.y + rsin))
200 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
202 Point(center.x - rcos, center.y - rsin))
203 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
205 Point(center.x + rcos, center.y - rsin))
206 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
208 Point(center.x + rcos, center.y + rsin))
209 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
214 test({}, {10, 10}, 2.0);
219 TEST(TessellatorTest, StrokedCircleTessellationVertices) {
220 auto tessellator = std::make_shared<Tessellator>();
224 ASSERT_GT(radius, half_width);
226 tessellator->StrokedCircle(
transform, center, radius, half_width);
229 auto vertex_count = generator.GetVertexCount();
230 auto vertices = std::vector<Point>();
231 generator.GenerateVertices([&vertices](
const Point& p) {
232 vertices.push_back(p);
234 EXPECT_EQ(vertices.size(), vertex_count);
235 ASSERT_EQ(vertex_count % 4, 0u);
237 auto quadrant_count = vertex_count / 8;
240 for (
size_t i = 0; i < quadrant_count; i++) {
241 double angle =
kPiOver2 * i / (quadrant_count - 1);
242 double degrees = angle * 180.0 /
kPi;
243 double rsin = sin(angle) * (radius + half_width);
246 (i == quadrant_count - 1) ? 0.0f : cos(angle) * (radius + half_width);
248 Point(center.x - rcos, center.y - rsin))
249 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
251 Point(center.x + rsin, center.y - rcos))
252 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
254 Point(center.x + rcos, center.y + rsin))
255 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
257 Point(center.x - rsin, center.y + rcos))
258 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
262 for (
size_t i = 0; i < quadrant_count; i++) {
263 double angle =
kPiOver2 * i / (quadrant_count - 1);
264 double degrees = angle * 180.0 /
kPi;
265 double rsin = sin(angle) * (radius - half_width);
268 (i == quadrant_count - 1) ? 0.0f : cos(angle) * (radius - half_width);
270 Point(center.x - rcos, center.y - rsin))
271 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
273 Point(center.x + rsin, center.y - rcos))
274 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
276 Point(center.x + rcos, center.y + rsin))
277 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
279 Point(center.x - rsin, center.y + rcos))
280 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
284 test({}, {}, 2.0, 1.0);
285 test({}, {}, 2.0, 0.5);
286 test({}, {10, 10}, 2.0, 1.0);
291 TEST(TessellatorTest, RoundCapLineTessellationVertices) {
292 auto tessellator = std::make_shared<Tessellator>();
296 auto generator = tessellator->RoundCapLine(
transform, p0, p1, radius);
299 auto vertex_count = generator.GetVertexCount();
300 auto vertices = std::vector<Point>();
301 generator.GenerateVertices([&vertices](
const Point& p) {
302 vertices.push_back(p);
304 EXPECT_EQ(vertices.size(), vertex_count);
305 ASSERT_EQ(vertex_count % 4, 0u);
307 Point along = p1 - p0;
310 along *= radius / length;
314 Point across = {-along.
y, along.
x};
316 auto quadrant_count = vertex_count / 4;
317 for (
size_t i = 0; i < quadrant_count; i++) {
318 double angle =
kPiOver2 * i / (quadrant_count - 1);
319 double degrees = angle * 180.0 /
kPi;
321 Point relative_along =
322 along * ((i == quadrant_count - 1) ? 0.0f : cos(angle));
323 Point relative_across = across * sin(angle);
325 p0 - relative_along + relative_across)
326 <<
"vertex " << i <<
", angle = " << degrees <<
", "
327 <<
"line = " << p0 <<
" => " << p1 <<
", "
328 <<
"radius = " << radius << std::endl;
330 p0 - relative_along - relative_across)
331 <<
"vertex " << i <<
", angle = " << degrees <<
", "
332 <<
"line = " << p0 <<
" => " << p1 <<
", "
333 <<
"radius = " << radius << std::endl;
335 p1 + relative_along - relative_across)
336 <<
"vertex " << i <<
", angle = " << degrees <<
", "
337 <<
"line = " << p0 <<
" => " << p1 <<
", "
338 <<
"radius = " << radius << std::endl;
340 p1 + relative_along + relative_across)
341 <<
"vertex " << i <<
", angle = " << degrees <<
", "
342 <<
"line = " << p0 <<
" => " << p1 <<
", "
343 <<
"radius = " << radius << std::endl;
349 test({}, {0, 0}, {0, 0}, 10);
351 test({}, {0, 0}, {10, 0}, 2);
352 test({}, {10, 0}, {0, 0}, 2);
353 test({}, {0, 0}, {10, 10}, 2);
364 TEST(TessellatorTest, FilledEllipseTessellationVertices) {
365 auto tessellator = std::make_shared<Tessellator>();
368 auto center = bounds.GetCenter();
369 auto half_size = bounds.GetSize() * 0.5f;
371 auto generator = tessellator->FilledEllipse(
transform, bounds);
374 auto vertex_count = generator.GetVertexCount();
375 auto vertices = std::vector<Point>();
376 generator.GenerateVertices([&vertices](
const Point& p) {
377 vertices.push_back(p);
379 EXPECT_EQ(vertices.size(), vertex_count);
380 ASSERT_EQ(vertex_count % 4, 0u);
382 auto quadrant_count = vertex_count / 4;
383 for (
size_t i = 0; i < quadrant_count; i++) {
384 double angle =
kPiOver2 * i / (quadrant_count - 1);
385 double degrees = angle * 180.0 /
kPi;
388 (i == quadrant_count - 1) ? 0.0f : cos(angle) * half_size.width;
389 double rsin = sin(angle) * half_size.height;
391 Point(center.x - rcos, center.y + rsin))
392 <<
"vertex " << i <<
", angle = " << degrees <<
", "
393 <<
"bounds = " << bounds << std::endl;
395 Point(center.x - rcos, center.y - rsin))
396 <<
"vertex " << i <<
", angle = " << degrees <<
", "
397 <<
"bounds = " << bounds << std::endl;
399 Point(center.x + rcos, center.y - rsin))
400 <<
"vertex " << i <<
", angle = " << degrees <<
", "
401 <<
"bounds = " << bounds << std::endl;
403 Point(center.x + rcos, center.y + rsin))
404 <<
"vertex " << i <<
", angle = " << degrees <<
", "
405 <<
"bounds = " << bounds << std::endl;
425 TEST(TessellatorTest, FilledRoundRectTessellationVertices) {
426 auto tessellator = std::make_shared<Tessellator>();
430 FML_DCHECK(radii.width * 2 <= bounds.GetWidth()) << radii << bounds;
431 FML_DCHECK(radii.height * 2 <= bounds.GetHeight()) << radii << bounds;
433 Scalar middle_left = bounds.GetX() + radii.width;
434 Scalar middle_top = bounds.GetY() + radii.height;
435 Scalar middle_right = bounds.GetX() + bounds.GetWidth() - radii.width;
436 Scalar middle_bottom = bounds.GetY() + bounds.GetHeight() - radii.height;
438 auto generator = tessellator->FilledRoundRect(
transform, bounds, radii);
441 auto vertex_count = generator.GetVertexCount();
442 auto vertices = std::vector<Point>();
443 generator.GenerateVertices([&vertices](
const Point& p) {
444 vertices.push_back(p);
446 EXPECT_EQ(vertices.size(), vertex_count);
447 ASSERT_EQ(vertex_count % 4, 0u);
449 auto quadrant_count = vertex_count / 4;
450 for (
size_t i = 0; i < quadrant_count; i++) {
451 double angle =
kPiOver2 * i / (quadrant_count - 1);
452 double degrees = angle * 180.0 /
kPi;
454 double rcos = (i == quadrant_count - 1) ? 0.0f : cos(angle) * radii.width;
455 double rsin = sin(angle) * radii.height;
457 Point(middle_left - rcos, middle_bottom + rsin))
458 <<
"vertex " << i <<
", angle = " << degrees <<
", "
459 <<
"bounds = " << bounds << std::endl;
461 Point(middle_left - rcos, middle_top - rsin))
462 <<
"vertex " << i <<
", angle = " << degrees <<
", "
463 <<
"bounds = " << bounds << std::endl;
465 Point(middle_right + rcos, middle_top - rsin))
466 <<
"vertex " << i <<
", angle = " << degrees <<
", "
467 <<
"bounds = " << bounds << std::endl;
469 Point(middle_right + rcos, middle_bottom + rsin))
470 <<
"vertex " << i <<
", angle = " << degrees <<
", "
471 <<
"bounds = " << bounds << std::endl;
499 TEST(TessellatorTest, EarlyReturnEmptyConvexShape) {
504 builder.
MoveTo({10, 10},
true);
506 std::vector<Point> points;
507 std::vector<uint16_t> indices;
511 EXPECT_TRUE(points.empty());
515 TEST(TessellatorTest, ChecksConcurrentPolylineUsage) {
516 auto tessellator = std::make_shared<Tessellator>();
518 builder.
AddLine({0, 0}, {100, 100});
521 auto polyline = tessellator->CreateTempPolyline(path, 0.1);
522 EXPECT_DEBUG_DEATH(tessellator->CreateTempPolyline(path, 0.1),
Path TakePath(FillType fill=FillType::kNonZero)
PathBuilder & LineTo(Point point, bool relative=false)
Insert a line from the current position to point.
PathBuilder & MoveTo(Point point, bool relative=false)
PathBuilder & AddRect(const Rect &rect)
PathBuilder & AddLine(const Point &p1, const Point &p2)
Move to point p1, then insert a line from p1 to p2.
Paths are lightweight objects that describe a collection of linear, quadratic, or cubic segments....
static constexpr Scalar kCircleTolerance
The pixel tolerance used by the algorighm to determine how many divisions to create for a circle.
static void TessellateConvexInternal(const Path &path, std::vector< Point > &point_buffer, std::vector< uint16_t > &index_buffer, Scalar tolerance)
An extended tessellator that offers arbitrary/concave tessellation via the libtess2 library.
TessellatorLibtess::Result Tessellate(const Path &path, Scalar tolerance, const BuilderCallback &callback)
Generates filled triangles from the path. A callback is invoked once for the entire tessellation.
#define EXPECT_POINT_NEAR(a, b)
TEST(AllocationSizeTest, CanCreateTypedAllocations)
void LineTo(PathBuilder *builder, Scalar x, Scalar y)
const Path::Polyline & polyline
A 4x4 matrix using column-major storage.
static constexpr Matrix MakeScale(const Vector3 &s)
constexpr Type GetLength() const
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)
constexpr static TRect MakeLTRB(Type left, Type top, Type right, Type bottom)