Annotation of OpenXM_contrib/gnuplot/term/grass.trm, Revision 1.1.1.1
1.1 maekawa 1: /*[
2: * GNUPLOT - grass.trm
3: * $Id: grass.trm,v
4: *-
5: * Copyright (C) 1992-1995, 1999. James Darrell McCauley
6: *
7: * Permission to use, copy, and distribute this software and its
8: * documentation for any purpose with or without fee is hereby granted,
9: * provided that the above copyright notice appear in all copies and
10: * that both that copyright notice and this permission notice appear
11: * in supporting documentation.
12: *
13: * Permission to modify the software is granted, but not the right to
14: * distribute the complete modified source code. Modifications are to
15: * be distributed as patches to the released version. Permission to
16: * distribute binaries produced by compiling modified sources is granted,
17: * provided you
18: * 1. distribute the corresponding source modifications from the
19: * released version in the form of a patch file along with the binaries,
20: * 2. add special version identification to distinguish your version
21: * in addition to the base release version number,
22: * 3. provide your name and address as the primary contact for the
23: * support of your modified version, and
24: * 4. retain our contact information in regard to use of the base
25: * software.
26: * Permission to distribute the released version of the source code along
27: * with corresponding source modifications in the form of a patch file is
28: * granted with same provisions 2 through 4 for binary distributions.
29: *
30: * This software is provided "as is" without express or implied warranty
31: * to the extent permitted by applicable law.
32: *
33: * This software is provided "as is" without express or implied warranty.
34: *
35: * This file is included by ../term.c.
36: *
37: * This terminal driver supports:
38: * GRASS graphics driver
39: *
40: * AUTHOR
41: * James Darrell McCauley, PhD http://soils.ecn.purdue.edu/~mccauley/
42: * Dept of Agricultural Engineering mccauley@ecn.purdue.edu
43: * Purdue University tel: 317.494.1198 fax: 317.496.1115
44: *
45: * 05 Apr 1995 - cleaned up code by adding explicit function declarations.
46: * compiles clean with 'gcc -Wall'
47: * 14 Apr 1995 - adapted for new layout, added font selection
48: *
49: * 13 Jan 1999 - Copyright statement changed to new gnuplot copyright
50: * Permission given by orig author in private email (lh)
51: *
52: * send your comments or suggestions to (grassp-list@moon.cecer.army.mil).
53: *
54: ]*/
55:
56: #include "driver.h"
57:
58: #ifdef TERM_REGISTER
59: register_term(grass)
60: #endif
61:
62:
63: #ifdef TERM_PROTO
64: TERM_PUBLIC void GRASS_move __PROTO((unsigned int x, unsigned int y));
65: TERM_PUBLIC void GRASS_options __PROTO((void));
66: TERM_PUBLIC void GRASS_init __PROTO((void));
67: TERM_PUBLIC void GRASS_reset __PROTO((void));
68: TERM_PUBLIC void GRASS_graphics __PROTO((void));
69: TERM_PUBLIC void GRASS_text __PROTO((void));
70: TERM_PUBLIC void GRASS_vector __PROTO((unsigned int x, unsigned int y));
71: TERM_PUBLIC void GRASS_linetype __PROTO((int lt));
72: TERM_PUBLIC void GRASS_put_text __PROTO((unsigned int x, unsigned int y, char *str));
73: TERM_PUBLIC int GRASS_text_angle __PROTO((int ang));
74: TERM_PUBLIC int GRASS_justify_text __PROTO((enum JUSTIFY mode));
75: TERM_PUBLIC void GRASS_point __PROTO((unsigned int x, unsigned int y, int point));
76: TERM_PUBLIC int GRASS_set_font __PROTO((char *font));
77: /* TERM_PUBLIC void GRASS_set_pointsize __PROTO((double size)); */
78: TERM_PUBLIC void GRASS_arrow __PROTO((unsigned int sx, unsigned int sy, unsigned int ex, unsigned int ey, int head));
79: #endif /* TERM_PROTO */
80:
81: #ifndef TERM_PROTO_ONLY
82: #ifdef TERM_BODY
83:
84: #include <stdio.h>
85: #include <string.h>
86: /* #include "gis.h" */ /* this causes conflicts with things in term.c */
87:
88: #define GRASS_XMAX 1000
89: #define GRASS_YMAX 1000
90: #define GRASS_VCHAR 5
91: #define GRASS_HCHAR 5
92: #define GRASS_VTIC 3
93: #define GRASS_HTIC 3
94:
95: #define PNT_SIZE 3
96: #define TYPE_DOT -1
97: #define TYPE_X 0
98: #define TYPE_PLUS 1
99: #define TYPE_BOX 2
100: #define TYPE_DIAMOND 3 /* need type 4 and 5 */
101: #define TYPE_TRIANGLE 4
102: #define TYPE_OCTO 5
103: #define TYPE_ITRIANGLE 6
104: #define TYPE_FBOX 7
105: #define TYPE_FTRIANGLE 8
106: #define TYPE_FITRIANGLE 9
107: #define TYPE_FOCTO 10
108:
109: static void cont_abs __PROTO((int x, int y));
110: static void draw_points_dot __PROTO((int x, int y));
111: static void draw_points_diamond __PROTO((int x, int y));
112: static void draw_points_box __PROTO((int x, int y));
113: static void draw_points_fbox __PROTO((int x, int y));
114: static void draw_points_itriangle __PROTO((int x, int y));
115: static void draw_points_fitriangle __PROTO((int x, int y));
116: static void draw_points_triangle __PROTO((int x, int y));
117: static void draw_points_ftriangle __PROTO((int x, int y));
118: static void draw_points_plus __PROTO((int x, int y));
119: static void draw_points_octo __PROTO((int x, int y));
120: static void draw_points_focto __PROTO((int x, int y));
121: static void draw_points_x __PROTO((int x, int y));
122:
123: static int R__curx, R__cury;
124:
125: static int grass_yoffset;
126: static int grass_xoffset;
127: static int y_max;
128: static int points_buf_x[PNT_SIZE*PNT_SIZE]; /* for filled point types */
129: static int points_buf_y[PNT_SIZE*PNT_SIZE];
130:
131: TERM_PUBLIC void GRASS_move (x, y)
132: unsigned int x, y;
133: {
134: int R_move_abs ();
135: /* R_move_abs (grass_xoffset+x, grass_yoffset-y + y_max); */
136: R_move_abs (grass_xoffset+x, grass_yoffset-y);
137: }
138:
139: static void cont_abs (x, y)
140: int x, y;
141: {
142: int R_cont_abs ();
143: /* R_cont_abs (grass_xoffset+x, grass_xoffset-y + y_max); */
144: R_cont_abs (grass_xoffset+x, grass_yoffset-y);
145: }
146:
147: TERM_PUBLIC void GRASS_options ()
148: {
149: options_null (); /* no options to begin with */
150: }
151:
152: TERM_PUBLIC void GRASS_init ()
153: {
154: /* char buff[128]; */
155: char window_name[64];
156: float size = 3.0;
157: /* int backcolor; */
158: int dots_per_line;
159: int top, b, l, r;
160: /* int textcolor; */
161: struct termentry *t = term;
162: int G_gisinit();
163: int R_open_driver();
164: int D_setup();
165: int D_get_cur_wind();
166: int G_fatal_error();
167: int D_set_cur_wind();
168: int D_get_screen_window();
169: int R_set_window();
170: int R_text_size();
171: int R_font();
172: int R_screen_top();
173: int R_screen_bot();
174: int D_erase_window();
175:
176: G_gisinit ("g.gnuplot");
177:
178: R_open_driver ();
179:
180: D_setup (0);
181:
182: if (D_get_cur_wind (window_name))
183: G_fatal_error ("No current window");
184:
185: if (D_set_cur_wind (window_name))
186: G_fatal_error ("Current window not available");
187:
188: /* Set up the screen, conversions, and graphics */
189: D_get_screen_window (&top, &b, &l, &r);
190: /* D_set_overlay_mode (1); */
191:
192: /* Figure out where to put text */
193:
194: R_set_window (top, b, l, r);
195: t->xmax = r-l;
196: t->ymax = b-top;
197: grass_xoffset=l;
198: grass_yoffset=b;
199:
200: dots_per_line = (int) (size / 100.0 * (float) (t->ymax));
201: t->v_char = t->h_char = (int) (.8 * (float) dots_per_line);
202: R_text_size (t->h_char, t->v_char);
203: R_font("romans");
204:
205: t->v_tic = t->h_tic = 4;
206:
207: y_max = t->ymax; /* kludge? */
208:
209: R__curx = R_screen_top ();
210: R__cury = R_screen_bot () + grass_yoffset;
211:
212: D_erase_window();
213: /*
214: fprintf(stderr,"**********************************************\n");
215: fprintf(stderr,"DIAGNOSTIC TERMINAL SETUP\n");
216: fprintf(stderr,"top = %d\tb = %d\tl = %d\tr = %d\n", top,b,l,r);
217: fprintf(stderr,"name = %s\n", t->name);
218: fprintf(stderr,"description = %s\n", t->description);
219: fprintf(stderr,"xmax = %d\t", (int)t->xmax);
220: fprintf(stderr,"ymax = %d\n", (int)t->ymax);
221: fprintf(stderr,"v_char = %d\t", (int)t->v_char);
222: fprintf(stderr,"h_char = %d\n", (int)t->h_char);
223: fprintf(stderr,"v_tic = %d\t", (int)t->v_tic);
224: fprintf(stderr,"h_tic = %d\n", (int)t->h_tic);
225: fprintf(stderr,"**********************************************\n\n");
226: */
227: }
228:
229: TERM_PUBLIC void GRASS_reset ()
230: {
231: int R_standard_color();
232: int D_translate_color();
233: int R_flush();
234: int R_stabilize();
235: int R_close_driver();
236:
237: R_standard_color (D_translate_color ("black"));
238: /* D_erase_window(); .* don't clear after g.gnuplot is finished */
239: R_flush ();
240: R_stabilize ();
241: R_close_driver ();
242: }
243:
244: TERM_PUBLIC void GRASS_graphics ()
245: {
246: int D_erase_window();
247: int R_flush();
248: int R_stabilize();
249: int R_standard_color();
250: int D_translate_color();
251:
252: R_flush ();
253: R_stabilize ();
254: R_standard_color (D_translate_color ("black"));
255: D_erase_window();
256: return;
257: }
258:
259: TERM_PUBLIC void GRASS_text ()
260: {
261: int R_flush ();
262: int R_stabilize ();
263:
264: R_flush ();
265: R_stabilize ();
266: return; /* device can't be used as a terminal */
267: }
268:
269: TERM_PUBLIC void GRASS_vector (x, y)
270: unsigned int x, y;
271: {
272: int R_flush ();
273: int R_stabilize ();
274:
275: cont_abs (x, y);
276: R_flush ();
277: R_stabilize ();
278: }
279:
280: TERM_PUBLIC void GRASS_linetype (lt)
281: int lt;
282: {
283: int R_standard_color();
284: int D_translate_color();
285: int R_flush ();
286: int R_stabilize ();
287:
288: while (lt > 10) lt-=10;
289:
290: if (lt <= -2)
291: R_standard_color (D_translate_color ("gray"));
292: else if (lt == -1)
293: R_standard_color (D_translate_color ("white"));
294: else if (lt == 0)
295: R_standard_color (D_translate_color ("red"));
296: else if (lt == 1)
297: R_standard_color (D_translate_color ("green"));
298: else if (lt == 2)
299: R_standard_color (D_translate_color ("magenta"));
300: else if (lt == 3)
301: R_standard_color (D_translate_color ("brown"));
302: else if (lt == 4)
303: R_standard_color (D_translate_color ("orange"));
304: else if (lt == 5)
305: R_standard_color (D_translate_color ("yellow"));
306: else if (lt == 6)
307: R_standard_color (D_translate_color ("blue"));
308: else if (lt == 7)
309: R_standard_color (D_translate_color ("violet"));
310: else if (lt == 8)
311: R_standard_color (D_translate_color ("indigo"));
312: else if (lt == 9)
313: R_standard_color (D_translate_color ("gray"));
314: else /* if (lt == 10) */
315: R_standard_color (D_translate_color ("white"));
316: R_flush ();
317: R_stabilize ();
318: return;
319: }
320:
321: /* originally /usr/grass4/src/display/d.label/cmd/label.c */
322:
323: TERM_PUBLIC void GRASS_put_text (x, y, str)
324: unsigned int x, y;
325: char *str;
326: {
327: int R_text();
328: int R_flush ();
329: int R_stabilize ();
330: if (strlen (str) == 0)
331: return;
332:
333: GRASS_move (x, y);
334: /* R_standard_color (D_translate_color ("white")); */
335: R_text (str);
336: R_flush ();
337: R_stabilize ();
338: }
339:
340: TERM_PUBLIC int GRASS_text_angle (ang)
341: int ang;
342: {
343: int R_text_rotation();
344:
345: R_text_rotation((float)ang);
346: return TRUE; /* GRASS can (?) rotate text */
347: }
348:
349: TERM_PUBLIC int GRASS_justify_text (mode)
350: enum JUSTIFY mode;
351: {
352: return (FALSE); /* don't mess with this now */
353: }
354:
355:
356: TERM_PUBLIC void GRASS_point (x, y, point)
357: unsigned int x,y;
358: int point;
359: {
360: switch (point)
361: {
362: case TYPE_DOT:
363: draw_points_dot (x, y);
364: break;
365: case TYPE_X:
366: draw_points_x (x, y);
367: break;
368: case TYPE_PLUS:
369: draw_points_plus (x, y);
370: break;
371: case TYPE_BOX:
372: draw_points_box (x, y);
373: break;
374: case TYPE_DIAMOND:
375: draw_points_diamond (x, y);
376: break;
377: case TYPE_TRIANGLE:
378: draw_points_triangle (x, y);
379: break;
380: case TYPE_OCTO:
381: draw_points_octo (x, y);
382: break;
383: case TYPE_ITRIANGLE:
384: draw_points_itriangle (x, y);
385: break;
386: case TYPE_FBOX:
387: draw_points_fbox (x, y);
388: break;
389: case TYPE_FTRIANGLE:
390: draw_points_ftriangle (x, y);
391: break;
392: case TYPE_FITRIANGLE:
393: draw_points_fitriangle (x, y);
394: break;
395: case TYPE_FOCTO:
396: draw_points_focto (x, y);
397: break;
398: }
399: }
400:
401: /* modified from /usr/grass4/src/display/d.points/cmd/main.c */
402:
403: static void draw_points_dot (x, y)
404: int x, y;
405: {
406: GRASS_move (x, y);
407: cont_abs (x, y);
408: }
409:
410: static void draw_points_diamond (x, y)
411: int x, y;
412: {
413: GRASS_move (x, y + PNT_SIZE);
414: GRASS_vector (x + PNT_SIZE, y);
415: GRASS_vector (x, y - PNT_SIZE);
416: GRASS_vector (x - PNT_SIZE, y);
417: GRASS_vector (x, y + PNT_SIZE);
418: }
419:
420: static void draw_points_box (x, y)
421: int x, y;
422: {
423: GRASS_move (x - PNT_SIZE, y - PNT_SIZE);
424: GRASS_vector (x - PNT_SIZE, y + PNT_SIZE);
425: GRASS_vector (x + PNT_SIZE, y + PNT_SIZE);
426: GRASS_vector (x + PNT_SIZE, y - PNT_SIZE);
427: GRASS_vector (x - PNT_SIZE, y - PNT_SIZE);
428: }
429:
430: static void draw_points_fbox (x, y)
431: int x, y;
432: {
433: int R_polygon_abs();
434: points_buf_x[0] = grass_xoffset + x - PNT_SIZE;
435: points_buf_y[0]= grass_yoffset - (y + PNT_SIZE);
436: points_buf_x[1] = grass_xoffset + x + PNT_SIZE;
437: points_buf_y[1]= grass_yoffset - (y + PNT_SIZE);
438: points_buf_x[2] = grass_xoffset + x + PNT_SIZE;
439: points_buf_y[2]= grass_yoffset - (y - PNT_SIZE);
440: points_buf_x[3] = grass_xoffset + x - PNT_SIZE;
441: points_buf_y[3]= grass_yoffset - (y - PNT_SIZE);
442: R_polygon_abs(points_buf_x, points_buf_y, 4 );
443: }
444:
445: static void draw_points_itriangle (x, y)
446: int x, y;
447: {
448: GRASS_move (x - PNT_SIZE, y + PNT_SIZE);
449: GRASS_vector (x + PNT_SIZE, y + PNT_SIZE);
450: GRASS_vector (x , y - PNT_SIZE);
451: GRASS_vector (x - PNT_SIZE, y + PNT_SIZE);
452: }
453:
454: static void draw_points_fitriangle (x, y)
455: int x, y;
456: {
457: int R_polygon_abs();
458:
459: points_buf_x[0] = grass_xoffset + x + PNT_SIZE;
460: points_buf_y[0] = grass_yoffset - (y + PNT_SIZE);
461: points_buf_x[1] = grass_xoffset + x ;
462: points_buf_y[1] = grass_yoffset - (y - PNT_SIZE);
463: points_buf_x[2] = grass_xoffset + x - PNT_SIZE;
464: points_buf_y[2] = grass_yoffset - (y + PNT_SIZE);
465: R_polygon_abs(points_buf_x, points_buf_y, 3 );
466: }
467:
468: static void draw_points_triangle (x, y)
469: int x, y;
470: {
471: GRASS_move (x - PNT_SIZE, y - PNT_SIZE);
472: GRASS_vector (x , y + PNT_SIZE);
473: GRASS_vector (x + PNT_SIZE, y - PNT_SIZE);
474: GRASS_vector (x - PNT_SIZE, y - PNT_SIZE);
475: }
476:
477: static void draw_points_ftriangle (x, y)
478: int x, y;
479: {
480: int R_polygon_abs();
481:
482: points_buf_x[0] = grass_xoffset + x;
483: points_buf_y[0]= grass_yoffset - (y + PNT_SIZE);
484: points_buf_x[1] = grass_xoffset + x + PNT_SIZE;
485: points_buf_y[1]= grass_yoffset - (y - PNT_SIZE);
486: points_buf_x[2] = grass_xoffset + x - PNT_SIZE;
487: points_buf_y[2]= grass_yoffset - (y - PNT_SIZE);
488: R_polygon_abs(points_buf_x, points_buf_y, 3 );
489: }
490:
491: static void draw_points_plus (x, y)
492: int x, y;
493: {
494: GRASS_move (x - PNT_SIZE, y);
495: GRASS_vector (x + PNT_SIZE, y);
496: GRASS_move (x, y - PNT_SIZE);
497: GRASS_vector (x, y + PNT_SIZE);
498: }
499:
500: /* depends on PNT_SIZE */
501: static void draw_points_octo (x, y)
502: int x, y;
503: {
504: /* CCW */
505: GRASS_move (x - (int) (PNT_SIZE/3), y - PNT_SIZE); /* 1 */
506: GRASS_vector (x + (int) (PNT_SIZE/3), y - PNT_SIZE); /* 2 */
507: GRASS_vector (x + PNT_SIZE, y - (int) (PNT_SIZE/3)); /* 3 */
508: GRASS_vector (x + PNT_SIZE, y + (int) (PNT_SIZE/3)); /* 4 */
509: GRASS_vector (x + (int) (PNT_SIZE/3), y + PNT_SIZE); /* 5 */
510: GRASS_vector (x - (int) (PNT_SIZE/3), y + PNT_SIZE); /* 6 */
511: GRASS_vector (x - PNT_SIZE, y + (int) (PNT_SIZE/3)); /* 7 */
512: GRASS_vector (x - PNT_SIZE, y - (int) (PNT_SIZE/3)); /* 8 */
513: GRASS_vector (x - (int) (PNT_SIZE/3), y - PNT_SIZE); /* 1 */
514: }
515:
516: /* depends on PNT_SIZE */
517: static void draw_points_focto (x, y)
518: int x, y;
519: {
520: int R_polygon_abs();
521:
522: /* CCW */
523: points_buf_x[0] = grass_xoffset + x + (int) (PNT_SIZE/3);
524: points_buf_y[0] = grass_yoffset - (y - PNT_SIZE);
525: points_buf_x[1] = grass_xoffset + x + PNT_SIZE;
526: points_buf_y[1] = grass_yoffset - (y - (int) (PNT_SIZE/3));
527: points_buf_x[2] = grass_xoffset + x + PNT_SIZE;
528: points_buf_y[2] = grass_yoffset - (y + (int) (PNT_SIZE/3));
529: points_buf_x[3] = grass_xoffset + x + (int) (PNT_SIZE/3);
530: points_buf_y[3] = grass_yoffset - (y + PNT_SIZE);
531: points_buf_x[4] = grass_xoffset + x - (int) (PNT_SIZE/3);
532: points_buf_y[4] = grass_yoffset - (y + PNT_SIZE);
533: points_buf_x[5] = grass_xoffset + x - PNT_SIZE;
534: points_buf_y[5] = grass_yoffset - (y + (int) (PNT_SIZE/3));
535: points_buf_x[6] = grass_xoffset + x - PNT_SIZE;
536: points_buf_y[6] = grass_yoffset - (y - (int) (PNT_SIZE/3));
537: points_buf_x[7] = grass_xoffset + x - (int) (PNT_SIZE/3);
538: points_buf_y[7] = grass_yoffset - (y - PNT_SIZE);
539: R_polygon_abs(points_buf_x, points_buf_y, 8 );
540: }
541:
542: static void draw_points_x (x, y)
543: int x,y;
544: {
545: GRASS_move (x - PNT_SIZE, y - PNT_SIZE);
546: GRASS_vector (x + PNT_SIZE, y + PNT_SIZE);
547: GRASS_move (x + PNT_SIZE, y - PNT_SIZE);
548: GRASS_vector (x - PNT_SIZE, y + PNT_SIZE);
549: }
550:
551: TERM_PUBLIC int GRASS_set_font (font)
552: char *font;
553: {
554: char name[32];
555: int size,sep, R_font();
556: struct termentry *t = term;
557: int R_text_size (), dots_per_line;
558:
559: /* G_warning(font); */
560:
561: sep=strcspn(font,",");
562: strncpy(name,font,sep); name[sep]=NUL;
563: sscanf (&(font[sep+1]),"%d",&size);
564:
565: if (size==0)
566: size=3;
567: dots_per_line = (int) (size / 100.0 * (float) (t->ymax));
568: t->v_char = t->h_char = (int) (.8 * (float) dots_per_line);
569: R_text_size (t->h_char, t->v_char);
570: /* cyrilc,gothgbt,gothgrt,gothitt,greekc,greekcs,greekp,
571: greeks,italicc,italiccs,italict,romanc,romancs,romand,
572: romans,romant,scriptc,scripts */
573:
574: if (strlen(name) > 5 )
575: R_font(name);
576: else
577: R_font("romans");
578: return TRUE;
579: }
580:
581: #ifdef GRASS_POINTSIZE
582: TERM_PUBLIC void GRASS_set_pointsize (size));
583: double *size;
584: {
585: return;
586: }
587: #endif /* GRASS_POINTSIZE */
588:
589: /* need to fix */
590: TERM_PUBLIC void GRASS_arrow (sx, sy, ex, ey, head)
591: unsigned int sx, sy, ex, ey;
592: int head;
593: {
594: do_arrow (sx, sy, ex, ey, 1);
595: return;
596: }
597:
598: #endif /* TERM_BODY */
599:
600: #ifdef TERM_TABLE
601: TERM_TABLE_START(grass_driver)
602: "grass", "GRASS Graphics Monitor",
603: GRASS_XMAX, GRASS_YMAX, GRASS_VCHAR, GRASS_HCHAR,
604: GRASS_VTIC, GRASS_HTIC, GRASS_options, GRASS_init, GRASS_reset,
605: GRASS_text, null_scale, GRASS_graphics, GRASS_move, GRASS_vector,
606: GRASS_linetype, GRASS_put_text, GRASS_text_angle,
607: GRASS_justify_text, GRASS_point, GRASS_arrow, GRASS_set_font
608: TERM_TABLE_END(grass_driver)
609:
610:
611: #undef LAST_TERM
612: #define LAST_TERM grass_driver
613: #endif /* TERM_TABLE */
614: #endif /* TERM_PROTO_ONLY */
615:
616:
617: #ifdef TERM_HELP
618: START_HELP(grass)
619: "1 grass",
620: "?commands set terminal grass",
621: "?set terminal grass",
622: "?set term grass",
623: "?terminal grass",
624: "?term grass",
625: "?grass",
626: " The `grass` terminal driver gives `gnuplot` capabilities to users of the ",
627: " GRASS geographic information system. Contact grassp-list@moon.cecer.army.mil",
628: " for more information. Pages are written to the current frame of the GRASS",
629: " Graphics Window. There are no options."
630: END_HELP(grass)
631: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>