9#include "gtest/gtest.h"
20 std::vector<impeller::Point> a,
21 std::vector<impeller::Point> b) {
22 if (a.size() != b.size()) {
23 return ::testing::AssertionFailure() <<
"Colors length does not match";
25 for (
auto i = 0u;
i < b.size();
i++) {
27 return ::testing::AssertionFailure() <<
"Positions are not equal.";
30 return ::testing::AssertionSuccess();
34 std::vector<impeller::TextureFillVertexShader::PerVertexData> a,
35 std::vector<impeller::TextureFillVertexShader::PerVertexData> b) {
36 if (a.size() != b.size()) {
37 return ::testing::AssertionFailure() <<
"Colors length does not match";
39 for (
auto i = 0u;
i < b.size();
i++) {
41 return ::testing::AssertionFailure() <<
"Positions are not equal.";
43 if (!
PointNear(a[
i].texture_coords, b[
i].texture_coords)) {
44 return ::testing::AssertionFailure() <<
"Texture coords are not equal.";
47 return ::testing::AssertionSuccess();
50#define EXPECT_SOLID_VERTICES_NEAR(a, b) \
51 EXPECT_PRED2(&::SolidVerticesNear, a, b)
52#define EXPECT_TEXTURE_VERTICES_NEAR(a, b) \
53 EXPECT_PRED2(&::TextureVerticesNear, a, b)
66 return StrokePathGeometry::GenerateSolidStrokeVertices(
67 tessellator, path, stroke, scale);
73TEST(EntityGeometryTest, RectGeometryCoversArea) {
75 ASSERT_TRUE(geometry->CoversArea({},
Rect::MakeLTRB(0, 0, 100, 100)));
76 ASSERT_FALSE(geometry->CoversArea({},
Rect::MakeLTRB(-1, 0, 100, 100)));
77 ASSERT_TRUE(geometry->CoversArea({},
Rect::MakeLTRB(1, 1, 100, 100)));
78 ASSERT_TRUE(geometry->CoversArea({},
Rect()));
81TEST(EntityGeometryTest, FillPathGeometryCoversArea) {
87 ASSERT_TRUE(geometry->CoversArea({},
Rect::MakeLTRB(0, 0, 100, 100)));
88 ASSERT_FALSE(geometry->CoversArea({},
Rect::MakeLTRB(-1, 0, 100, 100)));
89 ASSERT_TRUE(geometry->CoversArea({},
Rect::MakeLTRB(1, 1, 100, 100)));
90 ASSERT_TRUE(geometry->CoversArea({},
Rect()));
93TEST(EntityGeometryTest, FillPathGeometryCoversAreaNoInnerRect) {
98 ASSERT_FALSE(geometry->CoversArea({},
Rect::MakeLTRB(0, 0, 100, 100)));
99 ASSERT_FALSE(geometry->CoversArea({},
Rect::MakeLTRB(-1, 0, 100, 100)));
100 ASSERT_FALSE(geometry->CoversArea({},
Rect::MakeLTRB(1, 1, 100, 100)));
101 ASSERT_FALSE(geometry->CoversArea({},
Rect()));
104TEST(EntityGeometryTest, FillArcGeometryCoverage) {
112 for (
int sweep = 360; sweep <= 720; sweep += 30) {
114 "start: " + std::to_string(
start) +
" + " + std::to_string(sweep);
117 EXPECT_EQ(geometry->GetCoverage({}), oval_bounds)
118 <<
"start: " <<
start <<
", sweep: " << sweep;
121 EXPECT_EQ(geometry->GetCoverage({}), oval_bounds)
122 <<
"start: " <<
start <<
", sweep: " << -sweep;
125 EXPECT_EQ(geometry->GetCoverage({}), oval_bounds)
126 <<
"start: " <<
start <<
", sweep: " << -sweep <<
", with center";
134 EXPECT_EQ(geometry->GetCoverage({}), oval_bounds)
135 <<
"start: " <<
start <<
" without center";
138 EXPECT_EQ(geometry->GetCoverage({}), oval_bounds)
139 <<
"start: " <<
start <<
" with center";
146 EXPECT_EQ(geometry->GetCoverage({}), oval_bounds)
147 <<
"start: " <<
start <<
" without center";
150 EXPECT_EQ(geometry->GetCoverage({}), oval_bounds)
151 <<
"start: " <<
start <<
" with center";
165 <<
"start: " <<
start - 45;
176 <<
"start: " <<
start + 45;
187 <<
"start: " <<
start + 135;
198 <<
"start: " <<
start + 225;
213 <<
"start: " <<
start - 45;
224 <<
"start: " <<
start + 45;
235 <<
"start: " <<
start + 135;
246 <<
"start: " <<
start + 225;
253 ASSERT_TRUE(oval_bounds.TransformBounds(transform45).Contains(oval_bounds));
255 EXPECT_TRUE(geometry->GetCoverage(transform45)
257 .Contains(oval_bounds));
262 ASSERT_TRUE(oval_bounds.TransformBounds(transform45).Contains(oval_bounds));
264 EXPECT_TRUE(geometry->GetCoverage(transform45)
266 .Contains(oval_bounds));
270TEST(EntityGeometryTest, StrokeArcGeometryCoverage) {
290 for (
int sweep = 360; sweep <= 720; sweep += 30) {
292 "start: " + std::to_string(
start) +
" + " + std::to_string(sweep);
295 EXPECT_EQ(geometry->GetCoverage({}), expanded_bounds)
296 <<
"start: " <<
start <<
", sweep: " << sweep;
299 EXPECT_EQ(geometry->GetCoverage({}), expanded_bounds)
300 <<
"start: " <<
start <<
", sweep: " << -sweep;
302 Degrees(-sweep), square_params);
303 EXPECT_EQ(geometry->GetCoverage({}), expanded_bounds)
304 <<
"start: " <<
start <<
", sweep: " << -sweep <<
", square caps";
312 EXPECT_EQ(geometry->GetCoverage({}), expanded_bounds)
313 <<
"start: " <<
start <<
", butt caps";
316 EXPECT_EQ(geometry->GetCoverage({}), squared_bounds)
317 <<
"start: " <<
start <<
", square caps";
324 EXPECT_EQ(geometry->GetCoverage({}), expanded_bounds)
325 <<
"start: " <<
start <<
" without center";
328 EXPECT_EQ(geometry->GetCoverage({}), squared_bounds)
329 <<
"start: " <<
start <<
" with center";
343 <<
"start: " <<
start - 45;
354 <<
"start: " <<
start + 45;
365 <<
"start: " <<
start + 135;
376 <<
"start: " <<
start + 225;
392 <<
"start: " <<
start - 45;
403 <<
"start: " <<
start + 45;
414 <<
"start: " <<
start + 135;
425 <<
"start: " <<
start + 225;
433 oval_bounds.TransformBounds(transform45).Contains(expanded_bounds));
435 EXPECT_TRUE(geometry->GetCoverage(transform45)
437 .Contains(expanded_bounds));
443 oval_bounds.TransformBounds(transform45).Contains(expanded_bounds));
445 EXPECT_TRUE(geometry->GetCoverage(transform45)
447 .Contains(squared_bounds));
453 oval_bounds.TransformBounds(transform45).Contains(expanded_bounds));
455 EXPECT_TRUE(geometry->GetCoverage(transform45)
457 .Contains(expanded_bounds));
463 oval_bounds.TransformBounds(transform45).Contains(expanded_bounds));
465 EXPECT_TRUE(geometry->GetCoverage(transform45)
467 .Contains(squared_bounds));
471TEST(EntityGeometryTest, FillRoundRectGeometryCoversArea) {
476 .top_right =
Size(2, 12),
477 .bottom_left =
Size(3, 13),
478 .bottom_right =
Size(4, 14),
483 EXPECT_TRUE(geom.CoversArea({},
Rect::MakeLTRB(103, 100, 196, 200)));
484 EXPECT_FALSE(geom.CoversArea({},
Rect::MakeLTRB(102, 100, 196, 200)));
485 EXPECT_FALSE(geom.CoversArea({},
Rect::MakeLTRB(103, 99, 196, 200)));
486 EXPECT_FALSE(geom.CoversArea({},
Rect::MakeLTRB(103, 100, 197, 200)));
487 EXPECT_FALSE(geom.CoversArea({},
Rect::MakeLTRB(103, 100, 196, 201)));
490 EXPECT_TRUE(geom.CoversArea({},
Rect::MakeLTRB(100, 112, 200, 186)));
491 EXPECT_FALSE(geom.CoversArea({},
Rect::MakeLTRB(99, 112, 200, 186)));
492 EXPECT_FALSE(geom.CoversArea({},
Rect::MakeLTRB(100, 111, 200, 186)));
493 EXPECT_FALSE(geom.CoversArea({},
Rect::MakeLTRB(100, 112, 201, 186)));
494 EXPECT_FALSE(geom.CoversArea({},
Rect::MakeLTRB(100, 112, 200, 187)));
497TEST(EntityGeometryTest, LineGeometryCoverage) {
500 {10, 10}, {20, 10}, {.width = 2, .cap =
Cap::kButt});
501 EXPECT_EQ(geometry->GetCoverage({}),
Rect::MakeLTRB(10, 9, 20, 11));
502 EXPECT_TRUE(geometry->CoversArea({},
Rect::MakeLTRB(10, 9, 20, 11)));
508 EXPECT_EQ(geometry->GetCoverage({}),
Rect::MakeLTRB(9, 9, 21, 11));
509 EXPECT_TRUE(geometry->CoversArea({},
Rect::MakeLTRB(9, 9, 21, 11)));
514 {10, 10}, {10, 20}, {.width = 2, .cap =
Cap::kButt});
515 EXPECT_EQ(geometry->GetCoverage({}),
Rect::MakeLTRB(9, 10, 11, 20));
516 EXPECT_TRUE(geometry->CoversArea({},
Rect::MakeLTRB(9, 10, 11, 20)));
522 EXPECT_EQ(geometry->GetCoverage({}),
Rect::MakeLTRB(9, 9, 11, 21));
523 EXPECT_TRUE(geometry->CoversArea({},
Rect::MakeLTRB(9, 9, 11, 21)));
527TEST(EntityGeometryTest, RoundRectGeometryCoversArea) {
530 EXPECT_FALSE(geometry->CoversArea({},
Rect::MakeLTRB(15, 15, 85, 85)));
531 EXPECT_TRUE(geometry->CoversArea({},
Rect::MakeLTRB(20, 20, 80, 80)));
532 EXPECT_TRUE(geometry->CoversArea({},
Rect::MakeLTRB(30, 1, 70, 99)));
533 EXPECT_TRUE(geometry->CoversArea({},
Rect::MakeLTRB(1, 30, 99, 70)));
536TEST(EntityGeometryTest, GeometryResultHasReasonableDefaults) {
543TEST(EntityGeometryTest, AlphaCoverageStrokePaths) {
546 ->ComputeAlphaCoverage(matrix),
549 ->ComputeAlphaCoverage(matrix),
552 ->ComputeAlphaCoverage(matrix),
555 ->ComputeAlphaCoverage(matrix),
558 ->ComputeAlphaCoverage(matrix),
561 ->ComputeAlphaCoverage(matrix),
564 ->ComputeAlphaCoverage(matrix),
568TEST(EntityGeometryTest, SimpleTwoLineStrokeVerticesButtCap) {
570 path_builder.
MoveTo({20, 20});
571 path_builder.
LineTo({30, 20});
572 path_builder.
MoveTo({120, 20});
573 path_builder.
LineTo({130, 20});
586 std::vector<Point> expected = {
606 EXPECT_EQ(
points, expected);
609TEST(EntityGeometryTest, SimpleTwoLineStrokeVerticesRoundCap) {
611 path_builder.
MoveTo({20, 20});
612 path_builder.
LineTo({30, 20});
613 path_builder.
MoveTo({120, 20});
614 path_builder.
LineTo({130, 20});
627 size_t count =
points.size();
628 ASSERT_TRUE((count & 0x1) == 0x0);
636 ASSERT_EQ(
points.size(), 40u);
642 auto offset = [](
int step,
bool left,
bool backwards) ->
Point {
646 Point center = backwards ? -along : along;
647 return left ? center + across : center - across;
652 EXPECT_EQ(
points[1],
Point(20, 20) + offset(1,
true,
true));
653 EXPECT_EQ(
points[2],
Point(20, 20) + offset(1,
false,
true));
654 EXPECT_EQ(
points[3],
Point(20, 20) + offset(2,
true,
true));
655 EXPECT_EQ(
points[4],
Point(20, 20) + offset(2,
false,
true));
656 EXPECT_EQ(
points[5],
Point(20, 20) + offset(3,
true,
true));
657 EXPECT_EQ(
points[6],
Point(20, 20) + offset(3,
false,
true));
662 EXPECT_EQ(
points[11],
Point(30, 20) + offset(3,
true,
false));
663 EXPECT_EQ(
points[12],
Point(30, 20) + offset(3,
false,
false));
664 EXPECT_EQ(
points[13],
Point(30, 20) + offset(2,
true,
false));
665 EXPECT_EQ(
points[14],
Point(30, 20) + offset(2,
false,
false));
666 EXPECT_EQ(
points[15],
Point(30, 20) + offset(1,
true,
false));
667 EXPECT_EQ(
points[16],
Point(30, 20) + offset(1,
false,
false));
678 EXPECT_EQ(
points[23],
Point(120, 20) + offset(1,
true,
true));
679 EXPECT_EQ(
points[24],
Point(120, 20) + offset(1,
false,
true));
680 EXPECT_EQ(
points[25],
Point(120, 20) + offset(2,
true,
true));
681 EXPECT_EQ(
points[26],
Point(120, 20) + offset(2,
false,
true));
682 EXPECT_EQ(
points[27],
Point(120, 20) + offset(3,
true,
true));
683 EXPECT_EQ(
points[28],
Point(120, 20) + offset(3,
false,
true));
688 EXPECT_EQ(
points[33],
Point(130, 20) + offset(3,
true,
false));
689 EXPECT_EQ(
points[34],
Point(130, 20) + offset(3,
false,
false));
690 EXPECT_EQ(
points[35],
Point(130, 20) + offset(2,
true,
false));
691 EXPECT_EQ(
points[36],
Point(130, 20) + offset(2,
false,
false));
692 EXPECT_EQ(
points[37],
Point(130, 20) + offset(1,
true,
false));
693 EXPECT_EQ(
points[38],
Point(130, 20) + offset(1,
false,
false));
697TEST(EntityGeometryTest, SimpleTwoLineStrokeVerticesSquareCap) {
699 path_builder.
MoveTo({20, 20});
700 path_builder.
LineTo({30, 20});
701 path_builder.
MoveTo({120, 20});
702 path_builder.
LineTo({130, 20});
716 std::vector<Point> expected = {
745 EXPECT_EQ(
points, expected);
748TEST(EntityGeometryTest, TwoLineSegmentsRightTurnStrokeVerticesBevelJoin) {
750 path_builder.
MoveTo({20, 20});
751 path_builder.
LineTo({30, 20});
752 path_builder.
LineTo({30, 30});
765 std::vector<Point> expected = {
779 EXPECT_EQ(
points, expected);
782TEST(EntityGeometryTest, TwoLineSegmentsLeftTurnStrokeVerticesBevelJoin) {
784 path_builder.
MoveTo({20, 20});
785 path_builder.
LineTo({30, 20});
786 path_builder.
LineTo({30, 10});
799 std::vector<Point> expected = {
813 EXPECT_EQ(
points, expected);
816TEST(EntityGeometryTest, TwoLineSegmentsRightTurnStrokeVerticesMiterJoin) {
818 path_builder.
MoveTo({20, 20});
819 path_builder.
LineTo({30, 20});
820 path_builder.
LineTo({30, 30});
833 std::vector<Point> expected = {
850 EXPECT_EQ(
points, expected);
853TEST(EntityGeometryTest, TwoLineSegmentsLeftTurnStrokeVerticesMiterJoin) {
855 path_builder.
MoveTo({20, 20});
856 path_builder.
LineTo({30, 20});
857 path_builder.
LineTo({30, 10});
870 std::vector<Point> expected = {
887 EXPECT_EQ(
points, expected);
890TEST(EntityGeometryTest, TinyQuadGeneratesCaps) {
892 path_builder.
MoveTo({20, 20});
906 std::vector<Point> expected = {
924 EXPECT_EQ(
points, expected);
927TEST(EntityGeometryTest, TinyConicGeneratesCaps) {
929 path_builder.
MoveTo({20, 20});
930 path_builder.
ConicCurveTo({20.125, 20}, {20.250, 20}, 0.6);
943 std::vector<Point> expected = {
961 EXPECT_EQ(
points, expected);
964TEST(EntityGeometryTest, TinyCubicGeneratesCaps) {
966 path_builder.
MoveTo({20, 20});
967 path_builder.
CubicCurveTo({20.0625, 20}, {20.125, 20}, {20.250, 20});
980 std::vector<Point> expected = {
998 EXPECT_EQ(
points, expected);
1001TEST(EntityGeometryTest, TwoLineSegmentsMiterLimit) {
1003 for (
int degrees = 10; degrees < 180; degrees += 10) {
1011 if (pixel_delta.GetDistance(
Point(1, 0)) *
width < 1.0f) {
1020 Degrees between(180 - degrees);
1027 path_builder.
LineTo(
Point(30, 20) + pixel_delta * 10.0f);
1038 .miter_limit = limit * 0.99f,
1041 EXPECT_EQ(points1.size(), 8u)
1042 <<
"degrees: " << degrees <<
", width: " <<
width <<
", "
1053 .miter_limit = limit * 1.01f,
1056 EXPECT_EQ(points2.size(), 9u)
1057 <<
"degrees: " << degrees <<
", width: " <<
width;
1058 EXPECT_LE(points2[4].GetDistance({30, 20}),
width * limit * 1.05f)
1059 <<
"degrees: " << degrees <<
", width: " <<
width <<
", "
1065TEST(EntityGeometryTest, TwoLineSegments180DegreeJoins) {
1080 .miter_limit = 4.0f,
1084 EXPECT_EQ(points_bevel.size(), 8u);
1093 .miter_limit = 400.0f,
1097 EXPECT_EQ(points_miter.size(), 8u);
1106 .miter_limit = 4.0f,
1110 EXPECT_EQ(points_round.size(), 19u);
1113TEST(EntityGeometryTest, TightQuadratic180DegreeJoins) {
1121 auto points_bevel_reference =
1128 .miter_limit = 4.0f,
1132 EXPECT_EQ(points_bevel_reference.size(), 74u);
1147 .miter_limit = 4.0f,
1151 EXPECT_GT(points_bevel.size(), points_bevel_reference.size());
1160 .miter_limit = 400.0f,
1164 EXPECT_GT(points_miter.size(), points_bevel_reference.size());
1173 .miter_limit = 4.0f,
1177 EXPECT_GT(points_round.size(), points_bevel_reference.size());
1180TEST(EntityGeometryTest, TightConic180DegreeJoins) {
1188 auto points_bevel_reference =
1195 .miter_limit = 4.0f,
1199 EXPECT_EQ(points_bevel_reference.size(), 78u);
1214 .miter_limit = 4.0f,
1218 EXPECT_GT(points_bevel.size(), points_bevel_reference.size());
1227 .miter_limit = 400.0f,
1231 EXPECT_GT(points_miter.size(), points_bevel_reference.size());
1240 .miter_limit = 4.0f,
1244 EXPECT_GT(points_round.size(), points_bevel_reference.size());
1247TEST(EntityGeometryTest, TightCubic180DegreeJoins) {
1256 auto points_reference =
1263 .miter_limit = 4.0f,
1267 EXPECT_EQ(points_reference.size(), 76u);
1282 .miter_limit = 4.0f,
1286 EXPECT_GT(points_bevel.size(), points_reference.size());
1295 .miter_limit = 400.0f,
1299 EXPECT_GT(points_miter.size(), points_reference.size());
1308 .miter_limit = 4.0f,
1312 EXPECT_GT(points_round.size(), points_reference.size());
1315TEST(EntityGeometryTest, RotatedFilledCircleGeometryCoverage) {
1319 ASSERT_EQ(geometry->GetCoverage({}).value_or(
Rect()), circle_bounds);
1325 EXPECT_TRUE(geometry->GetCoverage(transform45).has_value());
1326 Rect bounds = geometry->GetCoverage(transform45).value_or(
Rect());
1327 EXPECT_TRUE(bounds.Contains(circle_bounds))
1328 <<
"geometry bounds: " << bounds << std::endl
1329 <<
" circle bounds: " << circle_bounds;
1332TEST(EntityGeometryTest, RotatedStrokedCircleGeometryCoverage) {
1336 ASSERT_EQ(geometry->GetCoverage({}).value_or(
Rect()), circle_bounds);
1342 EXPECT_TRUE(geometry->GetCoverage(transform45).has_value());
1343 Rect bounds = geometry->GetCoverage(transform45).value_or(
Rect());
1344 EXPECT_TRUE(bounds.Contains(circle_bounds))
1345 <<
"geometry bounds: " << bounds << std::endl
1346 <<
" circle bounds: " << circle_bounds;
DlPathBuilder & LineTo(DlPoint p2)
Draw a line from the current point to the indicated point p2.
DlPathBuilder & MoveTo(DlPoint p2)
Start a new contour that will originate at the indicated point p2.
const DlPath TakePath()
Returns the path constructed by this path builder and resets its internal state to the default state ...
DlPathBuilder & ConicCurveTo(DlPoint cp, DlPoint p2, DlScalar weight)
Draw a conic curve (a rational quadratic bezier curve) from the current point to the indicated point ...
DlPathBuilder & AddRect(const DlRect &rect)
Append a closed rectangular contour to the path.
DlPathBuilder & QuadraticCurveTo(DlPoint cp, DlPoint p2)
Draw a quadratic bezier curve from the current point to the indicated point p2, using the indicated p...
DlPathBuilder & CubicCurveTo(DlPoint cp1, DlPoint cp2, DlPoint p2)
Draw a cubic bezier curve from the current point to the indicated point p2, using the indicated point...
A Geometry class that produces fillable vertices from any |RoundRect| object regardless of radii unif...
static std::unique_ptr< Geometry > MakeFillPath(const flutter::DlPath &path, std::optional< Rect > inner_rect=std::nullopt)
static std::unique_ptr< Geometry > MakeRect(const Rect &rect)
static std::unique_ptr< Geometry > MakeFilledArc(const Rect &oval_bounds, Degrees start, Degrees sweep, bool include_center)
static std::unique_ptr< Geometry > MakeStrokePath(const flutter::DlPath &path, const StrokeParameters &stroke={})
static std::unique_ptr< Geometry > MakeCircle(const Point ¢er, Scalar radius)
static std::unique_ptr< Geometry > MakeRoundRect(const Rect &rect, const Size &radii)
static std::unique_ptr< Geometry > MakeLine(const Point &p0, const Point &p1, const StrokeParameters &stroke)
static std::unique_ptr< Geometry > MakeStrokedCircle(const Point ¢er, Scalar radius, Scalar stroke_width)
static std::unique_ptr< Geometry > MakeStrokedArc(const Rect &oval_bounds, Degrees start, Degrees sweep, const StrokeParameters &stroke)
static std::vector< Point > GenerateSolidStrokeVertices(const PathSource &path, const StrokeParameters &stroke, Scalar scale)
A utility that generates triangles of the specified fill type given a polyline. This happens on the C...
inline ::testing::AssertionResult PointNear(impeller::Point a, impeller::Point b)
#define EXPECT_RECT_NEAR(a, b)
inline ::testing::AssertionResult SolidVerticesNear(std::vector< impeller::Point > a, std::vector< impeller::Point > b)
inline ::testing::AssertionResult TextureVerticesNear(std::vector< impeller::TextureFillVertexShader::PerVertexData > a, std::vector< impeller::TextureFillVertexShader::PerVertexData > b)
TEST(FrameTimingsRecorderTest, RecordVsync)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
constexpr float kSqrt2Over2
@ kNormal
The geometry has no overlapping triangles.
A 4x4 matrix using column-major storage.
static constexpr Matrix MakeTranslation(const Vector3 &t)
static Matrix MakeRotationZ(Radians r)
static constexpr Matrix MakeScale(const Vector3 &s)
static RoundRect MakeRectRadii(const Rect &rect, const RoundingRadii &radii)
A structure to store all of the parameters related to stroking a path or basic geometry object.
constexpr TRect< T > Expand(T left, T top, T right, T bottom) const
Returns a rectangle with expanded edges. Negative expansion results in shrinking.
static constexpr TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
std::vector< Point > points