missing NULL terminator in set_config_x
[geda-gaf.git] / gschem / src / m_basic.c
bloba0734be7f165c8bcdc10ad07600288da26896de5
1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2020 gEDA Contributors (see ChangeLog for details)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 #include <config.h>
22 #include <stdio.h>
23 #include <math.h>
25 #include <gschem.h>
27 /*! \brief Find the closest grid coordinate.
28 * \par Function Description
29 * This function snaps the current input coordinate to the
30 * closest grid coordinate.
32 * \param [in] w_current The GschemToplevel object.
33 * \param [in] input The coordinate to snap.
34 * \return The closest grid coordinate to the input.
36 int snap_grid(GschemToplevel *w_current, int input)
38 int p, m, n;
39 int sign, value, snap_size;
40 SNAP_STATE snap_mode;
42 snap_mode = gschem_options_get_snap_mode (w_current->options);
43 snap_size = gschem_options_get_snap_size (w_current->options);
45 if (snap_mode == SNAP_OFF) {
46 return(input);
49 /* this code was inspired from killustrator, it's much simpler than mine */
50 sign = ( input < 0 ? -1 : 1 );
51 value = abs(input);
53 p = value / snap_size;
54 m = value % snap_size;
55 n = p * snap_size;
56 if (m > snap_size / 2)
57 n += snap_size;
59 #if DEBUG
60 printf("p: %d\n", p);
61 printf("m: %d\n", m);
62 printf("m > snap_size / 2: %d\n", (m > snap_size / 2));
63 printf("n: %d\n", n);
64 printf("n*s: %d\n", n*sign);
65 #endif
67 return(sign*n);
72 /*! \brief */
73 typedef struct st_halfspace HALFSPACE;
75 /*! \brief */
76 struct st_halfspace {
77 int left; /* these are booleans */
78 int top;
79 int right;
80 int bottom;
83 /* \note
84 * encode_halfspace and clip are part of the cohen-sutherland clipping
85 * algorithm. They are used to determine if an object is visible or not
87 /*! \brief Encode WORLD coordinates as halfspace matrix.
88 * \par Function Description
89 * This function takes a point and checks if it is in the bounds
90 * of the current TOPLEVEL object's page coordinates. It
91 * handles points with WORLD coordinates.
93 * \param [in] w_current The GschemToplevel object.
94 * \param [in] point The point in WORLD coordinates to be checked.
95 * \param [out] halfspace The created HALFSPACE structure.
97 * \warning halfspace must be allocated before this function is called
99 static void WORLDencode_halfspace (GschemPageGeometry *geometry,
100 sPOINT *point, HALFSPACE *halfspace)
102 halfspace->left = point->x < geometry->viewport_left;
103 halfspace->right = point->x > geometry->viewport_right;
104 halfspace->bottom = point->y > geometry->viewport_bottom;
105 halfspace->top = point->y < geometry->viewport_top;
108 /*! \brief Check if a set of coordinates are within a clipping region
109 * \par Function Description
110 * This function will check if the given set of coordinates
111 * are within a clipping region. No action will be taken to change
112 * the coordinates.
114 * \param [in] w_current The GschemToplevel object.
115 * \param [in,out] x1 x coordinate of the first screen point.
116 * \param [in,out] y1 y coordinate of the first screen point.
117 * \param [in,out] x2 x coordinate of the second screen point.
118 * \param [in,out] y2 y coordinate of the second screen point.
119 * \return TRUE if coordinates are now visible, FALSE otherwise.
121 int clip_nochange (GschemPageGeometry *geometry, int x1, int y1, int x2, int y2)
123 HALFSPACE half1, half2;
124 HALFSPACE tmp_half;
125 sPOINT tmp_point;
126 sPOINT point1, point2;
127 float slope;
128 int in1, in2, done;
129 int visible;
130 int w_l, w_t, w_r, w_b;
132 point1.x = x1;
133 point1.y = y1;
134 point2.x = x2;
135 point2.y = y2;
137 /*printf("before: %d %d %d %d\n", x1, y1, x2, y2);*/
139 w_l = geometry->viewport_left;
140 w_t = geometry->viewport_top;
141 w_r = geometry->viewport_right;
142 w_b = geometry->viewport_bottom;
144 done = FALSE;
145 visible = FALSE;
147 do {
148 WORLDencode_halfspace (geometry, &point1, &half1);
149 WORLDencode_halfspace (geometry, &point2, &half2);
151 #if DEBUG
152 printf("starting loop\n");
153 printf("1 %d %d %d %d\n", half1.left, half1.top, half1.right, half1.bottom);
154 printf("2 %d %d %d %d\n", half2.left, half2.top, half2.right, half2.bottom);
155 #endif
157 in1 = (!half1.left) &&
158 (!half1.top) &&
159 (!half1.right) &&
160 (!half1.bottom);
162 in2 = (!half2.left) &&
163 (!half2.top) &&
164 (!half2.right) &&
165 (!half2.bottom);
168 if (in1 && in2) { /* trivally accept */
169 done = TRUE;
170 visible = TRUE;
171 } else if ( ((half1.left && half2.left) ||
172 (half1.right && half2.right)) ||
173 ((half1.top && half2.top) ||
174 (half1.bottom && half2.bottom)) ) {
175 done = TRUE; /* trivially reject */
176 visible = FALSE;
177 } else { /* at least one point outside */
178 if (in1) {
179 tmp_half = half1;
180 half1 = half2;
181 half2 = tmp_half;
183 tmp_point = point1;
184 point1 = point2;
185 point2 = tmp_point;
188 if (point2.x == point1.x) { /* vertical line */
189 if (half1.top) {
190 point1.y = w_t;
191 } else if (half1.bottom) {
192 point1.y = w_b;
194 } else { /* not a vertical line */
196 /* possible fix for alpha core dumping */
197 /* assume the object is visible */
198 if ((point2.x - point1.x) == 0) {
199 return(TRUE);
202 slope = (float) (point2.y - point1.y) /
203 (float) (point2.x - point1.x);
205 /* possible fix for alpha core dumping */
206 /* assume the object is visible */
207 if (slope == 0.0) {
208 return(TRUE);
211 if (half1.left) {
212 point1.y = point1.y +
213 (w_l - point1.x) * slope;
214 point1.x = w_l;
215 } else if (half1.right) {
216 point1.y = point1.y +
217 (w_r - point1.x) * slope;
218 point1.x = w_r;
219 } else if (half1.bottom) {
220 point1.x = point1.x +
221 (w_b - point1.y) / slope;
222 point1.y = w_b;
223 } else if (half1.top) {
224 point1.x = point1.x +
225 (w_t - point1.y) / slope;
226 point1.y = w_t;
228 } /* end of not a vertical line */
229 } /* end of at least one outside */
230 } while (!done);
232 return(visible);
235 /*! \brief Check if a bounding box is visible on the screen.
236 * \par Function Description
237 * This function checks if a given bounding box is visible on the screen.
239 * WARNING: top and bottom are mis-named in world-coords,
240 * top is the smallest "y" value, and bottom is the largest.
241 * Be careful! This doesn't correspond to what you'd expect.
243 * \param [in] w_current The GschemToplevel object.
244 * \param [in] wleft Left coordinate of the bounding box.
245 * \param [in] wtop Top coordinate of the bounding box.
246 * \param [in] wright Right coordinate of the bounding box.
247 * \param [in] wbottom Bottom coordinate of the bounding box.
248 * \return TRUE if bounding box is visible, FALSE otherwise
250 int visible (GschemToplevel *w_current,
251 int wleft, int wtop, int wright, int wbottom)
253 int visible=FALSE;
254 GschemPageGeometry *geometry = gschem_page_view_get_page_geometry (gschem_toplevel_get_current_page_view (w_current));
256 visible = clip_nochange (geometry, wleft, wtop, wright, wtop);
258 #if DEBUG
259 printf("vis1 %d\n", visible);
260 #endif
262 if (!visible) {
263 visible = clip_nochange (geometry, wleft, wbottom, wright, wbottom);
264 } else {
265 return(visible);
268 #if DEBUG
269 printf("vis2 %d\n", visible);
270 #endif
272 if (!visible) {
273 visible = clip_nochange (geometry, wleft, wtop, wleft, wbottom);
274 } else {
275 return(visible);
278 #if DEBUG
279 printf("vis3 %d\n", visible);
280 #endif
282 if (!visible) {
283 visible = clip_nochange (geometry, wright, wtop, wright, wbottom);
284 } else {
285 return(visible);
288 #if DEBUG
289 printf("vis4 %d\n", visible);
290 #endif
292 #if DEBUG
293 printf("%d %d %d\n", wleft, geometry->viewport_top, wright);
294 printf("%d %d %d\n", wtop, geometry->viewport_top, wbottom);
295 printf("%d %d %d\n", wleft, geometry->viewport_right, wright);
296 printf("%d %d %d\n", wtop, geometry->viewport_bottom, wbottom);
297 #endif
300 * now check to see if bounding box encompasses the entire viewport.
301 * We only need to test if one point on the screen clipping boundary
302 * is indide the bounding box of the object.
304 if (geometry->viewport_left >= wleft &&
305 geometry->viewport_left <= wright &&
306 geometry->viewport_top >= wtop &&
307 geometry->viewport_top <= wbottom ) {
308 visible = 1;
311 #if DEBUG
312 printf("vis5 %d\n", visible);
313 #endif
315 return(visible);
319 /*! \brief Rounds numbers by a power of 10.
320 * \par Function Description
321 * This function will round numbers using a power of 10 method.
322 * For example:
323 * 1235 rounds to 1000
324 * 670 rounds to 500
325 * 0.234 rounds to 0.2
326 * integer values would be enough if there are no numbers smaller than 1 (hw)
328 * \param [in] unrounded The number to be rounded.
329 * \return The rounded number.
331 /* rounds for example 1235 to 1000, 670 to 500, 0.234 to 0.2 ...
332 int would be enough if there are no numbers smaller 1 (hw)*/
333 double round_5_2_1(double unrounded)
335 int digits;
336 double betw_1_10;
338 /*only using the automatic cast */
339 digits = log10(unrounded);
340 /* creates numbers between 1 and 10 */
341 betw_1_10 = unrounded / pow(10,digits);
343 if (betw_1_10 < 1.5) {
344 return(pow(10,digits));
346 if (betw_1_10 > 1.4 && betw_1_10 < 3.5 ) {
347 return(2*pow(10,digits));
349 if (betw_1_10 > 3.4 && betw_1_10 < 7.5 ) {
350 return(5*pow(10,digits));
352 else {
353 return(10*pow(10,digits));