What does the variable D do inside the while in this Bresenham's line drawing algorithm? - c

I've found this Generalized Bresenham's Line Drawing Algorithm and I'm having a hard time understanding what the while is doing here.
Any help is greatly appreciated.
the code:
#define sign(x) ((x > 0)? 1 : ((x < 0)? -1: 0))
x = x1;
y = y1;
dx = abs(x2 - x1);
dy = abs(y2 - y1);
s1 = sign(x2 - x1);
s2 = sign(y2 - y1);
swap = 0;
if (dy > dx) {
temp = dx;
dx = dy;
dy = temp;
swap = 1;
}
D = 2*dy - dx;
for (i = 0; i < dx; i++) {
display_pixel (x, y);
while (D >= 0) {
D = D - 2*dx;
if (swap)
x += s1;
else
y += s2;
}
D = D + 2*dy;
if (swap)
y += s2;
else
x += s1;
}

D is the scaled distance from the line to the candidate x, y coordinate.
Better: D is scaled difference of the distance from the line to the candidates x+1, y+0 and x+1, y+1.
That is, as x increments, the sign of D indicates should the closer y increment by 0 or 1?
(The role of x, y interchanges depending on which octant the algorithm is applied.)
I expected while (D >= 0) { as if (D >= 0) {. Bresenham's line algorithm
Note that OP's code is subject to overflow in abs(x2 - x1) and 2*dy - dx. Alternates exist that do not rely on wider math.

Related

Is there some way to have y = k*m but in integers only?

I'm trying to write out pixles on a LCD. I'm plotting them at X, Y coordinates and I'm using this code:
void SSD1306_draw_line(uint8_t x0, uint8_t x1, uint8_t y0, uint8_t y1){
uint8_t k = (x1 - x0)/(y1 - y0);
uint8_t y = y0;
for(uint8_t x = x0; x < x1; x++){
pixel(x, y, true);
y += k;
}
}
The problem where is that if k becomes a decimal number e.g 1.98, then k will still 1. If k = 2.01, then k = 2 due to the uint8_t datatype.
Assume that we are going to plot the line (0,0), (40, 20) {x,y}.
Sure, now k will be 2. That works!
But assume that if we plot the line (0,0), (35, 20) {x,y}.
Now k will be a float number of 1.75. This will not work for me.
Is there a way to find a better k?
I have tried this, but the line does not follow the coordinates.
void SSD1306_draw_line(uint8_t x0, uint8_t x1, uint8_t y0, uint8_t y1){
float k = 0;
if(y1 > x1){
k = (y1 - y0)/(x1 - x0);
}else{
k = (x1 - x0)/(y1 - y0);
}
float y = y0;
for(uint8_t x = x0; x < x1; x++){
pixel(x, (uint8_t) y, true);
y += k;
}
}
Instead of attempting FP math, research Bresenham's line algorithm for an all integer solution.
Untested code:
void SSD1306_draw_line(uint8_t x0, uint8_t x1, uint8_t y0, uint8_t y1) {
int dx = x1 - x0;
int dy = y1 - y0;
int D = 2*dy - dx;
int y = y0;
// code still needs work when x0 > x1 or |dy| > |dx|
for (int x = x0; x <= x1; x++) {
pixel(x,y,true);
if (D > 0) {
y++;
D = D - 2*dx;
}
D = D + 2*dy;
}
}
You were on the right path with changing k and y to data type float.
But in addition to that, you need to make sure that the right hand side of
k = (y1 - y0)/(x1 - x0);
will be a float value, too. Currently, since only integral values are involved, the result of the expression on the right hand side will be integral. So k will never receive any fractional part.
To "enforce" floating point division, it is sufficient that one of the operands is of type float. You can achieve this by an explicit cast. Write, for example:
k = ((float)(y1 - y0))/(x1 - x0);

Can this line drawing algorithm be optimized? - SDL

For a project I have been working on, the ability to draw lines with a gradient (I.E. they change color over the interval they are drawn) would be very useful. I have an algorithm for this, as I will paste below, but it turns out to be DREADFULLY slow. I'm using the Bresenham algorithm to find each point, but I fear that I have reached the limits of software rendering. I've been using SDL2 thus far, and my line drawing algorithm appears 200x slower than SDL_RenderDrawLine. This is an estimate, and gathered from comparing the two functions' times to draw 10,000 lines. My function would take near 500ms, and SDL_RenderDrawLine did it in 2-3ms on my machine. I even tested the functions with horizontal lines to ensure it wasn't just a botched Bresenham algorithm, and similar slowness hatched. Unfortunately, SDL doesn't have an API for drawing lines with a gradient (or if it does, I'm blind). I knew that any software rendering would be significantly slower than hardware, but the shear magnitude of slowness caught me by surprise. Is there a method that can be used to speed this up? Have I just botched the drawing system beyond reason? I've considered saving an array of the pixels I wish to draw and then shoving them to the screen all at once, but I don't know how to do this with SDL2 and I can't seem to find the API in the wiki or documentation that allows for this. Would that even be faster?
Thanks for the consideration!
void DRW_LineGradient(SDL_Renderer* rend, SDL_Color c1, int x1, int y1, SDL_Color c2, int x2, int y2){
Uint8 tmpr, tmpg, tmpb, tmpa;
SDL_GetRenderDrawColor(rend, &tmpr, &tmpg, &tmpb, &tmpa);
int dy = y2 - y1;
int dx = x2 - x1;
/* Use doubles for a simple gradient */
double d = (abs(x1 - x2) > abs(y1 - y2) ? abs(x1 - x2) : abs(y1 - y2));
double dr = (c2.r - c1.r) / d;
double dg = (c2.g - c1.g) / d;
double db = (c2.b - c1.b) / d;
double da = (c2.a - c1.a) / d;
double r = c1.r, g = c1.g, b = c1.b, a = c1.a;
/* The line is vertical */
if (dx == 0) {
int y;
if (y2 >= y1) {
for (y = y1; y <= y2; y++) {
SDL_SetRenderDrawColor(rend, r, g, b, a);
SDL_RenderDrawPoint(rend, x1, y);
r += dr;
g += dg;
b += db;
a += da;
}
return;
}
else{
for (y = y1; y >= y2; y--) {
SDL_SetRenderDrawColor(rend, r, g, b, a);
SDL_RenderDrawPoint(rend, x1, y);
r += dr;
g += dg;
b += db;
a += da;
}
return;
}
}
/* The line is horizontal */
if (dy == 0) {
int x;
if (x2 >= x1) {
for (x = x1; x <= x2; x++) {
SDL_SetRenderDrawColor(rend, r, g, b, a);
SDL_RenderDrawPoint(rend, x, y1);
r += dr;
g += dg;
b += db;
a += da;
}
return;
}
else{
for (x = x1; x >= x2; x--) {
SDL_SetRenderDrawColor(rend, r, g, b, a);
SDL_RenderDrawPoint(rend, x, y1);
r += dr;
g += dg;
b += db;
a += da;
}
return;
}
}
/* The line has a slope of 1 or -1 */
if (abs(dy) == abs(dx)) {
int xmult = 1, ymult = 1;
if (dx < 0) {
xmult = -1;
}
if (dy < 0) {
ymult = -1;
}
int x = x1, y = y1;
do {
SDL_SetRenderDrawColor(rend, r, g, b, a);
SDL_RenderDrawPoint(rend, x, y);
x += xmult;
y += ymult;
r += dr;
g += dg;
b += db;
a += da;
} while (x != x2);
return;
}
/* Use bresenham's algorithm to render the line */
int checky = dx >> 1;
int octant = findOctant((Line){x1, y1, x2, y2, dx, dy});
dy = abs(dy);
dx = abs(dx);
x2 = abs(x2 - x1) + x1;
y2 = abs(y2 - y1) + y1;
if (octant == 1 || octant == 2 || octant == 5 || octant == 6) {
int tmp = dy;
dy = dx;
dx = tmp;
}
int x, y = 0;
for (x = 0; x <= dx; x++) {
SDL_SetRenderDrawColor(rend, r, g, b, a);
switch (octant) {
case 0:
SDL_RenderDrawPoint(rend, x + x1, y + y1);
break;
case 1:
SDL_RenderDrawPoint(rend, y + x1, x + y1);
break;
case 2:
SDL_RenderDrawPoint(rend, -y + x1, x + y1);
break;
case 3:
SDL_RenderDrawPoint(rend, -x + x1, y + y1);
break;
case 4:
SDL_RenderDrawPoint(rend, -x + x1, -y + y1);
break;
case 5:
SDL_RenderDrawPoint(rend, -y + x1, -x + y1);
break;
case 6:
SDL_RenderDrawPoint(rend, y + x1, -x + y1);
break;
case 7:
SDL_RenderDrawPoint(rend, x + x1, -y + y1);
break;
default:
break;
}
checky += dy;
if (checky >= dx) {
checky -= dx;
y++;
}
r += dr;
g += dg;
b += db;
a += da;
}
SDL_SetRenderDrawColor(rend, tmpr, tmpg, tmpb, tmpa);
}
SIDE NOTE:
I am reluctant to just move on to using OpenGL 3.0+ (Which I hear SDL2 has support for) because I don't know how to use it. Most tutorials I have found have explained the process of setting up the contexts with SDL and then coloring the screen one solid color, but then stop before explaining how to draw shapes and such. If someone could offer a good place to start learning about this, that would also be extremely helpful.
A lot of the overhead of your function is in repeated calls to SDL_RenderDrawPoint. This is (most likely) a generic function which needs to do the following operations:
check if x and y are in range for your current surface;
calculate the position inside the surface by multiplying y with surface->pitch and x with surface->format->BytesPerPixel;
check the current color model of the surface using SDL_PixelFormat;
convert the provided color to the correct format for this color model.
All of the above must be done for each single pixel. In addition, calling a function in itself is overhead -- small as it may be, it still needs to be done for each separate pixel, even if it is not visible.
You can:
omit x and y range checking if you are sure the line start and end points are always visible;
omit the convert-to-address step by calculating it once for the start of the line, then updating it by adding BytesPerPixel and pitch for a horizontal or vertical movement;
omit the convert-to-color model step by calculating the correct RGB values once (well, for a single color line, at least -- it's a bit harder for a gradient);
omit the function call by inlining the code to set a single pixel inside the line routine.
Another -- smaller -- issue: you call your own routine "Bresenham's ... but it isn't. Bresenham's optimization is actually that it avoids double calculations entirely (and its strongest point is that it still gives the mathematically correct output; something I would not count on when using double variables...).
The following routine does not check for range, color model, color values, or (indeed) if the surface should be locked. All of these operations should be ideally done outside the tight drawing loop. As it is, it assumes a 24-bit RGB color screen, with the Red byte first. [*]
I wrote this code for my current SDL environs, which is still SDL-1.0, but it should work for newer versions as well.
It is possible to use Bresenham's calculations for the delta-Red, delta-Green, and delta-Blue values as well, but I deliberately omitted them here :) They would add a lot of extra variables -- at a guess, three per color channel --, extra checks, and, not least of all, not really a visibly better quality. The difference between two successive values for Red, say 127 and 128, are usually too small to notice in a single pixel wide line. Besides, this small step would only occur if your line is at least 256 pixels long and you cover the entire range of Red from 0 to 255 in the gradient.
[*] If you are 100% sure you are targeting a specific screen model with your own program, you can use this (adjusted for that particular screen model, of course). It's feasible to target a couple of different screen models as well; write a customized routine for each, and use a function pointer to call the correct one.
Most likely this is how SDL_RenderDrawLine is able to squeeze out every millisecond of performance. Well worth writing all that code for a library (which will be used on a wide variety of screen set-ups), but most likely not for a single program such as yours. Notice I commented out a single range check, which falls back to a plain line routine if necessary. You could do the same for unusual or unexpected screen set-ups, and in that case simply call your own, slower, drawing routine. (Your routine is more robust as it uses SDL's native routines.)
The original line routine below was copied from The Internet more than a single decade ago, as I have been using it for ages. I'd gladly attribute it to someone; if anybody recognizes the comments (they are mostly as appeared in the original code), do post a comment.
void gradient_line (int x1,int y1,int x2,int y2,
int r1,int g1, int b1,
int r2,int g2, int b2)
{
int d; /* Decision variable */
int dx,dy; /* Dx and Dy values for the line */
int Eincr,NEincr; /* Decision variable increments */
int t; /* Counters etc. */
unsigned char *ScrPos;
int LineIncr;
int rd,gd,bd;
if (x1 < 0 || y1 < 0 || x2 < 0 || y2 < 0 ||
x1 >= SCREEN_WIDE || x2 >= SCREEN_WIDE ||
y1 >= SCREEN_HIGH || y2 >= SCREEN_HIGH)
{
line (x1,y1, x2,y2, (r1<<16)+(g1<<8)+b1);
return;
}
rd = (r2-r1)<<8;
gd = (g2-g1)<<8;
bd = (b2-b1)<<8;
dx = x2 - x1;
if (dx < 0)
dx = -dx;
dy = y2 - y1;
if (dy < 0)
dy = -dy;
if (dy <= dx)
{
/* We have a line with a slope between -1 and 1
*
* Ensure that we are always scan converting the line from left to
* right to ensure that we produce the same line from P1 to P0 as the
* line from P0 to P1.
*/
if (x2 < x1)
{
t = x2; x2 = x1; x1 = t; /* Swap X coordinates */
t = y2; y2 = y1; y1 = t; /* Swap Y coordinates */
/* Swap colors */
r1 = r2;
g1 = g2;
b1 = b2;
rd = -rd;
gd = -gd;
bd = -bd;
}
r1 <<= 8;
g1 <<= 8;
b1 <<= 8;
if (y2 > y1)
{
LineIncr = screen->pitch;
} else
{
LineIncr = -screen->pitch;
}
d = 2*dy - dx; /* Initial decision variable value */
Eincr = 2*dy; /* Increment to move to E pixel */
NEincr = 2*(dy - dx); /* Increment to move to NE pixel */
ScrPos = (unsigned char *)(screen->pixels+screen->pitch*y1+x1*screen->format->BytesPerPixel);
rd /= dx;
gd /= dx;
bd /= dx;
/* Draw the first point at (x1,y1) */
ScrPos[0] = r1 >> 8;
ScrPos[1] = g1 >> 8;
ScrPos[2] = b1 >> 8;
r1 += rd;
g1 += gd;
b1 += bd;
/* Incrementally determine the positions of the remaining pixels */
for (x1++; x1 <= x2; x1++)
{
if (d < 0)
{
d += Eincr; /* Choose the Eastern Pixel */
} else
{
d += NEincr; /* Choose the North Eastern Pixel */
ScrPos += LineIncr;
}
ScrPos[0] = r1>>8;
ScrPos[1] = g1>>8;
ScrPos[2] = b1>>8;
ScrPos += screen->format->BytesPerPixel;
r1 += rd;
g1 += gd;
b1 += bd;
}
} else
{
/* We have a line with a slope between -1 and 1 (ie: includes
* vertical lines). We must swap our x and y coordinates for this.
*
* Ensure that we are always scan converting the line from left to
* right to ensure that we produce the same line from P1 to P0 as the
* line from P0 to P1.
*/
if (y2 < y1)
{
t = x2; x2 = x1; x1 = t; /* Swap X coordinates */
t = y2; y2 = y1; y1 = t; /* Swap Y coordinates */
/* Swap colors */
r1 = r2;
g1 = g2;
b1 = b2;
rd = -rd;
gd = -gd;
bd = -bd;
}
r1 <<= 8;
g1 <<= 8;
b1 <<= 8;
if (x2 > x1)
{
LineIncr = screen->format->BytesPerPixel;
} else
{
LineIncr = -screen->format->BytesPerPixel;
}
d = 2*dx - dy; /* Initial decision variable value */
Eincr = 2*dx; /* Increment to move to E pixel */
NEincr = 2*(dx - dy); /* Increment to move to NE pixel */
rd /= dy;
gd /= dy;
bd /= dy;
/* Draw the first point at (x1,y1) */
ScrPos = (unsigned char *)(screen->pixels+screen->pitch*y1+x1*screen->format->BytesPerPixel);
ScrPos[0] = r1 >> 8;
ScrPos[1] = g1 >> 8;
ScrPos[2] = b1 >> 8;
r1 += rd;
g1 += gd;
b1 += bd;
/* Incrementally determine the positions of the remaining pixels
*/
for (y1++; y1 <= y2; y1++)
{
ScrPos += screen->pitch;
if (d < 0)
{
d += Eincr; /* Choose the Eastern Pixel */
} else
{
d += NEincr; /* Choose the North Eastern Pixel */
ScrPos += LineIncr; /* (or SE pixel for dx/dy < 0!) */
}
ScrPos[0] = r1 >> 8;
ScrPos[1] = g1 >> 8;
ScrPos[2] = b1 >> 8;
r1 += rd;
g1 += gd;
b1 += bd;
}
}
}
.. and this is a section of a screenful of random lines with random colors, with on the right a close-up:
I did not time the difference between "native" SDL line drawing, your naive method, a pure solid color Bresenham's implementation and this one; then again, this ought not be very much slower than an SDL native line.

Point on a straight line specific distance away in C

How do I find the point on the straight line that is specific distance away from a given point. I am writing this code in C but I do not get the right answer..Could you anyone guide me on what I am doing wrong.
I get the x1,y1,x2,y2 values and the distance left fine. Using these I can find the slope m and the y-intercept also fine.
Now, I need to find the point on the straight line connecting these two points that is 10 units away from the point x1,y1. I seem to be going wrong here. here's the code that I wrote.
int x1 = node[n].currentCoordinates.xCoordinate;
int y1 = node[n].currentCoordinates.yCoordinate;
int x2 = node[n].destinationLocationCoordinates.xCoordinate;
int y2 = node[n].destinationLocationCoordinates.yCoordinate;
int distanceleft = (y2 - y1) * (y2 - y1) + (x2 - x1) * (x2 - x1);
distanceleft = sqrt(distanceleft);
printf("Distance left to cover is %d\n",distanceleft);
int m = (y2 - y1)/(x2 - x1); // slope.
int b = y1 - m * x1; //y-intercept
//find point on the line that is 10 units away from
//current coordinates on equation y = mx + b.
if(x2 > x1)
{
printf("x2 is greater than x1\n");
int tempx = 0;
int tempy = 0;
for(tempx = x1; tempx <= x2; tempx++)
{
tempy = y1 + (y2 - y1) * (tempx - x1)/(x2 - x1);
printf("tempx = %d, tempy = %d\n",tempx,tempy);
int distanceofthispoint = (tempy - y1) * (tempy - y1) + (tempx - x1) * (tempx - x1);
distanceofthispoint = sqrt((int)distanceofthispoint);
if(distanceofthispoint >= 10)
{
//found new points.
node[n].currentCoordinates.xCoordinate = tempx;
node[n].currentCoordinates.yCoordinate = tempy;
node[n].TimeAtCurrentCoordinate = clock;
printf("Found the point at the matching distance\n");
break;
}
}
}
else
{
printf("x2 is lesser than x1\n");
int tempx = 0;
int tempy = 0;
for(tempx = x1; tempx >= x2; tempx--)
{
tempy = y1 + (y2 - y1) * (tempx - x1)/(x2 - x1);
printf("tempx = %d, tempy = %d\n",tempx,tempy);
int distanceofthispoint = (tempy - y1) * (tempy - y1) + (tempx - x1) * (tempx - x1);
distanceofthispoint = sqrt((int)distanceofthispoint);
if(distanceofthispoint >= 10)
{
//found new points.
node[n].currentCoordinates.xCoordinate = tempx;
node[n].currentCoordinates.yCoordinate = tempy;
node[n].TimeAtCurrentCoordinate = clock;
printf("Found the point at the matching distance\n");
break;
}
}
}
printf("at time %f, (%d,%d) are the coordinates of node %d\n",clock,node[n].currentCoordinates.xCoordinate,node[n].currentCoordinates.yCoordinate,n);
Here is how it is in math, I don't have time to write something in C.
You have a point (x1,y1) and another one (x2,y2), when linked it gives you a segment.
Thus you have a directional vector v=(xv, yv) where xv=x2-x1 and yv=y2-y1.
Now, you need to divide this vector by its norm, you get a new vector: vector = v / sqrt(xv2 + yv2).
Now, you just have to add to your origin point the vector multiplied by the distance at which you want your point:
Position = (x origin, y origin) + distance × vector
I hope this helps!
Or simpler,
Find the angle from the slope
θ = arctan(y2-y1/x2-x1)
You might want to modify the quadrant of θ based on the numerator and denominator of the slope. Then you can find any point on the line at distance d from (x1, y1)
x_new = x1 + d×cos(θ)
y_new = y1 + d×sin(θ)
In this case, you have d=10

Rotating a 2d array -> reversing a loop

I use the following code to rotate a bitmask (a packed 2d array). To be honest I do not have a firm grip of the algorithm used, I copied and modified the rotation code from the pygame library (where it was used to rotate surfaces). Due to the implementation of bitmask I can speed this rotation up a lot by reversing the inner loop. With that I mean, instead of doing foreach y { foreach x { ... } } I need to do foreach x { foreach y { ... } }. I have trouble reversing the loop because the trigonometry has to be adapted in a way I don't currently see at this moment.
Here's the code:
typedef struct bitmask {
int w,h;
BITMASK_W bits[1];
} bitmask_t;
bitmask_t* bitmask_rotate(const bitmask_t *mask, float angle) {
bitmask_t *newmask = NULL;
double radangle, sangle, cangle;
int isin, icos;
double cx, cy, sx, sy;
int x, y, ax, ay, xd, yd, dx, dy;
int nxmax, nymax, xmaxval, ymaxval;
radangle = angle * DEG_TO_RAD;
sangle = sin(radangle);
cangle = cos(radangle);
isin = (int)(sangle * 65536);
icos = (int)(cangle * 65536);
x = mask->w;
y = mask->h;
cx = cangle*x;
cy = cangle*y;
sx = sangle*x;
sy = sangle*y;
nxmax = (int) (MAX (MAX (MAX (fabs (cx + sy), fabs (cx - sy)), fabs (-cx + sy)), fabs (-cx - sy)));
nymax = (int) (MAX (MAX (MAX (fabs (sx + cy), fabs (sx - cy)), fabs (-sx + cy)), fabs (-sx - cy)));
newmask = bitmask_create(nxmax, nymax, 0);
if (!newmask) return NULL;
cy = newmask->h / 2;
xd = ((mask->w - newmask->w) << 15);
yd = ((mask->h - newmask->h) << 15);
ax = ((newmask->w) << 15) - (int)(cangle * ((newmask->w - 1) << 15));
ay = ((newmask->h) << 15) - (int)(sangle * ((newmask->w - 1) << 15));
xmaxval = ((mask->w) << 16) - 1;
ymaxval = ((mask->h) << 16) - 1;
for (y = 0; y < newmask->h; y++) {
dx = (ax + (isin * (cy - y))) + xd;
dy = (ay - (icos * (cy - y))) + yd;
for (x = 0; x < newmask->w; x++) {
if (!(dx < 0 || dy < 0 || dx > xmaxval || dy > ymaxval)) {
if (bitmask_getbit(mask, dx >> 16, dy >> 16)) {
bitmask_setbit(newmask, x, y);
}
}
dx += icos;
dy += isin;
}
}
return newmask;
}
Before people are going to ask "what have you tried?", I looped up rotating matrices on Wikipedia, and I could see what is going on there and how they implemented it in this algorithm (precalculate a starting dx and dy and then increment with icos and isin), but the bitshifts and parameters I don't understand (ax for example) make it hard for me to follow.
for (x = 0; x < newmask->w; x++) {
dx = (ax + (isin * cy + icos * x)) + xd;
dy = (ay - (icos * cy - isin * x)) + yd;
for (y = 0; y < newmask->h; y++) {
if (!(dx < 0 || dy < 0 || dx > xmaxval || dy > ymaxval)) {
if (bitmask_getbit(mask, dx >> 16, dy >> 16)) {
bitmask_setbit(newmask, x, y);
}
}
dx -= isin;
dy += icos;
}
}

Detecting if angle is more than 180 degrees

I'm working on a problem that the professor assigned, and I'm having a problem looking for a way to detect if the angle between 3 points is more than 180 degrees, e.g:
I want to detect if alpha is more than 180 degrees. Anyways, my professor has a code that solves the problem, but he has a function called zcross, but I don't exactly know how it works. Could anyone tell me? His code is here:
#include <fstream.h>
#include <math.h>
#include <stdlib.h>
struct point {
double x;
double y;
double angle;
};
struct vector {
double i;
double j;
};
point P[10000];
int hull[10000];
int
zcross (vector * u, vector * v)
{
double p = u->i * v->j - v->i * u->j;
if (p > 0)
return 1;
if (p < 0)
return -1;
return 0;
}
int
cmpP (const void *a, const void *b)
{
if (((point *) a)->angle < ((point *) b)->angle)
return -1;
if (((point *) a)->angle > ((point *) b)->angle)
return 1;
return 0;
}
void
main ()
{
int N, i, hullstart, hullend, a, b;
double midx, midy, length;
vector v1, v2;
ifstream fin ("fc.in");
fin >> N;
midx = 0, midy = 0;
for (i = 0; i < N; i++) {
fin >> P[i].x >> P[i].y;
midx += P[i].x;
midy += P[i].y;
}
fin.close ();
midx = (double) midx / N;
midy = (double) midy / N;
for (i = 0; i < N; i++)
P[i].angle = atan2 (P[i].y - midy, P[i].x - midx);
qsort (P, N, sizeof (P[0]), cmpP);
hull[0] = 0;
hull[1] = 1;
hullend = 2;
for (i = 2; i < N - 1; i++) {
while (hullend > 1) {
v1.i = P[hull[hullend - 2]].x - P[hull[hullend - 1]].x;
v1.j = P[hull[hullend - 2]].y - P[hull[hullend - 1]].y;
v2.i = P[i].x - P[hull[hullend - 1]].x;
v2.j = P[i].y - P[hull[hullend - 1]].y;
if (zcross (&v1, &v2) < 0)
break;
hullend--;
}
hull[hullend] = i;
hullend++;
}
while (hullend > 1) {
v1.i = P[hull[hullend - 2]].x - P[hull[hullend - 1]].x;
v1.j = P[hull[hullend - 2]].y - P[hull[hullend - 1]].y;
v2.i = P[i].x - P[hull[hullend - 1]].x;
v2.j = P[i].y - P[hull[hullend - 1]].y;
if (zcross (&v1, &v2) < 0)
break;
hullend--;
}
hull[hullend] = i;
hullstart = 0;
while (true) {
v1.i = P[hull[hullend - 1]].x - P[hull[hullend]].x;
v1.j = P[hull[hullend - 1]].y - P[hull[hullend]].y;
v2.i = P[hull[hullstart]].x - P[hull[hullend]].x;
v2.j = P[hull[hullstart]].y - P[hull[hullend]].y;
if (hullend - hullstart > 1 && zcross (&v1, &v2) >= 0) {
hullend--;
continue;
}
v1.i = P[hull[hullend]].x - P[hull[hullstart]].x;
v1.j = P[hull[hullend]].y - P[hull[hullstart]].y;
v2.i = P[hull[hullstart + 1]].x - P[hull[hullstart]].x;
v2.j = P[hull[hullstart + 1]].y - P[hull[hullstart]].y;
if (hullend - hullstart > 1 && zcross (&v1, &v2) >= 0) {
hullstart++;
continue;
}
break;
}
length = 0;
for (i = hullstart; i <= hullend; i++) {
a = hull[i];
if (i == hullend)
b = hull[hullstart];
else
b = hull[i + 1];
length += sqrt ((P[a].x - P[b].x) * (P[a].x - P[b].x) + (P[a].y - P[b].y) * (P[a].y - P[b].y));
}
ofstream fout ("fc.out");
fout.setf (ios: :fixed);
fout.precision (2);
fout << length << '\n';
fout.close ();
}
First, we know that if sin(a) is negative, then the angle is more than 180 degrees.
How do we find the sign of sin(a)? Here is where cross product comes into play.
First, let's define two vectors:
v1 = p1-p2
v2 = p3-p2
This means that the two vectors start at p2 and one points to p1 and the other points to p3.
Cross product is defined as:
(x1, y1, z1) x (x2, y2, z2) = (y1z2-y2z1, z1x2-z2x1, x1y2-x2y1)
Since your vectors are in 2d, then z1 and z2 are 0 and hence:
(x1, y1, 0) x (x2, y2, 0) = (0, 0, x1y2-x2y1)
That is why they call it zcross because only the z element of the product has a value other than 0.
Now, on the other hand, we know that:
||v1 x v2|| = ||v1|| * ||v2|| * abs(sin(a))
where ||v|| is the norm (size) of vector v. Also, we know that if the angle a is less than 180, then v1 x v2 will point upwards (right hand rule), while if it is larger than 180 it will point down. So in your special case:
(v1 x v2).z = ||v1|| * ||v2|| * sin(a)
Simply put, if the z value of v1 x v2 is positive, then a is smaller than 180. If it is negative, then it's bigger (The z value was x1y2-x2y1). If the cross product is 0, then the two vectors are parallel and the angle is either 0 or 180, depending on whether the two vectors have respectively same or opposite direction.
zcross is using the sign of the vector cross product (plus or minus in the z direction) to determine if the angle is more or less than 180 degrees, as you've put it.
In 3D, find the cross product of the vectors, find the minimum length for the cross product which is basically just finding the smallest number of x, y and z.
If the smallest value is smaller than 0, the angle of the vectors is negative.
So in code:
float Vector3::Angle(const Vector3 &v) const
{
float a = SquareLength();
float b = v.SquareLength();
if (a > 0.0f && b > 0.0f)
{
float sign = (CrossProduct(v)).MinLength();
if (sign < 0.0f)
return -acos(DotProduct(v) / sqrtf(a * b));
else
return acos(DotProduct(v) / sqrtf(a * b));
}
return 0.0f;
}
Another way to do it would be as follows:
calculate vector v1=p2-p1, v2 = p2 -p3.
Then, use the cross-product formula : u.v = ||u|| ||v|| cos(theta)

Resources