How do I make a convex shape infinitely rotate in SFML - rotation

I am making a game where I need a player to be constantly rotating. I have tried using a vertex array instead of a convex shape so that I could use trig to move the points around (which was shown to me in a tutorial), but it does not load my texture correctly. The player is a triangle and when I try to load the texture to the vertex array it displays it as completely black, and I want it to actually load my texture. when I used a convex shape, it did load the texture correctly, but I don't know how I'm going to make it rotate. I would prefer to use a convex shape since for me it's easier to work with.
#include <SFML/Graphics.hpp>
#include <math.h>
#include <stdlib.h>
int main()
{
sf::RenderWindow window(sf::VideoMode(800,800), "High noon showdown", sf::Style::Close | sf::Style::Titlebar);
sf::Texture p1texture;
p1texture.loadFromFile("2nd hns bandit.png");
sf::ConvexShape p1;
p1.setPointCount(3);
p1.setTexture(&p1texture);
//points for player 1
p1.setPoint(0, sf::Vector2f(70.0f, 380.0f));
p1.setPoint(1, sf::Vector2f(30.0f, 380.0f));
p1.setPoint(2, sf::Vector2f(30.0f, 310.0f));
//game loop
while(window.isOpen()) {
sf::Event evnt;
while(window.pollEvent(evnt)) {
switch(evnt.type){
case sf::Event::Closed:
window.close();
break;
}
}
window.clear(sf::Color(210,180,140,100));
window.draw(p1);
window.display();
}
return 0;
}

Related

Detecting if Voxel or voxel group is still connected to rest of object

So I am building a voxel-based physics simulator in which voxels can be destroyed. Every voxelized object has a kind of "center voxel" to describe it, ill call it "peace A". All voxels are simulated as one until they are separated from "peace A" or another voxel attached to it, then they(and/or other voxels connected to that voxel) get put into a new object with its own simulated physics. And here lies my problem, How Do I check if the voxel is still attached? in the most efficient way possible? pathfinding sounds like it would slow down allot when I scale up but happy to try and figure that out if its the best option. and updating all voxels at once when one voxel is destroyed doesn't sound too good either. Any of you geniuses have any ideas?
here are some drawings for clarity(ps please excuse my bad mouse-handwriting)
first image, with voxels still connected:
second image, when the voxels separate:
Segmentation/labeling is the way (similar to raster A* and flood fill).
for each voxel add a flag variable/space
this flag will be used to tell if voxel is used or not ... and can be used latter as a temp value...
clear all flags to zero and set actual object ID=1.
pick first voxel with flag=0
flood fill it with actual object ID
so using 6 or 26 connectivity (analogy to 4 or 8 connectivity in 2D) flood fill the voxel flags with ID.
increment ID and goto #3
stop when there are no more voxels with flag=0
After this the flag holds the sub object ID your original object is split into and ID holds the count of your new objects+1.
[edit1] C++/VCL/OpenGL example
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
#include "gl_simple.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
const int n=16; // voxel map resolution
bool map[n][n][n]; // voxel map
int flg[n][n][n]; // (flag)
int pal[]= // 0xAABBGGRR
{
0x007F0000,
0x00007F00,
0x0000007F,
0x00007F7F,
0x007F007F,
0x007F7F00,
0x00FF0000,
0x0000FF00,
0x000000FF,
0x0000FFFF,
0x00FF00FF,
0x00FFFF00,
};
const int pals=sizeof(pal)/sizeof(pals);
//---------------------------------------------------------------------------
void fill(int x,int y,int z,int id)
{
// inside map check
if ((x<0)||(x>=n)) return;
if ((y<0)||(y>=n)) return;
if ((z<0)||(z>=n)) return;
// is it active voxel?
if (!map[x][y][z]) return;
// already filled with the same id?
if (flg[x][y][z]==id) return;
// set flag
flg[x][y][z]=id;
// fill neighbors
fill(x-1,y,z,id);
fill(x+1,y,z,id);
fill(x,y-1,z,id);
fill(x,y+1,z,id);
fill(x,y,z-1,id);
fill(x,y,z+1,id);
fill(x-1,y-1,z,id);
fill(x-1,y+1,z,id);
fill(x+1,y-1,z,id);
fill(x+1,y+1,z,id);
fill(x-1,y,z-1,id);
fill(x-1,y,z+1,id);
fill(x+1,y,z-1,id);
fill(x+1,y,z+1,id);
fill(x,y-1,z-1,id);
fill(x,y-1,z+1,id);
fill(x,y+1,z-1,id);
fill(x,y+1,z+1,id);
fill(x-1,y-1,z-1,id);
fill(x-1,y-1,z+1,id);
fill(x-1,y+1,z-1,id);
fill(x-1,y+1,z+1,id);
fill(x+1,y-1,z-1,id);
fill(x+1,y-1,z+1,id);
fill(x+1,y+1,z-1,id);
fill(x+1,y+1,z+1,id);
}
//---------------------------------------------------------------------------
void recolor()
{
int x,y,z,id;
// clear all flags to zero and set actual object ID=1
id=1;
for (x=0;x<n;x++)
for (y=0;y<n;y++)
for (z=0;z<n;z++)
flg[x][y][z]=0;
// pick first voxel with flag=0
for (x=0;x<n;x++)
for (y=0;y<n;y++)
for (z=0;z<n;z++)
if (map[x][y][z])
if (flg[x][y][z]==0)
{
// flood fill it with actual object ID
fill(x,y,z,id);
// increment ID and goto #3
id++;
}
}
//---------------------------------------------------------------------------
void TForm1::draw()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_COLOR_MATERIAL);
// center the view around map[][][]
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0,0.0,-80.0);
glRotatef( 15.0,1.0,0.0,0.0);
glTranslatef(-n,-n,-n);
// render map[][][] as cubes (very slow old api version for simplicity)
int x,y,z,i;
for (x=0;x<n;x++)
for (y=0;y<n;y++)
for (z=0;z<n;z++)
if (map[x][y][z])
{
glPushMatrix();
glTranslatef(x+x,y+y,z+z);
glColor4ubv((BYTE*)&(pal[flg[x][y][z]%pals]));
glBegin(GL_QUADS);
for (i=0;i<3*24;i+=3)
{
glNormal3fv(vao_nor+i);
glVertex3fv(vao_pos+i);
}
glEnd();
glPopMatrix();
}
glFlush();
SwapBuffers(hdc);
}
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner)
{
gl_init(Handle);
// init map[][][]
int x,y,z,i0=2,i1=n-i0-1,xx,yy,zz;
for (x=0;x<n;x++)
for (y=0;y<n;y++)
for (z=0;z<n;z++)
{
// clear map
map[x][y][z]=false;
// cube edges
if (((x>=i0)&&(x<=i1))&&((y==i0)||(y==i1))&&((z==i0)||(z==i1))) map[x][y][z]=true;
if (((y>=i0)&&(y<=i1))&&((x==i0)||(x==i1))&&((z==i0)||(z==i1))) map[x][y][z]=true;
if (((z>=i0)&&(z<=i1))&&((x==i0)||(x==i1))&&((y==i0)||(y==i1))) map[x][y][z]=true;
// ball
xx=x-8; xx*=xx;
yy=y-8; yy*=yy;
zz=z-8; zz*=zz;
if (xx+yy+zz<=16) map[x][y][z]=true;
// X
if ((y==i0)&&(x== z )&&(x>=4)&&(x<12)) map[x][y][z]=true;
if ((y==i0)&&(x==n-z-1)&&(x>=4)&&(x<12)) map[x][y][z]=true;
}
recolor();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
gl_exit();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormResize(TObject *Sender)
{
gl_resize(ClientWidth,ClientHeight);
draw();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormPaint(TObject *Sender)
{
draw();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
draw();
}
//---------------------------------------------------------------------------
You can ignore the VCL stuff and also the OpenGL rendering The only important stuff is on the top of the code up to (including) function void recolor(); The map holds the individual voxels of our input map (hardcoded in my apps constructor with few objects). The flg array holds the id of object the corresponding voxel was labeled with (enumerated) and its used later for coloring each object with different color from the palette pal[]. To keep this as simple as I could I did not do any optimization (the fill and render are very slow because of that and can be optimized a lot).
Here preview (after calling the recolor()):
As you can see all the voxels connected share the same color which means they have the same id number in flg array (belong to same object) so the algo and code works as expected.
In case you want to use this the gl_simple.h is in here:
complete GL+GLSL+VAO/VBO C++ example
so you just need to port the VCL events into your environment style...
Pick a random, not connected, object
Recursively get the up/down/left/right object till there is no left (always checking if the object is already connected)
If there are no objects left in the scene that are not connected, stop
Go to Step 1

Boost Geometry Matrix Transformations on Polygons

Are there any examples of matrix transformations on polygons (cartesian), using Boost Geometry? I am defining the matrix with simple std::vectors.
Also, I could only find 1 example of matrix_transformers using ublas but it's way too convoluted for a simple matrix transformation. If this is the only way though, I'll stick with it, but it would be great to have other options, ad do this with std::vector instead of ublas::matrix.
Here's my solution for anyone who might be interested. Boost geometry actually added a strategy called matrix_transformer that relies on Boost's qvm::mat for matrix transformations. There's not that many examples out there, so here's my code:
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>
using namespace boost::geometry::strategy::transform;
typedef boost::geometry::model::d2::point_xy<double> point_2f;
typedef boost::geometry::model::polygon<point_2f> polygon_2f;
int main() {
polygon_2f pol;
boost::geometry::read_wkt("POLYGON((10 10,10 27,24 22,22 10,10 10))", pol);
polygon_2f polTrans;
// Set the rotation angle (in radians)
double angleDeg = 45;
double angleRad = angleDeg * 3.14159 / 180.0;
vector<vector<double> > mat = {{cos(angleRad), sin(angleRad), 0}, {-sin(angleRad), cos(angleRad), 0}, {0, 0, 1}};
// Create the matrix_trasformer for a simple rotation matrix
matrix_transformer<double, 2, 2> rotation(mat[0][0], mat[0][1], mat[0][2], mat[1][0], mat[1][1], mat[1][2], mat[2][0], mat[2][1], mat[2][2]);
// Apply the matrix_transformer
boost::geometry::transform(pol, polTrans, rotation);
// Create svg file to show results
std::ofstream svg("transformationExample.svg");
boost::geometry::svg_mapper<point_2f> mapper(svg, 400, 400);
mapper.add(pol);
mapper.map(pol, "fill-opacity:0.5;fill:rgb(153,204,0);stroke:rgb(153,204,0);stroke-width:2");
mapper.add(polTrans);
mapper.map(polTrans, "fill-opacity:0.5;fill:rgb(153,204,255);stroke:rgb(153,204,255);stroke-width:2");
return 0;
}
And here's my result, where the green polygon is the original and the blue polygon is transformed (remember that the rotation was about the origin):

Mathematically producing sphere-shaped hexagonal grid

I am trying to create a shape similar to this, hexagons with 12 pentagons, at an arbitrary size.
(Image Source)
The only thing is, I have absolutely no idea what kind of code would be needed to generate it!
The goal is to be able to take a point in 3D space and convert it to a position coordinate on the grid, or vice versa and take a grid position and get the relevant vertices for drawing the mesh.
I don't even know how one would store the grid positions for this. Does each "triagle section" between 3 pentagons get their own set of 2D coordinates?
I will most likely be using C# for this, but I am more interested in which algorithms to use for this and an explanation of how they would work, rather than someone just giving me a piece of code.
The shape you have is one of so called "Goldberg polyhedra", is also a geodesic polyhedra.
The (rather elegant) algorithm to generate this (and many many more) can be succinctly encoded in something called a Conway Polyhedron Notation.
The construction is easy to follow step by step, you can click the images below to get a live preview.
The polyhedron you are looking for can be generated from an icosahedron -- Initialise a mesh with an icosahedron.
We apply a "Truncate" operation (Conway notation t) to the mesh (the sperical mapping of this one is a football).
We apply the "Dual" operator (Conway notation d).
We apply a "Truncate" operation again. At this point the recipe is tdtI (read from right!). You can already see where this is going.
Apply steps 3 & 4 repeatedly until you are satisfied.
For example below is the mesh for dtdtdtdtI.
This is quite easy to implement. I would suggest using a datastructure that makes it easy to traverse the neighbourhood give a vertex, edge etc. such as winged-edge or half-edge datastructures for your mesh. You only need to implement truncate and dual operators for the shape you are looking for.
First some analysis of the image in the question: the spherical triangle spanned by neighbouring pentagon centers seems to be equilateral. When five equilateral triangles meet in one corner and cover the whole sphere, this can only be the configuration induced by a icosahedron. So there are 12 pentagons and 20 patches of a triangular cutout of a hexongal mesh mapped to the sphere.
So this is a way to construct such a hexagonal grid on the sphere:
Create triangular cutout of hexagonal grid: a fixed triangle (I chose (-0.5,0),(0.5,0),(0,sqrt(3)/2) ) gets superimposed a hexagonal grid with desired resolution n s.t. the triangle corners coincide with hexagon centers, see the examples for n = 0,1,2,20:
Compute corners of icosahedron and define the 20 triangular faces of it (see code below). The corners of the icosahedron define the centers of the pentagons, the faces of the icosahedron define the patches of the mapped hexagonal grids. (The icosahedron gives the finest regular division of the sphere surface into triangles, i.e. a division into congruent equilateral triangles. Other such divisions can be derived from a tetrahedron or an octahedron; then at the corners of the triangles one will have triangles or squares, resp. Furthermore the fewer and bigger triangles would make the inevitable distortion in any mapping of a planar mesh onto a curved surface more visible. So choosing the icosahedron as a basis for the triangular patches helps minimizing the distortion of the hexagons.)
Map triangular cutout of hexagonal grid to spherical triangles corresponding to icosaeder faces: a double-slerp based on barycentric coordinates does the trick. Below is an illustration of the mapping of a triangular cutout of a hexagonal grid with resolution n = 10 onto one spherical triangle (defined by one face of an icosaeder), and an illustration of mapping the grid onto all these spherical triangles covering the whole sphere (different colors for different mappings):
Here is Python code to generate the corners (coordinates) and triangles (point indices) of an icosahedron:
from math import sin,cos,acos,sqrt,pi
s,c = 2/sqrt(5),1/sqrt(5)
topPoints = [(0,0,1)] + [(s*cos(i*2*pi/5.), s*sin(i*2*pi/5.), c) for i in range(5)]
bottomPoints = [(-x,y,-z) for (x,y,z) in topPoints]
icoPoints = topPoints + bottomPoints
icoTriangs = [(0,i+1,(i+1)%5+1) for i in range(5)] +\
[(6,i+7,(i+1)%5+7) for i in range(5)] +\
[(i+1,(i+1)%5+1,(7-i)%5+7) for i in range(5)] +\
[(i+1,(7-i)%5+7,(8-i)%5+7) for i in range(5)]
And here is the Python code to map (points of) the fixed triangle to a spherical triangle using a double slerp:
# barycentric coords for triangle (-0.5,0),(0.5,0),(0,sqrt(3)/2)
def barycentricCoords(p):
x,y = p
# l3*sqrt(3)/2 = y
l3 = y*2./sqrt(3.)
# l1 + l2 + l3 = 1
# 0.5*(l2 - l1) = x
l2 = x + 0.5*(1 - l3)
l1 = 1 - l2 - l3
return l1,l2,l3
from math import atan2
def scalProd(p1,p2):
return sum([p1[i]*p2[i] for i in range(len(p1))])
# uniform interpolation of arc defined by p0, p1 (around origin)
# t=0 -> p0, t=1 -> p1
def slerp(p0,p1,t):
assert abs(scalProd(p0,p0) - scalProd(p1,p1)) < 1e-7
ang0Cos = scalProd(p0,p1)/scalProd(p0,p0)
ang0Sin = sqrt(1 - ang0Cos*ang0Cos)
ang0 = atan2(ang0Sin,ang0Cos)
l0 = sin((1-t)*ang0)
l1 = sin(t *ang0)
return tuple([(l0*p0[i] + l1*p1[i])/ang0Sin for i in range(len(p0))])
# map 2D point p to spherical triangle s1,s2,s3 (3D vectors of equal length)
def mapGridpoint2Sphere(p,s1,s2,s3):
l1,l2,l3 = barycentricCoords(p)
if abs(l3-1) < 1e-10: return s3
l2s = l2/(l1+l2)
p12 = slerp(s1,s2,l2s)
return slerp(p12,s3,l3)
[Complete re-edit 18.10.2017]
the geometry storage is on you. Either you store it in some kind of Mesh or you generate it on the fly. I prefer to store it. In form of 2 tables. One holding all the vertexes (no duplicates) and the other holding 6 indexes of used points per each hex you got and some aditional info like spherical position to ease up the post processing.
Now how to generate this:
create hex triangle
the size should be radius of your sphere. do not include the corner hexess and also skip last line of the triangle (on both radial and axial so there is 1 hex gap between neighbor triangles on sphere) as that would overlap when joining out triangle segments.
convert 60deg hexagon triangle to 72deg pie
so simply convert to polar coordiantes (radius,angle), center triangle around 0 deg. Then multiply radius by cos(angle)/cos(30); which will convert triangle into Pie. And then rescale angle with ratio 72/60. That will make our triangle joinable...
copy&rotate triangle to fill 5 segments of pentagon
easy just rotate the points of first triangle and store as new one.
compute z
based on this Hexagonal tilling of hemi-sphere you can convert distance in 2D map into arc-length to limit the distortions as much a s possible.
However when I tried it (example below) the hexagons are a bit distorted so the depth and scaling needs some tweaking. Or post processing latter.
copy the half sphere to form a sphere
simply copy the points/hexes and negate z axis (or rotate by 180 deg if you want to preserve winding).
add equator and all of the missing pentagons and hexes
You should use the coordinates of the neighboring hexes so no more distortion and overlaps are added to the grid. Here preview:
Blue is starting triangle. Darker blue are its copies. Red are pole pentagons. Dark green is the equator, Lighter green are the join lines between triangles. In Yellowish are the missing equator hexagons near Dark Orange pentagons.
Here simple C++ OpenGL example (made from the linked answer in #4):
//$$---- Form CPP ----
//---------------------------------------------------------------------------
#include <vcl.h>
#include <math.h>
#pragma hdrstop
#include "win_main.h"
#include "gl/OpenGL3D_double.cpp"
#include "PolyLine.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TMain *Main;
OpenGLscreen scr;
bool _redraw=true;
double animx= 0.0,danimx=0.0;
double animy= 0.0,danimy=0.0;
//---------------------------------------------------------------------------
PointTab pnt; // (x,y,z)
struct _hexagon
{
int ix[6]; // index of 6 points, last point duplicate for pentagon
int a,b; // spherical coordinate
DWORD col; // color
// inline
_hexagon() {}
_hexagon(_hexagon& a) { *this=a; }
~_hexagon() {}
_hexagon* operator = (const _hexagon *a) { *this=*a; return this; }
//_hexagon* operator = (const _hexagon &a) { ...copy... return this; }
};
List<_hexagon> hex;
//---------------------------------------------------------------------------
// https://stackoverflow.com/a/46787885/2521214
//---------------------------------------------------------------------------
void hex_sphere(int N,double R)
{
const double c=cos(60.0*deg);
const double s=sin(60.0*deg);
const double sy= R/(N+N-2);
const double sz=sy/s;
const double sx=sz*c;
const double sz2=0.5*sz;
const int na=5*(N-2);
const int nb= N;
const int b0= N;
double *q,p[3],ang,len,l,l0,ll;
int i,j,n,a,b,ix;
_hexagon h,*ph;
hex.allocate(na*nb);
hex.num=0;
pnt.reset3D(N*N);
b=0; a=0; ix=0;
// generate triangle hex grid
h.col=0x00804000;
for (b=1;b<N-1;b++) // skip first line b=0
for (a=1;a<b;a++) // skip first and last line
{
p[0]=double(a )*(sx+sz);
p[1]=double(b-(a>>1))*(sy*2.0);
p[2]=0.0;
if (int(a&1)!=0) p[1]-=sy;
ix=pnt.add(p[0]+sz2+sx,p[1] ,p[2]); h.ix[0]=ix; // 2 1
ix=pnt.add(p[0]+sz2 ,p[1]+sy,p[2]); h.ix[1]=ix; // 3 0
ix=pnt.add(p[0]-sz2 ,p[1]+sy,p[2]); h.ix[2]=ix; // 4 5
ix=pnt.add(p[0]-sz2-sx,p[1] ,p[2]); h.ix[3]=ix;
ix=pnt.add(p[0]-sz2 ,p[1]-sy,p[2]); h.ix[4]=ix;
ix=pnt.add(p[0]+sz2 ,p[1]-sy,p[2]); h.ix[5]=ix;
h.a=a;
h.b=N-1-b;
hex.add(h);
} n=hex.num; // remember number of hexs for the first triangle
// distort points to match area
for (ix=0;ix<pnt.nn;ix+=3)
{
// point pointer
q=pnt.pnt.dat+ix;
// convert to polar coordinates
ang=atan2(q[1],q[0]);
len=vector_len(q);
// match area of pentagon (72deg) triangle as we got hexagon (60deg) triangle
ang-=60.0*deg; // rotate so center of generated triangle is angle 0deg
while (ang>+60.0*deg) ang-=pi2;
while (ang<-60.0*deg) ang+=pi2;
len*=cos(ang)/cos(30.0*deg); // scale radius so triangle converts to pie
ang*=72.0/60.0; // scale up angle so rotated triangles merge
// convert back to cartesian
q[0]=len*cos(ang);
q[1]=len*sin(ang);
}
// copy and rotate the triangle to cover pentagon
h.col=0x00404000;
for (ang=72.0*deg,a=1;a<5;a++,ang+=72.0*deg)
for (ph=hex.dat,i=0;i<n;i++,ph++)
{
for (j=0;j<6;j++)
{
vector_copy(p,pnt.pnt.dat+ph->ix[j]);
rotate2d(-ang,p[0],p[1]);
h.ix[j]=pnt.add(p[0],p[1],p[2]);
}
h.a=ph->a+(a*(N-2));
h.b=ph->b;
hex.add(h);
}
// compute z
for (q=pnt.pnt.dat,ix=0;ix<pnt.nn;ix+=pnt.dn,q+=pnt.dn)
{
q[2]=0.0;
ang=vector_len(q)*0.5*pi/R;
q[2]=R*cos(ang);
ll=fabs(R*sin(ang)/sqrt((q[0]*q[0])+(q[1]*q[1])));
q[0]*=ll;
q[1]*=ll;
}
// copy and mirror the other half-sphere
n=hex.num;
for (ph=hex.dat,i=0;i<n;i++,ph++)
{
for (j=0;j<6;j++)
{
vector_copy(p,pnt.pnt.dat+ph->ix[j]);
p[2]=-p[2];
h.ix[j]=pnt.add(p[0],p[1],p[2]);
}
h.a= ph->a;
h.b=-ph->b;
hex.add(h);
}
// create index search table
int i0,i1,j0,j1,a0,a1,ii[5];
int **ab=new int*[na];
for (a=0;a<na;a++)
{
ab[a]=new int[nb+nb+1];
for (b=-nb;b<=nb;b++) ab[a][b0+b]=-1;
}
n=hex.num;
for (ph=hex.dat,i=0;i<n;i++,ph++) ab[ph->a][b0+ph->b]=i;
// add join ring
h.col=0x00408000;
for (a=0;a<na;a++)
{
h.a=a;
h.b=0;
a0=a;
a1=a+1; if (a1>=na) a1-=na;
i0=ab[a0][b0+1];
i1=ab[a1][b0+1];
j0=ab[a0][b0-1];
j1=ab[a1][b0-1];
if ((i0>=0)&&(i1>=0))
if ((j0>=0)&&(j1>=0))
{
h.ix[0]=hex[i1].ix[1];
h.ix[1]=hex[i0].ix[0];
h.ix[2]=hex[i0].ix[1];
h.ix[3]=hex[j0].ix[1];
h.ix[4]=hex[j0].ix[0];
h.ix[5]=hex[j1].ix[1];
hex.add(h);
ab[h.a][b0+h.b]=hex.num-1;
}
}
// add 2x5 join lines
h.col=0x00008040;
for (a=0;a<na;a+=N-2)
for (b=1;b<N-3;b++)
{
// +b hemisphere
h.a= a;
h.b=+b;
a0=a-b; if (a0< 0) a0+=na; i0=ab[a0][b0+b+0];
a0--; if (a0< 0) a0+=na; i1=ab[a0][b0+b+1];
a1=a+1; if (a1>=na) a1-=na; j0=ab[a1][b0+b+0];
j1=ab[a1][b0+b+1];
if ((i0>=0)&&(i1>=0))
if ((j0>=0)&&(j1>=0))
{
h.ix[0]=hex[i0].ix[5];
h.ix[1]=hex[i0].ix[4];
h.ix[2]=hex[i1].ix[5];
h.ix[3]=hex[j1].ix[3];
h.ix[4]=hex[j0].ix[4];
h.ix[5]=hex[j0].ix[3];
hex.add(h);
}
// -b hemisphere
h.a= a;
h.b=-b;
a0=a-b; if (a0< 0) a0+=na; i0=ab[a0][b0-b+0];
a0--; if (a0< 0) a0+=na; i1=ab[a0][b0-b-1];
a1=a+1; if (a1>=na) a1-=na; j0=ab[a1][b0-b+0];
j1=ab[a1][b0-b-1];
if ((i0>=0)&&(i1>=0))
if ((j0>=0)&&(j1>=0))
{
h.ix[0]=hex[i0].ix[5];
h.ix[1]=hex[i0].ix[4];
h.ix[2]=hex[i1].ix[5];
h.ix[3]=hex[j1].ix[3];
h.ix[4]=hex[j0].ix[4];
h.ix[5]=hex[j0].ix[3];
hex.add(h);
}
}
// add pentagons at poles
_hexagon h0,h1;
h0.col=0x00000080;
h0.a=0; h0.b=N-1; h1=h0; h1.b=-h1.b;
p[2]=sqrt((R*R)-(sz*sz));
for (ang=0.0,a=0;a<5;a++,ang+=72.0*deg)
{
p[0]=2.0*sz*cos(ang);
p[1]=2.0*sz*sin(ang);
h0.ix[a]=pnt.add(p[0],p[1],+p[2]);
h1.ix[a]=pnt.add(p[0],p[1],-p[2]);
}
h0.ix[5]=h0.ix[4]; hex.add(h0);
h1.ix[5]=h1.ix[4]; hex.add(h1);
// add 5 missing hexagons at poles
h.col=0x00600060;
for (ph=&h0,b=N-3,h.b=N-2,i=0;i<2;i++,b=-b,ph=&h1,h.b=-h.b)
{
a = 1; if (a>=na) a-=na; ii[0]=ab[a][b0+b];
a+=N-2; if (a>=na) a-=na; ii[1]=ab[a][b0+b];
a+=N-2; if (a>=na) a-=na; ii[2]=ab[a][b0+b];
a+=N-2; if (a>=na) a-=na; ii[3]=ab[a][b0+b];
a+=N-2; if (a>=na) a-=na; ii[4]=ab[a][b0+b];
for (j=0;j<5;j++)
{
h.a=((4+j)%5)*(N-2)+1;
h.ix[0]=ph->ix[ (5-j)%5 ];
h.ix[1]=ph->ix[ (6-j)%5 ];
h.ix[2]=hex[ii[(j+4)%5]].ix[4];
h.ix[3]=hex[ii[(j+4)%5]].ix[5];
h.ix[4]=hex[ii[ j ]].ix[3];
h.ix[5]=hex[ii[ j ]].ix[4];
hex.add(h);
}
}
// add 2*5 pentagons and 2*5 missing hexagons at equator
h0.a=0; h0.b=N-1; h1=h0; h1.b=-h1.b;
for (ang=36.0*deg,a=0;a<na;a+=N-2,ang-=72.0*deg)
{
p[0]=R*cos(ang);
p[1]=R*sin(ang);
p[2]=sz;
i0=pnt.add(p[0],p[1],+p[2]);
i1=pnt.add(p[0],p[1],-p[2]);
a0=a-1;if (a0< 0) a0+=na;
a1=a+1;if (a1>=na) a1-=na;
ii[0]=ab[a0][b0-1]; ii[2]=ab[a1][b0-1];
ii[1]=ab[a0][b0+1]; ii[3]=ab[a1][b0+1];
// hexagons
h.col=0x00008080;
h.a=a; h.b=0;
h.ix[0]=hex[ii[0]].ix[0];
h.ix[1]=hex[ii[0]].ix[1];
h.ix[2]=hex[ii[1]].ix[1];
h.ix[3]=hex[ii[1]].ix[0];
h.ix[4]=i0;
h.ix[5]=i1;
hex.add(h);
h.a=a; h.b=0;
h.ix[0]=hex[ii[2]].ix[2];
h.ix[1]=hex[ii[2]].ix[1];
h.ix[2]=hex[ii[3]].ix[1];
h.ix[3]=hex[ii[3]].ix[2];
h.ix[4]=i0;
h.ix[5]=i1;
hex.add(h);
// pentagons
h.col=0x000040A0;
h.a=a; h.b=0;
h.ix[0]=hex[ii[0]].ix[0];
h.ix[1]=hex[ii[0]].ix[5];
h.ix[2]=hex[ii[2]].ix[3];
h.ix[3]=hex[ii[2]].ix[2];
h.ix[4]=i1;
h.ix[5]=i1;
hex.add(h);
h.a=a; h.b=0;
h.ix[0]=hex[ii[1]].ix[0];
h.ix[1]=hex[ii[1]].ix[5];
h.ix[2]=hex[ii[3]].ix[3];
h.ix[3]=hex[ii[3]].ix[2];
h.ix[4]=i0;
h.ix[5]=i0;
hex.add(h);
}
// release index search table
for (a=0;a<na;a++) delete[] ab[a];
delete[] ab;
}
//---------------------------------------------------------------------------
void hex_draw(GLuint style) // draw hex
{
int i,j;
_hexagon *h;
for (h=hex.dat,i=0;i<hex.num;i++,h++)
{
if (style==GL_POLYGON) glColor4ubv((BYTE*)&h->col);
glBegin(style);
for (j=0;j<6;j++) glVertex3dv(pnt.pnt.dat+h->ix[j]);
glEnd();
}
if (0)
if (style==GL_POLYGON)
{
scr.text_init_pixel(0.1,-0.2);
glColor3f(1.0,1.0,1.0);
for (h=hex.dat,i=0;i<hex.num;i++,h++)
if (abs(h->b)<2)
{
double p[3];
vector_ld(p,0.0,0.0,0.0);
for (j=0;j<6;j++)
vector_add(p,p,pnt.pnt.dat+h->ix[j]);
vector_mul(p,p,1.0/6.0);
scr.text(p[0],p[1],p[2],AnsiString().sprintf("%i,%i",h->a,h->b));
}
scr.text_exit_pixel();
}
}
//---------------------------------------------------------------------------
void TMain::draw()
{
scr.cls();
int x,y;
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0,0.0,-5.0);
glRotated(animx,1.0,0.0,0.0);
glRotated(animy,0.0,1.0,0.0);
hex_draw(GL_POLYGON);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0,0.0,-5.0+0.01);
glRotated(animx,1.0,0.0,0.0);
glRotated(animy,0.0,1.0,0.0);
glColor3f(1.0,1.0,1.0);
glLineWidth(2);
hex_draw(GL_LINE_LOOP);
glCirclexy(0.0,0.0,0.0,1.5);
glLineWidth(1);
scr.exe();
scr.rfs();
}
//---------------------------------------------------------------------------
__fastcall TMain::TMain(TComponent* Owner) : TForm(Owner)
{
scr.init(this);
hex_sphere(10,1.5);
_redraw=true;
}
//---------------------------------------------------------------------------
void __fastcall TMain::FormDestroy(TObject *Sender)
{
scr.exit();
}
//---------------------------------------------------------------------------
void __fastcall TMain::FormPaint(TObject *Sender)
{
_redraw=true;
}
//---------------------------------------------------------------------------
void __fastcall TMain::FormResize(TObject *Sender)
{
scr.resize();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60,float(scr.xs)/float(scr.ys),0.1,100.0);
_redraw=true;
}
//-----------------------------------------------------------------------
void __fastcall TMain::Timer1Timer(TObject *Sender)
{
animx+=danimx; if (animx>=360.0) animx-=360.0; _redraw=true;
animy+=danimy; if (animy>=360.0) animy-=360.0; _redraw=true;
if (_redraw) { draw(); _redraw=false; }
}
//---------------------------------------------------------------------------
void __fastcall TMain::FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift)
{
Caption=Key;
if (Key==40){ animx+=2.0; _redraw=true; }
if (Key==38){ animx-=2.0; _redraw=true; }
if (Key==39){ animy+=2.0; _redraw=true; }
if (Key==37){ animy-=2.0; _redraw=true; }
}
//---------------------------------------------------------------------------
I know it is a bit of a index mess and also winding rule is not guaranteed as I was too lazy to made uniform indexing. Beware the a indexes of each hex are not linear and if you want to use them to map to 2D map you would need to recompute it using atan2 on x,y of its center point position.
Here previews:
Still some distortions are present. They are caused by fact that we using 5 triangles to connect at equator (so connection is guaranteed). That means the circumference is 5*R instead of 6.28*R. How ever this can be still improved by a field simulation. Just take all the points and add retractive forces based on their distance and bound to sphere surface. Run simulation and when the oscillations lower below threshold you got your sphere grid ...
Another option would be find out some equation to remap the grid points (similarly what I done for triangle to pie conversion) that would have better results.

Algorithm: How to disperse smaller spheres into a direction within a large sphere

I am trying to write a C source code visualization program which I expect to draw out function hierarchy using spheres inside spheres.
For a simple example, in code like this:
#include "stdio.h"
int pow(int base, int power) {
while(--power) {
base*=base;
}
return base;
}
int checkOdd(int i) {
if (i%2==0) return 0;
else return 1;
}
int checkPrime(int i) {
int j = i;
if (!checkOdd(i)) {
return 0;
}
for(j=1; j<i/2; j++) {
if (i%j==0) {
return 0;
}
}
return 1;
}
int main() {
int a = 3;
int b = 2;
int res = pow(a,b);
int bl = checkPrime(res);
printf("%d",res);
return 1;
}
The largest sphere which is the main function has two functions inside it, pow and checkPrime, which are two spheres inside main's sphere. Checkprime function's sphere has checkOdd's sphere in it.
I would like it so that the children spheres are somewhat clumped together in one side of the larger sphere, because I would like some space left out for putting in other things. However, the spheres must not touch each other, and the radius of the spheres are pre-determined and can not change to accomodate drawing accurately. I need an algorithm which determines the perfect center coordinates which would allow the smaller spheres not to touch each other while still being collected to one side of the larger sphere.
I have a 3D vector which shows the direction at which the smaller spheres must be concentrated in, looking from the center of the larger sphere. In the case of the picture, my 3D vector is facing bottom-down in a 2D-sense looking at the screen.
Currently my algorithm produces this by dispersing the sphere's center around a circle projected onto the larger sphere's surface, but it fails as the spheres overlap. Can anyone enlighten me with a way to disperse smaller spheres to one direction within the larger sphere?
I am using OpenGL and I prepared a function which can draw those transparent mesh spheres by feeding center coordinate and radius. I have knowledge of parent sphere's center and radius in designing this algorithm.

Finding the distance between two photos of the ceiling using SIFT

I am currently writing a project that will allow robot to find its location depending on the photos of the ceiling. The camera is mounted on the robot and is facing the ceiling directly (meaning that the center of the photo is always consider to be the position of the robot). The idea is to establish 0,0 position and orientation of the x,y axis using the first photo and then finding the distance and rotation between that and the next photo (which will be taken in the slightly different position) and establish new 0,0 position and orientation of x,y axis and so on. I am finding the features on the photo using the following algorithm (so far on only one image):
#include <opencv/cv.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/nonfree/nonfree.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
Mat img = imread("ceiling.jpg");
if (img.empty())
{
cout << "Cannot load an image!" << endl;
getchar();
return -1;
}
SIFT sift(10); //number of keypoints
vector<KeyPoint> key_points;
Mat descriptors, mascara;
Mat output_img;
sift(img,mascara,key_points,descriptors);
drawKeypoints(img, key_points, output_img);
namedWindow("Image");
imshow("Image", output_img);
imwrite("image.jpg", output_img);
waitKey(0);
return 0;
}
Is there any function that could help me do that?
If the images are not far apart, optical flow could be a better option. Look for documentation on cv::calcOpticalFlowPyrLK for details on how to use this.

Resources