How create a atom model in c++ with irrlicht - c++

I am working on a project in which I show a model of a atom with protons, neutrons, and electrons. I want to show the neutrons and protons like a atom model would and so I need some points to put my points around. So I need an function like this
<list of points> getPoints(int numberOfProtonsAndNeutrons)
I have tried iterating over the latitude and longitude, but I couldn't get the intervals to work. That also is not how atom model are visually shown.
So I need an idea of how to go about creating points to put my neutrons and protons on.

Well, assuming you want some neutrons and protons in the center, with some electrons outside in various orbits (the Bohr model), then you need a few things. We can just place all the protons and neutrons on the surface of a sphere with small radius (r=1), and then place the electrons on a sphere with radius increasing depending on the orbital shell the electron is on.
Without doing all the work for you, you need will need an atom class.
It will have a member representing the orbital shell using an index: i=0 could be the innermost shell, with i>0 defining the outer shells with electrons.
You could then compute the radius of the sphere using the index as a member function. Something like
radius() { return i * ShellDist + 1; }
where ShellDist is how far apart the electron shells should be.
You can create a class for the general atom, given its shell and type.
class Atom {
public:
static const double ShellDist = 2; // remember to include a definition for this
Atom(int shell) : shell(shell) {}
virtual void radius() { return shell * ShellDist + 1; }
private:
int shell;
};
class Electron : public Atom {
public:
Electron(int shell) : Atom(shell) {}
};
class Neutron : public Atom {
public:
Neutron() : Atom(0) {}
};
I'm assuming you want all the points on the sphere to be on a plane coincident with the sphere, with the plane going through the origin. To simplify this, we will just choose the circle which goes along the equator of the sphere, and then rotate it using a rotation matrix R.
So the equator circle's equation if z is the vertical axis
Vector3d
circle(double t, double r) { return Vector3d(cos(t) * r, sin(t) * r, 0); }
If z is our vertical axis, then z is always zero here.
Then, choose a rotation matrix R using a vector math library (I'm not sure which one you are using). You can usually create a euler angle representation. Rotate it by some random fixed amount about the x and y axes. This will rotate the circle so we put all the electrons on a random circular orbit around the origin. This is using Eigen:
Transform t = AngleAxis(rand() * 2 * M_PI, Vector3d(0, 1, 0))
* AngleAxis(rand() * 2 * M_PI, Vector3d(1, 0, 0));
Putting it together:
Vector3d createPoint(const Atom& atom, double t) {
auto xform = AngleAxis(rand() * 2 * M_PI, Vector3d(0, 1, 0))
* AngleAxis(rand() * 2 * M_PI, Vector3d(1, 0, 0));
Vector3d electronPoint = xform * circle(t, atom.shellRadius());
return electronPoint;
}
Finally, you can add all the points together for all the atoms in your original array
vector<Vector3d> getPoints() {
vector<shared_ptr<Atom>> atoms;
// construct your atoms depending on the molecule
// eg.
atom.push_back(make_shared<Electron>(1)); // Create an electron on shell 1
atom.push_back(make_shared<Neutron>()); // Create a neutron, which will be shell 0
vector<Vector3d> points;
for (const auto& atom : atoms) {
// instead of rand() you could use some scaling
// of the current time to get an animation with the shells orbiting,
points.push_back(createPoint(atom, rand()));
}
}
Finally, you can then pass this vector of points to irrlicht. You probably want to generate this every frame if you desire an animation.
Good luck! Irrlicht probably has a built-in matrix library which may also help. If you really want to speed things along, you could create custom vertex shaders which do all this math on the GPU, and then simply pass in electrons. This won't be necessary for any known molecules, though :). You also may want a fixed offset per electron. All of this could be done by adding parameters to the Electron and Neutron constructors, to change the start of their orbit.

Related

2d coordinates expansion and shrinking

I was trying to expand or shrink the 2d object up to K. Let's say I've a co-ordinate system like { {5,0}, {0,0}, {0,-5}, {5,-5}, {5,-10}, {0,-10} } (yellow marker shape) and I want to offset every position K = 1. The resultant shape would look something like this
As my initial approach was to find the center of the shape and increase each coordinate according to the center, the source is here. But it seems like it only works on a closed symmetric shape like squares and for asymmetric shapes or open shapes, it doesn't work.
My code is given below
void myFun() {
std::vector<std::pair<double, double>> co, CO;
co = { { {5,0}, {0,0}, {0,-5}, {5,-5}, {5,-10}, {0,-10} } };
double x = 0, y = 0;
double n = co.size();
for (auto it : co) {
x += it.first; y += it.second;
}
std::pair<double, double> o = { x / n, y / n };
int K = 1;
for (auto it : co) {
std::pair<double, double> inc = { (it.first - o.first) * K, (it.second - o.second) * K };
CO.push_back({ o.first - inc.first, o.second - inc.second });
}
reverse(CO.begin(), CO.end());
for (auto it: CO) {}
}
The output co-ordinate shape is
How can I improve my approach and solve this issue? Thank you.
I see two ways for you to achieve what you are after:
simply scaling around a point. Take all the coordinates that make up the shape and scale them. To make that happen around a certain point, use the usual approach consisting of those steps: 1. Translate such that (0,0) is the point to scale around, 2, Scale and 3. Translate back. That can easily be done with transform matrices.
Offset each point. That is far more complicated, since it requires you to define an In- / Outside of the shape. Event though this is a description for bezier curves, here you can find a good and illustrative description of the approach. Basically you need to find some kind of normal vector for each Point in the shape and offset it on a fixed amount in that direction.
Maybe there are other way and combinations of the both above which finally snap each point on the grid by rounding.

Drawing a sprite on the circumference of a circle based on the position of other objects

I'm making a sniper shooter arcade style game in Gamemaker Studio 2 and I want the position of targets outside of the viewport to be pointed to by chevrons that move along the circumference of the scope when it moves. I am using trig techniques to determine the coordinates but the chevron is jumping around and doesn't seem to be pointing to the target. I have the code broken into two: the code to determine the coordinates in the step event of the enemies class (the objects that will be pointed to) and a draw event in the same class. Additionally, when I try to rotate the chevron so it also points to the enemy, it doesn't draw at all.
Here's the coordinate algorithm and the code to draw the chevrons, respectively
//determine the angle the target makes with the player
delta_x = abs(ObjectPlayer.x - x); //x axis displacement
delta_y = abs(ObjectPlayer.y - y); //y axis displacement
angle = arctan2(delta_y,delta_x); //angle in radians
angle *= 180/pi //angle in radians
//Determine the direction based on the larger dimension and
largest_distance = max(x,y);
plusOrMinus = (largest_distance == x)?
sign(ObjectPlayer.x-x) : sign(ObjectPlayer.y-y);
//define the chevron coordinates
chevron_x = ObjectPlayer.x + plusOrMinus*(cos(angle) + 20);
chevron_y = ObjectPlayer.y + plusOrMinus*(sign(angle) + 20);
The drawing code
if(object_exists(ObjectEnemy)){
draw_text(ObjectPlayer.x, ObjectPlayer.y-10,string(angle));
draw_sprite(Spr_Chevron,-1,chevron_x,chevron_y);
//sSpr_Chevron.image_angle = angle;
}
Your current code is slightly more complex that it needs to be for this, if you want to draw chevrons pointing towards all enemies, you might as well do that on spot in Draw. And use degree-based functions if you're going to need degrees for drawing anyway
var px = ObjectPlayer.x;
var py = ObjectPlayer.y;
with (ObjectEnemy) {
var angle = point_direction(px, py, x, y);
var chevron_x = px + lengthdir_x(20, angle);
var chevron_y = py + lengthdir_y(20, angle);
draw_sprite_ext(Spr_Chevron, -1, chevron_x, chevron_y, 1, 1, angle, c_white, 1);
}
(also see: an almost-decade old blog post of mine about doing this while clamping to screen edges instead)
Specific problems with your existing code are:
Using a single-axis plusOrMinus with two axes
Adding 20 to sine/cosine instead of multiplying them by it
Trying to apply an angle to sSpr_Chevron (?) instead of using draw_sprite_ext to draw a rotated sprite.
Calculating largest_distance based on executing instance's X/Y instead of delta X/Y.

cocos2dx detect intersection with polygon sprite

I am using cocos2d-x 3.8.
I try to create two polygon sprites with the following code.
I know we can detect intersect with BoundingBox but is too rough.
Also, I know we can use Cocos2d-x C++ Physics engine to detect collisions but doesn't it waste a lot of resource of the mobile device? The game I am developing does not need physics engine.
is there a way to detect the intersect of polygon sprites?
Thank you.
auto pinfoTree = AutoPolygon::generatePolygon("Tree.png");
auto treeSprite= Sprite::create(pinfoTree);
treeSprite-> setPosition(width / 4 * 3 - 30 , height / 2 - 200);
this->addChild(treeSprite);
auto pinfoBird = AutoPolygon::generatePolygon("Bird.png");
auto Bird= Sprite::create(pinfoTree);
Bird->setPosition(width / 4 * 3, height / 2);
this->addChild(Bird)
This is a bit more complicated: AutoPolygon gives you a bunch of triangles - the PhysicsBody::createPolygon requires a convex polygon with clockwise winding… so these are 2 different things. The vertex count might even be limited. I think Box2d’s maximum count for 1 polygon is 8.
If you want to try this you’ll have to merge the triangles to form polygons. An option would be to start with one triangle and add more as long as the whole thing stays convex. If you can’t add any more triangles start a new polygon. Add all the polygons as PhysicsShapes to your physics body to form a compound object.
I would propose that you don’t follow this path because
Autopolygon is optimized for rendering - not for best fitting
physics - that is a difference. A polygon traced with Autopolygon will always be bigger than the original sprite - Otherwise you would see rendering artifacts.
You have close to no control over the generated polygons
Tracing the shape in the app will increase your startup time
Triangle meshes and physics outlines are 2 different things
I would try some different approach: Generate the collision shapes offline. This gives you a bunch of advantages:
You can generate and tweak the polygons in a visual editor e.g. by
using PhysicsEditor
Loading the prepares polygons is way faster
You can set additional parameters like mass etc
The solution is battle proven and works out of the box
But if you want to know how polygon intersect work. You can look at this code.
// Calculate the projection of a polygon on an axis
// and returns it as a [min, max] interval
public void ProjectPolygon(Vector axis, Polygon polygon, ref float min, ref float max) {
// To project a point on an axis use the dot product
float dotProduct = axis.DotProduct(polygon.Points[0]);
min = dotProduct;
max = dotProduct;
for (int i = 0; i < polygon.Points.Count; i++) {
flaot d = polygon.Points[i].DotProduct(axis);
if (d < min) {
min = dotProduct;
} else {
if (dotProduct> max) {
max = dotProduct;
}
}
}
}
// Calculate the distance between [minA, maxA] and [minB, maxB]
// The distance will be negative if the intervals overlap
public float IntervalDistance(float minA, float maxA, float minB, float maxB) {
if (minA < minB) {
return minB - maxA;
} else {
return minA - maxB;
}
}
// Check if polygon A is going to collide with polygon B.
public boolean PolygonCollision(Polygon polygonA, Polygon polygonB) {
boolean result = true;
int edgeCountA = polygonA.Edges.Count;
int edgeCountB = polygonB.Edges.Count;
float minIntervalDistance = float.PositiveInfinity;
Vector edge;
// Loop through all the edges of both polygons
for (int edgeIndex = 0; edgeIndex < edgeCountA + edgeCountB; edgeIndex++) {
if (edgeIndex < edgeCountA) {
edge = polygonA.Edges[edgeIndex];
} else {
edge = polygonB.Edges[edgeIndex - edgeCountA];
}
// ===== Find if the polygons are currently intersecting =====
// Find the axis perpendicular to the current edge
Vector axis = new Vector(-edge.Y, edge.X);
axis.Normalize();
// Find the projection of the polygon on the current axis
float minA = 0; float minB = 0; float maxA = 0; float maxB = 0;
ProjectPolygon(axis, polygonA, ref minA, ref maxA);
ProjectPolygon(axis, polygonB, ref minB, ref maxB);
// Check if the polygon projections are currentlty intersecting
if (IntervalDistance(minA, maxA, minB, maxB) > 0)
result = false;
return result;
}
}
The function can be used this way
boolean result = PolygonCollision(polygonA, polygonB);
I once had to program a collision detection algorithm where a ball was to collide with a rotating polygon obstacle. In my case the obstacles where arcs with certain thickness. and where moving around an origin. Basically it was rotating in an orbit. The ball was also rotating around an orbit about the same origin. It can move between orbits. To check the collision I had to just check if the balls angle with respect to the origin was between the lower and upper bound angles of the arc obstacle and check if the ball and the obstacle where in the same orbit.
In other words I used the various constrains and properties of the objects involved in the collision to make it more efficient. So use properties of your objects to cause the collision. Try using a similar approach depending on your objects

How to rotate an object so it faces another?

I am making a game in opengl, and i can't figure out how to make my enemy characters turn to face my player. I only need the enemy to rotate on the y axis towards the player. Then I want them to move towards him.I have tried a bunch of different methods but haven't been able to get anything to work.
There are a few things you need to decide on yourself at the beginning of the project to be used throughout the project, like the representation of positions and the orientation (as well as the setup of the screen/clip planes etc.) However, you haven't mentioned any of this. So you may have to adapt the code below to suit your game, but it should be easily adaptable and applicable.
For the following example, I'll assume that -y axis is the top of your screen.
#include <math.h> // atan2
// you need to way to represent position and directions
struct vector2{
float x;
float y;
} playerPosition, enemyPosition;
float playerRotation;
// setup the instances and values
void setup() {
// Set some default values for the positions
playerPosition.x = 100;
playerPosition.y = 100;
enemyPosition.x = 200;
enemyPosition.y = 300;
}
// called every frame
void update(float delta){
// get the direction vector between the player and the enemy. We can then use this to both calculate the rotation angle between the two as well as move the player towards the enemy.
vector2 dirToEnemy;
dirToEnemy.x = playerPosition.x - enemyPosition.x;
dirToEnemy.y = playerPosition.y - enemyPosition.y;
// move the player towards the enemy
playerPosition.x += dirToEnemy.x * delta * MOVEMENT_SPEED;
playerPosition.y += dirToEnemy.y * delta * MOVEMENT_SPEED;
// get the player angle on the y axis
playerRotation = atan2(-dirToEnemy.y, dirToEnemy.x);
}
void draw(){
// use the playerPosition and playerAngle to render the player
}
Using the above code, you should be able to move your player object around and set the angle of rotation (you need to watch out for radians/degrees of the returned and expected angle values).

Drawing a crescent shape in OpenGL

How can I draw a 2D crescent or moon shape in OpenGL? I have tried using sin and cos like how I did for drawing circles but because a crescent has a "cut" inside it, the sin and cos don't look enough. I couldn't figure out how I could do an intersection between 2 polygons either. So I'm thinking if there a mathematical formula for drawing the crescent?
This isn't mathematically correct, but it may be close enough to meet your needs:
void drawCrescentLine(float step,float scale,float fullness) {
float angle=0.0f;
while (angle<M_PI) {
glVertex2f(scale*sinf(angle),scale*cosf(angle));
angle+=step;
}
while (angle<(2.0f*M_PI)) {
glVertex2f(fullness*scale*sinf(angle),scale*cosf(angle));
angle+=step;
}
glVertex2f(0.0f,scale);
}
or
void drawCrescentTriStrip(float step,float scale,float fullness) {
glVertex2f(0.0f,scale);
float angle=step;
while (angle<M_PI) {
float sinAngle=sinf(angle);
float cosAngle=cosf(angle);
glVertex2f(scale*sinAngle,scale*cosAngle);
glVertex2f(-fullness*scale*sinAngle,scale*cosAngle);
angle+=step;
}
glVertex2f(0.0f,-scale);
}
At fullness=1, it will draw a circle of size scale while at fullness=-0.99f, it will draw a very thin cresent. You could use two different fullness values, rightFullness and leftFullness, and always set one of them to 1.0f so you can change the direction of the crescent.
You can draw two perpendicular ellipses that intersect each other. A crescent is formed with the space that is cut out from one of the eclipses. The intersection can be removed by using a bitwise NAND logical operator when drawing.
glEnable(GL_COLOR_LOGIC_OP);
drawEllipse1();
glLogicOp(GL_NAND);
drawEllipse2();
The long way of doing it is to specify a bunch of vertices that form a skeleton for the shape that you want. You can then 'connect the dots' with GL_LINES to draw your shape. If you want a smoother shape, you can use the vertices as control points for a Bezier/Catmull-Rom spline that would draw a smooth curve joining all your vertices.
You can try this:
Vertex outside [N+1]; // Fill in N with the precision you want
Vertex inside [N+1]; // Fill in N with the precision you want
double neg_size = sqrt (1 + NEG_DIST); // Size of intescting circle.
// NEG_DIST is the distance between their centers
// Greater NEG_DIST => wider crecent
double start_angle = atan (1 / NEG_DIST); // Start angle for the inside edge
double arc = M_PI - (2 * start_angle); // Arc of the inside edge
for (int i = 0; i <= N; i++)
{
// Outside edge
outside [i].x = cos ((M_PI / N) * i) * SIZE;
outside [i].y = sin ((M_PI / N) * i) * SIZE;
// Inside edge
inside [i].x = (cos (start_angle + ((arc / N) * i)) * neg_size) * SIZE;
inside [i].y = (sin (start_angle + ((arc / N) * i)) * neg_size - NEG_DIST) * SIZE;
}
This produces the intersected polys version of a crescent. It will give you an array of coordinates for an inside and outside arc for a crescent. Then you can feed these through your favorite draw method.
NOTE: The endpoints of inside and outside overlap (I did this so that I wouldn't have +/- 1's all over the place). I'm pretty sure a GL program will be fine with it, but if you have a fence post error with this, that may be where it came from