mirror of
git://projects.qi-hardware.com/ben-scans.git
synced 2024-11-21 21:05:56 +02:00
solidify: fast interactive face to solid converter
This commit is contained in:
parent
d5001c6c4a
commit
5f84394774
13
solidify/Makefile
Normal file
13
solidify/Makefile
Normal file
@ -0,0 +1,13 @@
|
||||
CFLAGS=-Wall -g `pkg-config --cflags gtk+-2.0`
|
||||
LDFLAGS=-lm `pkg-config --libs gtk+-2.0`
|
||||
|
||||
OBJS=array.o face.o level.o solidify.o
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: solidify
|
||||
|
||||
solidify: $(OBJS)
|
||||
|
||||
clean:
|
||||
rm -f $(OBJS)
|
72
solidify/array.c
Normal file
72
solidify/array.c
Normal file
@ -0,0 +1,72 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "array.h"
|
||||
|
||||
|
||||
static void resize(struct array *a,
|
||||
int nx0, int nx1, int ny0, int ny1)
|
||||
{
|
||||
int ox, oy, nx, ny;
|
||||
int n, x, y;
|
||||
int *tmp;
|
||||
|
||||
ox = a->max_x-a->min_x;
|
||||
oy = a->max_y-a->min_y;
|
||||
nx = nx1-nx0;
|
||||
ny = ny1-ny0;
|
||||
if (ox == nx && oy == ny)
|
||||
return;
|
||||
n = (nx+1)*(ny+1);
|
||||
tmp = alloc_size(n*sizeof(int));
|
||||
for (x = 0; x != n; x++)
|
||||
tmp[x] = UNDEF;
|
||||
for (x = a->min_x; x <= a->max_x; x++)
|
||||
for (y = a->min_y; y <= a->max_y; y++)
|
||||
tmp[x-nx0+(nx+1)*(y-ny0)] =
|
||||
a->data[x-a->min_x+(ox+1)*(y-a->min_y)];
|
||||
free(a->data);
|
||||
a->data = tmp;
|
||||
a->min_x = nx0;
|
||||
a->max_x = nx1;
|
||||
a->min_y = ny0;
|
||||
a->max_y = ny1;
|
||||
}
|
||||
|
||||
|
||||
struct array *new_array(void)
|
||||
{
|
||||
struct array *a;
|
||||
|
||||
a = alloc_type(struct array);
|
||||
a->data = NULL;
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
void free_array(struct array *a)
|
||||
{
|
||||
free(a->data);
|
||||
free(a);
|
||||
}
|
||||
|
||||
|
||||
void set(struct array *a, int x, int y, int z)
|
||||
{
|
||||
if (!a->data) {
|
||||
a->min_x = a->max_x = x;
|
||||
a->min_y = a->max_y = y;
|
||||
a->min_z = a->max_z = z;
|
||||
a->data = alloc_type(int);
|
||||
*a->data = z;
|
||||
} else {
|
||||
resize(a,
|
||||
x < a->min_x ? x : a->min_x, x > a->max_x ? x : a->max_x,
|
||||
y < a->min_y ? y : a->min_y, y > a->max_y ? y : a->max_y);
|
||||
if (z < a->min_z)
|
||||
a->min_z = z;
|
||||
if (z > a->max_z)
|
||||
a->max_z = z;
|
||||
a->data[x-a->min_x+(a->max_x-a->min_x+1)*(y-a->min_y)] = z;
|
||||
}
|
||||
}
|
29
solidify/array.h
Normal file
29
solidify/array.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef ARRAY_H
|
||||
#define ARRAY_H
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
#define UNDEF INT_MAX
|
||||
|
||||
|
||||
struct array {
|
||||
int min_x, max_x;
|
||||
int min_y, max_y;
|
||||
int min_z, max_z;
|
||||
int *data; /* NULL if there are no points */
|
||||
};
|
||||
|
||||
|
||||
struct array *new_array(void);
|
||||
void free_array(struct array *a);
|
||||
|
||||
void set(struct array *a, int x, int y, int z);
|
||||
|
||||
|
||||
static inline int get(const struct array *a, int x, int y)
|
||||
{
|
||||
return a->data[(x)-a->min_x+(a->max_x-a->min_x+1)*((y)-a->min_y)];
|
||||
}
|
||||
|
||||
#endif /* ARRAY_H */
|
45
solidify/face.c
Normal file
45
solidify/face.c
Normal file
@ -0,0 +1,45 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "array.h"
|
||||
#include "face.h"
|
||||
|
||||
|
||||
struct face *read_face(const char *name)
|
||||
{
|
||||
FILE *file;
|
||||
struct face *f;
|
||||
float x, y, z;
|
||||
int xi, yi, zi;
|
||||
|
||||
file = strcmp(name, "-") ? fopen(name, "r") : stdin;
|
||||
if (!file) {
|
||||
perror(name);
|
||||
exit(1);
|
||||
}
|
||||
f = alloc_type(struct face);
|
||||
f->a = new_array();
|
||||
|
||||
while (fscanf(file, "%f,%f,%f\r\n", &x, &y, &z) == 3) {
|
||||
/* @@@ hack - should auto-scale */
|
||||
xi = round(x*10.0);
|
||||
yi = round(y*10.0);
|
||||
zi = round(z*40.0);
|
||||
set(f->a, xi, yi, zi);
|
||||
}
|
||||
(void) fclose(file);
|
||||
|
||||
f->sx = f->a->max_x-f->a->min_x+1;
|
||||
f->sy = f->a->max_y-f->a->min_y+1;
|
||||
f->z_ref = (f->a->min_z+f->a->max_z)/2;
|
||||
fprintf(stderr, "%d-%d / %d-%d / %d-%d\n",
|
||||
f->a->min_x, f->a->max_x, f->a->min_y, f->a->max_y,
|
||||
f->a->min_z, f->a->max_z);
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
|
16
solidify/face.h
Normal file
16
solidify/face.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef FACE_H
|
||||
#define FACE_H
|
||||
|
||||
#include "array.h"
|
||||
|
||||
|
||||
struct face {
|
||||
struct array *a;
|
||||
int sx, sy;
|
||||
int z_ref;
|
||||
};
|
||||
|
||||
|
||||
struct face *read_face(const char *name);
|
||||
|
||||
#endif /* FACE_H */
|
139
solidify/level.c
Normal file
139
solidify/level.c
Normal file
@ -0,0 +1,139 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "array.h"
|
||||
#include "face.h"
|
||||
#include "level.h"
|
||||
|
||||
|
||||
static void draw_map(GtkWidget *widget, struct face *f)
|
||||
{
|
||||
int x, y, z;
|
||||
guchar *rgbbuf, *p;
|
||||
|
||||
rgbbuf = p = calloc(f->sx*f->sy, 3);
|
||||
if (!rgbbuf) {
|
||||
perror("calloc");
|
||||
exit(1);
|
||||
}
|
||||
for (y = f->sy-1; y >= 0; y--)
|
||||
for (x = 0; x != f->sx ; x++) {
|
||||
z = get(f->a, x+f->a->min_x, y+f->a->min_y);
|
||||
if (z == UNDEF) {
|
||||
p += 3;
|
||||
continue;
|
||||
}
|
||||
if (z == f->z_ref) {
|
||||
*p++ = 0;
|
||||
*p++ = 0;
|
||||
*p++ = 255;
|
||||
continue;
|
||||
}
|
||||
if (z < f->z_ref) {
|
||||
z = 255.0*(z-f->z_ref)/(f->z_ref-f->a->min_z);
|
||||
*p++ = 255;
|
||||
*p++ = z;
|
||||
*p++ = z;
|
||||
} else {
|
||||
z = 255.0*(f->z_ref-z)/(f->a->max_z-f->z_ref);
|
||||
*p++ = z;
|
||||
*p++ = 255;
|
||||
*p++ = z;
|
||||
}
|
||||
}
|
||||
gdk_draw_rgb_image(widget->window,
|
||||
widget->style->fg_gc[GTK_STATE_NORMAL],
|
||||
0, 0, f->sx, f->sy, GDK_RGB_DITHER_MAX, rgbbuf, f->sx*3);
|
||||
free(rgbbuf);
|
||||
}
|
||||
|
||||
|
||||
static void draw_image(GtkWidget *da, struct face *f)
|
||||
{
|
||||
fprintf(stderr, "%d\n", f->z_ref);
|
||||
draw_map(da, f);
|
||||
}
|
||||
|
||||
|
||||
static gboolean scroll_event(GtkWidget *widget, GdkEventScroll *event,
|
||||
gpointer data)
|
||||
{
|
||||
GtkWidget *da = gtk_bin_get_child(GTK_BIN(widget));
|
||||
struct face *f = data;
|
||||
|
||||
switch (event->direction) {
|
||||
case GDK_SCROLL_UP:
|
||||
if (f->z_ref > f->a->min_z) {
|
||||
f->z_ref--;
|
||||
draw_image(da, f);
|
||||
}
|
||||
break;
|
||||
case GDK_SCROLL_DOWN:
|
||||
if (f->z_ref < f->a->max_z) {
|
||||
f->z_ref++;
|
||||
draw_image(da, f);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* ignore */;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static gboolean expose_event(GtkWidget *widget, GdkEventExpose *event,
|
||||
gpointer user_data)
|
||||
{
|
||||
draw_image(widget, user_data);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static gboolean key_press_event(GtkWidget *widget, GdkEventKey *event,
|
||||
gpointer data)
|
||||
{
|
||||
if (event->keyval == 'q')
|
||||
gtk_main_quit();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static void make_screen(GtkWidget *root, struct face *f)
|
||||
{
|
||||
GtkWidget *evbox, *da;
|
||||
|
||||
da = gtk_drawing_area_new();
|
||||
gtk_widget_set_size_request(da, f->sx, f->sy);
|
||||
evbox = gtk_event_box_new();
|
||||
gtk_container_add(GTK_CONTAINER(evbox), da);
|
||||
gtk_container_add(GTK_CONTAINER(root), evbox);
|
||||
gtk_widget_show_all(root);
|
||||
draw_map(da, f);
|
||||
|
||||
g_signal_connect(G_OBJECT(evbox), "scroll-event",
|
||||
G_CALLBACK(scroll_event), f);
|
||||
g_signal_connect(G_OBJECT(da), "expose-event",
|
||||
G_CALLBACK(expose_event), f);
|
||||
g_signal_connect(G_OBJECT(root), "key-press-event",
|
||||
G_CALLBACK(key_press_event), NULL);
|
||||
}
|
||||
|
||||
|
||||
void level(struct face *f)
|
||||
{
|
||||
GtkWidget *root;
|
||||
|
||||
root = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_position(GTK_WINDOW(root), GTK_WIN_POS_CENTER);
|
||||
|
||||
#if 0
|
||||
/* get root->window */
|
||||
gtk_widget_show_all(root);
|
||||
#endif
|
||||
|
||||
g_signal_connect(G_OBJECT(root), "destroy",
|
||||
G_CALLBACK(gtk_main_quit), NULL);
|
||||
make_screen(root, f);
|
||||
gtk_main();
|
||||
}
|
9
solidify/level.h
Normal file
9
solidify/level.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef LEVEL_H
|
||||
#define LEVEL_H
|
||||
|
||||
#include "face.h"
|
||||
|
||||
|
||||
void level(struct face *f);
|
||||
|
||||
#endif /* LEVEL_H */
|
33
solidify/solidify.c
Normal file
33
solidify/solidify.c
Normal file
@ -0,0 +1,33 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <locale.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "face.h"
|
||||
#include "level.h"
|
||||
|
||||
|
||||
static void usage(const char *name)
|
||||
{
|
||||
fprintf(stderr, "usage: %s top XXXbottomXXX\n", name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct face *top;
|
||||
|
||||
gtk_init(&argc, &argv);
|
||||
switch (argc) {
|
||||
case 2:
|
||||
break;
|
||||
default:
|
||||
usage(*argv);
|
||||
}
|
||||
setlocale(LC_ALL, "C"); /* damage control */
|
||||
top = read_face(argv[1]);
|
||||
level(top);
|
||||
|
||||
return 0;
|
||||
}
|
15
solidify/util.h
Normal file
15
solidify/util.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef UTIL_H
|
||||
#define UTIL_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
#define alloc_size(s) \
|
||||
({ void *alloc_size_tmp = malloc(s); \
|
||||
if (!alloc_size_tmp) \
|
||||
abort(); \
|
||||
alloc_size_tmp; })
|
||||
|
||||
#define alloc_type(t) ((t *) alloc_size(sizeof(t)))
|
||||
|
||||
#endif /* UTIL_H */
|
Loading…
Reference in New Issue
Block a user