gschem
|
00001 /* gEDA - GPL Electronic Design Automation 00002 * gschem - gEDA Schematic Capture 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 #include <config.h> 00021 00022 #include <stdio.h> 00023 #include <math.h> 00024 00025 #include <gschem.h> 00026 00027 #ifdef HAVE_LIBDMALLOC 00028 #include <dmalloc.h> 00029 #endif 00030 00031 00040 int mil_x (GSCHEM_TOPLEVEL *w_current, int val) 00041 { 00042 double i; 00043 double fval; 00044 int j; 00045 00046 fval = val; 00047 i = fval * w_current->toplevel->page_current->to_world_x_constant + 00048 w_current->toplevel->page_current->left; 00049 00050 #ifdef HAS_RINT 00051 j = rint(i); 00052 #else 00053 j = i; 00054 #endif 00055 00056 return(j); 00057 } 00058 00067 int mil_y(GSCHEM_TOPLEVEL *w_current, int val) 00068 { 00069 double i; 00070 double fval; 00071 int j; 00072 00073 fval = w_current->toplevel->height - val; 00074 i = fval * w_current->toplevel->page_current->to_world_y_constant + 00075 w_current->toplevel->page_current->top; 00076 00077 #ifdef HAS_RINT 00078 j = rint(i); 00079 #else 00080 j = i; 00081 #endif 00082 00083 return(j); 00084 } 00085 00094 int pix_x (GSCHEM_TOPLEVEL *w_current, int val) 00095 { 00096 00097 double i; 00098 int j; 00099 00100 i = w_current->toplevel->page_current->to_screen_x_constant * 00101 (double)(val - w_current->toplevel->page_current->left); 00102 00103 #ifdef HAS_RINT 00104 j = rint(i); 00105 #else 00106 j = i; 00107 #endif 00108 00109 /* this is a temp solution to fix the wrapping associated with */ 00110 /* X coords being greated/less than than 2^15 */ 00111 if (j >= 32768) { 00112 j = 32767; 00113 } 00114 if (j <= -32768) { 00115 j = -32767; 00116 } 00117 00118 return(j); 00119 } 00120 00129 int pix_y(GSCHEM_TOPLEVEL *w_current, int val) 00130 { 00131 double i; 00132 int j; 00133 00134 i = w_current->toplevel->height - 00135 (w_current->toplevel->page_current->to_screen_y_constant * 00136 (double)(val - w_current->toplevel->page_current->top)); 00137 00138 #ifdef HAS_RINT 00139 j = rint(i); 00140 #else 00141 j = i; 00142 #endif 00143 00144 /* this is a temp solution to fix the wrapping associated with */ 00145 /* X coords being greated/less than than 2^15 */ 00146 if (j >= 32768) { 00147 j = 32767; 00148 } 00149 if (j <= -32768) { 00150 j = -32767; 00151 } 00152 00153 return(j); 00154 } 00155 00167 void WORLDtoSCREEN (GSCHEM_TOPLEVEL *w_current, int x, int y, int *px, int *py) 00168 { 00169 *px = pix_x (w_current, x); 00170 *py = pix_y (w_current, y); 00171 } 00172 00187 void SCREENtoWORLD (GSCHEM_TOPLEVEL *w_current, int mx, int my, int *x, int *y) 00188 { 00189 *x = mil_x (w_current, mx); 00190 *y = mil_y (w_current, my); 00191 } 00192 00202 int snap_grid(GSCHEM_TOPLEVEL *w_current, int input) 00203 { 00204 int p, m, n; 00205 int sign, value, snap_grid; 00206 00207 if (w_current->snap == SNAP_OFF || 00208 w_current->snap_size <= 0) { 00209 return(input); 00210 } 00211 00212 snap_grid = w_current->snap_size; 00213 00214 /* this code was inspired from killustrator, it's much simpler than mine */ 00215 sign = ( input < 0 ? -1 : 1 ); 00216 value = abs(input); 00217 00218 p = value / snap_grid; 00219 m = value % snap_grid; 00220 n = p * snap_grid; 00221 if (m > snap_grid / 2) 00222 n += snap_grid; 00223 00224 #if DEBUG 00225 printf("p: %d\n", p); 00226 printf("m: %d\n", m); 00227 printf("m > snap_grid / 2: %d\n", (m > snap_grid / 2)); 00228 printf("n: %d\n", n); 00229 printf("n*s: %d\n", n*sign); 00230 #endif 00231 00232 return(sign*n); 00233 } 00234 00243 int SCREENabs(GSCHEM_TOPLEVEL *w_current, int val) 00244 { 00245 double f0,f1,f; 00246 00247 double i; 00248 int j; 00249 00250 f0 = w_current->toplevel->page_current->left; 00251 f1 = w_current->toplevel->page_current->right; 00252 f = w_current->toplevel->width / (f1 - f0); 00253 i = f * (double)(val); 00254 00255 #ifdef HAS_RINT 00256 j = rint(i); 00257 #else 00258 j = i; 00259 #endif 00260 00261 return(j); 00262 00263 } 00264 00273 int WORLDabs(GSCHEM_TOPLEVEL *w_current, int val) 00274 { 00275 double fw0,fw1,fw,fval; 00276 00277 double i; 00278 int j; 00279 00280 fw1 = w_current->toplevel->page_current->right; 00281 fw0 = w_current->toplevel->page_current->left; 00282 fw = w_current->toplevel->width; 00283 fval = val; 00284 i = fval * (fw1 - fw0) / fw; 00285 00286 #ifdef HAS_RINT 00287 j = rint(i); 00288 #else 00289 j = i; 00290 #endif 00291 00292 return(j); 00293 } 00294 00295 00297 typedef struct st_halfspace HALFSPACE; 00298 00300 struct st_halfspace { 00301 int left; /* these are booleans */ 00302 int top; 00303 int right; 00304 int bottom; 00305 }; 00306 00307 /* \note 00308 * encode_halfspace and clip are part of the cohen-sutherland clipping 00309 * algorithm. They are used to determine if an object is visible or not 00310 */ 00323 static void WORLDencode_halfspace (GSCHEM_TOPLEVEL *w_current, 00324 sPOINT *point, HALFSPACE *halfspace) 00325 { 00326 halfspace->left = point->x < w_current->toplevel->page_current->left; 00327 halfspace->right = point->x > w_current->toplevel->page_current->right; 00328 halfspace->bottom = point->y > w_current->toplevel->page_current->bottom; 00329 halfspace->top = point->y < w_current->toplevel->page_current->top; 00330 } 00331 00346 int WORLDclip_change (GSCHEM_TOPLEVEL *w_current, 00347 int *x1, int *y1, int *x2, int *y2) 00348 { 00349 HALFSPACE half1, half2; 00350 HALFSPACE tmp_half; 00351 sPOINT tmp_point; 00352 sPOINT point1, point2; 00353 float slope; 00354 int in1, in2, done; 00355 int visible; 00356 int w_l, w_t, w_r, w_b; 00357 00358 point1.x = *x1; 00359 point1.y = *y1; 00360 point2.x = *x2; 00361 point2.y = *y2; 00362 00363 w_l = w_current->toplevel->page_current->left; 00364 w_t = w_current->toplevel->page_current->top; 00365 w_r = w_current->toplevel->page_current->right; 00366 w_b = w_current->toplevel->page_current->bottom; 00367 00368 done = FALSE; 00369 visible = FALSE; 00370 00371 do { 00372 WORLDencode_halfspace (w_current, &point1, &half1); 00373 WORLDencode_halfspace (w_current, &point2, &half2); 00374 00375 #if DEBUG 00376 printf("starting loop\n"); 00377 printf("1 %d %d %d %d\n", half1.left, half1.top, half1.right, half1.bottom); 00378 printf("2 %d %d %d %d\n", half2.left, half2.top, half2.right, half2.bottom); 00379 #endif 00380 00381 in1 = (!half1.left) && 00382 (!half1.top) && 00383 (!half1.right) && 00384 (!half1.bottom); 00385 00386 in2 = (!half2.left) && 00387 (!half2.top) && 00388 (!half2.right) && 00389 (!half2.bottom); 00390 00391 00392 if (in1 && in2) { /* trivally accept */ 00393 done = TRUE; 00394 visible = TRUE; 00395 } else if ( ((half1.left && half2.left) || 00396 (half1.right && half2.right)) || 00397 ((half1.top && half2.top) || 00398 (half1.bottom && half2.bottom)) ) { 00399 done = TRUE; /* trivially reject */ 00400 visible = FALSE; 00401 } else { /* at least one point outside */ 00402 if (in1) { 00403 tmp_half = half1; 00404 half1 = half2; 00405 half2 = tmp_half; 00406 00407 tmp_point = point1; 00408 point1 = point2; 00409 point2 = tmp_point; 00410 } 00411 00412 if (point2.x == point1.x) { /* vertical line */ 00413 if (half1.top) { 00414 point1.y = w_t; 00415 } else if (half1.bottom) { 00416 point1.y = w_b; 00417 } 00418 } else { /* not a vertical line */ 00419 00420 /* possible fix for alpha core dumping */ 00421 /* assume the object is visible */ 00422 if ((point2.x - point1.x) == 0) { 00423 return(TRUE); 00424 } 00425 00426 slope = (float) (point2.y - point1.y) / 00427 (float) (point2.x - point1.x); 00428 00429 /* possible fix for alpha core dumping */ 00430 /* assume the object is visible */ 00431 if (slope == 0.0) { 00432 return(TRUE); 00433 } 00434 00435 if (half1.left) { 00436 point1.y = point1.y + 00437 (w_l - point1.x) * slope; 00438 point1.x = w_l; 00439 } else if (half1.right) { 00440 point1.y = point1.y + 00441 (w_r - point1.x) * slope; 00442 point1.x = w_r; 00443 } else if (half1.bottom) { 00444 point1.x = point1.x + 00445 (w_b - point1.y) / slope; 00446 point1.y = w_b; 00447 } else if (half1.top) { 00448 point1.x = point1.x + 00449 (w_t - point1.y) / slope; 00450 point1.y = w_t; 00451 } 00452 } /* end of not a vertical line */ 00453 } /* end of at least one outside */ 00454 } while (!done); 00455 00456 /*printf("after: %d %d %d %d\n", point1.x, point1.y, point2.x, point2.y);*/ 00457 *x1 = point1.x; 00458 *y1 = point1.y; 00459 *x2 = point2.x; 00460 *y2 = point2.y; 00461 return(visible); 00462 } 00463 00477 int clip_nochange (GSCHEM_TOPLEVEL *w_current, int x1, int y1, int x2, int y2) 00478 { 00479 HALFSPACE half1, half2; 00480 HALFSPACE tmp_half; 00481 sPOINT tmp_point; 00482 sPOINT point1, point2; 00483 float slope; 00484 int in1, in2, done; 00485 int visible; 00486 int w_l, w_t, w_r, w_b; 00487 00488 point1.x = x1; 00489 point1.y = y1; 00490 point2.x = x2; 00491 point2.y = y2; 00492 00493 /*printf("before: %d %d %d %d\n", x1, y1, x2, y2);*/ 00494 00495 w_l = w_current->toplevel->page_current->left; 00496 w_t = w_current->toplevel->page_current->top; 00497 w_r = w_current->toplevel->page_current->right; 00498 w_b = w_current->toplevel->page_current->bottom; 00499 00500 done = FALSE; 00501 visible = FALSE; 00502 00503 do { 00504 WORLDencode_halfspace (w_current, &point1, &half1); 00505 WORLDencode_halfspace (w_current, &point2, &half2); 00506 00507 #if DEBUG 00508 printf("starting loop\n"); 00509 printf("1 %d %d %d %d\n", half1.left, half1.top, half1.right, half1.bottom); 00510 printf("2 %d %d %d %d\n", half2.left, half2.top, half2.right, half2.bottom); 00511 #endif 00512 00513 in1 = (!half1.left) && 00514 (!half1.top) && 00515 (!half1.right) && 00516 (!half1.bottom); 00517 00518 in2 = (!half2.left) && 00519 (!half2.top) && 00520 (!half2.right) && 00521 (!half2.bottom); 00522 00523 00524 if (in1 && in2) { /* trivally accept */ 00525 done = TRUE; 00526 visible = TRUE; 00527 } else if ( ((half1.left && half2.left) || 00528 (half1.right && half2.right)) || 00529 ((half1.top && half2.top) || 00530 (half1.bottom && half2.bottom)) ) { 00531 done = TRUE; /* trivially reject */ 00532 visible = FALSE; 00533 } else { /* at least one point outside */ 00534 if (in1) { 00535 tmp_half = half1; 00536 half1 = half2; 00537 half2 = tmp_half; 00538 00539 tmp_point = point1; 00540 point1 = point2; 00541 point2 = tmp_point; 00542 } 00543 00544 if (point2.x == point1.x) { /* vertical line */ 00545 if (half1.top) { 00546 point1.y = w_t; 00547 } else if (half1.bottom) { 00548 point1.y = w_b; 00549 } 00550 } else { /* not a vertical line */ 00551 00552 /* possible fix for alpha core dumping */ 00553 /* assume the object is visible */ 00554 if ((point2.x - point1.x) == 0) { 00555 return(TRUE); 00556 } 00557 00558 slope = (float) (point2.y - point1.y) / 00559 (float) (point2.x - point1.x); 00560 00561 /* possible fix for alpha core dumping */ 00562 /* assume the object is visible */ 00563 if (slope == 0.0) { 00564 return(TRUE); 00565 } 00566 00567 if (half1.left) { 00568 point1.y = point1.y + 00569 (w_l - point1.x) * slope; 00570 point1.x = w_l; 00571 } else if (half1.right) { 00572 point1.y = point1.y + 00573 (w_r - point1.x) * slope; 00574 point1.x = w_r; 00575 } else if (half1.bottom) { 00576 point1.x = point1.x + 00577 (w_b - point1.y) / slope; 00578 point1.y = w_b; 00579 } else if (half1.top) { 00580 point1.x = point1.x + 00581 (w_t - point1.y) / slope; 00582 point1.y = w_t; 00583 } 00584 } /* end of not a vertical line */ 00585 } /* end of at least one outside */ 00586 } while (!done); 00587 00588 return(visible); 00589 } 00590 00606 int visible (GSCHEM_TOPLEVEL *w_current, 00607 int wleft, int wtop, int wright, int wbottom) 00608 { 00609 int visible=FALSE; 00610 00611 /* don't do object clipping if this is false */ 00612 if (!w_current->toplevel->object_clipping) { 00613 return(TRUE); 00614 } 00615 00616 visible = clip_nochange (w_current, wleft, wtop, wright, wtop); 00617 00618 #if DEBUG 00619 printf("vis1 %d\n", visible); 00620 #endif 00621 00622 if (!visible) { 00623 visible = clip_nochange (w_current, wleft, wbottom, wright, wbottom); 00624 } else { 00625 return(visible); 00626 } 00627 00628 #if DEBUG 00629 printf("vis2 %d\n", visible); 00630 #endif 00631 00632 if (!visible) { 00633 visible = clip_nochange (w_current, wleft, wtop, wleft, wbottom); 00634 } else { 00635 return(visible); 00636 } 00637 00638 #if DEBUG 00639 printf("vis3 %d\n", visible); 00640 #endif 00641 00642 if (!visible) { 00643 visible = clip_nochange (w_current, wright, wtop, wright, wbottom); 00644 } else { 00645 return(visible); 00646 } 00647 00648 #if DEBUG 00649 printf("vis4 %d\n", visible); 00650 #endif 00651 00652 #if DEBUG 00653 printf("%d %d %d\n", wleft, w_current->toplevel->page_current->top, wright); 00654 printf("%d %d %d\n", wtop, w_current->toplevel->page_current->top, wbottom); 00655 printf("%d %d %d\n", wleft, w_current->toplevel->page_current->right, wright); 00656 printf("%d %d %d\n", wtop, w_current->toplevel->page_current->bottom, wbottom); 00657 #endif 00658 00659 /* 00660 * now check to see if bounding box encompasses the entire viewport. 00661 * We only need to test if one point on the screen clipping boundary 00662 * is indide the bounding box of the object. 00663 */ 00664 if (w_current->toplevel->page_current->left >= wleft && 00665 w_current->toplevel->page_current->left <= wright && 00666 w_current->toplevel->page_current->top >= wtop && 00667 w_current->toplevel->page_current->top <= wbottom ) { 00668 visible = 1; 00669 } 00670 00671 #if DEBUG 00672 printf("vis5 %d\n", visible); 00673 #endif 00674 00675 return(visible); 00676 } 00677 00678 00691 /* rounds for example 1235 to 1000, 670 to 500, 0.234 to 0.2 ... 00692 int would be enough if there are no numbers smaller 1 (hw)*/ 00693 double round_5_2_1(double unrounded) 00694 { 00695 int digits; 00696 double betw_1_10; 00697 00698 /*only using the automatic cast */ 00699 digits = log10(unrounded); 00700 /* creates numbers between 1 and 10 */ 00701 betw_1_10 = unrounded / pow(10,digits); 00702 00703 if (betw_1_10 < 1.5) { 00704 return(pow(10,digits)); 00705 } 00706 if (betw_1_10 > 1.4 && betw_1_10 < 3.5 ) { 00707 return(2*pow(10,digits)); 00708 } 00709 if (betw_1_10 > 3.4 && betw_1_10 < 7.5 ) { 00710 return(5*pow(10,digits)); 00711 } 00712 else { 00713 return(10*pow(10,digits)); 00714 } 00715 }