C Graphics - How to move an object with specific angle - c

I am working on C graphics program, where I will ask for Projection Angle from end user and then will use that angle to launch the rocket from earth (circle) surface.
But I am not able to do so.
Here what I found on google:
x1 = x + cos(angle) * distance;
y1 = y + sin(angle) * distance;
where x1 y1 are the new pixel position for object.
I tried this but it doesn't seem like working. Also I want rocket to move constantly till the end of screen, but the above code will directly print the object from position A to position B.
Complete Program Code
#include <stdio.h>
#include <conio.h>
#include <graphics.h>
#include <dos.h>
#include <math.h>
#include <stdlib.h>
#include <iostream.h>
#define cld cleardevice()
int _moonRadius = 20, _earthRadius = 40, _marsRadius = 25;
void mars () {
setfillstyle(9, BROWN);
setcolor(BROWN);
circle(getmaxx() - 25, 50, _marsRadius);
floodfill(getmaxx() - 27, 52, BROWN);
}
void moon () {
setfillstyle(9, WHITE);
setcolor(WHITE);
circle(getmaxx()/2, getmaxy()/2, _moonRadius);
floodfill(getmaxx()/2, getmaxy()/2, WHITE);
// Moon's gravitational area
setfillstyle(SOLID_FILL, DARKGRAY);
setcolor(DARKGRAY);
circle(getmaxx()/2, getmaxy()/2, _moonRadius * 5);
}
void earth () {
setfillstyle(9, GREEN);
setcolor(GREEN);
circle(40, getmaxy() - 100, _earthRadius);
floodfill(42, getmaxy() - 102, GREEN);
}
void rocket (int x, int y) {
setcolor(WHITE);
rectangle(x, y - 105, x + 70, y - 95);
}
void rocket_clear (int x, int y) {
setcolor(BLACK);
rectangle(x, y - 105, x + 70, y - 95);
}
void main () {
clrscr();
int angle, speed;
printf("Please provide input parameters.");
printf("Enter projection angle (range from 5 to 90)\n");
scanf("%d", &angle);
printf("Enter projection speed (range from 10 to 100)\n");
scanf("%d", &speed);
int gd=DETECT, gm, i, j, k;
initgraph(&gd, &gm, "C:\\TURBOC3\\BGI");
// Planets and rocket
mars();
moon();
earth();
rocket(80, 550); // let say initial pixel position x = 80, y = 550
// Moving the rocket
// Right now its only moving towards horizontal line, with speed implementation
// Now here I want to implement the angle of projection
for (i = 81; i < getmaxx() + 100; i++) {
// Also I am not sure about this loop's final range, should it go to getmaxx() or some other range
rocket(i, 550);
rocket_clear(i - 1, 550); // 550 is hard coded right now, so rocket will move only horizontally
delay(500 / speed);
}
getch();
}
Need your help guys, please.
(For reference: you can also think of a moving bullet from killer position to the position of person with some angle)
Thanks :)

Please read the comments starting with //=====
#include <stdio.h>
#include <conio.h>
#include <graphics.h>
#include <dos.h>
#include <math.h>
#include <stdlib.h>
#include <iostream.h>
#define cld cleardevice()
//===== making these values as constants
static const int _moonRadius = 20, _earthRadius = 40, _marsRadius = 25;
static double projection_angle = 0.0;
void mars () {
setfillstyle(9, BROWN);
setcolor(BROWN);
circle(getmaxx() - _marsRadius, 50, _marsRadius);
floodfill(getmaxx() - 27, 52, BROWN);
}
void moon () {
setfillstyle(9, WHITE);
setcolor(WHITE);
circle(getmaxx()/2, getmaxy()/2, _moonRadius);
floodfill(getmaxx()/2, getmaxy()/2, WHITE);
// Moon's gravitational area
setfillstyle(SOLID_FILL, DARKGRAY);
setcolor(DARKGRAY);
circle(getmaxx()/2, getmaxy()/2, _moonRadius * 5);
}
void earth () {
setfillstyle(9, GREEN);
setcolor(GREEN);
circle(40, getmaxy() - 100, _earthRadius);
floodfill(42, getmaxy() - 102, GREEN);
}
void rocket (int x, int y) {
setcolor(WHITE);
//===== a box of size 10x10
rectangle(x, y, x + 10, y - 10);
}
void rocket_clear (int x, int y) {
setcolor(BLACK);
//===== a box of size 10x10
rectangle(x, y, x + 10, y - 10);
}
void main () {
clrscr();
int angle, speed;
printf("Please provide input parameters.");
printf("Enter projection angle (range from 5 to 90)\n");
scanf("%d", &angle);
//===== angle validation
if (angle < 5 || angle > 90)
{
printf("Please provide angle in range [5, 90]\n");
getch();
return;
}
//===== calculate angle in radians
projection_angle = (angle * 3.14) / 180.0;
printf("projection_angle = %d\n", projection_angle);
printf("Enter projection speed (range from 10 to 100)\n");
scanf("%d", &speed);
//===== speed validation
if (speed < 10 || speed > 100)
{
printf("Please provide speed in range [10, 100]\n");
getch();
return;
}
int gd=DETECT, gm, i, j, k;
initgraph(&gd, &gm, "C:\\TURBOC3\\BGI");
// Planets and rocket
mars();
moon();
earth();
rocket(80, 550); // let say initial pixel position x = 80, y = 550
// Moving the rocket
// Right now its only moving towards horizontal line, with speed implementation
// Now here I want to implement the angle of projection
//===== to store prev position
int prev_i = 0, prev_j = 0;
//===== increments will be constant for a given angle and speed
const int x_inc = cos(projection_angle) * speed;
const int y_inc = sin(projection_angle) * speed;
//===== i and j will be updated with their respective increments
for (i = 90, j = getmaxy() - 100; i < getmaxx() + 100 && j >= -10; i += x_inc, j -= y_inc) {
// Also I am not sure about this loop's final range, should it go to getmaxx() or some other range
//===== clear the previous position
rocket_clear(prev_i, prev_j); // 550 is hard coded right now, so rocket will move only horizontally
//===== draw rocket at current position
rocket(i, j);
//===== make current position as previous position
prev_i = i;
prev_j = j;
//printf("x_inc = %lf, y_inc = %lf\n", cos(projection_angle) * speed, sin(projection_angle) * speed);
delay(500 / speed);
}
getch();
}
Note: You can replace 3.14 with actual Pi. Refer this.

Be sure that you are passing the angle in radians. To convert from degrees: radians=degrees*PI/180 (PI is defined in math.h which should be included by graphics.h) Make sure your variables are doubles.
Next you will probably want to bundle your X/Y coordinates in a struct so you can return the new position from a function:
typedef struct {
double x;
double y
} coord_t;
coord_t new_pos(double x, double y, double distance, double angle_deg) {
coord_t result;
double angle_rad = angle_deg * PI / 180;
result.x = x + cos(angle_rad) * distance;
result.y = y + sin(angle_rad) * distance;
return result;
}
Or you could handle all the angles in radians so the function doesn't have to do the extra calculation.

Related

Scaling a point from one 2d-space to another

The input to my program is a (x, y) integer coordinate inside the blue region of this circle of radius 100. I want to scale the input coordinate from the blue area to the red area, maintaining the the x and y ratios.
(link to the Desmos plot: https://www.desmos.com/calculator/61f4y2r7r4)
I know how to do this with one dimension - this answer gives a good overview on performing linear scaling. I attempted to apply this approach to the x and y axes separately. Here is some example code that I wrote to model the image.
#include <math.h>
#include <stdio.h>
#define RADIUS 100
static int find_point_on_circumference(int val) {
return sqrt(RADIUS * RADIUS - val * val);
}
static int scale(int val, int min_old, int max_old, int min_new, int max_new) {
return (max_old == min_old)
? val
: (((val - min_old) * (max_new - min_new)) / (max_old - min_old) + min_new);
}
int main() {
int x = 15;
int y = 96;
int boundary_old_x = 10;
int boundary_old_y = 10;
int boundary_new_x = 30;
int boundary_new_y = 20;
int new_x = scale(
x,
boundary_old_x,
find_point_on_circumference(y),
boundary_new_x,
find_point_on_circumference(y));
int new_y = scale(
y,
boundary_old_y,
find_point_on_circumference(x),
boundary_new_y,
find_point_on_circumference(x));
if (sqrt(new_x * new_x + new_y * new_y) <= RADIUS) {
printf("SUCCESS\n");
} else {
printf("FAIL\n");
}
return 0;
}
For this particular input, (15, 96), the result is outside of the circle. I can see that the reason for that is that my max-x bound is less than my min-x bound. I'm just not sure how I should be applying this scaling correctly in the first place.

Animating a trajectory of Cannon Shells C-program

I am unable to see what I did wrong with my code. I am supposed to determine the trajectory that two cannon shells will take when fired at 500 m/s at an angle of 50 degrees above the horizontal. One of the shells is assumed to experience no drag and the other experiences a drag coefficient of 0.0001. I was wondering as to why my code wasn't plotting correctly. Any help would be great!
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include "philsplot.h"
// Number of shells
#define N 2
// Defining the value of PI
#define PI 3.1415926535
int main()
{
double xmin, xmax, ymin, ymax, theta = (50 * (PI/180));
int color, style;
double expand;
// philsplot function to open an x-window
open_plot("800x600");
int i,j;
double vx[N], vy[N], x[N], y[N], h, ax[N], ay[N];
h = 0.01;
// philsplot function erases the canvas after flushpoint is called
erase_plot();
// plot using km for distance
xmin = 0; xmax = 1;
ymin = 0; ymax = 1;
expand = 1.1;
color = 1;
// philsplot function to set limits of the plotting canvas
box_plot(xmin,xmax,ymin,ymax,expand,color,"Distance (km)","Height (km)","RRRR","TTTT");
// philsplot function that maps the plotting canvas onto the screen
flush_plot();
style = 2;
color = 3;
expand = 1.0;
// The initial values
for(i=0; i<N; i++) {
// want the initial x-position to be this
x[i] = 0;
// want the initial y-position to be this
y[i] = 0;
// want the initial x-velocity to be this
vx[i] = 0.5*cos(theta);
// want the initial y-velocity to be this
vy[i] = 0.5*sin(theta);
}
for(j=0; j<N-1; j++) {
// Using Euler's method you get this:
ax[j] = (-0.0001) * (0.5) * vx[j];
ay[j] = (-0.00981) - (0.0001) * (0.5) * vy[j];
vx[j] = vx[j] - ax[j] * h;
vy[j] = vy[j] - ay[j] * h;
x[j] = x[j] + vx[j] * h;
y[j] = y[j] + vy[j] * h;
putpoint_plot(x[j],y[j],10, style, color, expand, 1);
flush_plot();
delay_plot(1000);
}
printf("hit enter for next plot: ");
getchar();
return 0;
}

C Mandelbrot Set Coloring

I am working on the following code in C. So far it has all been working and it is zoomed to the correct level, etc, however I am struggling with getting the colors to work as I want. Ideally I would like to end up with something like this regardless of color:
however my program as it is below currently produces something like this:
Therefore, I would appreciate any help I could get with making the colors turn out as I want them to.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define ITERMAX 100.0
#define DIVERGING 1.1
#define XMAX 500
#define YMAX 500
#define COLORINTENSITY 255
/* allow up to ITERMAX feedbacks searching for convergence
for the feedback
z0 = 0 + 0i
znew = z^2 + c
If we have not diverged to distance DIVERGING before ITERMAX feedbacks
we will assume the feedback is convergent at this value of c.
We will report divergence if |z|^2 > DIVERGING
*/
/* We will print color values for each pixel from (0, 0) to (XMAX, YMAX)
The color of pixel (cx, cy) will be set by convergent()
or by divergent()
depending on the convergence or divergence of the feedback
when c = cx + icy
*/
/* The max value of the red, green, or blue component of a color */
void convergent(); /* one color for convergence */
void divergent(); /* a different color for divergence */
void feedback(double *x, double *y, double cx, double cy);
void pixel(char red, char green, char blue);
FILE *fp;
int main()
{
fp = fopen("mandelbrot.ppm", "wb");
double x, y, cx, cy;
int iteration,squarex, squarey, pixelx, pixely;
double grow=1.0;
/* header for PPM output */
fprintf(fp, "P6\n# CREATOR: EK, BB, RPJ via the mandel program\n");
fprintf(fp, "%d %d\n%d\n",XMAX, YMAX, COLORINTENSITY);
for (pixely = 0; pixely < YMAX; pixely++) {
for (pixelx = 0; pixelx < XMAX; pixelx++) {
cx = (((float)pixelx)/((float)XMAX)-0.5)/grow*3.0-0.7;
cy = (((float)pixely)/((float)YMAX)-0.5)/grow*3.0;
x = 0.0; y = 0.0;
for (iteration=1;iteration<ITERMAX;iteration++) {
feedback(&x, &y, cx, cy);
if (x*x + y*y > 100.0) iteration = 1000;
}
if (iteration==ITERMAX) {
iteration = x*x + y*y;
pixel((char) 0, (char) 0, (char) 0);
}
else {
iteration = sqrt(x*x + y*y);
pixel((char) iteration, (char) 0, (char) iteration);
}
}
}
}
void feedback(double *x, double *y, double cx, double cy) {
/* Update x and y according to the feedback equation
xnew = x^2 - y^2 + cx
ynew = 2xy + cy
(these are the real and imaginary parts of the complex equation:
znew = z^2 + c)
*/
double xnew = (*x) * (*x) - (*y) * (*y) + cx;
double ynew = 2 * *x * *y + cy;
*x = xnew;
*y = ynew;
}
void pixel(char red, char green, char blue) {
/* put a r-g-b triple to the standard out */
fputc(red, fp);
fputc(green, fp);
fputc(blue, fp);
}
To fix the banding, you need to iterate over your tables to find your maximum value for the iteration count, then scale your other values to be relative to this max (ie. normalize the values). You may also wish to logarithmically rescale the values to adjust the slope of the color-change.
And you probably don't want to work directly in RGB space. If you define your colors in HSB space, you can set a constant hue and saturation, and vary the brightness proportionally to the normalized iteration counts.

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;

How to generate a set of points that are equidistant from each other and lie on a circle

I am trying to generate an array of n points that are equidistant from each other and lie on a circle in C. Basically, I need to be able to pass a function the number of points that I would like to generate and get back an array of points.
It's been a really long time since I've done C/C++, so I've had a stab at this more to see how I got on with it, but here's some code that will calculate the points for you. (It's a VS2010 console application)
// CirclePoints.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "stdio.h"
#include "math.h"
int _tmain()
{
int points = 8;
double radius = 100;
double step = ((3.14159265 * 2) / points);
double x, y, current = 0;
for (int i = 0; i < points; i++)
{
x = sin(current) * radius;
y = cos(current) * radius;
printf("point: %d x:%lf y:%lf\n", i, x, y);
current += step;
}
return 0;
}
Try something like this:
void make_circle(float *output, size_t num, float radius)
{
size_t i;
for(i = 0; i < num; i++)
{
const float angle = 2 * M_PI * i / num;
*output++ = radius * cos(angle);
*output++ = radius * sin(angle);
}
}
This is untested, there might be an off-by-one hiding in the angle step calculation but it should be close.
This assumes I understood the question correctly, of course.
UPDATE: Redid the angle computation to not be incrementing, to reduce float precision loss due to repeated addition.
Here's a solution, somewhat optimized, untested. Error can accumulate, but using double rather than float probably more than makes up for it except with extremely large values of n.
void make_circle(double *dest, size_t n, double r)
{
double x0 = cos(2*M_PI/n), y0 = sin(2*M_PI/n), x=x0, y=y0, tmp;
for (;;) {
*dest++ = r*x;
*dest++ = r*y;
if (!--n) break;
tmp = x*x0 - y*y0;
y = x*y0 + y*x0;
x = tmp;
}
}
You have to solve this in c language:
In an x-y Cartesian coordinate system, the circle with centre coordinates (a, b) and radius r is the set of all points (x, y) such that
(x - a)^2 + (y - b)^2 = r^2
Here's a javascript implementation that also takes an optional center point.
function circlePoints (radius, numPoints, centerX, centerY) {
centerX = centerX || 0;
centerY = centerY || 0;
var
step = (Math.PI * 2) / numPoints,
current = 0,
i = 0,
results = [],
x, y;
for (; i < numPoints; i += 1) {
x = centerX + Math.sin(current) * radius;
y = centerY + Math.cos(current) * radius;
results.push([x,y]);
console.log('point %d # x:%d, y:%d', i, x, y);
current += step;
}
return results;
}

Resources