Hard Light Productions Forums
Off-Topic Discussion => Programming => Topic started by: Thaeris on December 06, 2009, 02:42:45 pm
-
I'm currently in the process of building a program for my C++ final. After scouring the text for a good long time, there's a few setbacks which I just don't have the necessary knowledge to overcome.
First, however, I'll describe the program:
The program is quite simple when the parts as a whole are laid out... Essentially, the idea of the project is to use an algoritm based on normal distribution to generate a random mesh of user-determined dimensions. That said, here's how it does that:
(1.) The program needs to output a formatted text file in the X-Plane 700 object format. I chose to use this format as it can be visually read and interpereted by the user - thus, it's easy to write a program which writes the files for you; I can also open the files with AC3D. Here's an example:
A
700
OBJ
texture
quad
1 0 0 1 0
1 0 1 1 1
0 0 1 0 1
0 0 0 0 0
end
Basically, the program writes quads, which are conveniently described by a 4x5 matrix. Note that the last two columns are texture coordinates - those had to be included so the file could be read. The last two columns are a constant and are thus repeated for every quad generated. Generating a quad mesh is pretty darn easy - Here's the latest stable header file:
#pragma once
#include <iostream>
using namespace std;
void quadgen(unsigned int x, unsigned int z)
{
unsigned int xinit = x;
cout << "A" << endl;
cout << "700" << endl;
cout << "OBJ" << endl;
cout << "texture" << endl;
while ( z > 0 )
{
z--;
while ( x > 0 )
{
x--;
const int ROWS = 4;
const int COLS = 5;
double quad[ ROWS ][ COLS ] = { ( 1 + x ), 0, ( 0 + z ), 1, 0,
( 1 + x ), 0, ( 1 + z ), 1, 1,
( 0 + x ), 0, ( 1 + z ), 0, 1,
( 0 + x ), 0, ( 0 + z ), 0, 0 };
cout << "quad" << endl;
cout << quad[ 0 ][ 0 ] << "\t" << quad[ 0 ][ 1 ] << "\t" << quad[ 0 ][ 2 ] << "\t" << quad[ 0 ][ 3 ] << "\t" << quad[ 0 ][ 4 ] << endl;
cout << quad[ 1 ][ 0 ] << "\t" << quad[ 1 ][ 1 ] << "\t" << quad[ 1 ][ 2 ] << "\t" << quad[ 1 ][ 3 ] << "\t" << quad[ 1 ][ 4 ] << endl;
cout << quad[ 2 ][ 0 ] << "\t" << quad[ 2 ][ 1 ] << "\t" << quad[ 2 ][ 2 ] << "\t" << quad[ 2 ][ 3 ] << "\t" << quad[ 2 ][ 4 ] << endl;
cout << quad[ 3 ][ 0 ] << "\t" << quad[ 3 ][ 1 ] << "\t" << quad[ 3 ][ 2 ] << "\t" << quad[ 3 ][ 3 ] << "\t" << quad[ 3 ][ 4 ] << endl;
}
x = xinit;
}
cout << "end" << endl;
return;
}
void watertable(int yn, unsigned int x, unsigned int z, double wateralt)
{
if ( yn == 1 )
{
const int ROWS = 4;
const int COLS = 5;
double quad[ ROWS ][ COLS ] = { x, wateralt, 0, 1, 0,
x, wateralt, z, 1, 1,
0, wateralt, z, 0, 1,
0, wateralt, 0, 0, 0 };
cout << "A" << endl;
cout << "700" << endl;
cout << "OBJ" << endl;
cout << "texture" << endl;
cout << "quad" << endl;
cout << quad[ 0 ][ 0 ] << "\t" << quad[ 0 ][ 1 ] << "\t" << quad[ 0 ][ 2 ] << "\t" << quad[ 0 ][ 3 ] << "\t" << quad[ 0 ][ 4 ] << endl;
cout << quad[ 1 ][ 0 ] << "\t" << quad[ 1 ][ 1 ] << "\t" << quad[ 1 ][ 2 ] << "\t" << quad[ 1 ][ 3 ] << "\t" << quad[ 1 ][ 4 ] << endl;
cout << quad[ 2 ][ 0 ] << "\t" << quad[ 2 ][ 1 ] << "\t" << quad[ 2 ][ 2 ] << "\t" << quad[ 2 ][ 3 ] << "\t" << quad[ 2 ][ 4 ] << endl;
cout << quad[ 3 ][ 0 ] << "\t" << quad[ 3 ][ 1 ] << "\t" << quad[ 3 ][ 2 ] << "\t" << quad[ 3 ][ 3 ] << "\t" << quad[ 3 ][ 4 ] << endl;
cout << "end" << endl;
}
return;
}
So yeah, with the proper program, I can currently generate a triangulated mesh of meter^2 increments out to wahzoo dimensions... but only in the C++ ouput window. The problem with the output window, of course, is that it only retains so much data. For example, generating a 10x10 meter mesh is futile because the first quads generated WILL NOT BE THERE when I scroll to the top of the window. This is why outputting the data is essential.
Enter problem #1: The only file ouput stream I know how to use works like so: "[insert output file name here] << [insert output data here] << endl;
Yes, the file was initialized using fstream, so that's not the issue. The issue is that this method of dumping data into the file (which is created by the program, so that's no concern) is JUST THE SAME as a "cout << [place a function here that has a "cout << output" - type code within] << endl;" line, which just won't work... possibly due to overload reasons? Regardless, that's a huge problem, as X-Plane 700 object format needs to look like the example above: all the relative lines of code in that format rely on new lines and spaces to make the data work. Thus, I need to know how to make the desired output which pops up on the output screen get written directly to the output file.
Problem #2: The "y" coordinates of the "quadgen()" function are determined by a "pointmap" matrix. I've got a stable algorithm for inputting the y-coordinates in the function (which will need to be expanded to handle a matrix input), but that's in a test program... for a good reason. The program uses a pointmap of random numbers via an algorithm based off of normal distribution (I still need to write that, so don't ask...) to generate A USER-DETERMINED SIZED PLOT OF TERRAIN. As the "pointmap" corresponds directly to the "x" and "z" coordinates of the mesh, with the modified dimensions of ( x + 1 ) and ( z + 1 ) to accomodate for the edge verticies; the number of rows and colums (which need to be of const int type) cannot be initialized BECAUSE I CAN'T GET THE RESULTANT TERMS TO BE RECOGNIZED AS CONSTANT INTERGERS!!! I'm considering writing a function to do this, but as everything I've tried so far in the main window has failed, I really doubt a function is going to return the values I need. Thus, until I get this figured out, the y-coordinates needed by "quadgen()" from the "pointmap" matrix aren't any closer to getting in...
I'll be back in class by Tuesday, but I'd really like to get the minor functionality functions of the program (which are ironically vital...) in order. The sooner I get this done, the better. And, once it's done, I'll be happy to share the program with anyone who's interested. There is a X-Plane object plug-in for Blender, I believe, so If you don't have a version of AC3D which supports the X-Plane plug-in (most people wouldn't), you can still use it. ;)
-
Well, earlier today I tried to write a function that would return a 'const int' value to the the row and column parameter declarations. Even doing that, the program will still not recognize the input interger value. This is really bizzare, as if you input a normal interger directly into 'int RWS' or 'int CLS,' the program (well, at least the test version running this segment...) will function.
Really, someone must have an idea of how to get around this...
-
Do it like this:
#include <stdio.h>
using namespace std;
void quadgen(FILE* f, unsigned int x, unsigned int z)
{
fputs("A",f);
fputs("700",f);
fputs("OBJ",f);
fputs("texture",f);
while ( z > 0 )
{
z--;
while ( x > 0 )
{
x--;
const int ROWS = 4;
const int COLS = 5;
double quad[ ROWS ][ COLS ] = { ( 1 + x ), 0, ( 0 + z ), 1, 0,
( 1 + x ), 0, ( 1 + z ), 1, 1,
( 0 + x ), 0, ( 1 + z ), 0, 1,
( 0 + x ), 0, ( 0 + z ), 0, 0 };
fputs("quad", f);
fprintf(f, "%i\t%i\t%i\t%i\n", quad[ 0 ][ 0 ],quad[ 0 ][ 1 ],quad[ 0 ][ 2 ],quad[ 0 ][ 3 ],quad[ 0 ][ 4 ]);
fprintf(f, "%i\t%i\t%i\t%i\n", quad[ 1 ][ 0 ],quad[ 1 ][ 1 ],quad[ 1 ][ 2 ],quad[ 1 ][ 3 ],quad[ 1 ][ 4 ]);
fprintf(f, "%i\t%i\t%i\t%i\n", quad[ 2 ][ 0 ],quad[ 2 ][ 1 ],quad[ 2 ][ 2 ],quad[ 2 ][ 3 ],quad[ 2 ][ 4 ]);
fprintf(f, "%i\t%i\t%i\t%i\n", quad[ 3 ][ 0 ],quad[ 3 ][ 1 ],quad[ 3 ][ 2 ],quad[ 3 ][ 3 ],quad[ 3 ][ 4 ]);
}
x = xinit;
}
fputs("end", f);
}
Then at the start of your program, use this code to initialize the FILE* pointer:
FILE* f = fopen("yourfile.txt", "w");
Pass that into all the write functions, then when you are done, do this:
fclose(f);
-
Thanks, Erik.
I'll talk to my professor tomorrow about this method; this is an introductory C++ course, and string usage/file outputs weren't in the normal curriculum.
And once again, thank you. :yes:
-
Thaeris:
Code shouldn't be included in header files like that unless it's inlined in some fashion - you'll get linker errors when your program becomes a little bigger.
Examples of inlining are using the keyword 'inline' or including in a class - it's necessary for some template 'incantations' ( :P ) to have code in the same place as the declaration.
I haven't tried compiling your code, but I can't see what the problem with using streams - I'm assuming you've tried std::ofstream.
-
I'll talk to my professor tomorrow about this method; this is an introductory C++ course, and string usage/file outputs weren't in the normal curriculum.
Obviously they need to change the curriculum. :wtf:
-
Thank you for the feedback.
I assume looking into the cstdio library will help a lot with the output. Furthermore, a suggestion from my professor should get the user-specified matrix dimension taken care of...
All that's left to do after that is to write the algorithm which inputs numbers into the user-specified matrix; this portion of the code will be "modular," thus enabling better or different terrain elevation functions to be implemented.
@ portej05: The header file to date that I've included with my program only deals with plotting the quad surfaces I've mentioned; those code items are simply functions, not the "main gears" which enable the program to run. :)
Lastly, once the code is in a fairly stable state, I'll upload the .cpp and .h files if you're curious. :D
-
You'll still have problems with the linker if you include the header file more than once from anywhere.
You should be looking at the fstream header for file output.
There's the file streams in there - anything using an actual FILE* descriptor is really a C-sort-of API, and I'm not sure your professor will like that!
-
You'll still have problems with the linker if you include the header file more than once from anywhere.
You should be looking at the fstream header for file output.
There's the file streams in there - anything using an actual FILE* descriptor is really a C-sort-of API, and I'm not sure your professor will like that!
FILE* pointers are the easiest to use and far more sensible then a convoluted fstream that is totally unnecessary and complete overkill in this situation.
-
Seriously?
int i;
float j;
std::ofstream file( "filename.txt" );
file << "Hello World" << i << j << std::endl;
int i;
float j;
FILE* fp = fopen( "filename.txt", "w" );
fprintf( fp, "%s%d%f\n", "Hello World", i, j );
fclose( fp );
-
In general, Streams are much, much better.
- In education, remember that File pointers are not C++, they're C.
Secondly, Streams are objects.
They handle themselves - you don't have to worry about allocating enough buffer or handling overflows when the data gets slightly too big for the buffer you allocated.
It just happens.
- There are operators to tell them how much space to pre-allocate before you start writing, but you only need to do that for the speed gain. (Also it often means the memory usage is smaller, as they'll allocate in 'blocks', generally with the blocks getting bigger the more stuff you write to them).
The 'object' nature also means that if (when) you later decide that this stream actually should be part of a larger stream or needs further processing, it's trivial to do.
Eg:
- We want to display the surface on screen,
- The 'surface' we're creating needs buildings put onto it, so the stream actually shouldn't be immediately saved but passed to another function to add the buildings.
Portej is absolutely right about the header files though - you really don't want code there.
It should just be declarations of the class variables (public and private), and forward declarations of the functions you're going to implement in the associated .c++ file.
The reason for it is that it makes it much easier and faster to compile 'larger' programs that use your current small program for some utility - the larger program only needs to load the header file, and not the whole thing. Then the actual code in your small program can be already compiled ready for static linking (usually .o), or even fully compiled into a DLL that gets loaded at runtime.
-
Tomo: You'll also get multiply-defined symbol errors from the linker if you include the header in more than one compilation unit.
-
Alright, I'm moving along with this, but I've still got a few problems:
First off, I'll once again make a note that there are only two functions in the header file I'm using. I've used the simpler one to test the cstdio library on. Once more, that function goes by the name "watertable()." The good news is that I've written the correct format to file. The bad news is that the data is meaningless.
Here's the declarations in the "mesh.h" header file:
#pragma once
#include <iostream>
#include <cstdio>
using namespace std;
Disregard <iostream> - I've not yet re-written "quadgen()" and it thus still uses "cout" for output. I'm not sure if <cstdio> needs "namespace std," but it's easy enough to find out if it does or does not...
Here's the current "watertable()" function:
void watertable(FILE *output, int yn, unsigned int x, unsigned int z, double wateralt)
{
if ( yn == 1 )
{
const int ROWS = 4;
const int COLS = 5;
double quad[ ROWS ][ COLS ] = { x, wateralt, 0, 1, 0,
x, wateralt, z, 1, 1,
0, wateralt, z, 0, 1,
0, wateralt, 0, 0, 0 };
fputs( "A\n", output );
fputs( "700\n", output );
fputs( "OBJ\n", output );
fputs( "texture\n", output );
fputs( "quad\n", output );
fprintf( output, "%1i\t%1.3f\t%1i\t%1i\t%1i\n", quad[ 0 ][ 0 ], quad[ 0 ][ 1 ], quad[ 0 ][ 2 ], quad[ 0 ][ 3 ], quad[ 0 ][ 4 ] );
fprintf( output, "%1i\t%1.3f\t%1i\t%1i\t%1i\n", quad[ 1 ][ 0 ], quad[ 1 ][ 1 ], quad[ 1 ][ 2 ], quad[ 1 ][ 3 ], quad[ 1 ][ 4 ] );
fprintf( output, "%1i\t%1.3f\t%1i\t%1i\t%1i\n", quad[ 2 ][ 0 ], quad[ 2 ][ 1 ], quad[ 2 ][ 2 ], quad[ 2 ][ 3 ], quad[ 2 ][ 4 ] );
fprintf( output, "%1i\t%1.3f\t%1i\t%1i\t%1i\n", quad[ 3 ][ 0 ], quad[ 3 ][ 1 ], quad[ 3 ][ 2 ], quad[ 3 ][ 3 ], quad[ 3 ][ 4 ] );
fputs( "end", output );
}
return;
}
Now, here's the usage of the code in the main program:
FileW = fopen( "eaufile.obj", "w" );
if ( FileW != NULL )
{
watertable( FileW, resp, x, z, wateralt );
fclose( FileW );
}
Note that "FILE *FileW;" is declared at the initialization of the program.
Here's the problem - Entering 10 for 'x,' 10 for 'z,' and, oh, say 2 for 'wateralt,' I should get a 10x10 surface two meters in uniform elevation, and the output should look like this:
A
700
OBJ
texture
quad
10 2.000 0 1 0
10 2.000 10 1 1
0 2.000 10 0 1
0 2.000 0 0 0
end
However, the output instead looks like this:
A
700
OBJ
texture
quad
0 0.000 1072693248 0 0
0 0.000 1072693248 0 1076101120
0 0.000 1072693248 0 1076101120
0 0.000 1072693248 0 0
end
I suspect it might be something with reading the matrix entries, maybe? However, that makes very little sense. Would it b better to write the matrix entries as pointers to the individual matrix data locations?
-
I'll talk to my professor tomorrow about this method; this is an introductory C++ course, and string usage/file outputs weren't in the normal curriculum.
Obviously they need to change the curriculum. :wtf:
most intro courses have that at the very end of the first class or the beginning of the second.
also learn to redirect output, your original program was actually more flexible when it printed to screen.
-
It seems like your fprintf syntax is wrong.
http://www.cplusplus.com/reference/clibrary/cstdio/fprintf/
fprintf( output, "%1i\t%1.3f\t%1i\t%1i\t%1i\n", quad[ 0 ][ 0 ], quad[ 0 ][ 1 ], quad[ 0 ][ 2 ], quad[ 0 ][ 3 ], quad[ 0 ][ 4 ] );
fprintf( output, "%1i\t%1.3f\t%1i\t%1i\t%1i\n", quad[ 1 ][ 0 ], quad[ 1 ][ 1 ], quad[ 1 ][ 2 ], quad[ 1 ][ 3 ], quad[ 1 ][ 4 ] );
fprintf( output, "%1i\t%1.3f\t%1i\t%1i\t%1i\n", quad[ 2 ][ 0 ], quad[ 2 ][ 1 ], quad[ 2 ][ 2 ], quad[ 2 ][ 3 ], quad[ 2 ][ 4 ] );
fprintf( output, "%1i\t%1.3f\t%1i\t%1i\t%1i\n", quad[ 3 ][ 0 ], quad[ 3 ][ 1 ], quad[ 3 ][ 2 ], quad[ 3 ][ 3 ], quad[ 3 ][ 4 ] );
You are trying to output a double as an integer, because they are stored differently that won't work. Instead of %1i use %1f, or:
fprintf( output, "%1.0f\t%1.3f\t%1.0f\t%1.0f\t%1.0f\n", quad[ 0 ][ 0 ], quad[ 0 ][ 1 ], quad[ 0 ][ 2 ], quad[ 0 ][ 3 ], quad[ 0 ][ 4 ] );
fprintf( output, "%1.0f\t%1.3f\t%1.0f\t%1.0f\t%1.0f\n", quad[ 1 ][ 0 ], quad[ 1 ][ 1 ], quad[ 1 ][ 2 ], quad[ 1 ][ 3 ], quad[ 1 ][ 4 ] );
fprintf( output, "%1.0f\t%1.3f\t%1.0f\t%1.0f\t%1.0f\n", quad[ 2 ][ 0 ], quad[ 2 ][ 1 ], quad[ 2 ][ 2 ], quad[ 2 ][ 3 ], quad[ 2 ][ 4 ] );
fprintf( output, "%1.0f\t%1.3f\t%1.0f\t%1.0f\t%1.0f\n", quad[ 3 ][ 0 ], quad[ 3 ][ 1 ], quad[ 3 ][ 2 ], quad[ 3 ][ 3 ], quad[ 3 ][ 4 ] );
-
Thanks, Uchuujinsan, that's exactly what I needed! The program now spits out a quad AND GOES!
And yes, that's correct Bobboau, this is my first time taking C++, and inputs/outputs weren't part of the standard curriculum. Other things I'll need to learn for this project include vectors, which will hopefully solve the "dynamic matrix dimensions" problem. Lastly, is there a good place on the net I can learn about redirecting output? I still have the original, stable header files, so I could revert to using those...
After looking at the codes in the 'mesh.h' header, I've noted that the code is in fact a little bloated. The last two columns are constants, and I might be able to get away with removing the original scripted matrices in entirety. Though not necessary, I feel it would be good programming practice to make the code as streamlined as possible.
Anyway, here's another one - I got this portion of code to work earlier, but it used a different output library which couldn't dump the data to file as I needed it. Basically, it was a string code which accepted input for a file name to be outputted, then added the proper file extension. The file of this name was then used as the file to be written to. Here's the old code:
cin >> eaufile;
eaufile = eaufile + output;
FileW.open(eaufile.c_str(), ios::out);
if (FileW.fail())
{
cout << "\nThere seems to have been an error in creating the file...\nThis is unfortunate, and you will need to try again.\n\n";
exit(1);
}
cout << "The file has been initialized...\n\n";
FileW << (watertable(resp, x, z, wateralt)) << endl;
FileW.close();
cout << "Got it... Done!" << endl;
Obviously, the third-to-last line didn't work. However, the code did (a.) create a file with the name I wanted with the appropriate '.obj' file extension, and (b.) theoretically made that file available for writing. I made that work just fine with <fstream>, but I'm not certain of the mechanics of that process in <cstdio>. As far as I know, the way I'm doing this now won't allow me to pick a file name to stream data to. Is there a way around this?
-
redirecting of output is not a programming issue, it's an OS thing, typically it works like thus:
name_of_console_app.exe > name_of_file.txt
that's all there is to it, it's just a way to run your app.
also, don't worry so much about 'streamlining' it's much more important that your code is easy to follow.
-
Right, thanks Bobboau. :yes:
However, since I've got the output running just fine (as well as the naming of the output), that's no longer a concern. The program runs much faster with the <cstdio> library functions than the cout outputs - I might be waiting quite a while for all those quads to be written with cout. With the <cstdio> library, I might still be waiting a while, but not that long. Here's the solution to the naming problem:
cin >> terfile;
terfile = terfile + output;
FileT = fopen( terfile.c_str(), "w" );
if ( FileT != NULL )
{
cout << "\nInitializing file...\n";
quadgen( FileT, x, xscale, z, zscale );
fclose( FileT );
cout << "\nGot it... Done!\n";
}
What's to be done now is learn the <vector> library so I can create the 2-dimensional "array" of the configuration "array[ x + 1 ][ z + 1 ]." This array will then be fed into the "quadgen()" function, where the various values stored therein will be used as elevation values. Certainly, those elevation values will need to come from somewhere and "charge up the array," so-to-say; I'll create a placeholder random number generator for this purpose until a more realistic algorithm can be made. Once that is stable, I'll post the project here if you're curious. ;)
Lastly, the "streamlining" is not hard to understand once you know what you're dealing with in the mesh.h header - those functions don't need a 4x5 array created for them. The only thing that matters is that the output is a 4x5 array. I'll illustrate with the current "watertable()" function:
void watertable( FILE *output, int yn, unsigned int xsegs, double xscale, unsigned int zsegs, double zscale, double wateralt )
{
if ( yn == 1 )
{
fputs( "A\n", output );
fputs( "700\n", output );
fputs( "OBJ\n", output );
fputs( "texture\n", output );
fputs( "quad\n", output );
fprintf( output, "%1.3f\t%1.3f\t0.000\t1\t0\n", ( xsegs * xscale ), wateralt );
fprintf( output, "%1.3f\t%1.3f\t%1.3f\t1\t1\n", ( xsegs * xscale ), wateralt, ( zsegs * zscale ) );
fprintf( output, "0.000\t%1.3f\t%1.3f\t0\t1\n", wateralt, ( zsegs * zscale ) );
fprintf( output, "0.000\t%1.3f\t0.000\t0\t0\n", wateralt );
fputs( "end", output );
}
return;
}
I've not done a similar thing to "quadgen()" yet, as the old format is useful for visualization, as you've said. I may even retain the matrix for that one, though it will be shortened to a 4x3 format.
Also, I've since added a segment scaling feature, allowing the user to specify the uniform distance covered by each 'x' and 'z' entry... You might have noticed this by looking at the code already. Prior to this, a massive area (which might not actually be too massive) had to be drawn out by the meter. Thus a square kilometer drew 1,000,000 quads, thus drawing 2,000,000 triangles!. It took the program quite a while to do it, though outputting directly to file was WAYYY faster than cout, which would have been unusable anyway (only displays so much information). The final output was a heinous 70+ MB in size, and would have taken AC3D an unreasonable amount of time to open. Furthermore, don't forget that Object 700 format does NOT draw welded verticies...
Because the square km demonstrator was too rediculous to try playing with, I went for a smaller 200x400 mesh. Although the output was a relatively small 6 MB, it ttook AC3D a fairly long time to open. Even worse, the mesh was packin' 480,000 verts, most of which were unwelded. It must have taken more than two hours to weld all of those at once - 399,399 were removed, leaving the minimum number of 80,601 verts behind.
...Not to mention the constant 160,000 triangles... :p
When re-saved, the file grew to almost 10 MB, though you can actually open it in a reasonable amount of time. Here's proof:
[attachment deleted by admin]
-
What's to be done now is learn the <vector> library so I can create the 2-dimensional "array" of the configuration "array[ x + 1 ][ z + 1 ]."
You mean something like std::vector<std::vector<int> >
-
I believe so...
How do you set up a 2D array in vector format, by the way? I've seen an example in my text similar to this:
vector<datatype> vectorname( [initial term], [intial term + NUM] );
Of course, this is a one dimesional vector/"array." Ideally I should be able to make a 2D structure which is like an array with vectors, due to the expandability of vectors, of course. And thus I could have the pointmap, which is a matrix like so: pointmap[ x + 1 ][ z + 1 ]...
-
Ah, there was supposed to be a question mark at the end.
std::vector<std::vector<int> > myTwoDVec; //create a 2-dimensional vector, be careful, the space between the two ">" at the end is needed
myTwoDVec.resize(4); //set the size of the first dimension to 4 (now contains 4 vector<int>)
myTwoDVec[0].resize(5,0); //set the size of the first vector of the second dimension to 5
// The values will look like this
// 0 0 0 0 0 //size 5
// empty //size 0
// empty //size 0
// empty //size 0
std::vector<std::vector<int> > myTwoDVec; //create a 2-dimensional vector
std::vector<int> tmp;
tmp.resize(5, 2);
myTwoDVec.resize(4, tmp); //set the size of the first dimension to 4 (now contains 4 vector<int>)
// The values will look like this
// 2 2 2 2 2
// 2 2 2 2 2
// 2 2 2 2 2
// 2 2 2 2 2
http://www.cplusplus.com/reference/stl/vector/resize/
You can, of course, change single values with:
myTwoDVec[0][1] = 4; //be carefull that the vector is big enough to have this element)
or simply add an element at the end:
std::vector<int> tmp;
myTwoDVec.push_back(tmp);
myTwoDVec[0].push_back(6);
http://www.cplusplus.com/reference/stl/vector/push_back/
-
I think I'm down with most of the syntax and logic, but the array I'm trying to form is to be filled with double-precision numbers. Is there an addtional step for that, or would doing this work:
vector<vector<double> > 2Dvectorname; // This is the main vector "array," where the number of rows shall be initialized and another vector (declared
// below) shall be used to control the number of columns.
vector<double> columninputs; // This controls the number of columns in the vector array.
Any help is appreciated. :D If I can get this to work, I'll be golden.
-
Sure, just use double instead of int.
This works with any types, even with classes you have written yourself.
-
Thanks, that's good to hear!
I just want to say that your assistance has been invaluable, Uchuujinsan. :)
-
Thaeris, I'm not sure if it helps, but one way to visualise the STL is as comprised of Algorithms, Containers and Adaptors.
A container 'contains' an object (int/double/etc are all special cases of 'object'), an algorithm operates on a container (which could be a flat array also), and an adaptor makes a container behave slightly differently - for example queue is an adaptor to deque (MS STL).
There are some very good summaries around, but I like the cplusplus.com references.
Don't think of them as arrays - they behave quite differently (except for vector, which is fundamentally an array, but has some interesting insertion characteristics)
Hope the above helps with thinking about the STL.
-
That was mentioned in my textbook, though there doesn't seem to be a tremendous selection of topics on STL templates in the text. It's not bad, however...
I must say though, that I do not believe that the algoritm library is going to be the help I need. I am actually very close to having something that works more like it was intended to, though. With any luck, it will be today. ;7
-
(Insert "Yeah" beam here...)
YEAHHHHH!!!
It's not the best, but it works! All the framework is in place for eventually developing a procedural terrain generator. :yes: :yes: :yes:
Below is a sample image of the initial file generated (the mesh covers four square kilometers), then the same file subdivided, stretched to an aesthetically pleasing shape, and given a texture I had lying around.
You'll need A C++ compiler to run the program in its current state - it's not stand alone. Also, if you choose to try it/play around with it, you'll need a program which supports the file format outputted by the program. Since you probably don't have AC3D, here's a link to the Blender scripts you'll need:
http://www.marginal.org.uk/x-planescenery/tools.html
[attachment deleted by admin]
-
this could easily be modified to output to normal wavefront obj format, no? (pretty much any 3D software can open that)
btw, just to inform you, this compiled without any problems in devc++ by bloodshed.
-
I'm not sure, though I believe you could. I opened up a wavefront object file with a text editor to see the format, and indeed you can read it to a degree. However, it's not as sensible as object 700 format, which is why I didn't go for it right away. A project for a different time, maybe?
Anyway, I'd assume it would open and compile with any C++ compiler, so devc++ certainly should work, and it did, too!
Thus, after all that, all it needs is a better elevation algorithm and it will be much better. That might have to wait, though. With the other things I need to finish up, this might be what I turn in.
EDIT:
Yalp. Turned it in. :D
Also, playing with some terrain derived from an output mesh. Even though the algorithm to date is uber-simple, the randomness of the mesh means a few stretches of the verticies here and there can result in a tremendously organic-looking piece of land. Just start draging things about and you'll soon have a nice piece of 3D artwork... maybe. This is one of the few instances where subdivisions are not only practical, but perhaps necessary to achive a level of realism. After the initial stretching of the terrain, I'll subdivide it, reduce it, then subdivide and reduce again. Because subdivisions + reducing operations produce non-uniform triangles, this helps the landscape become more random and thus hopefully more realistic.
[attachment deleted by admin]
-
Impressive stuff :)
If you want to set yourself a challenge, you could always have a go at a poly-reduction system over distance ;)
-
I think there may be a name for this, (maybe Perlin noise?) but...
What if you start with a low-res grid (2x2 or so), randomize completely, then scale it up x2, and randomize by about half the amount? Repeat a few times...
-
http://www.gameprogrammer.com/fractal.html
You can get more information on basic procedural generation from here :)