Source file mesh_graphicsF.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
# 1 "graphics/mesh_graphicsFC.ml"
open Printf
open Bigarray
open Graphics
open Mesh
type mesh = fortran_layout t
type 'a vector = 'a vec
type vec = fortran_layout vector
let hypot x y = sqrt(x *. x +. y *. y)
(** Return the smaller box (xmin, xmax, ymin, ymax) containing the [mesh]. *)
let bounding_box (mesh: mesh) =
let pt = mesh#point in
let xmin = ref infinity
and xmax = ref neg_infinity
and ymin = ref infinity
and ymax = ref neg_infinity in
for i = 1 to Array2.dim2(pt) do
let x = pt.{1,i}
and y = pt.{2,i} in
if x > !xmax then xmax := x;
if x < !xmin then xmin := x;
if y > !ymax then ymax := y;
if y < !ymin then ymin := y;
done;
(!xmin, !xmax, !ymin, !ymax)
(** Contains the information to transform "mesh coordinates" into the
graphics ones. *)
type surf = { hx: float; hy: float; xbd: int; ybd: int;
xmin: float; ymin: float }
;;
let pixel_x s x = truncate((x -. s.xmin) *. s.hx) + s.xbd
let pixel_y s y = truncate((y -. s.ymin) *. s.hy) + s.ybd
let make_surf mesh width height =
let xmin, xmax, ymin, ymax = bounding_box mesh in
let hx = float width /. (xmax -. xmin)
and hy = float height /. (ymax -. ymin) in
let (xbd, ybd) = current_point() in
{ hx = hx; hy = hy; xbd = xbd; ybd = ybd; xmin = xmin; ymin = ymin }
let draw ?(width=600) ?(height=600) ?(color=foreground) ?(points=true)
?point_idx ?triangle_idx ?voronoi
?point_marker_color (mesh: mesh) =
let surf = make_surf mesh width height in
let pt = mesh#point
and triangle = mesh#triangle in
let triangle_idx = match triangle_idx with
| None -> (fun _ _ _ _ _ _ _ -> ())
| Some f -> (fun t x0 y0 x1 y1 x2 y2 ->
let d01 = hypot (x0 -. x1) (y0 -. y1)
and d02 = hypot (x0 -. x2) (y0 -. y2)
and d12 = hypot (x1 -. x2) (y1 -. y2) in
let d = d12 +. d02 +. d01 in
let x = (d12 *. x0 +. d02 *. x1 +. d01 *. x2) /. d
and y = (d12 *. y0 +. d02 *. y1 +. d01 *. y2) /. d in
moveto (pixel_x surf x) (pixel_y surf y);
f t;
set_color color) in
set_color color;
for t = 1 to Array2.dim2(triangle) do
let i0 = triangle.{1,t}
and i1 = triangle.{2,t}
and i2 = triangle.{3,t} in
try
let x0 = pt.{1,i0} and y0 = pt.{2,i0} in
let x1 = pt.{1,i1} and y1 = pt.{2,i1} in
let x2 = pt.{1,i2} and y2 = pt.{2,i2} in
let px0 = pixel_x surf x0 and py0 = pixel_y surf y0 in
let px1 = pixel_x surf x1 and py1 = pixel_y surf y1 in
let px2 = pixel_x surf x2 and py2 = pixel_y surf y2 in
draw_segments [| (px0, py0, px1, py1); (px1, py1, px2, py2);
(px2, py2, px0, py0) |];
triangle_idx t x0 y0 x1 y1 x2 y2;
with e ->
eprintf "Mesh_display: triangle %i (%i,%i,%i): %s\n%!"
t i0 i1 i2 (Printexc.to_string e)
done;
let marker = match point_marker_color with
| None -> (fun _ _ _ -> ())
| Some c -> (fun m px py ->
set_color c;
moveto px py;
draw_string(string_of_int m);
set_color color
) in
let point_idx = match point_idx with
| None -> (fun _ _ _ _ -> ())
| Some f -> (fun _s px py i ->
moveto px py;
f i;
set_color color) in
if points then begin
let pt_marker = mesh#point_marker in
for i = 1 to Array2.dim2(pt) do
let x = pt.{1,i} and y = pt.{2,i} in
let px = pixel_x surf x
and py = pixel_y surf y in
fill_circle px py 3;
point_idx surf px py i;
marker pt_marker.{i} px py
done;
end;
begin match voronoi with
| None -> ()
| Some _vor -> ()
end
;;
type point = { x : float; y : float }
let point s _i {x=x; y=y} =
draw_rect (pixel_x s x) (pixel_y s y) 1 1
let line s color {x=x0; y=y0} {x=x1; y=y1} =
set_color color;
draw_segments [| (pixel_x s x0, pixel_y s y0,
pixel_x s x1, pixel_y s y1) |]
let triangle s color {x=x0; y=y0} {x=x1; y=y1} {x=x2; y=y2} =
set_color color;
fill_poly [| (pixel_x s x0, pixel_y s y0);
(pixel_x s x1, pixel_y s y1);
(pixel_x s x2, pixel_y s y2) |]
let rec array_of_points s pts =
let l = List.length pts in
let apts = Array.make l (0,0) in
fill_array_of_points s apts 0 pts;
apts
and fill_array_of_points s apts i = function
| [] -> ()
| pt :: tl ->
apts.(i) <- (pixel_x s pt.x, pixel_y s pt.y);
fill_array_of_points s apts (i + 1) tl
let fill_triangle = triangle
let fill_quadrilateral s color {x=x0; y=y0} {x=x1; y=y1} {x=x2; y=y2}
{x=x3; y=y3} =
set_color color;
fill_poly [| (pixel_x s x0, pixel_y s y0);
(pixel_x s x1, pixel_y s y1);
(pixel_x s x2, pixel_y s y2);
(pixel_x s x3, pixel_y s y3) |]
module M = Map.Make(struct
type t = int
let compare x y = compare (x:int) y
end)
module Edge =
struct
let make() = ref M.empty
let add_edge t i1 i2 =
assert(i1 < i2);
try
let v = M.find i1 !t in
v := i2 :: !v
with Not_found ->
t := M.add i1 (ref [i2]) !t
let add t i1 i2 =
if i1 < i2 then add_edge t i1 i2 else add_edge t i2 i1
let on_boundary t i1 i2 =
assert(i1 < i2);
try
let v = M.find i1 !t in List.mem i2 !v
with Not_found -> false
let on t i1 i2 =
if i1 < i2 then on_boundary t i1 i2 else on_boundary t i2 i1
end;;
let default_level_eq l1 l2 =
abs_float(l1 -. l2) <= 1E-8 *. (abs_float l1 +. abs_float l2)
let mid p q = {x = 0.5 *. (p.x +. q.x); y = 0.5 *. (p.y +. q.y) }
let intercept {x=x1; y=y1} z1 {x=x2; y=y2} z2 l =
let d = z1 -. z2 and a = l -. z2 and b = z1 -. l in
{x = (a *. x1 +. b *. x2) /. d; y = (a *. y1 +. b *. y2) /. d }
let draw_levels ~boundary (mesh: mesh) (z: vec)
?(level_eq=default_level_eq) levels surf =
let edge = mesh#edge in
let marker = mesh#edge_marker in
let pt = mesh#point in
if Array2.dim2(edge) = 0 then
invalid_arg("Mesh_graphics.level_curves: mesh#edge must be nonempty");
if Array2.dim1(edge) <> 2 then
invalid_arg("Mesh_graphics.level_curves: mesh#edge must have 2 rows (fortran)");
if Array1.dim marker < Array2.dim2(edge) then
invalid_arg("Mesh_graphics.level_curves: dim mesh#edge_marker < number edges");
if Array2.dim2(pt) = 0 then
invalid_arg("Mesh_graphics.level_curves: mesh#point must be nonempty");
if Array2.dim1(pt) <> 2 then
invalid_arg("Mesh_graphics.level_curves: mesh#point must have 2 rows (fortran)");
let bd = Edge.make() in
for e = 1 to Array2.dim2(edge) do
let m = marker.{e} in
if m <> 0 then begin
let i1 = edge.{1,e}
and i2 = edge.{2,e} in
Edge.add bd i1 i2;
match boundary m with
| None -> ()
| Some color ->
let p1 = { x = pt.{1,i1}; y = pt.{2,i1} }
and p2 = { x = pt.{1,i2}; y = pt.{2,i2} } in
line surf color p1 p2
end
done;
let tr = mesh#triangle in
if Array2.dim2(tr) = 0 then
invalid_arg("Mesh_graphics.level_curves: mesh#triangle must be nonempty");
if Array2.dim1(tr) < 3 then
invalid_arg("Mesh_graphics.level_curves: mesh#triangle must have at least 3 \
rows (fortran) or 3 columns (C)");
let marker = mesh#point_marker in
for t = 1 to Array2.dim2(tr) do
let i1 = tr.{1,t}
and i2 = tr.{2,t}
and i3 = tr.{3,t} in
let p1 = { x = pt.{1,i1}; y = pt.{2,i1} }
and z1 = z.{i1} in
let p2 = { x = pt.{1,i2}; y = pt.{2,i2} }
and z2 = z.{i2} in
let p3 = { x = pt.{1,i3}; y = pt.{2,i3} }
and z3 = z.{i3} in
List.iter
(fun (l, color) ->
if level_eq l z1 then (
if level_eq l z2 then (
if level_eq l z3 then
if Edge.on bd i1 i2 then
if Edge.on bd i1 i3 || Edge.on bd i2 i3 then
triangle surf color p1 p2 p3
else line surf color p3 (mid p1 p2)
else
if Edge.on bd i1 i3 then
if Edge.on bd i2 i3 then triangle surf color p1 p2 p3
else line surf color p2 (mid p1 p3)
else
if Edge.on bd i2 i3 then line surf color p1 (mid p2 p3)
else triangle surf color p1 p2 p3
else
if not(Edge.on bd i1 i2) then line surf color p1 p2
)
else
if level_eq l z3 then
(if not(Edge.on bd i1 i3) then line surf color p1 p3)
else
if (z2 < l && l < z3) || (z3 < l && l < z2) then
line surf color p1 (intercept p2 z2 p3 z3 l)
)
else if l < z1 then (
if level_eq l z2 then
if level_eq l z3 then
(if not(Edge.on bd i2 i3) then line surf color p2 p3)
else if l > z3 then
line surf color p2 (intercept p1 z1 p3 z3 l)
else
(if marker.{i2} = 0 then point surf i2 p2)
else if l < z2 then (
if level_eq l z3 then
(if marker.{i3} = 0 then point surf i3 p3)
else if l > z3 then
line surf color (intercept p1 z1 p3 z3 l)
(intercept p2 z2 p3 z3 l)
)
else
line surf color (intercept p1 z1 p2 z2 l)
(if level_eq l z3 then p3
else if l < z3 then intercept p2 z2 p3 z3 l
else intercept p1 z1 p3 z3 l)
)
else (
if level_eq l z2 then
if level_eq l z3 then
(if not(Edge.on bd i2 i3) then line surf color p2 p3)
else if l < z3 then
line surf color p2 (intercept p1 z1 p3 z3 l)
else
(if marker.{i2} = 0 then point surf i2 p2)
else if l > z2 then (
if level_eq l z3 then
(if marker.{i3} = 0 then point surf i3 p3)
else if l < z3 then
line surf color (intercept p1 z1 p3 z3 l)
(intercept p2 z2 p3 z3 l)
)
else
line surf color (intercept p1 z1 p2 z2 l)
(if level_eq l z3 then p3
else if l > z3 then intercept p2 z2 p3 z3 l
else intercept p1 z1 p3 z3 l)
)
) levels
done
;;
type polygon_fill =
| Tri123
| Tri231 | Tri312
| Quad123
| Quad231 | Quad312
| Whole | Empty;;
let index c1 c2 c3 = c1 + 3 * c2 + 9 * c3 + 13
let super =
let d = Array.make 27 Empty in
d.(index( 1) ( 1) ( 1)) <- Whole;
d.(index( 1) ( 1) ( 0)) <- Whole;
d.(index( 1) ( 1) (-1)) <- Quad312;
d.(index( 1) ( 0) ( 1)) <- Whole;
d.(index( 1) ( 0) ( 0)) <- Whole;
d.(index( 1) ( 0) (-1)) <- Tri123;
d.(index( 1) (-1) ( 1)) <- Quad231;
d.(index( 1) (-1) ( 0)) <- Tri123;
d.(index( 1) (-1) (-1)) <- Tri123;
d.(index( 0) ( 1) ( 1)) <- Whole;
d.(index( 0) ( 1) ( 0)) <- Whole;
d.(index( 0) ( 1) (-1)) <- Tri231;
d.(index( 0) ( 0) ( 1)) <- Whole;
d.(index( 0) ( 0) ( 0)) <- Empty;
d.(index( 0) ( 0) (-1)) <- Empty;
d.(index( 0) (-1) ( 1)) <- Tri312;
d.(index( 0) (-1) ( 0)) <- Empty;
d.(index( 0) (-1) (-1)) <- Empty;
d.(index(-1) ( 1) ( 1)) <- Quad123;
d.(index(-1) ( 1) ( 0)) <- Tri231;
d.(index(-1) ( 1) (-1)) <- Tri231;
d.(index(-1) ( 0) ( 1)) <- Tri312;
d.(index(-1) ( 0) ( 0)) <- Empty;
d.(index(-1) ( 0) (-1)) <- Empty;
d.(index(-1) (-1) ( 1)) <- Tri312;
d.(index(-1) (-1) ( 0)) <- Empty;
d.(index(-1) (-1) (-1)) <- Empty;
d
let sub =
let d = Array.make 27 Empty in
d.(index( 1) ( 1) ( 1)) <- Empty;
d.(index( 1) ( 1) ( 0)) <- Empty;
d.(index( 1) ( 1) (-1)) <- Tri312;
d.(index( 1) ( 0) ( 1)) <- Empty;
d.(index( 1) ( 0) ( 0)) <- Empty;
d.(index( 1) ( 0) (-1)) <- Tri312;
d.(index( 1) (-1) ( 1)) <- Tri231;
d.(index( 1) (-1) ( 0)) <- Tri231;
d.(index( 1) (-1) (-1)) <- Quad123;
d.(index( 0) ( 1) ( 1)) <- Empty;
d.(index( 0) ( 1) ( 0)) <- Empty;
d.(index( 0) ( 1) (-1)) <- Tri312;
d.(index( 0) ( 0) ( 1)) <- Empty;
d.(index( 0) ( 0) ( 0)) <- Empty;
d.(index( 0) ( 0) (-1)) <- Whole;
d.(index( 0) (-1) ( 1)) <- Tri231;
d.(index( 0) (-1) ( 0)) <- Whole;
d.(index( 0) (-1) (-1)) <- Whole;
d.(index(-1) ( 1) ( 1)) <- Tri123;
d.(index(-1) ( 1) ( 0)) <- Tri123;
d.(index(-1) ( 1) (-1)) <- Quad231;
d.(index(-1) ( 0) ( 1)) <- Tri123;
d.(index(-1) ( 0) ( 0)) <- Whole;
d.(index(-1) ( 0) (-1)) <- Whole;
d.(index(-1) (-1) ( 1)) <- Quad312;
d.(index(-1) (-1) ( 0)) <- Whole;
d.(index(-1) (-1) (-1)) <- Whole;
d
let draw_xxx_level decision name ?(boundary=(fun _ -> Some black))
(mesh: mesh) (z: vec) l color surf =
let edge = mesh#edge in
let edge_marker = mesh#edge_marker in
let pt = mesh#point in
if Array2.dim2(edge) = 0 then
invalid_arg("Mesh_graphics" ^ name ^ ": mesh#edge must be nonempty");
if Array2.dim1(edge) <> 2 then
invalid_arg("Mesh_graphics" ^ name ^ ": mesh#edge must have 2 rows (fortran)");
if Array1.dim edge_marker < Array2.dim2(edge) then
invalid_arg("Mesh_graphics" ^ name ^ ": dim mesh#edge_marker < number edges");
if Array2.dim2(pt) = 0 then
invalid_arg("Mesh_graphics" ^ name ^ ": mesh#point must be nonempty");
if Array2.dim1(pt) <> 2 then
invalid_arg("Mesh_graphics" ^ name ^ ": mesh#point must have 2 rows (fortran)");
let tr = mesh#triangle in
if Array2.dim2(tr) = 0 then
invalid_arg("Mesh_graphics" ^ name ^ ": mesh#triangle must be nonempty");
if Array2.dim1(tr) < 3 then
invalid_arg("Mesh_graphics" ^ name ^ ": mesh#triangle must have at least 3 \
rows (fortran) or 3 columns (C)");
for t = 1 to Array2.dim2(tr) do
let i1 = tr.{1,t}
and i2 = tr.{2,t}
and i3 = tr.{3,t} in
let p1 = { x = pt.{1,i1}; y = pt.{2,i1} }
and z1 = z.{i1} in
let p2 = { x = pt.{1,i2}; y = pt.{2,i2} }
and z2 = z.{i2} in
let p3 = { x = pt.{1,i3}; y = pt.{2,i3} }
and z3 = z.{i3} in
match decision.(index (compare z1 l) (compare z2 l) (compare z3 l)) with
| Tri123 -> fill_triangle surf color p1 (intercept p1 z1 p2 z2 l)
(intercept p1 z1 p3 z3 l)
| Tri231 -> fill_triangle surf color p2 (intercept p2 z2 p3 z3 l)
(intercept p2 z2 p1 z1 l)
| Tri312 -> fill_triangle surf color p3 (intercept p3 z3 p1 z1 l)
(intercept p3 z3 p2 z2 l)
| Quad123 -> fill_quadrilateral surf color (intercept p1 z1 p2 z2 l)
(intercept p1 z1 p3 z3 l) p3 p2
| Quad231 -> fill_quadrilateral surf color (intercept p2 z2 p3 z3 l)
(intercept p2 z2 p1 z1 l) p1 p3
| Quad312 -> fill_quadrilateral surf color (intercept p3 z3 p1 z1 l)
(intercept p3 z3 p2 z2 l) p2 p1
| Whole -> fill_triangle surf color p1 p2 p3
| Empty -> ()
done;
for e = 1 to Array2.dim2(edge) do
let m = edge_marker.{e} in
if m <> 0 then begin
match boundary m with
| None -> ()
| Some color ->
let i1 = edge.{1,e}
and i2 = edge.{2,e} in
let p1 = { x = pt.{1,i1}; y = pt.{2,i1} }
and p2 = { x = pt.{1,i2}; y = pt.{2,i2} } in
line surf color p1 p2
end
done
let draw_super_level ?boundary mesh z level color surf =
draw_xxx_level super ".super_level" ?boundary mesh z level color surf
let draw_sub_level ?boundary mesh z level color surf =
draw_xxx_level sub ".sub_level" ?boundary mesh z level color surf
;;
let level_curves ~width ~height ?(boundary=(fun _ -> Some 0))
(mesh: mesh) (z: vec) ?level_eq levels =
let surf = make_surf mesh width height in
draw_levels ~boundary mesh z ?level_eq levels surf
let super_level ~width ~height ?(boundary=(fun _ -> Some 0))
(mesh: mesh) (z: vec) level color =
let surf = make_surf mesh width height in
draw_super_level ~boundary mesh z level color surf
let sub_level ~width ~height ?(boundary=(fun _ -> Some 0))
(mesh: mesh) (z: vec) level color =
let surf = make_surf mesh width height in
draw_sub_level ~boundary mesh z level color surf