mirror of
git://projects.qi-hardware.com/cae-tools.git
synced 2024-12-22 18:52:05 +02:00
Initial commit. For older history, see project ben-scans.
http://projects.qi-hardware.com/index.php/p/ben-scans/
This commit is contained in:
commit
e8d6837065
90
solidify/Makefile
Normal file
90
solidify/Makefile
Normal file
@ -0,0 +1,90 @@
|
||||
#
|
||||
# Makefile - Makefile of solidify
|
||||
#
|
||||
# Written 2010 by Werner Almesberger
|
||||
# Copyright 2010 by Werner Almesberger
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
|
||||
SHELL = /bin/bash
|
||||
|
||||
OBJS = array.o face.o histo.o level.o matrix.o overlap.o povray.o project.o \
|
||||
solidify.o style.o util.o
|
||||
|
||||
CFLAGS_WARN = -Wall -Wshadow -Wmissing-prototypes \
|
||||
-Wmissing-declarations -Wno-format-zero-length
|
||||
|
||||
CFLAGS = $(CFLAGS_WARN) -g -O9 `pkg-config --cflags gtk+-2.0`
|
||||
LDFLAGS = -lm `pkg-config --libs gtk+-2.0`
|
||||
|
||||
# ----- Verbosity control -----------------------------------------------------
|
||||
|
||||
CC_normal := $(CC)
|
||||
DEPEND_normal := $(CPP) $(CFLAGS) -MM -MG
|
||||
|
||||
CC_quiet = @echo " CC " $@ && $(CC_normal)
|
||||
DEPEND_quiet = @$(DEPEND_normal)
|
||||
|
||||
ifeq ($(V),1)
|
||||
CC = $(CC_normal)
|
||||
DEPEND = $(DEPEND_normal)
|
||||
else
|
||||
CC = $(CC_quiet)
|
||||
DEPEND = $(DEPEND_quiet)
|
||||
endif
|
||||
|
||||
# ----- Rules -----------------------------------------------------------------
|
||||
|
||||
.PHONY: all clean spotless
|
||||
|
||||
all: solidify
|
||||
|
||||
solidify: $(OBJS)
|
||||
|
||||
clean:
|
||||
rm -f $(OBJS) $(OBJS:.o=.d)
|
||||
|
||||
spotless: clean
|
||||
rm -f solidify
|
||||
|
||||
# ----- Experimental execution ------------------------------------------------
|
||||
|
||||
PRJ=http://projects.qi-hardware.com/index.php/p/ben-scans/source/tree/master
|
||||
DIR=$(PRJ)/data/csv
|
||||
FACE_A=$(DIR)/ben-batcvr-outside-100um.txt.bz2
|
||||
FACE_B=$(DIR)/ben-batcvr-inside-100um.txt.bz2
|
||||
D=1.16
|
||||
|
||||
.PHONY: new run pov disp
|
||||
|
||||
new: solidify
|
||||
rm -f batcvr.sfy
|
||||
./solidify batcvr.sfy $(FACE_A) $(FACE_B) $(D) >batcvr.inc
|
||||
|
||||
run: solidify
|
||||
./solidify batcvr.sfy >batcvr.inc
|
||||
|
||||
pov:
|
||||
povray +A -W1280 -H1024 main.pov
|
||||
|
||||
disp:
|
||||
display main.png
|
||||
|
||||
# ----- Dependencies ----------------------------------------------------------
|
||||
|
||||
# compile and generate dependencies, from fped, based on
|
||||
# http://scottmcpeak.com/autodepend/autodepend.html
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c $(CFLAGS) $*.c -o $*.o
|
||||
$(DEPEND) $*.c | \
|
||||
sed -e \
|
||||
'/^\(.*:\)\? */{p;s///;s/ *\\\?$$/ /;s/ */:\n/g;H;}' \
|
||||
-e '$${g;p;}' -e d >$*.d; \
|
||||
[ "$${PIPESTATUS[*]}" = "0 0" ] || { rm -f $*.d; exit 1; }
|
||||
|
||||
-include $(OBJS:.o=.d)
|
85
solidify/array.c
Normal file
85
solidify/array.c
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* array.c - Growable baseless 2D array
|
||||
*
|
||||
* Written 2010 by Werner Almesberger
|
||||
* Copyright 2010 by Werner Almesberger
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
|
||||
#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;
|
||||
}
|
||||
}
|
52
solidify/array.h
Normal file
52
solidify/array.h
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* array.h - Growable baseless 2D array
|
||||
*
|
||||
* Written 2010 by Werner Almesberger
|
||||
* Copyright 2010 by Werner Almesberger
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#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)];
|
||||
}
|
||||
|
||||
|
||||
static inline int get_bounded(const struct array *a, int x, int y)
|
||||
{
|
||||
if (x < a->min_x || x > a->max_x)
|
||||
return UNDEF;
|
||||
if (y < a->min_y || y > a->max_y)
|
||||
return UNDEF;
|
||||
return get(a, x, y);
|
||||
}
|
||||
|
||||
|
||||
#endif /* !ARRAY_H */
|
204
solidify/face.c
Normal file
204
solidify/face.c
Normal file
@ -0,0 +1,204 @@
|
||||
/*
|
||||
* face.c - Data structure and handling of one face of a part
|
||||
*
|
||||
* Written 2010 by Werner Almesberger
|
||||
* Copyright 2010 by Werner Almesberger
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "array.h"
|
||||
#include "histo.h"
|
||||
#include "face.h"
|
||||
|
||||
|
||||
#define CACHE_DIR ".cache"
|
||||
#define DEFAULT_STEP 1 /* 1 mm */
|
||||
#define MIN_STEP 0.005 /* 5 um */
|
||||
|
||||
|
||||
struct coord {
|
||||
float x, y, z;
|
||||
};
|
||||
|
||||
|
||||
static struct coord *load_file(const char *name)
|
||||
{
|
||||
FILE *file;
|
||||
struct coord *v, *n;
|
||||
int s;
|
||||
|
||||
if (!strcmp(name, "-")) {
|
||||
file = stdin;
|
||||
} else {
|
||||
int len;
|
||||
|
||||
len = strlen(name);
|
||||
if (len > 4 && !strcmp(name+len-4, ".bz2")) {
|
||||
char tmp[1000]; /* @@@ enough */
|
||||
|
||||
sprintf(tmp, "bzcat \"%s\"", name);
|
||||
file = popen(tmp, "r");
|
||||
if (!file) {
|
||||
perror(tmp);
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
file = fopen(name, "r");
|
||||
if (!file) {
|
||||
perror(name);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
v = n = alloc_type(struct coord);
|
||||
s = 1;
|
||||
|
||||
while (fscanf(file, "%f,%f,%f\r\n", &n->x, &n->y, &n->z) == 3) {
|
||||
n++;
|
||||
if (n-v == s) {
|
||||
struct coord *tmp;
|
||||
|
||||
s += s;
|
||||
tmp = realloc(v, sizeof(struct coord)*s);
|
||||
if (!tmp) {
|
||||
perror("realloc");
|
||||
exit(1);
|
||||
}
|
||||
n = n-v+tmp;
|
||||
v = tmp;
|
||||
}
|
||||
}
|
||||
if (file != stdin)
|
||||
(void) fclose(file);
|
||||
|
||||
n->x = n->y = n->z = 0;
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
static void adjust_step(double *step, double delta)
|
||||
{
|
||||
double n = round(delta/MIN_STEP);
|
||||
double s = n*MIN_STEP;
|
||||
|
||||
if (n && s < *step)
|
||||
*step = s;
|
||||
}
|
||||
|
||||
|
||||
static struct face *read_file(const char *name)
|
||||
{
|
||||
struct coord *v, *p;
|
||||
struct face *f;
|
||||
struct histo *h;
|
||||
int xi, yi, zi;
|
||||
|
||||
v = load_file(name);
|
||||
|
||||
f = alloc_type(struct face);
|
||||
f->a = new_array();
|
||||
|
||||
/*
|
||||
* Hack: the MDX-15 measures bumps along the x axis with 25 um
|
||||
* resolution, so we just ignore the x resultion we find and use the
|
||||
* y resolution instead.
|
||||
*/
|
||||
f->x_step = f->y_step =f->z_step = DEFAULT_STEP;
|
||||
for (p = v; p[1].x || p[1].y || p[1].z; p++) {
|
||||
adjust_step(&f->y_step, fabs(p[0].y-p[1].y));
|
||||
adjust_step(&f->z_step, fabs(p[0].z-p[1].z));
|
||||
}
|
||||
f->x_step = f->y_step;
|
||||
|
||||
for (p = v; p->x || p->y || p->z; p++) {
|
||||
xi = round(p->x/f->x_step);
|
||||
yi = round(p->y/f->y_step);
|
||||
zi = round(p->z/f->z_step);
|
||||
set(f->a, xi, yi, zi);
|
||||
}
|
||||
|
||||
free(v);
|
||||
|
||||
f->sx = f->a->max_x-f->a->min_x+1;
|
||||
f->sy = f->a->max_y-f->a->min_y+1;
|
||||
|
||||
f->cx = (f->a->min_x+f->a->max_x)/2;
|
||||
f->cy = (f->a->min_y+f->a->max_y)/2;
|
||||
|
||||
h = make_histo(f->a);
|
||||
f->z_ref = f->a->min_z+median(h);
|
||||
free_histo(h);
|
||||
f->fx = f->fy = 0;
|
||||
|
||||
f->m.a[0][0] = f->m.a[1][1] = 1;
|
||||
f->m.a[0][1] = f->m.a[1][0] = 0;
|
||||
f->m.b[0] = f->m.b[1] = 0;
|
||||
|
||||
fprintf(stderr, "%g %g %g\n", f->x_step, f->y_step, f->z_step);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
struct face *read_face(const char *name)
|
||||
{
|
||||
const char *p;
|
||||
int cwd;
|
||||
struct face *face;
|
||||
|
||||
if (strncmp(name, "http:", 5) && strncmp(name, "https:", 6))
|
||||
return read_file(name);
|
||||
p = strrchr(name, '/');
|
||||
if (!p || !p[1]) {
|
||||
fprintf(stderr, "malformed URL: \"%s\"\n", name);
|
||||
exit(1);
|
||||
}
|
||||
cwd = open(".", O_RDONLY);
|
||||
if (cwd < 0) {
|
||||
perror(".");
|
||||
exit(1);
|
||||
}
|
||||
if (chdir(CACHE_DIR) < 0) {
|
||||
perror(CACHE_DIR);
|
||||
exit(1);
|
||||
}
|
||||
if (access(p+1, R_OK) < 0) {
|
||||
char tmp[1000]; /* @@@ enough */
|
||||
int res;
|
||||
|
||||
sprintf(tmp, "wget '%s'", name);
|
||||
res = system(tmp);
|
||||
if (res < 0) {
|
||||
perror("system");
|
||||
exit(1);
|
||||
}
|
||||
if (!WIFEXITED(res) || WEXITSTATUS(res)) {
|
||||
fprintf(stderr, "%s: status %d\n", tmp, res);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
face = read_file(p+1);
|
||||
if (fchdir(cwd) < 0) {
|
||||
perror("fchdir");
|
||||
exit(1);
|
||||
}
|
||||
return face;
|
||||
}
|
39
solidify/face.h
Normal file
39
solidify/face.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* face.h - Data structure and handling of one face of a part
|
||||
*
|
||||
* Written 2010 by Werner Almesberger
|
||||
* Copyright 2010 by Werner Almesberger
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef FACE_H
|
||||
#define FACE_H
|
||||
|
||||
#include "array.h"
|
||||
#include "matrix.h"
|
||||
|
||||
|
||||
struct face {
|
||||
struct array *a;
|
||||
double x_step, y_step, z_step;
|
||||
int sx, sy; /* size */
|
||||
int cx, cy; /* center */
|
||||
int z_ref;
|
||||
double fx, fy; /* inclination factor */
|
||||
struct matrix m;
|
||||
};
|
||||
|
||||
|
||||
static inline double face_z0(const struct face *f, int x, int y)
|
||||
{
|
||||
return f->z_ref+f->fx*(x-f->sx/2)+f->fy*(y-f->sy/2);
|
||||
}
|
||||
|
||||
|
||||
struct face *read_face(const char *name);
|
||||
|
||||
#endif /* !FACE_H */
|
52
solidify/histo.c
Normal file
52
solidify/histo.c
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* histo.c - Distribution of Z values
|
||||
*
|
||||
* Written 2010 by Werner Almesberger
|
||||
* Copyright 2010 by Werner Almesberger
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
|
||||
#include "util.h"
|
||||
#include "array.h"
|
||||
#include "histo.h"
|
||||
|
||||
|
||||
struct histo *make_histo(struct array *a)
|
||||
{
|
||||
int i;
|
||||
struct histo *h;
|
||||
|
||||
h = alloc_type(struct histo);
|
||||
h->n = a->max_z-a->min_z+1;
|
||||
h->b = alloc_size(h->n*sizeof(int));
|
||||
for (i = 0; i != h->n; i++)
|
||||
h->b[i] = 0;
|
||||
for (i = 0; i != (a->max_x-a->min_x+1)*(a->max_y-a->min_y+1); i++)
|
||||
if (a->data[i] != UNDEF)
|
||||
h->b[a->data[i]-a->min_z]++;
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
void free_histo(struct histo *h)
|
||||
{
|
||||
free(h);
|
||||
}
|
||||
|
||||
|
||||
int median(const struct histo *h)
|
||||
{
|
||||
int tot = 0, sum = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i != h->n; i++)
|
||||
tot += h->b[i];
|
||||
for (i = 0; sum < tot/2; i++)
|
||||
sum += h->b[i];
|
||||
return i-1;
|
||||
}
|
29
solidify/histo.h
Normal file
29
solidify/histo.h
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* histo.h - Distribution of Z values
|
||||
*
|
||||
* Written 2010 by Werner Almesberger
|
||||
* Copyright 2010 by Werner Almesberger
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef HISTO_H
|
||||
#define HISTO_H
|
||||
|
||||
#include "array.h"
|
||||
|
||||
|
||||
struct histo {
|
||||
int n; /* number of bins */
|
||||
int *b; /* bins */
|
||||
};
|
||||
|
||||
|
||||
struct histo *make_histo(struct array *a);
|
||||
void free_histo(struct histo *h);
|
||||
int median(const struct histo *h);
|
||||
|
||||
#endif /* !HISTO_H */
|
200
solidify/level.c
Normal file
200
solidify/level.c
Normal file
@ -0,0 +1,200 @@
|
||||
/*
|
||||
* level.c - Interactively align a nearly horizontal plane with a face
|
||||
*
|
||||
* Written 2010 by Werner Almesberger
|
||||
* Copyright 2010 by Werner Almesberger
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "array.h"
|
||||
#include "face.h"
|
||||
#include "style.h"
|
||||
#include "level.h"
|
||||
|
||||
|
||||
#define NEAR 1
|
||||
|
||||
|
||||
static int has_osd;
|
||||
|
||||
|
||||
static double r_center(const struct face *f)
|
||||
{
|
||||
return hypot(f->sx, f->sy)/LEVEL_CENTER_DIV;
|
||||
}
|
||||
|
||||
|
||||
static void draw_map(GtkWidget *widget, struct face *f)
|
||||
{
|
||||
int x, y, z;
|
||||
double z0;
|
||||
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;
|
||||
}
|
||||
z0 = face_z0(f, x, y);
|
||||
if (fabs(z-z0) < NEAR) {
|
||||
*p++ = 255*fabs(z-z0);
|
||||
*p++ = 255*fabs(z-z0);
|
||||
*p++ = 255;
|
||||
continue;
|
||||
}
|
||||
if (z < z0) {
|
||||
z = z > z0-2*NEAR ? 255*(z-z0)/NEAR :
|
||||
255.0*(z-z0)/(z0-f->a->min_z);
|
||||
*p++ = 255;
|
||||
*p++ = z;
|
||||
*p++ = z;
|
||||
} else {
|
||||
z = z < z0+2*NEAR ? 255*(z0-z)/NEAR :
|
||||
255.0*(z0-z)/(f->a->max_z-z0);
|
||||
*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 *widget, struct face *f, int osd)
|
||||
{
|
||||
draw_map(widget, f);
|
||||
has_osd = osd;
|
||||
if (osd)
|
||||
draw_circle(widget->window, gc_osd,
|
||||
f->sx/2, f->sy/2, r_center(f));
|
||||
}
|
||||
|
||||
|
||||
static void scroll_z(GtkWidget *darea, struct face *f, int up, int osd)
|
||||
{
|
||||
if (up) {
|
||||
if (f->z_ref < f->a->max_z)
|
||||
f->z_ref++;
|
||||
} else {
|
||||
if (f->z_ref > f->a->min_z)
|
||||
f->z_ref--;
|
||||
}
|
||||
draw_image(darea, f, osd);
|
||||
}
|
||||
|
||||
|
||||
static void scroll_xy(GtkWidget *darea, struct face *f, int dx, int dy, int up,
|
||||
int osd)
|
||||
{
|
||||
double d;
|
||||
|
||||
d = (double) (up ? 1 : -1)/(dx*dx+dy*dy)/2.0;
|
||||
f->fx += d*dx;
|
||||
f->fy += d*dy;
|
||||
draw_image(darea, f, osd);
|
||||
}
|
||||
|
||||
|
||||
static gboolean scroll_event(GtkWidget *widget, GdkEventScroll *event,
|
||||
gpointer data)
|
||||
{
|
||||
GtkWidget *darea = gtk_bin_get_child(GTK_BIN(widget));
|
||||
struct face *f = data;
|
||||
int dx = event->x-f->sx/2;
|
||||
int dy = event->y-f->sy/2;
|
||||
double r = hypot(dx, dy);
|
||||
double rc = r_center(f);
|
||||
int center = r < rc;
|
||||
int osd = fabs(r-rc) < OSD_PROXIMITY;
|
||||
|
||||
switch (event->direction) {
|
||||
case GDK_SCROLL_UP:
|
||||
if (center)
|
||||
scroll_z(darea, f, 0, osd);
|
||||
else
|
||||
scroll_xy(darea, f, dx, dy, 1, osd);
|
||||
break;
|
||||
case GDK_SCROLL_DOWN:
|
||||
if (center)
|
||||
scroll_z(darea, f, 1, osd);
|
||||
else
|
||||
scroll_xy(darea, f, dx, dy, 0, osd);
|
||||
break;
|
||||
default:
|
||||
/* ignore */;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static gboolean expose_event(GtkWidget *widget, GdkEventExpose *event,
|
||||
gpointer user_data)
|
||||
{
|
||||
draw_image(widget, user_data, has_osd);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static gboolean motion_notify_event(GtkWidget *widget, GdkEventMotion *event,
|
||||
gpointer data)
|
||||
{
|
||||
struct face *f = data;
|
||||
int dx = event->x-f->sx/2;
|
||||
int dy = event->y-f->sy/2;
|
||||
double r = hypot(dx, dy);
|
||||
double rc = r_center(f);
|
||||
int osd = fabs(r-rc) < OSD_PROXIMITY;
|
||||
|
||||
if (osd != has_osd)
|
||||
draw_image(widget, f, osd);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
void level(GtkWidget *canvas, struct face *f)
|
||||
{
|
||||
GtkWidget *evbox, *darea;
|
||||
|
||||
evbox = gtk_event_box_new();
|
||||
darea = gtk_drawing_area_new();
|
||||
|
||||
gtk_widget_set_events(darea,
|
||||
GDK_EXPOSE | GDK_KEY_PRESS_MASK |
|
||||
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
|
||||
GDK_SCROLL |
|
||||
GDK_POINTER_MOTION_MASK);
|
||||
|
||||
gtk_widget_set_size_request(darea, f->sx, f->sy);
|
||||
gtk_container_add(GTK_CONTAINER(canvas), evbox);
|
||||
gtk_container_add(GTK_CONTAINER(evbox), darea);
|
||||
|
||||
draw_image(darea, f, 0);
|
||||
|
||||
g_signal_connect(G_OBJECT(evbox), "scroll-event",
|
||||
G_CALLBACK(scroll_event), f);
|
||||
g_signal_connect(G_OBJECT(darea), "expose-event",
|
||||
G_CALLBACK(expose_event), f);
|
||||
g_signal_connect(G_OBJECT(darea), "motion-notify-event",
|
||||
G_CALLBACK(motion_notify_event), f);
|
||||
}
|
23
solidify/level.h
Normal file
23
solidify/level.h
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* level.h - Interactively align a nearly horizontal plane with a face
|
||||
*
|
||||
* Written 2010 by Werner Almesberger
|
||||
* Copyright 2010 by Werner Almesberger
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef LEVEL_H
|
||||
#define LEVEL_H
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "face.h"
|
||||
|
||||
|
||||
void level(GtkWidget *canvas, struct face *f);
|
||||
|
||||
#endif /* !LEVEL_H */
|
51
solidify/main.pov
Normal file
51
solidify/main.pov
Normal file
@ -0,0 +1,51 @@
|
||||
#include "colors.inc"
|
||||
#include "batcvr.inc"
|
||||
|
||||
/*
|
||||
* POV-Ray defaults to a "camera" coordinate system that can be confusing.
|
||||
* We use a traditional mathematical/engineering view, with a view from
|
||||
* X-/Y-/Z+ into the X/Y plane.
|
||||
*/
|
||||
|
||||
camera {
|
||||
location <-30, -80, 40>
|
||||
look_at <20, 20, 0>
|
||||
sky z
|
||||
right -4/3*x
|
||||
}
|
||||
|
||||
background { color White }
|
||||
|
||||
light_source {
|
||||
<-200, -300, 200>
|
||||
color White
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark the coordinate axes:
|
||||
* - a red unit sphere at the center
|
||||
* - three green spheres at x = 10*i
|
||||
* - two blue spheres at y = 10*i
|
||||
* - one yellow sphere at z = 10
|
||||
*/
|
||||
|
||||
sphere { < 0, 0, 0>, 1 pigment { color Red } }
|
||||
sphere { <10, 0, 0>, 1 pigment { color Green } }
|
||||
sphere { <20, 0, 0>, 1 pigment { color Green } }
|
||||
sphere { <30, 0, 0>, 1 pigment { color Green } }
|
||||
sphere { < 0, 10, 0>, 1 pigment { color Blue } }
|
||||
sphere { < 0, 20, 0>, 1 pigment { color Blue } }
|
||||
sphere { < 0, 0, 10>, 1 pigment { color Yellow } }
|
||||
|
||||
#declare Finish = finish {
|
||||
brilliance 2
|
||||
phong 0.8
|
||||
phong_size 100
|
||||
metallic
|
||||
}
|
||||
|
||||
union {
|
||||
Part_batcvr
|
||||
pigment { rgbf <0.9, 0.9, 0.9, 0.5> }
|
||||
finish { Finish }
|
||||
}
|
66
solidify/matrix.c
Normal file
66
solidify/matrix.c
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* matrix.c - 2D matrix operations
|
||||
*
|
||||
* Written 2010 by Werner Almesberger
|
||||
* Copyright 2010 by Werner Almesberger
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "matrix.h"
|
||||
|
||||
|
||||
void matrix_identity(struct matrix *m)
|
||||
{
|
||||
m->a[0][0] = m->a[1][1] = 1;
|
||||
m->a[0][1] = m->a[1][0] = 0;
|
||||
m->b[0] = m->b[1] = 0;
|
||||
}
|
||||
|
||||
|
||||
void matrix_invert(const double m[2][2], double res[2][2])
|
||||
{
|
||||
double det = m[0][0]*m[1][1]-m[0][1]*m[1][0];
|
||||
|
||||
assert(res != (void *) m);
|
||||
res[0][0] = m[1][1]/det;
|
||||
res[0][1] = -m[0][1]/det;
|
||||
res[1][0] = -m[1][0]/det;
|
||||
res[1][1] = m[0][0]/det;
|
||||
}
|
||||
|
||||
|
||||
void matrix_mult(double a[2][2], double b[2][2], double res[2][2])
|
||||
{
|
||||
assert(res != a);
|
||||
assert(res != b);
|
||||
res[0][0] = a[0][0]*b[0][0]+a[0][1]*b[1][0];
|
||||
res[0][1] = a[0][0]*b[0][1]+a[0][1]*b[1][1];
|
||||
res[1][0] = a[1][0]*b[0][0]+a[1][1]*b[1][0];
|
||||
res[1][1] = a[1][0]*b[0][1]+a[1][1]*b[1][1];
|
||||
}
|
||||
|
||||
|
||||
void matrix_multv(const double v[2], double m[2][2], double res[2])
|
||||
{
|
||||
double tmp;
|
||||
|
||||
tmp = v[0]*m[0][0]+v[1]*m[0][1];
|
||||
res[1] = v[0]*m[1][0]+v[1]*m[1][1];
|
||||
res[0] = tmp;
|
||||
}
|
||||
|
||||
|
||||
void matrix_copy(double from[2][2], double to[2][2])
|
||||
{
|
||||
to[0][0] = from[0][0];
|
||||
to[0][1] = from[0][1];
|
||||
to[1][0] = from[1][0];
|
||||
to[1][1] = from[1][1];
|
||||
}
|
45
solidify/matrix.h
Normal file
45
solidify/matrix.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* matrix.h - 2D matrix operations
|
||||
*
|
||||
* Written 2010 by Werner Almesberger
|
||||
* Copyright 2010 by Werner Almesberger
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef MATRIX_H
|
||||
#define MATRIX_H
|
||||
|
||||
/*
|
||||
* 2D transformation:
|
||||
*
|
||||
* x' = x*a[0][0]+y*a[0][1]+b[0]
|
||||
* y' = x*a[1][0]+y*a[1][1]+b[1]
|
||||
*/
|
||||
|
||||
|
||||
struct matrix {
|
||||
double a[2][2];
|
||||
double b[2];
|
||||
};
|
||||
|
||||
|
||||
void matrix_identity(struct matrix *m);
|
||||
void matrix_invert(const double m[2][2], double res[2][2]);
|
||||
void matrix_mult(double a[2][2], double b[2][2], double res[2][2]);
|
||||
void matrix_multv(const double v[2], double m[2][2], double res[2]);
|
||||
void matrix_copy(double from[2][2], double to[2][2]);
|
||||
|
||||
|
||||
static inline void matrix_map(int x, int y, const struct matrix *m,
|
||||
double *res_x, double *res_y)
|
||||
{
|
||||
*res_x = x*m->a[0][0]+y*m->a[0][1]+m->b[0];
|
||||
*res_y = x*m->a[1][0]+y*m->a[1][1]+m->b[1];
|
||||
|
||||
}
|
||||
|
||||
#endif /* !MATRIX_H */
|
487
solidify/overlap.c
Normal file
487
solidify/overlap.c
Normal file
@ -0,0 +1,487 @@
|
||||
/*
|
||||
* overlap.c - Overlap two parallel faces
|
||||
*
|
||||
* Written 2010 by Werner Almesberger
|
||||
* Copyright 2010 by Werner Almesberger
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <limits.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "face.h"
|
||||
#include "solid.h"
|
||||
#include "style.h"
|
||||
#include "overlap.h"
|
||||
|
||||
|
||||
#define UNDEF_F HUGE_VAL
|
||||
|
||||
|
||||
static int has_osd;
|
||||
|
||||
|
||||
static int sx(const struct solid *s)
|
||||
{
|
||||
return (s->a->sx > s->b->sx ? s->a->sx : s->b->sx)+2*OVERLAP_BORDER;
|
||||
}
|
||||
|
||||
|
||||
static int sy(const struct solid *s)
|
||||
{
|
||||
return (s->a->sy > s->b->sy ? s->a->sy : s->b->sy)+2*OVERLAP_BORDER;
|
||||
}
|
||||
|
||||
|
||||
static double r_center(const struct solid *s)
|
||||
{
|
||||
return hypot(sx(s), sy(s))/OVERLAP_CENTER_DIV;
|
||||
}
|
||||
|
||||
|
||||
static double ramp(int z0, double w0, int z1, double w1)
|
||||
{
|
||||
if (z0 != UNDEF && z1 != UNDEF)
|
||||
return z0*w0+z1*w1;
|
||||
if (z0 == UNDEF && z0 == UNDEF)
|
||||
return UNDEF_F;
|
||||
if (z0 == UNDEF && w0 < w1)
|
||||
return z1;
|
||||
if (z1 == UNDEF && w0 > w1)
|
||||
return z0;
|
||||
return UNDEF_F;
|
||||
}
|
||||
|
||||
|
||||
static double zmix(struct face *f, double x, double y)
|
||||
{
|
||||
int xa, xb, ya, yb;
|
||||
double zx0, zx1;
|
||||
|
||||
xa = floor(x);
|
||||
xb = xa+1;
|
||||
ya = floor(y);
|
||||
yb = ya+1;
|
||||
|
||||
zx0 = ramp(
|
||||
get_bounded(f->a, xa, ya), yb-y,
|
||||
get_bounded(f->a, xa, yb), y-ya);
|
||||
zx1 = ramp(
|
||||
get_bounded(f->a, xb, ya), yb-y,
|
||||
get_bounded(f->a, xb, yb), y-ya);
|
||||
|
||||
return ramp(zx0, xb-x, zx1, x-xa);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Coordinate transformations, on the example of the x coordinate:
|
||||
*
|
||||
* - the x coordinate runs from 0 to sx(s)-1
|
||||
* - since we work relative to the screen center, this becomes x-sx(s)/2
|
||||
* This is what we perform the coordinate transform on.
|
||||
* - our model runs from min_x to max_x. Its center is at cx.
|
||||
*/
|
||||
|
||||
static void point(const struct solid *s, int x, int y, guchar *p,
|
||||
const struct matrix *ma, const struct matrix *mb)
|
||||
{
|
||||
double za, zb, z;
|
||||
double xaf, xbf, yaf, ybf;
|
||||
|
||||
matrix_map(x, y, ma, &xaf, &yaf);
|
||||
matrix_map(x, y, mb, &xbf, &ybf);
|
||||
|
||||
za = zmix(s->a, xaf, yaf);
|
||||
zb = zmix(s->b, xbf, ybf);
|
||||
|
||||
if (za == UNDEF_F && zb == UNDEF_F)
|
||||
return;
|
||||
|
||||
if (za == UNDEF_F) {
|
||||
z = 128.0*(zb-s->b->a->min_z)/(s->b->a->max_z-s->b->a->min_z);
|
||||
if (z < 0)
|
||||
z = 0;
|
||||
if (z > 255)
|
||||
z = 255;
|
||||
p[0] = 255;
|
||||
p[1] = z;
|
||||
p[2] = z;
|
||||
return;
|
||||
}
|
||||
if (zb == UNDEF_F) {
|
||||
z = 128.0*(za-s->a->a->min_z)/(s->a->a->max_z-s->a->a->min_z);
|
||||
if (z < 0)
|
||||
z = 0;
|
||||
if (z > 255)
|
||||
z = 255;
|
||||
p[0] = z;
|
||||
p[1] = 255;
|
||||
p[2] = z;
|
||||
return;
|
||||
}
|
||||
|
||||
z = za;
|
||||
za -= face_z0(s->a, xaf, yaf);
|
||||
zb -= face_z0(s->b, xbf, ybf);
|
||||
|
||||
if (za+zb < -s->dist) {
|
||||
p[0] = 0;
|
||||
p[1] = 0;
|
||||
p[2] = 255;
|
||||
return;
|
||||
}
|
||||
|
||||
z = 256.0*(z-s->a->a->min_z)/(s->a->a->max_z-s->a->a->min_z);
|
||||
if (z < 0)
|
||||
z = 0;
|
||||
if (z > 255)
|
||||
z = 255;
|
||||
p[0] = z;
|
||||
p[1] = z;
|
||||
p[2] = z;
|
||||
}
|
||||
|
||||
|
||||
static void merge_matrix(struct matrix *m, const struct solid *s,
|
||||
const struct face *f)
|
||||
{
|
||||
double tm[2][2], tm2[2][2];
|
||||
double tv[2];
|
||||
double f_x, f_y;
|
||||
|
||||
/*
|
||||
* Finally, we convert to model matrix coordinates.
|
||||
*
|
||||
* v' = v+c
|
||||
*/
|
||||
|
||||
m->b[0] += f->cx;
|
||||
m->b[1] += f->cy;
|
||||
|
||||
/*
|
||||
* Apply shrinkage caused by rotation out of z0.
|
||||
* We need to divide by x = cos a. We have f = tan a.
|
||||
* With sin^2 a + cos^2 a = 1, we get
|
||||
*
|
||||
* f = sqrt(1-cos^2 a)/cos a
|
||||
* = sqrt(1-x^2)/x
|
||||
* f^2 = 1/x^2-1
|
||||
* 1/(f^2+1) = x^2
|
||||
* cos a = sqrt(1/(f^2+1))
|
||||
*/
|
||||
|
||||
f_x = sqrt(f->fx*f->fx+1);
|
||||
f_y = sqrt(f->fy*f->fy+1);
|
||||
|
||||
m->a[0][0] *= f_x;
|
||||
m->a[0][1] *= f_x;
|
||||
m->b[0] *= f_x;
|
||||
m->a[1][0] *= f_y;
|
||||
m->a[1][1] *= f_y;
|
||||
m->b[1] *= f_y;
|
||||
|
||||
/*
|
||||
* The transformation matrix f->m describes a transformation of
|
||||
* (centered) model coordinates. We therefore have to reverse it:
|
||||
*
|
||||
* v = v'A+b
|
||||
* v-b = v'A
|
||||
* (v-b)A^-1 = v'
|
||||
* vA^-1-bA^-1 = v'
|
||||
*/
|
||||
|
||||
matrix_invert(f->m.a, tm);
|
||||
matrix_multv(f->m.b, tm, tv);
|
||||
tv[0] = -tv[0];
|
||||
tv[1] = -tv[1];
|
||||
|
||||
/*
|
||||
* Merge with the transformations we have so far:
|
||||
*
|
||||
* v' = vA1+b1 the transformation we have so far
|
||||
* v'' = v'A2+b2 the transformation we apply
|
||||
*
|
||||
* v'' = (vA1+b1)A2+b2
|
||||
* v'' = vA1A2+b1A2+b2
|
||||
*/
|
||||
|
||||
/*
|
||||
* So far, the theory. To make it really work, we have to calculate
|
||||
* v'' = vA1A2+b1+b2
|
||||
* duh ?!?
|
||||
*/
|
||||
|
||||
matrix_mult(m->a, tm, tm2); /* A1A2 */
|
||||
matrix_copy(tm2, m->a);
|
||||
// matrix_multv(m->b, tm, m->b); /* b1A2 */
|
||||
m->b[0] += tv[0]; /* b2 */
|
||||
m->b[1] += tv[1];
|
||||
|
||||
/*
|
||||
* Our input is a screen coordinate, its origin is in a corner so we
|
||||
* first have to make it center-based:
|
||||
*
|
||||
* v' = (v-s/2)A+b
|
||||
* v' = vA+(b-s/2*A)
|
||||
*/
|
||||
|
||||
tv[0] = sx(s)/2;
|
||||
tv[1] = sy(s)/2;
|
||||
matrix_multv(tv, m->a, tv);
|
||||
m->b[0] -= tv[0];
|
||||
m->b[1] -= tv[1];
|
||||
}
|
||||
|
||||
|
||||
static void draw_map(GtkWidget *widget, struct solid *s)
|
||||
{
|
||||
guchar *rgbbuf, *p;
|
||||
int x, y;
|
||||
struct matrix ma = {
|
||||
.a = { { 1, 0 }, { 0, 1 } },
|
||||
.b = { 0, 0 },
|
||||
};
|
||||
struct matrix mb = {
|
||||
.a = { { -1, 0 }, { 0, 1 } },
|
||||
.b = { 0, 0 },
|
||||
};
|
||||
|
||||
rgbbuf = p = calloc(sx(s)*sy(s), 3);
|
||||
if (!rgbbuf) {
|
||||
perror("calloc");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
merge_matrix(&ma, s, s->a);
|
||||
merge_matrix(&mb, s, s->b);
|
||||
|
||||
for (y = sy(s)-1; y >= 0; y--)
|
||||
for (x = 0; x != sx(s) ; x++) {
|
||||
point(s, x, y, p, &ma, &mb);
|
||||
p += 3;
|
||||
}
|
||||
gdk_draw_rgb_image(widget->window,
|
||||
widget->style->fg_gc[GTK_STATE_NORMAL],
|
||||
0, 0, sx(s), sy(s), GDK_RGB_DITHER_MAX, rgbbuf, sx(s)*3);
|
||||
free(rgbbuf);
|
||||
}
|
||||
|
||||
|
||||
static void draw_image(GtkWidget *widget, struct solid *s, int osd)
|
||||
{
|
||||
int cx = sx(s)/2;
|
||||
int cy = sy(s)/2;
|
||||
int p;
|
||||
|
||||
draw_map(widget, s);
|
||||
has_osd = osd;
|
||||
if (!osd)
|
||||
return;
|
||||
draw_circle(widget->window, gc_osd, cx, cy, r_center(s));
|
||||
p = r_center(s)/sqrt(2);
|
||||
gdk_draw_line(widget->window, gc_osd, cx-p, cy-p, cx+p, cy+p);
|
||||
gdk_draw_line(widget->window, gc_osd, cx-p, cy+p, cx+p, cy-p);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Rotate such that a point at distance "r" moves one unit. Rotate
|
||||
* counter-clockwise for r > 1, clockwise for r < 0.
|
||||
*/
|
||||
|
||||
static void rotate(struct matrix *m, double r)
|
||||
{
|
||||
struct matrix t;
|
||||
double s, c;
|
||||
|
||||
s = 1/r;
|
||||
c = sqrt(1-s*s);
|
||||
t.a[0][0] = m->a[0][0]*c-m->a[1][0]*s;
|
||||
t.a[0][1] = m->a[0][1]*c-m->a[1][1]*s;
|
||||
t.a[1][0] = m->a[1][0]*c+m->a[0][0]*s;
|
||||
t.a[1][1] = m->a[1][1]*c+m->a[0][1]*s;
|
||||
t.b[0] = m->b[0]*c-m->b[1]*s;
|
||||
t.b[1] = m->b[0]*s+m->b[1]*c;
|
||||
*m = t;
|
||||
}
|
||||
|
||||
|
||||
static void do_shift(struct matrix *m, double dx, double dy)
|
||||
{
|
||||
m->b[0] += dx;
|
||||
m->b[1] += dy;
|
||||
}
|
||||
|
||||
|
||||
static void shift(struct matrix *m, int dx, int dy, double dist)
|
||||
{
|
||||
/*
|
||||
* Wheeling "up" in each quadrant shifts in the respective direction,
|
||||
* wheeling "down" in the opposite direction.
|
||||
*
|
||||
* No rule without exception: we treat the "down" quadrant like the
|
||||
* "up" quadrant, because it would be extremely counter-intuitive to
|
||||
* wheel "up" to move "down".
|
||||
*/
|
||||
|
||||
if (dx > 0 && dy < dx && dy > -dx)
|
||||
do_shift(m, dist, 0);
|
||||
if (dx < 0 && dy < -dx && dy > dx)
|
||||
do_shift(m, -dist, 0);
|
||||
if (dy > 0 && dx < dy && dx > -dy)
|
||||
do_shift(m, 0, dist);
|
||||
if (dy < 0 && dx < -dy && dx > dy)
|
||||
do_shift(m, 0, dist); /* exception ! */
|
||||
}
|
||||
|
||||
|
||||
static int osd_proximity(const struct solid *s, int dx, int dy)
|
||||
{
|
||||
double r = hypot(dx, dy);
|
||||
double rc = r_center(s);
|
||||
|
||||
if (fabs(r-rc) < OSD_PROXIMITY)
|
||||
return 1;
|
||||
if (r > rc)
|
||||
return 0;
|
||||
if (abs(abs(dx)-abs(dy)) < OSD_PROXIMITY)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static gboolean scroll_event(GtkWidget *widget, GdkEventScroll *event,
|
||||
gpointer data)
|
||||
{
|
||||
GtkWidget *darea = gtk_bin_get_child(GTK_BIN(widget));
|
||||
struct solid *s = data;
|
||||
int dx = event->x-sx(s)/2;
|
||||
int dy = event->y-sy(s)/2;
|
||||
double r = hypot(dx, dy);
|
||||
double rc = r_center(s);
|
||||
double rs, rot, dist;
|
||||
int center = r < rc;
|
||||
int osd = osd_proximity(s, dx, dy);
|
||||
|
||||
if (r < 1)
|
||||
return TRUE;
|
||||
|
||||
/*
|
||||
* rot goes exponentially from SLOWEST_ROT*rs to FASTEST_ROT for
|
||||
* r = rc to rs, with rs being half the canvas diagonal.
|
||||
*
|
||||
* The values are picked such that we achieve sufficient precision at
|
||||
* a reasonably large distance from the circle (for accidently entering
|
||||
* the circle would change the mode) but can also spin quickly, e.g.,
|
||||
* when a 180 degrees rotation is needed.
|
||||
*
|
||||
* First, normalize to 0 ... 1
|
||||
* Then, we start at exp(0) and end at
|
||||
* exp(ln(SLOWEST_ROT*rs/FASTEST_ROT)))
|
||||
*/
|
||||
rs = hypot(sx(s), sy(s))/2;
|
||||
rot = (r-rc)/(rs-rc);
|
||||
rot = SLOWEST_ROT*rs*exp(-rot*log(SLOWEST_ROT*rs/FASTEST_ROT));
|
||||
|
||||
/*
|
||||
* dist stays at 1 from 0...rc/DIST_STEPS, then linearly goes up to
|
||||
* DIST_STEPS from rc/DIST_STEPS...rc
|
||||
*/
|
||||
dist = r/rc*DIST_STEPS;
|
||||
if (dist < 0)
|
||||
dist = 1;
|
||||
|
||||
switch (event->direction) {
|
||||
case GDK_SCROLL_UP:
|
||||
if (center)
|
||||
shift(&s->a->m, dx, dy, dist);
|
||||
else
|
||||
rotate(&s->a->m, dx > 0 ? rot : -rot);
|
||||
draw_image(darea, s, osd);
|
||||
break;
|
||||
case GDK_SCROLL_DOWN:
|
||||
if (center)
|
||||
shift(&s->a->m, dx, dy, -dist);
|
||||
else
|
||||
rotate(&s->a->m, dx > 0 ? -rot : rot);
|
||||
draw_image(darea, s, osd);
|
||||
break;
|
||||
default:
|
||||
/* ignore */;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static gboolean expose_event(GtkWidget *widget, GdkEventExpose *event,
|
||||
gpointer user_data)
|
||||
{
|
||||
draw_image(widget, user_data, has_osd);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static gboolean motion_notify_event(GtkWidget *widget, GdkEventMotion *event,
|
||||
gpointer data)
|
||||
{
|
||||
struct solid *s = data;
|
||||
int dx = event->x-sx(s)/2;
|
||||
int dy = event->y-sy(s)/2;
|
||||
int osd = osd_proximity(s, dx, dy);
|
||||
|
||||
if (osd != has_osd)
|
||||
draw_image(widget, s, osd);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
void overlap(GtkWidget *canvas, struct solid *s)
|
||||
{
|
||||
GtkWidget *evbox, *darea;
|
||||
|
||||
evbox = gtk_event_box_new();
|
||||
darea = gtk_drawing_area_new();
|
||||
|
||||
gtk_widget_set_events(darea,
|
||||
GDK_EXPOSE | GDK_KEY_PRESS_MASK |
|
||||
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
|
||||
GDK_SCROLL |
|
||||
GDK_POINTER_MOTION_MASK);
|
||||
|
||||
gtk_widget_set_size_request(darea, sx(s), sy(s));
|
||||
gtk_container_add(GTK_CONTAINER(canvas), evbox);
|
||||
gtk_container_add(GTK_CONTAINER(evbox), darea);
|
||||
|
||||
draw_image(darea, s, 0);
|
||||
|
||||
g_signal_connect(G_OBJECT(evbox), "scroll-event",
|
||||
G_CALLBACK(scroll_event), s);
|
||||
g_signal_connect(G_OBJECT(darea), "expose-event",
|
||||
G_CALLBACK(expose_event), s);
|
||||
g_signal_connect(G_OBJECT(darea), "motion-notify-event",
|
||||
G_CALLBACK(motion_notify_event), s);
|
||||
|
||||
if (0) {
|
||||
int i;
|
||||
long t0 = time(NULL);
|
||||
gtk_widget_show_all(canvas);
|
||||
for (i = 0; i != 1000; i++) {
|
||||
rotate(&s->a->m, 100);
|
||||
draw_image(darea, s, 0);
|
||||
while (gtk_events_pending())
|
||||
gtk_main_iteration();
|
||||
}
|
||||
fprintf(stderr, "%lu\n", time(NULL)-t0);
|
||||
}
|
||||
|
||||
}
|
23
solidify/overlap.h
Normal file
23
solidify/overlap.h
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* overlap.h - Overlap two parallel faces
|
||||
*
|
||||
* Written 2010 by Werner Almesberger
|
||||
* Copyright 2010 by Werner Almesberger
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef OVERLAP_H
|
||||
#define OVERLAP_H
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "solid.h"
|
||||
|
||||
|
||||
void overlap(GtkWidget *canvas, struct solid *solid);
|
||||
|
||||
#endif /* !OVERLAP_H */
|
120
solidify/povray.c
Normal file
120
solidify/povray.c
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* povray.c - Generate POV-Ray output
|
||||
*
|
||||
* Written 2010 by Werner Almesberger
|
||||
* Copyright 2010 by Werner Almesberger
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "face.h"
|
||||
#include "solid.h"
|
||||
|
||||
|
||||
static void height_field(const char *name, const struct face *f,
|
||||
const struct matrix *m)
|
||||
{
|
||||
FILE *file;
|
||||
int x, y;
|
||||
int z;
|
||||
uint16_t g;
|
||||
uint8_t v[2];
|
||||
|
||||
file = fopen(name, "w");
|
||||
if (!file) {
|
||||
perror(name);
|
||||
exit(1);
|
||||
}
|
||||
fprintf(file, "P5\n%d %d\n65535\n", f->sx, f->sy);
|
||||
for (y = 0; y != f->sy; y++)
|
||||
for (x = 0; x != f->sx; x++) {
|
||||
z = get(f->a, x+f->a->min_x, y+f->a->min_y);
|
||||
g = z == UNDEF ? 0 :
|
||||
65535*(z-f->a->min_z)/(f->a->max_z-f->a->min_z);
|
||||
v[0] = g >> 8;
|
||||
v[1] = g;
|
||||
fwrite(v, 2, 1, file);
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
|
||||
static void sanitize(const char *s, char *res)
|
||||
{
|
||||
while (*s) {
|
||||
if ((*s >= 'A' && *s <= 'Z') ||
|
||||
(*s >= 'a' && *s <= 'z') ||
|
||||
(*s >= '0' && *s <= '9') || *s == '_')
|
||||
*res = *s;
|
||||
else
|
||||
*res = '_';
|
||||
res++;
|
||||
s++;
|
||||
}
|
||||
*res = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* For now, we put the part such that its x/y/z center is at the origin.
|
||||
* Later, we will also have to consider the changes the user made and the
|
||||
* relation with the opposing face.
|
||||
*/
|
||||
|
||||
static void povray_face(const struct face *f, const char *side,
|
||||
const char *prefix, int flip, double dist)
|
||||
{
|
||||
int sz = f->a->max_z-f->a->min_z;
|
||||
|
||||
/*
|
||||
* 1/65535 = 0.000015..., so we set the water level a bit lower, e.g.,
|
||||
* to 0.0001
|
||||
*/
|
||||
printf(
|
||||
"\theight_field {\n"
|
||||
"\t pgm \"%s-%s.pgm\"\n"
|
||||
"\t water_level 0.00001\n"
|
||||
"\t smooth\n"
|
||||
"\t scale <%g, %g, %g>\n"
|
||||
"\t rotate <90, 0, 0>\n"
|
||||
"\t translate <%g, %g, %g>\n"
|
||||
"\t translate <0, 0, %g>\n"
|
||||
"%s" /* flip bottom face */
|
||||
"\t translate <0, 0, %g>\n"
|
||||
"\t}\n", prefix, side,
|
||||
f->sx*f->x_step, sz*f->z_step, f->sy*f->y_step,
|
||||
-f->sx*f->x_step/2, f->sy*f->y_step/2, f->a->min_z*f->z_step,
|
||||
-f->z_ref*f->z_step,
|
||||
flip ? "\t rotate <180, 0, 0>\n" : "",
|
||||
dist*f->z_step);
|
||||
}
|
||||
|
||||
|
||||
void povray(const char *name, const struct solid *s)
|
||||
{
|
||||
struct matrix m;
|
||||
char tmp[1000]; /* @@@ enough */
|
||||
|
||||
m.a[0][0] = m.a[1][1] = 1;
|
||||
m.a[0][1] = m.a[1][0] = 0;
|
||||
m.b[0] = m.b[1] = 0;
|
||||
|
||||
sprintf(tmp, "%s-top.pgm", name);
|
||||
height_field(tmp, s->a, &m);
|
||||
sprintf(tmp, "%s-bot.pgm", name);
|
||||
height_field(tmp, s->b, &m);
|
||||
|
||||
sanitize(name, tmp);
|
||||
printf("#declare Part_%s =\n intersection {\n", tmp);
|
||||
povray_face(s->a, "top", name, 0, s->dist/2);
|
||||
povray_face(s->b, "bot", name, 1, -s->dist/2);
|
||||
printf(" }\n");
|
||||
}
|
192
solidify/project.c
Normal file
192
solidify/project.c
Normal file
@ -0,0 +1,192 @@
|
||||
/*
|
||||
* project.c - Load and save solidify project descriptions
|
||||
*
|
||||
* Written 2010 by Werner Almesberger
|
||||
* Copyright 2010 by Werner Almesberger
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "face.h"
|
||||
#include "solid.h"
|
||||
#include "project.h"
|
||||
|
||||
|
||||
static struct project *make_project(const char *name,
|
||||
const char *top, const char *bottom, double dist_mm)
|
||||
{
|
||||
struct project *prj;
|
||||
|
||||
prj = alloc_type(struct project);
|
||||
prj->name = stralloc(name);
|
||||
prj->top = stralloc(top);
|
||||
prj->bottom = stralloc(bottom);
|
||||
prj->s.a = read_face(top);
|
||||
prj->s.b = read_face(bottom);
|
||||
|
||||
if (prj->s.a->x_step != prj->s.a->x_step ||
|
||||
prj->s.a->y_step != prj->s.a->y_step ||
|
||||
prj->s.a->z_step != prj->s.a->z_step) {
|
||||
fprintf(stderr, "both faces must have the same resolution\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
prj->s.dist = dist_mm/prj->s.a->z_step;
|
||||
return prj;
|
||||
}
|
||||
|
||||
|
||||
struct project *new_project(const char *name,
|
||||
const char *top, const char *bottom, double dist_mm)
|
||||
{
|
||||
FILE *file;
|
||||
|
||||
file = fopen(name, "r");
|
||||
if (file) {
|
||||
fprintf(stderr, "%s: already exists\n", name);
|
||||
exit(1);
|
||||
}
|
||||
return make_project(name, top, bottom, dist_mm);
|
||||
}
|
||||
|
||||
|
||||
static void read_face_data(FILE *file, struct face *f)
|
||||
{
|
||||
float v;
|
||||
|
||||
if (fscanf(file, "%f", &v) != 1)
|
||||
return;
|
||||
f->z_ref = v/f->z_step;
|
||||
|
||||
if (fscanf(file, "%f", &v) != 1)
|
||||
return;
|
||||
f->fx = tan(v/180*M_PI);
|
||||
|
||||
if (fscanf(file, "%f", &v) != 1)
|
||||
return;
|
||||
f->fy = tan(v/180*M_PI);
|
||||
|
||||
if (fscanf(file, "%f", &v) != 1)
|
||||
return;
|
||||
v = v/180*M_PI;
|
||||
f->m.a[0][0] = cos(v);
|
||||
f->m.a[0][1] = -sin(v);
|
||||
f->m.a[1][0] = sin(v);
|
||||
f->m.a[1][1] = cos(v);
|
||||
|
||||
if (fscanf(file, "%f", &v) != 1)
|
||||
return;
|
||||
f->m.b[0] = v/f->x_step;
|
||||
|
||||
if (fscanf(file, "%f", &v) != 1)
|
||||
return;
|
||||
f->m.b[1] = v/f->y_step;
|
||||
}
|
||||
|
||||
|
||||
static void read_optional(FILE *file, struct project *prj)
|
||||
{
|
||||
float v;
|
||||
|
||||
if (fscanf(file, "%f", &v) != 1)
|
||||
return;
|
||||
prj->s.dist = v/prj->s.a->z_step;
|
||||
|
||||
read_face_data(file, prj->s.a);
|
||||
read_face_data(file, prj->s.b);
|
||||
}
|
||||
|
||||
|
||||
struct project *load_project(const char *name)
|
||||
{
|
||||
FILE *file;
|
||||
char top[1000], bottom[1000]; /* @@@ enough */
|
||||
struct project *prj;
|
||||
|
||||
file = fopen(name, "r");
|
||||
if (!file) {
|
||||
perror(name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!fgets(top, sizeof(top), file)) {
|
||||
fprintf(stderr, "%s: can't read name of top face\n", name);
|
||||
exit(1);
|
||||
}
|
||||
if (strchr(top, '\n'))
|
||||
*strchr(top, '\n') = 0;
|
||||
|
||||
if (!fgets(bottom, sizeof(bottom), file)) {
|
||||
fprintf(stderr, "%s: can't read name of bottom face\n",
|
||||
bottom);
|
||||
exit(1);
|
||||
}
|
||||
if (strchr(bottom, '\n'))
|
||||
*strchr(bottom, '\n') = 0;
|
||||
|
||||
prj = make_project(name, top, bottom, 0);
|
||||
|
||||
read_optional(file, prj);
|
||||
|
||||
return prj;
|
||||
}
|
||||
|
||||
|
||||
static void save_face_data(FILE *file, const char *name, const struct face *f)
|
||||
{
|
||||
double a;
|
||||
|
||||
a = asin(-f->m.a[0][1])/M_PI*180;
|
||||
if (f->m.a[0][0] < 0)
|
||||
a = 180-a;
|
||||
if (fprintf(file, "%g %g %g\n%g %g %g\n",
|
||||
f->z_ref*f->z_step,
|
||||
atan(f->fx)/M_PI*180, atan(f->fy)/M_PI*180,
|
||||
a, f->m.b[0]*f->x_step, f->m.b[1]*f->y_step) < 0) {
|
||||
perror(name);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void save_project(const struct project *prj)
|
||||
{
|
||||
char tmp[1000]; /* @@@ enough */
|
||||
FILE *file;
|
||||
|
||||
sprintf(tmp, "%s~", prj->name);
|
||||
file = fopen(tmp, "w");
|
||||
if (!file) {
|
||||
perror(tmp);
|
||||
exit(1);
|
||||
}
|
||||
if (fprintf(file,
|
||||
"%s\n%s\n%g\n", prj->top, prj->bottom,
|
||||
prj->s.dist*prj->s.a->z_step) < 0) {
|
||||
perror(tmp);
|
||||
exit(1);
|
||||
}
|
||||
save_face_data(file, tmp, prj->s.a);
|
||||
save_face_data(file, tmp, prj->s.b);
|
||||
if (fclose(file) < 0) {
|
||||
perror(tmp);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (rename(tmp, prj->name) < 0) {
|
||||
fprintf(stderr, "rename %s to %s: %s\n", tmp, prj->name,
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
}
|
48
solidify/project.h
Normal file
48
solidify/project.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* project.h - Load and save solidify project descriptions
|
||||
*
|
||||
* Written 2010 by Werner Almesberger
|
||||
* Copyright 2010 by Werner Almesberger
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Project file structure:
|
||||
*
|
||||
* line 1: file name of top face (required)
|
||||
* line 2: file name of bottom face (required)
|
||||
* line 3 and beyond, separated by whitespace:
|
||||
* - z distance between faces, in mm
|
||||
* - z distance of the z0 plane from the midpoint of the top face, in mm
|
||||
* - inclination of the x axis of the z0 plane of the top face, in degrees
|
||||
* - inclination of the y axis of the z0 plane of the top face, in degrees
|
||||
* - rotation of the top face, in degrees
|
||||
* - x shift of the top face, in mm
|
||||
* - y shift of the top face, in mm
|
||||
* - the above 6 fields for the bottom face
|
||||
*/
|
||||
|
||||
#ifndef PROJECT_H
|
||||
#define PROJECT_H
|
||||
|
||||
#include "solid.h"
|
||||
|
||||
|
||||
struct project {
|
||||
const char *name;
|
||||
const char *top;
|
||||
const char *bottom;
|
||||
struct solid s;
|
||||
};
|
||||
|
||||
|
||||
struct project *new_project(const char *name,
|
||||
const char *top, const char *bottom, double dist_mm);
|
||||
struct project *load_project(const char *name);
|
||||
void save_project(const struct project *prj);
|
||||
|
||||
#endif /* !PROJECT_H */
|
24
solidify/solid.h
Normal file
24
solidify/solid.h
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* solid.h - Data structure and handling of a solid made of two opposing faces
|
||||
*
|
||||
* Written 2010 by Werner Almesberger
|
||||
* Copyright 2010 by Werner Almesberger
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef SOLID_H
|
||||
#define SOLID_H
|
||||
|
||||
struct solid {
|
||||
struct face *a, *b;
|
||||
double dist;
|
||||
};
|
||||
|
||||
|
||||
void povray(const char *name, const struct solid *s);
|
||||
|
||||
#endif /* !SOLID_H */
|
163
solidify/solidify.c
Normal file
163
solidify/solidify.c
Normal file
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* solidify.c - Merge two opposing faces of a part into a solid
|
||||
*
|
||||
* Written 2010 by Werner Almesberger
|
||||
* Copyright 2010 Werner Almesberger
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <locale.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "face.h"
|
||||
#include "solid.h"
|
||||
#include "project.h"
|
||||
#include "style.h"
|
||||
#include "level.h"
|
||||
#include "overlap.h"
|
||||
|
||||
|
||||
static struct project *prj;
|
||||
static const struct face *active; /* NULL if overlapping */
|
||||
static GtkWidget *canvas;
|
||||
|
||||
|
||||
static void clicked(GtkButton *button, gpointer user_data)
|
||||
{
|
||||
struct face *face = user_data;
|
||||
|
||||
if (active == face)
|
||||
return;
|
||||
|
||||
gtk_widget_destroy(gtk_bin_get_child(GTK_BIN(canvas)));
|
||||
|
||||
if (face)
|
||||
level(canvas, face);
|
||||
else
|
||||
overlap(canvas, &prj->s);
|
||||
active = face;
|
||||
|
||||
gtk_widget_show_all(canvas);
|
||||
}
|
||||
|
||||
|
||||
static GtkWidget *gui_buttons(void)
|
||||
{
|
||||
GtkWidget *vbox, *but;
|
||||
|
||||
vbox = gtk_vbox_new(FALSE, 0);
|
||||
|
||||
but = gtk_button_new_with_label("A");
|
||||
gtk_box_pack_start(GTK_BOX(vbox), but, FALSE, FALSE, 0);
|
||||
g_signal_connect(G_OBJECT(but), "clicked",
|
||||
G_CALLBACK(clicked), prj->s.a);
|
||||
|
||||
but = gtk_button_new_with_label("B");
|
||||
gtk_box_pack_start(GTK_BOX(vbox), but, FALSE, FALSE, 0);
|
||||
g_signal_connect(G_OBJECT(but), "clicked",
|
||||
G_CALLBACK(clicked), prj->s.b);
|
||||
|
||||
but = gtk_button_new_with_label("A+B");
|
||||
gtk_box_pack_start(GTK_BOX(vbox), but, FALSE, FALSE, 0);
|
||||
g_signal_connect(G_OBJECT(but), "clicked",
|
||||
G_CALLBACK(clicked), NULL);
|
||||
|
||||
return vbox;
|
||||
}
|
||||
|
||||
|
||||
static gboolean key_press_event(GtkWidget *widget, GdkEventKey *event,
|
||||
gpointer data)
|
||||
{
|
||||
if (event->keyval == 'q')
|
||||
gtk_main_quit();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static void gui(void)
|
||||
{
|
||||
GtkWidget *root, *hbox, *buttons;
|
||||
|
||||
root = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_position(GTK_WINDOW(root), GTK_WIN_POS_CENTER);
|
||||
|
||||
hbox = gtk_hbox_new(FALSE, 0);
|
||||
gtk_container_add(GTK_CONTAINER(root), hbox);
|
||||
|
||||
canvas = gtk_event_box_new();
|
||||
gtk_box_pack_start(GTK_BOX(hbox), canvas, FALSE, FALSE, 0);
|
||||
|
||||
/* initialize root->window */
|
||||
gtk_widget_show_all(root);
|
||||
|
||||
buttons = gui_buttons();
|
||||
gtk_box_pack_start(GTK_BOX(hbox), buttons, FALSE, FALSE, 0);
|
||||
|
||||
level(canvas, prj->s.a);
|
||||
active = prj->s.a;
|
||||
|
||||
init_style(root->window);
|
||||
|
||||
gtk_widget_show_all(root);
|
||||
|
||||
g_signal_connect(G_OBJECT(root), "key-press-event",
|
||||
G_CALLBACK(key_press_event), NULL);
|
||||
g_signal_connect(G_OBJECT(root), "destroy",
|
||||
G_CALLBACK(gtk_main_quit), NULL);
|
||||
|
||||
gtk_main();
|
||||
}
|
||||
|
||||
|
||||
static void usage(const char *name)
|
||||
{
|
||||
fprintf(stderr, "usage: %s project [top bottom dist]\n", name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
double dist;
|
||||
|
||||
gtk_init(&argc, &argv);
|
||||
setlocale(LC_ALL, "C"); /* damage control */
|
||||
|
||||
switch (argc) {
|
||||
case 2:
|
||||
prj = load_project(argv[1]);
|
||||
break;
|
||||
case 5:
|
||||
dist = atof(argv[4]);
|
||||
prj = new_project(argv[1], argv[2], argv[3], dist);
|
||||
break;
|
||||
default:
|
||||
usage(*argv);
|
||||
}
|
||||
|
||||
gui();
|
||||
|
||||
save_project(prj);
|
||||
|
||||
if (!isatty(1)) {
|
||||
const char *slash = strrchr(prj->name, '/');
|
||||
char tmp[1000]; /* @@@ enough */
|
||||
|
||||
strcpy(tmp, slash ? slash+1 : prj->name);
|
||||
if (strchr(tmp, '.'))
|
||||
*strchr(tmp, '.') = 0;
|
||||
povray(tmp, &prj->s);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
53
solidify/style.c
Normal file
53
solidify/style.c
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* style.c - GUI style parameters and items
|
||||
*
|
||||
* Written 2010 by Werner Almesberger
|
||||
* Copyright 2010 by Werner Almesberger
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "style.h"
|
||||
|
||||
|
||||
GdkGC *gc_osd;
|
||||
|
||||
|
||||
static GdkColor get_color(GdkDrawable *da, const char *spec)
|
||||
{
|
||||
GdkColormap *cmap;
|
||||
GdkColor color;
|
||||
|
||||
cmap = gdk_drawable_get_colormap(da);
|
||||
if (!gdk_color_parse(spec, &color))
|
||||
abort();
|
||||
if (!gdk_colormap_alloc_color(cmap, &color, FALSE, TRUE))
|
||||
abort();
|
||||
return color;
|
||||
}
|
||||
|
||||
|
||||
static GdkGC *gc(GdkDrawable *da, const char *spec, int width)
|
||||
{
|
||||
GdkGCValues gc_values = {
|
||||
.background = get_color(da, "black"),
|
||||
.foreground = get_color(da, spec),
|
||||
.line_width = width,
|
||||
};
|
||||
|
||||
return gdk_gc_new_with_values(da, &gc_values,
|
||||
GDK_GC_FOREGROUND | GDK_GC_BACKGROUND | GDK_GC_LINE_WIDTH);
|
||||
}
|
||||
|
||||
|
||||
void init_style(GdkDrawable *da)
|
||||
{
|
||||
gc_osd = gc(da, "#ffff00", 4);
|
||||
}
|
33
solidify/style.h
Normal file
33
solidify/style.h
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* style.h - GUI style parameters and items
|
||||
*
|
||||
* Written 2010 by Werner Almesberger
|
||||
* Copyright 2010 by Werner Almesberger
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef STYLE_H
|
||||
#define STYLE_H
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
|
||||
extern GdkGC *gc_osd;
|
||||
|
||||
|
||||
#define OSD_PROXIMITY 20 /* pixels */
|
||||
#define LEVEL_CENTER_DIV 5 /* fraction of diagonal */
|
||||
#define OVERLAP_BORDER 10 /* pixels around min. drawing area */
|
||||
#define OVERLAP_CENTER_DIV 5 /* fraction of diagonal */
|
||||
#define SLOWEST_ROT 3 /* thrice the half-diagonal */
|
||||
#define FASTEST_ROT 2 /* one pixel in distance of 2 pixels */
|
||||
#define DIST_STEPS 5 /* fastest shift is 5 px/wheel step */
|
||||
|
||||
|
||||
void init_style(GdkDrawable *da);
|
||||
|
||||
#endif /* !STYLE_H */
|
22
solidify/util.c
Normal file
22
solidify/util.c
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* util.c - Common utility functions
|
||||
*
|
||||
* Written 2010 by Werner Almesberger
|
||||
* Copyright 2010 by Werner Almesberger
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
|
||||
void draw_circle(GdkDrawable *da, GdkGC *gc, int x, int y, int r)
|
||||
{
|
||||
gdk_draw_arc(da, gc, FALSE, x-r, y-r, 2*r, 2*r, 0, 360*64);
|
||||
}
|
38
solidify/util.h
Normal file
38
solidify/util.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* util.h - Common utility functions
|
||||
*
|
||||
* Written 2009 by Werner Almesberger
|
||||
* Copyright 2009 by Werner Almesberger
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef UTIL_H
|
||||
#define UTIL_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <gtk/gtk.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)))
|
||||
|
||||
#define stralloc(s) \
|
||||
({ char *stralloc_tmp = strdup(s); \
|
||||
if (!stralloc_tmp) \
|
||||
abort(); \
|
||||
stralloc_tmp; })
|
||||
|
||||
|
||||
void draw_circle(GdkDrawable *da, GdkGC *gc, int x, int y, int r);
|
||||
|
||||
#endif /* !UTIL_H */
|
Loading…
Reference in New Issue
Block a user