2 Copyright (C) 2005,2006,2007,2008 Eugene K. Ressler, Jr.
4 This file is part of Sketch, a small, simple system for making
5 3d drawings with LaTeX and the PSTricks or TikZ package.
7 Sketch 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 3, or (at your option)
12 Sketch is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Sketch; see the file COPYING.txt. If not, see
19 http://www.gnu.org/copyleft */
28 char *expr_val_type_str
[] = {
35 // set expression value to given type and value
37 set_float (EXPR_VAL
* r
, FLOAT val
)
44 print_float (FILE * f
, EXPR_VAL
* val
)
46 fprintf (f
, F
, val
->val
.flt
);
50 set_point (EXPR_VAL
* r
, POINT_3D val
)
53 copy_pt_3d (r
->val
.pt
, val
);
57 print_point (FILE * f
, EXPR_VAL
* val
)
59 FLOAT
*p
= val
->val
.pt
;
60 fprintf (f
, "(" F
"," F
"," F
")", p
[X
], p
[Y
], p
[Z
]);
64 set_vector (EXPR_VAL
* r
, VECTOR_3D val
)
67 copy_vec_3d (r
->val
.vec
, val
);
71 print_vector (FILE * f
, EXPR_VAL
* val
)
73 FLOAT
*v
= val
->val
.vec
;
74 fprintf (f
, "[" F
"," F
"," F
"]", v
[X
], v
[Y
], v
[Z
]);
78 set_transform (EXPR_VAL
* r
, TRANSFORM val
)
81 copy_transform (r
->val
.xf
, val
);
85 print_transform (FILE * f
, EXPR_VAL
* val
)
87 FLOAT
*xf
= val
->val
.xf
;
91 for (i
= 0; i
< 4; i
++)
94 for (j
= 0; j
< 16; j
+= 4)
95 fprintf (f
, "%s" F
, (j
== 0) ? "" : ",", xf
[i
+ j
]);
101 // coerce an expression value to given type
102 // generate error message if it can't be done
104 coerce_to_float (EXPR_VAL
* r
, FLOAT
* val
, SRC_LINE line
)
106 if (r
->tag
== E_FLOAT
)
113 err (line
, "expected float, found %s", expr_val_type_str
[r
->tag
]);
118 coerce_to_point (EXPR_VAL
* r
, POINT_3D val
, SRC_LINE line
)
120 if (r
->tag
== E_POINT
)
122 copy_pt_3d (val
, r
->val
.pt
);
126 val
[X
] = val
[Y
] = val
[Z
] = 0;
127 err (line
, "expected point, found %s", expr_val_type_str
[r
->tag
]);
132 coerce_to_vector (EXPR_VAL
* r
, VECTOR_3D val
, SRC_LINE line
)
134 if (r
->tag
== E_VECTOR
)
136 copy_vec_3d (val
, r
->val
.vec
);
140 val
[X
] = val
[Y
] = val
[Z
] = 0;
141 err (line
, "expected vector, found %s", expr_val_type_str
[r
->tag
]);
146 coerce_to_transform (EXPR_VAL
* r
, TRANSFORM val
, SRC_LINE line
)
148 if (r
->tag
== E_TRANSFORM
)
150 copy_transform (val
, r
->val
.xf
);
155 err (line
, "expected transform, found %s", expr_val_type_str
[r
->tag
]);
159 typedef void (*PRINT_FUNC
) (FILE *, EXPR_VAL
*);
161 static PRINT_FUNC print_expr_val_tbl
[] = {
169 print_expr_val (FILE * f
, EXPR_VAL
* r
)
171 (*print_expr_val_tbl
[r
->tag
]) (f
, r
);
174 #define HASH(A, B) (((A) << 2) | (B))
177 do_add (EXPR_VAL
* r
, EXPR_VAL
* a
, EXPR_VAL
* b
, SRC_LINE line
)
179 switch (HASH (a
->tag
, b
->tag
))
181 case HASH (E_FLOAT
, E_FLOAT
):
182 set_float (r
, a
->val
.flt
+ b
->val
.flt
);
184 case HASH (E_POINT
, E_VECTOR
):
186 add_vec_to_pt_3d (r
->val
.pt
, a
->val
.pt
, b
->val
.vec
);
188 case HASH (E_VECTOR
, E_POINT
):
190 add_vec_to_pt_3d (r
->val
.pt
, b
->val
.pt
, a
->val
.vec
);
192 case HASH (E_VECTOR
, E_VECTOR
):
194 add_vecs_3d (r
->val
.vec
, a
->val
.vec
, b
->val
.vec
);
197 err (line
, "operands of + (types %s and %s) cannot be added",
198 expr_val_type_str
[a
->tag
], expr_val_type_str
[b
->tag
]);
205 do_sub (EXPR_VAL
* r
, EXPR_VAL
* a
, EXPR_VAL
* b
, SRC_LINE line
)
207 switch (HASH (a
->tag
, b
->tag
))
209 case HASH (E_FLOAT
, E_FLOAT
):
210 set_float (r
, a
->val
.flt
- b
->val
.flt
);
212 case HASH (E_POINT
, E_POINT
):
214 sub_pts_3d (r
->val
.vec
, a
->val
.pt
, b
->val
.pt
);
216 case HASH (E_POINT
, E_VECTOR
):
218 add_scaled_vec_to_pt_3d (r
->val
.pt
, a
->val
.pt
, b
->val
.vec
, -1);
220 case HASH (E_VECTOR
, E_VECTOR
):
222 sub_vecs_3d (r
->val
.vec
, a
->val
.vec
, b
->val
.vec
);
225 err (line
, "operands of - (types %s and %s) cannot be subtracted",
226 expr_val_type_str
[a
->tag
], expr_val_type_str
[b
->tag
]);
233 do_mul (EXPR_VAL
* r
, EXPR_VAL
* a
, EXPR_VAL
* b
, SRC_LINE line
)
235 switch (HASH (a
->tag
, b
->tag
))
237 case HASH (E_FLOAT
, E_FLOAT
):
238 set_float (r
, a
->val
.flt
* b
->val
.flt
);
240 case HASH (E_VECTOR
, E_FLOAT
):
242 scale_vec_3d (r
->val
.vec
, a
->val
.vec
, b
->val
.flt
);
244 case HASH (E_FLOAT
, E_VECTOR
):
246 scale_vec_3d (r
->val
.vec
, b
->val
.vec
, a
->val
.flt
);
248 case HASH (E_VECTOR
, E_VECTOR
):
250 cross (r
->val
.vec
, a
->val
.vec
, b
->val
.vec
);
252 case HASH (E_TRANSFORM
, E_TRANSFORM
):
253 r
->tag
= E_TRANSFORM
;
254 compose (r
->val
.xf
, a
->val
.xf
, b
->val
.xf
);
256 case HASH (E_TRANSFORM
, E_POINT
):
258 transform_pt_3d (r
->val
.pt
, a
->val
.xf
, b
->val
.pt
);
260 case HASH (E_TRANSFORM
, E_VECTOR
):
262 transform_vec_3d (r
->val
.vec
, a
->val
.xf
, b
->val
.vec
);
265 err (line
, "operands of * (types %s and %s) cannot be multiplied",
266 expr_val_type_str
[a
->tag
], expr_val_type_str
[b
->tag
]);
273 do_thn (EXPR_VAL
* r
, EXPR_VAL
* a
, EXPR_VAL
* b
, SRC_LINE line
)
275 switch (HASH (a
->tag
, b
->tag
))
277 case HASH (E_TRANSFORM
, E_TRANSFORM
):
278 r
->tag
= E_TRANSFORM
;
279 compose (r
->val
.xf
, b
->val
.xf
, a
->val
.xf
);
281 case HASH (E_POINT
, E_TRANSFORM
):
283 transform_pt_3d (r
->val
.pt
, b
->val
.xf
, a
->val
.pt
);
285 case HASH (E_VECTOR
, E_TRANSFORM
):
287 transform_vec_3d (r
->val
.vec
, b
->val
.xf
, a
->val
.vec
);
291 "operands of 'then' (types %s and %s) cannot be multiplied",
292 expr_val_type_str
[a
->tag
], expr_val_type_str
[b
->tag
]);
299 safe_dvd (FLOAT a
, FLOAT b
, SRC_LINE line
)
301 if (-FLOAT_EPS
< b
&& b
< FLOAT_EPS
)
303 err (line
, "attempt to divide " F
" by zero", a
);
310 do_dvd (EXPR_VAL
* r
, EXPR_VAL
* a
, EXPR_VAL
* b
, SRC_LINE line
)
312 switch (HASH (a
->tag
, b
->tag
))
314 case HASH (E_FLOAT
, E_FLOAT
):
315 set_float (r
, safe_dvd (a
->val
.flt
, b
->val
.flt
, line
));
317 case HASH (E_VECTOR
, E_FLOAT
):
319 scale_vec_3d (r
->val
.vec
, a
->val
.vec
, safe_dvd (1, b
->val
.flt
, line
));
321 case HASH (E_FLOAT
, E_VECTOR
):
323 scale_vec_3d (r
->val
.vec
, b
->val
.vec
, safe_dvd (1, a
->val
.flt
, line
));
326 err (line
, "operands of / (types %s and %s) cannot be divided",
327 expr_val_type_str
[a
->tag
], expr_val_type_str
[b
->tag
]);
334 do_dot (EXPR_VAL
* r
, EXPR_VAL
* a
, EXPR_VAL
* b
, SRC_LINE line
)
336 switch (HASH (a
->tag
, b
->tag
))
338 case HASH (E_VECTOR
, E_VECTOR
):
340 r
->val
.flt
= dot_3d (a
->val
.vec
, b
->val
.vec
);
342 case HASH (E_FLOAT
, E_FLOAT
):
343 case HASH (E_VECTOR
, E_FLOAT
):
344 case HASH (E_FLOAT
, E_VECTOR
):
345 case HASH (E_TRANSFORM
, E_TRANSFORM
):
346 case HASH (E_TRANSFORM
, E_POINT
):
347 case HASH (E_TRANSFORM
, E_VECTOR
):
348 do_mul (r
, a
, b
, line
);
351 err (line
, "operands of dot (types %s and %s) cannot be multiplied",
352 expr_val_type_str
[a
->tag
], expr_val_type_str
[b
->tag
]);
359 do_index (EXPR_VAL
* r
, EXPR_VAL
* a
, int index
, SRC_LINE line
)
364 set_float (r
, a
->val
.vec
[index
]);
367 set_float (r
, a
->val
.pt
[index
]);
371 "operand of 'index is a %s and should be a point or a vector",
372 expr_val_type_str
[a
->tag
]);
379 do_inverse (TRANSFORM inv
, TRANSFORM xf
, SRC_LINE line
)
382 invert (inv
, &det
, xf
, 1e-4);
385 err (line
, "inverse of singular transform");
390 // put a^n into r; r and a can't both be the same storage
391 // exploits a^(2n) = (a^n)^2 to reduce work
393 do_transform_power (TRANSFORM r
, TRANSFORM a
, int n
, SRC_LINE line
)
398 do_inverse (inv
, a
, line
);
399 do_transform_power (r
, inv
, -n
, line
);
407 int m
= (int) bit (30);
410 copy_transform (r
, a
);
411 for (m
>>= 1; m
; m
>>= 1)
421 to_integer (FLOAT x
, int *n
)
423 double frac_part
, int_part
;
425 frac_part
= modf (x
, &int_part
);
426 if (-1e9
<= int_part
&& int_part
<= 1e9
)
435 do_pwr (EXPR_VAL
* r
, EXPR_VAL
* a
, EXPR_VAL
* b
, SRC_LINE line
)
440 switch (HASH (a
->tag
, b
->tag
))
442 case HASH (E_FLOAT
, E_FLOAT
):
443 set_float (r
, pow (a
->val
.flt
, b
->val
.flt
));
445 case HASH (E_TRANSFORM
, E_FLOAT
):
446 if (to_integer (b
->val
.flt
, &n
))
448 do_transform_power (xf_pwr
, a
->val
.xf
, n
, line
);
452 err (line
, "transform power out of domain (integer -1e9..1e9)");
455 set_transform (r
, xf_pwr
);
458 err (line
, "operands of ^ (types %s and %s) must be type float",
459 expr_val_type_str
[a
->tag
], expr_val_type_str
[b
->tag
]);
466 do_mag (EXPR_VAL
* r
, EXPR_VAL
* a
, SRC_LINE line
)
471 set_float (r
, a
->val
.flt
>= 0 ? a
->val
.flt
: -a
->val
.flt
);
474 set_float (r
, length_vec_3d (a
->val
.vec
));
477 err (line
, "operand of magnitude operator (type %s) must be vector",
478 expr_val_type_str
[a
->tag
]);
485 do_neg (EXPR_VAL
* r
, EXPR_VAL
* a
, SRC_LINE line
)
490 set_float (r
, -a
->val
.flt
);
494 negate_vec_3d (r
->val
.vec
, a
->val
.vec
);
497 err (line
, "operand of unary minus (type %s) cannot be negated",
498 expr_val_type_str
[a
->tag
]);
505 do_unit (EXPR_VAL
* r
, EXPR_VAL
* a
, SRC_LINE line
)
507 if (a
->tag
== E_VECTOR
)
510 find_unit_vec_3d (r
->val
.vec
, a
->val
.vec
);
514 static VECTOR_3D k
= { 0, 0, 1 };
515 err (line
, "operand of unit operator (type %s) must be vector",
516 expr_val_type_str
[a
->tag
]);
522 do_sqrt (EXPR_VAL
* r
, EXPR_VAL
* a
, SRC_LINE line
)
528 err (line
, "square root of negative number");
529 set_float (r
, sqrt (a
->val
.flt
));
532 err (line
, "operand of sqrt (type %s) must be float",
533 expr_val_type_str
[a
->tag
]);
539 do_sin (EXPR_VAL
* r
, EXPR_VAL
* a
, SRC_LINE line
)
544 set_float (r
, sin ((PI
/ 180) * a
->val
.flt
));
547 err (line
, "operand of sin (type %s) must be float",
548 expr_val_type_str
[a
->tag
]);
554 do_cos (EXPR_VAL
* r
, EXPR_VAL
* a
, SRC_LINE line
)
559 set_float (r
, cos ((PI
/ 180) * a
->val
.flt
));
562 err (line
, "operand of cos (type %s) must be float",
563 expr_val_type_str
[a
->tag
]);
569 do_atan2 (EXPR_VAL
* r
, EXPR_VAL
* a
, EXPR_VAL
* b
, SRC_LINE line
)
571 switch (HASH (a
->tag
, b
->tag
))
573 case HASH (E_FLOAT
, E_FLOAT
):
574 set_float (r
, (180 / PI
) * atan2 (a
->val
.flt
, b
->val
.flt
));
577 err (line
, "operands of atan2 (types %s, %s) must be float",
578 expr_val_type_str
[a
->tag
], expr_val_type_str
[b
->tag
]);