First, some background:
I'm working on a project which requires me to simulate interactions between objects that can be thought of as polygons (usually triangles or quadrilaterals, almost certainly fewer than seven sides), each side of which is composed of the radius of two circles with a variable (and possibly zero) number of 'rivers' of various constant widths passing between them, and out of the polygon through some other side. As these rivers and circles and their widths (and the positions of the circles) are specified at runtime, one of these polygons with N sides and M rivers running through it can be completely described by an array of N+2M pointers, each referring to the relevant rivers/circles, starting from an arbitrary corner of the polygon and passing around (in principal, since rivers can't overlap, they should be specifiable with less data, but in practice I'm not sure how to implement that).
I was originally programming this in Python, but quickly found that for more complex arrangements performance was unacceptably slow. In porting this over to C++ (chosen because of its portability and compatibility with SDL, which I'm using to render the result once optimization is complete) I am at somewhat of a loss as to how to deal with the polygon structure.
The obvious thing to do is to make a class for them, but as C++ lacks even runtime-sized arrays or multi-type arrays, the only way to do this would be with a ludicrously cumbersome set of vectors describing the list of circles, rivers, and their relative placement, or else an even more cumbersome 'edge' class of some kind. Rather than this, it seems like the better option is to use a much simpler, though still annoying, vector of void pointers, each pointing to the rivers/circles as described above.
Now, the question:
If I am correct, the proper way to handle the relevant memory allocations here with the minimum amount of confusion (not saying much...) is something like this:
int doStuffWithPolygons(){
std::vector<std::vector<void *>> polygons;
while(/*some circles aren't assigned a polygon*/){
std::vector<void *> polygon;
void *start = &/*next circle that has not yet been assigned a polygon*/;
void *lastcircle = start;
void *nextcircle;
nextcircle = &/*next circle to put into the polygon*/;
while(nextcircle != start){
polygon.push_back(lastcircle);
std::vector<River *> rivers = /*list of rivers between last circle and next circle*/;
for(unsigned i = 0; i < rivers.size(); i++){
polygon.push_back(rivers[i]);
}
lastcircle = nextcircle;
nextcircle = &/*next circle to put into the polygon*/;
}
polygons.push_back(polygon);
}
int score = 0;
//do whatever you're going to do to evaluate the polygons here
return score;
}
int main(){
int bestscore = 0;
std::vector<int> bestarrangement; //contains position of each circle
std::vector<int> currentarrangement = /*whatever arbitrary starting arrangement is appropriate*/;
while(/*not done evaluating polygon configurations*/){
//fiddle with current arrangement a bit
int currentscore = doStuffWithPolygons();
if(currentscore > bestscore){
bestscore = currentscore;
bestarrangement = currentarrangement;
}
}
//somehow report what the best arrangement is
return 0;
}
If I properly understand how this stuff is handled, I shouldn't need any delete or .clear() calls because everything goes out of scope after the function call. Am I correct about this? Also, is there any part of the above that is needlessly complex, or else is insufficiently complex? Am I right in thinking that this is as simple as C++ will let me make it, or is there some way to avoid some of the roundabout construction?
And if you're response is going to be something like 'don't use void pointers' or 'just make a polygon class', unless you can explain how it will make the problem simpler, save yourself the trouble. I am the only one who will ever see this code, so I don't care about adhering to best practices. If I forget how/why I did something and it causes me problems later, that's my own fault for insufficiently documenting it, not a reason to have written it differently.
edit
Since at least one person asked, here's my original python, handling the polygon creation/evaluation part of the process:
#lots of setup stuff, such as the Circle and River classes
def evaluateArrangement(circles, rivers, tree, arrangement): #circles, rivers contain all the circles, rivers to be placed. tree is a class describing which rivers go between which circles, unrelated to the problem at hand. arrangement contains (x,y) position of the circles in the current arrangement.
polygons = []
unassignedCircles = range(len(circles))
while unassignedCircles:
polygon = []
start = unassignedCircles[0]
lastcircle = start
lastlastcircle = start
nextcircle = getNearest(start,arrangement)
unassignedCircles.pop(start)
unassignedCircles.pop(nextcircle)
while(not nextcircle = start):
polygon += [lastcircle]
polygon += getRiversBetween(tree, lastcircle,nextcircle)
lastlastcircle = lastcircle
lastcircle = nextcircle;
nextcircle = getNearest(lastcircle,arrangement,lastlastcircle) #the last argument here guarantees that the new nextcircle is not the same as the last lastcircle, which it otherwise would have been guaranteed to be.
unassignedCircles.pop(nextcircle)
polygons += [polygon]
return EvaluatePolygons(polygons,circles,rivers) #defined outside.
Void as template argument must be lower case. Other than that it should work, but I also recommend using a base class for that. With a smart pointer you can let the system handle all the memory management.
Related
I'm trying to move some vertex in an arrangement using an Arrangement_accessor. What I did so far is:
ArrangementAccessor acc(*(self.arr)); // I'm using Objective-C++
Point_2 newPoint = toPoint_2(mouse);
// Change the vertex position
acc.modify_vertex_ex(v, newPoint);
// adjust all incident curves
Arrangement_2::Halfedge_around_vertex_circulator curr, first;
curr = first = v->incident_halfedges();
do {
Point_2 sourcePoint = curr->source()->point();
Segment_2 newSegment = Segment_2(sourcePoint, newPoint);
acc.modify_edge_ex(curr, newSegment);
} while (++curr != first);
This is actually partially working (I ensure no overlapping is produced). But as soon as I change the lexicographically order of some halfedges endpoints, the Arrangement::isValid() returns false.
So my questions are:
Why does changing xy-order destroy the arrangement? I know this is also documented, but I don't really get why this is important.
And: Is there any way to fix this in my implementation? I already tried the easier remove vertex / insert vertex method, but that is not really what I want. (I want to keep the faces and their reference / index mapping alive)
Would be really glad if you could help me understand this.
Yours, Salabasti
The direction of every halfedge is cached to expedite frequent operations. The concept ArrangementDcelHalfedge (https://doc.cgal.org/latest/Arrangement_on_surface_2/classArrangementDcelHalfedge.html#a2bcd73c9eb8383be066161612de98033) requires supporting the methods direction() and set_direction(). So, either you also surgically fix the direction of the affected halfedges using the method set_direction() or you remove these halfedges and then re-insert them. You can retain low complexity by using the specialized insertion functions; see, e.g.,
https://doc.cgal.org/latest/Arrangement_on_surface_2/classCGAL_1_1Arrangement__2.html#a88fed7cf475e474d187e65beb894dde2, and
https://doc.cgal.org/latest/Arrangement_on_surface_2/classCGAL_1_1Arrangement__2.html#a7b90245d8a42ed90ea13b9d911adac73
I am currently going through some code and I currently have a road class, with a vector of pointers to lanes (a private member), and this road class includes a lane class. This lane class contains a vector of pointers to vehicles, which is another class that contains simple get and set functions to update and obtain a vehicle's position, velocity etc. Now, I have vehicles moving in separate lanes and I allow them to switch lanes, as it is so in traffic flow. However, I would like my vehicles to continuously find a distance from it and the vehicle in front, i.e., look in the vehicles vector and find the closest vehicle. Then I intend to use that to instruct whether a car should decelerate or not. I would also like to make sure that cars which are leading the rest, since once a vehicle leaves the displaywindow height, they should be deleted.
My attempt at this is as follows:
void Lane::Simulate(double time)
{ // This simulate allows check between other vehicles.
double forwardDistance = 0;
for (unsigned int iV = 0; iV < fVehicles.size(); iV++)
{
for(unsigned int jV = 0; jV < fVehicles.size(); jV++)
{
forwardDistance = fVehicles[iV]->getPosition() - fVehicles[jV]->getPosition();
}
}
if(fVehicles.size() < 15)
{
addRanVehicle(); // Adds a vehicle, with position zero but random velocities, to each lane.
}
for (unsigned int iVehicle = 0; iVehicle < fVehicles.size(); iVehicle++)
{
fVehicles[iVehicle]->Simulate(time); // Updates position based on time, velocity and acceleration.
}
}
There may be a much better method than using this forwardDistance parameter. The idea is to loop over each pair of vehicles, avoid the point iV == jV, and find the vehicle which is in front of the iVth vehicle, and record the distance between the two vehicles into a setDistance() function (which is a function of my Vehicle class). I should then be able to use this to check whether a car is too close, check whether it can overtake, or whether it just has to brake.
Currently, I am not sure how to make an efficient looping mechanism for this.
Investigate the cost of performing an ordered insert of Vehicles into the lane. If the Vehicles are ordered according to position on the road, detecting the distance of two Vehicles is child's play:
Eg
for (size_t n = 0; n < fVehicles.size() - 1; n++)
{
distance = fVehicles[n].getPosition() - fVehicles[n+1].getPosition();
}
This is O(N) vs O(N^2) (using ^ as exponent, not XOR). The price of this simplification is the requiring ordered insert into fVehicles, and that should be O(N): One std::binary_search to detect the insertion point and whatever shuffling is required by fVehicles to free up space to place the Vehicle.
Maintaining ordering of fVehicles may be beneficial in other places as well. Visualizing the list (graphically or by print statements) will be much easier, debugging is generally easier on the human brain when everything is in a nice predictable order, and CPUs... They LOVE going in a nice, predictable straight line. Sometimes you get a performance boost that you didn't see coming. Great write-up on that here: Why is it faster to process a sorted array than an unsorted array?
Only way to be sure if this is better is to try it and measure it.
Other Suggestions:
Don't use pointers to the vehicles.
Not only are they harder to manage, they can slow you down quite a bit. As mentioned above, modern CPUs are really good at going in straight lines, and pointers can throw a kink in that straight line.
You never really know where in dynamic memory a pointer is going to be relative to the last pointer you looked at. But with a contiguous block of Vehicles , when the CPU loads Vehicle N it can possibly also grab Vehicles N+1 and N+2. If it can't because they are too big, it doesn't matter much because it already knows where they are, and while the CPU is processing, and idle memory channel could be reading ahead and grabbing the data you're going to need soon.
With the pointer you save a bit every time you move a Vehicle from lane to lane (pointers are usually much cheaper than objects to copy), but may suffer on each and every loop iteration in each and every simulation tick and the volume really adds up. Bjarne Stroustrup, God-Emperor of C++, has an excellent write up on this problem using linked lists as an example (Note linked list is often worse than vector of pointer, but the idea is the same).
Take advantage of std::deque.
std::vector Is really good at stack-like behaviour. You can add to and remove from the end lightning fast, but if you add to or remove from the beginning, everything in the vector is moved.
Most of the lane insertions are likely to be at one end and the removals at the other simply because older Vehicles will gravitate toward the end as Vehicles are added to the beginning or vise versa. This is a certainty if suggestion 1 is taken and fVehicles is ordered. New vehicles will be added to the lane at the beginning, a few will change lanes into or out of the middle, and old vehicles will be removed from the end. deque is optimized for inserting and removing at both ends so adding new cars is cheap, removing old cars is cheap and you only pay full price for cars that change lanes.
Documentation on std::deque
Addendum
Take advantage of range-based for where possible. Range-based for takes most of the iteration logic away and hides it from you.
Eg this
for (unsigned int iV = 0; iV < fVehicles.size(); iV++)
{
for(unsigned int jV = 0; jV < fVehicles.size(); jV++)
{
forwardDistance = fVehicles[iV]->getPosition() - fVehicles[jV]->getPosition();
}
}
becomes
for (auto v_outer: fVehicles)
{
for (auto v_inner: fVehicles)
{
forwardDistance = v_outer->getPosition() - v_inner->getPosition();
}
}
It doesn't look much better if you are counting lines, but you can't accidentally
iV <= fVehicles.size()
or
fVehicles[iV]->getPosition() - fVehicles[iV]->getPosition()
It removes the possibility for you to make silly, fatal, and hard-to-spot errors.
Let's break one down:
for (auto v_outer: fVehicles)
^ ^ ^
type | |
variable name |
Container to iterate
Documentation on Range-based for
In this case I'm also taking advantage of auto. auto allows the compiler to select the type of the data. The compiler knows that fVehicles contains pointers to Vehicles, so it replaces auto with Vehicle * for you. This takes away some of the headaches if you find yourself refactoring the code later.
Documentation on auto
Unfortunately in this cans it can also trap you. If you follow the suggestions above, fVehicles becomes
std::dequeue<Vehicle> fVehicles;
which means auto is now Vehicle. Which makes v_outer a copy, costing you copying time and meaning if you change v_outer, you change a copy and the original goes unchanged. to avoid that, tend toward
for (auto &v_outer: fVehicles)
The compiler is good at deciding how best to handle that reference or if it even needs it.
so I'm making a lame little snowboarding game (which is what all my questions have been about) and I'm having some issues.
I have a Biome class, which has a dynamic array to store the possible obstacles for that biome (obstsInBiome). Here is the constructor:
Biome::Biome(Obstacle obsts[], int amountOfObsts)
{
maxObstAmount = 10; // Max amount of obstacles to spawn in each biome
obstAmount = amountOfObsts; // The amount of obstacles passed in in the obsts parameter
// This part copys the array passed in to the obstsInBiome array (Class member to store obstacles)
// I think this is where the error may be
obstsInBiome = new Obstacle [amountOfObsts]; // Creating array to hold the possible obstacles in this biome
for (int x = 0; x < amountOfObsts; x++) // Filling the obstacle array with the obstacles passed in
{
obstsInBiome[x] = obsts[x];
}
}
Then to create a new biome, i use this:
Obstacle villageObsts[] = {tree, rock, cabin, log}; // tree, rock, and cabin are all Obstacles
Biome village(villageObsts, 4);
Somewhere within this code, the first element of obstsInBiome is not getting set properly.
village.obstsInBiome[0] is what I mean.
When i try to draw that to the screen, it doesn't appear and invisible collisions happen with the player as if they hit the obstacle. The rest of the array (rock, cabin, and log) all work perfectly. village.obstsInBiome[1 through 3] all work fine.
Can someone point out the error in this code?
At first glance, in particular at where you say you think the error is, it could be in the implementation of the copy constructor for the tree. I don't know what exactly an "Obstacle" is, nor do I know what the specific characteristics of those 4 instances are. Perhaps the tree instance has some kind of data that doesn't copy cleanly, whereas the other 3 do.
If you aren't sure what I mean by the copy constructor, that is probably a good thing to learn about.
http://en.wikipedia.org/wiki/Copy_constructor
So I have a Node class that contains a member variable "center" that is a Vec2float*. The reason for this is because I want to use the drawSolidCircle function, and I need a Vec2float variable to represent the center. One of the questions I have is, is a Vec2float a vector, or a point in space? A lot of the member functions make it sound like some kind of vector class, yet the set() function only takes in two arguments which makes it seem like a point in space, and in order to draw a circle, you would need a point and a radius, not a vector. Also another problem I am having, is that if someone gives me 2 doubles, how can I convert them to Vec2float properly and set the x and y of center (if it even has an x and y). So for example in the function below, I am given an array of Entries and the length of it, 'n'. An entry has two member variables 'x' & 'y' which are both doubles. I want to create an array of Nodes and copy over that data to use it to draw circles.
cinder::Vec2<float>* center;//in my Node class
void function::build(Entry* c, int n) {
Node* nd = new Node[n];
for(int i = 0;i<n;i++) {
nd[i].center = //what goes here if c[i].x and c[i].y are doubles?
}
references:
Vec2 class: http://libcinder.org/docs/v0.8.4/classcinder_1_1_vec2.html
list of functions that draw shapes, im using drawSolidCircle: http://libcinder.org/docs/v0.8.4/namespacecinder_1_1gl.html
Any suggestions?
To make your life easy, you can use the cinder namespace. Add the following line after the includes at the top of your file.
using namespace ci;
which then enables you to simply write, for example:
Vec2f center(1.5f, 1.5f);
std::cout << center << std::endl;
Indeed, Vec2<float> is typedef'ed as Vec2f in Cinder.
Also, you shouldn't have to cast doubles into floats because they are casted implicitly, just pass them in!
Lastly, you really have to be careful with pointers. Most of the time, if I want an array of objects, I would use a std::vector, and use shared_ptr. Here's where I learned how to do just that: https://forum.libcinder.org/topic/efficiency-vector-of-pointers
I won't cover the whole theory behind vectors. Here's a good reference (using the Processing language): http://natureofcode.com/book/chapter-1-vectors/ In short, yes you should use them to store positions, but mathematically they are still vectors (you can think of a position vector as an arrow from the origin (0,0) to your current position).
I also suggest you have a look at the numerous samples provided with the library.
well i figured something out, it compiles for now, whether it will work for my program in the future is debatable. But here is what i did:
float f1 = (float)(c[i].x);
float f2 = (float)(c[i].y);
cinder::Vec2<float>* p = new cinder::Vec2<float>(f1,f2);
nd[i].center = p;
i casted the doubles to floats separately, then made a variable p using the Vec2 constructor, and then set center equal to that. like i said it compiles, we shall see if it works :D
I've got a question about the architecture of a data structure I'm writing. I'm writing an image class, and I'm going to use it in a specific algorithm. In this algorithm, I need to touch every pixel in the image that's within a certain border. The classic way I know to do this is with two nested for loops:
for(int i = ROW_BORDER; i < img->height - ROW_BORDER; i++)
for(int j = COL_BORDER; j < img->width - COL_BORDER; j++)
WHATEVER
However, I've been told that in style of the STL, it is in general better to return an iterator rather than use loops as above. It would be very easy to get an iterator to look at every pixel in the image, and it would even be easy to incorporate the border constraints, but I feel like included the border is blowing loose coupling out of the water.
So, the question is, should I return a special "border-excluding iterator", use the for loops, or is there a better way I haven't thought of?
Just to avoid things like "well, just use OpenCV, or VXL!" , I'm not actually writing an image class, I'm writing a difference-of-gaussian pyramid for use in a feature detector. That said, the same issues apply, and it was simpler to write two for loops than three or four.
To have something reusable, I'd go with a map function.
namespace your_imaging_lib {
template <typename Fun>
void transform (Image &img, Fun fun) {
const size_t width = img.width(),
size = img.height() * img.width();
Pixel *p = img.data();
for (size_t s=0; s!=size; s+=width)
for (size_t x=0; x!=width; ++x)
p[x + s] = fun (p[x + s]);
}
template <typename Fun>
void generate (Image &img, Fun fun) {
const size_t width = img.width(), size = img.height();
Pixel *p = img.data();
for (size_t s=0, y=0; s!=size; s+=width, ++y)
for (size_t x=0; x!=width; ++x)
p[x + s] = fun (x, y);
}
}
Some refinement needed. E.g., some systems like x, y to be in [0..1).
You can then use this like:
using namespace your_imaging_lib;
Image i = Image::FromFile ("foobar.png");
map (i, [](Pixel const &p) { return Pixel::Monochrome(p.r()); });
or
generate (i, [](int x, int y) { return (x^y) & 0xFF; });
Iff you need knowledge of both coordinates (x and y), I guarantee this will give better performance compared to iterators which need an additional check for each iteration.
Iterators, on the other hand, will make your stuff usable with standard algorithms, like std::transform, and you could make them almost as fast if pixel positions are not needed and you do not have a big pitch in your data (pitch is for alignment, usually found on graphics hardware surfaces).
I suspect you should be using the visitor pattern instead-- instead of returning an iterator or some sort of collection of your items, you should pass in the operation to be done on each pixel/item to your data structure that holds the items, and the data structure should be able to apply that operation to each item. Whether your data structure uses for loops or iterators to traverse the pixel/whatever collection is hidden, and the operation is decoupled from the data structure.
IMHO it sounds like a good idea to have an iterator that touches every pixel. However, it doesn't sound as appealing to me to include the border constraints inside of it. Maybe try to achieve something like:
IConstraint *bc=new BorderConstraint("blue-border");
for(pixel_iterator itr=img.begin(); itr!=img.end(); itr++) {
if(!bc->check(itr))
continue;
// do whatever
}
Where IConstraint is a base class that can be derived to make many different BorderConstraints.
My rationale is that iterators iterate in different ways but I don't think they need to know about your business logic. That could be abstracted away into another design construct as depcited via Constraints above.
In the case of bitmap data it is noteworthy that there are no iterator based algorithms or datasets commonly used in the popular image manipulation APIs. This should be a clue as to that it is hard to implement as efficiently as a regular 2D array. (thanks phresnel)
If you really require/prefer an iterator for your image sans border, you should invent a new concept to iterate. My suggestion would be something like an ImageArea.
class ImageArea: Image
{ int clipXLeft, clipXRight;
int clipYTop, clipYBottom;
public:
ImageArea(Image i, clipXTop ... )
And construct your iterator from there. The iterators can then be transparent to work with images or regions within an image.
On the other hand, a regular x/y index based approach is not a bad idea. Iterators are very useful for abstracting data sets, but comes with a cost when you implement them on your own.