can't get the archimedes spiral - opengl

I trying to draw spiral, but i get circle.
for(int i = 0 ; i < 121; i++)
{
for(int a = 0 ; a <= 3; a++)
{
if(a == 1){
vertires_chikl[d] = GLfloat(X + R * cos(t));
d++;
}
if(a == 2){
vertires_chikl[d] = GLfloat(Y + R * sin(t));
d++;
}
if(a == 3){
vertires_chikl[d] = GLfloat(0.0);
d++;
}
}
t = t+ 0.256f;
// we are moving in a circle
R = R + 0.00001f;
// circle shifted to the side (right and up)
// Y = Y+ 0.0001f;
// X = X+ 0.0001f;
}
why i do wrong ????
while I tried to change the function. As I remember when increasing the variable R there should be a growth and a change in the circumference. Doesn’t it happen why ???
matematik model i give there
afler uncommented R
afler 5 sec :3

thank tkausl.
the mistake was that global variable static float R = 0.4f; // Radius of circle.
i make this local
float R = 0.4f; // Radius of circle.
for(int i = 0 ; i < 121; i++)
{
for(int a = 0 ; a <= 3; a++)
{
if(a == 1){
vertires_chikl[d] = GLfloat(X + R * cos(t));
d++;
}
if(a == 2){
vertires_chikl[d] = GLfloat(Y + R * sin(t));
d++;
}
if(a == 3){
vertires_chikl[d] = GLfloat(0.0);
d++;
}
}
t = t+ 0.256f;
// we are moving in a circle
R = R + 0.004f;
// circle shifted to the side (right and up)
// Y = Y+ 0.0001f;
// X = X+ 0.0001f;
}
result

Related

Google kickstart 2021 L shaped plots cannot understand what is wrong here?

So here is the code I wrote for the question(https://codingcompetitions.withgoogle.com/kickstart/round/0000000000436140/000000000068c509#problem). For the sample input I am getting the right answer but it is not clearing test set 1.
I have created the code such that it checks for "1" up down right and left for each element of array and sees whether from that junction an L can be made.
For reference these are the conditions in the question:
"A segment is called "good" if all the cells in the segment contain only 1s.
An "L-shape" is defined as an unordered pair of segments, which has all the following properties:
Each of the segments must be a "good" segment.
The two segments must be perpendicular to each other.
The segments must share one cell that is an endpoint of both segments.
Segments must have length at least 2.
The length of the longer segment is twice the length of the shorter segment."
#include <bits/stdc++.h>
int main()
{
using namespace std;
int t, u;
cin >> t;
for (u = 1; u <= t; u++) {
int i, j, k, l = 0, a[40][40], r, c, right = 0, left = 0, up = 0, down = 0, downc, upc, lc, rc;
cin >> r >> c;
for (i = 0; i < r; i++) {
for (j = 0; j < c; j++) {
cin >> a[i][j];
}
}
for (i = 0; i < r; i++) {
for (j = 0; j < c; j++) {
if (a[i][j] == 1) {
right = 0;
left = 0;
up = 0;
down = 0;
downc = 0;
upc = 0;
lc = 0;
rc = 0;
for (k = i; k < r; k++) {
if (a[k][j] == 0)
break;
else
down++;
}
for (k = i; k >= 0; k--) {
if (a[k][j] == 0)
break;
else
up++;
}
for (k = j; k < c; k++) {
if (a[i][k] == 0)
break;
else
right++;
}
for (k = j; k >= 0; k--) {
if (a[i][k] == 0)
break;
else
left++;
}
if (!(up > 1 && down > 1 && right > 1 && left > 1)) {
downc = down;
upc = up;
rc = right;
lc = left;
if (up >= 2) {
if (right >= 4) {
while ((upc * 2) > right)
upc--;
l = l + upc - 1;
}
upc = up;
if (left >= 4) {
while ((upc * 2) > left)
upc--;
l = l + upc - 1;
}
upc = up;
}
if (down >= 2) {
if (right >= 4) {
while ((downc * 2) > right)
downc--;
l = l + downc - 1;
}
downc = down;
if (left >= 4) {
while ((downc * 2) > left)
downc--;
l = l + downc - 1;
}
downc = down;
}
if (right >= 2) {
if (up >= 4) {
while ((rc * 2) > up)
rc--;
l = l + rc - 1;
}
rc = right;
if (down >= 4) {
while ((rc * 2) > down)
rc--;
l = l + rc - 1;
}
rc = right;
}
if (left >= 2) {
if (up >= 4) {
while ((lc * 2) > up)
lc--;
l = l + lc - 1;
}
lc = left;
if (down >= 4) {
while ((lc * 2) > down)
lc--;
l = l + lc - 1;
}
lc = left;
}
}
}
}
}
cout << "Case #" << u << ": " << l << "\n";
}
}
Ok so I found the issue finally :
There was no need for " if (!(up > 1 && down > 1 && right > 1 && left > 1)) {.....}"
But still this code is too time consuming to run 1000x1000 grid case. Hence it fails test 2.
Edit: It was a mistake on my end. I bounded the array as 40x40. On changing it to a[1000][1000] it ran both tests successfully. Congos to me.

Exponential Smoothing of Newton Fractal

I'm writing myself a Newton Fractal Generator. The images all looked like this:
But I actually would like it to look a bit smoother - sure I've done some research and I ran over http://www.hiddendimension.com/FractalMath/Convergent_Fractals_Main.html and this looks rather correct, except that there are at the edges of the basins some issues..
This is my generation loop:
while (i < 6000 && fabs(z.r) < 10000 && !found){
f = computeFunction(z, params, paramc[0]);
d = computeFunction(z, paramsD, paramc[1]);
iterexp = iterexp + exp(-fabs(z.r) - 0.5 / (fabs(subComplex(zo, z).r)));
zo = z;
z = subComplex(z, divComplex(f, d));
i++;
for (int j = 0; j < paramc[0] - 1; j++){
if (compComplex(z, zeros[j], RESOLUTION)){
resType[x + xRes * y] = j;
result[x + xRes * y] = iterexp;
found = true;
break;
}
}
if (compComplex(z, zo, RESOLUTION/100)){
resType[x + xRes * y] = 12;
break;
}
}
The coloration:
const int xRes = res[0];
const int yRes = res[1];
for (int y = 0; y < fraktal->getHeight(); y++){
for (int x = 0; x < fraktal->getWidth(); x++){
int type, it;
double conDiv;
if (genCL && genCL->err == CL_SUCCESS){
conDiv = genCL->result[x + y * xRes];
type = genCL->typeRes[x + y * xRes];
it = genCL->iterations[x + y * xRes];
} else {
type = 3;
conDiv = runNewton(std::complex<double>((double)((x - (double)(xRes / 2)) / zoom[0]), (double)((y - (double)(yRes / 2)) / zoom[1])), type);
}
if (type < 15){
Color col;
col.setColorHexRGB(colors[type]);
col.setColorHSV(col.getHue(), col.getSaturation(), 1-conDiv);
fraktal->setPixel(x, y, col);
} else {
fraktal->setPixel(x, y, conDiv, conDiv, conDiv, 1);
}
}
}
I appreciate any help to actually smooth this ;-)
Thanks,
- fodinabor

Denoise algorithm in weave

I'm making a program that denoises an image. It does this by converting the RGB values of the image into it's HSI values, then operates on the HSI values and converts them back into RGB. My problem is that for some reason, quite a bit of the image gets the wrong colors after the denoising (the denoising itself works).
I'm at a standstill now with no ideas what is causing it (except that it's probably in the conversion process between RGB and HSI somewhere), so do any of you fine gentlemen/women have any idea? Here's an example of a picture that turned out wrong (all the extra green color):
These are the formulas:
FYI the formula has one error, which is that if R==G==B then H and S should be set to 0. You'll see that in the code.
Here's my weave code for the two different conversion processes (RGB>HSI, HSI>RGB). Cos and acos values need to be in degrees, hence the addition 180/pi and pi/180. The i in G[i], etc. just refers to the pixel being converted (it loops through all the pixels in the picture).
To HSI:
translateToHSI = r"""
for (int i=0; i<(m*n); i++)
{
I[i] = (R[i]+G[i]+B[i])/3;
if (I[i] == 0)
{
S[i] = 0;
}
else
{
float fl = fmin(R[i], G[i]);
fl = fmin(fl, B[i]);
S[i] = 1-(fl/I[i]);
}
float func = (R[i]-(G[i]/2.0)-(B[i]/2.0))/sqrt((R[i]*R[i])+(G[i]*G[i])+(B[i]*B[i])-(R[i]*G[i])-(R[i]*B[i])-(G[i]*B[i]));
if (R[i]==G[i] && G[i] == B[i])
{
H[i] = 0;
S[i] = 0;
}
else if (G[i]<B[i])
{
H[i] = 360-(acos(func)*180.0/3.14159265);
}
else
{
H[i] = acos(func)*180.0/3.1459265;
}
}
"""
to RGB:
translateToRGB = r"""
for (int i=0; i<(m*n); i++)
{
if (H[i] == 0)
{
R[i] = I[i]+2*I[i]*S[i];
G[i] = I[i]-I[i]*S[i];
B[i] = I[i]-I[i]*S[i];
}
else if (H[i] < 120)
{
float func = cos(H[i]*3.14159265/180)/cos(60-H[i]*3.14159265/180);
R[i] = I[i]+I[i]*S[i]*func;
G[i] = I[i]+I[i]*S[i]*(1-func);
B[i] = I[i]-I[i]*S[i];
}
else if (H[i] == 120)
{
R[i] = I[i]-I[i]*S[i];
G[i] = I[i]+2*I[i]*S[i];
B[i] = I[i]-I[i]*S[i];
}
else if (H[i] < 240)
{
float func = cos((H[i]-120)*3.14159265/180)/cos((180-H[i])*3.1459265/180);
R[i] = I[i]-I[i]*S[i];
G[i] = I[i]+I[i]*S[i]*func;
B[i] = I[i]+I[i]*S[i]*(1-func);
}
else if (H[i] == 240)
{
R[i] = I[i]-I[i]*S[i];
G[i] = I[i]-I[i]*S[i];
B[i] = I[i]+2*I[i]*S[i];
}
else
{
float func = cos((H[i]-240)*3.14159265/180)/cos((300-H[i])*3.14159265/180);
R[i] = I[i]+I[i]*S[i]*(1-func);
G[i] = I[i]-I[i]*S[i];
B[i] = I[i]+I[i]*S[i]*func;
}
}
"""
So I wrote the following code
#include <iostream>
#include <math.h>
void toHSI(float R, float G, float B, float& H, float& S, float& I) {
I = (R+G+B)/3;
if (I == 0)
{
S = 0;
}
else
{
float fl = fmin(R, G);
fl = fmin(fl, B);
S = 1-(fl/I);
}
float func = (R-(G/2.0)-(B/2.0))/sqrt((R*R)+(G*G)+(B*B)-(R*G)-(R*B)-(G*B));
if (R==G && G == B)
{
H = 0;
S = 0;
}
else if (G<B)
{
H = 360-(acos(func)*180.0/3.14159265);
}
else
{
H = acos(func)*180.0/3.1459265;
}
}
void toRGB(float H, float S, float I, float& R, float& G, float& B) {
if (H == 0)
{
R = I+2*I*S;
G = I-I*S;
B = I-I*S;
}
else if (H < 120)
{
float func = cos(H*3.14159265/180)/cos(60-H*3.14159265/180);
R = I+I*S*func;
G = I+I*S*(1-func);
B = I-I*S;
}
else if (H == 120)
{
R = I-I*S;
G = I+2*I*S;
B = I-I*S;
}
else if (H < 240)
{
float func = cos((H-120)*3.14159265/180)/cos((180-H)*3.1459265/180);
R = I-I*S;
G = I+I*S*func;
B = I+I*S*(1-func);
}
else if (H == 240)
{
R = I-I*S;
G = I-I*S;
B = I+2*I*S;
}
else
{
float func = cos((H-240)*3.14159265/180)/cos((300-H)*3.14159265/180);
R = I+I*S*(1-func);
G = I-I*S;
B = I+I*S*func;
}
}
int main() {
for (int r = 0; r < 255; r += 10) {
for (int g = 0; g < 255; g += 10) {
for (int b = 0; b < 255; b += 10) {
float r1, g1, b1, h, s, i;
toHSI(r, g, b, h, s, i);
toRGB(h, s, i, r1, g1, b1);
if (fabs(r - r1) > 5 || fabs(g - g1) > 5 || fabs(b - b1) > 5) {
std::cout << r << ' ' << g << ' ' << b << " --> "
<< h << ' ' << s << ' ' << i << " --> "
<< r1 << ' ' << g1 << ' ' << b1 << std::endl;
}
}
}
}
}
Demo for convenience
The first lines of output are:
0 20 0 --> 119.835 1 6.66667 --> -9.17128 29.1713 0
0 30 0 --> 119.835 1 10 --> -13.7569 43.7569 0
0 40 0 --> 119.835 1 13.3333 --> -18.3426 58.3426 0
0 50 0 --> 119.835 1 16.6667 --> -22.9282 72.9282 0
0 60 0 --> 119.835 1 20 --> -27.5138 87.5138 0
Now you can debug this code with any of the values which give wrong results and find where the bug is.

Drawing lines with Bresenham's Line Algorithm

My computer graphics homework is to implement OpenGL algorithms using only the ability to draw points.
So obviously I need to get drawLine() to work before I can draw anything else. drawLine() has to be done using integers only. No floating point.
This is what I was taught. Basically, lines can be broken up into 4 different categories, positive steep, positive shallow, negative steep and negative shallow. This is the picture I am supposed to draw:
and this is the picture my program is drawing:
The colors are done for us. We are given vertices and we need to use Bresenham's Line algorithm to draw the lines based on the start and end points.
This is what I have so far:
int dx = end.x - start.x;
int dy = end.y - start.y;
//initialize varibales
int d;
int dL;
int dU;
if (dy > 0){
if (dy > dx){
//+steep
d = dy - 2*dx;
dL = -2*dx;
dU = 2*dy - 2*dx;
for (int x = start.x, y = start.y; y <= end.y; y++){
Vertex v(x,y);
drawPoint(v);
if (d >= 1){
d += dL;
}else{
x++;
d += dU;
}
}
} else {
//+shallow
d = 2*dy - dx;
dL = 2*dy;
dU = 2*dy - 2*dx;
for (int x = start.x, y = start.y; x <= end.x; x++) {
Vertex v(x,y);
drawPoint(v);
// if choosing L, next y will stay the same, we only need
// to update d by dL
if (d <= 0) {
d += dL;
// otherwise choose U, y moves up 1
} else {
y++;
d += dU;
}
}
}
} else {
if (-dy > dx){
cout << "-steep\n";
//-steep
d = dy - 2*dx;
//south
dL = 2*dx;
//southeast
dU = 2*dy - 2*dx;
for (int x = start.x, y = start.y; y >= end.y; --y){
Vertex v(x,y);
drawPoint(v);
//if choosing L, next x will stay the same, we only need
//to update d
if (d >= 1){
d -= dL;
} else {
x++;
d -= dU;
}
}
} else {
cout << "-shallow\n";
//-shallow
d = 2*dy - dx;
dL = 2*dy;
dU = 2*dy - 2*dx;
for (int x = start.x, y = start.y; x <= end.x; x++){
Vertex v(x,y);
drawPoint(v);
if (d >= 0){
d += dL;
} else {
--y;
d -= dU;
}
}
}
}
I know my error is going to be something silly, but I honestly cannot figure out what I am doing wrong. Why are some of the lines drawn incorrectly as shown above?
/*BRESENHAAM ALGORITHM FOR LINE DRAWING*/
#include<iostream.h>
#include<graphics.h>
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<math.h>
#include<dos.h>
void bhm_line(int,int,int,int,int);
void main()
{
int ghdriver=DETECT,ghmode,errorcode,x1,x2,y1,y2;
initgraph(&ghdriver,&ghmode,"..\\bgi");
errorcode = graphresult();
if(errorcode !=grOk)
{
cout<<"Graphics error:%s\n"<<grapherrormsg(errorcode);
cout<<"Press any key to halt:";
getch();
exit(1);
}
clrscr();
cout<<"Enter the coordinates (x1,y1): ";
cin>>x1>>y1;
cout<<"Enter the coordinates (x2,y2): ";
cin>>x2>>y2;
bhm_line(x1,y1,x2,y2,1);
getch();
}
void bhm_line(int x1,int y1,int x2,int y2,int c)
{
int x,y,dx,dy,dx1,dy1,px,py,xe,ye,i;
dx=x2-x1;
dy=y2-y1;
dx1=fabs(dx);
dy1=fabs(dy);
px=2*dy1-dx1;
py=2*dx1-dy1;
if(dy1<=dx1)
{
if(dx>=0)
{
x=x1;
y=y1;
xe=x2;
}
else
{
x=x2;
y=y2;
xe=x1;
}
putpixel(x,y,c);
for(i=0;x<xe;i++)
{
x=x+1;
if(px<0)
{
px=px+2*dy1;
}
else
{
if((dx<0 && dy<0) || (dx>0 && dy>0))
{
y=y+1;
}
else
{
y=y-1;
}
px=px+2*(dy1-dx1);
}
delay(0);
putpixel(x,y,c);
}
}
else
{
if(dy>=0)
{
x=x1;
y=y1;
ye=y2;
}
else
{
x=x2;
y=y2;
ye=y1;
}
putpixel(x,y,c);
for(i=0;y<ye;i++)
{
y=y+1;
if(py<=0)
{
py=py+2*dx1;
}
else
{
if((dx<0 && dy<0) || (dx>0 && dy>0))
{
x=x+1;
}
else
{
x=x-1;
}
py=py+2*(dx1-dy1);
}
delay(0);
putpixel(x,y,c);
}
}
}
I implemented the original Bresenham's algorithm in C++ and tried to optimize as much as I could (especially regarding removing the IF from the interior loop).
It draws in a linear buffer instead of a surface, and for this matter, this implementation was almost as fast as EFLA (Extremely Fast Line Algorithm) (maybe 5% slower).
#include <vector>
#include <math.h>
using namespace std;
vector<unsigned char> buffer;
int imageSide = 2048; // the width of the surface
struct Point2Di
{
int x;
int y;
Point2Di(const int &x, const int &y): x(x), y(y){}
Point2Di(){}
};
void drawLine(const Point2Di &p0, const Point2Di &p1)
{
int dx = p1.x - p0.x;
int dy = p1.y - p0.y;
int dLong = abs(dx);
int dShort = abs(dy);
int offsetLong = dx > 0 ? 1 : -1;
int offsetShort = dy > 0 ? imageSide : -imageSide;
if(dLong < dShort)
{
swap(dShort, dLong);
swap(offsetShort, offsetLong);
}
int error = 2 * dShort - dLong;
int index = p0.y*imageSide + p0.x;
const int offset[] = {offsetLong, offsetLong + offsetShort};
const int abs_d[] = {2*dShort, 2*(dShort - dLong)};
for(int i = 0; i <= dLong; ++i)
{
buffer[index] = 255; // or a call to your painting method
const int errorIsTooBig = error >= 0;
index += offset[errorIsTooBig];
error += abs_d[errorIsTooBig];
}
}
The EFLA implementation that I am using is:
void drawLine(Point2Di p0, Point2Di p1)
{
bool yLonger=false;
int shortLen=p1.y-p0.y;
int longLen=p1.x-p0.x;
if (abs(shortLen)>abs(longLen)) {
swap(shortLen, longLen);
yLonger=true;
}
int decInc = longLen==0 ? decInc=0 : ((shortLen << 16) / longLen);
if (yLonger) {
p0.y*=imageSide;
p1.y*=imageSide;
if (longLen>0)
for (int j=0x8000+(p0.x<<16);p0.y<=p1.y;p0.y+=imageSide, j+=decInc)
buffer[p0.y + (j >> 16)] = 255; // or a call to your painting method
else
for (int j=0x8000+(p0.x<<16);p0.y>=p1.y;p0.y-=imageSide, j-=decInc)
buffer[p0.y + (j >> 16)] = 255; // or a call to your painting method
}
else
{
if (longLen>0)
for (int j=0x8000+(p0.y<<16);p0.x<=p1.x;++p0.x, j+=decInc)
buffer[(j >> 16) * imageSide + p0.x] = 255; // or a call to your painting method
else
for (int j=0x8000+(p0.y<<16);p0.x>=p1.x;--p0.x, j-=decInc)
buffer[(j >> 16) * imageSide + p0.x] = 255; // or a call to your painting method
}
}
In case anyone was wondering what the problem was, I still don't know what it was. What I ended up doing was re-factored my code so that the -shallow and -steep used the same algorithm as +shallow and +steep, respectively. After adjusting the x,y coordinates (negating the x or y coordinate), when I went to plot them I negated my original negation so that it plotted in the right spot.

C++ triangle rasterization

I'm trying to fix this triangle rasterizer, but cannot make it work correctly. For some reason it only draws half of the triangles.
void DrawTriangle(Point2D p0, Point2D p1, Point2D p2)
{
Point2D Top, Middle, Bottom;
bool MiddleIsLeft;
if (p0.y < p1.y) // case: 1, 2, 5
{
if (p0.y < p2.y) // case: 1, 2
{
if (p1.y < p2.y) // case: 1
{
Top = p0;
Middle = p1;
Bottom = p2;
MiddleIsLeft = true;
}
else // case: 2
{
Top = p0;
Middle = p2;
Bottom = p1;
MiddleIsLeft = false;
}
}
else // case: 5
{
Top = p2;
Middle = p0;
Bottom = p1;
MiddleIsLeft = true;
}
}
else // case: 3, 4, 6
{
if (p0.y < p2.y) // case: 4
{
Top = p1;
Middle = p0;
Bottom = p2;
MiddleIsLeft = false;
}
else // case: 3, 6
{
if (p1.y < p2.y) // case: 3
{
Top = p1;
Middle = p2;
Bottom = p0;
MiddleIsLeft = true;
}
else // case 6
{
Top = p2;
Middle = p1;
Bottom = p0;
MiddleIsLeft = false;
}
}
}
float xLeft, xRight;
xLeft = xRight = Top.x;
float mLeft, mRight;
// Region 1
if(MiddleIsLeft)
{
mLeft = (Top.x - Middle.x) / (Top.y - Middle.y);
mRight = (Top.x - Bottom.x) / (Top.y - Bottom.y);
}
else
{
mLeft = (Top.x - Bottom.x) / (Top.y - Bottom.y);
mRight = (Middle.x - Top.x) / (Middle.y - Top.y);
}
int finalY;
float Tleft, Tright;
for (int y = ceil(Top.y); y < (int)Middle.y; y++)
{
Tleft=float(Top.y-y)/(Top.y-Middle.y);
Tright=float(Top.y-y)/(Top.y-Bottom.y);
for (int x = ceil(xLeft); x <= ceil(xRight) - 1 ; x++)
{
FrameBuffer::SetPixel(x, y, p0.r,p0.g,p0.b);
}
xLeft += mLeft;
xRight += mRight;
finalY = y;
}
// Region 2
if (MiddleIsLeft)
{
mLeft = (Bottom.x - Middle.x) / (Bottom.y - Middle.y);
}
else
{
mRight = (Middle.x - Bottom.x) / (Middle.y - Bottom.y);
}
for (int y = Middle.y; y <= ceil(Bottom.y) - 1; y++)
{
Tleft=float(Bottom.y-y)/(Bottom.y-Middle.y);
Tright=float(Top.y-y)/(Top.y-Bottom.y);
for (int x = ceil(xLeft); x <= ceil(xRight) - 1; x++)
{
FrameBuffer::SetPixel(x, y, p0.r,p0.g,p0.b);
}
xLeft += mLeft;
xRight += mRight;
}
}
Here is what happens when I use it to draw shapes.
When I disable the second region, all those weird triangles disappear.
The wireframe mode works perfect, so this eliminates all the other possibilities other than the triangle rasterizer.
I kind of got lost in your implementation, but here's what I do (I have a slightly more complex version for arbitrary convex polygons, not just triangles) and I think apart from the Bresenham's algorithm it's very simple (actually the algorithm is simple too):
#include <stddef.h>
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#define SCREEN_HEIGHT 22
#define SCREEN_WIDTH 78
// Simulated frame buffer
char Screen[SCREEN_HEIGHT][SCREEN_WIDTH];
void SetPixel(long x, long y, char color)
{
if ((x < 0) || (x >= SCREEN_WIDTH) ||
(y < 0) || (y >= SCREEN_HEIGHT))
{
return;
}
Screen[y][x] = color;
}
void Visualize(void)
{
long x, y;
for (y = 0; y < SCREEN_HEIGHT; y++)
{
for (x = 0; x < SCREEN_WIDTH; x++)
{
printf("%c", Screen[y][x]);
}
printf("\n");
}
}
typedef struct
{
long x, y;
unsigned char color;
} Point2D;
// min X and max X for every horizontal line within the triangle
long ContourX[SCREEN_HEIGHT][2];
#define ABS(x) ((x >= 0) ? x : -x)
// Scans a side of a triangle setting min X and max X in ContourX[][]
// (using the Bresenham's line drawing algorithm).
void ScanLine(long x1, long y1, long x2, long y2)
{
long sx, sy, dx1, dy1, dx2, dy2, x, y, m, n, k, cnt;
sx = x2 - x1;
sy = y2 - y1;
if (sx > 0) dx1 = 1;
else if (sx < 0) dx1 = -1;
else dx1 = 0;
if (sy > 0) dy1 = 1;
else if (sy < 0) dy1 = -1;
else dy1 = 0;
m = ABS(sx);
n = ABS(sy);
dx2 = dx1;
dy2 = 0;
if (m < n)
{
m = ABS(sy);
n = ABS(sx);
dx2 = 0;
dy2 = dy1;
}
x = x1; y = y1;
cnt = m + 1;
k = n / 2;
while (cnt--)
{
if ((y >= 0) && (y < SCREEN_HEIGHT))
{
if (x < ContourX[y][0]) ContourX[y][0] = x;
if (x > ContourX[y][1]) ContourX[y][1] = x;
}
k += n;
if (k < m)
{
x += dx2;
y += dy2;
}
else
{
k -= m;
x += dx1;
y += dy1;
}
}
}
void DrawTriangle(Point2D p0, Point2D p1, Point2D p2)
{
int y;
for (y = 0; y < SCREEN_HEIGHT; y++)
{
ContourX[y][0] = LONG_MAX; // min X
ContourX[y][1] = LONG_MIN; // max X
}
ScanLine(p0.x, p0.y, p1.x, p1.y);
ScanLine(p1.x, p1.y, p2.x, p2.y);
ScanLine(p2.x, p2.y, p0.x, p0.y);
for (y = 0; y < SCREEN_HEIGHT; y++)
{
if (ContourX[y][1] >= ContourX[y][0])
{
long x = ContourX[y][0];
long len = 1 + ContourX[y][1] - ContourX[y][0];
// Can draw a horizontal line instead of individual pixels here
while (len--)
{
SetPixel(x++, y, p0.color);
}
}
}
}
int main(void)
{
Point2D p0, p1, p2;
// clear the screen
memset(Screen, ' ', sizeof(Screen));
// generate random triangle coordinates
srand((unsigned)time(NULL));
p0.x = rand() % SCREEN_WIDTH;
p0.y = rand() % SCREEN_HEIGHT;
p1.x = rand() % SCREEN_WIDTH;
p1.y = rand() % SCREEN_HEIGHT;
p2.x = rand() % SCREEN_WIDTH;
p2.y = rand() % SCREEN_HEIGHT;
// draw the triangle
p0.color = '1';
DrawTriangle(p0, p1, p2);
// also draw the triangle's vertices
SetPixel(p0.x, p0.y, '*');
SetPixel(p1.x, p1.y, '*');
SetPixel(p2.x, p2.y, '*');
Visualize();
return 0;
}
Output:
*111111
1111111111111
111111111111111111
1111111111111111111111
111111111111111111111111111
11111111111111111111111111111111
111111111111111111111111111111111111
11111111111111111111111111111111111111111
111111111111111111111111111111111111111*
11111111111111111111111111111111111
1111111111111111111111111111111
111111111111111111111111111
11111111111111111111111
1111111111111111111
11111111111111
11111111111
1111111
1*
The original code will only work properly with triangles that have counter-clockwise winding because of the if-else statements on top that determines whether middle is left or right. It could be that the triangles which aren't drawing have the wrong winding.
This stack overflow shows how to Determine winding of a 2D triangles after triangulation
The original code is fast because it doesn't save the points of the line in a temporary memory buffer. Seems a bit over-complicated even given that, but that's another problem.
The following code is in your implementation:
if (p0.y < p1.y) // case: 1, 2, 5
{
if (p0.y < p2.y) // case: 1, 2
{
if (p1.y < p2.y) // case: 1
{
Top = p0;
Middle = p1;
Bottom = p2;
MiddleIsLeft = true;
}
else // case: 2
{
Top = p0;
Middle = p2;
Bottom = p1;
MiddleIsLeft = false;
}
}
This else statement means that p2.y (or Middle) can equal p1.y (or Bottom). If this is true, then when region 2 runs
if (MiddleIsLeft)
{
mLeft = (Bottom.x - Middle.x) / (Bottom.y - Middle.y);
}
else
{
mRight = (Middle.x - Bottom.x) / (Middle.y - Bottom.y);
}
That else line will commit division by zero, which is not possible.