1/*
2 * dms - calculate in degrees, minutes, and seconds (based on deg)
3 *
4 * Copyright (C) 1999,2010,2021  David I. Bell and Landon Curt Noll
5 *
6 * Calc is open software; you can redistribute it and/or modify it under
7 * the terms of the version 2.1 of the GNU Lesser General Public License
8 * as published by the Free Software Foundation.
9 *
10 * Calc is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU Lesser General
13 * Public License for more details.
14 *
15 * A copy of version 2.1 of the GNU Lesser General Public License is
16 * distributed with calc under the filename COPYING-LGPL.  You should have
17 * received a copy with calc; if not, write to Free Software Foundation, Inc.
18 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 *
20 * Under source code control:	1990/02/15 01:50:33
21 * File existed as early as:	before 1990
22 *
23 * Share and enjoy!  :-)	http://www.isthe.com/chongo/tech/comp/calc/
24 */
25
26
27obj dms {deg, min, sec};
28
29define dms(deg, min, sec)
30{
31    local obj dms ans;		/* return value */
32
33    /* default missing args to 0 */
34    if (isnull(sec)) {
35	sec = 0;
36    }
37    if (isnull(min)) {
38	min = 0;
39    }
40
41    /* load object */
42    ans.deg = deg;
43    ans.min = min;
44    ans.sec = sec;
45
46    /* return properly formed object */
47    ans = fixdms(ans);
48    return ans;
49}
50
51
52define dms_add(a, b)
53{
54    local obj dms ans;		/* return value */
55
56    /* initialize value to 1st arg */
57    if (istype(a, ans)) {
58	/* 1st arg is dms object, load it */
59	ans.deg = a.deg;
60	ans.min = a.min;
61	ans.sec = a.sec;
62    } else {
63	/* 1st arg is not dms, assume scalar degrees */
64	ans.deg = a;
65	ans.min = 0;
66	ans.sec = 0;
67    }
68
69    /* add value of 2nd arg */
70    if (istype(b, ans)) {
71	/* 2nd arg is dms object, add it */
72	ans.deg += b.deg;
73	ans.min += b.min;
74	ans.sec += b.sec;
75    } else {
76	/* 2nd arg is not dms, add scalar degrees */
77	ans.deg += b;
78    }
79
80    /* return normalized result */
81    ans = fixdms(ans);
82    return ans;
83}
84
85
86define dms_neg(a)
87{
88    local obj dms ans;		/* return value */
89
90    /* negate argument */
91    if (istype(a, ans)) {
92	/* 1st arg is dms object, load it */
93	ans.deg = -a.deg;
94	ans.min = -a.min;
95	ans.sec = -a.sec;
96    } else {
97	/* 2nd arg is not dms, negate scalar degrees */
98	ans.deg = -a;
99	ans.min = 0;
100	ans.sec = 0;
101    }
102
103    /* return normalized result */
104    ans = fixdms(ans);
105    return ans;
106}
107
108
109define dms_sub(a, b)
110{
111    local obj dms ans;		/* return value */
112
113    /* initialize value to 1st arg */
114    if (istype(a, ans)) {
115	/* 1st arg is dms object, load it */
116	ans.deg = a.deg;
117	ans.min = a.min;
118	ans.sec = a.sec;
119    } else {
120	/* 1st arg is not dms, assume scalar degrees */
121	ans.deg = a;
122	ans.min = 0;
123	ans.sec = 0;
124    }
125
126    /* subtract value of 2nd arg */
127    if (istype(b, ans)) {
128	/* 2nd arg is dms object, subtract it */
129	ans.deg -= b.deg;
130	ans.min -= b.min;
131	ans.sec -= b.sec;
132    } else {
133	/* 2nd arg is not dms, subtract scalar degrees */
134	ans.deg -= b;
135    }
136
137    /* return normalized result */
138    ans = fixdms(ans);
139    return ans;
140}
141
142
143define dms_mul(a, b)
144{
145    local obj dms ans;		/* return value */
146
147    /* dms object multiplication */
148    if (istype(a, ans) && istype(b, ans)) {
149	ans.deg = dms_abs(a) * dms_abs(b);
150	ans.min = 0;
151	ans.sec = 0;
152
153    /* scalar multiplication */
154    } else if (istype(a, ans)) {
155	ans.deg = a.deg * b;
156	ans.min = a.min * b;
157	ans.sec = a.sec * b;
158    } else {
159	ans.deg = b.deg * a;
160	ans.min = b.min * a;
161	ans.sec = b.sec * a;
162    }
163
164    /* return normalized result */
165    ans = fixdms(ans);
166    return ans;
167}
168
169
170define dms_print(a)
171{
172    local obj dms ans;		/* temp object for dms type testing */
173
174    /* firewall - arg must be a dms object */
175    if (! istype(a, ans)) {
176	quit "dms_print called with non dms object";
177    }
178
179    /* print in dms form */
180    print a.deg : 'd' : a.min : 'm' : a.sec : 's' :;
181}
182
183
184define dms_abs(a)
185{
186    local obj dms ans;		/* temp object for dms type testing */
187    local deg;			/* return scalar value */
188
189    /* firewall - just absolute value non dms objects */
190    if (! istype(a, ans)) {
191	return abs(a);
192    }
193
194    /* compute degrees */
195    deg = a.deg + a.min / 60 + a.sec / 3600;
196
197    /* return degrees */
198    return deg;
199}
200
201
202define dms_norm(a)
203{
204    local obj dms ans;		/* temp object for dms type testing */
205    local deg;			/* degrees */
206
207    /* firewall - arg must be a dms object */
208    if (! istype(a, ans)) {
209	quit "dms_norm called with non dms object";
210    }
211
212    /* square degrees (norm is the square of absolute value */
213    deg = dms_abs(a);
214
215    /* return degrees */
216    return deg*deg;
217}
218
219
220define dms_test(a)
221{
222    local obj dms ans;		/* temp value */
223
224    /* firewall - arg must be a dms object */
225    if (! istype(a, ans)) {
226	quit "dms_test called with non dms object";
227    }
228
229    /* return false of non-zero */
230    ans = fixdms(a);
231    if (ans.deg == 0 && ans.min == 0 && ans.sec == 0) {
232	/* false */
233	return 0;
234    }
235    /* true */
236    return 1;
237}
238
239
240define dms_int(a)
241{
242    local obj dms ans;		/* return value */
243
244    /* firewall - arg must be a dms object */
245    if (! istype(a, ans)) {
246	quit "dms_int called with non dms object";
247    }
248
249    /* normalize the argument */
250    ans = fixdms(a);
251
252    /* truncate to the nearest second */
253    ans.sec = int(ans.sec);
254
255    /* return value to the nearest second */
256    return ans;
257}
258
259
260define dms_frac(a)
261{
262    local obj dms ans;		/* return value */
263
264    /* firewall - arg must be a dms object */
265    if (! istype(a, ans)) {
266	quit "dms_frac called with non dms object";
267    }
268
269    /* normalize the argument */
270    ans = fixdms(a);
271
272    /* remove all but fractional seconds */
273    ans.deg = 0;
274    ans.min = 0;
275    ans.sec = frac(ans.sec);
276
277    /* return value to the second fraction */
278    return ans;
279}
280
281
282define dms_rel(a,b)
283{
284    local abs_a, abs_b;		/* scalars of the arguments */
285
286    /* compute scalars of the arguments */
287    abs_a = dms_abs(a);
288    abs_b = dms_abs(b);
289
290    /* return the comparison */
291    return cmp(abs_a, abs_b);
292}
293
294
295define dms_cmp(a,b)
296{
297    local abs_a, abs_b;		/* scalars of the arguments */
298
299    /* compute scalars of the arguments */
300    abs_a = dms_abs(a);
301    abs_b = dms_abs(b);
302
303    /* return the equality comparison */
304    return (abs_a == abs_b);
305}
306
307
308define dms_inc(a)
309{
310    local obj dms ans;		/* return value */
311
312    /* increment a dms object */
313    if (istype(a, ans)) {
314	ans = a;
315	++ans.sec;
316
317	/* return normalized result */
318	ans = fixdms(ans);
319	return ans;
320    }
321
322    /* increment a scalar */
323    return a+1;
324}
325
326
327define dms_dec(a)
328{
329    local obj dms ans;		/* return value */
330
331    /* decrement a dms object */
332    if (istype(a, ans)) {
333	ans = a;
334	--ans.sec;
335
336	/* return normalized result */
337	ans = fixdms(ans);
338	return ans;
339    }
340
341    /* decrement a scalar */
342    return a-1;
343}
344
345
346define fixdms(a)
347{
348    local obj dms ans;		/* temp value */
349
350    /* firewall */
351    if (! istype(a, ans)) {
352	quit "attempt to fix a non dms object";
353    }
354
355    /* use builtin d2dms function */
356    d2dms(a.deg + a.min/60 + a.sec/3600, a.deg, a.min, a.sec),;
357
358    /* return normalized result */
359    return a;
360}
361
362if (config("resource_debug") & 3) {
363    print "obj dms {deg, min, sec} defined";
364}
365