Convert array of point to polygon - c++

I have array of point with latitude and longitude, from this array generating LineString to display way on road by leaflet.
Now i want to improve code function to detect when user point (received from GPS device):
1) Out from waypoint
2) Position on waypoint
3) Direction (begin or back)
After having tried many ways to implement my idea i coming to convert my array of point to Polygon and control by boost::geometry::intersection
I tried realise this function by search near point in array that work perfect in one way road else code can lock point from neighbour way :(
Example of ways:
[start]--------------[end]
But it can be so
[start]
---------one_road---turning_road_and_reverse-]
-------two_road-----------
[end]
Now i want to convert array to one polygon
-----------------------------------------------
one_road
two_road
-----------------------------------------------
i think that i can easily release function to detect location without errors
May be someone know how easily convert linestring to polygon?
example
i have:
LINESTRING(-105.40392744645942 38.49004450086558,-105.40486621961463 38.491262147649266,-105.40443706617225 38.49272329662804,-105.40424394712318 38.49368058506501,-105.4055099497782 38.49443633010962,-105.40690469846595 38.494940155735165,-105.40694761381019 38.49450350706328,-105.40634679899085 38.49324392875914,-105.40510225400794 38.49146368720108,-105.40437269315589 38.490422393448746,-105.40394675757852 38.489957795386)
i want:
POLYGON((-105.40419674129225 38.49056599190572,-105.40475464076735 38.49046522094479,-105.40737247676589 38.494462360981586,-105.40685749263503 38.49520130375959,-105.40647554502357 38.493848529093356,-105.4052739153849 38.49193394396309,-105.4047160159098 38.49237060820819,-105.40473747358192 38.49344546276763,-105.40600347623695 38.49430197601443,-105.40664720640052 38.49480580257953,-105.40585327253211 38.494789008417456,-105.40432977781165 38.49394929532246,-105.40394353971351 38.493059188756156,-105.40465164289344 38.49129573761371,-105.40419674129225 38.49056599190572))
Please help!

Your question is in serious need of a SSCCE. Reading it you might be looking for anything from trivial type conversion to complicated routing algorithms.
Here's are two simple SSCCE's that show how to do the type conversions you describe.
NOTE The extra work to check that the polygon is valid (it needs to be closed, and the points need to have the correct orientation for the outer ring)
Array Of Point To Polygon
Live On Coliru
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/linestring.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <iostream>
#include <boost/geometry/io/io.hpp>
namespace bg = boost::geometry;
namespace bgm = bg::model;
using point = bgm::d2::point_xy<int>;
using polygon = bgm::polygon<point>;
void debug_print(polygon const& p) {
std::string reason;
bool valid = bg::is_valid(p, reason);
std::cout << bg::dsv(p) << " - " << (!valid?"invalid ("+reason+")":"valid") << "\n";
}
int main() {
point arr[] { {1,3}, {4,5}, {9, 0} };
for (auto& p : arr)
std::cout << bg::wkt(p) << " ";
std::cout << "\n";
polygon p { {std::begin(arr), std::end(arr)} };
debug_print(p);
bg::correct(p);
debug_print(p);
std::cout << bg::wkt(p) << "\n";
}
Prints:
POINT(1 3) POINT(4 5) POINT(9 0)
(((1, 3), (4, 5), (9, 0))) - invalid (Geometry has too few points)
(((1, 3), (4, 5), (9, 0), (1, 3))) - valid
POLYGON((1 3,4 5,9 0,1 3))
LineString To Polygon
Live On Coliru
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/linestring.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <iostream>
#include <boost/geometry/io/io.hpp>
namespace bg = boost::geometry;
namespace bgm = bg::model;
using point = bgm::d2::point_xy<int>;
using linestring = bgm::linestring<point>;
using ring = bgm::ring<point>;
using polygon = bgm::polygon<point>;
void debug_print(polygon const& p) {
std::string reason;
bool valid = bg::is_valid(p, reason);
std::cout << bg::dsv(p) << " - " << (!valid?"invalid ("+reason+")":"valid") << "\n";
}
int main() {
linestring ls { {1,3}, {4,5}, {9, 0} };
std::cout << bg::wkt(ls) << "\n";
polygon p { ring{ls.begin(), ls.end()} };
debug_print(p);
bg::correct(p);
debug_print(p);
std::cout << bg::wkt(p) << "\n";
}
Prints
LINESTRING(1 3,4 5,9 0)
(((1, 3), (4, 5), (9, 0))) - invalid (Geometry has too few points)
(((1, 3), (4, 5), (9, 0), (1, 3))) - valid
POLYGON((1 3,4 5,9 0,1 3))

i found solution this is boost::geometry::buffer
using namespace boost::geometry::model;
namespace bg = boost::geometry;
typedef bg::model::point <double , 2, bg::cs::cartesian > point_t;
typedef boost::geometry::model::polygon <point_t> polygon_t;
typedef bg::model::linestring<point_t> linestring_t;
linestring_t ls1;
vector<BSONElement> point_records = record.getField("points").Array();
linestring_t ls1;
for(vector<BSONElement>::iterator it = point_records.begin(); it != point_records.end(); ++it)
{
BSONObj point_record = (*it).Obj();
bg::append(ls1, point_t(point_record.getField("lo").Double(), point_record.getField("lat").Double()));
}
const double buffer_distance = 1.0;
const int points_per_circle = 36;
// Declare other strategies
boost::geometry::strategy::buffer::distance_symmetric<double> distance_strategy(0.0002);
boost::geometry::strategy::buffer::join_round join_strategy(points_per_circle);
boost::geometry::strategy::buffer::end_round end_strategy(points_per_circle);
boost::geometry::strategy::buffer::point_circle circle_strategy(points_per_circle);
boost::geometry::strategy::buffer::side_straight side_strategy;
boost::geometry::model::multi_polygon<polygon_t> result;
/* polygon_t result; */
boost::geometry::buffer(ls1, result,
distance_strategy, side_strategy,
join_strategy, end_strategy, circle_strategy);
Please sorry for bad english!

Related

C++ Boost RTree overlaps does not work correctly

I am kinda confused and think I get something wrong but I really fail to see it.
I have a boost::geometry::index::rtree that stores 2D boxes of 2D geographic points. Now I try to check if a new box I add to that rtree overlaps with any box already in that rtree. And this check somehow fails for one test and I really don't get why because I do not believe the error is in the rtree/overlaps implementation.
My code is the following (in Visual Studio test environment):
using CoordinateSystem = boost::geometry::cs::geographic<boost::geometry::degree>;
using Point = boost::geometry::model::point<double, 2, CoordinateSystem>;
using RTreeBox = boost::geometry::model::box<Point>;
using RTreeEntry = std::pair<RTreeBox, uint64_t>;
constexpr static auto kRTreeMaxElementsPerNode = 4;
using RTreeAlgorithm = boost::geometry::index::rstar<kRTreeMaxElementsPerNode>;
using RTree = boost::geometry::index::rtree<RTreeEntry, RTreeAlgorithm>;
bool TestAddTreeEntry(RTree& tree, uint64_t index, RTreeBox box)
{
if (!boost::geometry::is_valid(box)) {
boost::geometry::correct(box);
}
std::vector<RTreeEntry> query_results;
tree.query(boost::geometry::index::overlaps(box), std::back_inserter(query_results));
if (query_results.size() > 0)
{
return false;
}
tree.insert(std::make_pair(box, index));
return true;
}
TEST_METHOD(test_rtree_mapping) {
RTree tree;
Assert::IsTrue(TestAddTreeEntry(tree, 1, RTreeBox({ 1, 1 }, { 3, 3 })));
Assert::IsTrue(TestAddTreeEntry(tree, 1, RTreeBox({ 4, 1 }, { 9, 5 })));
Assert::IsTrue(TestAddTreeEntry(tree, 1, RTreeBox({ 1, 4 }, { 2, 9 })));
Assert::IsFalse(TestAddTreeEntry(tree, 1, RTreeBox({ 1, 2.75 }, { 2, 9 })));
Assert::IsFalse(TestAddTreeEntry(tree, 1, RTreeBox({ 1, 4 }, { 3.5, 9 })));
}
The first Assert::IsFalse works - but also unexpectedly only overlaps with the first box ({1, 1}, {3, 3}) and not with the third one ({1, 4}, {2, 9}). The second Assert::IsFalse does not work because the entry is successfully added.
Anyone knows a reason behind this? Has this something to do with geographic coordinates that I do not understand yet?
Kind regards
Overlaps doesn't do what you expect. It's too strict. The docs state:
The function overlaps implements function Overlaps from the OGC Simple Feature Specification.
The OGC document contains:
That's admittedly hard to parse, but that's the nature of technical specifications. Luckily, intersects is much simpler:
a.Intersects(b) ⇔ ! a.Disjoint(b)
DEMO
I created a test program that
allows you to override the RELATION (e.g. bgi::intersects, bgi::overlaps, !bgi::disjoint)
also writes a SVG vizualtion of the shapes involved.
Live On Compiler Explorer
#include <boost/geometry.hpp>
#include <boost/geometry/index/rtree.hpp>
#include <fstream>
namespace bg = boost::geometry;
namespace bgm = bg::model;
namespace bgi = bg::index;
using CS = bg::cs::geographic<bg::degree>;
using Point = bg::model::point<double, 2, CS>;
using Box = bg::model::box<Point>;
using Tree = std::pair<Box, uint64_t>;
constexpr static auto kRTreeMaxElementsPerNode = 4;
using RTreeAlgorithm = bgi::rstar<kRTreeMaxElementsPerNode>;
using RTree = bgi::rtree<Tree, RTreeAlgorithm>;
#ifndef RELATION
#define RELATION bgi::intersects
#endif
#define RELATION_STR BOOST_PP_STRINGIZE(RELATION)
bool add(RTree& tree, uint64_t index, Box box) {
if (std::string reason; !bg::is_valid(box, reason)) {
std::cerr << "Trying to correct: " << bg::dsv(box) << " (" << reason << ")" << std::endl;
bg::correct(box);
assert(bg::is_valid(box));
}
for (auto it = qbegin(tree, RELATION(box)), e = qend(tree); it != e; ++it)
return false;
tree.insert(std::make_pair(box, index));
return true;
}
int main() {
std::cout << std::boolalpha;
RTree tree;
struct {
Box box;
char const* name;
char const* color;
} const shapes[]{
{{{1.00, 1.00}, {3.00, 3.00}}, "box1", "red"},
{{{4.00, 1.00}, {9.00, 5.00}}, "box2", "green"},
{{{1.00, 4.00}, {2.00, 9.00}}, "box3", "blue"},
{{{1.00, 2.75}, {2.00, 9.00}}, "probe1", "orange"},
{{{1.00, 4.00}, {3.50, 6.00}}, "probe2", "gray"},
};
for (auto const& s : shapes) {
auto idx = (&s - shapes);
auto added = add(tree, idx, s.box);
std::cout << "Adding " << s.name << " as #" << idx << ": "
<< (added ? "ACCEPT" : "REJECTED") << " " << bg::dsv(s.box)
<< "\n";
if (!added) {
for (auto it = qbegin(tree, RELATION(s.box)), e = qend(tree); it != e; ++it) {
std::cout << " - because " << s.name << " " << RELATION_STR
<< " " << shapes[it->second].name << "\n";
}
}
}
{
std::ofstream ofs("output.svg");
bg::svg_mapper<Point> svg(ofs, 400, 400);
auto style = [](std::string c) {
return "fill-rule:nonzero;fill-opacity:0.25;fill:" + c +
";stroke:" + c + ";stroke-width:1;";
};
for (auto const& [b, name, color] : shapes) {
svg.add(b);
}
for (auto const& [b, name, color] : shapes) {
auto h = b.max_corner().get<1>() - b.min_corner().get<1>();
auto mc = b.max_corner();
mc.set<1>(mc.get<1>() - h / 2);
svg.text(mc,
name +
("\n" + boost::lexical_cast<std::string>(bg::dsv(b))),
style(color));
}
for (auto const& [b, _, color] : shapes)
svg.map(b, style(color));
}
}
With either -DRELATION=bgi::intersects or -DRELATION=!bgi::disjoint:
Adding box1 as #0: ACCEPT ((1, 1), (3, 3))
Adding box2 as #1: ACCEPT ((4, 1), (9, 5))
Adding box3 as #2: ACCEPT ((1, 4), (2, 9))
Adding probe1 as #3: REJECTED ((1, 2.75), (2, 9))
- because probe1 bgi::intersects box1
- because probe1 bgi::intersects box3
Adding probe2 as #4: REJECTED ((1, 4), (3.5, 6))
- because probe2 bgi::intersects box3
(replacing bgi::intersects with !bgi::disjoint in the output obviously).
Visualization:
Note how the output changes if you change probe1:
{{{1.00, 2.75}, {1.50, 9.00}}, "probe1", "orange"},
That looks like:
This would behave as you expected even with the bgi::overlaps. Overlaps is just too strict for the expectated output.

How to emulate boost::algorithm::find_if_backward with Range-v3?

I've been using extensively boost::algorithm::find_if_backward to get a forward iterator to the last element in a range satisfying a predicate.
How do I accomplish the same task using Range-v3?
This is my attempt, which looks a bit clunky; and I'm not even sure is robust enough. Actually, as suggested in a comment, the code is not robust enough, because when no element is found, range_it_to_last_2 ends up being std::next(v.begin(), -1), which is undefined behavior, I believe.
#include <algorithm>
#include <boost/algorithm/find_backward.hpp>
#include <boost/hana/functional/partial.hpp>
#include <iostream>
#include <range/v3/algorithm/find_if.hpp>
#include <range/v3/view/reverse.hpp>
using boost::algorithm::find_if_backward;
using ranges::find_if;
using ranges::views::reverse;
auto constexpr is_2 = boost::hana::partial(std::equal_to<>{}, 2);
int main() {
std::vector<int> v{0,1,2,2,2,3};
// What I have been doing so far:
auto boost_it_to_last_2 = find_if_backward(v, is_2);
// The Range-v3 analogous I could come up with, but it's ugly:
auto range_it_to_last_2 = std::next(find_if(v | reverse, is_2).base(), -1);
for (auto it = v.begin(); it <= boost_it_to_last_2; ++it) {
std::cout << *it << ' ';
} // prints 0 1 2 2 2
std::cout << std::endl;
for (auto it = v.begin(); it <= range_it_to_last_2; ++it) {
std::cout << *it << ' ';
} // prints 0 1 2 2 2
std::cout << std::endl;
}
Assuming you always know that a match is found, why not simplify to the following, getting the identical output:
Live On Godbolt
#include <algorithm>
#include <boost/algorithm/find_backward.hpp>
#include <boost/hana/functional/partial.hpp>
#include <fmt/ranges.h>
#include <range/v3/algorithm/find_if.hpp>
#include <range/v3/view/subrange.hpp>
#include <range/v3/view/reverse.hpp>
using boost::algorithm::find_if_backward;
using ranges::find_if;
using ranges::views::reverse;
using ranges::subrange;
auto constexpr pred = boost::hana::partial(std::equal_to<>{}, 2);
int main() {
std::vector<int> v {0,1,2,2,2,3};
auto boost_match = find_if_backward(v, pred);
auto range_match = find_if(v | reverse, pred).base();
static_assert(std::is_same_v<decltype(boost_match), decltype(range_match)>);
fmt::print("boost: {}\nrange: {}\n",
subrange(v.begin(), boost_match+1),
subrange(v.begin(), range_match));
}
Prints
boost: {0, 1, 2, 2, 2}
range: {0, 1, 2, 2, 2}
(Some toy respellings for fun: https://godbolt.org/z/ccPKeo)

divide boost segment into N equal segments using boost geometry

I created a line segment using boost geometry model. I am wondering if there is a way in boost to divide the segment into N equal line segments.
Please do not consider this question as duplicated version of this.
(EDIT)
because is over-dated and I have already tried the answer provided for this question.
The simplest thing that comes to mind:
Live On Coliru
#include <boost/geometry/geometry.hpp>
#include <boost/geometry/io/io.hpp>
#include <boost/geometry/arithmetic/arithmetic.hpp>
#include <boost/geometry/geometries/segment.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/linestring.hpp>
#include <iostream>
template <typename Segment, typename Point = typename boost::geometry::point_type<Segment>::type>
auto split_into(unsigned N, Segment const& s) {
using namespace boost::geometry;
assert(N>1);
auto step = s.second;
subtract_point(step, s.first);
divide_value(step, N-1);
std::vector<Point> segments;
std::generate_n(back_inserter(segments), N, [accu=s.first, step] () mutable { Point p = accu; return add_point(accu, step), p; });
return model::linestring<Point> {segments.begin(), segments.end()};
}
using namespace boost::geometry;
using Point = model::d2::point_xy<double>;
int main() {
model::segment<Point> const line { {1,3}, {11,33} };
std::cout << wkt(line) << "\n";
std::cout << wkt(split_into(5, line)) << "\n";
}
Prints
LINESTRING(1 3,11 33)
LINESTRING(1 3,3.5 10.5,6 18,8.5 25.5,11 33)
Fancy Range Version
One that might scale better for large N:
Live On Coliru
#include <boost/range/adaptors.hpp>
#include <boost/range/irange.hpp>
template <typename Segment, typename Point = typename boost::geometry::point_type<Segment>::type>
auto split_into(unsigned N, Segment const& s) {
using namespace boost::geometry;
using namespace boost::adaptors;
assert(N>1);
auto step = s.second;
subtract_point(step, s.first);
divide_value(step, N-1);
auto gen = boost::irange(0u, N) | transformed([=](int i) { auto p = step; multiply_value(p, i); add_point(p, s.first); return p; });
return model::linestring<Point> { boost::begin(gen), boost::end(gen) };
}
Prints
LINESTRING(1 3,11 33)
LINESTRING(1 3,3.5 10.5,6 18,8.5 25.5,11 33)
If you need to divide AB segment to N equal pieces, then coordinates of starting point for i-th segment (and the end of previous segment) might be calculated using parametric equation of line.
Pseudocode:
for i = 0.. N-1
t = i / N
Start[i].X = A.X * (1 - t) + B.X * t
Start[i].Y = A.Y * (1 - t) + B.Y * t

Cuda::thrust: Performing compact operation with Device_vector

I'm still fairly new to Cuda and while a stackoverflow user gave me a descriptive example on how to use thrust::copy_if to compact an array of known size on the host (as I worded my question badly), I've been unable to convert the approach to use device_vectors (to deal with inputted arrays of unknown size on the device).
I'm attempting to generate a compacted list of the positions of all the elements in a vector which match a user specified predicate. The working example I was given is:
#include <thrust/copy.h>
#include <thrust/iterator/counting_iterator.h>
#include <thrust/functional.h>
#include <iostream>
using namespace thrust::placeholders;
int main()
{
const int N = 10;
int objectArray[N] = { 1, 11, 7, 2, 7, 23, 6, 6, 9, 11 };
int results[N]={0};
int* end = thrust::copy_if(thrust::make_counting_iterator(0), thrust::make_counting_iterator(N), objectArray, results, _1 == 7);
thrust::copy(results, results+N, std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl << "result count = " << end-results << std::endl;
return 0;
}
I've tried to modify the code to use device vectors (and compute on the device) as follows:
#include <thrust/copy.h>
#include <thrust/iterator/counting_iterator.h>
#include <thrust/functional.h>
#include <iostream>
using namespace thrust::placeholders;
int soughtElement=7;
reader.open("Numeric_1a40Coords.txt");
reader >> sizeOfProteinChain; //This returns the size of the input
reader.close();
thrust::host_vector<int> Host_names(sizeOfProteinChain);
thrust::host_vector<int> Host_results;
ImportNumericNameValues("Numeric_1a40Coords.txt", Host_names); //This populates the vector with "sizeOfProteinChain" number of elements
thrust::device_vector<int> Device_names = Host_Names;
thrust::device_vector<int> Device_results = Host_results;
Host_results = thrust::copy_if(thrust::make_counting_iterator(0), thrust::make_counting_iterator(sizeOfProteinChain), Device_names, Device_results, _1 == soughtElement);
host_results=device_results;
for (int i=0;i<sizeOfProteinChain;i++)
cout<< host_results[i]<<" ";
cout<<endl;
/*Not sure how to get the resulting number of compacted position elements with device vectors instead of pointer arrays*/
I get errors stating that:
class "thrust::device_vector>" has no member
"iterator_category"
and:
no instance of overloaded function "thrust::copy_if" matches the
argument list
I've been stuck on this for a while and any suggestions on how to correct those errors, or more accurately convert the above sample, would be greatly appreciated. My previous question on this matter can be found here:
You might want to read the thrust quick start guide.
This will get you in trouble:
thrust::host_vector<int> Host_results;
that creates a vector of zero size. Later when you do this:
thrust::device_vector<int> Device_results = Host_results;
You've created another vector of zero size. Although these will not create compile errors, if you try to use these (e.g. by copying something into them) without a proper size allocation, you're going to have trouble at run-time.
This is also wrong:
Host_results = thrust::copy_if(thrust::make_counting_iterator(0), thrust::make_counting_iterator(sizeOfProteinChain), Device_names, Device_results, _1 == soughtElement);
The return value of the thrust::copy_if function is an iterator. You cannot assign it to a vector. A vector is not the same as an iterator. Host_results is a vector.
Not sure what this is:
host_results=device_results;
Do you actually have a variable or vector somewhere that also begins with a lower case h? Because host_results is not the same as Host_results
Here's a complete worked example demonstrating how to do thrust::copy_if on device vectors of arbitrary length:
$ cat t808.cu
#include <thrust/copy.h>
#include <thrust/device_vector.h>
#include <thrust/iterator/counting_iterator.h>
#include <iostream>
#define COPY_VAL 7
using namespace thrust::placeholders;
int main(){
int objectArray[] = { 1, 11, 7, 2, 7, 23, 6, 6, 9, 11 };
int dsize = sizeof(objectArray)/sizeof(int);
int results[dsize];
thrust::device_vector<int> d_obj(objectArray, objectArray+dsize);
thrust::device_vector<int> d_res(dsize);
int resultCount = thrust::copy_if(thrust::make_counting_iterator(0), thrust::make_counting_iterator(dsize), d_obj.begin(), d_res.begin(), (_1 == COPY_VAL)) - d_res.begin();
thrust::copy(d_res.begin(), d_res.end(), results);
std::cout << "resultCount = " << resultCount << std::endl << "results: " << std::endl;
thrust::copy(d_res.begin(), d_res.end(), std::ostream_iterator<int>(std::cout, ", "));
std::cout << std::endl;
return 0;
}
$ nvcc -o t808 t808.cu
$ ./t808
resultCount = 2
results:
2, 4, 0, 0, 0, 0, 0, 0, 0, 0,
$

Boost.Geometry polygon point assignment

i am trying to use boost geometry and having trouble assigning points to a polygon.
Lets assume i create an static vector of points
boost::geometry::model::d2::point_xy<double> >* a;
And then i create a polygon:
boost::geometry::model::polygon<boost::geometry::model::d2::point_xy<double> > polygon;
Assuming i have already defined the values of the points of a.
How can i assign the points from a to P?
The boost::geometry::assign_points() algorithm can be used to assign a range of points to a polygon.
If a is a range of points and P is a polygon, then one would use:
boost::geometry::assign_points(P, a);
Here is a complete example demonstrating the usage of assign_points:
#include <iostream>
#include <vector>
#include <boost/assign/std/vector.hpp>
#include <boost/geometry.hpp>
#include <boost/geometry/algorithms/area.hpp>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/io/dsv/write.hpp>
int main()
{
using namespace boost::assign;
typedef boost::geometry::model::d2::point_xy<double> point_xy;
// Create points to represent a 5x5 closed polygon.
std::vector<point_xy> points;
points +=
point_xy(0,0),
point_xy(0,5),
point_xy(5,5),
point_xy(5,0),
point_xy(0,0)
;
// Create a polygon object and assign the points to it.
boost::geometry::model::polygon<point_xy> polygon;
boost::geometry::assign_points(polygon, points);
std::cout << "Polygon " << boost::geometry::dsv(polygon) <<
" has an area of " << boost::geometry::area(polygon) << std::endl;
}
Which produces the following output:
Polygon (((0, 0), (0, 5), (5, 5), (5, 0), (0, 0))) has an area of 25