C++ How to get the window size (width and height)? - c++

I'm trying to create a graph and I need to know the size of the window the user is running the code in. I'm trying to scale the data so the data shows only on the size of the window, without wrapping or scrolling. I'm on windows but I want to use something similar to Linux equivalent
int lines = atoi(getenv("LINES") ;
int cols = atoi(getenv("COLUMNS") ;
So I can scale numbers and show a graph like this
320 a ============================================================
160 b ==============================
80 c ===============
40 d =======
20 e ===
10 f =
5 g
2 h
1 i
2 j
17 k ===
41 l =======
67 m ============
97 n ==================
127 o ========================
157 p =============================
191 q ====================================
227 r ===========================================
257 s ================================================
283 t =====================================================
331 u ==============================================================
367 v =====================================================================
373 w ======================================================================
379 x ========================================================================
383 y ========================================================================
389 z ==========================================================================
Is there something that will work on Windows and Linux? I'm using Visual Studio 2012.

Use GetWindowRect
RECT rect;
if(GetWindowRect(hwnd, &rect))
{
int width = rect.right - rect.left;
int height = rect.bottom - rect.top;
}

Use GetConsoleScreenBufferInfo or one of its siblings.
You are interrested in the dzSize field of the "returned" struct.
Read documentation here: http://msdn.microsoft.com/en-us/library/windows/desktop/ms683171(v=vs.85).aspx

You already have a solution for Linux.
On Windows the API call you need is GetConsoleScreenBufferInfo.
This returns a CONSOLE_SCREEN_BUFFER_INFO struct, from which you read out the dwSize member:
A COORD structure that contains the size of the console screen buffer, in character columns and rows.

Related

Discrepancy between command line XRandR and own code

I need to programatically get the refresh rate of a monitor.
When I type xrandr (1.4.1, opensuse 13) on the command line I get:
Screen 0: minimum 8 x 8, current 1920 x 1200, maximum 16384 x 16384
VGA-0 disconnected primary (normal left inverted right x axis y axis)
DVI-D-0 connected 1920x1200+0+0 (normal left inverted right x axis y axis) 518mm x 324mm
1920x1200 60.0*+
1920x1080 60.0
1680x1050 60.0
1600x1200 60.0
1280x1024 60.0
1280x960 60.0
1024x768 60.0
800x600 60.3
640x480 59.9
HDMI-0 disconnected (normal left inverted right x axis y axis)
This result is confirmed by nvidia-settings -q RefreshRate, among other things.
But ...
when I run the following code (origin: https://github.com/raboof/xrandr/blob/master/xrandr.c), compiled with g++ 4.8.1 (with -lX11 -lXext -lXrandr) :
int nsize;
int nrate;
short *rates;
XRRScreenSize *sizes;
Display *dpy = XOpenDisplay(NULL);
Window root = DefaultRootWindow(dpy);
XRRScreenConfiguration *conf = XRRGetScreenInfo(dpy, root);
printf ("Current rate: %d\n",XRRConfigCurrentRate(conf));
sizes = XRRConfigSizes(conf, &nsize);
printf(" SZ: Pixels Refresh\n");
for (int i = 0; i < nsize; i++) {
printf("%-2d %5d x %-5d", i, sizes[i].width, sizes[i].height);
rates = XRRConfigRates(conf, i, &nrate);
if (nrate)
printf(" ");
for (int j = 0; j < nrate; j++)
printf("%-4d", rates[j]);
printf("\n");
}
XRRFreeScreenConfigInfo(conf);
I get:
Current rate: 50
SZ: Pixels Refresh
0 1920 x 1200 50
1 1920 x 1080 51
2 1680 x 1050 52
3 1600 x 1200 53
4 1280 x 1024 54
5 1280 x 960 55
6 1024 x 768 56
7 800 x 600 57
8 640 x 480 58
9 1440 x 900 59
10 1366 x 768 60
11 1280 x 800 61
12 1280 x 720 62
Why am I getting this result?
What I am doing wrong?
The software uses OpenGL with GLEW. can this have any influence?
We do call glXQueryDrawable(dpy, drawable, GLX_SWAP_INTERVAL_EXT, &val) but afterwards, and I do not think this should have any influence.
I found the answer:
If the XRandR sever supports version 1.2 of the protocol, then the appropriate functions need to be used (wich I plan to do by copying snippets of code from https://github.com/raboof/xrandr/blob/master/xrandr.c where has_1_2 is true).
My code in the question uses functions for the version 1.1 of the protocol, and therefore only the metamodes are returned.
As a simple check, I tried the following two commands:
xrandr --q1
xrandr --q12.
And indeed the 1st one gives me the same result I programatically get.
Credits go to http://www.ogre3d.org/forums/viewtopic.php?f=4&t=65010&start=200

Solid fill of an ellipse in python dxf

I'd like to draw filled ellipse with python. This would be easy if I could use PIL oder some other libraries. The problem is I need the ellipse in a .dxf file format. Therefore I used the dxfwrite package. This allows me to draw an ellipse but I couldn't find a way to fill it with a solid color. The following code does draw an ellipse line, but does not fill it.
import dxfwrite
from dxfwrite import DXFEngine as dxf
name = 'ellipse.dxf'
dwg = dxf.drawing(name)
dwg.add(dxf.ellipse((0,0), 5., 10., segments=200))
dwg.save()
Does anybody of you guys know a solution?
The HATCH entity is not supported by dxfwrite, if you use ezdxf this is the solution:
import ezdxf
dwg = ezdxf.new('AC1015') # hatch requires the DXF R2000 (AC1015) format or later
msp = dwg.modelspace() # adding entities to the model space
# important: major axis >= minor axis (ratio <= 1.) else AutoCAD crashes
msp.add_ellipse((0, 0), major_axis=(0, 10), ratio=0.5)
hatch = msp.add_hatch(color=2)
with hatch.edit_boundary() as boundary: # edit boundary path (context manager)
edge_path = boundary.add_edge_path()
# an edge path can contain line, arc, ellipse or spline elements
edge_path.add_ellipse((0, 0), major_axis_vector=(0, 10), minor_axis_length=0.5)
# upcoming ezdxf 0.7.7:
# renamed major_axis_vector to major_axis
# renamed minor_axis_length to ratio
dwg.saveas("solid_hatch_ellipse.dxf")
You could fill an ellipse by using a solid hatch object:
For the above example, here is a snippet from the DXF file that contains the ellipse and the hatch:
AcDbEntity
8
0
100
AcDbEllipse
10
2472.192919
20
1311.37942
30
0.0
11
171.0698134145308
21
-27.61597470964863
31
0.0
210
0.0
220
0.0
230
1.0
40
0.2928953354556341
41
0.0
42
6.283185307179586
0
HATCH
5
5A
330
2
100
AcDbEntity
8
0
100
AcDbHatch
10
0.0
20
0.0
30
0.0
210
0.0
220
0.0
230
1.0
2
SOLID
70
1
71
1
91
1
92
5
93
1
72
3
10
2472.192919357234
20
1311.379420138197
11
171.0698134145308
21
-27.61597470964863
40
0.2928953354556341
50
0.0
51
360.0
73
1
97
1
330
59
75
1
76
1
47
0.794178
98
1
10
2428.34191358924
20
1317.777876434349
450
0
451
0
460
0.0
461
0.0
452
0
462
1.0
453
2
463
0.0
63
5
421
255
463
1.0
63
2
421
16776960
470
LINEAR
1001
GradientColor1ACI
1070
5
1001
GradientColor2ACI
1070
2
1001
ACAD
1010
0.0
1020
0.0
1030
0.0
There are a lot of DXF codes involved. This is the information Autodesk provide:
Hatch group codes
Group code
Description
100
Subclass marker (AcDbHatch)
10
Elevation point (in OCS)
DXF: X value = 0; APP: 3D point (X and Y always equal 0, Z represents the elevation)
20, 30
DXF: Y and Z values of elevation point (in OCS)
Y value = 0, Z represents the elevation
210
Extrusion direction (optional; default = 0, 0, 1)
DXF: X value; APP: 3D vector
220, 230
DXF: Y and Z values of extrusion direction
2
Hatch pattern name
70
Solid fill flag (solid fill = 1; pattern fill = 0); for MPolygon, the version of MPolygon
63
For MPolygon, pattern fill color as the ACI
71
Associativity flag (associative = 1; non-associative = 0); for MPolygon, solid-fill flag (has solid fill = 1; lacks solid fill = 0)
91
Number of boundary paths (loops)
varies
Boundary path data. Repeats number of times specified by code 91. See Boundary Path Data
75
Hatch style:
0 = Hatch “odd parity” area (Normal style)
1 = Hatch outermost area only (Outer style)
2 = Hatch through entire area (Ignore style)
76
Hatch pattern type:
0 = User-defined; 1 = Predefined; 2 = Custom
52
Hatch pattern angle (pattern fill only)
41
Hatch pattern scale or spacing (pattern fill only)
73
For MPolygon, boundary annotation flag (boundary is an annotated boundary = 1; boundary is not an annotated boundary = 0)
77
Hatch pattern double flag (pattern fill only):
0 = not double; 1 = double
78
Number of pattern definition lines
varies
Pattern line data. Repeats number of times specified by code 78. See Pattern Data
47
Pixel size used to determine the density to perform various intersection and ray casting operations in hatch pattern computation for associative hatches and hatches created with the Flood method of hatching
98
Number of seed points
11
For MPolygon, offset vector
99
For MPolygon, number of degenerate boundary paths (loops), where a degenerate boundary path is a border that is ignored by the hatch
10
Seed point (in OCS)
DXF: X value; APP: 2D point (multiple entries)
20
DXF: Y value of seed point (in OCS); (multiple entries)
450
Indicates solid hatch or gradient; if solid hatch, the values for the remaining codes are ignored but must be present. Optional; if code 450 is in the file, then the following codes must be in the file: 451, 452, 453, 460, 461, 462, and 470. If code 450 is not in the file, then the following codes must not be in the file: 451, 452, 453, 460, 461, 462, and 470
0 = Solid hatch
1 = Gradient
451
Zero is reserved for future use
452
Records how colors were defined and is used only by dialog code:
0 = Two-color gradient
1 = Single-color gradient
453
Number of colors:
0 = Solid hatch
2 = Gradient
460
Rotation angle in radians for gradients (default = 0, 0)
461
Gradient definition; corresponds to the Centered option on the Gradient Tab of the Boundary Hatch and Fill dialog box. Each gradient has two definitions, shifted and unshifted. A Shift value describes the blend of the two definitions that should be used. A value of 0.0 means only the unshifted version should be used, and a value of 1.0 means that only the shifted version should be used.
462
Color tint value used by dialog code (default = 0, 0; range is 0.0 to 1.0). The color tint value is a gradient color and controls the degree of tint in the dialog when the Hatch group code 452 is set to 1.
463
Reserved for future use:
0 = First value
1 = Second value
470
String (default = LINEAR)
I hope this may be of some use to you. I apologize if I missunderstood your issue.

Vector of Vectors. Remove duplicates based on specific index of inner vectors

I have been using a combination of different variables and data structures for this, I am not sure which is best in practice. I don't care much how long it takes to run these calculations, I just care about the end result.
I have a combination of values. V - W - X - Y : Z. V,W,X, and Y are used to calculate Z. V, W, X, and Y each have 256 different possibilities. So I believe I am working with a combination.
V - W - X - Y : Z
So long as all my values are the same, the order doesn't matter, I still get the same result.
0 - 52 - 115 - 249 : 0.059784
52 - 249 - 0 - 114 : 0.059784
249 - 52 - 114 - 0 : 0.059784
0 - 52 - 115 - 250 : 0.057423
0 - 250 - 115 - 52 : 0.057423
250 - 0 - 52 - 115 : 0.057423
0 - 52 - 115 - 251 : 0.055006
115 - 251 - 52 - 0 : 0.055006
251 - 0 - 52 - 115 : 0.055006
I need my end result to be a list of these values that are unique to Z. I don't really care which combination gets saved to achieve said unique value for Z. I just need to retain the value of Z which is a float (though in the end result I can store it as a string I suppose), and the values of V, W, X, Y.
So if I start with this:
250 - 0 - 52 - 115 : 0.057423
0 - 52 - 115 - 249 : 0.059784
0 - 52 - 115 - 250 : 0.057423
52 - 249 - 0 - 114 : 0.059784
0 - 52 - 115 - 251 : 0.055006
0 - 250 - 115 - 52 : 0.057423
251 - 0 - 52 - 115 : 0.055006
249 - 52 - 114 - 0 : 0.059784
115 - 251 - 52 - 0 : 0.055006
I would end with something similar to this:
250 - 0 - 52 - 115 : 0.057423
0 - 52 - 115 - 249 : 0.059784
115 - 251 - 52 - 0 : 0.055006
Any help/advice would be appreciated. Many thanks!
EDIT: Adding more to this to help decipher some issues.
So the idea of the entire project I am working on is to calculate every possible resistance for a quad digital potentiometer when you wire each of the four potentiometers in parallel. I may calculate series later, but for right now parallel is what I am after.
The potentiometer itself has an A terminal, B terminal, and Wiper terminal. We are looking for the resistance between the A terminal and the wiper terminal.
This is a 1k ohm 8 bit potentiometer. That means we have 256 steps of resolution to work with. To calculate the resistance for a certain step, we figure out:
trim = (((( (ohmRatingOfDigiPot)*(numberofPossibleSteps - stepToCalculate) )/numberofPOssileSteps)+wiperResistance)/1000);
So, our equation turns out to be
trim = (((( (1000)*(256-index) )/256)+50)/1000)
Where index is the step (out of 256 total steps) we are on.
So I figure out the possible values of each of these steps and I pass them into an array. One for each of the four potentiometers in the quad potentiometer.
for(int i = 0; i < 256; i++)
{
trim = (((( (1000)*(256-index) )/256)+50)/1000);
index++;
potOneSteps[i] = trim;
potTwoSteps[i] = trim;
potThreeSteps[i] = trim;
potFourSteps[i] = trim;
}
Yes, I know there is probably a much better way to do that. Like I said, it has been so long since I've used C++. This worked and I knew I had other things to worry about so it ended up staying. Ha.
So now I need to figure out every possible value for these four potentiometers in every different combination available. 4 potentiometers with 256 possible value for each? Bring on the for loops!
To calculate the resistance of resistors in parallel, we use:
Total Resistance = ( 1 / ( (1/R1) + (1/R2) + (1/R3) + ... + (1/Rn))
For our four arrays I figured this:
for (int A1W1 = 0; A1W1 < 256; A1W1++)
{
for (int A2W2 = 0; A2W2 < 256; A2W2++)
{
for (int A3W3 = 0; A3W3 < 256; A3W3++)
{
for (int A4W4 = 0; A4W4 < 256; A4W4++)
{
rTrim = (1/((1/potOneSteps[A1W1]) + (1/potTwoSteps[A2W2]) + (1/potThreeSteps[A3W3]) + (1/potFourSteps[A4W4])));
}
}
}
}
Very long. Very processor and memory intensive. Very poor. I know. I know.
This was the only way I could think to go through all of the values to do the calculations. Not sure if there is a better way, open to any and all suggestions.
So in my original post, V - W - Y - X correspond with the index where Z was calculated. And Z is the the actual resistance that we calculated using the values at said indices. Since all of the arrays are the same we get repeat values like I spoke about in the original post. So I only need to know the unique values for Z/rTrim and the step(s) at which it was found in order to have all of the possible values and be able to set the digital pots to said values.
I am open to any and all variables/data structures/etc for this. Nothing really has to be set to a certain type so I can deal with doubles, floats, ints, arrays, vectors, sets, linked lists (oh please no!), etc.
I hope that makes sense. Kind of long winded but I figured it would be beneficial to have all of the information available for what I am trying to go for. Many thanks!!
EDIT2:
I may have solved this problem with PHP and mySQL, my "native" languages. If you guys still want to lend a hand, I am all ears and willing to learn best practices, but don't feel obligated. Much appreciated for the help you did provide!
Edit :
As I suspected, your problem is not to remove duplicates from an already computed array of values. From what I have understood about your edit, you can simply compute the necessary values without duplicates in the first place.
For instance, imagine two loops in the range 0 to 3 like so :
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
someVectorOfPair.push_back(std::make_pair(i, j));
}
}
Here, you will get all the possible ordered pairs of values from 0 to 3. Now, you are looking for all the possible unordered pairs, so you consider (0, 1) and (1, 0) duplicates. This is the most straightforward way to do it :
for (int i = 0; i < 4; ++i) {
for (int j = i; j < 4; ++j) { // Only one character changed
someVectorOfPair.push_back(std::make_pair(i, j));
}
}
If you start j with the current value of i, you will not compute pairs (x, y) where y < x. However, you will get every other combinations, and it seems that it solves your problem.
Oh, by the way, (((( (1000)*(256-index) )/256)+50)/1000) can be written like so : (256.-i)/256. + 0.05. I did not understand everything in your calculations, but if i can go backward, you can simplify further : i/256. + 0.05. The point is here to do floating-point calculation if i is an int. You can also cast with static_cast<double> (or float).
Original :
How do you store your data ? How much data do you have ? How do you calculate Z ?
Without the answers to these questions, I can only present a very simple (but not efficient) way to reach your goal : copying your data into another "vector of vector" with duplicate checking. This is roughly how it is done (not tested) :
for (itD : data) {
itR = std::find_if(result.begin(), result.end(), [&itD](result::iterator it) { it.Z == itD.Z });
if (itR == result.end()) {
result.push_back(*itD);
}
}
Then again, this is not really efficient. You can also use a set (ordered or not) to store the result : this way, insertion automatically checks for duplicates (since a set have unique keys).
First, let's get the combinatorics right:
Given n items and d possibilities for each item, where n=4and d=256 here, we have:
Number of combinations if order is important: d ^ n and 256^4 is simply 2^32 for 4 x 8 = 32 bit
If order is not important, the formula is (n+d-1)! / (d! * (n-1!)) ... 2.862.209 ~ 3M distinct combinations in this case (a lot better that the 4G of the ordered combinations)
However, given the problem of n resistors (in parallel or serial), not only is the order not important, but even the combinations themselves are only important if they yield different sums.
The number of different sums (as opposed to their probabilities) is trivially (n * d) - (n - 1) (With the lowest sum 0 := 0 + 0 + 0 + 0 and the highest 1020 := 255 + ... + 255 for 1021 different sums in this case.
So, what you should do, expanding on the answer of #PaulMc, is to define operator< in terms of the sum of the 4 values, not their possibly unstable float result.
However, given your for loops from the question, you'd still insert into the set 4G(!) (256^4) times to get your 1021 slots filled.
So, if you already know that the order doesn't matter, fill the set in an efficient manner, and it doesn't matter if you get all combinations, you just need to capture all different sums:
Full example here / the loop:
using Combination = std::array<int, n>;
...
std::set<Combination> all;
Combination c{}; // must value initialize a std::array to zero-init its int values
for (int pos = 0; pos != n; ++pos) {
for (int i = 0; i != d; ++i) {
c[pos] = i; // c[0] from 0..d (remains at d), then c[1] from 0..d, etc.
all.insert(c);
}
}
You can do the following:
1) define a class that holds the 4 values and the floating point value.
2) Define an operator < for this class that compares the floating point value.
3) Define a std::set of this class and populate it.
Here is an example:
#include <set>
#include <vector>
#include <array>
#include <algorithm>
#include <iterator>
#include <ostream>
#include <iostream>
typedef std::vector<int> IntVector;
struct MyValueClass
{
IntVector m_vals;
double m_finalVal;
bool operator < (const MyValueClass& c2) const
{ return (m_finalVal < c2.m_finalVal); }
MyValueClass(const IntVector& v, double val) : m_vals(v), m_finalVal(val) {}
};
typedef std::set<MyValueClass> ValueClassSet;
using namespace std;
int main()
{
vector<MyValueClass> mc;
// Sample data
mc.push_back(MyValueClass(IntVector{ 250, 0, 52, 115 }, 0.057423));
mc.push_back(MyValueClass(IntVector{ 0, 52, 115, 249 }, 0.059784));
mc.push_back(MyValueClass(IntVector{ 0, 52, 115, 250 }, 0.057423));
mc.push_back(MyValueClass(IntVector{ 52, 249, 0, 114 }, 0.059784));
mc.push_back(MyValueClass(IntVector{ 0, 52, 115, 251 }, 0.055006));
mc.push_back(MyValueClass(IntVector{ 0, 250, 115, 52 }, 0.057423));
mc.push_back(MyValueClass(IntVector{ 251, 0, 52, 115 }, 0.055006));
mc.push_back(MyValueClass(IntVector{ 249, 52, 114, 0 }, 0.059784));
mc.push_back(MyValueClass(IntVector{ 115, 251, 52, 0 }, 0.055006));
// populate set with sample data from vector
ValueClassSet ms;
ValueClassSet::iterator it = ms.begin();
copy(mc.begin(), mc.end(), inserter(ms, it));
// output results
ValueClassSet::iterator it2 = ms.begin();
while (it2 != ms.end())
{
copy(it2->m_vals.begin(), it2->m_vals.end(), ostream_iterator<int>(cout, " "));
cout << " : " << it2->m_finalVal << "\n";
++it2;
}
}
Output:
0 52 115 251 : 0.055006
250 0 52 115 : 0.057423
0 52 115 249 : 0.059784
So basically, we populate a vector of your information, and then we populate the set with the vector. Since a std::set only stores unique values, only the unique Z items will be stored. The operator < that we set up for the MyValueClass type is what std::set will use to determine if an item is already in the set.
Note: I used C++11 initialization syntax to populate the vector. If you're using a compiler that is pre C++11, populate the vector the "old-fashioned way".

Find area under a curve using c++ and a file

I have updated the code and now I know how to store the first two number into x1 and z1 but how do I let it into x2 and z2 in order to calculate the area? Thanks.
Here's what I have so far:
#include <fstream>
#include <iostream>
double x1=0;
double x2=0;
double z1=0;
double z2=0;
double n;
double sum;
double area;
using namespace std;
int main()
{
ifstream infile;
infile.open("xydata.dat");
infile.ignore(1000, '\n') ;
while(!infile.eof())
{
infile>>n;
if(n>=20.00&&n<=20.50)
{
x1=n
}
else
{
z1=n
}
area = (x1+x2)*(z2-z1)/2;
}
cout<<"The sum of all are under the curve is "<<sum<<"."<<endl;
return 0;
}
and the file is here:
xydata.dat
x values y values
20.00 0
20.02 15
20.04 27
20.06 39
20.08 54
20.10 65
20.12 75
20.14 84
20.16 93
20.18 101
20.20 108
20.22 113
20.24 116
20.26 115
20.28 112
20.30 107
20.32 100
20.34 92
20.36 83
20.38 74
20.40 64
20.42 53
20.44 39
20.46 27
20.48 15
20.50 0
Is this a homework? (Not posting any code due to the previous question)
I am assuming you want the area between the x axis and the curve. Here is a shortcut:
Consider every pair of consecutive coordinates specifying a rectangle, with a triangle sitting on top of it. You get the rectangle's area by multiplying the (differences in x) with (the smaller y). and then get the triangle's area by the (difference in x), multiplied by (the difference in y), and having the half of it. Add these two areas and it will give you an approximate area under the curve for the pair of coordinates. Repeat this procedure for all consecutive pairs of coordinates and add them up.

Understanding some C++ coding practice [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I am currently trying to understand how the following code (http://pastebin.com/zTHUrmyx) works, my approach is currently compiling the software in debug and using gdb to step through the code.
However, I'm running into the problem that 'step' does not always tell me what is going on. Particularly unclear to me is the EXECUTE {...} which I cannot step into.
How do I go about learning what the code is doing?
1 /*
2 Copyright 2008 Brain Research Institute, Melbourne, Australia
3
4 Written by J-Donald Tournier, 27/06/08.
5
6 This file is part of MRtrix.
7
8 MRtrix is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 MRtrix is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with MRtrix. If not, see <http://www.gnu.org/licenses/>.
20
21
22 15-10-2008 J-Donald Tournier <d.tournier#brain.org.au>
23 * fix -prs option handling
24 * remove MR::DICOM_DW_gradients_PRS flag
25
26 15-10-2008 J-Donald Tournier <d.tournier#brain.org.au>
27 * add -layout option to manipulate data ordering within the image file
28
29 14-02-2010 J-Donald Tournier <d.tournier#brain.org.au>
30 * fix -coord option so that the "end" keyword can be used
31
32
33 */
34
35 #include "app.h"
36 #include "image/position.h"
37 #include "image/axis.h"
38 #include "math/linalg.h"
39
40 using namespace std;
41 using namespace MR;
42
43 SET_VERSION_DEFAULT;
44
45 DESCRIPTION = {
46 "perform conversion between different file types and optionally extract a subset of the input image.",
47 "If used correctly, this program can be a very useful workhorse. In addition to converting images between different formats, it can be used to extract specific studies from a data set, extract a specific region of interest, flip the images, or to scale the intensity of the images.",
48 NULL
49 };
50
51 ARGUMENTS = {
52 Argument ("input", "input image", "the input image.").type_image_in (),
53 Argument ("ouput", "output image", "the output image.").type_image_out (),
54 Argument::End
55 };
56
57
58 const gchar* type_choices[] = { "REAL", "IMAG", "MAG", "PHASE", "COMPLEX", NULL };
59 const gchar* data_type_choices[] = { "FLOAT32", "FLOAT32LE", "FLOAT32BE", "FLOAT64", "FLOAT64LE", "FLOAT64BE",
60 "INT32", "UINT32", "INT32LE", "UINT32LE", "INT32BE", "UINT32BE",
61 "INT16", "UINT16", "INT16LE", "UINT16LE", "INT16BE", "UINT16BE",
62 "CFLOAT32", "CFLOAT32LE", "CFLOAT32BE", "CFLOAT64", "CFLOAT64LE", "CFLOAT64BE",
63 "INT8", "UINT8", "BIT", NULL };
64
65 OPTIONS = {
66 Option ("coord", "select coordinates", "extract data only at the coordinates specified.", false, true)
67 .append (Argument ("axis", "axis", "the axis of interest").type_integer (0, INT_MAX, 0))
68 .append (Argument ("coord", "coordinates", "the coordinates of interest").type_sequence_int()),
69
70 Option ("vox", "voxel size", "change the voxel dimensions.")
71 .append (Argument ("sizes", "new dimensions", "A comma-separated list of values. Only those values specified will be changed. For example: 1,,3.5 will change the voxel size along the x & z axes, and leave the y-axis voxel size unchanged.")
72 .type_sequence_float ()),
73
74 Option ("datatype", "data type", "specify output image data type.")
75 .append (Argument ("spec", "specifier", "the data type specifier.").type_choice (data_type_choices)),
76
77 Option ("scale", "scaling factor", "apply scaling to the intensity values.")
78 .append (Argument ("factor", "factor", "the factor by which to multiply the intensities.").type_float (NAN, NAN, 1.0)),
79
80 Option ("offset", "offset", "apply offset to the intensity values.")
81 .append (Argument ("bias", "bias", "the value of the offset.").type_float (NAN, NAN, 0.0)),
82
83 Option ("zero", "replace NaN by zero", "replace all NaN values with zero."),
84
85 Option ("output", "output type", "specify type of output")
86 .append (Argument ("type", "type", "type of output.")
87 .type_choice (type_choices)),
88
89 Option ("layout", "data layout", "specify the layout of the data in memory. The actual layout produced will depend on whether the output image format can support it.")
90 .append (Argument ("spec", "specifier", "the data layout specifier.").type_string ()),
91
92 Option ("prs", "DW gradient specified as PRS", "assume that the DW gradients are specified in the PRS frame (Siemens DICOM only)."),
93
94 Option::End
95 };
96
97
98
99 inline bool next (Image::Position& ref, Image::Position& other, const std::vector<int>* pos)
100 {
101 int axis = 0;
102 do {
103 ref.inc (axis);
104 if (ref[axis] < ref.dim(axis)) {
105 other.set (axis, pos[axis][ref[axis]]);
106 return (true);
107 }
108 ref.set (axis, 0);
109 other.set (axis, pos[axis][0]);
110 axis++;
111 } while (axis < ref.ndim());
112 return (false);
113 }
114
115
116
117
118
119 EXECUTE {
120 std::vector<OptBase> opt = get_options (1); // vox
121 std::vector<float> vox;
122 if (opt.size())
123 vox = parse_floats (opt[0][0].get_string());
124
125
126 opt = get_options (3); // scale
127 float scale = 1.0;
128 if (opt.size()) scale = opt[0][0].get_float();
129
130 opt = get_options (4); // offset
131 float offset = 0.0;
132 if (opt.size()) offset = opt[0][0].get_float();
133
134 opt = get_options (5); // zero
135 bool replace_NaN = opt.size();
136
137 opt = get_options (6); // output
138 Image::OutputType output_type = Image::Default;
139 if (opt.size()) {
140 switch (opt[0][0].get_int()) {
141 case 0: output_type = Image::Real; break;
142 case 1: output_type = Image::Imaginary; break;
143 case 2: output_type = Image::Magnitude; break;
144 case 3: output_type = Image::Phase; break;
145 case 4: output_type = Image::RealImag; break;
146 }
147 }
148
149
150
151
152 Image::Object &in_obj (*argument[0].get_image());
153
154 Image::Header header (in_obj);
155
156 if (output_type == 0) {
157 if (in_obj.is_complex()) output_type = Image::RealImag;
158 else output_type = Image::Default;
159 }
160
161 if (output_type == Image::RealImag) header.data_type = DataType::CFloat32;
162 else if (output_type == Image::Phase) header.data_type = DataType::Float32;
163 else header.data_type.unset_flag (DataType::ComplexNumber);
164
165
166 opt = get_options (2); // datatype
167 if (opt.size()) header.data_type.parse (data_type_choices[opt[0][0].get_int()]);
168
169 for (guint n = 0; n < vox.size(); n++)
170 if (isfinite (vox[n])) header.axes.vox[n] = vox[n];
171
172 opt = get_options (7); // layout
173 if (opt.size()) {
174 std::vector<Image::Axis> ax = parse_axes_specifier (header.axes, opt[0][0].get_string());
175 if (ax.size() != (guint) header.axes.ndim())
176 throw Exception (String("specified layout \"") + opt[0][0].get_string() + "\" does not match image dimensions");
177
178 for (guint i = 0; i < ax.size(); i++) {
179 header.axes.axis[i] = ax[i].axis;
180 header.axes.forward[i] = ax[i].forward;
181 }
182 }
183
184
185 opt = get_options (8); // prs
186 if (opt.size() && header.DW_scheme.rows() && header.DW_scheme.columns()) {
187 for (guint row = 0; row < header.DW_scheme.rows(); row++) {
188 double tmp = header.DW_scheme(row, 0);
189 header.DW_scheme(row, 0) = header.DW_scheme(row, 1);
190 header.DW_scheme(row, 1) = tmp;
191 header.DW_scheme(row, 2) = -header.DW_scheme(row, 2);
192 }
193 }
194
195 std::vector<int> pos[in_obj.ndim()];
196
197 opt = get_options (0); // coord
198 for (guint n = 0; n < opt.size(); n++) {
199 int axis = opt[n][0].get_int();
200 if (pos[axis].size()) throw Exception ("\"coord\" option specified twice for axis " + str (axis));
201 pos[axis] = parse_ints (opt[n][1].get_string(), header.dim(axis)-1);
202 header.axes.dim[axis] = pos[axis].size();
203 }
204
205 for (int n = 0; n < in_obj.ndim(); n++) {
206 if (pos[n].empty()) {
207 pos[n].resize (in_obj.dim(n));
208 for (guint i = 0; i < pos[n].size(); i++) pos[n][i] = i;
209 }
210 }
211
212
213 in_obj.apply_scaling (scale, offset);
214
215
216
217
218
219
220 Image::Position in (in_obj);
221 Image::Position out (*argument[1].get_image (header));
222
223 for (int n = 0; n < in.ndim(); n++) in.set (n, pos[n][0]);
224
225 ProgressBar::init (out.voxel_count(), "copying data...");
226
227 do {
228
229 float re, im = 0.0;
230 in.get (output_type, re, im);
231 if (replace_NaN) if (gsl_isnan (re)) re = 0.0;
232 out.re (re);
233
234 if (output_type == Image::RealImag) {
235 if (replace_NaN) if (gsl_isnan (im)) im = 0.0;
236 out.im (im);
237 }
238
239 ProgressBar::inc();
240 } while (next (out, in, pos));
241
242 ProgressBar::done();
243 }
As was noted in the comments, EXECUTE seems to be a macro, apparent from the context a function header (and maybe a bit more, e.g. some global variables and functions), so the part in curly braces is the function body.
To get to the definition of EXECUTE, you will have to examine the headers.
However, if you can reach some part of the code during debugging, you could insert a string or char[] at that point, giving it the stringified version of EXECUTE, so you get whatever the preprocessor will emit for EXECUTE at that position in the code.
#define STR(x) #x
#define STRINGIFY(x) STR(x)
char c[] = STRINGIFY(EXECUTE);
the two macros are a known little macro trick to get the content of any macro as a string literal. Try it out and inspect the char array in your debugger to get the content of execute.
My wild guess here: EXECUTE is the main function or a replacement for it, the OPTIONS and ARGUMENTS describe what arguments the program expects and what command line options you can pass to it. Those macros and some of the used functions and variables (get_options, argument) are part of a little framework that should facilitate the usage, evaluation and user information about command line options.