source: branches/ali/SECEDIT/SEC_paint.cxx

Last change on this file was 19397, checked in by westram, 20 months ago
  • allow custom helix symbol translation (EDIT4 → SECEDIT)
    • default translation does reproduce same bond display as before (if helix settings in EDIT4 are set to default as well).
    • remove bond pair definitions from SECEDIT
    • reset user layout of 'Bond definitions' window (required because default size shrinked)
    • remove 3.5k now obsolete code :-)
    • update documentation
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 45.9 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : SEC_paint.cxx                                     //
4//   Purpose   :                                                   //
5//                                                                 //
6//   Institute of Microbiology (Technical University Munich)       //
7//   http://www.arb-home.de/                                       //
8//                                                                 //
9// =============================================================== //
10
11#include "SEC_root.hxx"
12#include "SEC_graphic.hxx"
13#include "SEC_iter.hxx"
14#include "SEC_drawn_pos.hxx"
15#include "SEC_bonddef.hxx"
16#include "SEC_toggle.hxx"
17
18#include <aw_msg.hxx>
19#include <iupac.h>
20
21#include <ed4_extern.hxx>
22
23#include <arb_defs.h>
24
25#include <iostream>
26#include <sstream>
27#include <AW_helix.hxx>
28
29using namespace std;
30
31// -------------------
32//      Debugging
33
34#if defined(ASSERTION_USED)
35
36inline bool valid_cb_params(AW_CL cd1, AW_CL cd2) {
37    return cd1 == 0 || cd2 != -1;
38}
39inline bool valid_cb_params(AW_device *device) {
40    const AW_click_cd *cd = device->get_click_cd();
41    return valid_cb_params(cd->get_cd1(), cd->get_cd2());
42}
43
44#endif
45
46#if defined(DEBUG)
47// #define PAINT_REGION_INDEX // // paint region-internal index next to base
48
49static void paintDebugInfo(AW_device *device, int color, const Position& pos, const char *txt) {
50    sec_assert(valid_cb_params(device));
51    device->circle(color, AW::FillStyle::SOLID, pos.xpos(), pos.ypos(), 0.06, 0.06);
52    device->text(SEC_GC_DEFAULT, txt, pos.xpos(), pos.ypos(), 0, AW_SCREEN);
53}
54static void paintStrandDebugInfo(AW_device *device, int color, SEC_helix_strand *strand) {
55    AW_click_cd cd(device, strand->self(), strand->rightAttachAbspos());        paintDebugInfo(device, color, strand->rightAttachPoint(), "RAP");
56    cd.set_cd2(strand->leftAttachAbspos());                                     paintDebugInfo(device, color, strand->leftAttachPoint(), "LAP");
57    cd.set_cd2(strand->startAttachAbspos());                                    paintDebugInfo(device, color, strand->get_fixpoint(), strand->isRootsideFixpoint() ? "RFP" : "FP");
58}
59
60#endif // DEBUG
61
62// -------------------
63//      PaintData
64
65class PaintData {
66    int gc_edit4_to_secedit[ED4_G_DRAG+1]; // GC translation table (EDIT4 -> SECEDIT)
67    int line_property_gc[SEC_GC_LAST_DATA+1][SEC_GC_LAST_DATA+1]; // of two GCs, which is responsible for line properties
68
69public:
70    PaintData() {
71        int gc;
72
73        // GC translation (EDIT4->SECEDIT)
74        for (gc = 0; gc <= ED4_G_DRAG; gc++) {
75            gc_edit4_to_secedit[gc] = -1; // invalid
76        }
77        for (gc = ED4_G_SBACK_0; gc <= ED4_G_SBACK_8; gc++) { // IRRELEVANT_LOOP
78            gc_edit4_to_secedit[gc] = gc-ED4_G_SBACK_0+SEC_GC_SBACK_0;
79        }
80        for (gc = ED4_G_CBACK_0; gc <= ED4_G_CBACK_9; gc++) { // IRRELEVANT_LOOP
81            gc_edit4_to_secedit[gc] = gc-ED4_G_CBACK_0+SEC_GC_CBACK_0;
82        }
83
84        // calc line property GCs
85        for (gc = SEC_GC_FIRST_DATA; gc <= SEC_GC_LAST_DATA; gc++) {
86            for (int gc2 = SEC_GC_FIRST_DATA; gc <= SEC_GC_LAST_DATA; gc++) {
87                int prop_gc;
88                if (gc == gc2) {
89                    prop_gc = gc;
90                }
91                else {
92                    if (gc == SEC_GC_LOOP || gc2 == SEC_GC_LOOP) {
93                        prop_gc = SEC_GC_LOOP; // use loop-properties in loop and at loop-helix-transition
94                    }
95                    else if (gc == SEC_GC_NHELIX || gc2 == SEC_GC_NHELIX) {
96                        prop_gc = SEC_GC_NHELIX; // use nhelix-properties in nhelix and at helix-nhelix-transition
97                    }
98                    else {
99                        prop_gc = SEC_GC_HELIX; // use helix-properties in helix
100                    }
101                }
102                line_property_gc[gc][gc2] = prop_gc;
103            }
104        }
105    }
106
107    int convert_BackgroundGC(int edit4_gc) const {
108        // returns -1 if edit4_gc is invalid
109        sec_assert(edit4_gc >= 0 && edit4_gc <= ED4_G_DRAG);
110        return gc_edit4_to_secedit[edit4_gc];
111    }
112
113    int get_linePropertyGC(int gc1, int gc2) {
114        // of the GCs of two positions, it returns the GC which is
115        // defining the properties for the background painted in-between the two positions
116        sec_assert(gc1 >= SEC_GC_FIRST_DATA && gc1 <= SEC_GC_LAST_DATA);
117        sec_assert(gc2 >= SEC_GC_FIRST_DATA && gc2 <= SEC_GC_LAST_DATA);
118        return line_property_gc[gc1][gc2];
119    }
120};
121
122static PaintData paintData;
123
124// ---------------------
125//      Annotations
126
127void SEC_root::paintAnnotation(AW_device *device, int gc,
128                               const Position& pos, const Position& left, const Position& right,
129                               double noteDistance, const char *text,
130                               bool lineToPos, bool linesToLeftRight, bool boxText)
131{
132    // draw annotation to explicit position 'pos' (annotation is drawn "above" the line left->right)
133    // The distance between pos and note is determined by
134    // * textsize (minimal half textsize/boxsize) and
135    // * the given 'noteDistance'
136    // lineToPos        == true -> draw a line from text to 'pos'
137    // linesToLeftRight == true -> draw lines from text to 'left' and 'right'
138    // boxText          == true -> draw a box around text
139
140    sec_assert(valid_cb_params(device));
141
142    Vector strand(left, right);
143    Angle pos2note(strand);
144    pos2note.rotate270deg();
145
146    int    fontgc        = gc <= SEC_GC_LAST_FONT ? gc : SEC_GC_DEFAULT;
147    double half_charSize = center_char[fontgc].length();
148
149    SizedCstr stext(text);
150
151    // calculate textsize
152    AW_pos half_width  = 0.5 * device->rtransform_size(device->get_string_size(gc, stext));
153    AW_pos half_height = center_char[fontgc].y();
154
155    double note_distance  = max(half_height, half_width) * (boxText ? 1.3 : 1.0);
156    note_distance         = max(note_distance, noteDistance);
157
158    Position note_center = pos + pos2note.normal()*note_distance;
159
160    if (device->get_filter() & AW_PRINTER) {
161        boxText = false; // don't print/xfig-export boxes
162    }
163
164    if (lineToPos || linesToLeftRight) {
165        device->set_line_attributes(gc, 1, AW_SOLID);
166
167        if (lineToPos) {
168            Vector dist = pos2note.normal()*half_charSize;
169            device->line(gc, boxText ? note_center : note_center-dist, pos+dist);
170        }
171        if (linesToLeftRight) {
172            Vector out(pos, note_center);
173
174            if (out.length()*2 >= strand.length()) { // short strands -> draw simple bracket
175                Vector toLeft(note_center, left);
176                Vector toRight(note_center, right);
177
178                device->line(gc, boxText ? note_center : note_center+toLeft*(half_width/toLeft.length()),
179                             left-toLeft*(half_charSize/toLeft.length()), AW_ALL_DEVICES_SCALED);
180                device->line(gc, boxText ? note_center : note_center+toRight*(half_width/toRight.length()),
181                             right-toRight*(half_charSize/toRight.length()), AW_ALL_DEVICES_SCALED);
182            }
183            else {
184                Vector rightIndent = out;
185                rightIndent.rotate270deg();
186
187                Position rightOut = right+out+rightIndent;
188                Position leftOut  = left+out-rightIndent;
189
190                Vector posPad = Vector(right, rightOut).set_length(half_charSize);
191                device->line(gc, right+posPad, rightOut);
192                posPad.rotate90deg();
193                device->line(gc, left+posPad, leftOut);
194
195                if (boxText) {
196                    device->line(gc, leftOut, rightOut);
197                }
198                else {
199                    Vector rightTextPad(note_center, rightOut);
200                    rightTextPad.set_length(half_width);
201
202                    device->line(gc, note_center+rightTextPad, rightOut);
203                    device->line(gc, note_center-rightTextPad, leftOut);
204                }
205            }
206        }
207    }
208
209    Vector   center_textcorner(-half_width, half_height); // from center to lower left corner
210    Position textcorner = note_center+center_textcorner;
211
212    if (boxText) {
213        Vector    center_corner(-half_width-half_height*0.3, half_height*1.3); // box is 25% bigger than text
214        Rectangle box(note_center+center_corner, -2*center_corner);
215
216        device->clear_part(box, -1);
217        device->box(gc, AW::FillStyle::EMPTY, box);
218    }
219
220    device->text(gc, text, textcorner);
221}
222
223void SEC_root::paintPosAnnotation(AW_device *device, int gc, size_t absPos, const char *text, bool lineToBase, bool boxText) {
224    // draw a annotation next to a base (only works after paint()).
225    // if nothing was drawn at absPos, annotate a position between previous and next drawn position.
226    // text       == NULp    -> draw absPos as number
227    // lineToBase == true    -> draw a line to the base itself
228    // boxText    == true    -> draw a box around text
229
230    size_t          abs1, abs2;
231    const Position& pos1 = drawnPositions->drawn_before(absPos, &abs1);
232    const Position& pos2 = drawnPositions->drawn_after (absPos, &abs2);
233
234    LineVector vec12(pos1, pos2);
235    Position   mid12 = vec12.centroid();
236    Position   pos;
237    {
238        const Position *posDrawn = drawnPositions->drawn_at(absPos);
239        if (posDrawn) { // absPos was drawn
240            pos = *posDrawn;
241        }
242        else { // absPos was not drawn -> use position in-between
243            pos = mid12;
244        }
245    }
246
247    if (!text) text = GBS_global_string("%zu", absPos);
248
249    AW_click_cd cd(device, 0, absPos);
250    paintAnnotation(device, gc, pos, pos1, pos2, vec12.length(), text, lineToBase, false, boxText);
251}
252
253void SEC_root::paintEcoliPositions(AW_device *device) {
254    long abspos = db->ecoli()->rel_2_abs(0);
255    paintPosAnnotation(device, SEC_GC_ECOLI, size_t(abspos), "1", true, true);
256
257    const BI_ecoli_ref *ecoli = db->ecoli();
258    for (size_t ep = bio2info(100); ep < (size_t)ecoli->base_count(); ep += 100) {
259        abspos = ecoli->rel_2_abs(ep);
260        paintPosAnnotation(device, SEC_GC_ECOLI, size_t(abspos), GBS_global_string("%i", info2bio(ep)), true, true);
261    }
262}
263
264void SEC_root::paintHelixNumbers(AW_device *device) {
265    for (SEC_base_iterator elem(this); elem; ++elem) {
266        if (elem->getType() == SEC_HELIX) {
267            SEC_helix& helix = static_cast<SEC_helix&>(*elem);
268
269            // paint helix number of right (3') helix strand
270            SEC_helix_strand *strand = helix.strandToRoot()->is3end() ? helix.strandToRoot() : helix.strandToOutside();
271
272            int         absPos  = strand->startAttachAbspos();
273            const char *helixNr = helixNrAt(absPos);
274
275            if (helixNr) {
276                if (helix.standardSize() == 0) { // helix with zero length (just one position on each strand)
277                    paintPosAnnotation(device, SEC_GC_HELIX_NO,
278                                       strand->startAttachAbspos(), helixNr, true, true);
279                }
280                else {
281                    const Position& start = strand->startAttachPoint();
282                    const Position& end   = strand->endAttachPoint();
283                    Position helixCenter           = centroid(start, end);
284
285                    AW_click_cd cd(device, strand->self(), absPos);
286                    paintAnnotation(device, SEC_GC_HELIX_NO,
287                                    helixCenter, start, end,
288                                    // displayParams.distance_between_strands*2,
289                                    displayParams.distance_between_strands,
290                                    helixNr, false, true, true);
291                }
292            }
293        }
294    }
295}
296
297
298#if defined(PAINT_ABSOLUTE_POSITION)
299void SEC_root::showSomeAbsolutePositions(AW_device *device) {
300    if (device->get_filter() != AW_SIZE) { // ignore for size calculation (@@@)
301        Rectangle screen = device->rtransform(Rectangle(device->get_area_size(), INCLUSIVE_OUTLINE));
302        Vector    diag3  = screen.diagonal()/3;
303        Rectangle showInside(screen.upper_left_corner()+diag3*1.85, diag3);
304
305        AW_click_cd cd(device, 0, -1);
306        device->box(SEC_GC_DEFAULT, AW::FillStyle::EMPTY, showInside);
307
308        PosMap::const_iterator end = drawnPositions->end();
309        for (PosMap::const_iterator pos = drawnPositions->begin(); pos != end; ++pos) {
310            if (showInside.contains(pos->second)) {
311                paintPosAnnotation(device, SEC_GC_DEFAULT, pos->first, NULp, true, true);
312            }
313        }
314    }
315}
316#endif // PAINT_ABSOLUTE_POSITION
317
318void SEC_root::announce_base_position(int base_pos, const Position& draw_pos) {
319    drawnPositions->announce(base_pos, draw_pos);
320}
321void SEC_root::clear_announced_positions() {
322    if (!drawnPositions) drawnPositions = new SEC_drawn_positions;
323    drawnPositions->clear();
324}
325
326void SEC_root::delete_announced_positions() {
327    delete drawnPositions;
328    drawnPositions = NULp;
329}
330
331
332// ----------------------------
333//      Paints CONSTRAINTS
334
335void SEC_helix_strand::paint_constraints(AW_device *device) {
336    double minS = helix_info->minSize();
337    double maxS = helix_info->maxSize();
338
339    if (minS>0 || maxS>0) {
340        const Position& startP = startAttachPoint();
341        const Position& endP   = endAttachPoint();
342
343        bool drawMidLine = minS>0 && maxS>0;
344        Position minP = startP + Vector(startP, endP) * (drawMidLine ? minS/maxS : 0.5);
345
346        AW_click_cd cd(device, self(), startAttachAbspos());
347        get_root()->paintAnnotation(device, SEC_GC_DEFAULT,
348                                    minP, startP, endP,
349                                    get_root()->display_params().distance_between_strands*2,
350                                    GBS_global_string("%.1f-%.1f", minS, maxS),
351                                    drawMidLine, true, true);
352    }
353}
354
355void SEC_loop::paint_constraints(AW_device *device) {
356    int abspos = get_fixpoint_strand()->startAttachAbspos();
357
358    double minS = minSize();
359    double maxS = maxSize();
360
361    if (minS>0 || maxS>0) {
362        AW_click_cd cd(device, self(), abspos);
363
364        if (minS>0) device->circle(SEC_GC_DEFAULT, AW::FillStyle::EMPTY, center, Vector(minS, minS));
365        if (maxS>0) device->circle(SEC_GC_DEFAULT, AW::FillStyle::EMPTY, center, Vector(maxS, maxS));
366
367        device->text(SEC_GC_DEFAULT, GBS_global_string("%.1f-%.1f", minS, maxS), center+Vector(0, max(minS, maxS)/2), 0.5, AW_ALL_DEVICES_UNSCALED);
368    }
369}
370
371// ---------------------------
372//      Background colors
373
374void SEC_root::cacheBackgroundColor() { // @@@ move to SEC_db_interface
375    freenull(bg_color);
376
377    int start = 0;
378    int len   = db->length();
379    int end   = len-1;
380
381    ARB_alloc(bg_color, len);
382
383    const char *bg_sai    = displayParams.display_sai    ? host().get_SAI_background(start, end)    : NULp;
384    const char *bg_search = displayParams.display_search ? host().get_search_background(start, end) : NULp;
385
386    if (bg_sai) {
387        if (bg_search) {
388            for (int i = start; i <= end; ++i) {
389                bg_color[i] = bg_search[i] ? bg_search[i] : bg_sai[i];
390            }
391        }
392        else memcpy(bg_color, bg_sai, len);
393    }
394    else {
395        if (bg_search) memcpy(bg_color, bg_search, len);
396        else memset(bg_color, 0, len);
397    }
398}
399
400void SEC_root::paintBackgroundColor(AW_device *device, SEC_bgpaint_mode mode, const Position& p1, int color1, int gc1, const Position& p2, int color2, int gc2, int skel_gc) {
401    // paints background colors for p2 and connection between p1 and p2.
402    // gc1/gc2 are foreground gc used to detect size of background regions
403    //
404    // Also paints skeleton
405
406    sec_assert(valid_cb_params(device));
407
408    color1 = paintData.convert_BackgroundGC(color1); // convert EDIT4-GCs into SECEDIT-GCs
409    color2 = paintData.convert_BackgroundGC(color2);
410
411    if (color1 >= 0 || color2 >= 0 || displayParams.show_strSkeleton) {
412        const double& radius1 = get_char_radius(gc1);
413        const double& radius2 = get_char_radius(gc2);
414
415        if (mode & BG_PAINT_FIRST && color1 >= 0) { // paint first circle ?
416            device->circle(color1, AW::FillStyle::SOLID, p1, Vector(radius1, radius1));
417        }
418
419        if (mode & BG_PAINT_SECOND && color2 >= 0) { // paint second circle ?
420            device->circle(color2, AW::FillStyle::SOLID, p2, Vector(radius1, radius1));
421        }
422
423        if (color1 == color2 && color1 >= 0) { // colors are equal -> paint background between points
424            device->set_line_attributes(color1, bg_linewidth[paintData.get_linePropertyGC(gc1, gc2)], AW_SOLID);
425            device->line(color1, p1, p2);
426        }
427
428        if (displayParams.show_strSkeleton) { // paint skeleton?
429            Position s1    = p1;
430            Position s2    = p2;
431            bool     space = false;
432
433            if (displayParams.hide_bases) {
434                space = true; // no base chars -> enough space to paint
435            }
436            else {
437                Vector v12(p1, p2);
438                double vlen = v12.length();
439
440                // Note: LINE_THICKNESS
441                //       Lines drawn with thickness != 1 differ between motif-version and gtk-version:
442                //       in motif thicker lines are also drawn longer than specified (half thickness on each side)
443                const double CORR = skelThickWorld;
444
445                if ((radius1+radius2+CORR) < vlen) { // test if there is enough space between characters
446                    s1 = p1 + v12*((radius1+CORR/2)/vlen); // skeleton<->base attach-points
447                    s2 = p2 - v12*((radius2+CORR/2)/vlen);
448                    space = true;
449                }
450            }
451
452            if (space) {
453                device->set_line_attributes(skel_gc, displayParams.skeleton_thickness, AW_SOLID);
454#if defined(DEBUG)
455                if (displayParams.show_debug) { s1 = p1; s2 = p2; } // in debug mode always show full skeleton
456#endif // DEBUG
457                device->line(skel_gc, s1, s2);
458            }
459        }
460    }
461}
462
463void SEC_root::paintSearchPatternStrings(AW_device *device, int clickedPos, AW_pos xPos,  AW_pos yPos) {
464    int searchColor = getBackgroundColor(clickedPos);
465
466    if (searchColor >= SEC_GC_SBACK_0 && searchColor <= SEC_GC_SBACK_8) {
467        static const char *text[SEC_GC_SBACK_8-SEC_GC_SBACK_0+1] = {
468            "User 1",
469            "User 2",
470            "Probe",
471            "Primer (local)",
472            "Primer (region)",
473            "Primer (global)",
474            "Signature (local)",
475            "Signature (region)",
476            "Signature (global)",
477        };
478
479        AW_click_cd cd(device, 0, clickedPos);
480        device->text(searchColor, text[searchColor-SEC_GC_SBACK_0], xPos, yPos, 0, AW_SCREEN);
481    }
482    else {
483        aw_message("Please click on a search result");
484    }
485}
486
487// ---------------
488//      Bonds
489
490void SEC_bond_def::paint(AW_device *device, char base1, char base2, const Position& p1, const Position& p2, const Vector& toNextBase, const double& char_radius) const {
491    if (base1 && base2) {
492        char e4_symbol = helix->get_symbol(base1, base2);
493        char symbol    = edit4_to_secedit[safeCharIndex(e4_symbol)];
494        if (symbol != ' ') {
495            paint_symbol(device, SEC_GC_BONDS, symbol, p1, p2, toNextBase, char_radius);
496        }
497    }
498}
499
500void SEC_bond_def::paint_symbol(AW_device *device, int GC, char bondChar, const Position& p1, const Position& p2, const Vector& toNextBase, const double& char_radius) const {
501    Vector v12(p1, p2);
502    double oppoDist = v12.length();
503    double bondLen  = oppoDist-2*char_radius;
504
505    if (bondLen <= 0.0) return; // not enough space to draw bond
506
507    Vector pb = v12*(char_radius/oppoDist);
508
509    Position b1 = p1+pb; // start/end pos of bond
510    Position b2 = p2-pb;
511
512    Position center = centroid(b1, b2);
513
514    Vector aside = toNextBase;
515    {
516        // limit aside-size by strand-distance
517        double aside_len     = aside.length();
518        double max_aside_len = min(aside_len, Vector(b1, b2).length());
519        if (max_aside_len<aside_len) {
520            aside *= max_aside_len/aside_len;
521        }
522    }
523    aside *= 0.22; // max. 22% towards next base position (has to be less than 25%, because 'aside' is added twice for some bondtypes)
524
525    switch (bondChar) {
526        case '-':               // single line
527            device->line(GC, b1, b2);
528            break;
529
530        case '#':               // double cross
531        case '=':               // double line
532            device->line(GC, b1+aside, b2+aside);
533            device->line(GC, b1-aside, b2-aside);
534
535            if (bondChar == '#') {
536                Vector   outside = v12*(bondLen/oppoDist/4);
537                Position c1      = center+outside;
538                Position c2      = center-outside;
539
540                aside *= 2;
541
542                device->line(GC, c1-aside, c1+aside);
543                device->line(GC, c2-aside, c2+aside);
544            }
545            break;
546
547        case '~': {
548            double radius = aside.length();
549            {
550                double maxRadius = bondLen/4;
551                if (maxRadius<radius) radius = maxRadius;
552            }
553
554            Vector outside = v12*(radius/oppoDist);
555
556            Position c1 = center+outside;
557            Position c2 = center-outside;
558
559            aside *= 2;
560
561            Angle angle(outside);
562            int   deg = AW_INT(angle.degrees());
563
564            const int INSIDE  = 2;
565            const int OUTSIDE = 15;
566
567            Vector vRadius(radius, radius);
568            device->arc(GC, AW::FillStyle::EMPTY, c1, vRadius, deg+180+INSIDE, -(180+INSIDE+OUTSIDE));
569            device->arc(GC, AW::FillStyle::EMPTY, c2, vRadius, deg+INSIDE,     -(180+INSIDE+OUTSIDE));
570            break;
571        }
572
573        case '+':               // cross
574            aside *= 2;
575            device->line(GC, center-aside, center+aside);
576            if (2*aside.length() < bondLen) {
577                aside.rotate90deg();
578                device->line(GC, center-aside, center+aside);
579            }
580            else {
581                device->line(GC, b1, b2);
582            }
583            break;
584
585        case 'o':
586        case '.': {             // circles
587            double radius            = aside.length();
588            if (bondChar == 'o') radius *= 2;
589            device->circle(GC, AW::FillStyle::EMPTY, center, Vector(radius, radius));
590            break;
591        }
592
593        default: {
594            char buf[20];
595            sprintf(buf, "'%c'", bondChar);
596            device->text(GC, buf, center+Vector(0, char_radius), 0.5, AW_ALL_DEVICES_UNSCALED);
597
598            if (bondLen>4*char_radius) {
599                Position c1 = center-2*pb;
600                Position c2 = center+2*pb;
601                device->line(GC, b1, c1);
602                device->line(GC, b2, c2);
603            }
604
605            break;
606        }
607    }
608}
609
610// -----------------------
611//      Paint helices
612
613struct StrandPositionData {
614    int      abs[2];            // absolute sequence position
615    int      previous[2];       // previous drawn index
616    bool     drawn[2];          // draw position ?
617    bool     isPair;            // true if position is pairing
618    Position realpos[2];        // real position
619};
620
621void SEC_helix_strand::paint_strands(AW_device *device, const Vector& strand_vec, const double& strand_len) {
622    static StrandPositionData *data      = NULp;
623    static int                 allocated = 0;
624
625    const SEC_region* Region[2] = { get_region(), other_strand->get_region() };
626    int base_count = Region[0]->get_base_count();
627
628    sec_assert(Region[1]->get_base_count() == base_count); // not aligned ?
629
630    if (base_count<1) {
631        return; // completely skip painting on strands w/o any base
632    }
633
634    if (allocated<base_count) {
635        delete [] data;
636        data      = new StrandPositionData[base_count];
637        allocated = base_count;
638    }
639
640    SEC_root       *root  = get_root();
641    const BI_helix *helix = root->get_helixDef();
642
643    double base_dist = base_count>1 ? strand_len / (base_count-1) : 1;
644    Vector vnext     = strand_vec * base_dist; // vector from base to next base (in strand)
645
646    // first calculate positions
647    {
648        StrandPositionData *curr = &data[0];
649
650        int idx[2] = { 0, base_count-1 };
651        Position pos[2] = { leftAttach, rightAttach };
652        Vector toNonBind[2]; // vectors from normal to non-binding positions
653        toNonBind[1] = (strand_vec*0.5).rotate90deg();
654        toNonBind[0] = -toNonBind[1];
655
656        for (int strand = 0; strand<2; ++strand) {
657            curr->abs[strand]      = Region[strand]->getBasePos(idx[strand]);
658            curr->previous[strand] = 0;
659            curr->drawn[strand]    = (curr->abs[strand] >= 0);
660        }
661
662        for (int dIdx = 1; ; ++dIdx) {
663            sec_assert(pos[0].valid());
664            sec_assert(pos[1].valid());
665
666            int oneAbs  = curr->drawn[0] ? curr->abs[0] : curr->abs[1];
667            sec_assert(oneAbs >= 0); // otherwise current position should have been eliminated by align_helix_strands
668            curr->isPair = helix->is_pairpos(oneAbs);
669
670            for (int strand = 0; strand<2; ++strand) {
671                if (curr->isPair) {
672                    curr->realpos[strand] = pos[strand];
673                    curr->drawn[strand]   = true;
674                }
675                else {
676                    curr->realpos[strand] = pos[strand]+toNonBind[strand];
677                }
678
679                sec_assert(curr->realpos[strand].valid());
680            }
681
682            if (dIdx >= base_count) break;
683
684            ++idx[0];
685            --idx[1];
686
687            StrandPositionData *prev = curr;
688            curr                     = &data[dIdx];
689
690            for (int strand = 0; strand<2; ++strand) {
691                pos[strand]           += vnext;
692                curr->abs[strand]       = Region[strand]->getBasePos(idx[strand]);
693                curr->previous[strand]  = prev->drawn[strand] ? dIdx-1 : prev->previous[strand];
694                curr->drawn[strand]     = (curr->abs[strand] >= 0);
695            }
696        }
697    }
698
699    const int pair2helixGC[2] = { SEC_GC_NHELIX, SEC_GC_HELIX };
700    const int pair2skelGC[2] = { SEC_SKELE_NHELIX, SEC_SKELE_HELIX };
701
702    const SEC_db_interface   *db   = root->get_db();
703    const SEC_displayParams&  disp = root->display_params();
704
705    // draw background and skeleton
706    for (int pos = 1; pos<base_count; ++pos) {
707        StrandPositionData *curr = &data[pos];
708        for (int strand = 0; strand<2; ++strand) {
709            if (curr->drawn[strand]) {
710                StrandPositionData *prev = &data[curr->previous[strand]];
711
712                int backAbs = disp.edit_rightward
713                    ? max(prev->abs[strand], curr->abs[strand])
714                    : min(prev->abs[strand], curr->abs[strand]);
715
716                AW_click_cd cd(device, self(), backAbs);
717                root->paintBackgroundColor(device,
718                                           pos == base_count-1 ? BG_PAINT_NONE : BG_PAINT_SECOND,
719                                           prev->realpos[strand], root->getBackgroundColor(prev->abs[strand]), pair2helixGC[prev->isPair],
720                                           curr->realpos[strand], root->getBackgroundColor(curr->abs[strand]), pair2helixGC[curr->isPair],
721                                           pair2skelGC[curr->isPair && prev->isPair]);
722            }
723        }
724    }
725
726    // draw base characters and bonds
727    char baseBuf[20] = "x";
728    for (int pos = 0; pos<base_count; ++pos) {
729        StrandPositionData *curr = &data[pos];
730        char base[2] = { 0, 0 };
731
732        int    gc          = pair2helixGC[curr->isPair];
733        Vector center_char = root->get_center_char_vector(gc);
734
735        for (int strand = 0; strand<2; ++strand) {
736            if (curr->drawn[strand]) {
737                int             abs     = curr->abs[strand];
738                const Position& realPos = curr->realpos[strand];
739
740                sec_assert(abs >= 0);
741
742                base[strand] = db->baseAt(abs);
743                root->announce_base_position(abs, realPos);
744
745                if (!disp.hide_bases) {
746                    baseBuf[0]        = base[strand];
747                    Position base_pos = realPos + center_char; // center base at realpos
748                    AW_click_cd cd(device, self(), abs);
749#if defined(DEBUG)
750                    if (disp.show_debug) device->line(gc, realPos, base_pos);
751#endif // DEBUG
752
753                    device->text(gc, baseBuf, base_pos, 0.0, AW_ALL_DEVICES_SCALED);
754                }
755            }
756        }
757
758        if (disp.show_bonds == SHOW_NHELIX_BONDS || (disp.show_bonds == SHOW_HELIX_BONDS && curr->isPair)) {
759            AW_click_cd cd(device, self(), curr->abs[0]);
760            db->bonds()->paint(device, base[0], base[1], curr->realpos[0], curr->realpos[1], vnext,
761                               root->get_char_radius(pair2helixGC[curr->isPair])
762                               +root->get_bondThickWorld()/2 // see .@LINE_THICKNESS
763                               );
764        }
765    }
766}
767
768void SEC_helix_strand::paint(AW_device *device) {
769    sec_assert(isRootsideFixpoint());
770
771    Vector strand_vec(rightAttach, other_strand->leftAttach);
772    double strand_len     = strand_vec.length(); // length of strand
773
774    if (strand_len>0) {
775        strand_vec.normalize();     // normalize
776    }
777    else { // strand with zero length (contains only one base-pair)
778        strand_vec = Vector(rightAttach, leftAttach).rotate90deg();
779    }
780
781    other_strand->origin_loop->paint(device); // first paint next loop
782    paint_strands(device, strand_vec, strand_len); // then paint strand
783
784    SEC_root                 *root = get_root();
785    const SEC_displayParams&  disp = root->display_params();
786
787    if (disp.show_strSkeleton && !disp.show_bonds && disp.hide_bases) {
788        // display strand direction
789        LineVector strandArrow;
790        if (strand_len>0) {
791            strandArrow = LineVector(get_fixpoint(), strand_vec);
792        }
793        else {
794            Vector fix2arrowStart(get_fixpoint(), leftAttachPoint());
795            fix2arrowStart.rotate90deg();
796            strandArrow = LineVector(get_fixpoint()-fix2arrowStart, 2*fix2arrowStart);
797        }
798
799        AW_click_cd cd(device, get_helix()->self(), startAttachAbspos());
800        device->line(SEC_GC_HELIX, strandArrow);
801
802        Vector right = strandArrow.line_vector(); // left arrowhead vector
803        right        = (right * (disp.distance_between_strands*0.35/right.length())).rotate135deg();
804
805        Vector left = Vector(right).rotate90deg();
806
807        Position head = strandArrow.head();
808        device->line(SEC_GC_HELIX, LineVector(head, left));
809        device->line(SEC_GC_HELIX, LineVector(head, right));
810    }
811
812#if defined(DEBUG)
813    if (disp.show_debug) paintStrandDebugInfo(device, SEC_GC_HELIX, other_strand);
814#endif // DEBUG
815
816    if (root->get_show_constraints() & SEC_HELIX) paint_constraints(device);
817}
818
819
820// ---------------------
821//      Paint loops
822
823void SEC_segment::paint(AW_device *device, SEC_helix_strand *previous_strand_pointer) {
824    int base_count = get_region()->get_base_count(); // bases in segment
825
826    const Position& startP = previous_strand_pointer->rightAttachPoint();
827    const Position& endP   = next_helix_strand->leftAttachPoint();
828
829    Angle  current;             // start/current angle
830    Angle  end;                 // end angle
831    double radius1;             // start and..
832    double radius2;             // end radius of segment
833
834    {
835        Vector seg_start_radius(center1, startP);
836        radius1  = seg_start_radius.length();
837        current = seg_start_radius;
838
839        Vector seg_end_radius(center2, endP);
840        radius2  = seg_end_radius.length();
841        end = seg_end_radius;
842    }
843
844    int steps = base_count+1;
845
846    double step = ((end-current)/steps).radian();
847
848    // correct if we have to paint more than a full loop
849    if ((alpha - (step*steps)) > M_PI) {
850        step += (2*M_PI)/steps;
851    }
852
853    double radStep = (radius2-radius1)/steps;
854
855    Vector cstep(center1, center2);
856    cstep /= steps;
857
858    SEC_root                 *root = get_root();
859    const SEC_db_interface   *db   = root->get_db();
860    const SEC_displayParams&  disp = root->display_params();
861#if defined(DEBUG)
862    if (disp.show_debug) {
863        paintStrandDebugInfo(device, SEC_GC_LOOP, previous_strand_pointer);
864
865        int startAbsPos = previous_strand_pointer->rightAttachAbspos();
866        int endAbsPos   = next_helix_strand->leftAttachAbspos();
867
868        AW_click_cd cd(device, self(), startAbsPos);
869        paintDebugInfo(device, SEC_GC_LOOP, center1, GBS_global_string("SC1 (step=%5.3f)", step));
870        device->line(SEC_GC_LOOP, center1, startP);
871        device->line(SEC_GC_LOOP, center1, center2);
872
873        cd.set_cd2(endAbsPos);
874        paintDebugInfo(device, SEC_GC_LOOP, center2, "SC2");
875        device->line(SEC_GC_LOOP, center2, endP);
876    }
877#endif // DEBUG
878
879    char baseBuf[5]  = "?";      // contains base char during print
880    Position pos    = startP;
881    int      abs    = previous_strand_pointer->rightAttachAbspos();
882    int      back   = root->getBackgroundColor(abs);
883    int      gc     = root->is_pairpos(abs) ? SEC_GC_HELIX : SEC_GC_NHELIX;
884    int      nextGc = SEC_GC_LOOP;
885
886    Position currCenter = center1;
887    double   currRadius = radius1;
888
889    Angle step_angle(step);
890
891    for (int i = -1; i<base_count; i++) { // for each segment position (plus one pre-loop)
892        current    += step_angle;     // iterate over angles
893        currCenter += cstep;
894        currRadius += radStep;
895
896        Position nextPos = currCenter + current.normal()*currRadius;
897        int      nextAbs;
898
899        if (i == (base_count-1)) { // last position (belongs to strand)
900            nextAbs    = next_helix_strand->leftAttachAbspos();
901            if (nextAbs<0) { // helix doesn't start with pair
902                nextAbs = next_helix_strand->getNextAbspos();
903            }
904            nextGc = root->is_pairpos(nextAbs) ? SEC_GC_HELIX : SEC_GC_NHELIX;
905        }
906        else {
907            nextAbs = get_region()->getBasePos(i+1);
908        }
909
910        int nextBack = root->getBackgroundColor(nextAbs);
911
912        // paint background (from pos to nextPos)
913        AW_click_cd cd(device, self(), disp.edit_rightward ? nextAbs : abs);
914        root->paintBackgroundColor(device, i == -1 ? BG_PAINT_BOTH : BG_PAINT_SECOND,
915                                   pos, back, gc, nextPos, nextBack, nextGc, SEC_SKELE_LOOP);
916
917        if (i >= 0) {
918            // paint base char at pos
919            baseBuf[0]           = abs>0 ? db->baseAt(abs) : '?';
920            Vector   center_char = root->get_center_char_vector(gc);
921            Position base_pos    = pos + center_char; // center base character at pos
922
923            cd.set_cd2(abs);
924            if (!disp.hide_bases) {
925#if defined(DEBUG)
926                // show line from base paint pos to calculated center of char
927                // (which is currently calculated wrong!)
928                if (disp.show_debug) device->line(SEC_GC_LOOP, pos, base_pos);
929#endif // DEBUG
930                device->text(SEC_GC_LOOP, baseBuf, base_pos, 0.0, AW_ALL_DEVICES_SCALED);
931            }
932            root->announce_base_position(abs, pos);
933        }
934
935        // prepare next loop
936        pos  = nextPos;
937        abs  = nextAbs;
938        back = nextBack;
939        gc   = nextGc;
940    }
941}
942
943void SEC_loop::paint(AW_device *device) {
944    for (SEC_segment_iterator seg(this); seg; ++seg) { // first paint all segments
945        seg->paint(device, seg->get_previous_strand());
946    }
947    for (SEC_strand_iterator strand(this); strand; ++strand) { // then paint all outgoing strands
948        if (strand->isRootsideFixpoint()) strand->paint(device);
949    }
950
951    SEC_root *sroot = get_root();
952#if defined(DEBUG)
953    if (sroot->display_params().show_debug) {
954        SEC_helix_strand *fixpoint_strand = get_fixpoint_strand();
955        int               abspos          = fixpoint_strand->startAttachAbspos();
956        AW_click_cd cd(device, self(), abspos);
957
958        device->set_line_attributes(SEC_GC_CURSOR, 1, AW_SOLID);
959        device->line(SEC_GC_CURSOR, get_center(), fixpoint_strand->get_fixpoint());
960
961        paintStrandDebugInfo(device, SEC_GC_CURSOR, fixpoint_strand);
962        paintDebugInfo(device, SEC_GC_CURSOR, get_center(), "LC");
963    }
964#endif // DEBUG
965    if (sroot->get_show_constraints() & SEC_LOOP) paint_constraints(device);
966}
967
968// ------------------------------------------------------------
969//      Paint the whole structure (starting with SEC_root)
970
971GB_ERROR SEC_root::paint(AW_device *device) {
972    SEC_loop *rootLoop = get_root_loop();
973    sec_assert(rootLoop);
974    clear_announced_positions(); // reset positions next to cursor
975
976    const BI_helix *helix = get_helixDef();
977    sec_assert(helix);
978
979    GB_ERROR error = helix->get_error();
980
981    if (!error) {
982        sec_assert(SEC_GC_FIRST_FONT == 0);
983        // @@@ font group should be built at startup and after each font change (no need to do on every paint!)
984        font_group.unregisterAll();
985        for (int gc = SEC_GC_FIRST_FONT; gc <= SEC_GC_LAST_FONT; ++gc) {
986            font_group.registerFont(device, gc, "ACGTU-.");
987            center_char[gc] = device->rtransform(Vector(-0.5*font_group.get_width(gc), 0.5*font_group.get_ascent(gc)));
988        }
989
990        // calculate size for background painting
991        sec_assert(SEC_GC_FIRST_DATA == 0);
992        for (int gc = SEC_GC_FIRST_DATA; gc <= SEC_GC_LAST_DATA; ++gc) {
993            int maxSize = hypotenuse(font_group.get_width(gc), font_group.get_ascent(gc));
994            bg_linewidth[gc] = maxSize*0.75;
995
996            maxSize        += 2;                                        // add 2 extra pixels
997            charRadius[gc]  = device->rtransform_size(maxSize) * 0.5;   // was 0.75
998        }
999
1000        skelThickWorld = device->rtransform_size(displayParams.skeleton_thickness);
1001        bondThickWorld = device->rtransform_size(displayParams.bond_thickness);
1002
1003        cacheBackgroundColor();
1004
1005        device->set_line_attributes(SEC_SKELE_HELIX,  displayParams.skeleton_thickness, AW_SOLID);
1006        device->set_line_attributes(SEC_SKELE_NHELIX, displayParams.skeleton_thickness, AW_SOLID);
1007        device->set_line_attributes(SEC_SKELE_LOOP,   displayParams.skeleton_thickness, AW_SOLID);
1008        device->set_line_attributes(SEC_GC_BONDS,     displayParams.bond_thickness,     AW_SOLID);
1009
1010        // mark the rootLoop with a box and print structure number
1011        {
1012            const Position&  loop_center = rootLoop->get_center();
1013            const char      *structId    = db->structure()->name();
1014
1015            AW_click_cd cd(device, rootLoop->self(), -1);
1016
1017            Vector center2corner(-1, -1);
1018            center2corner.set_length(rootLoop->drawnSize()*0.33);
1019
1020            Position upperleft_corner = loop_center+center2corner;
1021            Vector   diagonal         = -2*center2corner;
1022
1023            Position textPos(loop_center.xpos(), upperleft_corner.ypos());
1024
1025            device->box(SEC_GC_DEFAULT, AW::FillStyle::EMPTY, upperleft_corner, diagonal, AW_ALL_DEVICES_UNSCALED);
1026            device->text(SEC_GC_DEFAULT, structId, textPos, 0.5);
1027        }
1028
1029#if defined(CHECK_INTEGRITY)
1030        check_integrity(CHECK_ALL);
1031#endif // CHECK_INTEGRITY
1032
1033        rootLoop->paint(device);
1034
1035        // paint ecoli positions:
1036        if (displayParams.show_ecoli_pos) paintEcoliPositions(device);
1037
1038        if (displayParams.show_helixNrs) {
1039            paintHelixNumbers(device);
1040        }
1041
1042#if defined(PAINT_ABSOLUTE_POSITION)
1043        if (displayParams.show_debug) showSomeAbsolutePositions(device);
1044#endif // PAINT_ABSOLUTE_POSITION
1045
1046        // paint cursor:
1047        if (!drawnPositions->empty() &&
1048            (device->get_filter()&(AW_PRINTER|AW_PRINTER_EXT)) == 0) // don't print/xfig-export cursor
1049        {
1050            size_t   abs1, abs2;
1051            Position pos1, pos2;
1052            size_t curAbs;
1053
1054            if (displayParams.edit_rightward) {
1055                pos1   = drawnPositions->drawn_before(cursorAbsPos, &abs1);
1056                pos2   = drawnPositions->drawn_after(cursorAbsPos-1, &abs2);
1057                curAbs = abs2;
1058            }
1059            else {
1060                pos1   = drawnPositions->drawn_before(cursorAbsPos+1, &abs1);
1061                pos2   = drawnPositions->drawn_after(cursorAbsPos, &abs2);
1062                curAbs = abs1;
1063            }
1064
1065            AW_click_cd cd(device, 0, curAbs);
1066#if defined(DEBUG) && 1
1067            // draw a testline to see the baseline on that the cursor is positioned
1068            device->set_line_attributes(SEC_GC_CURSOR, 1, AW_DASHED);
1069            device->line(SEC_GC_CURSOR, pos1, pos2);
1070#endif
1071
1072            Position mid = centroid(pos1, pos2);
1073            Vector   v(pos1, pos2);
1074            {
1075                Vector v_drawn      = device->transform(v);
1076                double drawn_length = v_drawn.length();
1077
1078                sec_assert(drawn_length>0.0);
1079
1080                double cursor_size = 1.3 * max(font_group.get_max_width(), font_group.get_max_ascent()); // 30% bigger than max font size
1081                double stretch     = cursor_size*0.5/drawn_length; // stretch cursor (half fontsize in each direction)
1082
1083                v.rotate90deg() *= stretch;
1084            }
1085
1086            LineVector cursor(mid+v, mid-v);
1087            device->set_line_attributes(SEC_GC_CURSOR, 3, AW_SOLID);
1088            device->line(SEC_GC_CURSOR, cursor);
1089            set_last_drawed_cursor_position(cursor);
1090
1091            LineVector cursor_dir(cursor.head(), displayParams.edit_rightward ? v.rotate270deg() : v.rotate90deg());
1092            device->line(SEC_GC_CURSOR, cursor_dir);
1093
1094
1095            int cursor_gc  = -1;
1096            int disp_pos = -1;
1097
1098            switch (displayParams.show_curpos) {
1099                case SHOW_ABS_CURPOS:
1100                    cursor_gc = SEC_GC_CURSOR;
1101                    disp_pos  = info2bio(curAbs);
1102                    break;
1103                case SHOW_BASE_CURPOS:
1104                    cursor_gc = SEC_GC_DEFAULT;
1105                    disp_pos  = host().get_base_position(curAbs+1); // show bases up to cursorpos (inclusive)
1106                    break;
1107                case SHOW_ECOLI_CURPOS: {
1108                    cursor_gc = SEC_GC_ECOLI;
1109                    disp_pos  = db->ecoli()->abs_2_rel(curAbs+1); // show ecoli base position (inclusive cursorpos)
1110                    break;
1111                }
1112                case SHOW_NO_CURPOS:
1113                    cursor_gc = -1;
1114                    break;
1115            }
1116
1117            if (cursor_gc >= 0) {
1118                paintPosAnnotation(device, cursor_gc, curAbs, GBS_global_string("%u", disp_pos), true, true);
1119            }
1120        }
1121    }
1122    return error;
1123}
1124
1125void SEC_region::align_helix_strands(SEC_root *root, SEC_region *other_region) {
1126    if (abspos_array) {
1127        const BI_helix *helix = root->get_helixDef();
1128        if (helix && !helix->get_error()) {
1129            SEC_region *reg[2] = { this, other_region };
1130            int incr[2] = { 1, -1 }; // this is iterated forward, other_region backward
1131            int *absarr[2];
1132            int *new_absarr[2] = { NULp, NULp };
1133
1134
1135            for (int r = 0; r<2; ++r) {
1136                absarr[r] = reg[r]->abspos_array;
1137            }
1138
1139            for (int write = 0; write < 2; ++write) {
1140                int curr[2] = { 0, reg[1]->baseCount-1 };
1141                int last[2] = { reg[0]->baseCount-1, 0 };
1142                int newp[2] = { 0, 0 };
1143
1144                while (curr[0] <= last[0] && curr[1] >= last[1]) {
1145                    int  abs[2];
1146                    bool ispair[2];
1147
1148                    for (int r = 0; r<2; ++r) {
1149                        abs[r]    = absarr[r][curr[r]];
1150                        ispair[r] = abs[r] >= 0 && helix->is_pairpos(abs[r]);
1151                    }
1152
1153                    if (ispair[0] && ispair[1]) {
1154                        if (helix->opposite_position(abs[0]) != size_t(abs[1]) ||
1155                            helix->opposite_position(abs[1]) != size_t(abs[0]))
1156                        {
1157                            GB_ERROR error = GBS_global_string("Helix '%s/%s' folded at wrong position. Please refold.",
1158                                                               helix->helixNr(abs[0]), helix->helixNr(abs[1]));
1159                            aw_message(error);
1160                        }
1161
1162                        for (int r = 0; r<2; ++r) { // fill up to align binding positions
1163                            while (newp[r]<newp[1-r]) {
1164                                if (write) {
1165                                    new_absarr[r][newp[r]] = -1;
1166                                }
1167                                newp[r]++;
1168                            }
1169                        }
1170
1171                        sec_assert(newp[0] == newp[1]);
1172
1173                        for (int r = 0; r<2; ++r) { // copy binding positions
1174                            if (write) new_absarr[r][newp[r]] = abs[r];
1175                            newp[r]++; curr[r] += incr[r];
1176                        }
1177                    }
1178                    else {
1179                        bool collected = false;
1180                        for (int r = 0; r<2; ++r) {
1181                            if (abs[r] >= 0 && !ispair[r]) { // collect non-pairing bases
1182                                if (write) {
1183                                    new_absarr[r][newp[r]] = abs[r];
1184                                }
1185                                newp[r]++; curr[r] += incr[r];
1186                                collected           = true;
1187                            }
1188                        }
1189                        if (!collected) {
1190                            for (int r = 0; r<2; ++r) {
1191                                if (abs[r]<0) curr[r] += incr[r];
1192                            }
1193                        }
1194                    }
1195                }
1196
1197                sec_assert(newp[0] == newp[1]); // alignment failed
1198
1199                for (int r = 0; r<2; ++r) {
1200                    if (write) {
1201                        if (r == 1) { // reverse positions
1202                            int  p2  = newp[1]-1;
1203                            int *arr = new_absarr[1];
1204                            for (int p = 0; p<p2; ++p, --p2) { // LOOP_VECTORIZED[!<810]
1205                                swap(arr[p], arr[p2]);
1206                            }
1207                        }
1208
1209                        delete [] reg[r]->abspos_array;
1210                        reg[r]->abspos_array      = new_absarr[r];
1211#if defined(ASSERTION_USED)
1212                        reg[r]->abspos_array_size = newp[r];
1213#endif // ASSERTION_USED
1214                        reg[r]->set_base_count(newp[r]);
1215                    }
1216                    else {
1217                        // allocate buffers for second pass
1218                        new_absarr[r] = new int[newp[r]];
1219                    }
1220                }
1221            }
1222        }
1223    }
1224}
1225
Note: See TracBrowser for help on using the repository browser.