2010-09-24 04:17:19 +03:00
|
|
|
/*
|
|
|
|
* 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 "face.h"
|
Introduce a solid data type and use it, mainly in overlap()
- solidify/solid.h: definition of a solid made from two opposing faces
- solidify/overlap.h (overlap), solidify/overlap.c (draw_image,
scroll_event, overlap): operate on solid instead of face
- solidify/overlap.c (sx, sy, draw_image, overlap): helper functions sx()
and sy() to determine canvas size
- solidify/overlap.c (BORDER, sx, sy): added a border around the piece,
to help with positioning
- solidify/solidify.c (clicked, gui_buttons, gui, main): use solid instead
of faces
2010-09-24 05:41:35 +03:00
|
|
|
#include "solid.h"
|
2010-09-24 04:17:19 +03:00
|
|
|
#include "overlap.h"
|
|
|
|
|
|
|
|
|
|
|
|
#define UNDEF_F HUGE_VAL
|
Introduce a solid data type and use it, mainly in overlap()
- solidify/solid.h: definition of a solid made from two opposing faces
- solidify/overlap.h (overlap), solidify/overlap.c (draw_image,
scroll_event, overlap): operate on solid instead of face
- solidify/overlap.c (sx, sy, draw_image, overlap): helper functions sx()
and sy() to determine canvas size
- solidify/overlap.c (BORDER, sx, sy): added a border around the piece,
to help with positioning
- solidify/solidify.c (clicked, gui_buttons, gui, main): use solid instead
of faces
2010-09-24 05:41:35 +03:00
|
|
|
#define BORDER 10 /* pixels around the minimum drawing area */
|
|
|
|
|
|
|
|
|
|
|
|
static int sx(const struct solid *s)
|
|
|
|
{
|
|
|
|
return (s->a->sx > s->b->sx ? s->a->sx : s->b->sx)+2*BORDER;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int sy(const struct solid *s)
|
|
|
|
{
|
|
|
|
return (s->a->sy > s->b->sy ? s->a->sy : s->b->sy)+2*BORDER;
|
|
|
|
}
|
2010-09-24 04:17:19 +03:00
|
|
|
|
|
|
|
|
|
|
|
static double ramp(int z0, double w0, int z1, double w1)
|
|
|
|
{
|
|
|
|
if (z0 != UNDEF && z1 != UNDEF)
|
|
|
|
return w0 == 0 && w1 == 0 ? z0 : 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 = ceil(x);
|
|
|
|
ya = floor(y);
|
|
|
|
yb = ceil(y);
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
Introduce a solid data type and use it, mainly in overlap()
- solidify/solid.h: definition of a solid made from two opposing faces
- solidify/overlap.h (overlap), solidify/overlap.c (draw_image,
scroll_event, overlap): operate on solid instead of face
- solidify/overlap.c (sx, sy, draw_image, overlap): helper functions sx()
and sy() to determine canvas size
- solidify/overlap.c (BORDER, sx, sy): added a border around the piece,
to help with positioning
- solidify/solidify.c (clicked, gui_buttons, gui, main): use solid instead
of faces
2010-09-24 05:41:35 +03:00
|
|
|
static void draw_image(GtkWidget *widget, struct solid *s)
|
2010-09-24 04:17:19 +03:00
|
|
|
{
|
|
|
|
guchar *rgbbuf, *p;
|
|
|
|
int x, y;
|
|
|
|
double z;
|
Introduce a solid data type and use it, mainly in overlap()
- solidify/solid.h: definition of a solid made from two opposing faces
- solidify/overlap.h (overlap), solidify/overlap.c (draw_image,
scroll_event, overlap): operate on solid instead of face
- solidify/overlap.c (sx, sy, draw_image, overlap): helper functions sx()
and sy() to determine canvas size
- solidify/overlap.c (BORDER, sx, sy): added a border around the piece,
to help with positioning
- solidify/solidify.c (clicked, gui_buttons, gui, main): use solid instead
of faces
2010-09-24 05:41:35 +03:00
|
|
|
struct face *f = s->a;
|
2010-09-24 04:17:19 +03:00
|
|
|
|
Introduce a solid data type and use it, mainly in overlap()
- solidify/solid.h: definition of a solid made from two opposing faces
- solidify/overlap.h (overlap), solidify/overlap.c (draw_image,
scroll_event, overlap): operate on solid instead of face
- solidify/overlap.c (sx, sy, draw_image, overlap): helper functions sx()
and sy() to determine canvas size
- solidify/overlap.c (BORDER, sx, sy): added a border around the piece,
to help with positioning
- solidify/solidify.c (clicked, gui_buttons, gui, main): use solid instead
of faces
2010-09-24 05:41:35 +03:00
|
|
|
rgbbuf = p = calloc(sx(s)*sy(s), 3);
|
2010-09-24 04:17:19 +03:00
|
|
|
if (!rgbbuf) {
|
|
|
|
perror("calloc");
|
|
|
|
exit(1);
|
|
|
|
}
|
Introduce a solid data type and use it, mainly in overlap()
- solidify/solid.h: definition of a solid made from two opposing faces
- solidify/overlap.h (overlap), solidify/overlap.c (draw_image,
scroll_event, overlap): operate on solid instead of face
- solidify/overlap.c (sx, sy, draw_image, overlap): helper functions sx()
and sy() to determine canvas size
- solidify/overlap.c (BORDER, sx, sy): added a border around the piece,
to help with positioning
- solidify/solidify.c (clicked, gui_buttons, gui, main): use solid instead
of faces
2010-09-24 05:41:35 +03:00
|
|
|
for (y = sy(s)-1; y >= 0; y--)
|
|
|
|
for (x = 0; x != sx(s) ; x++) {
|
2010-09-24 04:17:19 +03:00
|
|
|
int xa = x+f->a->min_x;
|
|
|
|
int ya = y+f->a->min_y;
|
|
|
|
|
|
|
|
z = zmix(f,
|
|
|
|
xa*f->m.a[0][0]+ya*f->m.a[0][1]+f->m.b[0],
|
|
|
|
xa*f->m.a[1][0]+ya*f->m.a[1][1]+f->m.b[1]);
|
|
|
|
if (z == UNDEF_F) {
|
|
|
|
p += 3;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
z = 256.0*(z-f->a->min_z)/(f->a->max_z-f->a->min_z);
|
|
|
|
if (z < 0)
|
|
|
|
z = 0;
|
|
|
|
if (z > 255)
|
|
|
|
z = 255;
|
|
|
|
*p++ = z;
|
|
|
|
*p++ = z;
|
|
|
|
*p++ = z;
|
|
|
|
}
|
|
|
|
gdk_draw_rgb_image(widget->window,
|
|
|
|
widget->style->fg_gc[GTK_STATE_NORMAL],
|
Introduce a solid data type and use it, mainly in overlap()
- solidify/solid.h: definition of a solid made from two opposing faces
- solidify/overlap.h (overlap), solidify/overlap.c (draw_image,
scroll_event, overlap): operate on solid instead of face
- solidify/overlap.c (sx, sy, draw_image, overlap): helper functions sx()
and sy() to determine canvas size
- solidify/overlap.c (BORDER, sx, sy): added a border around the piece,
to help with positioning
- solidify/solidify.c (clicked, gui_buttons, gui, main): use solid instead
of faces
2010-09-24 05:41:35 +03:00
|
|
|
0, 0, sx(s), sy(s), GDK_RGB_DITHER_MAX, rgbbuf, sx(s)*3);
|
2010-09-24 04:17:19 +03:00
|
|
|
free(rgbbuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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 gboolean scroll_event(GtkWidget *widget, GdkEventScroll *event,
|
|
|
|
gpointer data)
|
|
|
|
{
|
|
|
|
GtkWidget *da = gtk_bin_get_child(GTK_BIN(widget));
|
Introduce a solid data type and use it, mainly in overlap()
- solidify/solid.h: definition of a solid made from two opposing faces
- solidify/overlap.h (overlap), solidify/overlap.c (draw_image,
scroll_event, overlap): operate on solid instead of face
- solidify/overlap.c (sx, sy, draw_image, overlap): helper functions sx()
and sy() to determine canvas size
- solidify/overlap.c (BORDER, sx, sy): added a border around the piece,
to help with positioning
- solidify/solidify.c (clicked, gui_buttons, gui, main): use solid instead
of faces
2010-09-24 05:41:35 +03:00
|
|
|
struct solid *s = data;
|
|
|
|
struct face *f = s->a;
|
2010-09-24 04:17:19 +03:00
|
|
|
int dx = event->x-f->sx/2;
|
|
|
|
int dy = event->y-f->sy/2;
|
|
|
|
double r = hypot(dx, dy);
|
|
|
|
|
|
|
|
if (r < 1)
|
|
|
|
return TRUE;
|
|
|
|
switch (event->direction) {
|
|
|
|
case GDK_SCROLL_UP:
|
|
|
|
rotate(&f->m, r);
|
Introduce a solid data type and use it, mainly in overlap()
- solidify/solid.h: definition of a solid made from two opposing faces
- solidify/overlap.h (overlap), solidify/overlap.c (draw_image,
scroll_event, overlap): operate on solid instead of face
- solidify/overlap.c (sx, sy, draw_image, overlap): helper functions sx()
and sy() to determine canvas size
- solidify/overlap.c (BORDER, sx, sy): added a border around the piece,
to help with positioning
- solidify/solidify.c (clicked, gui_buttons, gui, main): use solid instead
of faces
2010-09-24 05:41:35 +03:00
|
|
|
draw_image(da, s);
|
2010-09-24 04:17:19 +03:00
|
|
|
break;
|
|
|
|
case GDK_SCROLL_DOWN:
|
|
|
|
rotate(&f->m, -r);
|
Introduce a solid data type and use it, mainly in overlap()
- solidify/solid.h: definition of a solid made from two opposing faces
- solidify/overlap.h (overlap), solidify/overlap.c (draw_image,
scroll_event, overlap): operate on solid instead of face
- solidify/overlap.c (sx, sy, draw_image, overlap): helper functions sx()
and sy() to determine canvas size
- solidify/overlap.c (BORDER, sx, sy): added a border around the piece,
to help with positioning
- solidify/solidify.c (clicked, gui_buttons, gui, main): use solid instead
of faces
2010-09-24 05:41:35 +03:00
|
|
|
draw_image(da, s);
|
2010-09-24 04:17:19 +03:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* ignore */;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static gboolean expose_event(GtkWidget *widget, GdkEventExpose *event,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
draw_image(widget, user_data);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
Introduce a solid data type and use it, mainly in overlap()
- solidify/solid.h: definition of a solid made from two opposing faces
- solidify/overlap.h (overlap), solidify/overlap.c (draw_image,
scroll_event, overlap): operate on solid instead of face
- solidify/overlap.c (sx, sy, draw_image, overlap): helper functions sx()
and sy() to determine canvas size
- solidify/overlap.c (BORDER, sx, sy): added a border around the piece,
to help with positioning
- solidify/solidify.c (clicked, gui_buttons, gui, main): use solid instead
of faces
2010-09-24 05:41:35 +03:00
|
|
|
void overlap(GtkWidget *canvas, struct solid *s)
|
2010-09-24 04:17:19 +03:00
|
|
|
{
|
|
|
|
GtkWidget *evbox, *da;
|
|
|
|
|
2010-09-24 05:18:46 +03:00
|
|
|
evbox = gtk_event_box_new();
|
2010-09-24 04:17:19 +03:00
|
|
|
da = gtk_drawing_area_new();
|
Introduce a solid data type and use it, mainly in overlap()
- solidify/solid.h: definition of a solid made from two opposing faces
- solidify/overlap.h (overlap), solidify/overlap.c (draw_image,
scroll_event, overlap): operate on solid instead of face
- solidify/overlap.c (sx, sy, draw_image, overlap): helper functions sx()
and sy() to determine canvas size
- solidify/overlap.c (BORDER, sx, sy): added a border around the piece,
to help with positioning
- solidify/solidify.c (clicked, gui_buttons, gui, main): use solid instead
of faces
2010-09-24 05:41:35 +03:00
|
|
|
gtk_widget_set_size_request(da, sx(s), sy(s));
|
2010-09-24 05:18:46 +03:00
|
|
|
gtk_container_add(GTK_CONTAINER(canvas), evbox);
|
2010-09-24 04:17:19 +03:00
|
|
|
gtk_container_add(GTK_CONTAINER(evbox), da);
|
2010-09-24 05:18:46 +03:00
|
|
|
|
Introduce a solid data type and use it, mainly in overlap()
- solidify/solid.h: definition of a solid made from two opposing faces
- solidify/overlap.h (overlap), solidify/overlap.c (draw_image,
scroll_event, overlap): operate on solid instead of face
- solidify/overlap.c (sx, sy, draw_image, overlap): helper functions sx()
and sy() to determine canvas size
- solidify/overlap.c (BORDER, sx, sy): added a border around the piece,
to help with positioning
- solidify/solidify.c (clicked, gui_buttons, gui, main): use solid instead
of faces
2010-09-24 05:41:35 +03:00
|
|
|
draw_image(da, s);
|
2010-09-24 04:17:19 +03:00
|
|
|
|
|
|
|
g_signal_connect(G_OBJECT(evbox), "scroll-event",
|
Introduce a solid data type and use it, mainly in overlap()
- solidify/solid.h: definition of a solid made from two opposing faces
- solidify/overlap.h (overlap), solidify/overlap.c (draw_image,
scroll_event, overlap): operate on solid instead of face
- solidify/overlap.c (sx, sy, draw_image, overlap): helper functions sx()
and sy() to determine canvas size
- solidify/overlap.c (BORDER, sx, sy): added a border around the piece,
to help with positioning
- solidify/solidify.c (clicked, gui_buttons, gui, main): use solid instead
of faces
2010-09-24 05:41:35 +03:00
|
|
|
G_CALLBACK(scroll_event), s);
|
2010-09-24 04:17:19 +03:00
|
|
|
g_signal_connect(G_OBJECT(da), "expose-event",
|
Introduce a solid data type and use it, mainly in overlap()
- solidify/solid.h: definition of a solid made from two opposing faces
- solidify/overlap.h (overlap), solidify/overlap.c (draw_image,
scroll_event, overlap): operate on solid instead of face
- solidify/overlap.c (sx, sy, draw_image, overlap): helper functions sx()
and sy() to determine canvas size
- solidify/overlap.c (BORDER, sx, sy): added a border around the piece,
to help with positioning
- solidify/solidify.c (clicked, gui_buttons, gui, main): use solid instead
of faces
2010-09-24 05:41:35 +03:00
|
|
|
G_CALLBACK(expose_event), s);
|
2010-09-24 04:17:19 +03:00
|
|
|
}
|