1 /* @source cirdna application
2 **
3 ** Draws circular maps of DNA constructs
4 ** @author Copyright (C) Nicolas Tourasse (tourasse@biotek.uio.no),
5 ** Biotechnology Centre of Oslo, Norway.
6 ** @@
7 **
8 ** This program is free software; you can redistribute it and/or
9 ** modify it under the terms of the GNU General Public License
10 ** as published by the Free Software Foundation; either version 2
11 ** of the License, or (at your option) any later version.
12 **
13 ** This program is distributed in the hope that it will be useful,
14 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 ** GNU General Public License for more details.
17 **
18 ** You should have received a copy of the GNU General Public License
19 ** along with this program; if not, write to the Free Software
20 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21 ******************************************************************************/
22 
23 #include "emboss.h"
24 #include <math.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdlib.h>
28 
29 
30 
31 
32 static AjBool cirdna_ReadInput(AjPFile infile,
33                                float *Start, float *End);
34 static AjPStr cirdna_ReadGroup(AjPFile infile, ajint maxlabels,
35 			       float* From, float *To,
36 			       AjPStr *Name2, char *FromSymbol,
37 			       char *ToSymbol, AjPStr *Style2,
38 			       ajint *NumLabels, ajint *NumNames,
39 			       ajint *Colour);
40 static float cirdna_TextGroup(float TextHeight, float TextLength,
41 			      AjPStr const *Name2, ajint NumLabels,
42 			      const ajint *NumNames,
43 			      AjPStr const *Style2,
44 			      const float* From,
45 			      const float* To,
46 			      const AjPStr PosTicks);
47 static float cirdna_TextGroupStr(AjPStr const *Name2, ajint NumLabels,
48 				 const ajint *NumNames,
49 				 float TextCoef, AjPStr const *Style2,
50 				 const float* From,
51 				 const float* To,
52 				 const AjPStr PosTicks);
53 static float cirdna_HeightGroup(float postext,
54 				float TickHeight, float BlockHeight,
55 				float RangeHeight,
56 				AjPStr const *Style2, ajint NumLabels,
57 				const AjPStr PosTicks,
58 				const AjPStr PosBlocks, ajint Adjust);
59 static ajint cirdna_OverlapTextGroup(AjPStr const *Name2,
60 				     AjPStr const *Style2,
61 				     ajint NumLabels,
62 				     const float* From, const float* To,
63 				     float Start, float End,
64 				     const AjPStr PosTicks, ajint *Adjust);
65 static AjBool cirdna_OverlapTickRuler(ajint NumGroups, const ajint *NumLabels,
66 				     float* const * From,
67 				      const AjPStr PosTicks,
68 				      ajint RulerTick);
69 static void cirdna_DrawGroup(float xDraw, float yDraw, float posblock,
70 			     float posrange, float postext, float TickHeight,
71 			     float BlockHeight, float RangeHeight,
72 			     float RealLength, float Radius, float RadiusMax,
73 			     const float* From, const float* To,
74 			     AjPStr const *Name2,
75 			     const char *FromSymbol, const char *ToSymbol,
76 			     AjPStr const *Style2, AjBool InterSymbol,
77 			     AjBool InterTicks, ajint NumLabels,
78 			     float OriginAngle,
79 			     const ajint *NumNames, const AjPStr PosTicks,
80 			     const AjPStr PosBlocks, const ajint *Adjust,
81 			     ajint InterColour, const ajint *Colour,
82 			     const AjPStr BlockType);
83 static float cirdna_TextRuler(float Start, float End, ajint GapSize,
84 			      float TextLength, float TextHeight,
85 			      const AjPStr PosTicks, ajint NumGroups,
86 			      const ajint *NumLabels);
87 static float cirdna_TextRulerStr(float Start, float End, ajint GapSize,
88 				 float TextCoef, const AjPStr PosTicks,
89 				 ajint NumGroups, const ajint *NumLabels);
90 static float cirdna_HeightRuler(float Start, float End, ajint GapSize,
91 				float postext, float TickHeight,
92 				const AjPStr PosTicks, ajint NumGroups,
93 				const ajint *NumLabels);
94 static void cirdna_DrawRuler(float xDraw, float yDraw, float Start, float End,
95 			     float RealLength, float Radius, float TickHeight,
96 			     float OriginAngle, ajint GapSize,
97 			     AjBool TickLines, float postext,
98 			     ajint NumGroups, const ajint *NumLabels,
99 			     float* const * From,
100 			     const AjPStr PosTicks, ajint Colour);
101 static void cirdna_DrawTicks(float xDraw, float yDraw, float RealLength,
102 			     float Radius, float TickHeight, float From,
103 			     const AjPStr Name2, float OriginAngle,
104 			     float postext,
105 			     const AjPStr PosTicks,
106 			     ajint NumNames, ajint Adjust,
107 			     ajint Colour);
108 static void cirdna_DrawBlocks(float xDraw, float yDraw, float RealLength,
109 			      float Radius, ajint BlockHeight, float From,
110 			      float To, const AjPStr Name2,
111 			      float postext, float OriginAngle,
112 			      const AjPStr PosBlocks, ajint NumNames,
113 			      ajint Adjust,
114 			      ajint Colour, const AjPStr BlockType);
115 static void cirdna_DrawRanges(float xDraw, float yDraw, float RealLength,
116 			      float Radius, float RangeHeight, float From,
117 			      float To, char FromSymbol,
118 			      char ToSymbol, const AjPStr Name2,
119 			      float OriginAngle,
120 			      ajint NumNames, float postext, ajint Adjust,
121 			      ajint Colour);
122 static void cirdna_InterBlocks(float xDraw, float yDraw, float RealLength,
123 			       float Radius, float BlockHeight, float From,
124 			       float To, float OriginAngle,
125 			       AjBool InterSymbol, ajint Colour);
126 static void cirdna_DrawArrowHeadsOncurve(float xDraw, float yDraw,
127 					 float RealLength, float Height,
128 					 float Length, float Radius,
129 					 float Angle, ajint Way);
130 static void cirdna_DrawBracketsOncurve(float xDraw, float yDraw,
131 				       float RealLength, float Height,
132 				       float Length, float Radius,
133 				       float Angle, ajint Way);
134 static void cirdna_DrawBarsOncurve(float xDraw, float yDraw,
135 				       float Height, float Radius,
136 				       float Angle);
137 static void cirdna_HorTextPile(float x, float y, float Radius,
138 			       float StartAngle, float EndAngle,
139 			       const AjPStr Name2,
140 			       float postext, ajint NumNames);
141 static float cirdna_HorTextPileHeight(float postext, ajint NumNames);
142 static float cirdna_HorTextPileLengthMax(const AjPStr Name2, ajint NumNames);
143 static float cirdna_ComputeAngle(float RealLength, float Length,
144 				 float OriginAngle);
145 static float cirdna_ComputeArc(float RealLength, float Length);
146 
147 
148 
149 static AjPStr** Style=NULL;
150 static AjPStr** Name=NULL;
151 /*static AjPStr Style[MAXGROUPS][MAXLABELS]; */
152 /*static AjPStr Name[MAXGROUPS][MAXLABELS];*/
153 
154 static ajint cirdnaMaxinter=0;
155 static ajint* cirdnaInter=NULL;
156 /*ajint Inter[MAXLABELS];*/
157 
158 
159 static float* cirdnaFromText=NULL;
160 static float* cirdnaToText=NULL;
161 /*    float FromText[MAXLABELS];*/
162 /*    float ToText[MAXLABELS];*/
163 
164 
165 
166 
167 /* @prog cirdna ***************************************************************
168 **
169 ** Draws circular maps of DNA constructs
170 **
171 ******************************************************************************/
172 
main(int argc,char ** argv)173 int main(int argc, char **argv)
174 {
175     AjPGraph graph;
176     ajint i;
177     ajint j;
178     ajint GapSize;
179     ajint* NumLabels;
180     ajint** NumNames;
181 /*    ajint NumNames[MAXGROUPS][MAXLABELS];*/
182     ajint NumGroups;
183     ajint InterColour;
184     ajint** Colour;
185     ajint** Adjust;
186     ajint* AdjustMax=NULL;
187     char** FromSymbol=NULL;
188     char** ToSymbol=NULL;
189 /*    ajint Colour[MAXGROUPS][MAXLABELS];*/
190 /*    ajint Adjust[MAXGROUPS][MAXLABELS];*/
191 /*    ajint AdjustMax[MAXGROUPS];*/
192 /*    char FromSymbol[MAXGROUPS][MAXLABELS];*/
193 /*    char ToSymbol[MAXGROUPS][MAXLABELS];*/
194     float xDraw;
195     float yDraw;
196     float Radius;
197     float RadiusMax;
198     float DrawRadius;
199     float OriginAngle;
200     float** From=NULL;
201     float** To=NULL;
202 /*    float From[MAXGROUPS][MAXLABELS];*/
203 /*    float To[MAXGROUPS][MAXLABELS];*/
204     float TotalHeight;
205     float* GroupHeight=NULL;
206 /*    float GroupHeight[MAXGROUPS];*/
207     float RulerHeight;
208     float Width;
209     float Height;
210     float Border;
211     float Start;
212     float End;
213     float DrawLength;
214     float RealLength;
215     float TickHeight;
216     float BlockHeight;
217     float RangeHeight;
218     float TextLength;
219     float TextHeight;
220     float GapGroup;
221     float posblock;
222     float posrange;
223     float postext;
224     AjPFile infile;
225     AjPStr line;
226     AjPStr* GroupName=NULL;
227 /*    AjPStr GroupName[MAXGROUPS];*/
228     AjBool Ruler;
229     AjBool InterSymbol;
230     AjBool InterTicks;
231     AjPStr PosTicks;
232     AjBool TickLines;
233     AjPStr BlockType;
234     AjPStr PosBlocks;
235     float charsize;
236     float minsize;
237     ajint maxgroups;
238     ajint maxlabels;
239 
240     /* read the ACD file for graphical programs */
241     embInit("cirdna", argc, argv);
242 
243     /* array size limits */
244     maxgroups = ajAcdGetInt("maxgroups");
245     maxlabels = ajAcdGetInt("maxlabels");
246 
247     /* to draw or not to draw the ruler */
248     Ruler = ajAcdGetBoolean("ruler");
249 
250     /* get the type of blocks */
251     BlockType = ajAcdGetListSingle("blocktype");
252 
253     /* get the angle of the molecule's origin */
254     OriginAngle = ajAcdGetFloat("originangle");
255 
256     /* get the position of the ticks */
257     PosTicks = ajAcdGetSelectSingle("posticks");
258 
259     /* get the position of the text for blocks */
260     PosBlocks = ajAcdGetSelectSingle("posblocks");
261 
262     /* to draw or not to draw junctions to link blocks */
263     InterSymbol = ajAcdGetBoolean("intersymbol");
264     /* get the colour of junctions used to link blocks */
265     InterColour = ajAcdGetInt("intercolour");
266 
267     /* to draw or not to draw junctions between ticks */
268     InterTicks = ajAcdGetBoolean("interticks");
269 
270     /* get the size of the intervals between the ruler's ticks */
271     GapSize = ajAcdGetInt("gapsize");
272     /* to draw or not to draw vertical lines at ruler's ticks */
273     TickLines = ajAcdGetBoolean("ticklines");
274 
275 
276     /* set the output graphical context */
277     graph = ajAcdGetGraph("graphout");
278 
279     /* get the input file */
280     infile = ajAcdGetInfile("infile");
281 
282     /* Allocate memory for the old fixed-length arrays */
283 
284     AJCNEW0(Style, maxgroups);
285     AJCNEW0(Name, maxgroups);
286     AJCNEW0(NumNames, maxgroups);
287     AJCNEW0(NumLabels, maxgroups);
288     AJCNEW0(Colour, maxgroups);
289     AJCNEW0(Adjust, maxgroups);
290     AJCNEW0(AdjustMax, maxgroups);
291     AJCNEW0(FromSymbol, maxgroups);
292     AJCNEW0(ToSymbol, maxgroups);
293     AJCNEW0(From, maxgroups);
294     AJCNEW0(To, maxgroups);
295     AJCNEW0(GroupHeight, maxgroups);
296     AJCNEW0(GroupName, maxgroups);
297 
298     /* length and height of text */
299     /*TextHeight = 10;
300     TextLength = TextHeight+25;*/
301     TextHeight = 2*ajAcdGetFloat("textheight");
302     TextLength = 7*ajAcdGetFloat("textlength");
303 
304 
305     /* read the start and end positions */
306     if(!cirdna_ReadInput(infile, &Start, &End))
307         ajFatal("Error processing input file");
308 
309     /* compute the real length of the molecule */
310     RealLength = (End - Start) + 1;
311 
312     /* height of a tick, a block, and a range */
313     TickHeight = 3*ajAcdGetFloat("tickheight");
314     if( ajStrMatchCaseC(PosBlocks, "Out") )
315 	BlockHeight = 3*ajAcdGetFloat("blockheight");
316     else
317     {
318 	BlockHeight = (TextHeight+3)*ajAcdGetFloat("blockheight");
319 	if(BlockHeight<(TextHeight+3) )
320 	    BlockHeight = (TextHeight+3);
321     }
322     RangeHeight = 3*ajAcdGetFloat("rangeheight");
323 
324     /* set the relative positions of elements of a group */
325     posblock = 0;
326     posrange = 0;
327     GapGroup = 3*ajAcdGetFloat("gapgroup");
328 
329     ajGraphAppendTitleS(graph, ajFileGetPrintnameS(infile));
330 
331     /* open the window in which the graphics will be drawn */
332     ajGraphOpenMm(graph, &Width, &Height);
333 
334     Border = (float) 2.0 * (TickHeight+TextLength);
335     DrawLength = Height - 2*Border;
336 
337     /* coordinates of the circle's center */
338     xDraw = Width/(float)2.0;
339     yDraw = Height/(float)2.0;
340 
341     /* radius of the outermost circle */
342     Radius = RadiusMax = DrawLength/(float)2.0;
343 
344     /* read the contents of the groups */
345     line = ajStrNew();
346     ajFileSeek(infile, 0L, 0);
347     i = 0;
348     while( ajReadlineTrim(infile, &line) )
349     {
350 	if( ajStrPrefixC(line, "group") )
351 	{
352 	    if (i == maxgroups)
353 		ajWarn("Too many groups (maxgroups=%d) in input", maxgroups);
354 	    if (i < maxgroups)
355 	    {
356 		AJCNEW0(Style[i], maxlabels);
357 		AJCNEW0(Name[i], maxlabels);
358 		AJCNEW0(NumNames[i], maxlabels);
359 		AJCNEW0(Colour[i], maxlabels);
360 		AJCNEW0(Adjust[i], maxlabels);
361 		AJCNEW0(FromSymbol[i], maxlabels);
362 		AJCNEW0(ToSymbol[i], maxlabels);
363 		AJCNEW0(From[i], maxlabels);
364 		AJCNEW0(To[i], maxlabels);
365 
366 		GroupName[i] = cirdna_ReadGroup(infile, maxlabels,
367 						From[i], To[i],
368 						Name[i],
369 						FromSymbol[i], ToSymbol[i],
370 						Style[i], &NumLabels[i],
371 						NumNames[i], Colour[i]);
372 		j = NumLabels[i];
373 		AJCRESIZE(Style[i], j);
374 		AJCRESIZE(Name[i], j);
375 		AJCRESIZE(NumNames[i], j);
376 		AJCRESIZE(Colour[i], j);
377 		AJCRESIZE(Adjust[i], j);
378 		AJCRESIZE(FromSymbol[i], j);
379 		AJCRESIZE(ToSymbol[i], j);
380 		AJCRESIZE(From[i], j);
381 		AJCRESIZE(To[i], j);
382 	    }
383 	    i++;
384 	}
385     }
386     NumGroups = i;
387 
388     AJCRESIZE(Style, i);
389     AJCRESIZE(Name, i);
390     AJCRESIZE(NumNames, i);
391     AJCRESIZE(NumLabels, i);
392     AJCRESIZE(Colour, i);
393     AJCRESIZE(Adjust, i);
394     AJCRESIZE(AdjustMax, i);
395     AJCRESIZE(FromSymbol, i);
396     AJCRESIZE(ToSymbol, i);
397     AJCRESIZE(From, i);
398     AJCRESIZE(To, i);
399     AJCRESIZE(GroupHeight, i);
400     AJCRESIZE(GroupName, i);
401 
402     /* remove the beginning of the molecule in case it doesn't begin at 1 */
403     if (Start != 1)
404     {
405 	for(i=0; i<NumGroups; i++)
406 	    for(j=0; j<NumLabels[i]; j++)
407 	    {
408 		From[i][j] -= (Start-1);
409 		To[i][j]   -= (Start-1);
410 	    }
411     }
412 
413     /* compute the character size that fits all groups, including the ruler */
414     minsize = 100.0;
415     charsize = cirdna_TextRuler(Start, End, GapSize, TextLength, TextHeight,
416 				PosTicks, NumGroups, NumLabels);
417     if( charsize<minsize ) minsize = charsize;
418     ajDebug("Calculated charsize: %f minsize:%f\n", charsize, minsize);
419     for(i=0; i<NumGroups; i++)
420     {
421 	charsize = cirdna_TextGroup(TextHeight, TextLength, Name[i],
422 				    NumLabels[i], NumNames[i],
423 				    Style[i], From[i], To[i],
424 				    PosTicks);
425 	if( charsize<minsize )
426 	    minsize = charsize;
427     }
428     ajGraphicsSetDefcharsize(minsize);
429     ajDebug("Initial charsize: %f\n", minsize);
430 
431 
432     /* find whether horizontal text strings overlap within a group */
433     postext = (ajGraphicsCalcTextheight()+1)*ajAcdGetFloat("postext");
434     for(i=0; i<NumGroups; i++)
435 	AdjustMax[i] = cirdna_OverlapTextGroup(Name[i], Style[i], NumLabels[i],
436 					       From[i], To[i], Start, End,
437 					       PosTicks, Adjust[i]);
438 
439 
440     /* compute the height of the ruler */
441     RulerHeight = cirdna_HeightRuler(Start, End, GapSize, postext, TickHeight,
442 				     PosTicks, NumGroups, NumLabels);
443     if(!RulerHeight)
444 	ajDebug("Err: Ruler height");
445 
446     /* compute the height of the groups */
447     TotalHeight = 0.0;
448     for(i=0; i<NumGroups; i++)
449     {
450 	GroupHeight[i] = cirdna_HeightGroup(postext,
451 					    TickHeight, BlockHeight,
452 					    RangeHeight, Style[i],
453 					    NumLabels[i],
454 					    PosTicks, PosBlocks, AdjustMax[i]);
455 	TotalHeight += (GroupHeight[i]+GapGroup);
456     }
457 
458     /*
459     **  decrease the radius such that the innermost group is not
460     **  compressed in the centre of the circle
461     */
462     DrawRadius = Radius - (TotalHeight/NumGroups);
463 
464     /*
465     **  if the groups are too big, resize them such that they fit in the
466     **  window
467     */
468     if(TotalHeight<DrawRadius)
469 	TotalHeight = DrawRadius;
470     TickHeight/=(TotalHeight/DrawRadius);
471     BlockHeight/=(TotalHeight/DrawRadius);
472     RangeHeight/=(TotalHeight/DrawRadius);
473     TextHeight/=(TotalHeight/DrawRadius);
474     TextLength/=(TotalHeight/DrawRadius);
475     postext/=(TotalHeight/DrawRadius);
476     posblock/=(TotalHeight/DrawRadius);
477     posrange/=(TotalHeight/DrawRadius);
478     GapGroup/=(TotalHeight/DrawRadius);
479 
480     /*
481     **  the groups having been resized, recompute the character size that
482     ** fits all groups, including the ruler
483     */
484     minsize = 100.0;
485     charsize = cirdna_TextRulerStr(Start, End, GapSize,
486 				   (TotalHeight/DrawRadius),
487 				   PosTicks, NumGroups, NumLabels);
488     ajDebug("Resized calculated charsize: %f minsize:%f\n", charsize, minsize);
489     if(charsize<minsize)
490 	minsize = charsize;
491     for(i=0; i<NumGroups; i++)
492     {
493 	charsize = cirdna_TextGroupStr(Name[i], NumLabels[i], NumNames[i],
494 				       (TotalHeight/DrawRadius),
495 				       Style[i], From[i], To[i],
496 				       PosTicks);
497 	if(charsize<minsize)
498 	    minsize = charsize;
499     }
500     ajGraphicsSetDefcharsize(minsize);
501     ajDebug("Resized charsize: %f\n", minsize);
502 
503 
504     /* the ruler having been resized, recompute its height */
505     RulerHeight = cirdna_HeightRuler(Start, End, GapSize, postext, TickHeight,
506 				     PosTicks, NumGroups, NumLabels);
507     /* the groups having been resized, recompute their height */
508     TotalHeight = 0.0;
509     for(i=0; i<NumGroups; i++)
510     {
511 	GroupHeight[i] = cirdna_HeightGroup(postext,
512 					    TickHeight, BlockHeight,
513 					    RangeHeight,
514 					    Style[i], NumLabels[i],
515 					    PosTicks, PosBlocks,
516 					    AdjustMax[i]);
517 	TotalHeight += (GroupHeight[i]+GapGroup);
518     }
519 
520     /* draw the ruler */
521     if(Ruler)
522 	cirdna_DrawRuler(xDraw, yDraw, Start, End,
523 			 RealLength, Radius, TickHeight,
524 			 OriginAngle, GapSize, TickLines,
525 			 postext, NumGroups, NumLabels,
526 			 From, PosTicks, 1);
527 
528     /* draw the groups */
529     for(i=0; i<NumGroups; i++)
530     {
531 	Radius -= (GroupHeight[i]+GapGroup);
532 	cirdna_DrawGroup(xDraw, yDraw, posblock, posrange, postext, TickHeight,
533 			 BlockHeight, RangeHeight, RealLength,
534 			 Radius, RadiusMax, From[i], To[i],
535 			 Name[i], FromSymbol[i], ToSymbol[i], Style[i],
536 			 InterSymbol, InterTicks, NumLabels[i],
537 			 OriginAngle, NumNames[i], PosTicks, PosBlocks,
538 			 Adjust[i], InterColour, Colour[i], BlockType);
539 	ajStrDel(&GroupName[i]);
540     }
541 
542 
543     /* close the input file */
544     ajFileClose(&infile);
545     ajStrDel(&line);
546 
547     ajStrDel(&PosTicks);
548     ajStrDel(&PosBlocks);
549     ajStrDel(&BlockType);
550 
551     /* close the graphical window */
552     ajGraphicsClose();
553     ajGraphxyDel(&graph);
554 
555     for(i=0;i<NumGroups;i++)
556     {
557 	for(j=0;j<NumLabels[i];j++)
558 	{
559 	    ajStrDel(&Style[i][j]);
560 	    ajStrDel(&Name[i][j]);
561 	}
562 	ajStrDel(&GroupName[i]);
563 	AJFREE(NumNames[i]);
564 	AJFREE(Colour[i]);
565 	AJFREE(Adjust[i]);
566 	AJFREE(FromSymbol[i]);
567 	AJFREE(ToSymbol[i]);
568 	AJFREE(From[i]);
569 	AJFREE(To[i]);
570 	AJFREE(Name[i]);
571 	AJFREE(Style[i]);
572     }
573     AJFREE(AdjustMax);
574     AJFREE(GroupHeight);
575     AJFREE(NumLabels);
576     AJFREE(GroupName);
577     AJFREE(NumNames);
578     AJFREE(Style);
579     AJFREE(Name);
580     AJFREE(Colour);
581     AJFREE(Adjust);
582     AJFREE(FromSymbol);
583     AJFREE(ToSymbol);
584     AJFREE(From);
585     AJFREE(To);
586     AJFREE(cirdnaInter);
587     AJFREE(cirdnaFromText);
588     AJFREE(cirdnaToText);
589 
590     embExit();
591 
592     return 0;
593 }
594 
595 
596 
597 
598 /* @funcstatic cirdna_TextRuler ***********************************************
599 **
600 ** Compute the character size that fits all elements of the ruler
601 ** provided that the height and the length of all strings are at
602 ** most TextHeight and TextLength, respectively
603 **
604 ** @param [r] Start [float] Undocumented
605 ** @param [r] End [float] Undocumented
606 ** @param [r] GapSize [ajint] Undocumented
607 ** @param [r] TextLength [float] Undocumented
608 ** @param [r] TextHeight [float] Undocumented
609 ** @param [r] PosTicks [const AjPStr] Undocumented
610 ** @param [r] NumGroups [ajint] Undocumented
611 ** @param [r] NumLabels [const ajint*] Undocumented
612 ** @return [float] Undocumented
613 ** @@
614 ******************************************************************************/
615 
cirdna_TextRuler(float Start,float End,ajint GapSize,float TextLength,float TextHeight,const AjPStr PosTicks,ajint NumGroups,const ajint * NumLabels)616 static float cirdna_TextRuler(float Start, float End, ajint GapSize,
617 			      float TextLength, float TextHeight,
618 			      const AjPStr PosTicks, ajint NumGroups,
619 			      const ajint *NumLabels)
620 {
621     ajint i;
622     ajint j;
623     const AjPStr token;
624     AjPStr string;
625     float charsize;
626     float minsize = 100.0;
627 
628     string = ajStrNew();
629 
630     ajStrFromInt(&string, (ajint)Start);
631     charsize = ajGraphicsCalcCharsize(0, 0, TextLength, TextLength,
632                                       ajStrGetPtr(string), TextHeight );
633     if(charsize < minsize)
634 	minsize = charsize;
635 
636     for(i=GapSize; i<End; i+=GapSize)
637 	if(i>Start)
638 	{
639 	    ajStrFromInt(&string, i);
640 	    charsize = ajGraphicsCalcCharsize(0, 0, TextLength, TextLength,
641                                               ajStrGetPtr(string), TextHeight );
642 	    if(charsize < minsize)
643 		minsize = charsize;
644 	}
645 
646     for(i=0; i<NumGroups; i++)
647 	for(j=0; j<NumLabels[i]; j++)
648 	    if(ajStrMatchCaseC(Style[i][j], "Tick") &&
649 	       ajStrMatchCaseC(PosTicks, "Out") )
650 	    {
651 		token = ajStrParseC(Name[i][j], ";");
652 		charsize = ajGraphicsCalcCharsize( 0, 0, TextLength,
653                                                    TextLength,
654                                                    ajStrGetPtr(token),
655                                                    TextHeight );
656 		if(charsize < minsize)
657 		    minsize = charsize;
658 	    }
659 
660     ajStrDel(&string);
661 
662     return minsize;
663 }
664 
665 
666 
667 
668 /* @funcstatic cirdna_TextRulerStr ********************************************
669 **
670 ** compute the character size that fits all elements of the ruler provided
671 ** that the height and the length of all strings are multiplied by TextCoef
672 **
673 ** @param [r] Start [float] Undocumented
674 ** @param [r] End [float] Undocumented
675 ** @param [r] GapSize [ajint] Undocumented
676 ** @param [r] TextCoef [float] Undocumented
677 ** @param [r] PosTicks [const AjPStr] Undocumented
678 ** @param [r] NumGroups [ajint] Undocumented
679 ** @param [r] NumLabels [const ajint*] Undocumented
680 ** @return [float] Undocumented
681 ** @@
682 ******************************************************************************/
683 
cirdna_TextRulerStr(float Start,float End,ajint GapSize,float TextCoef,const AjPStr PosTicks,ajint NumGroups,const ajint * NumLabels)684 static float cirdna_TextRulerStr(float Start, float End, ajint GapSize,
685 				 float TextCoef, const AjPStr PosTicks,
686 				 ajint NumGroups, const ajint *NumLabels)
687 {
688     ajint i;
689     ajint  j;
690     const AjPStr token;
691     AjPStr string;
692     float charsize;
693     float minsize = 100.0;
694     float stringLength;
695     float stringHeight;
696 
697     string = ajStrNew();
698 
699     ajStrFromInt(&string, (ajint)Start);
700     stringLength = ajGraphicsCalcTextlengthS(string);
701     stringHeight = ajGraphicsCalcTextheight();
702     charsize = ajGraphicsCalcCharsize(0, 0, stringLength/TextCoef,
703                                       stringLength/TextCoef,
704                                       ajStrGetPtr(string),
705                                       stringHeight/TextCoef );
706     if( charsize < minsize ) minsize = charsize;
707 
708     for(i=GapSize; i<End; i+=GapSize)
709 	if(i>Start)
710 	{
711 	    ajStrFromInt(&string, i);
712 	    stringLength = ajGraphicsCalcTextlengthS(string);
713 	    stringHeight = ajGraphicsCalcTextheight();
714 	    charsize = ajGraphicsCalcCharsize(0, 0, stringLength/TextCoef,
715                                               stringLength/TextCoef,
716                                               ajStrGetPtr(string),
717                                               stringHeight/TextCoef);
718 	    if(charsize < minsize)
719 		minsize = charsize;
720 	}
721 
722     for(i=0; i<NumGroups; i++)
723 	for(j=0; j<NumLabels[i]; j++)
724 	{
725 	    if( ajStrMatchCaseC(Style[i][j], "Tick") &&
726 	       ajStrMatchCaseC(PosTicks, "Out") )
727 	    {
728 		token = ajStrParseC(Name[i][j], ";");
729 		stringLength = ajGraphicsCalcTextlengthS(token);
730 		stringHeight = ajGraphicsCalcTextheight();
731 		charsize = ajGraphicsCalcCharsize(0, 0, stringLength/TextCoef,
732                                                   stringLength/TextCoef,
733                                                   ajStrGetPtr(token),
734                                                   stringHeight/TextCoef );
735 		if(charsize < minsize)
736 		    minsize = charsize;
737 	    }
738 	}
739 
740     ajStrDel(&string);
741 
742     return minsize;
743 }
744 
745 
746 
747 
748 /* @funcstatic cirdna_HeightRuler *********************************************
749 **
750 ** compute the ruler's height
751 **
752 ** @param [r] Start [float] Undocumented
753 ** @param [r] End [float] Undocumented
754 ** @param [r] GapSize [ajint] Undocumented
755 ** @param [r] postext [float] Undocumented
756 ** @param [r] TickHeight [float] Undocumented
757 ** @param [r] PosTicks [const AjPStr] Undocumented
758 ** @param [r] NumGroups [ajint] Undocumented
759 ** @param [r] NumLabels [const ajint*] Undocumented
760 ** @return [float] Undocumented
761 ** @@
762 ******************************************************************************/
763 
cirdna_HeightRuler(float Start,float End,ajint GapSize,float postext,float TickHeight,const AjPStr PosTicks,ajint NumGroups,const ajint * NumLabels)764 static float cirdna_HeightRuler(float Start, float End, ajint GapSize,
765 				float postext, float TickHeight,
766 				const AjPStr PosTicks, ajint NumGroups,
767 				const ajint *NumLabels)
768 {
769     ajint i;
770     ajint j;
771     float RulerHeight;
772     float stringLength;
773     float maxLength = 0.0;
774     const AjPStr token;
775     AjPStr string;
776 
777     string = ajStrNew();
778 
779     RulerHeight = TickHeight+postext;
780 
781     ajStrFromInt(&string, (ajint)Start);
782     stringLength = ajGraphicsCalcTextlengthS(string);
783     if(stringLength>maxLength)
784 	maxLength = stringLength;
785 
786     for(i=GapSize; i<End; i+=GapSize)
787 	if(i>Start)
788 	{
789 	    ajStrFromInt(&string, i);
790 	    stringLength = ajGraphicsCalcTextlengthS(string);
791 	    if(stringLength>maxLength)
792 		maxLength = stringLength;
793 	}
794 
795     for(i=0; i<NumGroups; i++)
796 	for(j=0; j<NumLabels[i]; j++)
797 	    if(ajStrMatchCaseC(Style[i][j], "Tick") &&
798 	       ajStrMatchCaseC(PosTicks, "Out") )
799 	    {
800 		token = ajStrParseC(Name[i][j], ";");
801 		stringLength = ajGraphicsCalcTextlengthS(token);
802 		if( stringLength>maxLength )
803 		    maxLength = stringLength;
804 	    }
805 
806     RulerHeight += maxLength;
807 
808     ajStrDel(&string);
809 
810     return RulerHeight;
811 }
812 
813 
814 
815 
816 /* @funcstatic cirdna_DrawRuler ***********************************************
817 **
818 ** draw a ruler
819 **
820 ** @param [r] xDraw [float] Undocumented
821 ** @param [r] yDraw [float] Undocumented
822 ** @param [r] Start [float] Undocumented
823 ** @param [r] End [float] Undocumented
824 ** @param [r] RealLength [float] Undocumented
825 ** @param [r] Radius [float] Undocumented
826 ** @param [r] TickHeight [float] Undocumented
827 ** @param [r] OriginAngle [float] Undocumented
828 ** @param [r] GapSize [ajint] Undocumented
829 ** @param [r] TickLines [AjBool] Undocumented
830 ** @param [r] postext [float] Undocumented
831 ** @param [r] NumGroups [ajint] Undocumented
832 ** @param [r] NumLabels [const ajint*] Undocumented
833 ** @param [r] From [float* const *] Undocumented
834 ** @param [r] PosTicks [const AjPStr] Undocumented
835 ** @param [r] Colour [ajint] Undocumented
836 ** @@
837 ******************************************************************************/
838 
cirdna_DrawRuler(float xDraw,float yDraw,float Start,float End,float RealLength,float Radius,float TickHeight,float OriginAngle,ajint GapSize,AjBool TickLines,float postext,ajint NumGroups,const ajint * NumLabels,float * const * From,const AjPStr PosTicks,ajint Colour)839 static void cirdna_DrawRuler(float xDraw, float yDraw, float Start, float End,
840 			     float RealLength, float Radius, float TickHeight,
841 			     float OriginAngle, ajint GapSize,
842 			     AjBool TickLines, float postext,
843 			     ajint NumGroups, const ajint *NumLabels,
844 			     float* const * From,
845 			     const AjPStr PosTicks, ajint Colour)
846 {
847     ajint i;
848     AjPStr string;
849     AjPStr posticks;
850     float *xy;
851     float Angle;
852 
853     string   = ajStrNew();
854     posticks = ajStrNew();
855 
856     ajGraphicsSetFgcolour(Colour);
857 
858     ajGraphicsDrawposCircle( xDraw, yDraw, Radius );
859 
860     ajStrAssignEmptyC(&posticks, "Out");
861 
862     /* set the circle's origin */
863     ajStrFromInt(&string, (ajint)Start);
864     if(TickLines)
865     {
866 	Angle = cirdna_ComputeAngle(RealLength, 0, OriginAngle);
867 	xy = ajGraphicsCalcCoord(xDraw, yDraw, Radius, Angle);
868 	ajGraphicsDrawposLine(xDraw, yDraw, xy[0], xy[1]);
869 	AJFREE(xy);
870     }
871 
872     if(!cirdna_OverlapTickRuler(NumGroups, NumLabels, From, PosTicks,
873 				(ajint)Start) )
874 	cirdna_DrawTicks(xDraw, yDraw, RealLength, Radius, TickHeight, 0,
875 			 string, OriginAngle, postext,
876 			 posticks, 1, 0, Colour);
877 
878     /* draw the ruler's ticks */
879     for(i=GapSize; i<End; i+=GapSize)
880 	if(i>Start)
881 	{
882 	    ajStrFromInt(&string, i);
883 	    if( TickLines )
884 	    {
885 		Angle = cirdna_ComputeAngle(RealLength, i-Start, OriginAngle);
886 		xy = ajGraphicsCalcCoord(xDraw, yDraw, Radius, Angle);
887 		ajGraphicsDrawposLine(xDraw, yDraw, xy[0], xy[1]);
888 		AJFREE(xy);
889 	    }
890 	    if(!cirdna_OverlapTickRuler(NumGroups, NumLabels, From, PosTicks,
891 					i))
892 		cirdna_DrawTicks(xDraw, yDraw, RealLength, Radius, TickHeight,
893 				 i-Start, string, OriginAngle,
894 				 postext, posticks, 1, 0, Colour);
895 	}
896 
897     ajStrDel(&string);
898     ajStrDel(&posticks);
899 
900     return;
901 }
902 
903 
904 
905 
906 /* @funcstatic cirdna_DrawTicks ***********************************************
907 **
908 ** draw a Tick
909 **
910 ** @param [r] xDraw [float] Undocumented
911 ** @param [r] yDraw [float] Undocumented
912 ** @param [r] RealLength [float] Undocumented
913 ** @param [r] Radius [float] Undocumented
914 ** @param [r] TickHeight [float] Undocumented
915 ** @param [r] From [float] Undocumented
916 ** @param [r] Name2 [const AjPStr] Undocumented
917 ** @param [r] OriginAngle [float] Undocumented
918 ** @param [r] postext [float] Undocumented
919 ** @param [r] PosTicks [const AjPStr] Undocumented
920 ** @param [r] NumNames [ajint] Undocumented
921 ** @param [r] Adjust [ajint] Undocumented
922 ** @param [r] Colour [ajint] Undocumented
923 ** @@
924 ******************************************************************************/
925 
cirdna_DrawTicks(float xDraw,float yDraw,float RealLength,float Radius,float TickHeight,float From,const AjPStr Name2,float OriginAngle,float postext,const AjPStr PosTicks,ajint NumNames,ajint Adjust,ajint Colour)926 static void cirdna_DrawTicks(float xDraw, float yDraw, float RealLength,
927 			     float Radius, float TickHeight, float From,
928 			     const AjPStr Name2, float OriginAngle,
929 			     float postext,
930 			     const AjPStr PosTicks,
931 			     ajint NumNames, ajint Adjust,
932 			     ajint Colour)
933 {
934     float Angle;
935     float StartAngle;
936     float EndAngle;
937     float *xy1;
938     float *xy2;
939     float *xy3;
940     float stringLength;
941     float r1Ticks = Radius;
942     float r2Ticks = r1Ticks+TickHeight;
943     const AjPStr token;
944     float mmtolen;
945 
946     /* radius is 2pi*radius in mm, RealLength in bases */
947     mmtolen = RealLength/(Radius * (float) 2.0 * (float) 3.1416);
948 
949     ajGraphicsSetFgcolour(Colour);
950 
951     Angle = cirdna_ComputeAngle(RealLength, From, OriginAngle);
952 
953     xy1 = ajGraphicsCalcCoord(xDraw, yDraw, r1Ticks, Angle);
954     xy2 = ajGraphicsCalcCoord(xDraw, yDraw, r2Ticks, Angle);
955     ajGraphicsDrawposLine(xy1[0], xy1[1], xy2[0], xy2[1] );
956     AJFREE(xy1);
957     AJFREE(xy2);
958 
959     if(ajStrMatchCaseC(PosTicks, "In") )
960     {
961 	stringLength = mmtolen * cirdna_HorTextPileLengthMax(Name2, NumNames);
962 	StartAngle = cirdna_ComputeAngle(RealLength, From+stringLength/2,
963 					 OriginAngle);
964 	EndAngle = cirdna_ComputeAngle(RealLength, From-stringLength/2,
965 				       OriginAngle);
966 	cirdna_HorTextPile(xDraw, yDraw, r2Ticks+(Adjust*postext), StartAngle,
967 			   EndAngle, Name2, postext, 1);
968     }
969     else
970     {
971 	token = ajStrParseC(Name2, ";");
972 	/*ajStrExchangeCC(&Name2, ";", " ");*/
973 	stringLength = mmtolen * ajGraphicsCalcTextlengthS(token);
974 	xy1 = ajGraphicsCalcCoord(xDraw, yDraw, r2Ticks+postext, Angle);
975 	xy2 = ajGraphicsCalcCoord(xDraw, yDraw, r2Ticks+postext+stringLength,
976 			     Angle);
977 	xy3 = ajGraphicsCalcCoord(xDraw, yDraw, r2Ticks+postext-stringLength,
978 			     Angle);
979 	if((Angle>=0.0 && Angle<=90.0) || (Angle>=270.0 && Angle<=360.0) ||
980 	   (Angle>=360.0 && Angle<=450.0) || (Angle>=630.0 && Angle<=720.0) )
981 	    ajGraphicsDrawposTextAtlineJustify( xy1[0], xy1[1], xy2[0], xy2[1],
982                                                 ajStrGetPtr(token), 0.0 );
983 	else
984 	    ajGraphicsDrawposTextAtlineJustify( xy1[0], xy1[1], xy3[0], xy3[1],
985                                                 ajStrGetPtr(token), 1.0 );
986 	AJFREE(xy1);
987 	AJFREE(xy2);
988 	AJFREE(xy3);
989     }
990 
991     return;
992 }
993 
994 
995 
996 
997 /* @funcstatic cirdna_DrawBlocks **********************************************
998 **
999 ** draw a Block
1000 **
1001 ** @param [r] xDraw [float] Undocumented
1002 ** @param [r] yDraw [float] Undocumented
1003 ** @param [r] RealLength [float] Undocumented
1004 ** @param [r] Radius [float] Undocumented
1005 ** @param [r] BlockHeight [ajint] Undocumented
1006 ** @param [r] From [float] Undocumented
1007 ** @param [r] To [float] Undocumented
1008 ** @param [r] Name2 [const AjPStr] Undocumented
1009 ** @param [r] postext [float] Undocumented
1010 ** @param [r] OriginAngle [float] Undocumented
1011 ** @param [r] PosBlocks [const AjPStr] Undocumented
1012 ** @param [r] NumNames [ajint] Undocumented
1013 ** @param [r] Adjust [ajint] Undocumented
1014 ** @param [r] Colour [ajint] Undocumented
1015 ** @param [r] BlockType [const AjPStr] Undocumented
1016 ** @@
1017 ******************************************************************************/
1018 
cirdna_DrawBlocks(float xDraw,float yDraw,float RealLength,float Radius,ajint BlockHeight,float From,float To,const AjPStr Name2,float postext,float OriginAngle,const AjPStr PosBlocks,ajint NumNames,ajint Adjust,ajint Colour,const AjPStr BlockType)1019 static void cirdna_DrawBlocks(float xDraw, float yDraw, float RealLength,
1020 			      float Radius, ajint BlockHeight, float From,
1021 			      float To, const AjPStr Name2, float postext,
1022 			      float OriginAngle, const AjPStr PosBlocks,
1023 			      ajint NumNames, ajint Adjust, ajint Colour,
1024 			      const AjPStr BlockType)
1025 {
1026     float StartAngle;
1027     float EndAngle;
1028     float stringLength;
1029     float stringHeight;
1030     float r1Blocks;
1031     float r2Blocks;
1032     float mmtolen;
1033 
1034     /* radius is 2pi*radius in mm, RealLength in bases */
1035     mmtolen = RealLength/(Radius * (float) 2.0 * (float) 3.1416);
1036 
1037     r1Blocks = Radius+((float)1.0*BlockHeight/(float)2);
1038     r2Blocks = r1Blocks-BlockHeight;
1039 
1040     StartAngle = cirdna_ComputeAngle(RealLength, From, OriginAngle);
1041     EndAngle = cirdna_ComputeAngle(RealLength, To, OriginAngle);
1042 
1043     ajGraphicsSetFgcolour(Colour);
1044     if(ajCharCmpCase(ajStrGetPtr(BlockType), "Open")==0 )
1045 	ajGraphicsDrawarcRect(xDraw, yDraw, r2Blocks,
1046                               StartAngle, EndAngle, (float)BlockHeight);
1047     else if( ajCharCmpCase(ajStrGetPtr(BlockType), "Filled")==0 )
1048 	ajGraphicsDrawarcRectFill(xDraw, yDraw, r2Blocks,
1049                                   StartAngle, EndAngle, (float)BlockHeight);
1050     else
1051     {
1052 	ajGraphicsDrawarcRectFill(xDraw, yDraw, r2Blocks,
1053                                   StartAngle, EndAngle, (float)BlockHeight);
1054 	ajGraphicsSetFgcolour(0);
1055 	ajGraphicsDrawarcRect(xDraw, yDraw, r2Blocks,
1056                               StartAngle, EndAngle, (float)BlockHeight);
1057 	ajGraphicsSetFgcolour(Colour);
1058     }
1059 
1060     stringLength = mmtolen * cirdna_HorTextPileLengthMax(Name2, NumNames);
1061     stringHeight = ajGraphicsCalcTextheight();
1062     StartAngle   = cirdna_ComputeAngle(RealLength,
1063                                        (To+From)/2 + stringLength/2,
1064 				       OriginAngle);
1065     EndAngle = cirdna_ComputeAngle(RealLength,
1066                                    (To+From)/2 - stringLength/2,
1067 				   OriginAngle);
1068 
1069     if(ajStrMatchCaseC(PosBlocks, "Out") )
1070 	cirdna_HorTextPile(xDraw, yDraw, r1Blocks+Adjust*postext, StartAngle,
1071 			   EndAngle, Name2, postext, 1);
1072     else
1073 	cirdna_HorTextPile(xDraw, yDraw,
1074 			   (r1Blocks+r2Blocks)/2-(stringHeight/2)-postext,
1075 			   StartAngle, EndAngle, Name2, postext, 1);
1076 
1077     return;
1078 }
1079 
1080 
1081 
1082 
1083 /* @funcstatic cirdna_DrawRanges **********************************************
1084 **
1085 ** draw a Range
1086 **
1087 ** @param [r] xDraw [float] Undocumented
1088 ** @param [r] yDraw [float] Undocumented
1089 ** @param [r] RealLength [float] Undocumented
1090 ** @param [r] Radius [float] Undocumented
1091 ** @param [r] RangeHeight [float] Undocumented
1092 ** @param [r] From [float] Undocumented
1093 ** @param [r] To [float] Undocumented
1094 ** @param [r] FromSymbol [char] Undocumented
1095 ** @param [r] ToSymbol [char] Undocumented
1096 ** @param [r] Name2 [const AjPStr] Undocumented
1097 ** @param [r] OriginAngle [float] Undocumented
1098 ** @param [r] NumNames [ajint] Undocumented
1099 ** @param [r] postext [float] Undocumented
1100 ** @param [r] Adjust [ajint] Undocumented
1101 ** @param [r] Colour [ajint] Undocumented
1102 ** @@
1103 ******************************************************************************/
1104 
cirdna_DrawRanges(float xDraw,float yDraw,float RealLength,float Radius,float RangeHeight,float From,float To,char FromSymbol,char ToSymbol,const AjPStr Name2,float OriginAngle,ajint NumNames,float postext,ajint Adjust,ajint Colour)1105 static void cirdna_DrawRanges(float xDraw, float yDraw, float RealLength,
1106 			      float Radius, float RangeHeight, float From,
1107 			      float To, char FromSymbol, char ToSymbol,
1108 			      const AjPStr Name2, float OriginAngle,
1109 			      ajint NumNames, float postext, ajint Adjust,
1110 			      ajint Colour)
1111 {
1112     float StartAngle;
1113     float EndAngle;
1114     float stringLength;
1115     float rRanges = Radius;
1116     float rupper;
1117     float BoundaryLength;
1118     float mmtolen;
1119 
1120     /* radius is 2pi*radius in mm, RealLength in bases */
1121     mmtolen = RealLength/(Radius * (float) 2.0 * (float) 3.1416);
1122 
1123     rupper = rRanges+((float)1.0*RangeHeight/(float)2);
1124 
1125     ajGraphicsSetFgcolour(Colour);
1126 
1127     StartAngle = cirdna_ComputeAngle(RealLength, From, OriginAngle);
1128     EndAngle   = cirdna_ComputeAngle(RealLength, To, OriginAngle);
1129     ajGraphicsDrawarcArc(xDraw, yDraw, rRanges, StartAngle, EndAngle);
1130 
1131     if( RangeHeight>(From-To)/3 )
1132 	BoundaryLength = (From-To)/3;
1133     else
1134 	BoundaryLength = RangeHeight;
1135 
1136     if(FromSymbol=='<')
1137 	cirdna_DrawArrowHeadsOncurve(xDraw, yDraw, RealLength, RangeHeight,
1138 				     BoundaryLength, rRanges, StartAngle,
1139 				     +1);
1140     if(FromSymbol=='>')
1141 	cirdna_DrawArrowHeadsOncurve(xDraw, yDraw, RealLength, RangeHeight,
1142 				     BoundaryLength, rRanges, StartAngle,
1143 				     -1);
1144     if(FromSymbol=='[')
1145 	cirdna_DrawBracketsOncurve(xDraw, yDraw, RealLength, RangeHeight,
1146 				   BoundaryLength, rRanges, StartAngle,
1147 				   +1);
1148     if(FromSymbol==']')
1149 	cirdna_DrawBracketsOncurve(xDraw, yDraw, RealLength, RangeHeight,
1150 				   BoundaryLength, rRanges, StartAngle,
1151 				   -1);
1152     if(FromSymbol=='|')
1153 	cirdna_DrawBarsOncurve(xDraw, yDraw, RangeHeight,
1154 				   rRanges, StartAngle);
1155 
1156     if(ToSymbol=='<')
1157 	cirdna_DrawArrowHeadsOncurve(xDraw, yDraw, RealLength, RangeHeight,
1158 				     BoundaryLength, rRanges, EndAngle,
1159 				     +1);
1160     if(ToSymbol=='>')
1161 	cirdna_DrawArrowHeadsOncurve(xDraw, yDraw, RealLength, RangeHeight,
1162 				     BoundaryLength, rRanges, EndAngle,
1163 				     -1);
1164     if(ToSymbol=='[')
1165 	cirdna_DrawBracketsOncurve(xDraw, yDraw, RealLength, RangeHeight,
1166 				   BoundaryLength, rRanges, EndAngle,
1167 				   +1);
1168     if(ToSymbol==']')
1169 	cirdna_DrawBracketsOncurve(xDraw, yDraw, RealLength, RangeHeight,
1170 				   BoundaryLength, rRanges, EndAngle,
1171 				   -1);
1172     if(ToSymbol=='|')
1173 	cirdna_DrawBarsOncurve(xDraw, yDraw, RangeHeight,
1174 			       rRanges, EndAngle);
1175 
1176     stringLength = mmtolen * cirdna_HorTextPileLengthMax(Name2, NumNames);
1177     StartAngle   = cirdna_ComputeAngle(RealLength, (To+From)/2+stringLength/2,
1178 				       OriginAngle);
1179     EndAngle = cirdna_ComputeAngle(RealLength, (To+From)/2-stringLength/2,
1180 				   OriginAngle);
1181     cirdna_HorTextPile(xDraw, yDraw, rupper+(Adjust*postext), StartAngle,
1182 		       EndAngle, Name2, postext, 1);
1183 
1184     return;
1185 }
1186 
1187 
1188 
1189 
1190 /* @funcstatic cirdna_InterBlocks *********************************************
1191 **
1192 ** draw an InterBlock
1193 **
1194 ** @param [r] xDraw [float] Undocumented
1195 ** @param [r] yDraw [float] Undocumented
1196 ** @param [r] RealLength [float] Undocumented
1197 ** @param [r] Radius [float] Undocumented
1198 ** @param [r] BlockHeight [float] Undocumented
1199 ** @param [r] From [float] Undocumented
1200 ** @param [r] To [float] Undocumented
1201 ** @param [r] OriginAngle [float] Undocumented
1202 ** @param [r] InterSymbol [AjBool] Undocumented
1203 ** @param [r] Colour [ajint] Undocumented
1204 ** @@
1205 ******************************************************************************/
1206 
cirdna_InterBlocks(float xDraw,float yDraw,float RealLength,float Radius,float BlockHeight,float From,float To,float OriginAngle,AjBool InterSymbol,ajint Colour)1207 static void cirdna_InterBlocks(float xDraw, float yDraw, float RealLength,
1208 			       float Radius, float BlockHeight, float From,
1209 			       float To, float OriginAngle,
1210 			       AjBool InterSymbol, ajint Colour)
1211 {
1212     float StartAngle;
1213     float  EndAngle;
1214     float r1Inter;
1215     float r2Inter;
1216 
1217 
1218     r1Inter = Radius+((float)1.0*BlockHeight/(float)2);
1219     r2Inter = r1Inter-BlockHeight;
1220 
1221     ajGraphicsSetFgcolour(Colour);
1222 
1223     StartAngle = cirdna_ComputeAngle(RealLength, To, OriginAngle);
1224     EndAngle   = cirdna_ComputeAngle(RealLength, From, OriginAngle);
1225 
1226     if(InterSymbol)
1227 	ajGraphicsDrawarcArc(xDraw, yDraw, (r1Inter+r2Inter)/2, StartAngle,
1228                              EndAngle);
1229 
1230     return;
1231 }
1232 
1233 
1234 
1235 
1236 /* @funcstatic cirdna_ComputeAngle ********************************************
1237 **
1238 ** compute the angle at the Length position
1239 **
1240 ** @param [r] RealLength [float] Undocumented
1241 ** @param [r] Length [float] Undocumented
1242 ** @param [r] OriginAngle [float] Undocumented
1243 ** @return [float] Undocumented
1244 ** @@
1245 ******************************************************************************/
1246 
cirdna_ComputeAngle(float RealLength,float Length,float OriginAngle)1247 static float cirdna_ComputeAngle(float RealLength, float Length,
1248 				 float OriginAngle)
1249 {
1250     float i;
1251     float j;
1252 
1253     i = Length/RealLength;
1254     j = i * 360 - OriginAngle;
1255 
1256     return 360-j;
1257 }
1258 
1259 
1260 
1261 
1262 /* @funcstatic cirdna_ComputeArc ********************************************
1263 **
1264 ** compute the angle covering the length as a fraction of the real length
1265 **
1266 ** @param [r] RealLength [float] Undocumented
1267 ** @param [r] Length [float] Undocumented
1268 ** @return [float] Undocumented
1269 ** @@
1270 ******************************************************************************/
1271 
cirdna_ComputeArc(float RealLength,float Length)1272 static float cirdna_ComputeArc(float RealLength, float Length)
1273 {
1274     float i;
1275     float j;
1276 
1277     i = Length/RealLength;
1278     j = i * 360;
1279 
1280     return j;
1281 }
1282 
1283 
1284 
1285 
1286 /* @funcstatic cirdna_DrawArrowHeadsOncurve ***********************************
1287 **
1288 ** draw arrowheads on a curve
1289 **
1290 ** @param [r] xDraw [float] Undocumented
1291 ** @param [r] yDraw [float] Undocumented
1292 ** @param [r] RealLength [float] Undocumented
1293 ** @param [r] Height [float] Undocumented
1294 ** @param [r] Length [float] Undocumented
1295 ** @param [r] Radius [float] Undocumented
1296 ** @param [r] Angle [float] Undocumented
1297 ** @param [r] Way [ajint] Undocumented
1298 ** @@
1299 ******************************************************************************/
1300 
cirdna_DrawArrowHeadsOncurve(float xDraw,float yDraw,float RealLength,float Height,float Length,float Radius,float Angle,ajint Way)1301 static void cirdna_DrawArrowHeadsOncurve(float xDraw, float yDraw,
1302 					 float RealLength, float Height,
1303 					 float Length, float Radius,
1304 					 float Angle, ajint Way)
1305 {
1306     float *xy1;
1307     float *xy2;
1308     float pos;
1309     float middle;
1310 
1311 
1312     middle = (float)1.0*Height/(float)2;
1313 
1314     pos = cirdna_ComputeArc(RealLength, Length);
1315     if(pos < 1.0)
1316         pos = 1.0;
1317 
1318     if(Way==1)
1319     {
1320 	xy1 = ajGraphicsCalcCoord(xDraw, yDraw, Radius, Angle);
1321 	xy2 = ajGraphicsCalcCoord(xDraw, yDraw, Radius+middle, Angle+pos);
1322 	ajGraphicsDrawposLine( xy1[0], xy1[1], xy2[0], xy2[1] );
1323 	AJFREE(xy2);
1324 	xy2 = ajGraphicsCalcCoord(xDraw, yDraw, Radius-middle, Angle+pos);
1325 	ajGraphicsDrawposLine( xy1[0], xy1[1], xy2[0], xy2[1] );
1326 	AJFREE(xy1);
1327 	AJFREE(xy2);
1328     }
1329 
1330     if(Way==-1)
1331     {
1332 	xy1 = ajGraphicsCalcCoord(xDraw, yDraw, Radius+middle, Angle-pos);
1333 	xy2 = ajGraphicsCalcCoord(xDraw, yDraw, Radius, Angle);
1334 	ajGraphicsDrawposLine( xy1[0], xy1[1], xy2[0], xy2[1] );
1335 	AJFREE(xy1);
1336 	xy1 = ajGraphicsCalcCoord(xDraw, yDraw, Radius-middle, Angle-pos);
1337 	ajGraphicsDrawposLine( xy1[0], xy1[1], xy2[0], xy2[1] );
1338 	AJFREE(xy1);
1339 	AJFREE(xy2);
1340     }
1341 
1342     return;
1343 }
1344 
1345 
1346 
1347 
1348 /* @funcstatic cirdna_DrawBracketsOncurve *************************************
1349 **
1350 ** draw brackets on a curve
1351 **
1352 ** @param [r] xDraw [float] Undocumented
1353 ** @param [r] yDraw [float] Undocumented
1354 ** @param [r] RealLength [float] Undocumented
1355 ** @param [r] Height [float] Undocumented
1356 ** @param [r] Length [float] Undocumented
1357 ** @param [r] Radius [float] Undocumented
1358 ** @param [r] Angle [float] Undocumented
1359 ** @param [r] Way [ajint] Undocumented
1360 ** @@
1361 ******************************************************************************/
1362 
cirdna_DrawBracketsOncurve(float xDraw,float yDraw,float RealLength,float Height,float Length,float Radius,float Angle,ajint Way)1363 static void cirdna_DrawBracketsOncurve(float xDraw, float yDraw,
1364 				       float RealLength, float Height,
1365 				       float Length, float Radius,
1366 				       float Angle, ajint Way)
1367 {
1368     float *xy1;
1369     float *xy2;
1370     float pos;
1371     float middle;
1372 
1373     middle = (float)1.0*Height/(float)2;
1374 
1375     pos = cirdna_ComputeArc(RealLength, Length);
1376     if(pos < 1.0)
1377         pos = 1.0;
1378 
1379     if(Way==1)
1380     {
1381 	xy1 = ajGraphicsCalcCoord(xDraw, yDraw, Radius+middle, Angle);
1382 	xy2 = ajGraphicsCalcCoord(xDraw, yDraw, Radius-middle, Angle);
1383 	ajGraphicsDrawposLine(xy1[0], xy1[1], xy2[0], xy2[1]);
1384 	AJFREE(xy1);
1385 	AJFREE(xy2);
1386 
1387 	ajGraphicsDrawarcArc(xDraw, yDraw, Radius+middle, Angle-pos, Angle);
1388 	ajGraphicsDrawarcArc(xDraw, yDraw, Radius-middle, Angle-pos, Angle);
1389     }
1390 
1391     if(Way==-1)
1392     {
1393 	xy1 = ajGraphicsCalcCoord(xDraw, yDraw, Radius+middle, Angle);
1394 	xy2 = ajGraphicsCalcCoord(xDraw, yDraw, Radius-middle, Angle);
1395 	ajGraphicsDrawposLine(xy1[0], xy1[1], xy2[0], xy2[1]);
1396 	AJFREE(xy1);
1397 	AJFREE(xy2);
1398 	ajGraphicsDrawarcArc(xDraw, yDraw, Radius+middle, Angle, Angle+pos);
1399 	ajGraphicsDrawarcArc(xDraw, yDraw, Radius-middle, Angle, Angle+pos);
1400     }
1401 
1402     return;
1403 }
1404 
1405 
1406 
1407 
1408 /* @funcstatic cirdna_DrawBarsOncurve *****************************************
1409 **
1410 ** draw bars on a curve
1411 **
1412 ** @param [r] xDraw [float] Undocumented
1413 ** @param [r] yDraw [float] Undocumented
1414 ** @param [r] Height [float] Undocumented
1415 ** @param [r] Radius [float] Undocumented
1416 ** @param [r] Angle [float] Undocumented
1417 ** @return [void]
1418 ** @@
1419 ******************************************************************************/
1420 
cirdna_DrawBarsOncurve(float xDraw,float yDraw,float Height,float Radius,float Angle)1421 static void cirdna_DrawBarsOncurve(float xDraw, float yDraw,
1422 				   float Height, float Radius,
1423 				   float Angle)
1424 {
1425     float *xy1;
1426     float *xy2;
1427     float middle;
1428 
1429     middle = (float)1.0*Height/(float)2;
1430 
1431     xy1 = ajGraphicsCalcCoord(xDraw, yDraw, Radius+middle, Angle);
1432     xy2 = ajGraphicsCalcCoord(xDraw, yDraw, Radius-middle, Angle);
1433     ajGraphicsDrawposLine( xy1[0], xy1[1], xy2[0], xy2[1] );
1434     AJFREE(xy1);
1435     AJFREE(xy2);
1436 
1437     return;
1438 }
1439 
1440 
1441 
1442 
1443 /* @funcstatic cirdna_HorTextPile *********************************************
1444 **
1445 ** write a pile of horizontal text strings
1446 **
1447 ** @param [r] x [float] Undocumented
1448 ** @param [r] y [float] Undocumented
1449 ** @param [r] Radius [float] Undocumented
1450 ** @param [r] StartAngle [float] Undocumented
1451 ** @param [r] EndAngle [float] Undocumented
1452 ** @param [r] Name2 [const AjPStr] Undocumented
1453 ** @param [r] postext [float] Undocumented
1454 ** @param [r] NumNames [ajint] Undocumented
1455 ** @@
1456 ******************************************************************************/
1457 
cirdna_HorTextPile(float x,float y,float Radius,float StartAngle,float EndAngle,const AjPStr Name2,float postext,ajint NumNames)1458 static void cirdna_HorTextPile(float x, float y, float Radius,
1459 			       float StartAngle, float EndAngle,
1460 			       const AjPStr Name2, float postext,
1461 			       ajint NumNames)
1462 {
1463     float rupper;
1464     float stringHeight;
1465     float totalHeight;
1466     const AjPStr token;
1467     ajint i;
1468 
1469     totalHeight = Radius+postext;
1470     for(i=0; i<NumNames; i++)
1471     {
1472 	if(i==0)
1473 	    token = ajStrParseC(Name2, ";");
1474 	else
1475 	    token = ajStrParseC(NULL, ";");
1476 	stringHeight = ajGraphicsCalcTextheight();
1477 	rupper = totalHeight+stringHeight;
1478 	if(token && ajStrGetPtr(token))
1479 	    ajGraphicsDrawarcTextJustify(x, y,
1480                                          (totalHeight+rupper)/2, StartAngle,
1481                                          EndAngle, ajStrGetPtr(token), 0.5);
1482 	totalHeight+=(stringHeight+postext);
1483     }
1484 
1485     return;
1486 }
1487 
1488 
1489 
1490 
1491 /* @funcstatic cirdna_HorTextPileHeight ***************************************
1492 **
1493 ** compute the height of a pile of horizontal text strings
1494 **
1495 ** @param [r] postext [float] Undocumented
1496 ** @param [r] NumNames [ajint] Undocumented
1497 ** @return [float] Undocumented
1498 ** @@
1499 ******************************************************************************/
1500 
cirdna_HorTextPileHeight(float postext,ajint NumNames)1501 static float cirdna_HorTextPileHeight(float postext, ajint NumNames)
1502 {
1503     float stringHeight;
1504     float totalHeight;
1505     ajint i;
1506 
1507     totalHeight = 0.0;
1508     for(i=0; i<NumNames; i++)
1509     {
1510 	stringHeight = ajGraphicsCalcTextheight();
1511 	totalHeight += (stringHeight+postext);
1512     }
1513 
1514     return totalHeight;
1515 }
1516 
1517 
1518 
1519 
1520 /* @funcstatic cirdna_HorTextPileLengthMax ************************************
1521 **
1522 ** compute the maximum length of a pile of horizontal text strings
1523 ** (this is the length of the longest string)
1524 **
1525 ** @param [r] Name2 [const AjPStr] Undocumented
1526 ** @param [r] NumNames [ajint] Undocumented
1527 ** @return [float] Undocumented
1528 ** @@
1529 ******************************************************************************/
1530 
cirdna_HorTextPileLengthMax(const AjPStr Name2,ajint NumNames)1531 static float cirdna_HorTextPileLengthMax(const AjPStr Name2, ajint NumNames)
1532 {
1533     float stringLength;
1534     float maxLength;
1535     ajint i;
1536     const AjPStr token;
1537 
1538     maxLength = 0.0;
1539     for(i=0; i<NumNames; i++)
1540     {
1541 	if(i==0)
1542 	    token = ajStrParseC(Name2, ";");
1543 	else
1544 	    token = ajStrParseC(NULL, ";");
1545 	stringLength = ajGraphicsCalcTextlengthS(token);
1546 
1547 	if(stringLength>maxLength)
1548 	    maxLength = stringLength;
1549     }
1550 
1551     return maxLength;
1552 }
1553 
1554 
1555 
1556 
1557 /* @funcstatic cirdna_ReadInput ***********************************************
1558 **
1559 ** read the beginning of the input file
1560 **
1561 ** @param [u] infile [AjPFile] Undocumented
1562 ** @param [w] Start [float*] Undocumented
1563 ** @param [w] End [float*] Undocumented
1564 ** @return [AjBool] True if input file is valid
1565 ** @@
1566 ******************************************************************************/
1567 
cirdna_ReadInput(AjPFile infile,float * Start,float * End)1568 static AjBool cirdna_ReadInput(AjPFile infile,
1569                                float *Start, float *End)
1570 {
1571     AjPStr line;
1572 
1573     AjBool foundstart = ajFalse;
1574     AjBool foundend   = ajFalse;
1575 
1576     line = ajStrNew();
1577     while(ajReadlineTrim(infile, &line))
1578     {
1579 	/* read the start and end positions */
1580 	if(ajStrPrefixC(line, "Start"))
1581         {
1582             foundstart = ajTrue;
1583 	    if(sscanf(ajStrGetPtr(line), "%*s%f", Start) != 1)
1584                 return ajFalse;
1585         }
1586 
1587 	if(ajStrPrefixC(line, "End"))
1588         {
1589             foundend = ajTrue;
1590 	    if(sscanf(ajStrGetPtr(line), "%*s%f", End) != 1)
1591             {
1592                 ajStrDel(&line);
1593                 return ajFalse;
1594             }
1595         }
1596     }
1597 
1598     ajStrDel(&line);
1599 
1600     if(!foundstart || !foundend)
1601     {
1602         ajWarn("Missing Start and/or End line(s) in input file");
1603         return ajFalse;
1604     }
1605 
1606 
1607     return ajTrue;;
1608 }
1609 
1610 
1611 
1612 
1613 /* @funcstatic cirdna_ReadGroup ***********************************************
1614 **
1615 ** read a group
1616 **
1617 ** @param [u] infile [AjPFile] Undocumented
1618 ** @param [r] maxlabels [ajint] Undocumented
1619 ** @param [w] From [float*] From position array
1620 ** @param [w] To [float*] To position array
1621 ** @param [w] Name2 [AjPStr*] Array of sequence names
1622 ** @param [w] FromSymbol [char*] Undocumented
1623 ** @param [w] ToSymbol [char*] Undocumented
1624 ** @param [w] Style2 [AjPStr *] Undocumented
1625 ** @param [w] NumLabels [ajint*] Undocumented
1626 ** @param [w] NumNames [ajint*] Array of ajints
1627 ** @param [w] Colour [ajint*] Array of colour codes
1628 ** @return [AjPStr] Undocumented
1629 ******************************************************************************/
1630 
1631 
cirdna_ReadGroup(AjPFile infile,ajint maxlabels,float * From,float * To,AjPStr * Name2,char * FromSymbol,char * ToSymbol,AjPStr * Style2,ajint * NumLabels,ajint * NumNames,ajint * Colour)1632 static AjPStr cirdna_ReadGroup(AjPFile infile, ajint maxlabels,
1633 			       float* From, float* To,
1634 			       AjPStr *Name2, char *FromSymbol,
1635 			       char *ToSymbol, AjPStr *Style2,
1636 			       ajint *NumLabels, ajint *NumNames,
1637 			       ajint *Colour)
1638 {
1639     ajint i;
1640     ajint j;
1641     AjPStr GroupName;
1642     AjPStr line;
1643     const AjPStr token;
1644     char *style;
1645     ajlong pos;
1646 
1647     line      = ajStrNew();
1648     GroupName = ajStrNew();
1649 
1650     style = (char *)AJALLOC( 10*sizeof(char) );
1651 
1652     /* read the group's name */
1653     pos = ajFileResetPos(infile);
1654     while(ajReadlineTrim(infile, &GroupName))
1655     {
1656 	token = ajStrParseC(GroupName, " \n\t\r\f");
1657 	if(ajStrGetLen(token)!=0)
1658 	{
1659 	    if(ajStrMatchCaseC(GroupName, "label") ||
1660 	       ajStrMatchCaseC(GroupName, "endgroup"))
1661 		ajStrAssignC(&GroupName, " ");
1662 
1663 	    if(ajStrGetLen(GroupName)>20)
1664 		ajStrCutRange( &GroupName, 20, ajStrGetLen(GroupName)-1 );
1665 	    break;
1666 	}
1667     }
1668 
1669     i = 0;
1670     ajFileSeek(infile, pos, 0);
1671     while(ajReadlineTrim(infile, &line))
1672     {
1673 	token = ajStrParseC(line, " \n\t\r\f");
1674 	if(ajStrGetLen(token)!=0)
1675 	{
1676 	    if(ajStrPrefixC(line, "endgroup"))
1677 		break;
1678 	    else
1679 	    {
1680 		/* read the group's label(s) */
1681 		if(ajStrPrefixC(line, "label"))
1682 		{
1683 		    while(ajReadlineTrim(infile, &line))
1684 		    {
1685 			if (i == maxlabels)
1686 			    ajWarn("Too many labels (maxlabels=%d) in input",
1687 				   maxlabels);
1688 			token = ajStrParseC(line, " \n\t\r\f");
1689 			if(ajStrGetLen(token)!=0)
1690 			{
1691 			    if (i < maxlabels)
1692 			    {
1693 				FromSymbol[i] = '<';
1694 				ToSymbol[i] = '>';
1695 				sscanf( ajStrGetPtr(line), "%s", style );
1696 				if(ajCharMatchCaseC(style, "Tick"))
1697 				    sscanf( ajStrGetPtr(line), "%*s %f %d %*c",
1698 					   &From[i], &Colour[i] );
1699 				if(ajCharMatchCaseC(style, "Block"))
1700 				    sscanf( ajStrGetPtr(line), "%*s %f %f %d %*c",
1701 					   &To[i], &From[i], &Colour[i] );
1702 				if(ajCharMatchCaseC(style, "Range"))
1703 				    sscanf( ajStrGetPtr(line),
1704 					   "%*s %f %f %c %c %d %*c",
1705 					   &To[i], &From[i],
1706 					   &FromSymbol[i], &ToSymbol[i],
1707 					   &Colour[i] );
1708 				ajStrAssignC(&Style2[i], style);
1709 			    }
1710 			    break;
1711 			}
1712 		    }
1713 
1714 		    j = 0;
1715 
1716 		    /* read the label's name(s) */
1717 		    while(ajReadlineTrim(infile, &line))
1718 		    {
1719 			token = ajStrParseC(line, " \n\t\r\f");
1720 			if(ajStrGetLen(token)!=0)
1721 			{
1722 			    if(ajStrPrefixC(line, "endlabel"))
1723 				break;
1724 			    else
1725 			    {
1726 				if (i < maxlabels)
1727 				{
1728 				    ajStrAppendS(&Name2[i], line);
1729 				    ajStrAppendC(&Name2[i], ";");
1730 				    j++;
1731 				}
1732 			    }
1733 			}
1734 		    }
1735 		    if (i < maxlabels)
1736 			NumNames[i] = j;
1737 		    i++;
1738 		}
1739 	    }
1740 	}
1741     }
1742     if (i < maxlabels)
1743 	*NumLabels = i;
1744     else
1745 	*NumLabels = maxlabels;
1746 
1747     AJFREE(style);
1748     ajStrDel(&line);
1749 
1750     return GroupName;
1751 }
1752 
1753 
1754 
1755 
1756 /* @funcstatic cirdna_TextGroup ***********************************************
1757 **
1758 **  compute the character size that fits all elements of a group
1759 **  provided that the height and the length of all strings are at most
1760 **  TextHeight and TextLength, respectively
1761 **
1762 ** @param [r] TextHeight [float] Undocumented
1763 ** @param [r] TextLength [float] Undocumented
1764 ** @param [r] Name2 [AjPStr const *] Undocumented
1765 ** @param [r] NumLabels [ajint] Undocumented
1766 ** @param [r] NumNames [const ajint*] Undocumented
1767 ** @param [r] Style2 [AjPStr const *] Undocumented
1768 ** @param [r] From [const float*] Undocumented
1769 ** @param [r] To [const float*] Undocumented
1770 ** @param [r] PosTicks [const AjPStr] Undocumented
1771 ** @return [float] Undocumented
1772 ******************************************************************************/
cirdna_TextGroup(float TextHeight,float TextLength,AjPStr const * Name2,ajint NumLabels,const ajint * NumNames,AjPStr const * Style2,const float * From,const float * To,const AjPStr PosTicks)1773 static float cirdna_TextGroup(float TextHeight, float TextLength,
1774 			      AjPStr const *Name2, ajint NumLabels,
1775 			      const ajint *NumNames,
1776 			      AjPStr const *Style2,
1777 			      const float* From,
1778 			      const float* To,
1779 			      const AjPStr PosTicks)
1780 {
1781     ajint i;
1782     ajint j;
1783     float charsize;
1784     float  minsize = 100.0;
1785     const AjPStr token;
1786 
1787     for(i=0; i<NumLabels; i++)
1788     {
1789 	for(j=0; j<NumNames[i]; j++)
1790 	{
1791 	    if(!(ajStrMatchCaseC(Style2[i], "Tick") &&
1792 		  ajStrMatchCaseC(PosTicks, "Out")))
1793 	    {
1794 		if(j==0)
1795 		    token = ajStrParseC(Name2[i], ";");
1796 		else
1797 		    token = ajStrParseC(NULL, ";");
1798 		if(ajStrMatchCaseC(Style2[i], "Block") &&
1799 		   ((From[i]-To[i])<TextLength))
1800 		    charsize = ajGraphicsCalcCharsize(0, 0, From[i]-To[i],
1801                                                       From[i]-To[i],
1802                                                       ajStrGetPtr(token),
1803                                                       TextHeight);
1804 		else
1805 		    charsize = ajGraphicsCalcCharsize(0, 0, TextLength,
1806                                                       TextLength,
1807                                                       ajStrGetPtr(token),
1808                                                       TextHeight);
1809 		if(charsize < minsize)
1810 		    minsize = charsize;
1811 	    }
1812 	}
1813     }
1814 
1815     return minsize;
1816 }
1817 
1818 
1819 
1820 
1821 /* @funcstatic cirdna_TextGroupStr ********************************************
1822 **
1823 **  compute the character size that fits all elements of a group provided that
1824 **  the height and the length of all strings are multiplied by TextCoef
1825 **
1826 ** @param [r] Name2 [AjPStr const *] Undocumented
1827 ** @param [r] NumLabels [ajint] Undocumented
1828 ** @param [r] NumNames [const ajint*] Undocumented
1829 ** @param [r] TextCoef [float] Undocumented
1830 ** @param [r] Style2 [AjPStr const *] Undocumented
1831 ** @param [r] From [const float*] Undocumented
1832 ** @param [r] To [const float*] Undocumented
1833 ** @param [r] PosTicks [const AjPStr] Undocumented
1834 ** @return [float] Undocumented
1835 ******************************************************************************/
cirdna_TextGroupStr(AjPStr const * Name2,ajint NumLabels,const ajint * NumNames,float TextCoef,AjPStr const * Style2,const float * From,const float * To,const AjPStr PosTicks)1836 static float cirdna_TextGroupStr(AjPStr const *Name2, ajint NumLabels,
1837 				 const ajint *NumNames,
1838 				 float TextCoef, AjPStr const *Style2,
1839 				 const float* From, const float* To,
1840 				 const AjPStr PosTicks)
1841 {
1842     ajint i;
1843     ajint j;
1844     float charsize;
1845     float minsize = 100.0;
1846     float stringLength;
1847     float stringHeight;
1848     const AjPStr token;
1849 
1850     for(i=0; i<NumLabels; i++)
1851     {
1852 	for(j=0; j<NumNames[i]; j++)
1853 	{
1854 	    if(!(ajStrMatchCaseC(Style2[i], "Tick") &&
1855 		  ajStrMatchCaseC(PosTicks, "Out")))
1856 	    {
1857 		if(j==0)
1858 		    token = ajStrParseC(Name2[i], ";");
1859 		else
1860 		    token = ajStrParseC(NULL, ";");
1861 		stringLength = ajGraphicsCalcTextlengthS(token);
1862 		stringHeight = ajGraphicsCalcTextheight();
1863 		if(ajStrMatchCaseC(Style2[i], "Block") &&
1864 		   ((From[i]-To[i])<stringLength))
1865 		    charsize = ajGraphicsCalcCharsize(0, 0,
1866                                                       (From[i]-To[i])/TextCoef,
1867                                                       (From[i]-To[i])/TextCoef,
1868                                                       ajStrGetPtr(token),
1869                                                       stringHeight/TextCoef);
1870 		else
1871 		    charsize = ajGraphicsCalcCharsize(0, 0,
1872                                                       stringLength/TextCoef,
1873                                                       stringLength/TextCoef,
1874                                                       ajStrGetPtr(token),
1875                                                       stringHeight/TextCoef);
1876 		if(charsize < minsize)
1877 		    minsize = charsize;
1878 	    }
1879 	}
1880     }
1881 
1882     return minsize;
1883 }
1884 
1885 
1886 
1887 
1888 /* @funcstatic cirdna_HeightGroup *********************************************
1889 **
1890 ** compute the height of a group depending on what's in it
1891 **
1892 ** @param [r] postext [float] Undocumented
1893 ** @param [r] TickHeight [float] Undocumented
1894 ** @param [r] BlockHeight [float] Undocumented
1895 ** @param [r] RangeHeight [float] Undocumented
1896 ** @param [r] Style2 [AjPStr const *] Undocumented
1897 ** @param [r] NumLabels [ajint] Undocumented
1898 ** @param [r] PosTicks [const AjPStr] Undocumented
1899 ** @param [r] PosBlocks [const AjPStr] Undocumented
1900 ** @param [r] Adjust [ajint] Undocumented
1901 ** @return [float] Undocumented
1902 ******************************************************************************/
1903 
cirdna_HeightGroup(float postext,float TickHeight,float BlockHeight,float RangeHeight,AjPStr const * Style2,ajint NumLabels,const AjPStr PosTicks,const AjPStr PosBlocks,ajint Adjust)1904 static float cirdna_HeightGroup(float postext,
1905 				float TickHeight, float BlockHeight,
1906 				float RangeHeight,
1907 				AjPStr const *Style2, ajint NumLabels,
1908 				const AjPStr PosTicks,
1909 				const AjPStr PosBlocks, ajint Adjust)
1910 {
1911     ajint i;
1912     float GroupHeight;
1913     float uheight;
1914     float umaxheight = 0.0;
1915     float lheight;
1916     float lmaxheight = 0.0;
1917 
1918 
1919     for(i=0; i<NumLabels; i++)
1920     {
1921 	if(ajStrMatchCaseC(Style2[i], "Tick") &&
1922 	   ajStrMatchCaseC(PosTicks, "In"))
1923 	{
1924 	    uheight = TickHeight;
1925 	    lheight = 0.0;
1926 	    uheight+=cirdna_HorTextPileHeight(postext, 1);
1927 
1928 	    if(uheight > umaxheight)
1929 		umaxheight = uheight;
1930 
1931 	    if(lheight > lmaxheight)
1932 		lmaxheight = lheight;
1933 	}
1934 
1935 	if(ajStrMatchCaseC(Style2[i], "Block"))
1936 	{
1937 	    uheight = (float)1.0*BlockHeight/(float)2;
1938 	    lheight = (float)1.0*BlockHeight/(float)2;
1939 
1940 	    if(ajStrMatchCaseC(PosBlocks, "Out"))
1941 		uheight+=cirdna_HorTextPileHeight(postext, 1);
1942 
1943 	    if(uheight > umaxheight)
1944 		umaxheight = uheight;
1945 
1946 	    if( lheight > lmaxheight )
1947 		lmaxheight = lheight;
1948 	}
1949 
1950 	if(ajStrMatchCaseC(Style2[i], "Range"))
1951 	{
1952 	    uheight = (float)1.0*RangeHeight/2;
1953 	    lheight = (float)1.0*RangeHeight/2;
1954 	    uheight+=cirdna_HorTextPileHeight(postext, 1);
1955 
1956 	    if(uheight > umaxheight)
1957 		umaxheight = uheight;
1958 
1959 	    if(lheight > lmaxheight)
1960 		lmaxheight = lheight;
1961 	}
1962     }
1963 
1964     GroupHeight = umaxheight+lmaxheight+(Adjust*postext);
1965 
1966     return GroupHeight;
1967 }
1968 
1969 
1970 
1971 
1972 /* @funcstatic cirdna_OverlapTextGroup ****************************************
1973 **
1974 ** find whether horizontal text strings overlap within a group
1975 **
1976 ** @param [r] Name2 [AjPStr const *] Undocumented
1977 ** @param [r] Style2 [AjPStr const *] Undocumented
1978 ** @param [r] NumLabels [ajint] Undocumented
1979 ** @param [r] From [const float*] Undocumented
1980 ** @param [r] To [const float*] Undocumented
1981 ** @param [r] Start [float] Undocumented
1982 ** @param [r] End [float] Undocumented
1983 ** @param [r] PosTicks [const AjPStr] Undocumented
1984 ** @param [w] Adjust [ajint*] Array elements written
1985 ** @return [ajint] Undocumented
1986 ******************************************************************************/
1987 
cirdna_OverlapTextGroup(AjPStr const * Name2,AjPStr const * Style2,ajint NumLabels,const float * From,const float * To,float Start,float End,const AjPStr PosTicks,ajint * Adjust)1988 static ajint cirdna_OverlapTextGroup(AjPStr const *Name2, AjPStr const *Style2,
1989 				     ajint NumLabels,
1990 				     const float* From, const float* To,
1991 				     float Start, float End,
1992 				     const AjPStr PosTicks, ajint *Adjust)
1993 {
1994     ajint i;
1995     ajint j;
1996     ajint AdjustMax;
1997     const AjPStr token;
1998     static ajint maxnumlabels=0;
1999     float llim;
2000     float ulim;
2001     float stringLength;
2002 
2003     if (NumLabels > maxnumlabels)
2004     {
2005 	maxnumlabels = NumLabels;
2006 	AJCRESIZE(cirdnaFromText, maxnumlabels);
2007 	AJCRESIZE(cirdnaToText, maxnumlabels);
2008     }
2009     /* compute the length of the horizontal strings */
2010     for(i=0; i<NumLabels; i++)
2011     {
2012 	if(ajStrMatchCaseC(Style2[i], "Tick") &&
2013 	   ajStrMatchCaseC(PosTicks, "In"))
2014 	{
2015 	    token = ajStrParseC(Name2[i], ";");
2016 	    stringLength = ajGraphicsCalcTextlengthS(token);
2017 	    ulim = From[i]+stringLength/2;
2018 	    if(ulim>(End-Start-1))
2019 		ulim = End-Start-1-ulim;
2020 	    llim = From[i]-stringLength/2;
2021 	    if((ulim<0.0) || (llim<0.0))
2022 	    {
2023 		cirdnaFromText[i] = llim;
2024 		cirdnaToText[i] = ulim;
2025 	    }
2026 	    else
2027 	    {
2028 		cirdnaFromText[i] = ulim;
2029 		cirdnaToText[i] = llim;
2030 	    }
2031 	}
2032 	else if(ajStrMatchCaseC(Style2[i], "Block"))
2033 	{
2034 	    token = ajStrParseC(Name2[i], ";");
2035 	    stringLength = ajGraphicsCalcTextlengthS(token);
2036 	    ulim = (To[i]+From[i])/2+stringLength/2;
2037 	    if(ulim>(End-Start-1))
2038 		ulim = End-Start-1-ulim;
2039 	    llim = (To[i]+From[i])/2-stringLength/2;
2040 	    if((ulim<0.0) || (llim<0.0))
2041 	    {
2042 		cirdnaFromText[i] = llim;
2043 		cirdnaToText[i] = ulim;
2044 	    }
2045 	    else
2046 	    {
2047 		cirdnaFromText[i] = ulim;
2048 		cirdnaToText[i] = llim;
2049 	    }
2050 	}
2051 	else if(ajStrMatchCaseC(Style2[i], "Range"))
2052 	{
2053 	    token = ajStrParseC(Name2[i], ";");
2054 	    stringLength = ajGraphicsCalcTextlengthS(token);
2055 	    ulim = (To[i]+From[i])/2+stringLength/2;
2056 	    if(ulim>(End-Start-1))
2057 		ulim = End-Start-1-ulim;
2058 	    llim = (To[i]+From[i])/2-stringLength/2;
2059 	    if((ulim<0.0) || (llim<0.0))
2060 	    {
2061 		cirdnaFromText[i] = llim;
2062 		cirdnaToText[i] = ulim;
2063 	    }
2064 	    else
2065 	    {
2066 		cirdnaFromText[i] = ulim;
2067 		cirdnaToText[i] = llim;
2068 	    }
2069 	}
2070 	else
2071 	    cirdnaFromText[i] =  cirdnaToText[i] = 0.0;
2072     }
2073 
2074     /*
2075     **  if some strings overlap, the position of the overlapping strings
2076     **  is moved upwards by Adjust
2077     */
2078     for(i=0; i<NumLabels; i++)
2079 	Adjust[i] = 0;
2080 
2081     for(i=0; i<NumLabels; i++)
2082     {
2083 	for(j=0; j<NumLabels; j++)
2084 	{
2085 	    if((i!=j) && (Adjust[i]==Adjust[j]))
2086 	    {
2087 		if(j>i)
2088 		{
2089 		    if(cirdnaFromText[i]<0.0)
2090 		    {
2091 			ulim = End-Start-1+cirdnaFromText[i];
2092 			if((cirdnaToText[j]<=ulim) &&
2093 			   (cirdnaFromText[j]>=ulim))
2094 			    Adjust[j] = Adjust[i]+1;
2095 		    }
2096 		    if((cirdnaToText[j]<=cirdnaFromText[i]) &&
2097 		       (cirdnaFromText[j]>=cirdnaFromText[i]))
2098 			Adjust[j] = Adjust[i]+1;
2099 		}
2100 
2101 		if(i>j)
2102 		{
2103 		    if(cirdnaFromText[j]<0.0)
2104 		    {
2105 			ulim = End-Start-1+cirdnaFromText[j];
2106 			if((cirdnaToText[i]<=ulim) &&
2107 			   (cirdnaFromText[i]>=ulim))
2108 			    Adjust[i] = Adjust[j]+1;
2109 		    }
2110 
2111 		    if((cirdnaToText[i]<=cirdnaFromText[j]) &&
2112 		       (cirdnaFromText[i]>=cirdnaFromText[j]))
2113 			Adjust[i] = Adjust[j]+1;
2114 		}
2115 	    }
2116 	}
2117     }
2118 
2119     AdjustMax = 0;
2120     for(i=0; i<NumLabels; i++)
2121 	if(Adjust[i]>AdjustMax)
2122 	    AdjustMax = Adjust[i];
2123 
2124     return AdjustMax;
2125 }
2126 
2127 
2128 
2129 
2130 /* @funcstatic cirdna_OverlapTickRuler ****************************************
2131 **
2132 ** find whether group ticks and ruler's ticks overlap
2133 **
2134 ** @param [r] NumGroups [ajint] Undocumented
2135 ** @param [r] NumLabels [const ajint*] Undocumented
2136 ** @param [r] From [float* const *] Undocumented
2137 ** @param [r] PosTicks [const AjPStr] Undocumented
2138 ** @param [r] RulerTick [ajint] Undocumented
2139 ** @return [AjBool] Undocumented
2140 ******************************************************************************/
2141 
cirdna_OverlapTickRuler(ajint NumGroups,const ajint * NumLabels,float * const * From,const AjPStr PosTicks,ajint RulerTick)2142 static AjBool cirdna_OverlapTickRuler(ajint NumGroups, const ajint *NumLabels,
2143 				      float* const * From,
2144 				      const AjPStr PosTicks,
2145 				      ajint RulerTick)
2146 {
2147     ajint i;
2148     ajint j;
2149     ajint overlap = 0;
2150 
2151     for(i=0; i<NumGroups; i++)
2152 	for(j=0; j<NumLabels[i]; j++)
2153 	{
2154 	    if(ajStrMatchCaseC(Style[i][j], "Tick") &&
2155 	       ajStrMatchCaseC(PosTicks, "Out") &&
2156 	       From[i][j]==RulerTick)
2157 	    {
2158 		overlap = 1;
2159 		break;
2160 	    }
2161 	}
2162 
2163     if(overlap==0)
2164 	return ajFalse;
2165 
2166     return ajTrue;
2167 }
2168 
2169 
2170 
2171 
2172 /* @funcstatic cirdna_DrawGroup ***********************************************
2173 **
2174 ** draw a group
2175 **
2176 ** @param [r] xDraw [float] Undocumented
2177 ** @param [r] yDraw [float] Undocumented
2178 ** @param [r] posblock [float] Undocumented
2179 ** @param [r] posrange [float] Undocumented
2180 ** @param [r] postext [float] Undocumented
2181 ** @param [r] TickHeight [float] Undocumented
2182 ** @param [r] BlockHeight [float] Undocumented
2183 ** @param [r] RangeHeight [float] Undocumented
2184 ** @param [r] RealLength [float] Undocumented
2185 ** @param [r] Radius [float] Undocumented
2186 ** @param [r] RadiusMax [float] Undocumented
2187 ** @param [r] From [const float*] Undocumented
2188 ** @param [r] To [const float*] Undocumented
2189 ** @param [r] Name2 [AjPStr const *] Undocumented
2190 ** @param [r] FromSymbol [const char*] Undocumented
2191 ** @param [r] ToSymbol [const char*] Undocumented
2192 ** @param [r] Style2 [AjPStr const *] Undocumented
2193 ** @param [r] InterSymbol [AjBool] Undocumented
2194 ** @param [r] InterTicks [AjBool] Undocumented
2195 ** @param [r] NumLabels [ajint] Undocumented
2196 ** @param [r] OriginAngle [float] Undocumented
2197 ** @param [r] NumNames [const ajint*] Undocumented
2198 ** @param [r] PosTicks [const AjPStr] Undocumented
2199 ** @param [r] PosBlocks [const AjPStr] Undocumented
2200 ** @param [r] Adjust [const ajint*] Undocumented
2201 ** @param [r] InterColour [ajint] Undocumented
2202 ** @param [r] Colour [const ajint*] Undocumented
2203 ** @param [r] BlockType [const AjPStr] Undocumented
2204 ** @return [void]
2205 ******************************************************************************/
2206 
cirdna_DrawGroup(float xDraw,float yDraw,float posblock,float posrange,float postext,float TickHeight,float BlockHeight,float RangeHeight,float RealLength,float Radius,float RadiusMax,const float * From,const float * To,AjPStr const * Name2,const char * FromSymbol,const char * ToSymbol,AjPStr const * Style2,AjBool InterSymbol,AjBool InterTicks,ajint NumLabels,float OriginAngle,const ajint * NumNames,const AjPStr PosTicks,const AjPStr PosBlocks,const ajint * Adjust,ajint InterColour,const ajint * Colour,const AjPStr BlockType)2207 static void cirdna_DrawGroup(float xDraw, float yDraw, float posblock,
2208 			     float posrange, float postext, float TickHeight,
2209 			     float BlockHeight, float RangeHeight,
2210 			     float RealLength, float Radius, float RadiusMax,
2211 			     const float* From, const float* To,
2212 			     AjPStr const *Name2,
2213 			     const char *FromSymbol, const char *ToSymbol,
2214 			     AjPStr const *Style2,
2215 			     AjBool InterSymbol, AjBool InterTicks,
2216 			     ajint NumLabels,
2217 			     float OriginAngle, const ajint *NumNames,
2218 			     const AjPStr PosTicks, const AjPStr PosBlocks,
2219 			     const ajint *Adjust,
2220 			     ajint InterColour, const ajint *Colour,
2221 			     const AjPStr BlockType)
2222 {
2223     ajint i;
2224     ajint j;
2225     ajint  NumBlocks;
2226 
2227     if (NumLabels > cirdnaMaxinter)
2228     {
2229 	cirdnaMaxinter = NumLabels;
2230 	AJCRESIZE(cirdnaInter, cirdnaMaxinter);
2231     }
2232 
2233     /* draw all labels */
2234     for(j=0, i=0; i<NumLabels; i++)
2235     {
2236 	if(ajStrMatchCaseC(Style2[i], "Tick"))
2237 	{
2238 	    if(ajStrMatchCaseC(PosTicks, "In"))
2239 	    {
2240 		cirdna_DrawTicks(xDraw, yDraw, RealLength, Radius, TickHeight,
2241 				 From[i], Name2[i], OriginAngle,
2242 				 postext, PosTicks, NumNames[i],
2243 				 Adjust[i], Colour[i]);
2244 		if(InterTicks)
2245 		    ajGraphicsDrawposCircle(xDraw, yDraw, Radius);
2246 	    }
2247 	    else
2248 		cirdna_DrawTicks(xDraw, yDraw, RealLength, RadiusMax,
2249 				 TickHeight, From[i], Name2[i], OriginAngle,
2250 				 postext, PosTicks,
2251 				 NumNames[i], Adjust[i], Colour[i]);
2252 	}
2253 
2254 	if( ajStrMatchCaseC(Style2[i], "Block") )
2255 	{
2256 	    cirdna_DrawBlocks(xDraw, yDraw, RealLength, Radius-posblock,
2257 			      (ajint)BlockHeight, From[i], To[i],
2258 			      Name2[i], postext,
2259 			      OriginAngle, PosBlocks, NumNames[i], Adjust[i],
2260 			      Colour[i], BlockType);
2261 	    cirdnaInter[j++] = i;
2262 	}
2263 
2264 	if(ajStrMatchCaseC(Style2[i], "Range"))
2265 	    cirdna_DrawRanges(xDraw, yDraw, RealLength, Radius-posrange,
2266 			      RangeHeight, From[i], To[i], FromSymbol[i],
2267 			      ToSymbol[i], Name2[i], OriginAngle, NumNames[i],
2268 			      postext, Adjust[i], Colour[i]);
2269     }
2270     NumBlocks = j;
2271 
2272     /* draw all interblocks */
2273     for(i=0; i<NumBlocks-1; i++)
2274 	cirdna_InterBlocks(xDraw, yDraw, RealLength, Radius-posblock,
2275 			   BlockHeight,
2276 			   From[cirdnaInter[i]], To[cirdnaInter[i+1]],
2277 			   OriginAngle, InterSymbol, InterColour);
2278 
2279     return;
2280 }
2281