Last active
December 26, 2019 22:57
-
-
Save LingDong-/ed7f8b56b74d903afc73fffaf1e2cee0 to your computer and use it in GitHub Desktop.
cli-ptcloud.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// cli-ptcloud.c | |
// - Lingdong Huang 2019 | |
// | |
// View point clouds (.ply format) in commandline | |
// | |
// Dependencies: | |
// - curses (-lcurses, comes with most unix systems) | |
// - rply (http://w3.impa.br/~diego/software/rply/, place in path below: | |
#define RPLY_PATH "include/rply/rply.h" | |
// | |
// Compile: | |
// $ gcc -O3 include/rply/rply.h include/rply/rply.c cli-ptcloud.c -lcurses -lm; mv ./a.out cli-ptcloud | |
// | |
// Usage: | |
// $ ./cli-ptcloud path/to/model.ply | |
// | |
// Controls: | |
// - Keys 0-6 to switch view | |
// - Mouse to rotate the model in 0th (free) view | |
// | |
#include <curses.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <getopt.h> | |
#include <stdint.h> | |
#include <string.h> | |
#include <math.h> | |
#include RPLY_PATH | |
#define M_MOVE 0x8000000 | |
#define LM_CLICK 0x1 | |
#define LM_DRAG 0x80000 | |
#define LM_UP 0x40000 | |
#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) | |
#define MAX(X, Y) (((X) > (Y)) ? (X) : (Y)) | |
#define MAT_IDEN [16]={1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1} | |
#define MAT_ROTX(a) [16]={1,0,0,0, 0,cos(a),-sin(a),0, 0,sin(a),cos(a),0, 0,0,0,1} | |
#define MAT_ROTY(a) [16]={cos(a),0,sin(a),0, 0,1,0,0, -sin(a),0,cos(a),0, 0,0,0,1} | |
#define MAT_ROTZ(a) [16]={cos(a),-sin(a),0,0, sin(a),cos(a),0,0, 0,0,1,0, 0,0,0,1} | |
#define MAT_TRSL(x,y,z) [16]={1,0,0,x, 0,1,0,y, 0,0,1,z, 0,0,0,1} | |
#define MAT_SCAL(x,y,z) [16]={x,0,0,0, 0,y,0,0, 0,0,z,0, 0,0,0,1} | |
#define MAT_MULT(A,B) [16]={(A)[0]*(B)[0]+(A)[1]*(B)[4]+(A)[2]*(B)[8]+(A)[3]*(B)[12],(A)[0]*(B)[1]+(A)[1]*(B)[5]+(A)[2]*(B)[9]+(A)[3]*(B)[13],(A)[0]*(B)[2]+(A)[1]*(B)[6]+(A)[2]*(B)[10]+(A)[3]*(B)[14],(A)[0]*(B)[3]+(A)[1]*(B)[7]+(A)[2]*(B)[11]+(A)[3]*(B)[15],(A)[4]*(B)[0]+(A)[5]*(B)[4]+(A)[6]*(B)[8]+(A)[7]*(B)[12],(A)[4]*(B)[1]+(A)[5]*(B)[5]+(A)[6]*(B)[9]+(A)[7]*(B)[13],(A)[4]*(B)[2]+(A)[5]*(B)[6]+(A)[6]*(B)[10]+(A)[7]*(B)[14],(A)[4]*(B)[3]+(A)[5]*(B)[7]+(A)[6]*(B)[11]+(A)[7]*(B)[15],(A)[8]*(B)[0]+(A)[9]*(B)[4]+(A)[10]*(B)[8]+(A)[11]*(B)[12],(A)[8]*(B)[1]+(A)[9]*(B)[5]+(A)[10]*(B)[9]+(A)[11]*(B)[13],(A)[8]*(B)[2]+(A)[9]*(B)[6]+(A)[10]*(B)[10]+(A)[11]*(B)[14],(A)[8]*(B)[3]+(A)[9]*(B)[7]+(A)[10]*(B)[11]+(A)[11]*(B)[15],(A)[12]*(B)[0]+(A)[13]*(B)[4]+(A)[14]*(B)[8]+(A)[15]*(B)[12],(A)[12]*(B)[1]+(A)[13]*(B)[5]+(A)[14]*(B)[9]+(A)[15]*(B)[13],(A)[12]*(B)[2]+(A)[13]*(B)[6]+(A)[14]*(B)[10]+(A)[15]*(B)[14],(A)[12]*(B)[3]+(A)[13]*(B)[7]+(A)[14]*(B)[11]+(A)[15]*(B)[15]} | |
#define MAT_TFRM(A,v) [3]={((A)[0]*(v)[0]+(A)[1]*(v)[1]+(A)[2]*(v)[2]+(A)[3])/((A)[12]*(v)[0]+(A)[13]*(v)[1]+(A)[14]*(v)[2]+(A)[15]),((A)[4]*(v)[0]+(A)[5]*(v)[1]+(A)[6]*(v)[2]+(A)[7])/((A)[12]*(v)[0]+(A)[13]*(v)[1]+(A)[14]*(v)[2]+(A)[15]),((A)[8]*(v)[0]+(A)[9]*(v)[1]+(A)[10]*(v)[2]+(A)[11])/((A)[12]*(v)[0]+(A)[13]*(v)[1]+(A)[14]*(v)[2]+(A)[15])} | |
#define MAT_PROJ(f,v) [2]={(f)*(v)[0]/(v)[2],(f)*(v)[1]/(v)[2]} | |
#define MAX_W 256 | |
#define MAX_H 218 | |
#define MAX_BINS (MAX_W*MAX_H) | |
#define SHADE_PT " .:;!+*#" | |
#define VMODE_FREE 0 | |
#define VMODE_FRONT 1 | |
#define VMODE_LEFT 2 | |
#define VMODE_RIGHT 3 | |
#define VMODE_TOP 4 | |
#define VMODE_BOTTOM 5 | |
#define VMODE_BACK 6 | |
char* ptbin; | |
float* ptcloud; | |
long ptcloud_idx = 0; | |
long n_vertices = 0; | |
float xmin, xmax, ymin, ymax, zmin, zmax; | |
float xrot, yrot, zrot; | |
int vmode = VMODE_FREE; | |
static int vertex_cb(p_ply_argument argument) { | |
long eol; | |
ply_get_argument_user_data(argument, NULL, &eol); | |
float f = ply_get_argument_value(argument); | |
ptcloud[ptcloud_idx]=f; | |
if (ptcloud_idx % 3 == 0){ | |
xmin = MIN(f,xmin); | |
xmax = MAX(f,xmax); | |
} | |
if (ptcloud_idx % 3 == 1){ | |
ymin = MIN(f,ymin); | |
ymax = MAX(f,ymax); | |
} | |
if (ptcloud_idx % 3 == 2){ | |
zmin = MIN(f,zmin); | |
zmax = MAX(f,zmax); | |
} | |
ptcloud_idx++; | |
return 1; | |
} | |
int load_vertices(char* path){ | |
p_ply ply = ply_open(path, NULL, 0, NULL); | |
if (!ply) return 1; | |
if (!ply_read_header(ply)) return 1; | |
p_ply_element element = NULL; | |
n_vertices = | |
ply_set_read_cb(ply, "vertex", "x", vertex_cb, NULL, 0); | |
ply_set_read_cb(ply, "vertex", "y", vertex_cb, NULL, 0); | |
ply_set_read_cb(ply, "vertex", "z", vertex_cb, NULL, 1); | |
ptcloud = (float *)malloc(n_vertices*3*sizeof(float)); | |
if (!ptcloud){ | |
exit(1); | |
} | |
if (!ply_read(ply)) return 1; | |
ply_close(ply); | |
return 0; | |
} | |
void normalize_ptcloud(){ | |
float s = 2/MAX(MAX(xmax-xmin,ymax-ymin),zmax-zmin); | |
for (long i = 0; i < n_vertices; i++){ | |
ptcloud[i*3+0] = (ptcloud[i*3+0]-xmin)*s-1; | |
ptcloud[i*3+1] = (ptcloud[i*3+1]-ymin)*s-1; | |
ptcloud[i*3+2] = (ptcloud[i*3+2]-zmin)*s-1; | |
} | |
} | |
void print_ptcloud(){ | |
for (long i = 0; i < n_vertices; i++){ | |
printf("[%ld] %f %f %f\n",i,ptcloud[i*3],ptcloud[i*3+1],ptcloud[i*3+2]); | |
} | |
printf("#vertices: %ld.\n",n_vertices); | |
} | |
void draw_ptcloud(){ | |
int W = MIN(COLS,MAX_W); | |
int H = MIN(LINES,MAX_H); | |
for (int i = 0; i < W*H; i++){ | |
ptbin[i] = 0; | |
} | |
int m = MIN(W/2,H); | |
int padx = 0; | |
int pady = 0; | |
if (W/2 > H){ | |
padx = (W/2-H); | |
}else{ | |
pady = (H-W/2)/2; | |
} | |
for (long i = 0; i < n_vertices; i++){ | |
float x = ptcloud[i*3+0]; | |
float y = ptcloud[i*3+1]; | |
float z = ptcloud[i*3+2]; | |
float rotx MAT_ROTX(xrot); | |
float roty MAT_ROTY(yrot); | |
float rotz MAT_ROTZ(zrot); | |
float rotxy MAT_MULT(roty,rotx); | |
float rot MAT_MULT(rotz,rotxy); | |
float trl MAT_TRSL(0,0,10); | |
float tfm MAT_MULT(trl,rot); | |
float v[3] = {x,y,z}; | |
float u MAT_TFRM(tfm,v); | |
float w MAT_PROJ(10,u); | |
int r = round(pady-w[1] * (m/2) + (m/2)); | |
int c = round(padx+w[0] * m + m); | |
if (0 <= c && c < W && 0 <= r && r < H){ | |
ptbin[r*W+c]++; | |
} | |
} | |
for (int i = 0; i < H; i++){ | |
for (int j = 0; j < W; j++){ | |
int n = MIN(7,ptbin[i*W+j]); | |
if (!(i==H-1 && j==W-1)){ | |
mvprintw(i,j,"%c",SHADE_PT[n]); | |
} | |
} | |
} | |
} | |
int mousex; | |
int mousey; | |
void on_keypress(int c){ | |
if (48 <= c && c <= 54){ | |
vmode = c-48; | |
} | |
} | |
void handle_events(){ | |
int c = wgetch(stdscr); | |
if (c == ERR) { | |
}else if (c == KEY_MOUSE) { | |
MEVENT event; | |
if (getmouse(&event) == OK) { | |
mousex = event.x; | |
mousey = event.y; | |
} | |
} else { | |
on_keypress(c); | |
} | |
} | |
void init_curses(){ | |
initscr(); | |
cbreak(); | |
noecho(); | |
keypad(stdscr, TRUE); | |
mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, NULL); | |
mouseinterval(0); | |
curs_set(0); | |
printf("\033[?1003h\n"); // Makes the terminal report mouse movement events | |
} | |
void exit_curses(){ | |
printf("\033[?1003l\n"); // Disable mouse movement events, as l = low | |
endwin(); | |
} | |
int main(int argc, char** argv){ | |
load_vertices(argv[1]); | |
normalize_ptcloud(); | |
print_ptcloud(); | |
ptbin = (char*)malloc(MAX_BINS*sizeof(char)); | |
init_curses(); | |
long frame = 0; | |
char vdesc[10]; | |
for(;;) { | |
int W = MIN(COLS,MAX_W); | |
int H = MIN(LINES,MAX_H); | |
if (frame == 0){ | |
mousex = W/2; | |
mousey = H/2; | |
}else{ | |
handle_events(); | |
} | |
xrot = 0; | |
yrot = 0; | |
zrot = 0; | |
switch(vmode){ | |
/*--*/ case VMODE_FREE: | |
xrot = ((float)mousey/(float)LINES-0.5)*M_PI*2; | |
yrot = ((float)mousex/(float)COLS-0.5)*M_PI*2; | |
strcpy(vdesc,"FREE\0"); | |
break; case VMODE_TOP: | |
xrot = M_PI/2; | |
strcpy(vdesc,"TOP\0"); | |
break; case VMODE_BOTTOM: | |
xrot = -M_PI/2; | |
strcpy(vdesc,"BOTTOM\0"); | |
break; case VMODE_LEFT: | |
yrot = M_PI/2; | |
strcpy(vdesc,"LEFT\0"); | |
break; case VMODE_RIGHT: | |
yrot = -M_PI/2; | |
strcpy(vdesc,"RIGHT\0"); | |
break; case VMODE_FRONT: | |
strcpy(vdesc,"FRONT\0"); | |
break; case VMODE_BACK: | |
yrot = M_PI; | |
strcpy(vdesc,"BACK\0"); | |
break; default:; | |
} | |
draw_ptcloud(); | |
mvprintw(0,0,"MODEL: %s",argv[1]); | |
mvprintw(1,0,"VIEW: (%d) %s",vmode,vdesc); | |
refresh(); | |
frame++; | |
} | |
exit_curses(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment