I am having a bit of an issue with rotating a shape with given degrees.
void Shape::rotate(double degrees)
{
// rotates the vertices of a shape by a specified angle in degrees
int x, y, xx, yy;
double radians;
x = centroid.getX();
y = centroid.getY();
vertices.push_back(Vertex(x, y));
x = vertices.back().getX() - centroid.getX();
y = vertices.back().getY() - centroid.getY();
radians = (degrees * PI) / 180;
xx = round(x * cos(radians) - y * sin(radians));
yy = round(y * cos(radians) + x * sin(radians));
xx = xx + centroid.getX();
yy = yy + centroid.getY();
vertices.push_back(Vertex(xx, yy));
radians = (degrees * PI) / 180;
xx = round(x * cos(radians) - y * sin(radians));
yy = round(y * cos(radians) + x * sin(radians));
xx = xx + centroid.getX();
yy = yy + centroid.getY();
vertices.push_back(Vertex(xx, yy));
radians = (degrees * PI) / 180;
xx = round(x * cos(radians) - y * sin(radians));
yy = round(y * cos(radians) + x * sin(radians));
xx = xx + centroid.getX();
yy = yy + centroid.getY();
vertices.push_back(Vertex(xx, yy));
}
but the output i get is this:
Messed up rhombus
Any ideas where I'm going wrong?
Related
My function getHeightOfTerrain() is calling a barycentric formula function that is not returning the correct height for the one set test height in : heightMapFromArray[][].
I've tried watching OpenGL JAVA Game tutorials 14,21, 22, by "thin matrix" and I am confused on how to use my array: heightMapforBaryCentric in both of the supplied functions, and how to set the arguments that are passed to the baryCentic() function in some sort of manner so that I can solve the problem.
int creaateTerrain(int height, int width)
{
float holderY[6] = { 0.f ,0.f,0.f,0.f,0.f,0.f };
float scaleit = 1.5f;
float holder[6] = { 0.f,0.f,0.f,0.f,0.f,0.f };
for (int z = 0, z2 =0; z < iterationofHeightMap;z2++)
{
//each loop is two iterations and creates one quad (two triangles)
//however because each iteration is by two (i.e. : x=x+2) om bottom
//the amount of triangles is half the x value
//
//number of vertices : 80 x 80 x 6.
//column
for (int x = 0, x2 = 0; x < iterationofHeightMap;x2++)
{
//relevant - A : first triangle - on left triangle
//[row] [colum[]
holder[0] = heightMapFromArray[z][x];
//holder[0] = (float)imageData[(z / 2 * MAP_Z + (x / 2)) * 3];
//holder[0] = holder[0] / 255;// *scaleit;
vertices.push_back(glm::vec3(x, holder[0], z));
//match height map with online barycentric use
heightMapforBaryCentric[x2][z2] = holder[0];
holder[1] = heightMapFromArray[z+2][x];
//holder[1] = (float)imageData[(((z + 2) / 2 * MAP_Z + ((x) / 2))) * 3];
//holder[1] = holder[1] / 255;// 6 * scaleit;
vertices.push_back(glm::vec3(x, holder[1], z + 2));
//match height map with online barycentric use
heightMapforBaryCentric[x2][z2+1] = holder[1];
holder[2] = heightMapFromArray[z+2][x+2];
//holder[2] = (float)imageData[(((z + 2) / 2 * MAP_Z + ((x + 2) / 2))) * 3];
//holder[2] = holder[2] / 255;// *scaleit;
vertices.push_back(glm::vec3(x + 2, holder[2], z + 2));
////match height map with online barycentric use
heightMapforBaryCentric[x2+1][z2+1] = holder[2];
//relevant - B - second triangle (on right side)
holder[3] = heightMapFromArray[z][x];
//holder[3] = (float)imageData[((z / 2)*MAP_Z + (x / 2)) * 3];
//holder[3] = holder[3] / 255;// 256 * scaleit;
vertices.push_back(glm::vec3(x, holder[3], z));
holder[4] = heightMapFromArray[x+2][z+2];
//holder[4] = (float)imageData[(((z + 2) / 2 * MAP_Z + ((x + 2) / 2))) * 3];
//holder[4] = holder[4] / 255;// *scaleit;
vertices.push_back(glm::vec3(x + 2, holder[4], z + 2));
holder[5] = heightMapFromArray[x+2][z];
//holder[5] = (float)imageData[((z / 2)*MAP_Z + ((x + 2) / 2)) * 3];
//holder[5] = holder[5] / 255;// *scaleit;
vertices.push_back(glm::vec3(x + 2, holder[5], z));
x = x + 2;
}
z = z + 2;
}
return(1);
}
float getHeightOfTerrain(float worldX, float worldZ) {
float terrainX = worldX;
float terrainZ = worldZ;
int gridSquareSize = 2.0f;
gridX = (int)floor(terrainX / gridSquareSize);
gridZ = (int)floor(terrainZ / gridSquareSize);
xCoord = ((float)(fmod(terrainX, gridSquareSize)) / (float)gridSquareSize);
zCoord = ((float)(fmod(terrainZ, gridSquareSize)) / (float)gridSquareSize);
if (xCoord <= (1 - zCoord))
{
answer = baryCentric(
//left triangle
glm::vec3(0.0f, heightMapforBaryCentric[gridX][gridZ], 0.0f),
glm::vec3(0.0f, heightMapforBaryCentric[gridX][gridZ+1], 1.0f),
glm::vec3(1.0f, heightMapforBaryCentric[gridX+1][gridZ+1], 1.0f),
glm::vec2(xCoord, zCoord));
// if (answer != 1)
// {
// fprintf(stderr, "Z:gridx: %d gridz: %d answer: %f\n", gridX, gridZ,answer);
//
// }
}
else
{
//right triangle
answer = baryCentric(glm::vec3(0, heightMapforBaryCentric[gridX][gridZ], 0),
glm::vec3(1,heightMapforBaryCentric[gridX+1][gridZ+1], 1),
glm::vec3(1,heightMapforBaryCentric[gridX+1][gridZ], 0),
glm::vec2(xCoord, zCoord));
}
if (answer == 1)
{
answer = 0;
}
//answer = abs(answer - 1);
return(answer);
}
float baryCentric(glm::vec3 p1, glm::vec3 p2, glm::vec3 p3 , glm::vec2 pos) {
float det = (p2.z - p3.z) * (p1.x - p3.x) + (p3.x - p2.x) * (p1.z - p3.z);
float l1 = ((p2.z - p3.z) * (pos.x - p3.x) + (p3.x - p2.x) * (pos.y - p3.z)) / det;
float l2 = ((p3.z - p1.z) * (pos.x - p3.x) + (p1.x - p3.x) * (pos.y - p3.z)) / det;
float l3 = 1.0f - l1 - l2;
return (l1 * p1.y + l2 * p2.y + l3 * p3.y);
}
My expected results were that the center of the test grid's height to be the set value .5 and gradually less as the heights declined. My results were the heights being all the same, varied, or increasing. Usually these heights were under the value of one.
What I try to achieve is to rotate a line around rectangle center so it always stays in its bounds touching them (or having some padding).
Now I have the following routine for this, as you see I use tan calculations dividing my rectangle into 8 parts (red lines)
It works so far, but for some reason I have inconsistency using other calculation for radius drawing (green line), the lines won't always match as expected and I wonder why.
Basically the same could be achieved using just sin/cos calculations and finding cross points between lines and rect borders, but for some reason I could not get it to work.
std::pair<Point, Point>
MathUtils::calculateRotatingLine(Size size, double degrees)
{
auto width = size.width;
auto height = size.height;
double diagonalAngleTopRight = radiansToDegrees(atan((width / 2) / (height / 2)));
double diagonalAngleBottomRight = 90 + (90 - diagonalAngleTopRight);
double diagonalAngleBottomLeft = 180 + diagonalAngleTopRight;
double diagonalAngleTopLeft = 180 + diagonalAngleBottomRight;
double x, y;
/*
* *8*1*
* 7* *2
* 6* *3
* *5*4*
*/
// 1
if (degrees >= 0 && degrees <= diagonalAngleTopRight) {
x = width / 2 + height / 2 * tan(degreesToRadians(degrees));
y = 0;
}
// 2
else if (degrees > diagonalAngleTopRight && degrees <= 90) {
x = width;
y = width / 2 * tan(degreesToRadians(degrees - diagonalAngleTopRight));
}
// 3
else if (degrees > 90 && degrees <= diagonalAngleBottomRight) {
x = width;
y = height / 2 + width / 2 * tan(degreesToRadians(degrees - 90));
}
// 4
else if (degrees > diagonalAngleBottomRight && degrees <= 180) {
x = width - height / 2 * tan(degreesToRadians(degrees - diagonalAngleBottomRight));
y = height;
}
// 5
else if (degrees > 180 && degrees <= diagonalAngleBottomLeft) {
x = width / 2 - height / 2 * tan(degreesToRadians(degrees - 180));
y = height;
}
// 6
else if (degrees > diagonalAngleBottomLeft && degrees <= 270) {
x = 0;
y = height - width / 2 * tan(degreesToRadians(degrees - diagonalAngleBottomLeft));
}
// 7
else if (degrees > 270 && degrees <= diagonalAngleTopLeft) {
x = 0;
y = height / 2 - width / 2 * tan(degreesToRadians(degrees - 270));
}
// 8
else {
x = height / 2 * tan(degreesToRadians(degrees - diagonalAngleTopLeft));
y = 0;
}
return {Point{width / 2, height / 2}, Point{x, y}};
}
Green line calculation
Point
MathUtils::calculateCirclePoint(double radius, double degrees)
{
return {radius * cos(degreesToRadians(degrees)), radius * sin(degreesToRadians(degrees))};
}
EDIT
Awesome, it works thanks to #MBo
Point
MathUtils::calculateCrossPoint(Size size, double degrees)
{
auto x0 = size.width / 2;
auto y0 = size.height / 2;
auto vx = cos(degreesToRadians(degrees - 90));
auto vy = sin(degreesToRadians(degrees - 90));
//potential border positions
auto ex = vx > 0 ? size.width : 0;
auto ey = vy > 0 ? size.height : 0;
//check for horizontal/vertical directions
if (vx == 0) {
return {x0, ey};
}
if (vy == 0) {
return {ex, y0};
}
// in general case find times of intersections with horizontal and vertical edge line
auto tx = (ex - x0) / vx;
auto ty = (ey - y0) / vy;
// and get intersection for smaller parameter value
if (tx <= ty) {
return {ex, y0 + tx * vy};
}
return {x0 + ty * vx, ey};
}
Pseudocode to find intersection of ray emitted from rectangle center (with angle an in radians) with edges. (Works also for other (x0,y0) positions)
x0 = width / 2;
y0 = height / 2;
vx = cos(an);
vy = sin(an);
//potential border positions
ex = vx > 0? width: 0
ey = vy > 0? height: 0
//check for horizontal/vertical directions
if vx = 0 then
return cx = x0, cy = ey
if vy = 0 then
return cx = ex, cy = y0
//in general case find times of intersections with horizontal and vertical edge line
tx = (ex - x0) / vx
ty = (ey - y0) / vy
//and get intersection for smaller parameter value
if tx <= ty then
return cx = ex, cy = y0 + tx * vy
else
return cx = x0 + ty * vx, cy = ey
In implementing Blinn/Loop's algorithm on curve rendering, I realize there is a special case on Loop Curve Type. As described in their paper (subsection 4.4, page 6-7), they said the curve should be divided into two but I'm really confused how to obtain the intersection point.
Here's my rendering result:
As stated in the paper, this artifact occurs when either td/sd or te/se lie in between value [0, 1].
My source code:
...
case CURVE_TYPE_LOOP:
td = d2 + sqrt(4.0 * d1 * d3 - 3.0 * d2 *d2);
sd = 2.0 * d1;
te = d2 - sqrt(4.0 * d1 * d3 - 3.0 * d2 * d2);
se = 2.0 * d1;
if((td / sd > 0.0 && td/ sd < 1.0) || (te / se > 0.0 && te/ se < 1.0))
std::cout << "error\n";
// F matrix will be multiplied with inverse M3 to obtain tex coords (I use Eigen library btw...)
F << td * te, td * td * te, td * te * te, 1,
(-se * td) - (se * te), (-se * td * td) - (2.0 * sd * te * td), (-sd * te * te) - (2.0 * se * td * te), 0,
sd * se, te * sd * sd + 2.0 * se * td* sd, td * se * se + 2 * sd * te * se, 0,
0, -sd * sd * se, -sd * se * se, 0;
break;
...
Solved it,
I should get the splitting value t,
here's my code:
// get t
double splitLoop = -1.0;
switch (curve_type)
{
case CURVE_TYPE_UNKNOWN:
break;
case CURVE_TYPE_SERPENTINE:
tl = d2 + ((1.0 / sqrt(3.0)) * sqrt(3.0 * d2 * d2 - 4.0 * d1 * d3));
sl = 2.0 * d1;
tm = d2 - ((1.0 / sqrt(3.0)) * sqrt(3.0 * d2 * d2 - 4.0 * d1 * d3));
sm = 2.0 * d1;
F << tl * tm, tl * tl * tl, tm * tm * tm, 1,
-(sm * tl) -(sl * tm), -(3.0 * sl * tl * tl), -(3.0 * sm * tm * tm), 0,
sl * sm, 3.0 * sl * sl * tl, 3.0 * sm * sm * tm, 0,
0, -(sl * sl * sl), -(sm * sm * sm), 0;
break;
case CURVE_TYPE_LOOP:
td = d2 + sqrt(4.0 * d1 * d3 - 3.0 * d2 *d2);
sd = 2.0 * d1;
te = d2 - sqrt(4.0 * d1 * d3 - 3.0 * d2 * d2);
se = 2.0 * d1;
// Get splitting t
if((td / sd) > 0.0 && (td / sd) < 1.0)
{
splitLoop = td / sd;
}
else if((te / se) > 0.0 && (te/ se) < 1.0)
{
splitLoop = te / se;
}
F << td * te, td * td * te, td * te * te, 1,
(-se * td) - (se * te), (-se * td * td) - (2.0 * sd * te * td), (-sd * te * te) - (2.0 * se * td * te), 0,
sd * se, te * sd * sd + 2.0 * se * td* sd, td * se * se + 2 * sd * te * se, 0,
0, -sd * sd * se, -sd * se * se, 0;
break;
case CURVE_TYPE_QUADRATIC:
break;
case CURVE_TYPE_LINE:
break;
}
if(splitLoop > 0.0 && splitLoop < 1.0)
{
// SPLIT
double x01 = (x1 - x0) * splitLoop + x0;
double y01 = (y1 - y0) * splitLoop + y0;
double x12 = (x2 - x1) * splitLoop + x1;
double y12 = (y2 - y1) * splitLoop + y1;
double x23 = (x3 - x2) * splitLoop + x2;
double y23 = (y3 - y2) * splitLoop + y2;
double x012 = (x12 - x01) * splitLoop + x01;
double y012 = (y12 - y01) * splitLoop + y01;
double x123 = (x23 - x12) * splitLoop + x12;
double y123 = (y23 - y12) * splitLoop + y12;
double x0123 = (x123 - x012) * splitLoop + x012;
double y0123 = (y123 - y012) * splitLoop + y012;
// CURVE A (recursive)
DrawCubic(x0, y0, x01, y01, x012, y012, x0123, y0123);
// CURVE B (recursive)
DrawCubic(x0123, y0123, x123, y123, x23, y23, x3, y3);
}
else
{
// Draw as usual...
}
== EDIT ==
After i experimented again for a while, There's a numerical error on my program when the values of td/sd or te/se on subcurves lie again in between [0, 1], since my program use recursive by calling DrawCubic(), it causes recursive heap error.
In the meantime, I use 'hack' solution where I will not call DrawCurve() inside the recursive call (making sure the recursive is called only once). So far the result is quite satisfying and I don't see any artifact.
Any feedback is really welcomed since I'm not really good in numerical calculation :)
The original second order ODEs are
x'' - 2 * omega * y' - omega ** 2 * x = - mue * (x + pi2 * r12) / np.sqrt((x + pi2 * r12) ** 2 + y ** 2) ** 3 - mum * (x - pi1 * r12) / np.sqrt((x - pi1 * r12) ** 2 + y ** 2)
y'' + 2 * omega * x' - omega **2 * y = - mue * y / np.sqrt((x + pi2 * r12) ** 2 + y ** 2) ** 3 - mum * y / np.sqrt((x - pi1 * r12) ** 2 + y ** 2)
z'' = 0
So here is the code I used to solve the ODE but first I broke it up into 2 first orders.
I am receiving the error that the module on line 61 is not callable.
Line 61 is u = odeint(deriv, u0, dt)
#!/usr/bin/env python
import numpy as np
import scipy.integrate as odeint
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
me = 5.974 * 10 ** (24) # mass of the earth
mm = 7.348 * 10 ** (22) # mass of the moon
G = 6.67259 * 10 ** (-20) # gravitational parameter
re = 6378.0 # radius of the earth in km
rm = 1737.0 # radius of the moon in km
r12 = 384400.0 # distance between the CoM of the earth and moon
M = me + mm
pi1 = me / M
pi2 = mm / M
mue = 398600.0 # gravitational parameter of earth km^3/sec^2
mum = G * mm # grav param of the moon
mu = mue + mum
omega = np.sqrt(mu / r12 ** 3)
nu = 0.0 # flight path angle
x = 327156.0 # x location where the moon's SOI effects the spacecraft
y = 33050.0 # y location
vbo = 10.85 # velocity at burnout
gamma = -141.868 * np.pi / 180 # angle in radians of true anomaly
vx = vbo * (np.sin(gamma) * np.cos(nu) - np.cos(gamma) * np.sin(nu))
# velocity of the bo in the x direction
vy = vbo * (np.sin(gamma) * np.sin(nu) + np.cos(gamma) * np.cos(nu))
# velocity of the bo in the y direction
xrel = (re + 300.0) * np.cos(gamma)
# spacecraft x location relative to the earth
yrel = (re + 300.0) * np.sin(gamma)
# r0 = [xrel, yrel, 0]
# v0 = [vx, vy, 0]
u0 = [xrel, yrel, 0, vx, vy, 0]
def deriv(u, dt):
n1 = -((mue * (u[0] + pi2 * r12) / np.sqrt((u[0] + pi2 * r12) ** 2
+ u[1] ** 2) ** 3)
- (mum * (u[0] - pi1 * r12) / np.sqrt((u[0] - pi1 * r12) ** 2
+ u[1] ** 2) ** 3))
n2 = -((mue * u[1] / np.sqrt((u[0] + pi2 * r12) ** 2 + u[1] ** 2) ** 3)
- (mum * u[1] / np.sqrt((u[0] - pi1 * r12) ** 2 + u[1] ** 2) ** 3))
return [u[3], # dotu[0] = u[3]
u[4], # dotu[1] = u[4]
u[5], # dotu[2] = u[5]
2 * omega * u[5] + omega ** 2 * u[0] + n1, # dotu[3] = that
omega ** 2 * u[1] - 2 * omega * u[4] + n2, # dotu[4] = that
0] # dotu[5] = 0
dt = np.arange(0.0, 250000.0, .1)
u = odeint(deriv, u0, dt)
x, y, z, x2, y2, z2 = u.T
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot(x, y, z)
plt.show()
Assuming you mean this error:
~/coding$ python orbit1.py
Traceback (most recent call last):
File "orbit1.py", line 61, in <module>
u = odeint(deriv, u0, dt)
TypeError: 'module' object is not callable
This is because you want the function named odeint in scipy.integrate. Your line
import scipy.integrate as odeint
imports the entire module and gives it the name odeint. Try
from scipy.integrate import odeint
instead, or
import scipy.integrate
[...]
u = scipy.integrate.odeint(deriv, u0, dt)
which should give you
Here is the code I am using.
#define ANGLETORADIANS 0.017453292519943295769236907684886f // PI / 180
#define RADIANSTOANGLE 57.295779513082320876798154814105f // 180 / PI
rotation = rotation *ANGLETORADIANS;
cosRotation = cos(rotation);
sinRotation = sin(rotation);
for(int i = 0; i < 3; i++)
{
px[i] = (vec[i].x + centerX) * (cosRotation - (vec[i].y + centerY)) * sinRotation;
py[i] = (vec[i].x + centerX) * (sinRotation + (vec[i].y + centerY)) * cosRotation;
printf("num: %i, px: %f, py: %f\n", i, px[i], py[i]);
}
so far it seams my Y value is being fliped.. say I enter the value of X = 1 and Y = 1 with a 45 rotation you should see about x = 0 and y = 1.25 ish but I get x = 0 y = -1.25.
Also my 90 degree rotation always return x = 0 and y = 0.
p.s I know I'm only centering my values and not putting them back where they came from. It's not needed to put them back as all I need to know is the value I'm getting now.
Your bracket placement doesn't look right to me. I would expect:
px[i] = (vec[i].x + centerX) * cosRotation - (vec[i].y + centerY) * sinRotation;
py[i] = (vec[i].x + centerX) * sinRotation + (vec[i].y + centerY) * cosRotation;
Your brackets are wrong. It should be
px[i] = ((vec[i].x + centerX) * cosRotation) - ((vec[i].y + centerY) * sinRotation);
py[i] = ((vec[i].x + centerX) * sinRotation) + ((vec[i].y + centerY) * cosRotation);
instead