How do draw a polygon using gdimage in C? - c

I've got an assignment at Uni which involves drawing lots of different shapes, all of whihch has to be drawn using the gdImage library in C language. So far I've used gdImageLine and gdImageRectangle, like this:
gdImageLine ( gdImage, 150, 70, 170, 90, blue);
or
gdImageRectangle( gdImage, 110, 80, 160, 120, blue);
I'm very inexperienced/have no clue about C, so any help would be great!
Hi, sorry I got confused. I wanted to draw a shape using "gdImagePolygon" in the way/similar to how I used the other two, if that makes sense? I've been given this link (http://cnfolio.com/public/libgd_drawing_reference.html), thanks

gdImagePolygon has the following signature:
gdImagePolygon(gdImagePtr im, gdPointPtr points, int pointsTotal, int color)
gdImagePtr is a pointer to a gdImage Structure
gdPointPtr is a pointer to a gdPoint structure (just two ints, x and y of the point):
typedef struct {
int x, y;
} gdPoint, *gdPointPtr;
pointsTotal is the number of points you'll have total (minimum of 3)
color is the color
The sample to draw a triangle:
... inside a function ...
gdImagePtr im;
int black;
int white;
/* Points of polygon */
gdPoint points[3]; // an array of gdPoint structures is used here
im = gdImageCreate(100, 100);
/* Background color (first allocated) */
black = gdImageColorAllocate(im, 0, 0, 0);
/* Allocate the color white (red, green and
blue all maximum). */
white = gdImageColorAllocate(im, 255, 255, 255);
/* Draw a triangle. */
points[0].x = 50;
points[0].y = 0;
points[1].x = 99;
points[1].y = 99;
points[2].x = 0;
points[2].y = 99;
gdImagePolygon(im, points, 3, white);
/* ... Do something with the image, such as
saving it to a file... */
/* Destroy it */
gdImageDestroy(im);

I wrote this code snippet from scratch, please notice me if there is any mistake. Thanks.
int Draw_Polygon (int Side, ...)
{
va_list Ap;
va_start (Ap, Side);
int X_1 = va_arg (Ap, int);
int X_0 = X_1;
int Y_1 = va_arg (Ap, int);
int Y_0 = Y_1;
int Cnt;
for (Cnt = 0; Cnt < Side-1; Cnt++)
{
int X_2 = va_arg (Ap, int);
int Y_2 = va_arg (Ap, int);
gdImageLine ( gdImage, X_1, Y_1, X_2, Y_2, blue);
X_1 = X_2;
Y_1 = Y_2;
}
gdImageLine ( gdImage, X_1, Y_1, X_0, Y_0, blue);
va_end(Ap);
return 0;
}
int main (void)
{
if (Draw_Polygon (5, 0, 0, 0, 10, 12, 12, 16, 8, 5, 0) == 0) // Draw a pentagon.
{
// Success !
}
if (Draw_Polygon (6, 0, 0, 0, 10, 12, 12, 16, 8, 6, 3, 5, 0) == 0) // Draw a hexagon.
{
// Success !
}
}

Quick pseudocode to draw a polygon of N sides, with a side length of L:
Procedure DrawPol (integer N,L)
Integer i
For i=1 To N
Draw (L)
Turn (360/N)
EndFor
EndProcedure
This pseudocode is base on two primitives, which are common in languages like LOGO:
Draw (L) : draws a line of L pixels in the current direction
Turn (A) : changes current direction by adding A degrees to the
current direction
To implement Draw and Turn using the Line function you can use something like this:
Real CurrentAngle = 0 /* global variable */
Integer CurrentX = MAXX / 2 /* last point drawn */
Integer CurrentY = MAXY / 2 /* initialized to the center of the paint area */
Procedure Draw (Integer L)
Integer FinalX,FinalY
FinalX = CurrentX + L*cos(CurrentAngle)
FinalY = CurrentY + L*sin(CurrentAngle)
Line (CurrentX, CurrentY, FinalX, FinalY) /* gdImageLine() function actually */
CurrentX = FinalX
CurrentY = FinalY
EndProcedure
Procedure Turn (Float A)
CurrentAngle = CurrentAngle + A
If (CurrentAngle>360) /* MOD operator usually works */
CurrentAngle = 360-CurrentAngle /* only for integers */
EndIf
EndProcedure

Related

Making projectile shoot using with allegro library in C

I'm trying to make a projectile shoot using with allegro library in C.And I couldn't do it in no way.My all code is below.My circle goes up but then disappear.Even if not I can't bring it down to the ground.I'm not good at physic so if my equals are wrong please forgive me.
#include <allegro.h>
#include < math.h >
void StartAlleg(); // my start program function
void EndAlleg();
int main() {
StartAlleg();
BITMAP *buffer = create_bitmap(640, 480);
int g = 10, Vo = 0 , Vx = 5, Vy = 475, angle= 0;
double time = 0, tUp = 0,hmax=0; //g is gravity
show_mouse(screen);
while (!key[KEY_ESC])
{
circle(buffer, Vx, Vy, 5, makecol(255, 0, 0));
if (key[KEY_UP]&&angle<360) angle++;
if (key[KEY_RIGHT]) Vo++;
if (key[KEY_DOWN] && angle>0) angle--;
if (key[KEY_LEFT] && Vo>0) Vo--;
textout_ex(buffer, font, "Player 1 : ", 0, 0, makecol(255, 255, 13), -1);
textprintf(buffer, font, 0, 25, makecol(255, 255, 13), "Angle = %d ",angle);
textprintf(buffer, font, 0, 15, makecol(255, 255, 13), "Speed = %d ", Vo);
if (key[KEY_Z] ){
Vx = Vo*cos(double(angle));
Vy = Vo*sin(double(angle));
if (angle== 180 || angle == 360) Vy = 0;
if (angle== 90 || angle== 270) Vx = 0;
if (Vx < 0) Vx *= (-1);
if (Vy < 0) Vy *= (-1);
tUp = Vy / g;
time = tUp * 2;
hmax = (Vy*Vy) / (2*g);
}
textprintf(buffer, font, 0, 35, makecol(255, 255, 13), "tUp Value = %.2f ", tUp);
for (int i = 1; i <= time; i++)
{
if (i<tUp){ Vx = Vx + g; Vy += g; }
else{ Vy -= g; Vx = Vx + g; }
}
blit(buffer, screen, 0, 0, 0, 0, 640, 480);
rest(60);
clear_bitmap(buffer);
}
EndAlleg(); // my end program function
return 0;
}
END_OF_MAIN()
void StartAlleg() {
int depth, res;
allegro_init();
depth = desktop_color_depth();
if (depth == 0) depth = 32;
set_color_depth(depth);
res = set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);
if (res != 0) {
allegro_message(allegro_error);
exit(-1);
}
install_timer();
install_keyboard();
install_mouse();
install_sound(DIGI_AUTODETECT, MIDI_AUTODETECT, "A");
}
void EndAlleg() {
clear_keybuf();
}
I think , the main problem is here :
for (int i = 1; i <= time; i++)
{
if (i<tUp){ Vx = Vx + g; Vy += g; }
else{ Vy -= g; Vx = Vx + g; }
}
I didn't try to understand all your code, but it seems that your calculations are wrong.
Here is how gravity can be implemented :
First, you need to keep track of your projectile position, with variables like Px Py. This position will give you the drawing coordinates.
Then you need to keep track of its speed, usually horizontal and vertical speed, with variables like Vx Vy. If your initial speed is a single vector with angle, convert it once.
Every tick of your game (every loop iteration in your case), you add the speeds to the positions. Then to add gravity, you subtract 10 to the vertical speed, also at every tick (it implements acceleration of -10).
And thats all. Negative speeds and accelerations are normal, you don't need to check, but you can check for borders for positions. Also, you should note that you usually divide the speeds and accelerations by the frequency of your ticks, or else the faster your loop the faster the projectile will move.
You should note that this isn't the best way to implement gravity, because this only approximate physics (more ticks per second will give you more accurate simulation). You should google "game implement gravity properly" for an accurate algorithm, I'm not an expert.

Line fit from an array of 2d vectors

I have a problem in some C code, I assume it belonged here over the Mathematics exchange.
I have an array of changes in x and y position generated by a user dragging a mouse, how could I determine if a straight line was drawn or not.
I am currently using linear regression, is there a better(more efficient) way to do this?
EDIT:
Hough transformation attempt:
#define abSIZE 100
#define ARRAYSIZE 10
int A[abSIZE][abSIZE]; //points in the a-b plane
int dX[10] = {0, 10, 13, 8, 20, 18, 19, 22, 12, 23};
int dY[10] = {0, 2, 3, 1, -1, -2, 0, 0, 3, 1};
int absX[10]; //absolute positions
int absY[10];
int error = 0;
int sumx = 0, sumy = 0, i;
//Convert deltas to absolute positions
for (i = 0; i<10; i++) {
absX[i] = sumx+=dX[i];
absY[i] = sumy+=dY[i];
}
//initialise array to zero
int a, b, x, y;
for(a = -abSIZE/2; a < abSIZE/2; a++) {
for(b = -abSIZE/2; b< abSIZE/2; b++) {
A[a+abSIZE/2][b+abSIZE/2] = 0;
}
}
//Hough transform
int aMax = 0;
int bMax = 0;
int highest = 0;
for(i=0; i<10; i++) {
x = absX[i];
y = absX[i];
for(a = -abSIZE/2; a < abSIZE/2; a++) {
for(b = -abSIZE/2; b< abSIZE/2; b++) {
if (a*x + b == y) {
A[a+abSIZE/2][b+abSIZE/2] += 1;
if (A[a+abSIZE/2][b+abSIZE/2] > highest) {
highest++; //highest = A[a+abSIZE/2][b+abSIZE/2]
aMax = a;
bMax = b;
}
}
}
}
}
printf("Line is Y = %d*X + %d\n",aMax,bMax);
//Calculate MSE
int e;
for (i = 0; i < ARRAYSIZE; i++) {
e = absY[i] - (aMax * absX[i] + bMax);
e = (int) pow((double)e, 2);
error += e;
}
printf("error is: %d\n", error);
Though linear regression sounds like a perfectly reasonable way to solve the task, here's another suggestion: Hough transform, which might be somewhat more robust against outliers. Here is a very rough sketch of how this can be applied:
initialize a large matrix A with zeros
transform your deltas to some absolute coordinates (x, y) in a x-y-plane (e.g. start with (0,0))
for each point
there are non-unique parameters a and b such that a*x + b = y. All such points (a,b) define a straight line in the a-b-plane
draw this "line" in the a-b-plane by adding ones to the corresponding cells in A, which represents the quantized plane
now you can find a maximum in the a-b-plane-matrix A, which will correspond to the parameters (a, b) of the straight line in the x-y-plane that has most support by the original points
finally, calculate MSE to the original points and decide with some threshold if the move was a straight line
More details e.g. here:
http://homepages.inf.ed.ac.uk/rbf/CVonline/LOCAL_COPIES/MARSHALL/node32.html
Edit: here's a quote from Wikipedia that explains why it's better to use a different parametrization to deal with vertical lines (where a would become infinite in ax+b=y):
However, vertical lines pose a problem. They are more naturally described as x = a and would give rise to unbounded values of the slope parameter m. Thus, for computational reasons, Duda and Hart proposed the use of a different pair of parameters, denoted r and theta, for the lines in the Hough transform. These two values, taken in conjunction, define a polar coordinate.
Thanks to Zaw Lin for pointing this out.

Why is my ray-traced image entirely black?

I had to generate an image that's a black circle, black being (0, 0 , 0) and white being (1, 1, 1), but I keep getting a completely black image. Here's all my code:
#include "cast.h"
#include "collisions.h"
#include <stdio.h>
#include "math.h"
int cast_ray(struct ray r, struct sphere spheres[], int num_spheres)
{
int isFound;
struct maybe_point mp;
isFound = 0;
for (int i = 0; i < num_spheres; i++)
{
mp = sphere_intersection_point(r, spheres[i]);
if (mp.isPoint == 1)
{
isFound = 1;
}
else
{
isFound = 0;
}
}
return isFound;
}
void print_pixel(double a, double b, double c)
{
int i, j, k;
i = a * 255;
j = b * 255;
k = c * 255;
printf("%d %d %d ", i, j, k);
}
void cast_all_rays(double min_x, double max_x, double min_y, double max_y,
int width, int height, struct point eye,
struct sphere spheres[], int num_spheres)
{
double width_interval, height_interval, y, x;
int intersect;
width_interval = (max_x - min_x)/width;
height_interval = (max_y - min_y)/height;
for (y = max_y; y > min_y; y = y - height_interval)
{
for (x = min_x; x < max_x; x = x + width_interval)
{
struct ray r;
r.p = eye;
r.dir.x = x;
r.dir.y = y;
r.dir.z = 0.0;
intersect = cast_ray(r, spheres, num_spheres);
if (intersect != 0)
{
print_pixel (0, 0, 0);
}
else
{
print_pixel (1, 1, 1);
}
}
I already had functions that I know are correct which find whether or not the ray intersects with a sphere. The function that I used to find intersection points was in the function cast_ray.
sphere_intersection_point(r, spheres[i]);
The print_pixel function translates the integer values by multiplying them with the max color value, which is 255.
And the cast_all_rays function casts rays into the whole scene from our eyes (going through all the x coordinates before changing the y). If the ray intersects with a sphere, the pixel is black, thus, forming a black circle in the end.
And here are the limits for the x, y, and radius (NOTE: I'M USING THE PPM FORMAT):
Eye at <0.0, 0.0, -14.0>.
A sphere at <1.0, 1.0, 0.0> with radius 2.0.
A sphere at <0.5, 1.5, -3.0> with radius 0.5.
min_x at -10, max_x at 10, min_y of -7.5, max_y at 7.5, width=1024, and height=768.
I need to generate an image of a black circle, but I keep getting an image that's completely black. I have a feeling that the problem lies inside the cast_all_rays function, but I just can't seem to find what it is. Help is appreciated! Thanks.
And just in case something went wrong with my testing, here's my test.c file for cast_all_rays:
#include "collisions.h"
#include "data.h"
#include "cast.h"
#include <stdio.h>
void cast_all_rays_tests(void)
{
printf("P3\n");
printf("%d %d\n", 1024, 768);
printf("255\n");
double min_x, max_x, min_y, max_y;
int width, height;
struct point eye;
struct sphere spheres[2];
eye.x = 0.0;
eye.y = 0.0;
eye.z = -14.0;
spheres[0].center.x = 1.0;
spheres[0].center.y = 1.0;
spheres[0].center.z = 0.0;
spheres[0].radius = 2.0;
spheres[1].center.x = 0.5;
spheres[1].center.y = 1.5;
spheres[1].center.z = -3.0;
spheres[1].radius = 0.5;
min_x = -10;
max_x = 10;
min_y = -7.5;
max_y = 7.5;
cast_all_rays(min_x, max_x, min_y, max_y, width, height, eye, spheres, num_spheres);
}
int main()
{
cast_all_rays_tests();
return 0;
}
Not sure if this is the problem you're having, but you should only set isFound if you intersect a sphere. Don't set it if you don't intersect. Otherwise your image will be governed by only the last sphere in the list.
if (mp.isPoint == 1)
{
isFound = 1;
}
//else
//{
// isFound = 0;
//}
Since your image is entirely black, it seems like your intersection code is bung or your field of view is too narrow. If you don't have any joy with the above change, maybe you should post details on your x- and y-limits, the eye position, and the position and radius of the sphere.
One more thing I noticed is r.dir.z = 0.0. Do you subtract the eye position from this to get a direction, or is that your true ray direction? Surely you need to give a non-zero z-direction. Normally you set the x and the y based on your view plane and provide a constant z such as 1 or -1.
[edit]
To make it clearer from the comments below, I believe that you haven't correctly set up your ray direction. Instead you have simply set the direction to be the view-plane's pixel position, ignoring the eye position. The following would be more usual:
struct ray r;
r.p = eye;
r.dir.x = x - eye.x;
r.dir.y = y - eye.y;
r.dir.z = 0.0 - eye.z;

Tracking objects using histogram data in OpenCV

I am trying to track objects inside an image using histogram data from the object. I pass in a reference image to get the histogram data and store it in a Mat. From there I load in an image and try and use the histogram data to detect the object. The problem I am coming with is not only is it not tracking the object, but it's not updating the detection. If I load image "1.jpg" the detection will claim that the object is in the top right corner when it's in the bottom left. When I pass in the second image the detection field does not move at all. This continues for the next batch of images as well. Below is a code snippet of my application.
This is being done in a Windows 7 32-bit environment using OpenCV2.3 in VS2010. Thanks in advance for any help
int main( int argc, char** argv )
{
vector<string> szFileNames;
IplImage* Image;
Mat img, hist, backproj;
Rect trackWindow;
// Load histogram data
hist = ImageHistogram("C:/Users/seb/Documents/redbox1.jpg", backproj);
Image = cvLoadImage("C:/Users/seb/Documents/1.jpg");
img = Mat(Image);
trackWindow = Rect(0, 0, Image->width, Image->height);
imshow("Histogram", hist);
while(true)
{
Detection(img, backproj, trackWindow);
imshow("Image", img);
char c = cvWaitKey(1);
switch(c)
{
case 32:
{
cvReleaseImage(&Image);
Image = cvLoadImage("C:/Users/seb/Documents/redbox2.jpg");
img = Mat(Image);
break;
}
}
}
cvReleaseImage(&Image);
// Destroy all windows
cvDestroyWindow("Histogram");
cvDestroyWindow("Image");
return 0;
}
Mat ImageHistogram(string szFilename, Mat& backproj)
{
// Create histogram values
int vmin = 10;
int vmax = 256;
int smin = 30;
int hsize = 16;
float hranges[] = {0,180};
const float* phranges = hranges;
// Load the image
IplImage* Image = cvLoadImage(szFilename.c_str());
Rect rect = Rect(0, 0, Image->width, Image->height);
// Convert Image to a matrix
Mat ImageMat = Mat(Image);
// Create and initialize the Histogram
Mat hsv, mask, hue, hist, histimg = Mat::zeros(200, 320, CV_8UC3);
cvtColor(ImageMat, hsv, CV_BGR2HSV);
// Create and adjust the histogram values
inRange(hsv, Scalar(0, smin, vmin), Scalar(180, 256, vmax), mask);
int ch[] = {0, 0};
hue.create(hsv.size(), hsv.depth());
mixChannels(&hsv, 1, &hue, 1, ch, 1);
Mat roi(hue, rect), maskroi(mask, rect);
calcHist(&roi, 1, 0, maskroi, hist, 1, &hsize, &phranges);
normalize(hist, hist, 0, 255, CV_MINMAX);
histimg = Scalar::all(0);
int binW = histimg.cols / hsize;
Mat buf(1, hsize, CV_8UC3);
for( int i = 0; i < hsize; i++ )
buf.at<Vec3b>(i) = Vec3b(saturate_cast<uchar>(i*180./hsize), 255, 255);
cvtColor(buf, buf, CV_HSV2BGR);
for( int i = 0; i < hsize; i++ )
{
int val = saturate_cast<int>(hist.at<float>(i)*histimg.rows/255);
rectangle( histimg, Point(i*binW,histimg.rows),
Point((i+1)*binW,histimg.rows - val),
Scalar(buf.at<Vec3b>(i)), -1, 8 );
}
calcBackProject(&hue, 1, 0, hist, backproj, &phranges);
backproj &= mask;
cvReleaseImage(&Image);
return histimg;
}
void Detection(Mat& image, Mat& backproj, Rect& trackWindow)
{
RotatedRect trackBox = CamShift(backproj, trackWindow, TermCriteria( CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1 ));
int test2 = trackWindow.area();
if(trackBox.size.height > 0 && trackBox.size.width > 0)
{
if( trackWindow.area() <= 1 )
{
int cols = backproj.cols, rows = backproj.rows, r = (MIN(cols, rows) + 5)/6;
trackWindow = Rect(trackWindow.x - r, trackWindow.y - r,
trackWindow.x + r, trackWindow.y + r) &
Rect(0, 0, cols, rows);
}
int test = trackBox.size.area();
if(test >= 1)
{
rectangle(image, trackBox.boundingRect(), Scalar(255,0,0), 3, CV_AA);
ellipse( image, trackBox, Scalar(0,0,255), 3, CV_AA );
}
}
}
I've figured out the issue. It had to deal with me not converting the image that I'm checking upon. I had to get histogram data from my colored box and then I had to get the histogram from the image I was using to search.

drawing multiple rectangles with Cairo graphics

I'm trying to write a Cairo program to black-fill the entire image and then draw another rectangle inside of it a different color. Eventually, I'm going to make this a program that generates a .png of the current time that looks like a digital clock. For now, this is where I'm getting hung up.
Here's my code:
#include <stdio.h>
#include <cairo.h>
//on color: 0.6, 1.0, 0
//off color: 0.2, 0.4, 0
int prop_number_width;
int prop_number_height;
int prop_width;
int prop_height;
int prop_space_width;
int prop_space_height;
double width;
double height;
double w_unit;
double h_unit;
void draw_number(cairo_t* cr, int unit_width, int num);
int main(int argc, char** argv) {
/* proportional sizes:
* the widths and heights of the diagram
*/
prop_number_width = 5; //how many spaces the number takes up
prop_number_height = 6;
prop_space_width = 1; //extra width on each side
prop_space_height = 1; //extra height on each side
prop_width = 25 + (2 * prop_space_width); //width of diagram
prop_height = 6 + (2 * prop_space_height); //height of diagram
/* actual sizes:
* the pixel value of different sizes
*/
width = 200.0;
height = 100.0;
w_unit = width / prop_width;
h_unit = height / prop_height;
//begin cairo stuff
cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, (int)width, (int)height);
cairo_t* cr = cairo_create(surface);
//black fill
cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
cairo_rectangle(cr, 0.0, 0.0, width, height); //cr ref, x, y, width, height
cairo_fill_preserve(cr);
//draw numbers from left to right
draw_number(cr, 0, 1);
//draw_number(cr, 6, 3);
//draw_number(cr, 14, 3);
//draw_number(cr, 20, 7);
//draw in colons
cairo_destroy(cr);
cairo_surface_write_to_png(surface, "test.png");
cairo_surface_destroy(surface);
return 0;
}
void draw_number(cairo_t* cr, int unit_width, int num) {
//determine the box size that the number will be drawn in
double box_x = w_unit * (prop_space_width + unit_width);
double box_y = h_unit * prop_space_height;
double box_width = w_unit * prop_number_width;
double box_height = h_unit * prop_number_height;
printf("{box_x: %lf box_y: %lf} {box_width: %lf box_height: %lf}\n", box_x, box_y, box_width, box_height);
cairo_set_source_rgb(cr, 0.2, 0.4, 0);
cairo_rectangle(cr, box_x, box_y, box_width, box_height);
cairo_fill_preserve(cr);
}
The problem is with this code it draws the rectangle to take up the whole image where from the printf's it should only take up a small part. Does anybody know how I can make this rectangle show up as the correct size?
I should have looked at the API more carefully. I needed to do cairo_fill() instead of cairo_fill_preserve(). Apparently, the first call to cairo_fill_preserve() was keeping the original rectangle and always filling that one.

Resources