1 /* Graphics_utils.cpp
2  *
3  * Copyright (C) 1992-2007,2009-2012,2015-2020 Paul Boersma
4  *
5  * This code is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or (at
8  * your option) any later version.
9  *
10  * This code is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13  * See the GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this work. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "GraphicsP.h"
20 
21 /***** UTILITIES: *****/
22 /***** THESE ROUINTES OUTPUT TO CURRENT GRAPHICS BY CALLING PRIMITIVES. *****/
23 /***** THE TWO UTILITIES "Graphics_grey" AND "Graphics_altitude" *****/
24 /***** ARE IN DIFFERENT FILES BECAUSE THEY NEED LOCAL SUBROUTINES. *****/
25 
26 /********** Utility functions. **********/
27 
28 /********** Drawing into margins. **********/
29 
Graphics_drawInnerBox(Graphics me)30 void Graphics_drawInnerBox (Graphics me) {
31 	const double original_x1WC = my d_x1WC, original_x2WC = my d_x2WC, original_y1WC = my d_y1WC, original_y2WC = my d_y2WC;
32 	const int original_lineType = my lineType;
33 	const double original_lineWidth = my lineWidth;
34 	const MelderColour original_colour = my colour;
35 
36 	Graphics_setInner (me);
37 	Graphics_setWindow (me, 0.0, 1.0, 0.0, 1.0);
38 	Graphics_setLineType (me, Graphics_DRAWN);
39 	Graphics_setLineWidth (me, 2.0 * original_lineWidth);
40 	Graphics_setColour (me, Melder_BLACK);
41 	Graphics_rectangle (me, 0.0, 1.0, 0.0, 1.0);
42 	Graphics_unsetInner (me);
43 
44 	Graphics_setWindow (me, original_x1WC, original_x2WC, original_y1WC, original_y2WC);
45 	Graphics_setLineType (me, original_lineType);
46 	Graphics_setLineWidth (me, original_lineWidth);
47 	Graphics_setColour (me, original_colour);
48 }
49 
Graphics_textLeft(Graphics me,bool farr,conststring32 text)50 void Graphics_textLeft (Graphics me, bool farr, conststring32 text) {
51 	const double original_x1WC = my d_x1WC, original_x2WC = my d_x2WC, original_y1WC = my d_y1WC, original_y2WC = my d_y2WC;
52 	const int vert = ( farr ? Graphics_TOP : Graphics_BOTTOM );
53 	const MelderColour original_colour = my colour;
54 
55 	Graphics_setColour (me, Melder_BLACK);
56 	Graphics_setWindow (me, 0.0, 1.0, 0.0, 1.0);
57 	Graphics_setTextRotation (me, 90.0);
58 	Graphics_setTextAlignment (me, Graphics_CENTRE, vert);
59 	if (! farr)
60 		Graphics_setInner (me);
61 	Graphics_text (me, 0.0, 0.5, text);
62 	if (! farr)
63 		Graphics_unsetInner (me);
64 
65 	Graphics_setTextRotation (me, 0.0);
66 	Graphics_setWindow (me, original_x1WC, original_x2WC, original_y1WC, original_y2WC);
67 	Graphics_setColour (me, original_colour);
68 }
69 
Graphics_textRight(Graphics me,bool farr,conststring32 text)70 void Graphics_textRight (Graphics me, bool farr, conststring32 text) {
71 	const double original_x1WC = my d_x1WC, original_x2WC = my d_x2WC, original_y1WC = my d_y1WC, original_y2WC = my d_y2WC;
72 	const int vert = ( farr ? Graphics_TOP : Graphics_BOTTOM );
73 	const MelderColour original_colour = my colour;
74 
75 	Graphics_setWindow (me, 0.0, 1.0, 0.0, 1.0);
76 	Graphics_setColour (me, Melder_BLACK);
77 	Graphics_setTextAlignment (me, Graphics_CENTRE, vert);
78 	Graphics_setTextRotation (me, 270.0);
79 	if (! farr)
80 		Graphics_setInner (me);
81 	Graphics_text (me, 1.0, 0.5, text);
82 	if (! farr)
83 		Graphics_unsetInner (me);
84 
85 	Graphics_setTextRotation (me, 0.0);
86 	Graphics_setWindow (me, original_x1WC, original_x2WC, original_y1WC, original_y2WC);
87 	Graphics_setColour (me, original_colour);
88 }
89 
Graphics_textBottom(Graphics me,bool farr,conststring32 text)90 void Graphics_textBottom (Graphics me, bool farr, conststring32 text) {
91 	const double original_x1WC = my d_x1WC, original_x2WC = my d_x2WC, original_y1WC = my d_y1WC, original_y2WC = my d_y2WC;
92 	const MelderColour original_colour = my colour;
93 
94 	Graphics_setWindow (me, 0.0, 1.0, 0.0, 1.0);
95 	Graphics_setColour (me, Melder_BLACK);
96 	if (farr) {
97 		Graphics_setTextAlignment (me, Graphics_CENTRE, Graphics_BOTTOM);
98 		Graphics_text (me, 0.5, 0.0, text);
99 	} else {
100 		Graphics_setTextAlignment (me, Graphics_CENTRE, Graphics_TOP);
101 		Graphics_setInner (me);
102 		Graphics_text (me, 0.5, - my vertTick, text);
103 		Graphics_unsetInner (me);
104 	}
105 
106 	Graphics_setWindow (me, original_x1WC, original_x2WC, original_y1WC, original_y2WC);
107 	Graphics_setColour (me, original_colour);
108 }
109 
Graphics_textTop(Graphics me,bool farr,conststring32 text)110 void Graphics_textTop (Graphics me, bool farr, conststring32 text) {
111 	const double original_x1WC = my d_x1WC, original_x2WC = my d_x2WC, original_y1WC = my d_y1WC, original_y2WC = my d_y2WC;
112 	const MelderColour original_colour = my colour;
113 
114 	Graphics_setWindow (me, 0.0, 1.0, 0.0, 1.0);
115 	Graphics_setColour (me, Melder_BLACK);
116 	if (farr) {
117 		Graphics_setTextAlignment (me, Graphics_CENTRE, Graphics_TOP);
118 		Graphics_text (me, 0.5, 1.0, text);
119 	} else {
120 		Graphics_setTextAlignment (me, Graphics_CENTRE, Graphics_BOTTOM);
121 		Graphics_setInner (me);
122 		Graphics_text (me, 0.5, 1.0 + my vertTick, text);
123 		Graphics_unsetInner (me);
124 	}
125 
126 	Graphics_setWindow (me, original_x1WC, original_x2WC, original_y1WC, original_y2WC);
127 	Graphics_setColour (me, original_colour);
128 }
129 
Graphics_marksLeft(Graphics me,int numberOfMarks,bool haveNumbers,bool haveTicks,bool haveDottedLines)130 void Graphics_marksLeft (Graphics me, int numberOfMarks, bool haveNumbers, bool haveTicks, bool haveDottedLines) {
131 	const double original_x1WC = my d_x1WC, original_x2WC = my d_x2WC, original_y1WC = my d_y1WC, original_y2WC = my d_y2WC;
132 	const int original_lineType = my lineType;
133 	const double original_lineWidth = my lineWidth;
134 	const MelderColour original_colour = my colour;
135 	if (numberOfMarks < 2)
136 		return;
137 
138 	Graphics_setWindow (me, 0.0, 1.0, original_y1WC, original_y2WC);
139 	Graphics_setColour (me, Melder_BLACK);
140 	Graphics_setTextAlignment (me, Graphics_RIGHT, Graphics_HALF);
141 	Graphics_setInner (me);
142 	if (haveTicks) {
143 		Graphics_setLineType (me, Graphics_DRAWN);
144 		Graphics_setLineWidth (me, 2.0 * original_lineWidth);
145 	}
146 	for (int i = 1; i <= numberOfMarks; i ++) {
147 		const double f = (i - 1.0) / (numberOfMarks - 1);
148 		const double yWC = original_y1WC + (original_y2WC - original_y1WC) * f;
149 		if (haveNumbers)
150 			Graphics_text (me, - my horTick, yWC, Melder_float (Melder_half (yWC)));
151 		if (haveTicks)
152 			Graphics_line (me, - my horTick, yWC, 0, yWC);
153 	}
154 	if (haveTicks)
155 		Graphics_setLineWidth (me, original_lineWidth);
156 	if (haveDottedLines && numberOfMarks > 2) {
157 		Graphics_setLineType (me, Graphics_DOTTED);
158 		Graphics_setLineWidth (me, 0.67 * original_lineWidth);
159 		for (int i = 2; i < numberOfMarks; i ++) {
160 			const double f = (i - 1.0) / (numberOfMarks - 1);
161 			const double yWC = original_y1WC + (original_y2WC - original_y1WC) * f;
162 			Graphics_line (me, 0.0, yWC, 1.0, yWC);
163 		}
164 		Graphics_setLineWidth (me, original_lineWidth);
165 	}
166 	Graphics_unsetInner (me);
167 
168 	Graphics_setWindow (me, original_x1WC, original_x2WC, original_y1WC, original_y2WC);
169 	Graphics_setLineType (me, original_lineType);
170 	Graphics_setColour (me, original_colour);
171 }
172 
Graphics_marksRight(Graphics me,int numberOfMarks,bool haveNumbers,bool haveTicks,bool haveDottedLines)173 void Graphics_marksRight (Graphics me, int numberOfMarks, bool haveNumbers, bool haveTicks, bool haveDottedLines) {
174 	const double original_x1WC = my d_x1WC, original_x2WC = my d_x2WC, original_y1WC = my d_y1WC, original_y2WC = my d_y2WC;
175 	const int original_lineType = my lineType;
176 	const double original_lineWidth = my lineWidth;
177 	const MelderColour original_colour = my colour;
178 	if (numberOfMarks < 2)
179 		return;
180 
181 	Graphics_setWindow (me, 0.0, 1.0, original_y1WC, original_y2WC);
182 	Graphics_setColour (me, Melder_BLACK);
183 	Graphics_setTextAlignment (me, Graphics_LEFT, Graphics_HALF);
184 	Graphics_setInner (me);
185 	if (haveTicks) {
186 		Graphics_setLineType (me, Graphics_DRAWN);
187 		Graphics_setLineWidth (me, 2.0 * original_lineWidth);
188 	}
189 	for (int i = 1; i <= numberOfMarks; i ++) {
190 		const double f = (i - 1.0) / (numberOfMarks - 1);
191 		const double yWC = original_y1WC + (original_y2WC - original_y1WC) * f;
192 		if (haveNumbers)
193 			Graphics_text (me, 1.0 + my horTick, yWC, Melder_float (Melder_half (yWC)));
194 		if (haveTicks)
195 			Graphics_line (me, 1.0, yWC, 1.0 + my horTick, yWC);
196 	}
197 	if (haveTicks)
198 		Graphics_setLineWidth (me, original_lineWidth);
199 	if (haveDottedLines && numberOfMarks > 2) {
200 		Graphics_setLineType (me, Graphics_DOTTED);
201 		Graphics_setLineWidth (me, 0.67 * original_lineWidth);
202 		for (int i = 2; i < numberOfMarks; i ++) {
203 			const double f = (i - 1.0) / (numberOfMarks - 1);
204 			const double yWC = original_y1WC + (original_y2WC - original_y1WC) * f;
205 			Graphics_line (me, 0.0, yWC, 1.0, yWC);
206 		}
207 		Graphics_setLineWidth (me, original_lineWidth);
208 	}
209 	Graphics_unsetInner (me);
210 
211 	Graphics_setWindow (me, original_x1WC, original_x2WC, original_y1WC, original_y2WC);
212 	Graphics_setLineType (me, original_lineType);
213 	Graphics_setColour (me, original_colour);
214 }
215 
Graphics_marksBottom(Graphics me,int numberOfMarks,bool haveNumbers,bool haveTicks,bool haveDottedLines)216 void Graphics_marksBottom (Graphics me, int numberOfMarks, bool haveNumbers, bool haveTicks, bool haveDottedLines) {
217 	const double original_x1WC = my d_x1WC, original_x2WC = my d_x2WC, original_y1WC = my d_y1WC, original_y2WC = my d_y2WC;
218 	int original_lineType = my lineType;
219 	const double original_lineWidth = my lineWidth;
220 	const MelderColour original_colour = my colour;
221 	if (numberOfMarks < 2)
222 		return;
223 
224 	Graphics_setWindow (me, original_x1WC, original_x2WC, 0.0, 1.0);
225 	Graphics_setColour (me, Melder_BLACK);
226 	Graphics_setTextAlignment (me, Graphics_CENTRE, Graphics_TOP);
227 	Graphics_setInner (me);
228 	if (haveTicks) {
229 		Graphics_setLineType (me, Graphics_DRAWN);
230 		Graphics_setLineWidth (me, 2.0 * original_lineWidth);
231 	}
232 	for (int i = 1; i <= numberOfMarks; i ++) {
233 		const double f = (i - 1.0) / (numberOfMarks - 1);
234 		const double xWC = original_x1WC + (original_x2WC - original_x1WC) * f;
235 		if (haveNumbers)
236 			Graphics_text (me, xWC, - my vertTick, Melder_float (Melder_half (xWC)));
237 		if (haveTicks)
238 			Graphics_line (me, xWC, - my vertTick, xWC, 0);
239 	}
240 	if (haveTicks)
241 		Graphics_setLineWidth (me, original_lineWidth);
242 	if (haveDottedLines && numberOfMarks > 2) {
243 		Graphics_setLineType (me, Graphics_DOTTED);
244 		Graphics_setLineWidth (me, 0.67 * original_lineWidth);
245 		for (int i = 2; i < numberOfMarks; i ++) {
246 			const double f = (i - 1.0) / (numberOfMarks - 1);
247 			const double xWC = original_x1WC + (original_x2WC - original_x1WC) * f;
248 			Graphics_line (me, xWC, 0.0, xWC, 1.0);
249 		}
250 		Graphics_setLineWidth (me, original_lineWidth);
251 	}
252 	Graphics_unsetInner (me);
253 
254 	Graphics_setWindow (me, original_x1WC, original_x2WC, original_y1WC, original_y2WC);
255 	Graphics_setLineType (me, original_lineType);
256 	Graphics_setColour (me, original_colour);
257 }
258 
Graphics_marksTop(Graphics me,int numberOfMarks,bool haveNumbers,bool haveTicks,bool haveDottedLines)259 void Graphics_marksTop (Graphics me, int numberOfMarks, bool haveNumbers, bool haveTicks, bool haveDottedLines) {
260 	const double original_x1WC = my d_x1WC, original_x2WC = my d_x2WC, original_y1WC = my d_y1WC, original_y2WC = my d_y2WC;
261 	const int original_lineType = my lineType;
262 	const double original_lineWidth = my lineWidth;
263 	const MelderColour original_colour = my colour;
264 	if (numberOfMarks < 2)
265 		return;
266 
267 	Graphics_setWindow (me, original_x1WC, original_x2WC, 0.0, 1.0);
268 	Graphics_setColour (me, Melder_BLACK);
269 	Graphics_setTextAlignment (me, Graphics_CENTRE, Graphics_BOTTOM);
270 	Graphics_setInner (me);
271 	if (haveTicks) {
272 		Graphics_setLineType (me, Graphics_DRAWN);
273 		Graphics_setLineWidth (me, 2.0 * original_lineWidth);
274 	}
275 	for (int i = 1; i <= numberOfMarks; i ++) {
276 		const double f = (i - 1.0) / (numberOfMarks - 1);
277 		const double xWC = original_x1WC + (original_x2WC - original_x1WC) * f;
278 		if (haveNumbers)
279 			Graphics_text (me, xWC, 1.0 + my vertTick, Melder_float (Melder_half (xWC)));
280 		if (haveTicks)
281 			Graphics_line (me, xWC, 1.0, xWC, 1.0 + my vertTick);
282 	}
283 	if (haveTicks)
284 		Graphics_setLineWidth (me, original_lineWidth);
285 	if (haveDottedLines && numberOfMarks > 2) {
286 		Graphics_setLineType (me, Graphics_DOTTED);
287 		Graphics_setLineWidth (me, 0.67 * original_lineWidth);
288 		for (int i = 2; i < numberOfMarks; i ++) {
289 			const double f = (i - 1.0) / (numberOfMarks - 1);
290 			const double xWC = original_x1WC + (original_x2WC - original_x1WC) * f;
291 			Graphics_line (me, xWC, 0.0, xWC, 1.0);
292 		}
293 		Graphics_setLineWidth (me, original_lineWidth);
294 	}
295 	Graphics_unsetInner (me);
296 
297 	Graphics_setWindow (me, original_x1WC, original_x2WC, original_y1WC, original_y2WC);
298 	Graphics_setLineType (me, original_lineType);
299 	Graphics_setColour (me, original_colour);
300 }
301 
302 #define MAXNUM_MARKS_PER_DECADE  7
303 static double decade_y [1 + MAXNUM_MARKS_PER_DECADE] [1 + MAXNUM_MARKS_PER_DECADE] = {
304 	{ 0 },
305 	{ 0, 10 },
306 	{ 0, 10, 30 },
307 	{ 0, 10, 20, 50 },
308 	{ 0, 10, 20, 30, 50 },
309 	{ 0, 10, 20, 30, 50, 70 },
310 	{ 0, 10, 15, 20, 30, 50, 70 },
311 	{ 0, 10, 15, 20, 30, 40, 50, 70 }
312 };
313 
Graphics_marksLeftLogarithmic(Graphics me,int numberOfMarksPerDecade,bool haveNumbers,bool haveTicks,bool haveDottedLines)314 void Graphics_marksLeftLogarithmic (Graphics me, int numberOfMarksPerDecade, bool haveNumbers, bool haveTicks, bool haveDottedLines) {
315 	const double x1 = my d_x1WC, x2 = my d_x2WC, y1 = my d_y1WC, y2 = my d_y2WC;
316 	const int lineType = my lineType;
317 	const double lineWidth = my lineWidth;
318 	const MelderColour colour = my colour;
319 	Melder_clip (1, & numberOfMarksPerDecade, MAXNUM_MARKS_PER_DECADE);
320 	if (y1 > 300.0 || y2 > 300.0)
321 		return;
322 
323 	const double py1 = pow (10.0, y1 + ( y1 < y2 ? -1e-6 : 1e-6 ));
324 	const double py2 = pow (10.0, y2 + ( y1 < y2 ? 1e-6 : -1e-6 ));
325 	Graphics_setWindow (me, 0, 1, y1, y2);
326 	Graphics_setColour (me, Melder_BLACK);
327 	Graphics_setTextAlignment (me, Graphics_RIGHT, Graphics_HALF);
328 	Graphics_setInner (me);
329 	for (int i = 1; i <= numberOfMarksPerDecade; i ++) {
330 		double y = decade_y [numberOfMarksPerDecade] [i];
331 		while (y < (y1<y2?py1:py2))
332 			y *= 10.0;
333 		while (y >= (y1<y2?py1:py2))
334 			y /= 10.0;
335 		for (y *= 10.0; y <= (y1<y2?py2:py1); y *= 10.0) {
336 			if (haveNumbers)
337 				Graphics_text (me, - my horTick, log10 (y), Melder_float (Melder_half (y)));
338 			if (haveTicks) {
339 				Graphics_setLineWidth (me, 2.0 * lineWidth);
340 				Graphics_setLineType (me, Graphics_DRAWN);
341 				Graphics_line (me, - my horTick, log10 (y), 0, log10 (y));
342 				Graphics_setLineWidth (me, lineWidth);
343 			}
344 			if (haveDottedLines) {
345 				Graphics_setLineType (me, Graphics_DOTTED);
346 				Graphics_setLineWidth (me, 0.67 * lineWidth);
347 				Graphics_line (me, 0.0, log10 (y), 1.0, log10 (y));
348 				Graphics_setLineType (me, lineType);
349 				Graphics_setLineWidth (me, lineWidth);
350 			}
351 		}
352 	}
353 	Graphics_unsetInner (me);
354 
355 	Graphics_setWindow (me, x1, x2, y1, y2);
356 	Graphics_setColour (me, colour);
357 }
358 
Graphics_marksRightLogarithmic(Graphics me,int numberOfMarksPerDecade,bool haveNumbers,bool haveTicks,bool haveDottedLines)359 void Graphics_marksRightLogarithmic (Graphics me, int numberOfMarksPerDecade, bool haveNumbers, bool haveTicks, bool haveDottedLines) {
360 	const double x1 = my d_x1WC, x2 = my d_x2WC, y1 = my d_y1WC, y2 = my d_y2WC;
361 	const int lineType = my lineType;
362 	const double lineWidth = my lineWidth;
363 	const MelderColour colour = my colour;
364 	Melder_clip (1, & numberOfMarksPerDecade, MAXNUM_MARKS_PER_DECADE);
365 	if (y1 > 300.0 || y2 > 300.0)
366 		return;
367 
368 	const double py1 = pow (10.0, y1 + ( y1 < y2 ? -1e-6 : 1e-6 ));
369 	const double py2 = pow (10.0, y2 + ( y1 < y2 ? 1e-6 : -1e-6 ));
370 	Graphics_setWindow (me, 0.0, 1.0, y1, y2);
371 	Graphics_setColour (me, Melder_BLACK);
372 	Graphics_setTextAlignment (me, Graphics_LEFT, Graphics_HALF);
373 	Graphics_setInner (me);
374 	for (int i = 1; i <= numberOfMarksPerDecade; i ++) {
375 		double y = decade_y [numberOfMarksPerDecade] [i];
376 		while (y < (y1<y2?py1:py2))
377 			y *= 10.0;
378 		while (y >= (y1<y2?py1:py2))
379 			y /= 10.0;
380 		for (y *= 10.0; y <= (y1<y2?py2:py1); y *= 10.0) {
381 			if (haveNumbers)
382 				Graphics_text (me, 1.0 + my horTick, log10 (y), Melder_float (Melder_half (y)));
383 			if (haveTicks) {
384 				Graphics_setLineWidth (me, 2.0 * lineWidth);
385 				Graphics_setLineType (me, Graphics_DRAWN);
386 				Graphics_line (me, 1.0, log10 (y), 1.0 + my horTick, log10 (y));
387 				Graphics_setLineWidth (me, lineWidth);
388 			}
389 			if (haveDottedLines) {
390 				Graphics_setLineType (me, Graphics_DOTTED);
391 				Graphics_setLineWidth (me, 0.67 * lineWidth);
392 				Graphics_line (me, 0.0, log10 (y), 1.0, log10 (y));
393 				Graphics_setLineType (me, lineType);
394 				Graphics_setLineWidth (me, lineWidth);
395 			}
396 		}
397 	}
398 	Graphics_unsetInner (me);
399 
400 	Graphics_setWindow (me, x1, x2, y1, y2);
401 	Graphics_setColour (me, colour);
402 }
403 
Graphics_marksTopLogarithmic(Graphics me,int numberOfMarksPerDecade,bool haveNumbers,bool haveTicks,bool haveDottedLines)404 void Graphics_marksTopLogarithmic (Graphics me, int numberOfMarksPerDecade, bool haveNumbers, bool haveTicks, bool haveDottedLines) {
405 	const double x1 = my d_x1WC, x2 = my d_x2WC, y1 = my d_y1WC, y2 = my d_y2WC;
406 	const int lineType = my lineType;
407 	const double lineWidth = my lineWidth;
408 	const MelderColour colour = my colour;
409 	Melder_clip (1, & numberOfMarksPerDecade, MAXNUM_MARKS_PER_DECADE);
410 	if (x1 > 300.0 || x2 > 300.0)
411 		return;
412 
413 	const double px1 = pow (10.0, x1 + ( x1 < x2 ? -1e-6 : 1e-6 ));
414 	const double px2 = pow (10.0, x2 + ( x1 < x2 ? 1e-6 : -1e-6 ));
415 	Graphics_setWindow (me, x1, x2, 0.0, 1.0);
416 	Graphics_setColour (me, Melder_BLACK);
417 	Graphics_setTextAlignment (me, Graphics_CENTRE, Graphics_BOTTOM);
418 	Graphics_setInner (me);
419 	for (int i = 1; i <= numberOfMarksPerDecade; i ++) {
420 		double x = decade_y [numberOfMarksPerDecade] [i];
421 		while (x < (x1<x2?px1:px2))
422 			x *= 10.0;
423 		while (x >= (x1<x2?px1:px2))
424 			x /= 10.0;
425 		for (x *= 10.0; x <= (x1<x2?px2:px1); x *= 10.0) {
426 			if (haveNumbers)
427 				Graphics_text (me, log10 (x), 1.0 + my vertTick, Melder_float (Melder_half (x)));
428 			if (haveTicks) {
429 				Graphics_setLineWidth (me, 2.0 * lineWidth);
430 				Graphics_setLineType (me, Graphics_DRAWN);
431 				Graphics_line (me, log10 (x), 1.0, log10 (x), 1.0 + my vertTick);
432 				Graphics_setLineWidth (me, lineWidth);
433 			}
434 			if (haveDottedLines) {
435 				Graphics_setLineType (me, Graphics_DOTTED);
436 				Graphics_setLineWidth (me, 0.67 * lineWidth);
437 				Graphics_line (me, log10 (x), 0.0, log10 (x), 1.0);
438 				Graphics_setLineType (me, lineType);
439 				Graphics_setLineWidth (me, lineWidth);
440 			}
441 		}
442 	}
443 	Graphics_unsetInner (me);
444 
445 	Graphics_setWindow (me, x1, x2, y1, y2);
446 	Graphics_setColour (me, colour);
447 }
448 
Graphics_marksBottomLogarithmic(Graphics me,int numberOfMarksPerDecade,bool haveNumbers,bool haveTicks,bool haveDottedLines)449 void Graphics_marksBottomLogarithmic (Graphics me, int numberOfMarksPerDecade, bool haveNumbers, bool haveTicks, bool haveDottedLines) {
450 	const double x1 = my d_x1WC, x2 = my d_x2WC, y1 = my d_y1WC, y2 = my d_y2WC;
451 	const int lineType = my lineType;
452 	const double lineWidth = my lineWidth;
453 	const MelderColour colour = my colour;
454 	Melder_clip (1, & numberOfMarksPerDecade, MAXNUM_MARKS_PER_DECADE);
455 	if (x1 > 300.0 || x2 > 300.0)
456 		return;
457 
458 	const double px1 = pow (10.0, x1 + ( x1 < x2 ? -1e-6 : 1e-6 ));
459 	const double px2 = pow (10.0, x2 + ( x1 < x2 ? 1e-6 : -1e-6 ));
460 	Graphics_setWindow (me, x1, x2, 0, 1);
461 	Graphics_setColour (me, Melder_BLACK);
462 	Graphics_setTextAlignment (me, Graphics_CENTRE, Graphics_TOP);
463 	Graphics_setInner (me);
464 	for (int i = 1; i <= numberOfMarksPerDecade; i ++) {
465 		double x = decade_y [numberOfMarksPerDecade] [i];
466 		while (x < (x1<x2?px1:px2))
467 			x *= 10.0;
468 		while (x >= (x1<x2?px1:px2))
469 			x /= 10.0;
470 		for (x *= 10.0; x <= (x1<x2?px2:px1); x *= 10.0) {
471 			if (haveNumbers)
472 				Graphics_text (me, log10 (x), - my vertTick, Melder_float (Melder_half (x)));
473 			if (haveTicks) {
474 				Graphics_setLineWidth (me, 2.0 * lineWidth);
475 				Graphics_setLineType (me, Graphics_DRAWN);
476 				Graphics_line (me, log10 (x), - my vertTick, log10 (x), 0.0);
477 				Graphics_setLineWidth (me, lineWidth);
478 			}
479 			if (haveDottedLines) {
480 				Graphics_setLineType (me, Graphics_DOTTED);
481 				Graphics_setLineWidth (me, 0.67 * lineWidth);
482 				Graphics_line (me, log10 (x), 0.0, log10 (x), 1.0);
483 				Graphics_setLineType (me, lineType);
484 				Graphics_setLineWidth (me, lineWidth);
485 			}
486 		}
487 	}
488 	Graphics_unsetInner (me);
489 
490 	Graphics_setWindow (me, x1, x2, y1, y2);
491 	Graphics_setColour (me, colour);
492 }
493 
Graphics_markLeft(Graphics me,double position,bool hasNumber,bool hasTick,bool hasDottedLine,conststring32 text)494 void Graphics_markLeft (Graphics me, double position, bool hasNumber, bool hasTick, bool hasDottedLine, conststring32 text /* cattable */) {
495 	const double x1WC = my d_x1WC, x2WC = my d_x2WC, y1WC = my d_y1WC, y2WC = my d_y2WC;
496 	const int lineType = my lineType;
497 	const double lineWidth = my lineWidth;
498 	const MelderColour colour = my colour;
499 
500 	Graphics_setWindow (me, 0.0, 1.0, y1WC, y2WC);
501 	Graphics_setColour (me, Melder_BLACK);
502 	Graphics_setTextAlignment (me, Graphics_RIGHT, Graphics_HALF);
503 	Graphics_setInner (me);
504 	if (hasNumber)
505 		Graphics_text (me, - my horTick, position, Melder_float (Melder_half (position)));
506 	if (hasTick) {
507 		Graphics_setLineType (me, Graphics_DRAWN);
508 		Graphics_setLineWidth (me, 2.0 * lineWidth);
509 		Graphics_line (me, - my horTick, position, 0.0, position);
510 		Graphics_setLineWidth (me, lineWidth);
511 	}
512 	if (hasDottedLine) {
513 		Graphics_setLineType (me, Graphics_DOTTED);
514 		Graphics_setLineWidth (me, 0.67 * lineWidth);
515 		Graphics_line (me, 0.0, position, 1.0, position);
516 		Graphics_setLineWidth (me, lineWidth);
517 	}
518 	if (text && text [0])
519 		Graphics_text (me, - my horTick, position, text);   // 'text' has to stay valid until here; no Graphics is allowed to use the cat buffer!
520 	Graphics_unsetInner (me);
521 
522 	Graphics_setWindow (me, x1WC, x2WC, y1WC, y2WC);
523 	Graphics_setLineType (me, lineType);
524 	Graphics_setColour (me, colour);
525 }
526 
Graphics_markRight(Graphics me,double position,bool hasNumber,bool hasTick,bool hasDottedLine,conststring32 text)527 void Graphics_markRight (Graphics me, double position, bool hasNumber, bool hasTick, bool hasDottedLine, conststring32 text /* cattable */) {
528 	const double x1WC = my d_x1WC, x2WC = my d_x2WC, y1WC = my d_y1WC, y2WC = my d_y2WC;
529 	const int lineType = my lineType;
530 	const double lineWidth = my lineWidth;
531 	const MelderColour colour = my colour;
532 
533 	Graphics_setWindow (me, 0.0, 1.0, y1WC, y2WC);
534 	Graphics_setColour (me, Melder_BLACK);
535 	Graphics_setTextAlignment (me, Graphics_LEFT, Graphics_HALF);
536 	Graphics_setInner (me);
537 	if (hasNumber)
538 		Graphics_text (me, 1.0 + my horTick, position, Melder_float (Melder_half (position)));
539 	if (hasTick) {
540 		Graphics_setLineType (me, Graphics_DRAWN);
541 		Graphics_setLineWidth (me, 2.0 * lineWidth);
542 		Graphics_line (me, 1.0, position, 1.0 + my horTick, position);
543 		Graphics_setLineWidth (me, lineWidth);
544 	}
545 	if (hasDottedLine) {
546 		Graphics_setLineType (me, Graphics_DOTTED);
547 		Graphics_setLineWidth (me, 0.67 * lineWidth);
548 		Graphics_line (me, 0.0, position, 1.0, position);
549 		Graphics_setLineWidth (me, lineWidth);
550 	}
551 	if (text && text [0])
552 		Graphics_text (me, 1.0 + my horTick, position, text);
553 	Graphics_unsetInner (me);
554 
555 	Graphics_setWindow (me, x1WC, x2WC, y1WC, y2WC);
556 	Graphics_setLineType (me, lineType);
557 	Graphics_setColour (me, colour);
558 }
559 
Graphics_markTop(Graphics me,double position,bool hasNumber,bool hasTick,bool hasDottedLine,conststring32 text)560 void Graphics_markTop (Graphics me, double position, bool hasNumber, bool hasTick, bool hasDottedLine, conststring32 text /* cattable */) {
561 	const double x1WC = my d_x1WC, x2WC = my d_x2WC, y1WC = my d_y1WC, y2WC = my d_y2WC;
562 	const int lineType = my lineType;
563 	const double lineWidth = my lineWidth;
564 	const MelderColour colour = my colour;
565 
566 	Graphics_setWindow (me, x1WC, x2WC, 0.0, 1.0);
567 	Graphics_setColour (me, Melder_BLACK);
568 	Graphics_setTextAlignment (me, Graphics_CENTRE, Graphics_BOTTOM);
569 	Graphics_setInner (me);
570 	if (hasNumber)
571 		Graphics_text (me, position, 1.0 + my vertTick, Melder_float (Melder_single (position)));
572 	if (hasTick) {
573 		Graphics_setLineType (me, Graphics_DRAWN);
574 		Graphics_setLineWidth (me, 2.0 * lineWidth);
575 		Graphics_line (me, position, 1.0, position, 1.0 + my vertTick);
576 		Graphics_setLineWidth (me, lineWidth);
577 	}
578 	if (hasDottedLine) {
579 		Graphics_setLineType (me, Graphics_DOTTED);
580 		Graphics_setLineWidth (me, 0.67 * lineWidth);
581 		Graphics_line (me, position, 0.0, position, 1.0);
582 		Graphics_setLineWidth (me, lineWidth);
583 	}
584 	if (text && text [0])
585 		Graphics_text (me, position, 1.0 + my vertTick, text);
586 	Graphics_unsetInner (me);
587 
588 	Graphics_setWindow (me, x1WC, x2WC, y1WC, y2WC);
589 	Graphics_setLineType (me, lineType);
590 	Graphics_setColour (me, colour);
591 }
592 
Graphics_markBottom(Graphics me,double position,bool hasNumber,bool hasTick,bool hasDottedLine,conststring32 text)593 void Graphics_markBottom (Graphics me, double position, bool hasNumber, bool hasTick, bool hasDottedLine, conststring32 text /* cattable */) {
594 	const double x1WC = my d_x1WC, x2WC = my d_x2WC, y1WC = my d_y1WC, y2WC = my d_y2WC;
595 	const int lineType = my lineType;
596 	const double lineWidth = my lineWidth;
597 	const MelderColour colour = my colour;
598 
599 	Graphics_setWindow (me, x1WC, x2WC, 0.0, 1.0);
600 	Graphics_setColour (me, Melder_BLACK);
601 	Graphics_setTextAlignment (me, Graphics_CENTRE, Graphics_TOP);
602 	Graphics_setInner (me);
603 	if (hasNumber)
604 		Graphics_text (me, position, - my vertTick, Melder_float (Melder_single (position)));
605 	if (hasTick) {
606 		Graphics_setLineType (me, Graphics_DRAWN);
607 		Graphics_setLineWidth (me, 2.0 * lineWidth);
608 		Graphics_line (me, position, - my vertTick, position, 0.0);
609 		Graphics_setLineWidth (me, lineWidth);
610 	}
611 	if (hasDottedLine) {
612 		Graphics_setLineType (me, Graphics_DOTTED);
613 		Graphics_setLineWidth (me, 0.67 * lineWidth);
614 		Graphics_line (me, position, 0.0, position, 1.0);
615 		Graphics_setLineWidth (me, lineWidth);
616 	}
617 	if (text && text [0])
618 		Graphics_text (me, position, - my vertTick, text);
619 	Graphics_unsetInner (me);
620 
621 	Graphics_setWindow (me, x1WC, x2WC, y1WC, y2WC);
622 	Graphics_setLineType (me, lineType);
623 	Graphics_setColour (me, colour);
624 }
625 
Graphics_markLeftLogarithmic(Graphics me,double position,bool hasNumber,bool hasTick,bool hasDottedLine,conststring32 text)626 void Graphics_markLeftLogarithmic (Graphics me, double position, bool hasNumber, bool hasTick, bool hasDottedLine, conststring32 text /* cattable */) {
627 	const double x1WC = my d_x1WC, x2WC = my d_x2WC, y1WC = my d_y1WC, y2WC = my d_y2WC;
628 	const int lineType = my lineType;
629 	const double lineWidth = my lineWidth;
630 	const MelderColour colour = my colour;
631 	if (position <= 0.0)
632 		return;
633 
634 	Graphics_setWindow (me, 0.0, 1.0, y1WC, y2WC);
635 	Graphics_setColour (me, Melder_BLACK);
636 	Graphics_setTextAlignment (me, Graphics_RIGHT, Graphics_HALF);
637 	Graphics_setInner (me);
638 	if (hasNumber)
639 		Graphics_text (me, - my horTick, log10 (position), Melder_float (Melder_half (position)));
640 	if (hasTick) {
641 		Graphics_setLineType (me, Graphics_DRAWN);
642 		Graphics_setLineWidth (me, 2.0 * lineWidth);
643 		Graphics_line (me, - my horTick, log10 (position), 0.0, log10 (position));
644 		Graphics_setLineWidth (me, lineWidth);
645 	}
646 	if (hasDottedLine) {
647 		Graphics_setLineType (me, Graphics_DOTTED);
648 		Graphics_setLineWidth (me, 0.67 * lineWidth);
649 		Graphics_line (me, 0.0, log10 (position), 1.0, log10 (position));
650 		Graphics_setLineWidth (me, lineWidth);
651 	}
652 	if (text && text [0])
653 		Graphics_text (me, - my horTick, log10 (position), text);
654 	Graphics_unsetInner (me);
655 
656 	Graphics_setWindow (me, x1WC, x2WC, y1WC, y2WC);
657 	Graphics_setLineType (me, lineType);
658 	Graphics_setColour (me, colour);
659 }
660 
Graphics_markRightLogarithmic(Graphics me,double position,bool hasNumber,bool hasTick,bool hasDottedLine,conststring32 text)661 void Graphics_markRightLogarithmic (Graphics me, double position, bool hasNumber, bool hasTick, bool hasDottedLine, conststring32 text /* cattable */) {
662 	const double x1WC = my d_x1WC, x2WC = my d_x2WC, y1WC = my d_y1WC, y2WC = my d_y2WC;
663 	const int lineType = my lineType;
664 	const double lineWidth = my lineWidth;
665 	const MelderColour colour = my colour;
666 	if (position <= 0.0)
667 		return;
668 
669 	Graphics_setWindow (me, 0.0, 1.0, y1WC, y2WC);
670 	Graphics_setColour (me, Melder_BLACK);
671 	Graphics_setTextAlignment (me, Graphics_LEFT, Graphics_HALF);
672 	Graphics_setInner (me);
673 	if (hasNumber)
674 		Graphics_text (me, 1.0 + my horTick, log10 (position), Melder_float (Melder_half (position)));
675 	if (hasTick) {
676 		Graphics_setLineType (me, Graphics_DRAWN);
677 		Graphics_setLineWidth (me, 2.0 * lineWidth);
678 		Graphics_line (me, 1.0, log10 (position), 1.0 + my horTick, log10 (position));
679 		Graphics_setLineWidth (me, lineWidth);
680 	}
681 	if (hasDottedLine) {
682 		Graphics_setLineType (me, Graphics_DOTTED);
683 		Graphics_setLineWidth (me, 0.67 * lineWidth);
684 		Graphics_line (me, 0.0, log10 (position), 1.0, log10 (position));
685 		Graphics_setLineWidth (me, lineWidth);
686 	}
687 	if (text && text [0])
688 		Graphics_text (me, 1.0 + my horTick, log10 (position), text);
689 	Graphics_unsetInner (me);
690 
691 	Graphics_setWindow (me, x1WC, x2WC, y1WC, y2WC);
692 	Graphics_setLineType (me, lineType);
693 	Graphics_setColour (me, colour);
694 }
695 
Graphics_markTopLogarithmic(Graphics me,double position,bool hasNumber,bool hasTick,bool hasDottedLine,conststring32 text)696 void Graphics_markTopLogarithmic (Graphics me, double position, bool hasNumber, bool hasTick, bool hasDottedLine, conststring32 text /* cattable */) {
697 	const double x1WC = my d_x1WC, x2WC = my d_x2WC, y1WC = my d_y1WC, y2WC = my d_y2WC;
698 	const int lineType = my lineType;
699 	const double lineWidth = my lineWidth;
700 	const MelderColour colour = my colour;
701 	if (position <= 0.0)
702 		return;
703 
704 	Graphics_setWindow (me, x1WC, x2WC, 0.0, 1.0);
705 	Graphics_setColour (me, Melder_BLACK);
706 	Graphics_setTextAlignment (me, Graphics_CENTRE, Graphics_BOTTOM);
707 	Graphics_setInner (me);
708 	if (hasNumber)
709 		Graphics_text (me, log10 (position), 1.0 + my vertTick, Melder_float (Melder_half (position)));
710 	if (hasTick) {
711 		Graphics_setLineType (me, Graphics_DRAWN);
712 		Graphics_setLineWidth (me, 2.0 * lineWidth);
713 		Graphics_line (me, log10 (position), 1.0, log10 (position), 1.0 + my vertTick);
714 		Graphics_setLineWidth (me, lineWidth);
715 	}
716 	if (hasDottedLine) {
717 		Graphics_setLineType (me, Graphics_DOTTED);
718 		Graphics_setLineWidth (me, 0.67 * lineWidth);
719 		Graphics_line (me, log10 (position), 0.0, log10 (position), 1.0);
720 		Graphics_setLineWidth (me, lineWidth);
721 	}
722 	if (text && text [0])
723 		Graphics_text (me, log10 (position), 1.0 + my vertTick, text);
724 	Graphics_unsetInner (me);
725 
726 	Graphics_setWindow (me, x1WC, x2WC, y1WC, y2WC);
727 	Graphics_setLineType (me, lineType);
728 	Graphics_setColour (me, colour);
729 }
730 
Graphics_markBottomLogarithmic(Graphics me,double position,bool hasNumber,bool hasTick,bool hasDottedLine,conststring32 text)731 void Graphics_markBottomLogarithmic (Graphics me, double position, bool hasNumber, bool hasTick, bool hasDottedLine, conststring32 text /* cattable */) {
732 	const double x1WC = my d_x1WC, x2WC = my d_x2WC, y1WC = my d_y1WC, y2WC = my d_y2WC;
733 	const int lineType = my lineType;
734 	const double lineWidth = my lineWidth;
735 	const MelderColour colour = my colour;
736 	if (position <= 0.0)
737 		return;
738 
739 	Graphics_setWindow (me, x1WC, x2WC, 0.0, 1.0);
740 	Graphics_setColour (me, Melder_BLACK);
741 	Graphics_setTextAlignment (me, Graphics_CENTRE, Graphics_TOP);
742 	Graphics_setInner (me);
743 	if (hasNumber)
744 		Graphics_text (me, log10 (position), - my vertTick, Melder_float (Melder_half (position)));
745 	if (hasTick) {
746 		Graphics_setLineType (me, Graphics_DRAWN);
747 		Graphics_setLineWidth (me, 2.0 * lineWidth);
748 		Graphics_line (me, log10 (position), - my vertTick, log10 (position), 0.0);
749 		Graphics_setLineWidth (me, lineWidth);
750 	}
751 	if (hasDottedLine) {
752 		Graphics_setLineType (me, Graphics_DOTTED);
753 		Graphics_setLineWidth (me, 0.67 * lineWidth);
754 		Graphics_line (me, log10 (position), 0.0, log10 (position), 1.0);
755 		Graphics_setLineWidth (me, lineWidth);
756 	}
757 	if (text && text [0])
758 		Graphics_text (me, log10 (position), - my vertTick, text);
759 	Graphics_unsetInner (me);
760 
761 	Graphics_setWindow (me, x1WC, x2WC, y1WC, y2WC);
762 	Graphics_setLineType (me, lineType);
763 	Graphics_setColour (me, colour);
764 }
765 
Graphics_marksLeftEvery(Graphics me,double units,double distance,bool haveNumbers,bool haveTicks,bool haveDottedLines)766 void Graphics_marksLeftEvery (Graphics me, double units, double distance, bool haveNumbers, bool haveTicks, bool haveDottedLines) {
767 	const double x1WC = my d_x1WC, x2WC = my d_x2WC, y1WC = my d_y1WC, y2WC = my d_y2WC;
768 	const int lineType = my lineType;
769 	const double lineWidth = my lineWidth;
770 	const MelderColour colour = my colour;
771 	distance *= units;
772 
773 	const integer first = Melder_iceiling (( y1WC < y2WC ? y1WC : y2WC ) / distance - 1e-5);
774 	const integer last  = Melder_ifloor   (( y1WC < y2WC ? y2WC : y1WC ) / distance + 1e-5);
775 	Graphics_setWindow (me, 0.0, 1.0, y1WC, y2WC);
776 	Graphics_setColour (me, Melder_BLACK);
777 	Graphics_setTextAlignment (me, Graphics_RIGHT, Graphics_HALF);
778 	Graphics_setInner (me);
779 	if (haveTicks) {
780 		Graphics_setLineType (me, Graphics_DRAWN);
781 		Graphics_setLineWidth (me, 2.0 * lineWidth);
782 	}
783 	for (integer i = first; i <= last; i ++) {
784 		const double yWC = i * distance;
785 		if (haveNumbers)
786 			Graphics_text (me, - my horTick, yWC, Melder_float (Melder_half (yWC / units)));
787 		if (haveTicks)
788 			Graphics_line (me, - my horTick, yWC, 0.0, yWC);
789 	}
790 	if (haveTicks)
791 		Graphics_setLineWidth (me, lineWidth);
792 	if (haveDottedLines) {
793 		Graphics_setLineType (me, Graphics_DOTTED);
794 		Graphics_setLineWidth (me, 0.67 * lineWidth);
795 		for (integer i = first; i <= last; i ++) {
796 			const double yWC = i * distance;
797 			Graphics_line (me, 0.0, yWC, 1.0, yWC);
798 		}
799 		Graphics_setLineWidth (me, lineWidth);
800 	}
801 	Graphics_unsetInner (me);
802 
803 	Graphics_setWindow (me, x1WC, x2WC, y1WC, y2WC);
804 	Graphics_setLineType (me, lineType);
805 	Graphics_setColour (me, colour);
806 }
807 
Graphics_marksRightEvery(Graphics me,double units,double distance,bool haveNumbers,bool haveTicks,bool haveDottedLines)808 void Graphics_marksRightEvery (Graphics me, double units, double distance, bool haveNumbers, bool haveTicks, bool haveDottedLines) {
809 	const double x1WC = my d_x1WC, x2WC = my d_x2WC, y1WC = my d_y1WC, y2WC = my d_y2WC;
810 	const int lineType = my lineType;
811 	const double lineWidth = my lineWidth;
812 	const MelderColour colour = my colour;
813 	distance *= units;
814 
815 	const integer first = Melder_iceiling (( y1WC < y2WC ? y1WC : y2WC ) / distance - 1e-5);
816 	const integer last  = Melder_ifloor   (( y1WC < y2WC ? y2WC : y1WC ) / distance + 1e-5);
817 	if (first > last)
818 		return;   // TODO: describe why this is. ppgb 2020-10-01
819 	Graphics_setWindow (me, 0.0, 1.0, y1WC, y2WC);
820 	Graphics_setColour (me, Melder_BLACK);
821 	Graphics_setTextAlignment (me, Graphics_LEFT, Graphics_HALF);
822 	Graphics_setInner (me);
823 	if (haveTicks) {
824 		Graphics_setLineType (me, Graphics_DRAWN);
825 		Graphics_setLineWidth (me, 2.0 * lineWidth);
826 	}
827 	for (integer i = first; i <= last; i ++) {
828 		const double yWC = i * distance;
829 		if (haveNumbers)
830 			Graphics_text (me, 1.0 + my horTick, yWC, Melder_float (Melder_half (yWC / units)));
831 		if (haveTicks)
832 			Graphics_line (me, 1.0, yWC, 1.0 + my horTick, yWC);
833 	}
834 	if (haveTicks)
835 		Graphics_setLineWidth (me, lineWidth);
836 	if (haveDottedLines) {
837 		Graphics_setLineType (me, Graphics_DOTTED);
838 		Graphics_setLineWidth (me, 0.67 * lineWidth);
839 		for (integer i = first; i <= last; i ++) {
840 			const double yWC = i * distance;
841 			Graphics_line (me, 0.0, yWC, 1.0, yWC);
842 		}
843 		Graphics_setLineWidth (me, lineWidth);
844 	}
845 	Graphics_unsetInner (me);
846 
847 	Graphics_setWindow (me, x1WC, x2WC, y1WC, y2WC);
848 	Graphics_setLineType (me, lineType);
849 	Graphics_setColour (me, colour);
850 }
851 
Graphics_marksBottomEvery(Graphics me,double units,double distance,bool haveNumbers,bool haveTicks,bool haveDottedLines)852 void Graphics_marksBottomEvery (Graphics me, double units, double distance, bool haveNumbers, bool haveTicks, bool haveDottedLines) {
853 	const double x1WC = my d_x1WC, x2WC = my d_x2WC, y1WC = my d_y1WC, y2WC = my d_y2WC;
854 	const int lineType = my lineType;
855 	const double lineWidth = my lineWidth;
856 	const MelderColour colour = my colour;
857 	distance *= units;
858 
859 	const integer first = Melder_iceiling (( x1WC < x2WC ? x1WC : x2WC ) / distance - 1e-5);
860 	const integer last  = Melder_ifloor   (( x1WC < x2WC ? x2WC : x1WC ) / distance + 1e-5);
861 	Graphics_setWindow (me, x1WC, x2WC, 0.0, 1.0);
862 	Graphics_setColour (me, Melder_BLACK);
863 	Graphics_setTextAlignment (me, Graphics_CENTRE, Graphics_TOP);
864 	Graphics_setInner (me);
865 	if (haveTicks) {
866 		Graphics_setLineType (me, Graphics_DRAWN);
867 		Graphics_setLineWidth (me, 2.0 * lineWidth);
868 	}
869 	for (integer i = first; i <= last; i ++) {
870 		const double xWC = i * distance;
871 		if (haveNumbers)
872 			Graphics_text (me, xWC, - my vertTick, Melder_float (Melder_half (xWC / units)));
873 		if (haveTicks)
874 			Graphics_line (me, xWC, - my vertTick, xWC, 0.0);
875 	}
876 	if (haveTicks)
877 		Graphics_setLineWidth (me, lineWidth);
878 	if (haveDottedLines) {
879 		Graphics_setLineType (me, Graphics_DOTTED);
880 		Graphics_setLineWidth (me, 0.67 * lineWidth);
881 		for (integer i = first; i <= last; i ++) {
882 			const double xWC = i * distance;
883 			Graphics_line (me, xWC, 0.0, xWC, 1.0);
884 		}
885 		Graphics_setLineWidth (me, lineWidth);
886 	}
887 	Graphics_unsetInner (me);
888 
889 	Graphics_setWindow (me, x1WC, x2WC, y1WC, y2WC);
890 	Graphics_setLineType (me, lineType);
891 	Graphics_setColour (me, colour);
892 }
893 
Graphics_marksTopEvery(Graphics me,double units,double distance,bool haveNumbers,bool haveTicks,bool haveDottedLines)894 void Graphics_marksTopEvery (Graphics me, double units, double distance, bool haveNumbers, bool haveTicks, bool haveDottedLines) {
895 	const double x1WC = my d_x1WC, x2WC = my d_x2WC, y1WC = my d_y1WC, y2WC = my d_y2WC;
896 	const int lineType = my lineType;
897 	const double lineWidth = my lineWidth;
898 	const MelderColour colour = my colour;
899 	distance *= units;
900 
901 	const integer first = Melder_iceiling (( x1WC < x2WC ? x1WC : x2WC ) / distance - 1e-5);
902 	const integer last  = Melder_ifloor   (( x1WC < x2WC ? x2WC : x1WC ) / distance + 1e-5);
903 	Graphics_setWindow (me, x1WC, x2WC, 0.0, 1.0);
904 	Graphics_setColour (me, Melder_BLACK);
905 	Graphics_setTextAlignment (me, Graphics_CENTRE, Graphics_BOTTOM);
906 	Graphics_setInner (me);
907 	if (haveTicks) {
908 		Graphics_setLineType (me, Graphics_DRAWN);
909 		Graphics_setLineWidth (me, 2.0 * lineWidth);
910 	}
911 	for (integer i = first; i <= last; i ++) {
912 		const double xWC = i * distance;
913 		if (haveNumbers)
914 			Graphics_text (me, xWC, 1.0 + my vertTick, Melder_float (Melder_half (xWC / units)));
915 		if (haveTicks)
916 			Graphics_line (me, xWC, 1.0, xWC, 1.0 + my vertTick);
917 	}
918 	if (haveTicks)
919 		Graphics_setLineWidth (me, lineWidth);
920 	if (haveDottedLines) {
921 		Graphics_setLineType (me, Graphics_DOTTED);
922 		Graphics_setLineWidth (me, 0.67 * lineWidth);
923 		for (integer i = first; i <= last; i ++) {
924 			const double xWC = i * distance;
925 			Graphics_line (me, xWC, 0.0, xWC, 1.0);
926 		}
927 		Graphics_setLineWidth (me, lineWidth);
928 	}
929 	Graphics_unsetInner (me);
930 
931 	Graphics_setWindow (me, x1WC, x2WC, y1WC, y2WC);
932 	Graphics_setLineType (me, lineType);
933 	Graphics_setColour (me, colour);
934 }
935 
Graphics_mark(Graphics me,double x,double y,double size_mm,conststring32 markString)936 void Graphics_mark (Graphics me, double x, double y, double size_mm, conststring32 markString /* cattable */) {
937 	int mark;
938 	if (! markString || ! markString [0])
939 		mark = 0;
940 	else if (! markString [1]) {
941 		if (markString [0] == '+')
942 			mark = 1;
943 		else if (markString [0] == 'x')
944 			mark = 2;
945 		else if (markString [0] == 'o')
946 			mark = 3;
947 		else if (markString [0] == '.')
948 			mark = 0;
949 		else
950 			mark = -1;
951 	} else
952 		mark = -1;
953 	if (mark == -1) {
954 		const double oldSize = my fontSize;
955 		const int oldHorizontalAlignment = my horizontalTextAlignment;
956 		const int oldVerticalAlignment = my verticalTextAlignment;
957 		Graphics_setFontSize (me, size_mm * 72.0 / 25.4);
958 		Graphics_setTextAlignment (me, Graphics_CENTRE, Graphics_HALF);
959 		Graphics_text (me, x, y, markString);
960 		Graphics_setFontSize (me, oldSize);
961 		Graphics_setTextAlignment (me, (kGraphics_horizontalAlignment) oldHorizontalAlignment, oldVerticalAlignment);
962 	} else if (mark == 0) {
963 		Graphics_fillCircle_mm (me, x, y, size_mm);
964 	} else if (mark == 1) {
965 		const double dx = 0.5 * Graphics_dxMMtoWC (me, size_mm);
966 		const double dy = 0.5 * Graphics_dyMMtoWC (me, size_mm);
967 		Graphics_line (me, x - dx, y, x + dx, y);
968 		Graphics_line (me, x, y - dy, x, y + dy);
969 	} else if (mark == 2) {
970 		const double dx = 0.4 * Graphics_dxMMtoWC (me, size_mm);
971 		const double dy = 0.4 * Graphics_dyMMtoWC (me, size_mm);
972 		Graphics_line (me, x - dx, y - dy, x + dx, y + dy);
973 		Graphics_line (me, x + dx, y - dy, x - dx, y + dy);
974 	} else {
975 		Graphics_circle_mm (me, x, y, size_mm);
976 	}
977 }
978 
Graphics_setTextRotation_vector(Graphics me,double dx,double dy)979 void Graphics_setTextRotation_vector (Graphics me, double dx, double dy) {
980 	double angle;
981 	if (dy == 0.0) {
982 		angle = ( dx >= 0.0 ? 0.0 : 180.0 );
983 	} else if (dx == 0.0) {
984 		angle = ( dy > 0.0 ? 90.0 : 270.0 );
985 	} else {
986 		const double dxDC = dx * my scaleX;
987 		const double dyDC = ( my yIsZeroAtTheTop ? -dy * my scaleY : dy * my scaleY );
988 		angle = atan2 (dyDC, dxDC) * (180.0 / NUMpi);
989 	}
990 	Graphics_setTextRotation (me, angle);
991 }
992 
993 /* End of file Graphics_utils.cpp */
994