positioning pie slice problems - c++

The language I use doesn't have the built ability to create charts of any kind. The following code I found here. It's very old c++ code.
Center of the circle (origin)= (h,k)
Radius = r
...
void Circular_arc(constint h, constint k, constint r, constint start_angle, constint end_angle)
{
int color = getcolor();
float angle = (((start_angle <= end_angle) ? start_angle : end_angle)*(M_PI / 180));
float range = (((end_angle > start_angle) ? end_angle : start_angle)*(M_PI / 180));
float x = (r*cos(angle));
float y = (r*sin(angle));
do
{
putpixel((int)(h + x + 0.5), (int)(k - y + 0.5), color);
angle += 0.001;
x = (r*cos(angle));
y = (r*sin(angle));
} while (angle <= range);
}
...
I converted it to the language I'm using. I've put it in a loop which runs.
The issue with the code is that the slices always start from the same location and draw over what has been previously drawn.
The end result looks like this:
You can see from the differently colored numbers on the screen that there are 3 other arcs being covered up. First the black arc is drawn. Then the red. Then the green. The the yellow one. As the arcs are drawn, they cover up the previously drawn arc. I've inverted the length of the angles to show that there are, in fact 4 total arcs. Again, the black is drawn first, then the red, then the green, then the yellow.
Is there a way to start the next pie slice at the end of the current pie slice?

Because I really don't understand Turbo C++ I can't say for sure. But I think this is your solution:
void Circular_arc(constint h, constint k, constint r, constint start_angle, constint end_angle)
{
static int offset = 0;
start_angle = (start_angle + offset) % 360;
end_angle = (end_angle + offset) % 360;
offset = end_angle;
int color = getcolor();
float angle = (((start_angle <= end_angle) ? start_angle : end_angle)*(M_PI / 180));
float range = (((end_angle > start_angle) ? end_angle : start_angle)*(M_PI / 180));
float x = (r*cos(angle));
float y = (r*sin(angle));
do
{
putpixel((int)(h + x + 0.5), (int)(k - y + 0.5), color);
angle += 0.001;
x = (r*cos(angle));
y = (r*sin(angle));
} while (angle <= range);
}
Let me also say that this is a horrible solution in that it is in no way object oriented. But it seems to be the best you can do without starting over (which you should do.)

I've revamped this and created a method out of it. I did the following to fix my issue. Firstly, I got rid of the process that converted the beginning and ending angles from degree to radians by creating another function that does converts just the ending angle to radians. After Circular_arc is called, I set start_angle equal to the value of end_angle. Less code is written/used. Secondly, I removed the first calculation for finding x,y and moved the second one to the first thing in the loop. This wasn't a necessity, but I'm a big fan of writing as little code as possible. I'm lazy like that. The third biggest part and the whole reason for the OP in the first place was starting the current arc and the end of the previous arc. To do this, I created a variable and set it equal to the value of the start_angle. I then set parameters in the do-while loop to while (start_angle <= (end_angle+angle)). This started the current arc at the end of the previous arc.
The following is my attempt at converting my code to C++. If there are errors then please let me know and I'll do my best fix them. I hope this helps someone in the future!
...
void Circular_arc(constint h, constint k, constint r, constint start_angle, constint end_angle)
{
float angle
angle = start_angle
do
{
x = (r*cos(start_angle));
y = (r*sin(start_angle));
putpixel((int)(h + x + 0.5), (int)(k - y + 0.5), getcolor());
angle += 0.001;
} while (start_angle <= (end_angle+angle));
}
...
Here's what the pie chart looks like so far...

Related

Bilinear Interpolation - OSRM Rastersource

I've got a question about bilinear interpolation in the OSRM-Project.
I understand the "normal" bilinear interpolation. Here the picture from Wikipedia, what is insane:
Now I'm trying to understand the bilinear interpolation which is used in the OSRM-Project for raster source data.
// Query raster source using bilinear interpolation
RasterDatum RasterSource::GetRasterInterpolate(const int lon, const int lat) const
{
if (lon < xmin || lon > xmax || lat < ymin || lat > ymax)
{
return {};
}
const auto xthP = (lon - xmin) / xstep;
const auto ythP =
(ymax - lat) /
ystep; // the raster texture uses a different coordinate system with y pointing downwards
const std::size_t top = static_cast<std::size_t>(fmax(floor(ythP), 0));
const std::size_t bottom = static_cast<std::size_t>(fmin(ceil(ythP), height - 1));
const std::size_t left = static_cast<std::size_t>(fmax(floor(xthP), 0));
const std::size_t right = static_cast<std::size_t>(fmin(ceil(xthP), width - 1));
// Calculate distances from corners for bilinear interpolation
const float fromLeft = xthP - left; // this is the fraction part of xthP
const float fromTop = ythP - top; // this is the fraction part of ythP
const float fromRight = 1 - fromLeft;
const float fromBottom = 1 - fromTop;
return {static_cast<std::int32_t>(raster_data(left, top) * (fromRight * fromBottom) +
raster_data(right, top) * (fromLeft * fromBottom) +
raster_data(left, bottom) * (fromRight * fromTop) +
raster_data(right, bottom) * (fromLeft * fromTop))};
}
Original Code here
Can someone explain me how the code works?
The input format are the SRTM data in ASCII format.
The variables height and width are defined as nrows and ncolumns.
The variables xstep and ystep are defined as:
return (max - min) / (static_cast<float>(count) - 1)
Where count is height for ystep and width for xstep, max and min similar.
And another question:
Can I use the same code for data in TIF-format and the whole world?
Horizontal pixel coordinates are in the range [0, width - 1]; similarly vertical coordinates are in [0, height - 1]. (Zero-indexing convention used in many many languages including C++)
The lines
const auto xthP = (lon - xmin) / xstep; (and for ythP)
Convert the input image-space coordinates (long, lat) into pixel coordinates. xstep is the width of each pixel in image-space.
Rounding this down (using floor) gives pixels intersected by the sample area on one side, and rounding up (ceil) gives the pixels on the other side. For the X-coordinate these give left and right.
The reason for using fmin and fmax are to clamp the coordinates so that they don't exceed the pixel coordinate range.
EDIT: since you are trying to interpret this picture, I'll list the corresponding parts below:
Q11 = (left, top)
Q12 - (left, bottom), etc.
P = (xthP, ythP)
R1 = fromTop, R2 = fromBottom etc.
A good start point would be http://www.cs.uu.nl/docs/vakken/gr/2011/Slides/06-texturing.pdf, slide 27. In future though, Google is your friend.

Lissajous figure in Direct3D

I made a cube in DirectX, but now I want the cube to move around. I want this cube to move around in a Lissajous pattern. But for some reason no matter what variables I enter my cube just makes circles instead of the Lissajous figure.
I'm not familiar with this function and I've been searching for answers but I can't seem to fix my problem. So may be I made a mistake in the function, or maybe I'm doing everything completely wrong.
This is the code I use to calculate the position, where m_Angle changes every frame so the cube keeps moving.
float scale = 3.f;
float valueA = 1.0f;
float valueB = 2.0f;
float valueX = scale * valueA * sin(m_Angle + ((valueB - 1) / valueB)*(XM_PIDIV2));
float valueZ = scale * valueB * sin(m_Angle);
m_pColoredCube_1->SetPos(XMFLOAT3(valueX, 0.0f, valueZ));
Liassajous figures are just an interference of different oscillations. An oscillation can be described as:
y(t) = amplitude * sin(2 * PI * frequency * t + phase)
In your case, t is m_Angle.
You then set different oscillations for the x and z component (and possibly for the y component, too). If you set both frequencies equal (as you did), you get a circle or ellipse, depending on the phase. What you want to do instead is:
float frequencyRatio = ...;
float phaseDifference = ...;
float valueX = scale * sin(m_Angle * frequencyRatio + phaseDifference);
float valueZ = scale * sin(m_Angle);
If you set frequencyRatio = 2.0f and phaseDifference = 0, you get the following figure:
Or for frequencyRatio = 5.0f / 4.0f and phaseDifference = 0:

Rotating a point around another point

I'm trying to rotate one point around a central point by an angle - standard problem. I've seen lots of posts about this but I can't get my implementation to work:
void Point::Rotate(const Point Pivot, const float Angle)
{
if (Angle == 0)
return;
float s = sin(Angle);
float c = cos(Angle);
x -= Pivot.x;
y -= Pivot.y;
x = (x * c) - (y * s) + Pivot.x;
y = (x * s) + (y * c) + Pivot.y;
}
This is my code, the logic of which I've gleaned from numerous source, for example here, and here.
As far as I'm aware, it should work. However, when I apply it to rotating for example, the point (0, 100) by 90 degrees (Pi/2 is given to the function) around (0, 0), the rotated point is apparently at (-100, -100); 100px below where it should be.
When trying to draw a circle (36 points) - it creates a vague heart shape. It looks like a graph I saw that I think was in polar coordinates - do I need to convert my point to Cartesian or something?
Can anyone spot anything wrong with my code?
Edit: Sorry, this function is a member function to a Point class - x and y are the member variables :/
You're almost there, but you're modifying x in the next-to-last line, meaning that the value of that coordinate fed into the y calculation is incorrect!
Instead, use temporary variables for the new x and y and then add the Pivot coordinates on afterwards:
double nx = (x * c) - (y * s);
double ny = (x * s) + (y * c);
x = nx + Pivot.x;
y = ny + Pivot.y;

Line-Circle Algorithm not quite working as expected

First, see:
https://math.stackexchange.com/questions/105180/positioning-a-widget-involving-intersection-of-line-and-a-circle
I have an algorithm that solves for the height of an object given a circle and an offset.
It sort of works but the height is always off:
Here is the formula:
and here is a sketch of what it is supposed to do:
And here is sample output from the application:
In the formula, offset = 10 and widthRatio is 3. This is why it is (1 / 10) because (3 * 3) + 1 = 10.
The problem, as you can see is the height of the blue rectangle is not correct. I set the bottom left offsets to be the desired offset (in this case 10) so you can see the bottom left corner is correct. The top right corner is wrong because from the top right corner, I should only have to go 10 pixels until I touch the circle.
The code I use to set the size and location is:
void DataWidgetsHandler::resize( int w, int h )
{
int tabSz = getProportions()->getTableSize() * getProportions()->getScale();
int r = tabSz / 2;
agui::Point tabCenter = agui::Point(
w * getProportions()->getTableOffset().getX(),
h * getProportions()->getTableOffset().getY());
float widthRatio = 3.0f;
int offset = 10;
int height = solveHeight(offset,widthRatio,tabCenter.getX(),tabCenter.getY(),r);
int width = height * widthRatio;
int borderMargin = height;
m_frame->setLocation(offset,
h - height - offset);
m_frame->setSize(width,height);
m_borderLayout->setBorderMargins(0,0,borderMargin,borderMargin);
}
I can assert that the table radius and table center location are correct.
This is my implementation of the formula:
int DataWidgetsHandler::solveHeight( int offset, float widthRatio, float h, float k, float r ) const
{
float denom = (widthRatio * widthRatio) + 1.0f;
float rSq = denom * r * r;
float eq = widthRatio * offset - offset - offset + h - (widthRatio * k);
eq *= eq;
return (1.0f / denom) *
((widthRatio * h) + k - offset - (widthRatio * (offset + offset)) - sqrt(rSq - eq) );
}
It uses the quadratic formula to find what the height should be so that the distance between the top right of the rectangle, bottom left, amd top left are = offset.
Is there something wrong with the formula or implementation? The problem is the height is never long enough.
Thanks
Well, here's my solution, which looks to resemble your solveHeight function. There might be some arithmetic errors in the below, but the method is sound.
You can think in terms of matching the coordinates at the point of the circle across
from the rectangle (P).
Let o_x,o_y be the lower left corner offset distances, w and h be the
height of the rectangle, w_r be the width ratio, dx be the desired
distance between the top right hand corner of the rectangle and the
circle (moving horizontally), c_x and c_y the coordinates of the
circle's centre, theta the angle, and r the circle radius.
Labelling it is half the work! Simply write down the coordinates of the point P:
P_x = o_x + w + dx = c_x + r cos(theta)
P_y = o_y + h = c_y + r sin(theta)
and we know w = w_r * h.
To simplify the arithmetic, let's collect some of the constant terms, and let X = o_x + dx - c_x and Y = o_y - c_y. Then we have
X + w_r * h = r cos(theta)
Y + h = r sin(theta)
Squaring and summing gives a quadratic in h:
(w_r^2 + 1) * h^2 + 2 (X*w_r + Y) h + (X^2+Y^2-r^2) == 0
If you compare this with your effective quadratic, then as long as we made different mistakes :-), you might be able to figure out what's going on.
To be explicit: we can solve this using the quadratic formula, setting
a = (w_r^2 + 1)
b = 2 (X*w_r + Y)
c = (X^2+Y^2-r^2)

Creating a linear gradient in 2D array

I have a 2D bitmap-like array of let's say 500*500 values. I'm trying to create a linear gradient on the array, so the resulting bitmap would look something like this (in grayscale):
(source: showandtell-graphics.com)
The input would be the array to fill, two points (like the starting and ending point for the Gradient tool in Photoshop/GIMP) and the range of values which would be used.
My current best result is this:
alt text http://img222.imageshack.us/img222/1733/gradientfe3.png
...which is nowhere near what I would like to achieve. It looks more like a radial gradient.
What is the simplest way to create such a gradient? I'm going to implement it in C++, but I would like some general algorithm.
This is really a math question, so it might be debatable whether it really "belongs" on Stack Overflow, but anyway: you need to project the coordinates of each point in the image onto the axis of your gradient and use that coordinate to determine the color.
Mathematically, what I mean is:
Say your starting point is (x1, y1) and your ending point is (x2, y2)
Compute A = (x2 - x1) and B = (y2 - y1)
Calculate C1 = A * x1 + B * y1 for the starting point and C2 = A * x2 + B * y2 for the ending point (C2 should be larger than C1)
For each point in the image, calculate C = A * x + B * y
If C <= C1, use the starting color; if C >= C2, use the ending color; otherwise, use a weighted average:
(start_color * (C2 - C) + end_color * (C - C1))/(C2 - C1)
I did some quick tests to check that this basically worked.
In your example image, it looks like you have a radial gradient. Here's my impromtu math explanation for the steps you'll need. Sorry for the math, the other answers are better in terms of implementation.
Define a linear function (like y = x + 1) with the domain (i.e. x) being from the colour you want to start with to the colour your want to end with. You can think of this in terms of a range the within Ox0 to OxFFFFFF (for 24 bit colour). If you want to handle things like brightness, you'll have to do some tricks with the range (i.e. the y value).
Next you need to map a vector across the matrix you have, as this defines the direction that the colours will change in. Also, the colour values defined by your linear function will be assigned at each point along the vector. The start and end point of the vector also define the min and max of the domain in 1. You can think of the vector as one line of your gradient.
For each cell in the matrix, colours can be assigned a value from the vector where a perpendicular line from the cell intersects the vector. See the diagram below where c is the position of the cell and . is the the point of intersection. If you pretend that the colour at . is Red, then that's what you'll assign to the cell.
|
c
|
|
Vect:____.______________
|
|
I'll just post my solution.
int ColourAt( int x, int y )
{
float imageX = (float)x / (float)BUFFER_WIDTH;
float imageY = (float)y / (float)BUFFER_WIDTH;
float xS = xStart / (float)BUFFER_WIDTH;
float yS = yStart / (float)BUFFER_WIDTH;
float xE = xEnd / (float)BUFFER_WIDTH;
float yE = yEnd / (float)BUFFER_WIDTH;
float xD = xE - xS;
float yD = yE - yS;
float mod = 1.0f / ( xD * xD + yD * yD );
float gradPos = ( ( imageX - xS ) * xD + ( imageY - yS ) * yD ) * mod;
float mag = gradPos > 0 ? gradPos < 1.0f ? gradPos : 1.0f : 0.0f;
int colour = (int)( 255 * mag );
colour |= ( colour << 16 ) + ( colour << 8 );
return colour;
}
For speed ups, cache the derived "direction" values (hint: premultiply by the mag).
There are two parts to this problem.
Given two colors A and B and some percentage p, determine what color lies p 'percent of the way' from A to B.
Given a point on a plane, find the orthogonal projection of that point onto a given line.
The given line in part 2 is your gradient line. Given any point P, project it onto the gradient line. Let's say its projection is R. Then figure out how far R is from the starting point of your gradient segment, as a percentage of the length of the gradient segment. Use this percentage in your function from part 1 above. That's the color P should be.
Note that, contrary to what other people have said, you can't just view your colors as regular numbers in your function from part 1. That will almost certainly not do what you want. What you do depends on the color space you are using. If you want an RGB gradient, then you have to look at the red, green, and blue color components separately.
For example, if you want a color "halfway between" pure red and blue, then in hex notation you are dealing with
ff 00 00
and
00 00 ff
Probably the color you want is something like
80 00 80
which is a nice purple color. You have to average out each color component separately. If you try to just average the hex numbers 0xff0000 and 0x0000ff directly, you get 0x7F807F, which is a medium gray. I'm guessing this explains at least part of the problem with your picture above.
Alternatively if you are in the HSV color space, you may want to adjust the hue component only, and leave the others as they are.
void Image::fillGradient(const SColor& colorA, const SColor& colorB,
const Point2i& from, const Point2i& to)
{
Point2f dir = to - from;
if(to == from)
dir.x = width - 1; // horizontal gradient
dir *= 1.0f / dir.lengthQ2(); // 1.0 / (dir.x * dir.x + dir.y * dir.y)
float default_kx = float(-from.x) * dir.x;
float kx = default_kx;
float ky = float(-from.y) * dir.y;
uint8_t* cur_pixel = base; // array of rgba pixels
for(int32_t h = 0; h < height; h++)
{
for(int32_t w = 0; w < width; w++)
{
float k = std::clamp(kx + ky, 0.0f, 1.0f);
*(cur_pixel++) = colorA.r * (1.0 - k) + colorB.r * k;
*(cur_pixel++) = colorA.g * (1.0 - k) + colorB.g * k;
*(cur_pixel++) = colorA.b * (1.0 - k) + colorB.b * k;
*(cur_pixel++) = colorA.a * (1.0 - k) + colorB.a * k;
kx += dir.x;
}
kx = default_kx;
ky += dir.y;
}
}