Ben NanoNote 3D scans
Sign in or create your account | Project List | Help
Ben NanoNote 3D scans Git Source Tree
Root/
Source at commit edb12b6e956b9d85def465745c80433154afd0ef created 13 years 6 months ago. By Werner Almesberger, When leveling, the center circle is now shown when the pointer approaches it. | |
---|---|
1 | /* |
2 | * level.c - Interactively align a nearly horizontal plane with a face |
3 | * |
4 | * Written 2010 by Werner Almesberger |
5 | * Copyright 2010 by Werner Almesberger |
6 | * |
7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by |
9 | * the Free Software Foundation; either version 2 of the License, or |
10 | * (at your option) any later version. |
11 | */ |
12 | |
13 | |
14 | #include <stdlib.h> |
15 | #include <stdio.h> |
16 | #include <math.h> |
17 | #include <gtk/gtk.h> |
18 | |
19 | #include "util.h" |
20 | #include "array.h" |
21 | #include "face.h" |
22 | #include "style.h" |
23 | #include "level.h" |
24 | |
25 | |
26 | #define NEAR 1 |
27 | |
28 | |
29 | static int has_osd; |
30 | |
31 | |
32 | static double r_center(const struct face *f) |
33 | { |
34 | return hypot(f->sx, f->sy)/LEVEL_CENTER_DIV; |
35 | } |
36 | |
37 | |
38 | static void draw_map(GtkWidget *widget, struct face *f) |
39 | { |
40 | int x, y, z; |
41 | double z0; |
42 | guchar *rgbbuf, *p; |
43 | |
44 | rgbbuf = p = calloc(f->sx*f->sy, 3); |
45 | if (!rgbbuf) { |
46 | perror("calloc"); |
47 | exit(1); |
48 | } |
49 | for (y = f->sy-1; y >= 0; y--) |
50 | for (x = 0; x != f->sx ; x++) { |
51 | z = get(f->a, x+f->a->min_x, y+f->a->min_y); |
52 | if (z == UNDEF) { |
53 | p += 3; |
54 | continue; |
55 | } |
56 | z0 = face_z0(f, x, y); |
57 | if (fabs(z-z0) < NEAR) { |
58 | *p++ = 255*fabs(z-z0); |
59 | *p++ = 255*fabs(z-z0); |
60 | *p++ = 255; |
61 | continue; |
62 | } |
63 | if (z < z0) { |
64 | z = z > z0-2*NEAR ? 255*(z-z0)/NEAR : |
65 | 255.0*(z-z0)/(z0-f->a->min_z); |
66 | *p++ = 255; |
67 | *p++ = z; |
68 | *p++ = z; |
69 | } else { |
70 | z = z < z0+2*NEAR ? 255*(z0-z)/NEAR : |
71 | 255.0*(z0-z)/(f->a->max_z-z0); |
72 | *p++ = z; |
73 | *p++ = 255; |
74 | *p++ = z; |
75 | } |
76 | } |
77 | gdk_draw_rgb_image(widget->window, |
78 | widget->style->fg_gc[GTK_STATE_NORMAL], |
79 | 0, 0, f->sx, f->sy, GDK_RGB_DITHER_MAX, rgbbuf, f->sx*3); |
80 | free(rgbbuf); |
81 | } |
82 | |
83 | |
84 | static void draw_image(GtkWidget *widget, struct face *f, int osd) |
85 | { |
86 | draw_map(widget, f); |
87 | has_osd = osd; |
88 | if (osd) |
89 | draw_circle(widget->window, gc_osd, |
90 | f->sx/2, f->sy/2, r_center(f)); |
91 | } |
92 | |
93 | |
94 | static void scroll_z(GtkWidget *darea, struct face *f, int up, int osd) |
95 | { |
96 | if (up) { |
97 | if (f->z_ref < f->a->max_z) |
98 | f->z_ref++; |
99 | } else { |
100 | if (f->z_ref > f->a->min_z) |
101 | f->z_ref--; |
102 | } |
103 | draw_image(darea, f, osd); |
104 | } |
105 | |
106 | |
107 | static void scroll_xy(GtkWidget *darea, struct face *f, int dx, int dy, int up, |
108 | int osd) |
109 | { |
110 | double d; |
111 | |
112 | d = (double) (up ? 1 : -1)/(dx*dx+dy*dy)/2.0; |
113 | f->fx += d*dx; |
114 | f->fy += d*dy; |
115 | draw_image(darea, f, osd); |
116 | } |
117 | |
118 | |
119 | static gboolean scroll_event(GtkWidget *widget, GdkEventScroll *event, |
120 | gpointer data) |
121 | { |
122 | GtkWidget *darea = gtk_bin_get_child(GTK_BIN(widget)); |
123 | struct face *f = data; |
124 | int dx = event->x-f->sx/2; |
125 | int dy = event->y-f->sy/2; |
126 | double r = hypot(dx, dy); |
127 | double rc = r_center(f); |
128 | int center = r < rc; |
129 | int osd = fabs(r-rc) < OSD_PROXIMITY; |
130 | |
131 | switch (event->direction) { |
132 | case GDK_SCROLL_UP: |
133 | if (center) |
134 | scroll_z(darea, f, 0, osd); |
135 | else |
136 | scroll_xy(darea, f, dx, dy, 1, osd); |
137 | break; |
138 | case GDK_SCROLL_DOWN: |
139 | if (center) |
140 | scroll_z(darea, f, 1, osd); |
141 | else |
142 | scroll_xy(darea, f, dx, dy, 0, osd); |
143 | break; |
144 | default: |
145 | /* ignore */; |
146 | } |
147 | return TRUE; |
148 | } |
149 | |
150 | |
151 | static gboolean expose_event(GtkWidget *widget, GdkEventExpose *event, |
152 | gpointer user_data) |
153 | { |
154 | draw_image(widget, user_data, has_osd); |
155 | return TRUE; |
156 | } |
157 | |
158 | |
159 | static gboolean motion_notify_event(GtkWidget *widget, GdkEventMotion *event, |
160 | gpointer data) |
161 | { |
162 | struct face *f = data; |
163 | int dx = event->x-f->sx/2; |
164 | int dy = event->y-f->sy/2; |
165 | double r = hypot(dx, dy); |
166 | double rc = r_center(f); |
167 | int osd = fabs(r-rc) < OSD_PROXIMITY; |
168 | |
169 | if (osd != has_osd) |
170 | draw_image(widget, f, osd); |
171 | return FALSE; |
172 | } |
173 | |
174 | |
175 | void level(GtkWidget *canvas, struct face *f) |
176 | { |
177 | GtkWidget *evbox, *darea; |
178 | |
179 | evbox = gtk_event_box_new(); |
180 | darea = gtk_drawing_area_new(); |
181 | |
182 | gtk_widget_set_events(darea, |
183 | GDK_EXPOSE | GDK_KEY_PRESS_MASK | |
184 | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | |
185 | GDK_SCROLL | |
186 | GDK_POINTER_MOTION_MASK); |
187 | |
188 | gtk_widget_set_size_request(darea, f->sx, f->sy); |
189 | gtk_container_add(GTK_CONTAINER(canvas), evbox); |
190 | gtk_container_add(GTK_CONTAINER(evbox), darea); |
191 | |
192 | draw_image(darea, f, 0); |
193 | |
194 | g_signal_connect(G_OBJECT(evbox), "scroll-event", |
195 | G_CALLBACK(scroll_event), f); |
196 | g_signal_connect(G_OBJECT(darea), "expose-event", |
197 | G_CALLBACK(expose_event), f); |
198 | g_signal_connect(G_OBJECT(darea), "motion-notify-event", |
199 | G_CALLBACK(motion_notify_event), f); |
200 | } |
201 |
Branches:
master