Root/coord.c

Source at commit 688f2ab9345ca377690cce88dda52fe2cd0ec1ff created 2 years 9 months ago.
By Werner Almesberger, dimensions can now be specified in micrometers (um)
1/*
2 * coord.c - Coordinate representation and basic operations
3 *
4 * Written 2009, 2010, 2016 by Werner Almesberger
5 * Copyright 2009, 2010, 2016 by Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13
14#include <math.h>
15
16#include "util.h"
17#include "coord.h"
18
19
20/* ----- unit conversion --------------------------------------------------- */
21
22
23double mm_to_mil(double mm, int exponent)
24{
25    return mm*pow(MIL_IN_MM, -exponent);
26}
27
28
29double mil_to_mm(double mil, int exponent)
30{
31    return mil*pow(MIL_IN_MM, exponent);
32}
33
34
35double um_to_mm(double um, int exponent)
36{
37    return um*pow(UM_IN_MM, exponent);
38}
39
40
41/* ----- convert internal units to best external unit ---------------------- */
42
43
44double units_to_best(unit_type u, int *mm)
45{
46    /*
47     * For finding the best choice, we work with deci-micrometers and
48     * micro-inches. The conversion to "dum" is actually a no-op, but that
49     * may change if we ever pick a different internal unit than 0.1 um.
50     */
51
52    long dum = round(units_to_mm(u)*10000.0);
53    long uin = round(units_to_mil(u)*1000.0);
54
55    /* remove trailing zeroes */
56
57    while (dum && !(dum % 10))
58        dum /= 10;
59    while (uin && !(uin % 10))
60        uin /= 10;
61
62    /* ceil(log10(dum)) <= ceil(log10(uin)) ? */
63
64    while (dum && uin) {
65        dum /= 10;
66        uin /= 10;
67    }
68    if (!dum) {
69        *mm = 1;
70        return units_to_mm(u);
71    } else {
72        *mm = 0;
73        return units_to_mil(u);
74    }
75}
76
77
78/* ----- vector operations ------------------------------------------------- */
79
80
81struct coord normalize(struct coord v, unit_type len)
82{
83    double f;
84
85    f = len/hypot(v.x, v.y);
86    v.x *= f;
87    v.y *= f;
88    return v;
89}
90
91
92struct coord rotate(struct coord v, double angle)
93{
94    double rad = M_PI*angle/180.0;
95    struct coord res;
96
97    res.x = v.x*cos(rad)-v.y*sin(rad);
98    res.y = v.y*cos(rad)+v.x*sin(rad);
99    return res;
100}
101
102
103struct coord add_vec(struct coord a, struct coord b)
104{
105    a.x += b.x;
106    a.y += b.y;
107    return a;
108}
109
110
111struct coord sub_vec(struct coord a, struct coord b)
112{
113    a.x -= b.x;
114    a.y -= b.y;
115    return a;
116}
117
118
119struct coord neg_vec(struct coord v)
120{
121    v.x = -v.x;
122    v.y = -v.y;
123    return v;
124}
125
126
127/* ----- point on circle --------------------------------------------------- */
128
129
130struct coord rotate_r(struct coord c, unit_type r, double angle)
131{
132    struct coord p;
133
134    angle = angle/180.0*M_PI;
135    p.x = c.x+r*cos(angle);
136    p.y = c.y+r*sin(angle);
137    return p;
138}
139
140
141double theta_vec(struct coord v)
142{
143    double a;
144
145    a = atan2(v.y, v.x)/M_PI*180.0;
146    if (a < 0)
147        a += 360.0;
148    return a;
149}
150
151
152double theta(struct coord c, struct coord p)
153{
154    p.x -= c.x;
155    p.y -= c.y;
156    return theta_vec(p);
157}
158
159
160/* ----- sorting coordinates ----------------------------------------------- */
161
162
163void sort_coord(struct coord *min, struct coord *max)
164{
165    if (min->x > max->x)
166        SWAP(min->x, max->x);
167    if (min->y > max->y)
168        SWAP(min->y, max->y);
169
170}
171
172
173/* ----- distance calculations --------------------------------------------- */
174
175
176unit_type dist_point(struct coord a, struct coord b)
177{
178    return hypot(a.x-b.x, a.y-b.y);
179}
180
181
182static unit_type dist_line_xy(unit_type px, unit_type py,
183    unit_type ax, unit_type ay, unit_type bx, unit_type by)
184{
185    unit_type d_min, d;
186    double a, f;
187
188    d_min = hypot(ax-px, ay-py);
189    d = hypot(bx-px, by-py);
190    if (d < d_min)
191        d_min = d;
192    if (ax != bx || ay != by) {
193        /*
194         * We make a the line vector from point B and b the vector from
195         * B to point P. Then we calculate the projection of b on a.
196         */
197        ax -= bx;
198        ay -= by;
199        bx = px-bx;
200        by = py-by;
201        a = hypot(ax, ay);
202        f = ((double) ax*bx+(double) ay*by)/a/a;
203        if (f >= 0 && f <= 1) {
204            bx -= f*ax;
205            by -= f*ay;
206            d = hypot(bx, by);
207            if (d < d_min)
208                d_min = d;
209        }
210    }
211    return d_min;
212}
213
214
215unit_type dist_line(struct coord p, struct coord a, struct coord b)
216{
217    return dist_line_xy(p.x, p.y, a.x, a.y, b.x, b.y);
218}
219
220
221unit_type dist_rect(struct coord p, struct coord a, struct coord b)
222{
223    unit_type d_min, d;
224
225    d_min = dist_line_xy(p.x, p.y, a.x, a.y, b.x, a.y);
226    d = dist_line_xy(p.x, p.y, a.x, a.y, a.x, b.y);
227    if (d < d_min)
228        d_min = d;
229    d = dist_line_xy(p.x, p.y, a.x, b.y, b.x, b.y);
230    if (d < d_min)
231        d_min = d;
232    d = dist_line_xy(p.x, p.y, b.x, a.y, b.x, b.y);
233    if (d < d_min)
234        d_min = d;
235    return d_min;
236}
237
238
239int inside_rect(struct coord p, struct coord a, struct coord b)
240{
241    sort_coord(&a, &b);
242    if (p.x < a.x || p.x > b.x)
243        return 0;
244    if (p.y < a.y || p.y > b.y)
245        return 0;
246    return 1;
247}
248
249
250unit_type dist_circle(struct coord p, struct coord c, unit_type r)
251{
252    unit_type d;
253
254    d = hypot(p.x-c.x, p.y-c.y);
255    return fabs(d-r);
256}
257

Archive Download this file

Branches:
master



interactive