Directx C++ - Drawing DNA Shape - c++

In my current program I would like to be able to draw "DNA Shapes". I have written a "DrawPixel(x,y,r,g,b)" function which can draw a pixel on the screen. Moving on from this point I implemented the Bresenham line algorithm to draw a line as: "DrawLine(x1,y1,x2,y2,r,g,b)".
Now I realized that using an image for the DNA shapes would be a very bad choice (in multiple aspects). So I tried making a function to draw a DNA shape (As I couldn't find an algorithm). This is currently based on a circle drawing algorithm (Midpoint Circle Algorithm):
void D3DGHandler::DrawDNAShape(int x1, int y1, int length, int curves, int dir
int off, int r, int g, int b){
int x2Pos = sin(dir)*length+x1;
int y2Pos = cos(dir)*length+y1;
for (int i = 0; i < curves; i++) {
int xIncrease = (x2Pos / curves) * i;
int yIncrease = (y2Pos / curves) * i;
int rSquared = off * off;
int xPivot = (int)(off * 0.707107 + 0.5f);
for (int x = 0; x <= xPivot; x++) {
int y = (int)(sqrt((float)(rSquared - x*x)) + 0.5f);
DrawPixel(x1+x+xIncrease,y1+y+yIncrease,r,g,b);
DrawPixel(x1-x+xIncrease,y1+y+yIncrease,r,g,b);
DrawPixel(x1+x+xIncrease,y1-y+yIncrease,r,g,b);
DrawPixel(x1-x+xIncrease,y1-y+yIncrease,r,g,b);
DrawPixel(x1+y+xIncrease,y1+x+yIncrease,r,g,b);
DrawPixel(x1-y+xIncrease,y1+x+yIncrease,r,g,b);
DrawPixel(x1+y+xIncrease,y1-x+yIncrease,r,g,b);
DrawPixel(x1-y+xIncrease,y1-x+yIncrease,r,g,b);
}
}
}
This implementation is currently getting me some completely new functionality I was not looking for.
Along the lines of:
I would be very happy to hear any information you can give me!
Update
Expected result:
Expected Result
But then way more line-like.

You can draw two sinusoidal graphs with some offset will give you the required shape.
Eg. In R
x=(1:100)/10.0
plot(sin(x),x)
points(sin(x+2.5),x)

Related

Efficient Spline-Polygon rasterization

I am search for efficient algorithm and/or code to rasterize curved polygons. In best case such algorithm would support anti-aliasing with sub pixel accuracy. My goal is to understand and implement such algorithm in c++.
Point-In-Spline-Polygon Algorithm
Here is the code to detect if point is inside such curved polygon, and of course one could use brute-force to rasterize this, but it would be too slow.
Essentially I need fast c++ code to produce images presented in this article.
Brute force code would look something like this.
// draw a single pixel at x,y coordinates.
void draw_pixel(int x, int y, int coverage);
// slow code without anti-aliasing
void brute_force(int x_res, int y_res, double *poly) {
for(int y = 0; y < y_res; ++y) {
const double fy = double(y);
for(int x = 0; x < x_res; ++x) {
const double fx = double(x);
if (pointInSplinePoly(poly, fx, fy)) {
draw_pixel(x,y, 0xFF);
}
}
}
}
Here is slow code with 2x2 anti-aliasing.

How to aim the camera at the z-index of the cell in front of my character?

I've got a 3D terrain environment like so:
I'm trying to get the character (camera) to look up when climbing hills, and look down when descending, like climbing in real life.
This is what it's currently doing:
Right now the camera moves up and down the hills just fine, but I can't get the camera angle to work correctly. The only way I can think of aiming up or down depending on the terrain is getting the z-index of the cell my character is currently facing, and set that as the focus, but I really have no idea how to do that.
This is admittedly for an assignment, and we're intentionally not using objects so things are organized a little strangely.
Here's how I'm currently doing things:
const int M = 100; // width
const int N = 100; // height
double zHeights[M+1][N+1]; // 2D array containing the z-indexes of terrain cells
double gRX = 1.5; // x position of character
double gRY = 2.5; // y position of character
double gDirection = 45; // direction of character
double gRSpeed = 0.05; // move speed of character
double getZ(double x, double y) // returns the height of the current cell
{
double z = .5*sin(x*.25) + .4*sin(y*.15-.43);
z += sin(x*.45-.7) * cos(y*.315-.31)+.5;
z += sin(x*.15-.97) * sin(y*.35-8.31);
double amplitute = 5;
z *= amplitute;
return z;
}
void generateTerrain()
{
glBegin(GL_QUADS);
for (int i = 0; i <= M; i++)
{
for (int j = 0; j <= N; j++)
{
zHeights[i][j] = getZ(i,j);
}
}
}
void drawTerrain()
{
for (int i = 0; i < M; i++)
{
for (int j = 0; j < N; j++)
{
glColor3ub( (i*34525+j*5245)%256, (i*3456345+j*6757)%256, (i*98776+j*6554544)%256);
glVertex3d(i, j, getZ(i,j));
glVertex3d(i, j+1, getZ(i,j+1));
glVertex3d(i+1, j+1, getZ(i+1,j+1));
glVertex3d(i+1, j, getZ(i+1,j));
}
}
}
void display() // callback to glutDisplayFunc
{
glEnable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
double radians = gDirection /180.*3.141592654; // converts direction to radians
double z = getZ((int)gRX, (int)gRY); // casts as int to find z-index in zHeights[][]
double dx = cos(radians)*gRSpeed;
double dy = sin(radians)*gRSpeed;
double at_x = gRX + dx;
double at_y = gRY + dy;
double at_z = z; // source of problem, no idea what to do
gluLookAt(gRX, gRY, z + 2, // eye position
at_x, at_y, at_z + 2, // point to look at, also wrong
0, 0, 1); // up vector
drawTerrain();
glEnd();
}
void init()
{
generateTerrain();
}
Firstly, I don't see any reason to cast to int here:
double z = getZ((int)gRX, (int)gRY);
Just use the double values to get a smooth behavior.
Your basic approach is already pretty good. You take the current position (gRX, gRY), walk a bit in the viewing direction (dx, dy) and use that as the point to look at. There are just two small things that need adaptation:
double dx = cos(radians)*gRSpeed;
double dy = sin(radians)*gRSpeed;
Although multiplying by gRSpeed might be a good idea, in my opinion, this factor should not be related to the character's kinematics. Instead, this represents the smoothness of your view direction. Small values make the direction stick very closely to the terrain geometry, larger values smooth it out.
And finally, you need to evaluate the height at your look-at point:
double at_z = getZ(at_x, at_y);

Implementation of feature detection algorithm

I'm fairly new to programming and would like to know how to start implementing the following algorithm in C++,
Given a binary image where pixels with intensity 255 show edges and pixels with intensity 0 show the background, find line segments longer than n pixels in the image. t is a counter showing the number of iterations without finding a line, and tm is the maximum number of iterations allowed before exiting the program.
Let t=0.
Take two edge points randomly from the image and find equation of the line passing
through them.
Find m, the number of other edge points in the image that are within distance d pixels of
the line.
If m > n, go to Step 5.
Otherwise (m ≤ n), increment t by 1 and if t < tm go to Step 2, and
if t ≥ tm exit program.
Draw the line and remove the edge points falling within distance d pixels of it from the
image. Then, go to Step 1
Basically, I just want to randomly pick two points from the image, find the distance between them, and if that distance is too small, I would detect a line between them.
I would appreciate if a small code snippet is provided, to get me started.
this is more like a RANSAC parametric line detection. I would also keep this post updated if I get it done.
/* Display Routine */
#include "define.h"
ByteImage bimg; //A copy of the image to be viewed
int width, height; //Window dimensions
GLfloat zoomx = 1.0, zoomy = 1.0; //Pixel zoom
int win; //Window index
void resetViewer();
void reshape(int w, int h) {
glViewport(0, 0, (GLsizei)w, (GLsizei)h);
if ((w!=width) || (h!=height)) {
zoomx=(GLfloat)w/(GLfloat)bimg.nc;
zoomy=(GLfloat)h/(GLfloat)bimg.nr;
glPixelZoom(zoomx,zoomy);
}
width=w; height=h;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, (GLdouble)w, 0.0, (GLdouble)h);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void mouse(int button, int state, int x, int y) {
glutPostRedisplay();
if((button == GLUT_LEFT_BUTTON) && (state == GLUT_DOWN) &&
(zoomx==1.0) && (zoomy==1.0)){
printf(" row=%d, col=%d, int=%d.\n", y,x, (int)bimg.image[(bimg.nr-1-y)*bimg.nc+x]);
glutPostRedisplay();
}
}
void display() {
glClear(GL_COLOR_BUFFER_BIT);
glRasterPos2i(0, 0);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glDrawPixels((GLsizei)bimg.nc,(GLsizei)bimg.nr, GL_LUMINANCE,GL_UNSIGNED_BYTE, bimg.image);
glutSwapBuffers();
}
Let us assume you have an int[XDIMENSION][YDIMENSION]
Let t=0.
int t = 0; // ;-)
Take two edge points randomly from the image and find equation of the line passing through them.
Brute force: you could randomly search the image for points and re-search when they are not edge points
struct Point {
int x;
int y;
};
bool is_edge(Point a) {
return image[a.x][a.y] == 255;
}
int randomUpto(int upto) {
int r = rand() % upto;
return r;
}
, which needs the pseudo-random number generator to be initialized via
srand(time(NULL));
To find edge points
Point a;
do {
a.x = randomUpto(XDIMENSION);
a.y = randomUpto(YDIMENSION);
} while ( ! is_edge(a) );
Find m, the number of other edge points in the image that are within distance d pixels of the line.
You need the line between the points. Some searching yields this fine answer, which leads to
std::vector<Point> getLineBetween(Point a, Point b) {
double dx = b.x - a.x;
double dy = b.y - a.y;
double dist = sqrt(dx * dx + dy * dy);
dx /= dist;
dy /= dist;
std::vector<Point> points;
points.push_back(a);
for ( int i = 0 ; i < 2*dist; i++ ) {
Point tmp;
tmp.x = a.x + (int)(i * dx /2.0);
tmp.y = a.y + (int)(i * dy /2.0);
if ( tmp.x != points.back().x
|| tmp.y != points.back().y ) {
points.push_back(tmp);
}
}
return points;
}
Do you see a pattern here? Isolate the steps into substeps, ask google, look at the documentation, try out stuff until it works.
Your next steps might be to
create a distance function, euclidean should suffice
find all points next to line (or next to a point, which is easier) based on the distance function
Try out some and come back if you still need help.

why are Cubic Bezier functions not accurate compared too windows api PolyBezier?

I have been trying to find a way to draw a curved line/cubic bezier line using a custom function. However, all the examples and such found on the internet, differ a little from each other and usually produce different results, why? . None of the ones i have tried produce the same result as windows api PolyBezier which is what i need.
This is my current code for drawing cubic bezier lines:
double Factorial(int number)
{
double factorial = 1;
if (number > 1)
{
for (int count = 1; count <= number; count++) factorial = factorial * count;
}
return factorial;
}
double choose(double a, double b)
{
return Factorial(a) / (Factorial(b) * Factorial(a - b));
}
VOID MyPolyBezier(HDC hdc, PPOINT Pts, int Total)
{
float x, y;
MoveToEx(hdc, Pts[0].x, Pts[0].y, 0);
Total -= 1;
//for (float t = 0; t <= 1; t += (1./128.))
for (float t = 0; t <= 1; t += 0.0078125)
{
x = 0;
y = 0;
for (int I = 0; I <= Total; I++)
{
x += Pts[I].x * choose(Total, I) * pow(1 - t, Total - I) * pow(t, I);
y += Pts[I].y * choose(Total, I) * pow(1 - t, Total - I) * pow(t, I);
}
LineTo(hdc, x, y);
}
}
And here is the code for testing it.
POINT TestPts[4];
BYTE TestType[4] = {PT_MOVETO, PT_BEZIERTO, PT_BEZIERTO, PT_BEZIERTO};
//set x, y points for the curved line.
TestPts[0].x = 50;
TestPts[0].y = 200;
TestPts[1].x = 100;
TestPts[1].y = 100;
TestPts[2].x = 150;
TestPts[2].y = 200;
TestPts[3].x = 200;
TestPts[3].y = 200;
//Draw using custom function.
MyPolyBezier(hdc, TestPts, 4);
//Move the curve down some.
TestPts[0].y += 10;
TestPts[1].y += 10;
TestPts[2].y += 10;
TestPts[3].y += 10;
//Draw using windows api.
//PolyDraw(hdc, TestPts, TestType, 4); //PolyDraw gives the same result as PolyBezier.
PolyBezier(hdc, TestPts, 4);
And an attached image of my bad results:
Note: the bottom bezier line is windows(PolyBezier) version.
Edit:
the final goal, Windows(On the left) VS custom funtion. Hopefully this helps in some way.
So a cubic bezier is a mathematical curve. The cubic bezier is a specific case of a more general curve.
The cubic bezier is defined by 4 control points -- a start and end point, and 2 control points. In general, a bezier has n control points in order.
The line is drawn as a time parameter t goes from 0 to 1.
To find out where a general bezier of degree n is at time t:
For each adjacent pair of control points in your bezier, find the weighted average of them, as controlled by t. So at + b(1-t) for control points a before b.
Use these n-1 points to form a degree n-1 bezier.
Solve the new bezier at time t.
when you hit a degree 1 bezier, stop. That is your point.
Try writing an algorithm based off the true definition of bezier, and see where it differs from the windows curve. This may ne less frustrating than taking some approximation and having two sets of errors to reconcile.

Impact of cubic and catmull splines on image

I am trying to implement some function like below
For this I am trying to use Cubic interpolation and Catmull interpolation ( check both separately to compare the best result) , what i am not understanding is what impact these interpolation show on image and how we can get these points values where we clicked to set that curve ? and do we need to define the function these black points on the image separately ?
I am getting help from these resources
Source 1
Source 2
Approx the same focus
Edit
int main (int argc, const char** argv)
{
Mat input = imread ("E:\\img2.jpg");
for(int i=0 ; i<input.rows ; i++)
{
for (int p=0;p<input.cols;p++)
{
//for(int t=0; t<input.channels(); t++)
//{
input.at<cv::Vec3b>(i,p)[0] = 255*correction(input.at<cv::Vec3b>(i,p)[0]/255.0,ctrl,N); //B
input.at<cv::Vec3b>(i,p)[1] = 255*correction(input.at<cv::Vec3b>(i,p)[1]/255.0,ctrl,N); //G
input.at<cv::Vec3b>(i,p)[2] = 255*correction(input.at<cv::Vec3b>(i,p)[2]/255.0,ctrl,N); //R
//}
}
}
imshow("image" , input);
waitKey();
}
So if your control points are always on the same x coordinate
and linearly dispersed along whole range then you can do it like this:
//---------------------------------------------------------------------------
const int N=5; // number of control points (must be >= 4)
float ctrl[N]= // control points y values initiated with linear function y=x
{ // x value is index*1.0/(N-1)
0.00,
0.25,
0.50,
0.75,
1.00,
};
//---------------------------------------------------------------------------
float correction(float col,float *ctrl,int n)
{
float di=1.0/float(n-1);
int i0,i1,i2,i3;
float t,tt,ttt;
float a0,a1,a2,a3,d1,d2;
// find start control point
col*=float(n-1);
i1=col; col-=i1;
i0=i1-1; if (i0< 0) i0=0;
i2=i1+1; if (i2>=n) i2=n-1;
i3=i1+2; if (i3>=n) i3=n-1;
// compute interpolation coefficients
d1=0.5*(ctrl[i2]-ctrl[i0]);
d2=0.5*(ctrl[i3]-ctrl[i1]);
a0=ctrl[i1];
a1=d1;
a2=(3.0*(ctrl[i2]-ctrl[i1]))-(2.0*d1)-d2;
a3=d1+d2+(2.0*(-ctrl[i2]+ctrl[i1]));
// now interpolate new colro intensity
t=col; tt=t*t; ttt=tt*t;
t=a0+(a1*t)+(a2*tt)+(a3*ttt);
return t;
}
//---------------------------------------------------------------------------
It uses 4-point 1D interpolation cubic (from that link in my comment above) to get new color just do this:
new_col = correction(old_col,ctrl,N);
this is how it looks:
the green arrows shows derivation error (always only on start and end point of whole curve). It can be corrected by adding 2 more control points one before and one after all others ...
[Notes]
color range is < 0.0 , 1.0 > so if you need other then just multiply the result and divide the input ...
[edit1] the start/end derivations fixed a little
float correction(float col,float *ctrl,int n)
{
float di=1.0/float(n-1);
int i0,i1,i2,i3;
float t,tt,ttt;
float a0,a1,a2,a3,d1,d2;
// find start control point
col*=float(n-1);
i1=col; col-=i1;
i0=i1-1;
i2=i1+1; if (i2>=n) i2=n-1;
i3=i1+2;
// compute interpolation coefficients
if (i0>=0) d1=0.5*(ctrl[i2]-ctrl[i0]); else d1=ctrl[i2]-ctrl[i1];
if (i3< n) d2=0.5*(ctrl[i3]-ctrl[i1]); else d2=ctrl[i2]-ctrl[i1];
a0=ctrl[i1];
a1=d1;
a2=(3.0*(ctrl[i2]-ctrl[i1]))-(2.0*d1)-d2;
a3=d1+d2+(2.0*(-ctrl[i2]+ctrl[i1]));
// now interpolate new colro intensity
t=col; tt=t*t; ttt=tt*t;
t=a0+(a1*t)+(a2*tt)+(a3*ttt);
return t;
}
[edit2] just some clarification on the coefficients
they are all derived from this conditions:
y(t) = a0 + a1*t + a2*t*t + a3*t*t*t // direct value
y'(t) = a1 + 2*a2*t + 3*a3*t*t // first derivation
now you have points y0,y1,y2,y3 so I chose that y(0)=y1 and y(1)=y2 which gives c0 continuity (value is the same in the joint points between curves)
now I need c1 continuity so i add y'(0) must be the same as y'(1) from previous curve.
for y'(0) I choose avg direction between points y0,y1,y2
for y'(1) I choose avg direction between points y1,y2,y3
These are the same for the next/previous segments so it is enough. Now put it all together:
y(0) = y0 = a0 + a1*0 + a2*0*0 + a3*0*0*0
y(1) = y1 = a0 + a1*1 + a2*1*1 + a3*1*1*1
y'(0) = 0.5*(y2-y0) = a1 + 2*a2*0 + 3*a3*0*0
y'(1) = 0.5*(y3-y1) = a1 + 2*a2*1 + 3*a3*1*1
And solve this system of equtions (a0,a1,a2,a3 = ?). You will get what I have in source code above. If you need different properties of the curve then just make different equations ...
[edit3] usage
pic1=pic0; // copy source image to destination pic is mine image class ...
for (y=0;y<pic1.ys;y++) // go through all pixels
for (x=0;x<pic1.xs;x++)
{
float i;
// read, convert, write pixel
i=pic1.p[y][x].db[0]; i=255.0*correction(i/255.0,red control points,5); pic1.p[y][x].db[0]=i;
i=pic1.p[y][x].db[1]; i=255.0*correction(i/255.0,green control points,5); pic1.p[y][x].db[1]=i;
i=pic1.p[y][x].db[2]; i=255.0*correction(i/255.0,blue control points,5); pic1.p[y][x].db[2]=i;
}
On top there are control points per R,G,B. On bottom left is original image and on bottom right is corrected image.