libgeda
|
00001 /* gEDA - GPL Electronic Design Automation 00002 * libgeda - gEDA's library 00003 * Copyright (C) 1998-2010 Ales Hvezda 00004 * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details) 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00019 */ 00020 00025 #include <config.h> 00026 #include <stdio.h> 00027 #include <math.h> 00028 00029 #include "libgeda_priv.h" 00030 00031 #ifdef HAVE_LIBDMALLOC 00032 #include <dmalloc.h> 00033 #endif 00034 00047 int dist(int x1, int y1, int x2, int y2) 00048 { 00049 return sqrt(pow(x1-x2,2)+pow(y1-y2,2)); 00050 } 00051 00077 OBJECT *o_circle_new(TOPLEVEL *toplevel, 00078 char type, int color, 00079 int x, int y, int radius) 00080 { 00081 OBJECT *new_node; 00082 00083 /* create the object */ 00084 new_node = s_basic_new_object(type, "circle"); 00085 new_node->color = color; 00086 00087 new_node->circle = (CIRCLE *) g_malloc(sizeof(CIRCLE)); 00088 00089 /* describe the circle with its center and radius */ 00090 new_node->circle->center_x = x; 00091 new_node->circle->center_y = y; 00092 new_node->circle->radius = radius; 00093 00094 /* line type and filling initialized to default */ 00095 o_set_line_options(toplevel, new_node, 00096 END_NONE, TYPE_SOLID, 0, -1, -1); 00097 o_set_fill_options(toplevel, new_node, 00098 FILLING_HOLLOW, -1, -1, -1, -1, -1); 00099 00100 /* compute the bounding box coords */ 00101 o_circle_recalc(toplevel, new_node); 00102 00103 return new_node; 00104 } 00105 00115 OBJECT *o_circle_copy(TOPLEVEL *toplevel, OBJECT *o_current) 00116 { 00117 OBJECT *new_obj; 00118 00119 /* A new circle object is created with #o_circle_new(). 00120 * Values for its fields are default and need to be modified. */ 00121 new_obj = o_circle_new (toplevel, OBJ_CIRCLE, o_current->color, 0, 0, 0); 00122 00123 /* 00124 * The parameters of the new circle are set with the ones of the original 00125 * circle. The two circle have the same line type and the same filling 00126 * options. 00127 * 00128 * The bounding box coordinates are computed with 00129 * #o_circle_recalc(). 00130 */ 00131 /* modify */ 00132 new_obj->circle->center_x = o_current->circle->center_x; 00133 new_obj->circle->center_y = o_current->circle->center_y; 00134 new_obj->circle->radius = o_current->circle->radius; 00135 00136 o_set_line_options(toplevel, new_obj, o_current->line_end, 00137 o_current->line_type, o_current->line_width, 00138 o_current->line_length, o_current->line_space); 00139 o_set_fill_options(toplevel, new_obj, 00140 o_current->fill_type, o_current->fill_width, 00141 o_current->fill_pitch1, o_current->fill_angle1, 00142 o_current->fill_pitch2, o_current->fill_angle2); 00143 00144 o_circle_recalc(toplevel, new_obj); 00145 00146 /* new_obj->attribute = 0;*/ 00147 00148 return new_obj; 00149 } 00150 00179 void o_circle_modify(TOPLEVEL *toplevel, OBJECT *object, 00180 int x, int y, int whichone) 00181 { 00182 o_emit_pre_change_notify (toplevel, object); 00183 00184 switch(whichone) { 00185 case CIRCLE_CENTER: 00186 /* modify the center of the circle */ 00187 object->circle->center_x = x; 00188 object->circle->center_y = y; 00189 break; 00190 case CIRCLE_RADIUS: 00191 /* modify the radius of the circle */ 00192 if (x == 0) { 00193 s_log_message(_("Null radius circles are not allowed\n")); 00194 return; 00195 } 00196 object->circle->radius = x; 00197 break; 00198 default: 00199 break; 00200 } 00201 00202 /* recalculate the boundings */ 00203 o_circle_recalc(toplevel, object); 00204 o_emit_change_notify (toplevel, object); 00205 } 00206 00225 OBJECT *o_circle_read (TOPLEVEL *toplevel, const char buf[], 00226 unsigned int release_ver, unsigned int fileformat_ver, GError ** err) 00227 { 00228 OBJECT *new_obj; 00229 char type; 00230 int x1, y1; 00231 int radius; 00232 int color; 00233 int circle_width, circle_space, circle_length; 00234 int fill_width, angle1, pitch1, angle2, pitch2; 00235 int circle_end; 00236 int circle_type; 00237 int circle_fill; 00238 00239 if(release_ver <= VERSION_20000704) { 00240 /* 00241 * The old geda file format, i.e. releases 20000704 and older, does not 00242 * handle the line type and the filling of the box object. They are set 00243 * to default. 00244 */ 00245 if (sscanf(buf, "%c %d %d %d %d\n", &type, &x1, &y1, &radius, &color) != 5) { 00246 g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse circle object")); 00247 return NULL; 00248 } 00249 00250 circle_width = 0; 00251 circle_end = END_NONE; 00252 circle_type = TYPE_SOLID; 00253 circle_length= -1; 00254 circle_space = -1; 00255 00256 circle_fill = FILLING_HOLLOW; 00257 fill_width = 0; 00258 angle1 = -1; 00259 pitch1 = -1; 00260 angle2 = -1; 00261 pitch2 = -1; 00262 00263 } else { 00264 00265 /* 00266 * The current line format to describe a circle is a space separated 00267 * list of characters and numbers in plain ASCII on a single line. The 00268 * meaning of each item is described in the file format documentation. 00269 */ 00270 if (sscanf(buf, "%c %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n", 00271 &type, &x1, &y1, &radius, &color, 00272 &circle_width, &circle_end, &circle_type, 00273 &circle_length, &circle_space, &circle_fill, 00274 &fill_width, &angle1, &pitch1, &angle2, &pitch2) != 16) { 00275 g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse circle object")); 00276 return NULL; 00277 } 00278 } 00279 00280 00281 if (radius <= 0) { 00282 s_log_message(_("Found a zero or negative radius circle [ %c %d %d %d %d ]\n"), 00283 type, x1, y1, radius, color); 00284 s_log_message (_("Setting radius to 0\n")); 00285 radius = 0; 00286 } 00287 00288 if (color < 0 || color > MAX_COLORS) { 00289 s_log_message(_("Found an invalid color [ %s ]\n"), buf); 00290 s_log_message(_("Setting color to default color\n")); 00291 color = DEFAULT_COLOR; 00292 } 00293 00294 /* 00295 * A circle is internally described by its center and its radius. 00296 * 00297 * A new object is allocated, initialized and added to the object list. 00298 * Its filling and line type are set according to the values of the field 00299 * on the line. 00300 */ 00301 new_obj = o_circle_new(toplevel, type, color, x1, y1, radius); 00302 o_set_line_options(toplevel, new_obj, 00303 circle_end, circle_type, circle_width, 00304 circle_length, circle_space); 00305 o_set_fill_options(toplevel, new_obj, 00306 circle_fill, fill_width, pitch1, angle1, pitch2, angle2); 00307 00308 return new_obj; 00309 } 00310 00326 char *o_circle_save(TOPLEVEL *toplevel, OBJECT *object) 00327 { 00328 int x,y; 00329 int radius; 00330 int circle_width, circle_space, circle_length; 00331 int fill_width, angle1, pitch1, angle2, pitch2; 00332 char *buf; 00333 OBJECT_END circle_end; 00334 OBJECT_TYPE circle_type; 00335 OBJECT_FILLING circle_fill; 00336 00337 /* circle center and radius */ 00338 x = object->circle->center_x; 00339 y = object->circle->center_y; 00340 radius = object->circle->radius; 00341 00342 /* line type parameters */ 00343 circle_width = object->line_width; 00344 circle_end = object->line_end; 00345 circle_type = object->line_type; 00346 circle_length= object->line_length; 00347 circle_space = object->line_space; 00348 00349 /* filling parameters */ 00350 circle_fill = object->fill_type; 00351 fill_width = object->fill_width; 00352 angle1 = object->fill_angle1; 00353 pitch1 = object->fill_pitch1; 00354 angle2 = object->fill_angle2; 00355 pitch2 = object->fill_pitch2; 00356 00357 buf = g_strdup_printf("%c %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d", 00358 object->type, x, y, radius, object->color, 00359 circle_width, circle_end, circle_type, circle_length, 00360 circle_space, circle_fill, 00361 fill_width, angle1, pitch1, angle2, pitch2); 00362 return(buf); 00363 } 00364 00375 void o_circle_translate_world(TOPLEVEL *toplevel, 00376 int dx, int dy, OBJECT *object) 00377 { 00378 /* Do world coords */ 00379 object->circle->center_x = object->circle->center_x + dx; 00380 object->circle->center_y = object->circle->center_y + dy; 00381 00382 /* recalc the screen coords and the bounding box */ 00383 o_circle_recalc(toplevel, object); 00384 00385 } 00386 00400 void o_circle_rotate_world(TOPLEVEL *toplevel, 00401 int world_centerx, int world_centery, int angle, 00402 OBJECT *object) 00403 { 00404 int newx, newy; 00405 int x, y; 00406 00407 /* Only 90 degree multiple and positive angles are allowed. */ 00408 /* angle must be positive */ 00409 if(angle < 0) angle = -angle; 00410 /* angle must be a 90 multiple or no rotation performed */ 00411 if((angle % 90) != 0) return; 00412 00413 /* 00414 * The center of rotation (<B>world_centerx</B>,<B>world_centery</B>) is 00415 * translated to the origin. The rotation of the center around the origin 00416 * is then performed. Finally, the rotated circle is translated back to 00417 * its previous location. 00418 */ 00419 00420 /* translate object to origin */ 00421 object->circle->center_x -= world_centerx; 00422 object->circle->center_y -= world_centery; 00423 00424 /* rotate the center of the circle around the origin */ 00425 x = object->circle->center_x; 00426 y = object->circle->center_y; 00427 rotate_point_90(x, y, angle, &newx, &newy); 00428 object->circle->center_x = newx; 00429 object->circle->center_y = newy; 00430 00431 /* translate back in position */ 00432 object->circle->center_x += world_centerx; 00433 object->circle->center_y += world_centery; 00434 00435 o_circle_recalc(toplevel, object); 00436 00437 } 00438 00452 void o_circle_mirror_world(TOPLEVEL *toplevel, 00453 int world_centerx, int world_centery, 00454 OBJECT *object) 00455 { 00456 /* translate object to origin */ 00457 object->circle->center_x -= world_centerx; 00458 object->circle->center_y -= world_centery; 00459 00460 /* mirror the center of the circle */ 00461 object->circle->center_x = -object->circle->center_x; 00462 object->circle->center_y = object->circle->center_y; 00463 00464 /* translate back in position */ 00465 object->circle->center_x += world_centerx; 00466 object->circle->center_y += world_centery; 00467 00468 /* recalc boundings and screen coords */ 00469 o_circle_recalc(toplevel, object); 00470 00471 } 00472 00484 void o_circle_recalc(TOPLEVEL *toplevel, OBJECT *o_current) 00485 { 00486 int left, right, top, bottom; 00487 00488 if (o_current->circle == NULL) { 00489 return; 00490 } 00491 00492 /* update the bounding box - world unit */ 00493 world_get_circle_bounds(toplevel, o_current, 00494 &left, &top, &right, &bottom); 00495 o_current->w_left = left; 00496 o_current->w_top = top; 00497 o_current->w_right = right; 00498 o_current->w_bottom = bottom; 00499 o_current->w_bounds_valid = TRUE; 00500 } 00501 00515 void world_get_circle_bounds(TOPLEVEL *toplevel, OBJECT *object, int *left, 00516 int *top, int *right, int *bottom) 00517 { 00518 int halfwidth; 00519 00520 halfwidth = object->line_width / 2; 00521 00522 *left = object->circle->center_x - object->circle->radius; 00523 *top = object->circle->center_y - object->circle->radius; 00524 *right = object->circle->center_x + object->circle->radius; 00525 *bottom = object->circle->center_y + object->circle->radius; 00526 00527 /* This isn't strictly correct, but a 1st order approximation */ 00528 *left -= halfwidth; 00529 *top -= halfwidth; 00530 *right += halfwidth; 00531 *bottom += halfwidth; 00532 00533 } 00534 00545 gboolean o_circle_get_position (TOPLEVEL *toplevel, gint *x, gint *y, 00546 OBJECT *object) 00547 { 00548 *x = object->circle->center_x; 00549 *y = object->circle->center_y; 00550 return TRUE; 00551 } 00552 00576 void o_circle_print(TOPLEVEL *toplevel, FILE *fp, OBJECT *o_current, 00577 int origin_x, int origin_y) 00578 { 00579 int x, y, radius; 00580 int color; 00581 int circle_width, length, space; 00582 int fill_width, angle1, pitch1, angle2, pitch2; 00583 void (*outl_func)() = NULL; 00584 void (*fill_func)() = NULL; 00585 00586 if (o_current == NULL) { 00587 printf("got null in o_circle_print\n"); 00588 return; 00589 } 00590 00591 x = o_current->circle->center_x; 00592 y = o_current->circle->center_y; 00593 radius = o_current->circle->radius; 00594 00595 color = o_current->color; 00596 00597 /* 00598 * Depending on the type of the line for this particular circle, the 00599 * appropriate function is chosen among #o_circle_print_solid(), 00600 * #o_circle_print_dotted(), #o_circle_print_dashed(), 00601 * #o_circle_print_center() and #o_circle_print_phantom(). 00602 * 00603 * The needed parameters for each of these type is extracted from the 00604 * <B>o_current</B> object. Depending on the type, unused parameters are 00605 * set to -1. 00606 * 00607 * In the eventuality of a length and/or space null, the line is 00608 * printed solid to avoid and endless loop produced by other functions 00609 * in such a case. 00610 */ 00611 circle_width = o_current->line_width; 00612 if(circle_width <=2) { 00613 if(toplevel->line_style == THICK) { 00614 circle_width=LINE_WIDTH; 00615 } else { 00616 circle_width=2; 00617 } 00618 } 00619 length = o_current->line_length; 00620 space = o_current->line_space; 00621 00622 switch(o_current->line_type) { 00623 case(TYPE_SOLID): 00624 length = -1; space = -1; 00625 outl_func = o_circle_print_solid; 00626 break; 00627 00628 case(TYPE_DOTTED): 00629 length = -1; 00630 outl_func = o_circle_print_dotted; 00631 break; 00632 00633 case(TYPE_DASHED): 00634 outl_func = o_circle_print_dashed; 00635 break; 00636 00637 case(TYPE_CENTER): 00638 outl_func = o_circle_print_center; 00639 break; 00640 00641 case(TYPE_PHANTOM): 00642 outl_func = o_circle_print_phantom; 00643 break; 00644 00645 case(TYPE_ERASE): 00646 /* Unused for now print it solid */ 00647 length = -1; space = -1; 00648 outl_func = o_circle_print_solid; 00649 break; 00650 } 00651 00652 if((length == 0) || (space == 0)) { 00653 length = -1; space = -1; 00654 outl_func = o_circle_print_solid; 00655 } 00656 00657 (*outl_func)(toplevel, fp, 00658 x - origin_x, y - origin_y, 00659 radius, 00660 color, 00661 circle_width, length, space, 00662 origin_x, origin_y); 00663 00664 /* 00665 * If the filling type of the circle is not <B>HOLLOW</B>, the appropriate 00666 * function is chosen among #o_circle_print_filled(), #o_circle_print_mesh() 00667 * and #o_circle_print_hatch(). The corresponding parameters are extracted 00668 * from the <B>o_current</B> object and corrected afterward. 00669 * 00670 * The case where <B>pitch1</B> and <B>pitch2</B> are null or negative is 00671 * avoided as it leads to an endless loop in most of the called functions. 00672 * In such a case, the circle is printed filled. Unused parameters for 00673 * each of these functions are set to -1 or any passive value. 00674 */ 00675 if(o_current->fill_type != FILLING_HOLLOW) { 00676 fill_width = o_current->fill_width; 00677 angle1 = o_current->fill_angle1; 00678 pitch1 = o_current->fill_pitch1; 00679 angle2 = o_current->fill_angle2; 00680 pitch2 = o_current->fill_pitch2; 00681 00682 switch(o_current->fill_type) { 00683 case(FILLING_FILL): 00684 angle1 = -1; pitch1 = 1; 00685 angle2 = -1; pitch2 = 1; 00686 fill_width = -1; 00687 fill_func = o_circle_print_filled; 00688 break; 00689 00690 case(FILLING_MESH): 00691 fill_func = o_circle_print_mesh; 00692 break; 00693 00694 case(FILLING_HATCH): 00695 angle2 = -1; pitch2 = 1; 00696 fill_func = o_circle_print_hatch; 00697 break; 00698 00699 case(FILLING_VOID): 00700 /* Unused for now, print it filled */ 00701 angle1 = -1; pitch1 = 1; 00702 angle2 = -1; pitch2 = 1; 00703 fill_width = -1; 00704 fill_func = o_circle_print_filled; 00705 break; 00706 00707 case(FILLING_HOLLOW): 00708 /* nop */ 00709 break; 00710 } 00711 00712 if((pitch1 <= 0) || (pitch2 <= 0)) { 00713 angle1 = -1; pitch1 = 1; 00714 angle2 = -1; pitch2 = 1; 00715 fill_func = o_circle_print_filled; 00716 } 00717 00718 (*fill_func)(toplevel, fp, 00719 x, y, radius, 00720 color, 00721 fill_width, 00722 angle1, pitch1, angle2, pitch2, 00723 origin_x, origin_y); 00724 } 00725 } 00726 00753 void o_circle_print_solid(TOPLEVEL *toplevel, FILE *fp, 00754 int x, int y, int radius, 00755 int color, 00756 int circle_width, int length, int space, 00757 int origin_x, int origin_y) 00758 { 00759 00760 o_arc_print_solid(toplevel, fp, 00761 x, y, radius, 00762 0, FULL_CIRCLE / 64, 00763 color, 00764 circle_width, -1, -1, 00765 origin_x, origin_y); 00766 00767 } 00768 00769 00796 void o_circle_print_dotted(TOPLEVEL *toplevel, FILE *fp, 00797 int x, int y, int radius, 00798 int color, 00799 int circle_width, int length, int space, 00800 int origin_x, int origin_y) 00801 { 00802 00803 o_arc_print_dotted(toplevel, fp, 00804 x, y, radius, 00805 0, FULL_CIRCLE / 64, 00806 color, 00807 circle_width, -1, space, 00808 origin_x, origin_y); 00809 00810 } 00811 00837 void o_circle_print_dashed(TOPLEVEL *toplevel, FILE *fp, 00838 int x, int y, 00839 int radius, 00840 int color, 00841 int circle_width, int length, int space, 00842 int origin_x, int origin_y) 00843 { 00844 00845 o_arc_print_dashed(toplevel, fp, 00846 x, y, radius, 00847 0, FULL_CIRCLE / 64, 00848 color, 00849 circle_width, length, space, 00850 origin_x, origin_y); 00851 00852 } 00853 00879 void o_circle_print_center(TOPLEVEL *toplevel, FILE *fp, 00880 int x, int y, 00881 int radius, 00882 int color, 00883 int circle_width, int length, int space, 00884 int origin_x, int origin_y) 00885 { 00886 00887 o_arc_print_center(toplevel, fp, 00888 x, y, radius, 00889 0, FULL_CIRCLE / 64, 00890 color, 00891 circle_width, length, space, 00892 origin_x, origin_y); 00893 00894 } 00895 00921 void o_circle_print_phantom(TOPLEVEL *toplevel, FILE *fp, 00922 int x, int y, 00923 int radius, 00924 int color, 00925 int circle_width, int length, int space, 00926 int origin_x, int origin_y) 00927 { 00928 00929 o_arc_print_phantom(toplevel, fp, 00930 x, y, radius, 00931 0, FULL_CIRCLE / 64, 00932 color, 00933 circle_width, length, space, 00934 origin_x, origin_y); 00935 00936 } 00937 00965 void o_circle_print_filled(TOPLEVEL *toplevel, FILE *fp, 00966 int x, int y, int radius, 00967 int color, 00968 int fill_width, 00969 int angle1, int pitch1, 00970 int angle2, int pitch2, 00971 int origin_x, int origin_y) 00972 { 00973 f_print_set_color(toplevel, fp, color); 00974 00975 fprintf(fp, "%d %d %d dot\n", 00976 x-origin_x, y-origin_y, 00977 radius); 00978 00979 } 00980 01011 void o_circle_print_mesh(TOPLEVEL *toplevel, FILE *fp, 01012 int x, int y, int radius, 01013 int color, 01014 int fill_width, 01015 int angle1, int pitch1, 01016 int angle2, int pitch2, 01017 int origin_x, int origin_y) 01018 { 01019 o_circle_print_hatch(toplevel, fp, 01020 x, y, radius, 01021 color, 01022 fill_width, 01023 angle1, pitch1, 01024 -1, -1, 01025 origin_x, origin_y); 01026 o_circle_print_hatch(toplevel, fp, 01027 x, y, radius, 01028 color, 01029 fill_width, 01030 angle2, pitch2, 01031 -1, -1, 01032 origin_x, origin_y); 01033 01034 } 01035 01066 void o_circle_print_hatch(TOPLEVEL *toplevel, FILE *fp, 01067 int x, int y, int radius, 01068 int color, 01069 int fill_width, 01070 int angle1, int pitch1, 01071 int angle2, int pitch2, 01072 int origin_x, int origin_y) 01073 { 01074 CIRCLE circle; 01075 gint index; 01076 GArray *lines; 01077 01078 g_return_if_fail(toplevel != NULL); 01079 g_return_if_fail(fp != NULL); 01080 01081 f_print_set_color(toplevel, fp, color); 01082 01083 /* Avoid printing line widths too small */ 01084 if (fill_width <= 1) fill_width = 2; 01085 01086 lines = g_array_new(FALSE, FALSE, sizeof(LINE)); 01087 01088 circle.center_x = x; 01089 circle.center_y = y; 01090 circle.radius = radius; 01091 01092 m_hatch_circle(&circle, angle1, pitch1, lines); 01093 01094 for(index=0; index<lines->len; index++) { 01095 LINE *line = &g_array_index(lines, LINE, index); 01096 01097 fprintf(fp,"%d %d %d %d %d line\n", 01098 line->x[0], line->y[0], 01099 line->x[1], line->y[1], 01100 fill_width); 01101 } 01102 01103 g_array_free(lines, TRUE); 01104 } 01105 01116 double o_circle_shortest_distance (OBJECT *object, int x, int y, 01117 int force_solid) 01118 { 01119 int solid; 01120 01121 g_return_val_if_fail (object->circle != NULL, G_MAXDOUBLE); 01122 01123 solid = force_solid || object->fill_type != FILLING_HOLLOW; 01124 01125 return m_circle_shortest_distance (object->circle, x, y, solid); 01126 } 01127