Currently I am doing a work related to polygons. Polygon can be described as several vertices.
struct Polygon{
vector<Point2D> vertex;
Color color;
};
Now, I have some polygons already vector<Polygon> polygons
and a method can tell me that a point is inside which polygon
Polygon queryPolygon(Point2D point);
I need to set the color of the returned polygon.
My first question is how to know whether the returned polygon is inside vector<Polygon> polygons, the one I already have.
My first idea is to use unordered_set and compare (vertex.begin(), vertex.end()). I don't know whether there is any better idea.
Another question is some polygon might contain the same edge. How to design the data structure so that I can know the polygons that contains same edge like
vector<Polygon> queryPolygonWithSameEdge(Point2D edgeStart, Point2D edgeEnd);
of course brute-force is one way, but is there any better ideas?
Thanks.
First question
There are some unclear aspects about this first question (see my comments). I'll nevertheless answer, assuming that you want just to compare an arbitrary polygon returned by the query with known polygons stored in your vector, with something like:
auto f = find_if (v.begin(), v.end(), [&p](const auto &x) { return compare1(x.vertex, p.vertex); });
if (f!=v.end()) {
cout << "Found at "<< f-v.begin() <<endl;
}
else cout << "Not found";
Comparing polygons (level 1)
The first level would be to compare point by point. The problem, is that the ordering of points does matter, because with exactly the same points, you can draw a pentagon or a pentagram, just depending on the order chosen and whether or not you accept self-intersecting polygons.
For simply comparing if the vertexes in the two vectors are the same:
bool compare1(const vector<Point2D> &x, const vector<Point2D> &y ) {
return x==y;
}
Unfortunately, this will not work if you have two identical polygones, that are just represented using a different starting point.
Comparing polygons (level 2)
Here we take care of a potential different starting point. So the first thing is to find the offset of the first point of the fist polygon in the second polygon, and perform the comparison by taking care of the offset. If the point is not found in the seond polygon, they are not the same:
bool compare2(const vector<Point2D> &x, const vector<Point2D> &y ) {
if (x.size() != y.size()) // if different size it's not the same
return false;
auto offset = find (y.cbegin(), y.cend(), x[0]); // asumes at least 1 point
if (offset==y.cend())
return false;
return equal(offset, y.cend(), x.cbegin())
&& equal(y.cbegin(), offset, x.cbegin()+(y.cend()-offset));
}
Comparing polygons (level 3)
Now, it's also possible that the points are the same, but the first polygon goes clockwise and the second anticlockwise. So we need to check in both direction:
bool compare3(const vector<Point2D> &x, const vector<Point2D> &y ) {
if (x.size() != y.size())
return false;
auto offset = find (y.cbegin(), y.cend(), x[0]); // asumes at least 1 point
if (offset==y.cend()) // no point in commont
return false;
else if (equal(offset, y.cend(), x.cbegin())
&& equal(y.cbegin(), offset, x.cbegin()+(y.cend()-offset)))
return true;
// not equal. And in reverse order ?
auto roffset = make_reverse_iterator(offset+1);
return equal(roffset, y.crend(), x.cbegin())
&& equal(y.crbegin(), roffset, x.cbegin()+(y.crend()-roffset));
}
Here you have an online demo
Comparing polygons (level 4)
Now it is not excluded that two consecutive edges are perfectly aligned. So it is possible that a polygon has an additional point which is not relevant for the comparison.
I let you as exercise the handling for this case. But the most natural place to process this special case is when you populate your polygon.
Second question
To fin the common edges, the easiest way would IMHO be to add the edges to a map, being understood that you would normalize them to ensure that the points are always in the same order.
You could associate to the edge anything you want, for example: a count, a color, or a container with a pointer to the owning polygon.
Related
To give context to my question I will describe what it is I am ultimately trying to achieve - I am developing a game, I have a .obj model that I am using as my terrain and I must update the players height as they traverse the terrain (because the terrain is far from flat). I am achieving this currently by doing the following - when I load the mesh (terrain.obj) I store all its vertices (each vertex is a Vector3f object that has an x y and z value) in a std::vector<Vector3f> meshVertices, then every second in the "main game loop" I loop through every one of the Vector3f objects in meshVertices and check its x and z value against the players x and z value, if they are colliding I set the players height as the y value of the matched Vector3f object.
This system actually works and updates my players height as they traverse through the terrain, the only issue is this - my approach of checking every single mesh vertex against player position every second kills my frame rate, I need a much better system.
I will now describe my new optimized approach in the attempt of saving my frame rate - Firstly, when creating the mesh I don't just store each Vector3f vertex in a single std::vector<Vector3f>, I store the x y and z values of each Vector3f vertex of the mesh in three seperate std::vector<Vector3f>'s, named meshVerticesX, mechVerticesY and meshVerticesZ. These std::vector's can be seen in the following code:
for (Vector3f currentVertex : meshVertices) {
meshVerticesX.push_back((int)currentVertex.GetX());
}
for (Vector3f currentVertex : meshVertices) {
meshVerticesZ.push_back((int)currentVertex.GetZ());
}
for (Vector3f currentVertex : meshVertices) {
meshVerticesY.push_back((int)currentVertex.GetY());
}
Now every second I get the x and z value of the players position (casted to an int because I feel like making this system work with int values and not float values will be much easier for comparisons later) and then send them to functions that check to see if they exist in the before mentioned meshVerticesX and mechVerticesZ by returning a bool, the code responsible for this is as follows:
int playerPosX = (int) freeMoveObjects[0]->GetParent()->GetTransform()->GetPos()->GetX();
int playerPosZ = (int) freeMoveObjects[0]->GetParent()->GetTransform()->GetPos()->GetZ();
bool x = meshObjects[0]->checkMeshVerticesX(playerPosX);
bool z = meshObjects[0]->checkMeshVerticesZ(playerPosZ);
The functions checkMeshVerticesX and checkMeshVerticesZ are as follows:
bool Mesh::checkMeshVerticesX(int playerPosX)
{
return std::find(meshVerticesX.begin(), meshVerticesX.end(), playerPosX) != meshVerticesX.end();
}
bool Mesh::checkMeshVerticesZ(int playerPosZ)
{
return std::find(meshVerticesZ.begin(), meshVerticesZ.end(), playerPosZ) != meshVerticesZ.end();
}
Using the returned boolean values (true if the players position was in the respective std::vector or false if it was not) I then call another function (getMeshYHeight) that also gets passed the players x and z position that then checks the index of the respective std::vector's (meshVerticesX & meshVerticesZ) were the match was found, then checks if these indexes are equal and if so returns an int of that index from the meshVerticesY std::vector mentioned earlier, this code can be seen in the following:
if (x == true & z == true) {// boolean values returned by checkMeshVerticesX & checkMeshVerticesZ
int terrainVertexYHeight = meshObjects[0]->getMeshYHeight(playerPosX, playerPosZ);
freeMoveObjects[0]->GetParent()->GetTransform()->GetPos()->SetY(terrainVertexYHeight);
}
The function getMeshYHeight is as follows:
int Mesh::getMeshYHeight(int playerXPos, int playerZPos) {//15/2/20
auto iterX = std::find(meshVerticesX.begin(), meshVerticesX.end(), playerXPos) != meshVerticesX.end();
auto iterZ = std::find(meshVerticesZ.begin(), meshVerticesZ.end(), playerZPos) != meshVerticesZ.end();
int indexX = std::distance(meshVerticesX.begin(), iterX);
int indexZ = std::distance(meshVerticesZ.begin(), iterZ);
if (indexX == indexZ)
{
return meshVerticesY[indexX];
}
}
The idea here is that if the index from the meshVerticesX and meshVerticesZ std::vectors's for the original check match, then they must be the x and z values from an original Vector3f object when I first made the mesh as described earlier, and so that same index in meshVerticesY must contain that same Vector3f's objects y value, therefore return it and use it to set the players height.
The issue is that I cant even test if this works because the line of code int indexX = std::distance(meshVerticesX.begin(), iterX); gives an error saying the arguments supplied to std::distance are wrong (it says iterX is a bool instead of an int which is what I thought it would be).
So my question is - Firstly, if I diden't have this error would my approach even work? and if so, how can I fix the error?
I kind of lost track of your logic somewhere in the middle there, but to address the issue at hand: iterX is a bool!
auto iterX = std::find(...) != meshVerticesX.end();
In this statement, find returns an iterator, which you compare to another iterator, meshVerticesX.end(). The result of that expression (the comparison operator) is a bool, which is then assigned to iterX, so auto deduces that iterX needs to be of type bool.
could you convert your terrain's x,y coordinates to ints, you may need to scale it, then when you load the mesh you could just store the z value for every x,y point (you may have to take some sort of average over the 1x1 square). Now you don't have to look for collisions, instead for each object in the game you can just look up it's z value by it's (scaled) x,y coordinates.
Im very new to c++ and only know the very basics. array, if while for dynamic and pointer..
I am working on a code and here is what i want to do.
For example on a 2D square plane(10x10) I have randomly scattered 1000 points(an array of size 100).
The 2D square plane is divided into 10 smaller rectangles. Now I want to sort the 1000 points into these smaller rectangles. Basically, I want to make 10 dynamic arrays(one for each "small rectangle") and each of these array will contain the scattered points that are inside the corresponding region.
The most basic iteration i thought of was just use if, if, if...
But with this, I have to repeat the iteration 1000times for each region. And I think it is very inefficient.
Write a function to classify a single point, i.e. determine into which region it belongs. As a simple example that you can expand:
std::size_t classify(double px, double py, double split) {
if (px < split) {
return 0; // left plane
} else {
return 1; // right plane
}
}
Then, iterate over the points and put them into respective containers:
std::vector<std::vector<point_t>> region{2};
for (auto const & point : points) {
region[classify(point.x, point.y, split)].push_back(point);
}
This way you iterate once over all points, doing a classification (that should be possible to do in constant time in your case) for every point, which is the minimum work required.
I need a graph-search algorithm that is enough in our application of robot navigation and I chose Dijkstra's algorithm.
We are given the gridmap which contains free, occupied and unknown cells where the robot is only permitted to pass through the free cells. The user will input the starting position and the goal position. In return, I will retrieve the sequence of free cells leading the robot from starting position to the goal position which corresponds to the path.
Since executing the dijkstra's algorithm from start to goal would give us a reverse path coming from goal to start, I decided to execute the dijkstra's algorithm backwards such that I would retrieve the path from start to goal.
Starting from the goal cell, I would have 8 neighbors whose cost horizontally and vertically is 1 while diagonally would be sqrt(2) only if the cells are reachable (i.e. not out-of-bounds and free cell).
Here are the rules that should be observe in updating the neighboring cells, the current cell can only assume 8 neighboring cells to be reachable (e.g. distance of 1 or sqrt(2)) with the following conditions:
The neighboring cell is not out of bounds
The neighboring cell is unvisited.
The neighboring cell is a free cell which can be checked via the 2-D grid map.
Here is my implementation:
#include <opencv2/opencv.hpp>
#include <algorithm>
#include "Timer.h"
/// CONSTANTS
static const int UNKNOWN_CELL = 197;
static const int FREE_CELL = 255;
static const int OCCUPIED_CELL = 0;
/// STRUCTURES for easier management.
struct vertex {
cv::Point2i id_;
cv::Point2i from_;
vertex(cv::Point2i id, cv::Point2i from)
{
id_ = id;
from_ = from;
}
};
/// To be used for finding an element in std::multimap STL.
struct CompareID
{
CompareID(cv::Point2i val) : val_(val) {}
bool operator()(const std::pair<double, vertex> & elem) const {
return val_ == elem.second.id_;
}
private:
cv::Point2i val_;
};
/// Some helper functions for dijkstra's algorithm.
uint8_t get_cell_at(const cv::Mat & image, int x, int y)
{
assert(x < image.rows);
assert(y < image.cols);
return image.data[x * image.cols + y];
}
/// Some helper functions for dijkstra's algorithm.
bool checkIfNotOutOfBounds(cv::Point2i current, int rows, int cols)
{
return (current.x >= 0 && current.y >= 0 &&
current.x < cols && current.y < rows);
}
/// Brief: Finds the shortest possible path from starting position to the goal position
/// Param gridMap: The stage where the tracing of the shortest possible path will be performed.
/// Param start: The starting position in the gridMap. It is assumed that start cell is a free cell.
/// Param goal: The goal position in the gridMap. It is assumed that the goal cell is a free cell.
/// Param path: Returns the sequence of free cells leading to the goal starting from the starting cell.
bool findPathViaDijkstra(const cv::Mat& gridMap, cv::Point2i start, cv::Point2i goal, std::vector<cv::Point2i>& path)
{
// Clear the path just in case
path.clear();
// Create working and visited set.
std::multimap<double,vertex> working, visited;
// Initialize working set. We are going to perform the djikstra's
// backwards in order to get the actual path without reversing the path.
working.insert(std::make_pair(0, vertex(goal, goal)));
// Conditions in continuing
// 1.) Working is empty implies all nodes are visited.
// 2.) If the start is still not found in the working visited set.
// The Dijkstra's algorithm
while(!working.empty() && std::find_if(visited.begin(), visited.end(), CompareID(start)) == visited.end())
{
// Get the top of the STL.
// It is already given that the top of the multimap has the lowest cost.
std::pair<double, vertex> currentPair = *working.begin();
cv::Point2i current = currentPair.second.id_;
visited.insert(currentPair);
working.erase(working.begin());
// Check all arcs
// Only insert the cells into working under these 3 conditions:
// 1. The cell is not in visited cell
// 2. The cell is not out of bounds
// 3. The cell is free
for (int x = current.x-1; x <= current.x+1; x++)
for (int y = current.y-1; y <= current.y+1; y++)
{
if (checkIfNotOutOfBounds(cv::Point2i(x, y), gridMap.rows, gridMap.cols) &&
get_cell_at(gridMap, x, y) == FREE_CELL &&
std::find_if(visited.begin(), visited.end(), CompareID(cv::Point2i(x, y))) == visited.end())
{
vertex newVertex = vertex(cv::Point2i(x,y), current);
double cost = currentPair.first + sqrt(2);
// Cost is 1
if (x == current.x || y == current.y)
cost = currentPair.first + 1;
std::multimap<double, vertex>::iterator it =
std::find_if(working.begin(), working.end(), CompareID(cv::Point2i(x, y)));
if (it == working.end())
working.insert(std::make_pair(cost, newVertex));
else if(cost < (*it).first)
{
working.erase(it);
working.insert(std::make_pair(cost, newVertex));
}
}
}
}
// Now, recover the path.
// Path is valid!
if (std::find_if(visited.begin(), visited.end(), CompareID(start)) != visited.end())
{
std::pair <double, vertex> currentPair = *std::find_if(visited.begin(), visited.end(), CompareID(start));
path.push_back(currentPair.second.id_);
do
{
currentPair = *std::find_if(visited.begin(), visited.end(), CompareID(currentPair.second.from_));
path.push_back(currentPair.second.id_);
} while(currentPair.second.id_.x != goal.x || currentPair.second.id_.y != goal.y);
return true;
}
// Path is invalid!
else
return false;
}
int main()
{
// cv::Mat image = cv::imread("filteredmap1.jpg", CV_LOAD_IMAGE_GRAYSCALE);
cv::Mat image = cv::Mat(100,100,CV_8UC1);
std::vector<cv::Point2i> path;
for (int i = 0; i < image.rows; i++)
for(int j = 0; j < image.cols; j++)
{
image.data[i*image.cols+j] = FREE_CELL;
if (j == image.cols/2 && (i > 3 && i < image.rows - 3))
image.data[i*image.cols+j] = OCCUPIED_CELL;
// if (image.data[i*image.cols+j] > 215)
// image.data[i*image.cols+j] = FREE_CELL;
// else if(image.data[i*image.cols+j] < 100)
// image.data[i*image.cols+j] = OCCUPIED_CELL;
// else
// image.data[i*image.cols+j] = UNKNOWN_CELL;
}
// Start top right
cv::Point2i goal(image.cols-1, 0);
// Goal bottom left
cv::Point2i start(0, image.rows-1);
// Time the algorithm.
Timer timer;
timer.start();
findPathViaDijkstra(image, start, goal, path);
std::cerr << "Time elapsed: " << timer.getElapsedTimeInMilliSec() << " ms";
// Add the path in the image for visualization purpose.
cv::cvtColor(image, image, CV_GRAY2BGRA);
int cn = image.channels();
for (int i = 0; i < path.size(); i++)
{
image.data[path[i].x*cn*image.cols+path[i].y*cn+0] = 0;
image.data[path[i].x*cn*image.cols+path[i].y*cn+1] = 255;
image.data[path[i].x*cn*image.cols+path[i].y*cn+2] = 0;
}
cv::imshow("Map with path", image);
cv::waitKey();
return 0;
}
For the algorithm implementation, I decided to have two sets namely the visited and working set whose each elements contain:
The location of itself in the 2D grid map.
The accumulated cost
Through what cell did it get its accumulated cost (for path recovery)
And here is the result:
The black pixels represent obstacles, the white pixels represent free space and the green line represents the path computed.
On this implementation, I would only search within the current working set for the minimum value and DO NOT need to scan throughout the cost matrix (where initially, the initially cost of all cells are set to infinity and the starting point 0). Maintaining a separate vector of the working set I think promises a better code performance because all the cells that have cost of infinity is surely to be not included in the working set but only those cells that have been touched.
I also took advantage of the STL which C++ provides. I decided to use the std::multimap since it can store duplicating keys (which is the cost) and it sorts the lists automatically. However, I was forced to use std::find_if() to find the id (which is the row,col of the current cell in the set) in the visited set to check if the current cell is on it which promises linear complexity. I really think this is the bottleneck of the Dijkstra's algorithm.
I am well aware that A* algorithm is much faster than Dijkstra's algorithm but what I wanted to ask is my implementation of Dijkstra's algorithm optimal? Even if I implemented A* algorithm using my current implementation in Dijkstra's which is I believe suboptimal, then consequently A* algorithm will also be suboptimal.
What improvement can I perform? What STL is the most appropriate for this algorithm? Particularly, how do I improve the bottleneck?
You're using a std::multimap for 'working' and 'visited'. That's not great.
The first thing you should do is change visited into a per-vertex flag so you can do your find_if in constant time instead of linear times and also so that operations on the list of visited vertices take constant instead of logarithmic time. You know what all the vertices are and you can map them to small integers trivially, so you can use either a std::vector or a std::bitset.
The second thing you should do is turn working into a priority queue, rather than a balanced binary tree structure, so that operations are a (largish) constant factor faster. std::priority_queue is a barebones binary heap. A higher-radix heap---say quaternary for concreteness---will probably be faster on modern computers due to its reduced depth. Andrew Goldberg suggests some bucket-based data structures; I can dig up references for you if you get to that stage. (They're not too complicated.)
Once you've taken care of these two things, you might look at A* or meet-in-the-middle tricks to speed things up even more.
Your performance is several orders of magnitude worse than it could be because you're using graph search algorithms for what looks like geometry. This geometry is much simpler and less general than the problems that graph search algorithms can solve. Also, with a vertex for every pixel your graph is huge even though it contains basically no information.
I heard you asking "how can I make this better without changing what I'm thinking" but nevertheless I'll tell you a completely different and better approach.
It looks like your robot can only go horizontally, vertically or diagonally. Is that for real or just a side effect of you choosing graph search algorithms? I'll assume the latter and let it go in any direction.
The algorithm goes like this:
(0) Represent your obstacles as polygons by listing the corners. Work in real numbers so you can make them as thin as you like.
(1) Try for a straight line between the end points.
(2) Check if that line goes through an obstacle or not. To do that for any line, show that all corners of any particular obstacle lie on the same side of the line. To do that, translate all points by (-X,-Y) of one end of the line so that that point is at the origin, then rotate until the other point is on the X axis. Now all corners should have the same sign of Y if there's no obstruction. There might be a quicker way just using gradients.
(3) If there's an obstruction, propose N two-segment paths going via the N corners of the obstacle.
(4) Recurse for all segments, culling any paths with segments that go out of bounds. That won't be a problem unless you have obstacles that go out of bounds.
(5) When it stops recursing, you should have a list of locally optimised paths from which you can choose the shortest.
(6) If you really want to restrict bearings to multiples of 45 degrees, then you can do this algorithm first and then replace each segment by any 45-only wiggly version that avoids obstacles. We know that such a version exists because you can stay extremely close to the original line by wiggling very often. We also know that all such wiggly paths have the same length.
Suppose I have a CPU with several cores, on which I want to find which spheres are touching. Any set of spheres where each sphere is connected (ie. they're all touching at least one of the spheres in the set) is called a "group" and is to be organized into a vector called, in the example below, "group_members". To achieve this I am currently using a rather expensive operation that looks conceptually like this:
vector<Sphere*> unallocated_spheres = all_spheres; // start with a copy of all spheres
vector<vector<Sphere*>> group_sequence; // groups will be collected here
while (unallocated_spheres.size() > 0U) // each iteration of this will represent the creation of a new group
{
std::vector<Sphere*> group_members; // this will store all members of the current group
group_members.push_back(unallocated_spheres.back()); // start with the last sphere (pop_back requires less resources than erase)
unallocated_spheres.pop_back(); // it has been allocated to a group so remove it from the unallocated list
// compare each sphere in the new group to every other sphere, and continue to do so until no more spheres are added to the current group
for (size_t i = 0U; i != group_members.size(); ++i) // iterators would be unsuitable in this case
{
Sphere const * const sphere = group_members[i]; // the sphere to which all others will be compared to to check if they should be added to the group
auto it = unallocated_spheres.begin();
while (it != unallocated_spheres.end())
{
// check if the iterator sphere belongs to the same group
if ((*it)->IsTouching(sphere))
{
// it does belong to the same group; add it and remove it from the unallocated_spheres vector and repair iterators
group_members.push_back(*it);
it = unallocated_spheres.erase(it); // repair the iterator
}
else ++it; // if no others were found, increment iterator manually
}
}
group_sequence.push_back(group_members);
}
Does anyone have any suggestions for improving the efficiency of this code in terms of wall time? My program spends a significant fraction of the time running through these loops, and any advice on how to structurally change it to make it more efficient would be appreciated.
Note that as these are spheres, "IsTouching()" is a very quick floating point operation (comparing position and radii of the two spheres). It looks like this (note that x,y and z are the position of the sphere in that euclidean dimension):
// input whether this cell is touching the input cell (or if they are the same cell; both return true)
bool const Sphere::IsTouching(Sphere const * const that) const
{
// Apply pythagoras' theorem in 3 dimensions
double const dx = this->x - that->x;
double const dy = this->y - that->y;
double const dz = this->z - that->z;
// get the sum of the radii of the two cells
double const rad_sum = this->radius + that->radius;
// to avoid taking the square root to get actual distances, we instead compare
// the square of the pythagorean distance with the square of the radii sum
return dx*dx + dy*dy + dz*dz < rad_sum*rad_sum;
}
Does anyone have any suggestions for improving the efficiency of this code in terms of wall time?
Change the algorithm. Low-level optimization won't help you. (although you'll achieve very small speedup if you move group_members outside of the while loop)
You need to use space partitioning (bsp-tree, oct-tree) or sweep and prune algorithm.
Sweep and prune (wikipedia has links to original article, plus you can google it) can easily handle 100000 moving and potentially colliding spheres on single-core machine (well, as long as you don't put them all at the same coordinates) and is a bit easier to implement than space partitioning. If you know maximum possible size of colliding object, sweep and prune will be more suitable/simpler to implement.
If you're going to use sweep and prune algorithm, you should learn insertion sort algorithm. This sorting algorithm is faster than pretty much any other algorithm when you work on "almost" sorted data, which is the case with sweep-and-prune. Of course, you'll also need some implementation of quicksort or heapsort, but standard library provides that.
I need to draw a polygon in C++. I set random points in vector and then connect them via lines. But sometimes those lines intersect and i get something like this.
Is there any formula or something like that, so that the lines wouldn't cross?
Here is part of the code:
void draw_picture(Canvas & canvas) {
PairXY a,b,c,d,e;
int k;
vector <PairXY> vertex;
vertex.push_back(PairXY(drandom(k),drandom(k)));
vertex.push_back(PairXY(drandom(k),drandom(k)));
vertex.push_back(PairXY(drandom(k),drandom(k)));
vertex.push_back(PairXY(drandom(k),drandom(k)));
vertex.push_back(PairXY(drandom(k),drandom(k)));
vector <PairXY>::const_iterator iter;
iter = vertex.begin();
a=*iter;
iter = vertex.begin()+1;
b=*iter;
iter = vertex.begin()+2;
c=*iter;
iter = vertex.begin()+3;
d=*iter;
iter = vertex.begin()+4;
e=*iter;
Line l1(a,b);
draw_line(l1,canvas);
Line l2(b,c);
draw_line(l2,canvas);
Line l3(c,d);
draw_line(l3,canvas);
Line l4(d,e);
draw_line(l4,canvas);
Line l5(e,a);
draw_line(l5,canvas);
}
Sounds like you want a convex hull.
As far as calculating them goes, you have several options.
I've had good luck with the monotone chain algorithm.
It sounds like what you are probably looking for is a "Simple" (as opposed to "Complex") Polygon:
http://en.wikipedia.org/wiki/Simple_polygon
There's not necessarily a unique solution to that:
Sort point list into polygon
This is why the ordering of points or path segments typically matters in polygon drawing engines. If you are so inclined--however--you can find at least one non-complex polygon for a set of points:
http://www.computational-geometry.org/mailing-lists/compgeom-announce/2003-March/000727.html
http://www.computational-geometry.org/mailing-lists/compgeom-announce/2003-March/000732.html
Others have pointed out your code is repetitive as written. You also don't define k in the excerpt you shared, and it's better to use a plural term for a vector of objects ("vertices") rather than one suggesting it is singular ("vertex"). Here's one fairly simple-to-understand set of changes that should generalize to any number of vertices:
void draw_picture(Canvas & canvas, int k, int numVertices = 5) {
vector<PairXY> vertices;
for (int index = 0; index < numVertices; index++) {
vertices.push_back(PairXY(drandom(k),drandom(k)));
}
vector<PairXY>::const_iterator iter = vertices.begin();
while (iter != vertices.end()) {
PairXY startPoint = *iter;
iter++;
if (iter == vertices.end()) {
Line edgeLine (startPoint, vertices[0]);
draw_line(edgeLine, canvas);
} else {
Line edgeLine (startPoint, *iter);
draw_line(edgeLine, canvas);
}
}
}
There are a lot of ways to manage iterations in C++, although many of them are more verbose than their counterparts in other languages. Recently a nice range-based for loop was added in C++11, but your build environment may not support it yet.
sort the array before drawing it
Find the left most point
than go CCW from there
ie
leftmost where point y < first point y until none found
rightmost point until none found