1 /*  Part of XPCE --- The SWI-Prolog GUI toolkit
2 
3     Author:        Jan Wielemaker and Anjo Anjewierden
4     E-mail:        jan@swi.psy.uva.nl
5     WWW:           http://www.swi.psy.uva.nl/projects/xpce/
6     Copyright (c)  1985-2002, University of Amsterdam
7     All rights reserved.
8 
9     Redistribution and use in source and binary forms, with or without
10     modification, are permitted provided that the following conditions
11     are met:
12 
13     1. Redistributions of source code must retain the above copyright
14        notice, this list of conditions and the following disclaimer.
15 
16     2. Redistributions in binary form must reproduce the above copyright
17        notice, this list of conditions and the following disclaimer in
18        the documentation and/or other materials provided with the
19        distribution.
20 
21     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24     FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25     COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31     ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32     POSSIBILITY OF SUCH DAMAGE.
33 */
34 
35 #include <h/kernel.h>
36 #include <h/graphics.h>
37 #include <math.h>
38 #ifndef M_PI
39 #define M_PI (3.141593)
40 #endif
41 
42 #ifdef MAXFLOAT
43 #define DBL_INFINITE MAXFLOAT
44 #elif defined(HUGE_VAL)
45 #define DBL_INFINITE HUGE_VAL
46 #else
47 #define DBL_INFINITE HUGE
48 #endif
49 
50 
51 status
initialiseLine(Line ln,Int xa,Int ya,Int xb,Int yb,Name arrows)52 initialiseLine(Line ln, Int xa, Int ya, Int xb, Int yb, Name arrows)
53 { if ( isDefault(xa) )	xa = ZERO;
54   if ( isDefault(ya) )	ya = ZERO;
55   if ( isDefault(xb) )	xb = ZERO;
56   if ( isDefault(yb) )	yb = ZERO;
57 
58   assign(ln, start_x, xa);
59   assign(ln, start_y, ya);
60   assign(ln, end_x,   xb);
61   assign(ln, end_y,   yb);
62 
63   initialiseJoint((Joint) ln, ZERO, ZERO, ZERO, ZERO, arrows);
64 
65   return requestComputeGraphical(ln, DEFAULT);
66 }
67 
68 
69 #define area_points(x, y, w, h)         { x1 = x;                       \
70                                           y1 = y;                       \
71                                           x2 = x+w;                     \
72                                           x2 += (w>=0 ? -1 : 1);        \
73                                           y2 = y+h;                     \
74                                           y2 += (h>=0 ? -1 : 1);        \
75                                         }
76 
77 static status
loadLine(Line ln,IOSTREAM * fd,ClassDef def)78 loadLine(Line ln, IOSTREAM *fd, ClassDef def)
79 { TRY(loadSlotsObject(ln, fd, def));
80 
81   if ( isNil(ln->start_x) )		/* convert old (pre-4.9.4) line */
82   { Area a = ln->area;			/* representation */
83     int x = valInt(a->x);
84     int y = valInt(a->y);
85     int w = valInt(a->w);
86     int h = valInt(a->h);
87     int x1, y1, x2, y2;
88 
89     area_points(x, y, w, h);
90     assign(ln, start_x, toInt(x1));
91     assign(ln, start_y, toInt(y1));
92     assign(ln, end_x,   toInt(x2));
93     assign(ln, end_y,   toInt(y2));
94   }
95 
96   succeed;
97 }
98 
99 
100 status
adjustFirstArrowLine(Line ln)101 adjustFirstArrowLine(Line ln)
102 { if ( notNil(ln->first_arrow) )
103   { Any av[4];
104 
105     av[0] = ln->start_x;
106     av[1] = ln->start_y;
107     av[2] = ln->end_x;
108     av[3] = ln->end_y;
109 
110     if ( qadSendv(ln->first_arrow, NAME_points, 4, av) )
111     { assign(ln->first_arrow, displayed, ON);
112 
113       return ComputeGraphical(ln->first_arrow);
114     }
115   }
116 
117   fail;
118 }
119 
120 
121 status
adjustSecondArrowLine(Line ln)122 adjustSecondArrowLine(Line ln)
123 { if ( notNil(ln->second_arrow) )
124   { Any av[4];
125 
126     av[0] = ln->end_x;
127     av[1] = ln->end_y;
128     av[2] = ln->start_x;
129     av[3] = ln->start_y;
130 
131     if ( qadSendv(ln->second_arrow, NAME_points, 4, av) )
132     { assign(ln->second_arrow, displayed, ON);
133 
134       return ComputeGraphical(ln->second_arrow);
135     }
136   }
137 
138   fail;
139 }
140 
141 
142 status
computeLine(Line ln)143 computeLine(Line ln)
144 { if ( notNil(ln->request_compute) )
145   { int x1  = valInt(ln->start_x);
146     int x2  = valInt(ln->end_x);
147     int y1  = valInt(ln->start_y);
148     int y2  = valInt(ln->end_y);
149     int pen = valInt(ln->pen);
150     int x, y, w, h;
151     Area a = ln->area;
152 
153     if ( x1 < x2 )
154     { x = x1;
155       w = x2-x1;
156     } else
157     { x = x2;
158       w = x1-x2;
159     }
160     if ( y1 < y2 )
161     { y = y1;
162       h = y2-y1;
163     } else
164     { y = y2;
165       h = y1-y2;
166     }
167 
168     if ( pen ==	1 )
169     { w++;
170       h++;
171     } else if ( pen > 1 )
172     { int ex = (h > 0 ? (pen*h)/(w+h) : 0); /* h = 0: horizontal line */
173       int ey = (w > 0 ? (pen*w)/(w+h) : 0); /* w = 0: vertical line */
174       int hx = ex/2;
175       int hy = ey/2;
176 
177       x -= hx;
178       w += ex;
179       y -= hy;
180       h += ey;
181     }
182 
183     if ( ln->selected == ON )	/* should be solved elsewhere */
184     { x -= 3;
185       y -= 3;
186       w += 6;
187       h += 6;
188     }
189 
190     CHANGING_GRAPHICAL(ln,
191 		       assign(a, x, toInt(x));
192 		       assign(a, y, toInt(y));
193 		       assign(a, w, toInt(w));
194 		       assign(a, h, toInt(h));
195 
196 		       if ( adjustFirstArrowLine(ln) )
197 			 unionNormalisedArea(a, ln->first_arrow->area);
198 		       if ( adjustSecondArrowLine(ln) )
199 			 unionNormalisedArea(a, ln->second_arrow->area);
200 
201 		       changedEntireImageGraphical(ln));
202 
203     assign(ln, request_compute, NIL);
204   }
205 
206   succeed;
207 }
208 
209 
210 status
copyLine(Line l1,Line l2)211 copyLine(Line l1, Line l2)
212 { copyJoint((Joint) l1, (Joint) l2);
213 
214   assign(l1, start_x, l2->start_x);
215   assign(l1, start_y, l2->start_y);
216   assign(l1, end_x,   l2->end_x);
217   assign(l1, end_y,   l2->end_y);
218 
219   succeed;
220 }
221 
222 
223 static status
RedrawAreaLine(Line ln,Area a)224 RedrawAreaLine(Line ln, Area a)
225 { int x, y, w, h;
226   int x1 = valInt(ln->start_x);
227   int x2 = valInt(ln->end_x);
228   int y1 = valInt(ln->start_y);
229   int y2 = valInt(ln->end_y);
230   int pen = valInt(ln->pen);
231 
232   initialiseDeviceGraphical(ln, &x, &y, &w, &h);
233 
234   if ( pen != 0 )
235   { r_thickness(pen);
236     r_dash(ln->texture);
237     r_line(x1, y1, x2, y2);
238   }
239 
240   if ( adjustFirstArrowLine(ln) )
241     RedrawArea(ln->first_arrow, a);
242   if ( adjustSecondArrowLine(ln) )
243     RedrawArea(ln->second_arrow, a);
244 
245   return RedrawAreaGraphical(ln, a);
246 }
247 
248 
249 status
paintSelectedLine(Line ln)250 paintSelectedLine(Line ln)		/* assumes device is initialised! */
251 { r_complement(valInt(ln->start_x)-2, valInt(ln->start_y)-2, 5, 5);
252   r_complement(valInt(ln->end_x)-2,   valInt(ln->end_y)-2,   5, 5);
253 
254   succeed;
255 }
256 
257 
258 static status
geometryLine(Line ln,Int x,Int y,Int w,Int h)259 geometryLine(Line ln, Int x, Int y, Int w, Int h)
260 { int needcompute = FALSE;
261   Int dx = ZERO, dy = ZERO;
262 
263   if ( notDefault(w) )
264   { assign(ln, end_x, add(ln->start_x, w));
265     needcompute++;
266   }
267   if ( notDefault(h) )
268   { assign(ln, end_y, add(ln->start_y, h));
269     needcompute++;
270   }
271 
272   if ( notDefault(x) )
273   { dx = sub(x, ln->area->x);
274     assign(ln, start_x, add(ln->start_x, dx));
275     assign(ln, end_x, add(ln->end_x, dx));
276   }
277   if ( notDefault(y) )
278   { dy = sub(y, ln->area->y);
279     assign(ln, start_y, add(ln->start_y, dy));
280     assign(ln, end_y, add(ln->end_y, dy));
281   }
282 
283   CHANGING_GRAPHICAL(ln,
284 		     if ( needcompute )
285 		       requestComputeGraphical(ln, DEFAULT);
286 		     else
287 		     { Area a = ln->area;
288 
289 		       assign(a, x, add(a->x, dx));
290 		       assign(a, y, add(a->y, dy));
291 		       changedEntireImageGraphical(ln);
292 		     });
293 
294   succeed;
295 }
296 
297 
298 static status
startLine(Line ln,Point pos)299 startLine(Line ln, Point pos)
300 { return pointsLine(ln, pos->x, pos->y, DEFAULT, DEFAULT);
301 }
302 
303 
304 static status
endLine(Line ln,Point pos)305 endLine(Line ln, Point pos)
306 { return pointsLine(ln, DEFAULT, DEFAULT, pos->x, pos->y);
307 }
308 
309 
310 static status
startXLine(Line ln,Int x)311 startXLine(Line ln, Int x)
312 { return pointsLine(ln, x, DEFAULT, DEFAULT, DEFAULT);
313 }
314 
315 
316 static status
startYLine(Line ln,Int y)317 startYLine(Line ln, Int y)
318 { return pointsLine(ln, DEFAULT, y, DEFAULT, DEFAULT);
319 }
320 
321 
322 static status
endXLine(Line ln,Int x)323 endXLine(Line ln, Int x)
324 { return pointsLine(ln, DEFAULT, DEFAULT, x, DEFAULT);
325 }
326 
327 
328 static status
endYLine(Line ln,Int y)329 endYLine(Line ln, Int y)
330 { return pointsLine(ln, DEFAULT, DEFAULT, DEFAULT, y);
331 }
332 
333 
334 static Point
getStartLine(Line ln)335 getStartLine(Line ln)
336 { answer(answerObject(ClassPoint, ln->start_x, ln->start_y, EAV));
337 }
338 
339 
340 static Point
getEndLine(Line ln)341 getEndLine(Line ln)
342 { answer(answerObject(ClassPoint, ln->end_x, ln->end_y, EAV));
343 }
344 
345 
346 status
pointsLine(Line ln,Int sx,Int sy,Int ex,Int ey)347 pointsLine(Line ln, Int sx, Int sy, Int ex, Int ey)
348 { if ( !isDefault(sx) ) assign(ln, start_x, sx);
349   if ( !isDefault(sy) ) assign(ln, start_y, sy);
350   if ( !isDefault(ex) ) assign(ln, end_x,   ex);
351   if ( !isDefault(ey) ) assign(ln, end_y,   ey);
352 
353   return requestComputeGraphical(ln, DEFAULT);
354 }
355 
356 
357 static status
resizeLine(Line ln,Real xfactor,Real yfactor,Point origin)358 resizeLine(Line ln, Real xfactor, Real yfactor, Point origin)
359 { float xf, yf;
360   int ox = valInt(ln->area->x);
361   int oy = valInt(ln->area->y);
362 
363   init_resize_graphical(ln, xfactor, yfactor, origin, &xf, &yf, &ox, &oy);
364   if ( xf != 1.0 || yf != 1.0 )
365   { int x1, y1, x2, y2;
366 
367     x1 = ox + rfloat((float) (valInt(ln->start_x)-ox) * xf);
368     x2 = ox + rfloat((float) (valInt(ln->end_x)-ox)   * xf);
369     y1 = oy + rfloat((float) (valInt(ln->start_y)-oy) * yf);
370     y2 = oy + rfloat((float) (valInt(ln->end_y)-oy)   * yf);
371 
372     assign(ln, start_x, toInt(x1));
373     assign(ln, start_y, toInt(y1));
374     assign(ln, end_x,   toInt(x2));
375     assign(ln, end_y,   toInt(y2));
376 
377     return requestComputeGraphical(ln, DEFAULT);
378   }
379 
380   succeed;
381 }
382 
383 
384 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
385 int distanceLineToPoint()
386 
387 Calculate the distance between the infinite   extended line through (x1,
388 y1) and (x2, y2) to  the  point  (px,   py)  or,  if  extended is 0, the
389 distance to the line-segment between the two points.
390 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
391 
392 static int
dist(int x1,int y1,int x2,int y2)393 dist(int x1, int y1, int x2, int y2)
394 { double dx = (double)(x2-x1);
395   double dy = (double)(y2-y1);
396 
397   return rfloat(sqrt(dx*dx+dy*dy));
398 }
399 
400 
401 int
distanceLineToPoint(int x1,int y1,int x2,int y2,int px,int py,int extended)402 distanceLineToPoint(int x1, int y1, int x2, int y2, int px, int py,
403 		    int extended)
404 { float a;
405 
406   if ( y1 == y2 )
407   { if ( extended )
408     { return abs(y1 - py);
409     } else
410     { if ( x1 < x2 )
411       { if ( px < x1 )
412 	  return dist(x1, y1, px, py);
413 	else if ( px > x2 )
414 	  return dist(x2, y2, px, py);
415 	else
416 	  return abs(y1 - py);
417       } else
418       { if ( px < x2 )
419 	  return dist(x2, y2, px, py);
420 	else if ( px > x1 )
421 	  return dist(x1, y1, px, py);
422 	else
423 	  return abs(y1 - py);
424       }
425     }
426   }
427 
428   if ( x1 == x2 )
429   { if ( extended )
430     { return abs(x1 - px);
431     } else
432     { if ( y1 < y2 )
433       { if ( py < y1 )
434 	  return dist(x1, y1, px, py);
435 	else if ( py > y2 )
436 	  return dist(x2, y2, px, py);
437 	else
438 	  return abs(x1 - px);
439       } else
440       { if ( py < y2 )
441 	  return dist(x2, y2, px, py);
442 	else if ( py > y1 )
443 	  return dist(x1, y1, px, py);
444 	else
445 	  return abs(x1 - px);
446       }
447     }
448   }
449 
450   a = ((float)(y2 - y1)) / ((float)(x2 - x1));
451 
452   if ( !extended )
453   { int xproj = rfloat((px - a*(float)(y1-py)+a*a*(float)x1)/(1.0+a*a));
454 
455     /*Cprintf("Xproj = %d\n", xproj);*/
456 
457     if ( x1 < x2 )
458     { if ( xproj < x1 )
459 	return dist(x1, y1, px, py);
460       else if ( xproj > x2 )
461 	return dist(x2, y2, px, py);
462       else
463 	goto not_extended;
464     } else
465     { if ( xproj < x2 )
466 	return dist(x2, y2, px, py);
467       else if ( xproj > x1 )
468 	return dist(x1, y1, px, py);
469       else
470 	goto not_extended;
471     }
472   }
473 
474 not_extended:
475   return abs(rfloat((((float)(px - x1)) * a + ((float)(y1 - py))) /
476 					 sqrt(1.0 + a*a)));
477 }
478 
479 
480 static status
inEventAreaLine(Line ln,Int x,Int y)481 inEventAreaLine(Line ln, Int x, Int y)
482 { int d;
483   static int evtol = -1;
484 
485   if ( evtol < 0 )
486   { Int v = getClassVariableValueObject(ln, NAME_eventTolerance);
487     evtol = (v ? valInt(v) : 5);
488   }
489 
490   d = distanceLineToPoint(valInt(ln->start_x), valInt(ln->start_y),
491 			  valInt(ln->end_x), valInt(ln->end_y),
492 			  valInt(x), valInt(y), FALSE);
493   if ( d < evtol )
494     succeed;
495 
496   fail;
497 }
498 
499 
500 static Int
getDistanceLine(Line ln,Any obj,BoolObj segment)501 getDistanceLine(Line ln, Any obj, BoolObj segment)
502 { if ( instanceOfObject(obj, ClassEvent) && notNil(ln->device) )
503   { if ( !(obj = getPositionEvent((EventObj) obj, (Graphical) ln->device)) )
504       fail;
505   }
506 
507   if ( instanceOfObject(obj, ClassPoint) )
508   { Point pt = obj;
509     int extended = (segment != OFF);
510 
511     answer(toInt(distanceLineToPoint(valInt(ln->start_x), valInt(ln->start_y),
512 				     valInt(ln->end_x), valInt(ln->end_y),
513 				     valInt(pt->x), valInt(pt->y), extended)));
514   } else
515   { Graphical gr2 = obj;
516 
517     answer(getDistanceArea(ln->area, gr2->area));
518   }
519 }
520 
521 
522 
523 static Int
getLengthLine(Line ln)524 getLengthLine(Line ln)
525 { int dx = valInt(ln->end_x) - valInt(ln->start_x);
526   int dy = valInt(ln->end_y) - valInt(ln->start_y);
527 
528   answer(toInt(isqrt(dx*dx + dy*dy)));
529 }
530 
531 
532 static void
parms_line(Line ln,int * a,double * b)533 parms_line(Line ln, int *a, double *b)			/* y = a + bx */
534 { int x1 = valInt(ln->start_x);
535   int x2 = valInt(ln->end_x);
536   int y1 = valInt(ln->start_y);
537   int y2 = valInt(ln->end_y);
538 
539   if ( x1 == x2 )
540   { *b = DBL_INFINITE;			/* vertical */
541     *a = 0;
542   } else
543   { *b = (double)(y2 - y1) / (double)(x2 - x1);
544     *a = y1 - rfloat(*b * (double)x1);
545   }
546 
547   DEBUG(NAME_intersection, Cprintf("%d,%d --> %d,%d: y = %d + %2fx\n",
548 				   x1, y1, x2, y2, *a, *b));
549 }
550 
551 
552 Point
getIntersectionLine(Line l1,Line l2)553 getIntersectionLine(Line l1, Line l2)
554 { double b1, b2;
555   int a1, a2;
556   double xx;
557   int xy;
558 
559   parms_line(l1, &a1, &b1);
560   parms_line(l2, &a2, &b2);
561 
562   if ( b1 == b2 )
563     fail;				/* parallel */
564   if ( b1 == DBL_INFINITE )			/* l1 is vertical */
565   { xx = (double) valInt(l1->end_x);
566     xy = a2 + rfloat(b2 * xx);
567   } else if ( b2 == DBL_INFINITE )		/* l2 is vertical */
568   { xx = (double) valInt(l2->end_x);
569     xy = a1 + rfloat(b1 * xx);
570   } else
571   { xx = (double)(a2 - a1) / (b1 - b2);
572     xy = a1 + rfloat(b1 * xx);
573   }
574 
575   answer(answerObject(ClassPoint, toInt(rfloat(xx)), toInt(xy), EAV));
576 }
577 
578 
579 Real
getAngleLine(Line ln,Point p)580 getAngleLine(Line ln, Point p)
581 { int x1 = valInt(ln->start_x);
582   int x2 = valInt(ln->end_x);
583   int y1 = valInt(ln->start_y);
584   int y2 = valInt(ln->end_y);
585   double angle;
586   int rte = 0;				/* relative-to-end */
587 
588   if ( notDefault(p) &&
589        get_distance_point(p, x2, y2) < get_distance_point(p, x1, y1) )
590     rte++;
591 
592   if ( rte )
593     angle = atan2((double)(y2-y1), (double)(x1-x2));
594   else
595     angle = atan2((double)(y1-y2), (double)(x2-x1));
596   if ( angle < 0 )
597     angle = 2.0 * M_PI + angle;
598 
599   angle = (angle * 180.0) / M_PI;
600 
601   answer(CtoReal(angle));
602 }
603 
604 
605 static status
normaliseLine(Line ln)606 normaliseLine(Line ln)
607 { succeed;
608 }
609 
610 
611 static status
orientationLine(Line ln,Name o)612 orientationLine(Line ln, Name o)
613 { succeed;
614 }
615 
616 
617 static status
penLine(Line ln,Int pen)618 penLine(Line ln, Int pen)
619 { if ( ln->pen != pen )
620   { assign(ln, pen, pen);
621 
622     return requestComputeGraphical(ln, DEFAULT);
623   }
624 
625   succeed;
626 }
627 
628 
629 		 /*******************************
630 		 *	 CLASS DECLARATION	*
631 		 *******************************/
632 
633 /* Type declarations */
634 
635 static char *T_points[] =
636         { "start_x=[int]", "start_y=[int]", "end_x=[int]", "end_y=[int]" };
637 static char *T_initialise[] =
638         { "start_x=[int]", "start_y=[int]", "end_x=[int]", "end_y=[int]", "arrows=[{none,first,second,both}]" };
639 static char *T_resize[] =
640 	{ "factor_x=real", "factor_y=[real]", "origin=[point]" };
641 static char *T_geometry[] =
642 	{ "x=[int]", "y=[int]", "width=[int]", "height=[int]" };
643 static char *T_distance[] =
644 	{ "to=graphical|point|event", "segment=[bool]" };
645 
646 /* Instance Variables */
647 
648 vardecl var_line[] =
649 { SV(NAME_startX, "int", IV_GET|IV_STORE, startXLine,
650      NAME_tip, "X of start-point"),
651   SV(NAME_startY, "int", IV_GET|IV_STORE, startYLine,
652      NAME_tip, "Y of start-point"),
653   SV(NAME_endX,   "int", IV_GET|IV_STORE, endXLine,
654      NAME_tip, "X of end-point"),
655   SV(NAME_endY,   "int", IV_GET|IV_STORE, endYLine,
656      NAME_tip, "Y of end-point")
657 };
658 
659 
660 /* Send Methods */
661 
662 static senddecl send_line[] =
663 { SM(NAME_initialise, 5, T_initialise, initialiseLine,
664      DEFAULT, "Create line (X1,Y1) - (X2,Y2) with arrows"),
665   SM(NAME_normalise, 0, NULL, normaliseLine,
666      DEFAULT, "Redefined from graphical: no-op"),
667   SM(NAME_orientation, 1, "{north_west,south_west,north_east,south_east}", orientationLine,
668      DEFAULT, "Redefined from graphical: no-op"),
669   SM(NAME_compute, 0, NULL, computeLine,
670      NAME_update, "Update <-area of the line"),
671   SM(NAME_geometry, 4, T_geometry, geometryLine,
672      NAME_resize, "Define start and vector"),
673   SM(NAME_copy, 1, "line", copyLine,
674      NAME_copy, "Copy attributes from other line"),
675   SM(NAME_DrawPostScript, 1, "{head,body}", drawPostScriptLine,
676      NAME_postscript, "Create PostScript"),
677   SM(NAME_end, 1, "point", endLine,
678      NAME_tip, "Set end-point of line segment"),
679   SM(NAME_points, 4, T_points, pointsLine,
680      NAME_tip, "Reconfigure line (X1,Y1) - (X2,Y2)"),
681   SM(NAME_start, 1, "point", startLine,
682      NAME_tip, "Set start-point of line segment"),
683   SM(NAME_resize, 3, T_resize, resizeLine,
684      NAME_area, "Resize line with specified factor"),
685   SM(NAME_pen, 1, "0..", penLine,
686      NAME_appearance, "Thickness of drawing pen")
687 };
688 
689 /* Get Methods */
690 
691 static getdecl get_line[] =
692 { GM(NAME_angle, 1, "degrees=real", "origin=[point]", getAngleLine,
693      NAME_calculate, "Angle"),
694   GM(NAME_intersection, 1, "point", "with=line", getIntersectionLine,
695      NAME_calculate, "Intersection between both infinitely extended lines"),
696   GM(NAME_length, 0, "int", NULL, getLengthLine,
697      NAME_calculate, "Distance between start and end-points"),
698   GM(NAME_distance, 2, "int", T_distance, getDistanceLine,
699      NAME_calculate, "Distance between areas or to point"),
700   GM(NAME_end, 0, "point", NULL, getEndLine,
701      NAME_tip, "New point representing end-point"),
702   GM(NAME_start, 0, "point", NULL, getStartLine,
703      NAME_tip, "New point representing start-point")
704 };
705 
706 /* Resources */
707 
708 static classvardecl rc_line[] =
709 { RC(NAME_selectionHandles, RC_REFINE, "line",
710      NULL)
711 };
712 
713 /* Class Declaration */
714 
715 static Name line_termnames[] =
716 	{ NAME_startX, NAME_startY, NAME_endX, NAME_endY, NAME_arrows };
717 
718 ClassDecl(line_decls,
719           var_line, send_line, get_line, rc_line,
720           5, line_termnames,
721           "$Rev$");
722 
723 
724 status
makeClassLine(Class class)725 makeClassLine(Class class)
726 { declareClass(class, &line_decls);
727 
728   setRedrawFunctionClass(class, RedrawAreaLine);
729   setInEventAreaFunctionClass(class, inEventAreaLine);
730   setLoadStoreFunctionClass(class, loadLine, NULL);
731 
732   succeed;
733 }
734