# PPM Vectors

This is a discussion on PPM Vectors within the C Programming forums, part of the General Programming Boards category; I'm having a rough time trying to make a PPM image of a triangle given three points. If I can ...

1. ## PPM Vectors

I'm having a rough time trying to make a PPM image of a triangle given three points. If I can get the points into vectors, I can just say that

if (((x > AC) && (x < BC) && (x < AB)) && ((y > AB) && (y < AC) && (y < BC)))
make_pixel(purple);
else
make_pixel(black);

I understand how to get the slopes, but how can I form that into vectors? I've tried to get it into y=mx+b format... My three points are

A (400,100)
B (600,240)
C (525,450)

All in a 640 * 480W image.

Really lost here...

2. Is your array to hold the pixels, an array of structs with rows and columns, 640 rows x 480 columns, all able to hold a full pixel (red, green, and blue), so 3 chars?

Is your array to hold the pixels, an array of structs with rows and columns, 640 rows x 480 columns, all able to hold a full pixel (red, green, and blue), so 3 chars?
I believe so, except 640 columns and 480 rows. The background is longer than it is tall.

I meant a vector in the Geometric sense. Like a line segment. If I can print the line segments and just set a pixel 'i' to greater than, less than each vector then I can just use a for loop to fill in the triangle. Or at least, I think I can. My question is either how to (1) code line segments between each point or (2) how to draw a triangle. It isn't a right triangle, so that kinda complicates things.

My dad emailed me something called the Barycentric Coordinate System, but the math is just beyond me.

Barycentric coordinate system - Wikipedia, the free encyclopedia

Barycentric Coordinates, Areal coordinates

4. Since I did most of my beer drinking at home, your dad's Barycentric coordinate system, is well beyond me, also.

I believe I could do it with an array, however. I've drawn triangles with PPM images before, but I just wrote them out from start to finish, directly to the file, which I don't think is workable in your case.

Let me mess with that a bit.

5. This is what I came up with. This is my first time working with PPM files, using an array. Study it at your own risk!!

Code:
#include <stdio.h>
#include <stdlib.h>

#define WIDTH  120
#define HEIGHT 100

typedef struct pixels {
unsigned char r;
unsigned char g;
unsigned char b;
}pxl;

typedef struct points {
int x;
int y;
}point;

void triangles(pxl px[HEIGHT][WIDTH]);
void output(pxl px[][WIDTH],FILE *fp);

int main(void) {
pxl px[HEIGHT][WIDTH]={0};
FILE *fp;
fp=fopen("out.ppm","wb");

if(!fp) {
printf("Error: file failed to open\n");
return 0;
}

triangles(px);
output(px,fp);

system("out.ppm");
return 0;
}

//puts the pixels into the array px[][]
void triangles (pxl px[][WIDTH]) {
int r1,c1,rm; //rm=right margin
point A,B,C;      //where A,B,C are the corners of the triangle
A.y=10;           // A|-----------B
A.x=10;           //  |          /
B.y=10;           //  |         /
B.x=60;           //  |        /
C.y=80;           //  |       /
C.x=10;           //  |      /
//  |     /
//  |    /
//  |   /
//  |  /
//  | /
//  |/
rm=B.x;           //  C
for(r1=A.y;r1<=C.y;r1++) {

for(c1=A.x;c1<=rm;c1++) {

px[r1][c1].r=0;
px[r1][c1].g=255;
px[r1][c1].b=0;
}
rm-=WIDTH/HEIGHT;

}
}
void output(pxl px[][WIDTH],FILE *fp) {
int r,c;

fprintf(fp,"P6\n%d %d %d\n", WIDTH, HEIGHT, 255);

for(r=0;r<HEIGHT;r++) {
for(c=0;c<WIDTH;c++) {
fprintf(fp, "%c%c%c",px[r][c].r,px[r][c].g,px[r][c].b);
}
}
fclose(fp);
}

This is what I came up with. This is my first time working with PPM files, using an array. Study it at your own risk!!

Code:
#include <stdio.h>
#include <stdlib.h>

#define WIDTH  120
#define HEIGHT 100

typedef struct pixels {
unsigned char r;
unsigned char g;
unsigned char b;
}pxl;

typedef struct points {
int x;
int y;
}point;

void triangles(pxl px[HEIGHT][WIDTH]);
void output(pxl px[][WIDTH],FILE *fp);

int main(void) {
pxl px[HEIGHT][WIDTH]={0};
FILE *fp;
fp=fopen("out.ppm","wb");

if(!fp) {
printf("Error: file failed to open\n");
return 0;
}

triangles(px);
output(px,fp);

system("out.ppm");
return 0;
}

//puts the pixels into the array px[][]
void triangles (pxl px[][WIDTH]) {
int r1,c1,rm; //rm=right margin
point A,B,C;      //where A,B,C are the corners of the triangle
A.y=10;           // A|-----------B
A.x=10;           //  |          /
B.y=10;           //  |         /
B.x=60;           //  |        /
C.y=80;           //  |       /
C.x=10;           //  |      /
//  |     /
//  |    /
//  |   /
//  |  /
//  | /
//  |/
rm=B.x;           //  C
for(r1=A.y;r1<=C.y;r1++) {

for(c1=A.x;c1<=rm;c1++) {

px[r1][c1].r=0;
px[r1][c1].g=255;
px[r1][c1].b=0;
}
rm-=WIDTH/HEIGHT;

}
}
void output(pxl px[][WIDTH],FILE *fp) {
int r,c;

fprintf(fp,"P6\n%d %d %d\n", WIDTH, HEIGHT, 255);

for(r=0;r<HEIGHT;r++) {
for(c=0;c<WIDTH;c++) {
fprintf(fp, "%c%c%c",px[r][c].r,px[r][c].g,px[r][c].b);
}
}
fclose(fp);
}
How do you compile that? I tried gcc triangle.c ; ./a.out > out.ppm gave me an error out.ppm not found...

The way we compile PPM images is
gcc *.c
./a.out > *.ppm (this is where you name it whatever you want.)
display *.ppm

This is for a class and I have classmates that frequent these forums, so I'll post my code tomorrow for a future reference for anyone. It's due midnight tonight.

At this point I have it done, and it works, but I'm just curious how yours works.

7. Don't redirect the output - the program makes it's own output file. Just display it. (In Windows you can call system(filename.ext), and if the ext has a program associated with it (in this case a view program [IrfanView], pops up and handles the actual display.)

The actual size of the pic is not known because the background is black in IrvanView, and I left the background in the ppm file black also, so they have no precise separation here.

8. Nice

9. I'm using uBuntu instead of windows, that could be why it laughs at my './a.out' and calls me a retard...

10. The default output from the program IS out.ppm, so you could change that to "triangle.ppm" or some such.

I like Ubuntu (although I have practiced imitating a cussing sailor's vocabulary with it a few times). I program on a Windows PC, however.

The main difference between our programs is mine doesn't do the math yours does. Thank Gawd! :ROFL:

It uses the A,B,&C x and y values so it only colors green pixels within the triangle. (not tested yet, but more or less).

Thanks xArt.

The main difference between our programs is mine doesn't do the math yours does. Thank Gawd! :ROFL:
But your program only works with triangles which have a rectangle between A and B and B must be right of A and C must be below A.
It doesn't work for the points in OP's post[/Edit]

For a more general solution (i.e. no restrictions on the positions of A, B and C) you need the math (e.g. one of these two methods).

Bye, Andreas

12. I found a way to work with area's, to test if a point was inside a triangle or not, so the triangle function became:

Code:
void triangles (pxl px[][WIDTH]) {
int r,c,lox,hix,loy,hiy;
double areaABC,areaPTAB,areaPTBC,areaPTAC,areaPTotal;

point A,B,C;       //where A,B,C are the corners of the triangle
A.y=100;
A.x=400;
B.y=240;
B.x=600;
C.y=450;
C.x=525;

lox=400;
hix=600;
loy=100;
hiy=450;
areaABC = abs((A.x*(B.y - C.y) + B.x*(C.y - A.y) + C.x*(A.y-B.y))/2.0);

printf("areaABC: %.2f \n",areaABC); //getchar();

for(r=hiy;r>=loy;r--) {

for(c=lox;c<=hix;c++) {
areaPTAB= abs((A.x*(B.y-r) + B.x*(r-A.y) + c*(A.y-B.y))/2.0);
areaPTBC= abs((B.x*(C.y-r) + C.x*(r-B.y) + c*(B.y-C.y))/2.0);
areaPTAC= abs((A.x*(C.y-r) + C.x*(r-A.y) + c*(A.y-C.y))/2.0);
areaPTotal=areaPTAB+areaPTBC+areaPTAC;
//printf("areaPTAB: %.2f areaPTBC: %.2f  areaPTAC: %.2f\n",areaPTAB,areaPTBC,areaPTAC);
//printf("areaPTotal: %.2f\n",areaPTotal); //getchar();
if(areaABC>areaPTotal-2.0 && areaABC<areaPTotal+2.0) {
px[r][c].r=0;
px[r][c].g=255;
px[r][c].b=0;
}

}
}
}
Which has a sloppy "fudge" factor necessary - I'm using some int's where I would need doubles in those expressions, apparently.

Despite the arithmetic, it's not too slow.

13. Ha! The bug was abs() -- the little devil!

Code:
//puts the pixels into the array px[][]
void triangles (pxl px[][WIDTH]) {
int r,c, lox,hix,loy,hiy;
double areaABC,areaPTAB,areaPTBC,areaPTAC,areaPTotal;

point A,B,C;       //where A,B,C are the corners of the triangle
A.y=100;
A.x=400;
B.y=240;
B.x=600;
C.y=450;
C.x=525;

lox=400;
hix=600;
loy=100;
hiy=450;
areaABC = (A.x*(B.y - C.y) + B.x*(C.y - A.y) + C.x*(A.y-B.y))/2.0;

printf("areaABC: %.2f \n",areaABC); //getchar();

for(r=hiy;r>=loy;r--) {

for(c=lox;c<=hix;c++) {
areaPTAB= (A.x*(B.y-r) + B.x*(r-A.y) + c*(A.y-B.y))/2.0;
areaPTBC= (B.x*(C.y-r) + C.x*(r-B.y) + c*(B.y-C.y))/2.0;
areaPTAC= (A.x*(C.y-r) + C.x*(r-A.y) + c*(A.y-C.y))/2.0;

if(areaPTAB<0.000) areaPTAB*=-1;
if(areaPTBC<0.000) areaPTBC*=-1;
if(areaPTAC<0.000) areaPTAC*=-1;

areaPTotal=areaPTAB+areaPTBC+areaPTAC;
//printf("areaPTAB: %.2f areaPTBC: %.2f  areaPTAC: %.2f\n",areaPTAB,areaPTBC,areaPTAC);
//printf("areaPTotal: %.2f\n",areaPTotal); //getchar();

if(areaABC==areaPTotal) {
px[r][c].r=0;
px[r][c].g=255;
px[r][c].b=0;
}

}
}
}

14. Okay so I'm doing this as a service to future people with problems coding a triangle in C.. Here is my full code for the program.

I included a .h file for extra credit, I know it was useless in getting the triangle to print but it does make it a little easier to change the points around and see what happens.. There are two files, Shapes.c and Shapes.h

Shapes.c:
Code:
/* ||__This is programming assignment 3__||
||__ Robert Harp CPSC 101 Section 1 __||
||__          **Shapes.c**          __||
||__********************************__||
||__        **Due 03.14.13**        __||
||__ This is a program that creates __||
||__   a PPM image containing an    __||
||__  circle and a purple triangle  __||
++====================================++ */

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<stdbool.h>
#include "Shapes.h"

void make_image(int, int);
void make_pixel(unsigned char, unsigned char, unsigned char);
double area(int, int, int, int, int, int);
bool is_inside(int, int, int, int, int, int, int, int);

/*
*
*/

int main(void)
{
int height, width;

height = 480;
width = 640;

make_image(width, height);
fprintf(stderr, "creating an image with a width %d pixels by a height"
" %d pixels\n", width, height);

return (0);
}

/*
* function to make a PPM header for the file
*/

{
fprintf(stdout,"P6\n%d %d %d\n", width, height, 255);
}

/*
* function to make the image and all of its shapes
*/

void make_image(int width, int height)
{
int x, y; //values respective to each axis

for(y = 1; y <= height; y++)
{
for(x = 1; x <= width; x++)
{ //if <circle>, else if <triangle>, else <background>
if ((((x-CCX) * (x-CCX) + (y-CCY) * (y-CCY)) <= 5625))
{
make_pixel(255,125,1); //Orange circle
}
else
{
if (is_inside(TAX, TAY, TBX, TBY, TCX, TCY, x, y))
{
make_pixel(148, 0, 212); // Purple triangle
}
else
{
make_pixel(0, 0, 0); //Black background
}
}
}
}
}

/*
* Function to print each individual pixel
*/

void make_pixel(unsigned char r, unsigned char g, unsigned char b)
{
printf("%c%c%c", r, g, b);
}

/*
* Function to find the area of each
*/

double area(int x1, int y1, int x2, int y2, int x3, int y3)
{
return abs((x1*(y2-y3) + x2*(y3-y1)+ x3*(y1-y2))/2.0);
}

/*
* A function to check whether point P(x, y) lies inside the triangle formed
* by A(x1, y1), B(x2, y2) and C(x3, y3)
*/

bool is_inside(int x1, int y1, int x2, int y2, int x3, int y3, int x, int y)
{
/* Calculate area of triangle ABC */
double long A = area (x1, y1, x2, y2, x3, y3);

/* Calculate area of triangle PBC */
double long A1 = area (x, y, x2, y2, x3, y3);

/* Calculate area of triangle PAC */
double long A2 = area (x1, y1, x, y, x3, y3);

/* Calculate area of triangle PAB */
double long A3 = area (x1, y1, x2, y2, x, y);

/* Check if sum of A1, A2 and A3 is same as A */
return (A >= A1 + A2 + A3);
}
/*
* Coded by Robbo
*/

And Shapes.h:
Code:
#define CCX 225
#define CCY 175
#define TAX 400
#define TAY 100
#define TBX 600
#define TBY 240
#define TCX 525
#define TCY 450

/*
* To define my #define's
* CCX, CCY - Circle Center X value, Y value, respectively
* TAX, TAY - Triangle Point (A)'s X and Y values, respectively
* TBX, TBY - Triangle Point (B)'s X and Y values, respectively
* TCX, TCY - Triangle Point (C)'s X and Y values, respectively
*/
You are welcome, world.

Do note that in the last line of Shapes.c, the return value of "bool is_inside()" is >= to the sum of the areas. If you have it as ==, you will get a distorted triangle. <= doesn't print a triangle at all.

So if you steal this from the geeksforgeeks.org page like I did, you HAVE to change the last line to >= from == to get a full triangle.

Of course there are other ways to make a triangle, this is just an example to help with site traffic in the coming semesters of CPSC101 students at Clemson.