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
Related
I thought that a cool way of using vectors could be to have one vector class template hold an two separate int variables for x/y-coordinates to graph.
example:
std::vector<int, int> *name*;
// First int. being the x-intercept on a graph
// Second int. being the y-intercept on a graph
(I also understand that I could just make every even/odd location or two separate vectors to classify each x/y-coordinate, but for me I would just like to see if this could work)
However, after making this vector type, I came across an issue with assigning which int within the vector will be written to or extracted from. Could anyone tell me how to best select and std::cout both x/y ints appropriately?
P.S. - My main goal, in using vectors this way, is to make a very basic graph output to Visual Studio terminal. While being able to change individual x/y-intercepts by 'selecting' and changing if needed. These coordinates will be outputted to the terminal via for/while loops.
Also, would anyone like to list out different ways to best make x/y-coordinates with different containers?
Your question rather broad, in other words it is asking for a bit too much. I will just try to give you some pointers from which you can work your way to what you like.
A) equidistant x
If your x values are equidistant, ie 0, 0.5, 1, 1.5 then there is no need to store them, simply use a
std::vector<int> y;
if the number of variables is not known at compile time, otherwise a
std::array<int,N> y;
B) arbitrary x
There are several options that depend on what you actually want to do. For simply storing (x,y)-pairs and printing them on the screen, they all work equally well.
map
std::map<int,int> map_x_to_y = { { 1,1}, {2,4}, {3,9}};
// print on screen
for (const auto& xy : map_x_to_y) {
std::cout << xy.first << ":" xy.second;
}
a vector of pairs
std::vector<std::pair<int,int>> vector_x_and_y = { { 1,1}, {2,4}, {3,9}};
Printing on screen is actually the same as with map. The advantage of the map is that it has its elements ordered, while this is not the case for the vector.
C) not using any container
For leightweight calculations you can consider to not store the (xy) pairs at all, but simply use a function:
int fun(int x) { return x*x; }
TL;DR / more focussed
A vector stores one type. You cannot have a std::vector<int,int>. If you look at the documentation of std::vector you will find that the second template parameter is an allocator (something you probably dont have to care about for some time). If you want to store two values as one element in a vector you either have to use std::vector<std::pair<double,double>> or a different container.
PS
I used std::pair in the examples above. However, I do consider it as good practice to name things whenever I can and leave std::pair for cases when I simply cannot give names better than first and second. In this spirit you can replace std::pair in the above examples with a
struct data_point {
int x;
int y;
};
I'm working on a program using SDL. I have the following variable instantiated outside of my main function:
std::vector<SDL_Rect[TOTAL_ACTIVITIES][TOTAL_DIRECTIONS][ANIMATION_FRAMES]> gPersonSpriteClips;
(where the all-caps items are constant integers). It's a vector of arrays, because I intend to do a lot of sprite development later. For now, I just have a few placeholder sprites. So, the 3D array captures all aspects of a single human body-type spritesheet, and when I pull in the sheet I'll have the code split it up into multiple body types...
I have a class, "Character", which makes use of the array when it is preparing to render. Here is the call to render myCharacter in main:
myCharacter.render(bodySpritesheetTexture, &*gPersonSpriteClips[myCharacter.getBody()]);
Character.getBody() returns the vector index for the body type used by this instance of character. Here is the function declaration in Character.h:
void render(LTexture& characterSpriteSheetTexture, SDL_Rect spriteClips[TOTAL_ACTIVITIES][TOTAL_DIRECTIONS][ANIMATION_FRAMES]);
Here is the function itself in Character.cpp:
void Character::render(LTexture& characterSpriteSheetTexture, SDL_Rect spriteClips[TOTAL_PERSON_ACTIVITIES][TOTAL_CARDINAL_DIRECTIONS][PERSON_ANIMATION_FRAMES])
{
characterSpriteSheetTexture.render( mPosition.x, mPosition.y, &spriteClips[mActivity][mDirection][mAnimations[mActivity][mCurrentFrame]] );
}
mActivity is the enum for "which activity is presently being performed" by the character. mDirection is which direction he's facing. mAnimations lists frame orders (because some of these animations use the same sprites several times in various orders).
Finally, the render function for LTexture is taken right out of LazyFoo's SDL tutorials.
characterSpriteSheetTexture.render() is calling a function with the following declaration (in LTexture.h):
void render( int x, int y, SDL_Rect* clip = NULL, int targetHeight = NULL, int targetWidth = NULL, double angle = 0.0, SDL_Point* center = NULL, SDL_RendererFlip flip = SDL_FLIP_NONE );
So it's expecting an argument of type SDL_Rect* clip. That function makes a call to:
SDL_RenderCopyEx( gRenderer, mTexture, clip, &renderQuad, angle, center, flip );
I get an error when I compile the code, pointing me to a place inside the SDL libraries. I've successfully employed LTexture's render function by passing indexes from one-dimensional arrays of SDL_Rect into it, so I'm very confident that the problem exists in my vector argument.
Ignoring disagreements about naming conventions...... what am I doing wrong here, and what's the proper way to achieve what I'm trying to do?
Granted, I'll probably simplify my scheme for animating things significantly in the future; this is my first shot at generating a player character. Anyway, I'd like to know the mechanics of what's going wrong in this case.
Last thing, please don't suggest that I use boost. I'd really like to avoid boost for this program.
ETA:
Here is the declaration of mAnimations in Character.h:
std::vector<int> mAnimations[TOTAL_ACTIVITIES];
Here is the initialization of it in the default constructor:
for (int i = 0; i < TOTAL_ACTIVITIES; i++)
{
mAnimations[i].resize(ANIMATION_FRAMES);
for (int j = 0; j < ANIMATION_FRAMES; j++)
{
mAnimations[i][j] = j;
}
}
Change your global array definition like this:
using SdlRectArray = std::array<std::array<std::array<SDL_Rect, ANIMATION_FRAMES>, TOTAL_DIRECTIONS>, TOTAL_ACTIVITIES>;
std::vector<SdlRectArray> gPersonSpriteClips;
See here for why not to store arrays in a std::vector or any other container.
Accordingly, define your Character::render() method like this:
void render(LTexture& characterSpriteSheetTexture, SdlRectArray& spriteClips)
{
characterSpriteSheetTexture.render( mPosition.x, mPosition.y, &spriteClips[mActivity][mDirection][mAnimations[mActivity][mCurrentFrame]] );
}
And then you can call it like this:
myCharacter.render(bodySpritesheetTexture, gPersonSpriteClips[myCharacter.getBody()]);
as there's no need for doing &*.
It is difficult to tell from your question what the exact error is, but it seems likely that the root cause is "array decay".
In C++ (and in C), array arguments are almost always treated as pointers to the start of the array. For a multidimensional array, this means that the multiple-indexing you expect can't work, because the language has stripped away the size and shape information necessary.
The sole exception is that reference parameters do not decay in this way. However, if you rely on this, you (and anyone else who works on your code) will need to remember to use that exact reference parameter every time they pass the multidimensional array to another function.
In modern C++, this issue is typically fixed using std::array<>, which was designed for the purpose. In your case, that would be very verbose, so I'd suggest a type alias:
typedef std::array< std::array< std::array<SDL_Rect,
ANIMATION_FRAMES>, TOTAL_DIRECTIONS>, TOTAL_ACTIVITIES> SpriteClip;
std::vector<SpriteClip> gSpriteClips;
Alternatively, you could write a short class:
class SpriteClip {
SDL_Rect m_data[TOTAL_ACTIVITIES][TOTAL_DIRECTIONS][ANIMATION_FRAMES];
public:
SDL_Rect& get(activity, direction, frame) {
return m_data[activity][direction][frame];
}
};
This would let you change the representation easily -- for example, if you decided that you wanted different sprites to have different numbers of activities and frames.
I am writing a small toy game engine using Tinyobjloader for loading .obj files. I store the vertex data and everything using glm::vecX to make things easier.
Tinyobjloader gives me an std::vector<float>, when I want an std::vector<glm::vecX>. How would I do this without copying?
To be clear, a glm::vecX is a simple struct containing, for example, the float members x, y, z.
I was thinking that since structs can behave a bit like arrays, that std::move would work, but no luck.
Thanks!
Edit:
I know I wasn't clear about this, sorry. I would like to either move the std::vector<float> into an std::vector<glm::vecX> or pass it as a std::vector<glm::vecX>&.
Copying the data using std::memcpy works fine, but it copies the data, which I would like to avoid.
It may be possible to directly interpret the contents of the vector as instances of the struct, without having to copy the data. If you can guarantee the representation is compatible, that is. The contents of a vector<float> are laid out in memory as a sequence of float values directly following each other (an array) with no extra padding, while the contents of a vector<glm::vecX> are laid out as a sequence of vecX. Thus, you need to ensure the following conditions hold:
That glm::vecX is exactly the size of X floats, with no padding. Depending on the declaration of the struct, this may be platform-dependant.
That the contents of the vector<float> are in the correct sequence, i.e. as [x1,y1,z1, x2,y2,z2, ...] for a vec3 instead of [x1,x2,...,xN,y1,y2...].
In that case, you can safely reinterpret the data pointer of the float vector as pointer to an array of vecX as in this example:
std::vector<float> myObjData = ...;
auto nVecs = myObjData.size() / 3; // You should check that there are no remainders!
glm::vec3* vecs = reinterpret_cast<glm::vec3*>(myObjData.data());
std::cout << vecs[0]; // Use vecs[0..nVecs-1]
You cannot, however, safely reinterpret the vector itself as a vector of glm::vecX, not even as a const vector, because the number of elements stored in the vector might not be consistent after the reinterpretation. It depends on whether the vector<T> code stores the number of elements directly, or the number of allocated bytes (and then size() divides that by sizeof(T)):
// Don't do this, the result of .size() and .end() may be wrong!
const std::vector<glm::vec3>& bad = *reinterpret_cast<std::vector<glm::vec3>*>(&myObjData);
bad[bad.size()-1].z = 0; // Potential BOOM!
Most of the time, however, you don't need to pass an actual vector, since most functions in the standard library accept a container range, which is easy to give for arrays like the one in the first example. So, if you wanted to sort your vec3 array based on z position, and then print it out you would do:
// nVecs and vecs from the first example
std::sort(vecs, vecs+nVecs, // Sort by Z position
[](const glm::vec3& a, const glm::vec3& b) { return a.z < b.z; });
std::copy(vecs, vecs+nVecs, std::ostream_iterator<glm::vec3>(std::cout, "\n"));
In short: It is - to the best of my knowledge - not possible without copying.
And in my opinion, std::memcpy has no business being used with std::vector.
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.
i've just begin to approach in cpp. so mayebe it is a simple problem, mayebe it is a structural problem and i have to change my design.
i have 3 facts and 1 problem.
fact 1:
i have a Gesture class with a vector of Point inside
vector<Point> Gesture::getPoints();
the Gesture instances recive the vector in the constructor so i think it could be normal vector (no pointer). vectors are not shared between gestures neither a gesture change its own points (aside normalization).
fact 2:
Gesture class has a static method that normalize all points between [0:w]. normalize take a memory address to normalize in-place. i think that normalization in place could be a nice thing. this normalization method is used by widgets to visualize the path in vector for normalize point between 0 and width-of-the-widget
static void Gesture::normalize(vectot<Point> &pts, int w);
fact 3:
i have a widget that visualize points:
void MyWidget::setGestures(vector <Gesture *> gs)
because the gesture is produced by another widget dinamically i thought that it has been handy to work with a vector of pointer and can do some new Gesture calls.
problem:
i have several widget that visualize gesture. each one with a different width (== different normalization).
the first time i use:
Gesture::rescale(this->w, this->points);
Gesture * g = new Gesture(getPoints(), centroids);
and it's everything ok
the second time i have:
vector<Gesture* > gs = foo();
int num_gesture = gs.size();
for (int i = 0; i < num_gesture; ++i) {
vector<Point> pts = gs.at(i)->getPoints();
Gesture::rescale( widget->getWidth(), pts );
}
widget->setGestures(gs);
and here there are problem because this widget is drawing not normalized points.
i have tried some crazyness with pointers but if the program does not crash.. anyway it not normalized. and it get some error like: pointer to a temporary.
i don't knwo what to think, now.
Although your question is a little confusing, the problem seems to be that Gesture::getPoints() returns a vector and not a reference to a vector, so it actually returns a copy to the internal vector, and so changing it does not modify the gesture object itself.