1 /*
2  *  Eukleides version 1.5.4
3  *  Copyright (c) Christian Obrecht 2004-2010
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 3 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 
20 #include <stdlib.h>
21 #include <math.h>
22 #include "error.h"
23 #include "symbol.h"
24 #include "core.h"
25 #include "conic.h"
26 #include "utils.h"
27 #include "parser.tab.h"
28 
create_point_cartesian(void)29 void create_point_cartesian(void)
30 {
31     _point *val;
32 
33     get_mem(val, _point);
34     val->y = POPn;
35     val->x = POPn;
36     PSH(val);
37 }
38 
create_point_polar(void)39 void create_point_polar(void)
40 {
41     double r, a;
42     _point *val;
43 
44     get_mem(val, _point);
45     a = POPn;
46     r = POPn;
47     val->x = r*Cos(a);
48     val->y = r*Sin(a);
49     PSH(val);
50 }
51 
create_point_on_segment(void)52 void create_point_on_segment(void)
53 {
54     double x;
55     _set *set;
56     _point *A, *B;
57     _point *val;
58 
59     x = POPn;
60     set = POP(_set);
61     A = get_point(&set);
62     B = get_point(&set);
63     get_mem(val, _point);
64     val->x = A->x + x*(B->x - A->x);
65     val->y = A->y + x*(B->y - A->y);
66     PSH(val);
67 }
68 
create_point_on_line(void)69 void create_point_on_line(void)
70 {
71     double x;
72     _line *l;
73     _point *val;
74 
75     x = POPn;
76     l = POP(_line);
77     get_mem(val, _point);
78     val->x = l->x + x*Cos(l->a);
79     val->y = l->y + x*Sin(l->a);
80     PSH(val);
81 }
82 
create_point_with_abscissa(void)83 void create_point_with_abscissa(void)
84 {
85     double x, c;
86     _line *l;
87     _point *val;
88 
89     x = POPn;
90     l = POP(_line);
91     c = Cos(l->a);
92     if (ZERO(c)) runtime_error(_("invalid line"));
93     get_mem(val, _point);
94     val->x = x;
95     val->y = l->y + (x-l->x)*Sin(l->a)/c;
96     PSH(val);
97 }
98 
create_point_with_ordinate(void)99 void create_point_with_ordinate(void)
100 {
101     double y, s;
102     _line *l;
103     _point *val;
104 
105     y = POPn;
106     l = POP(_line);
107     s = Sin(l->a);
108     if (ZERO(s)) runtime_error(_("invalid line"));
109     get_mem(val, _point);
110     val->x = l->x + (y-l->y)*Cos(l->a)/s;
111     val->y = y;
112     PSH(val);
113 }
114 
create_point_on_circle(void)115 void create_point_on_circle(void)
116 {
117     double a;
118     _circle *c;
119     _point *val;
120 
121     a = POPn;
122     c = POP(_circle);
123     get_mem(val, _point);
124     val->x = c->x + c->r*Cos(a);
125     val->y = c->y + c->r*Sin(a);
126     PSH(val);
127 }
128 
create_point_on_conic(void)129 void create_point_on_conic(void)
130 {
131     _conic *C;
132     _point *val;
133     double c, s, t;
134 
135     t = POPn;
136     C = POP(_conic);
137     c = Cos(C->d);
138     s = Sin(C->d);
139     get_mem(val, _point);
140     switch (C->type) {
141 	case ELLIPSE:
142 	    parametric_ellipse(&(val->x), &(val->y), t,
143 			       C->x, C->y, C->a, C->b, c, s);
144 	    break;
145 	case HYPERBOLA:
146 	    if (t <= -180 || t >= 180 || t == 0)
147 		runtime_error("invalid argument");
148 	    parametric_hyperbola(&(val->x), &(val->y), t,
149 				 C->x, C->y, C->a, C->b, c, s);
150 	    break;
151     	case PARABOLA:
152 	    if (t <= -180 || t >= 180) runtime_error("invalid argument");
153 	    parametric_parabola(&(val->x), &(val->y), t,
154 				C->x, C->y, C->a, c, s);
155 	    break;
156     }
157     PSH(val);
158 }
159 
create_midpoint(void)160 void create_midpoint(void)
161 {
162     _set *set;
163     _point *A, *B;
164     _point *val;
165 
166     set = POP(_set);
167     A = get_point(&set);
168     B = get_point(&set);
169     get_mem(val, _point);
170     val->x = (A->x + B->x)/2;
171     val->y = (A->y + B->y)/2;
172     PSH(val);
173 }
174 
create_isobarycenter(void)175 void create_isobarycenter(void)
176 {
177     int n = 0;
178     _set *set;
179     _point *val;
180 
181     set = POP(_set);
182     if (set == NULL) runtime_error(_("empty set"));
183     get_mem(val, _point);
184     val->x = 0;
185     val->y = 0;
186     do {
187 	val->x += set->p->x;
188 	val->y += set->p->y;
189 	n++;
190 	set = set->next;
191     } while (set != NULL);
192     val->x /= n;
193     val->y /= n;
194     PSH(val);
195 }
196 
create_barycenter(void)197 void create_barycenter(void)
198 {
199     double c, s = 0;
200     _point *cur, *val;
201 
202     get_mem(val, _point);
203     val->x = 0;
204     val->y = 0;
205     c = POPn;
206     cur = POP(_point);
207     do {
208 	val->x += c*cur->x;
209 	val->y += c*cur->y;
210 	s += c;
211 	c = POPn;
212 	cur = POP(_point);
213     } while (cur != NULL);
214     val->x /= s;
215     val->y /= s;
216     PSH(val);
217 }
218 
219 #define cosine(a, b, c)	(b*b + c*c - a*a)/(2*b*c)
220 
221 #define tangent(x)	sqrt(1-x*x)/x
222 
create_orthocenter(void)223 void create_orthocenter(void)
224 {
225     _point *A, *B, *C, *val;
226     double a, b, c, ca, cb, cc, d;
227 
228     C = POP(_point);
229     B = POP(_point);
230     A = POP(_point);
231     get_mem(val, _point);
232     a = distance(B, C);
233     b = distance(C, A);
234     c = distance(A, B);
235     if (ZERO(a) || ZERO(b) || ZERO(c)) runtime_error(_("invalid triangle"));
236     ca = cosine(a, b, c);
237     cb = cosine(b, c, a);
238     cc = cosine(c, a, b);
239     if (ca == 0) {
240 	ca = 1; cb = 0; cc = 0;
241     } else if (cb == 0) {
242 	ca = 0; cb = 1; cc = 0;
243     } else if (cc == 0) {
244 	ca = 0; cb = 0; cc = 1;
245     } else {
246 	ca = tangent(ca); cb = tangent(cb); cc = tangent(cc);
247     }
248     d = ca + cb + cc;
249     val->x = (ca*A->x + cb*B->x + cc*C->x)/d;
250     val->y = (ca*A->y + cb*B->y + cc*C->y)/d;
251     PSH(val);
252 }
253 
translate_point(void)254 void translate_point(void)
255 {
256     _point *A, *val;
257     _vector *u;
258 
259     u = POP(_vector);
260     A = POP(_point);
261     get_mem(val, _point);
262     val->x = A->x + u->x;
263     val->y = A->y + u->y;
264     PSH(val);
265 }
266 
reflect_point(void)267 void reflect_point(void)
268 {
269     _point *A, *val;
270     _line *l;
271     double c, s, x, y, p;
272 
273     l = POP(_line);
274     A = POP(_point);
275     c = Cos(l->a);
276     s = Sin(l->a);
277     x = A->x - l->x;
278     y = A->y - l->y;
279     p = 2*(c*x + s*y);
280     get_mem(val, _point);
281     val->x = l->x + p*c - x;
282     val->y = l->y + p*s - y;
283     PSH(val);
284 }
285 
symetric_point(void)286 void symetric_point(void)
287 {
288     _point *A, *O, *val;
289 
290     O = POP(_point);
291     A = POP(_point);
292     get_mem(val, _point);
293     val->x = 2*O->x - A->x;
294     val->y = 2*O->y - A->y;
295     PSH(val);
296 }
297 
rotate_point(void)298 void rotate_point(void)
299 {
300     _point *A, *O, *val;
301     double a, c, s, x, y;
302 
303     a = POPn;
304     O = POP(_point);
305     A = POP(_point);
306     c = Cos(a);
307     s = Sin(a);
308     x = A->x - O->x;
309     y = A->y - O->y;
310     get_mem(val, _point);
311     val->x = O->x + c*x - s*y;
312     val->y = O->y + s*x + c*y;
313     PSH(val);
314 }
315 
homothetic_point(void)316 void homothetic_point(void)
317 {
318     _point *A, *O, *val;
319     double k;
320 
321     k = POPn;
322     O = POP(_point);
323     A = POP(_point);
324     get_mem(val, _point);
325     val->x = O->x + k*(A->x - O->x);
326     val->y = O->y + k*(A->y - O->y);
327     PSH(val);
328 }
329 
point_abscissa(void)330 void point_abscissa(void)
331 {
332     PSHn((POP(_point))->x);
333 }
334 
point_ordinate(void)335 void point_ordinate(void)
336 {
337     PSHn((POP(_point))->y);
338 }
339 
points_distance(void)340 void points_distance(void)
341 {
342     _point *A, *B;
343 
344     A = POP(_point);
345     B = POP(_point);
346     PSHn(distance(A, B));
347 }
348