void RenderParamCdxmlInterface::_renderMols()

in core/render2d/src/render_cdxml.cpp [160:473]


void RenderParamCdxmlInterface::_renderMols(RenderParams& params)
{
    MoleculeCdxmlSaver saver(*params.rOpt.output);

    Array<BaseMolecule*> mols;
    Array<int> ids;

    if (params.mols.size() != 0)
        for (int i = 0; i < params.mols.size(); ++i)
            mols.push(params.mols[i]);
    else if (params.mol.get() != 0)
        mols.push(params.mol.get());

    Array<float> column_widths;
    column_widths.resize(params.cnvOpt.gridColumnNumber);
    column_widths.fill(0);

    Array<float> title_widths;
    title_widths.resize(mols.size());
    title_widths.fill(0);

    Array<float> key_widths;
    key_widths.resize(mols.size());
    key_widths.fill(0);

    Array<float> prop_widths;
    prop_widths.resize(mols.size());
    prop_widths.fill(0);

    Array<Pos> positions;
    positions.resize(mols.size());

    Array<float> title_heights;
    title_heights.resize(mols.size());
    title_heights.fill(0);

    for (int mol_idx = 0; mol_idx < mols.size(); ++mol_idx)
    {
        int column = mol_idx % params.cnvOpt.gridColumnNumber;

        Pos& p = positions[mol_idx];
        _getBounds(params, mols[mol_idx]->asMolecule(), p.str_min, p.str_max, p.scale);

        float width = p.str_max.x - p.str_min.x;

        // Check titles width
        if (mol_idx < params.titles.size())
        {
            const Array<char>& title = params.titles[mol_idx];

            if (title.size() > 0)
            {
                int longest_line = _getLongestLine(title);

                // On average letters has width 6
                float letter_width = params.rOpt.titleFontFactor / 1.5f;

                float title_width = longest_line * letter_width / MoleculeCdxmlSaver::SCALE;
                title_widths[mol_idx] = title_width;
                width = std::max(width, title_width);
            }
        }
        if (params.rOpt.cdxml_context.get() != NULL)
        {
            RenderCdxmlContext& context = *params.rOpt.cdxml_context;
            if (context.enabled)
            {
                RenderCdxmlContext::PropertyData& data = context.property_data.at(mol_idx);
                float letter_width = context.propertyFontSize / 1.5f;
                int longest_line = _getLongestLineXml(data.propertyName);

                key_widths[mol_idx] = longest_line * letter_width / MoleculeCdxmlSaver::SCALE;

                longest_line += _getLongestLineXml(data.propertyValue);
                float prop_width = longest_line * letter_width / MoleculeCdxmlSaver::SCALE;
                prop_widths[mol_idx] = prop_width;

                width = std::max(width, prop_width);
            }
        }

        column_widths[column] = std::max(width, column_widths[column]);
    }

    float x_margins_base = 1.1f, y_margins_base = 1.1f;
    float x_grid_base = 1.5f;

    Array<float> column_offset;
    column_offset.resize(params.cnvOpt.gridColumnNumber);
    column_offset[0] = params.cnvOpt.marginX / 10.0f + x_margins_base;
    for (int i = 1; i < params.cnvOpt.gridColumnNumber; i++)
        column_offset[i] = column_offset[i - 1] + column_widths[i - 1] + x_grid_base;

    float page_y_offset_base = params.cnvOpt.marginY / 10.0f + y_margins_base;
    float row_y_offset = page_y_offset_base;
    int last_row = 0;
    float max_y = 0;

    float title_y = 0;

    // Get each structure bounds
    int row_moved = 0;
    for (int mol_idx = 0; mol_idx < mols.size(); ++mol_idx)
    {
        Pos& p = positions[mol_idx];

        int column = mol_idx % params.cnvOpt.gridColumnNumber;
        int row = mol_idx / params.cnvOpt.gridColumnNumber;

        p.page_offset.x = column_offset[column];
        p.page_offset.y = row_y_offset;

        p.size.diff(p.str_max, p.str_min);
        p.all_size = p.size;

        if (mol_idx < params.titles.size())
        {
            const Array<char>& title = params.titles[mol_idx];
            if (title.size() > 0)
            {
                int lines = title.count('\n') + 1;
                float letter_height = params.rOpt.titleFontFactor / MoleculeCdxmlSaver::SCALE;
                // float title_height = lines * saver.textLineHeight();
                // p.all_size.y += title_height + saver.textLineHeight(); // Add blank line
                float title_height = lines * letter_height;
                title_heights[mol_idx] = title_height;
                p.all_size.y += title_height + letter_height; // Add blank line
            }
        }
        if (params.rOpt.cdxml_context.get() != NULL)
        {
            RenderCdxmlContext& context = *params.rOpt.cdxml_context;
            if (context.enabled)
            {
                RenderCdxmlContext::PropertyData& data = context.property_data.at(mol_idx);
                int lines = data.propertyName.count('\n') + 1;

                float letter_height = params.rOpt.titleFontFactor / MoleculeCdxmlSaver::SCALE;
                float prop_height = lines * letter_height;
                p.all_size.y += prop_height + letter_height; // Add blank line
            }
        }

        // Check that the structure is fully on a single page
        int pbegin = (int)(p.page_offset.y / saver.pageHeight());
        int pend = (int)((p.page_offset.y + p.all_size.y) / saver.pageHeight());
        // Additional check that we didn't moved this row before
        if (pbegin != pend && row_moved != row)
        {
            // Update starting row_y_offset for the whole row and start this row again
            row_y_offset = (pbegin + 1) * saver.pageHeight() + page_y_offset_base;
            mol_idx = row * params.cnvOpt.gridColumnNumber - 1;
            row_moved = row;
            continue;
        }

        p.offset.x = p.page_offset.x - p.str_min.x + (column_widths[column] - p.size.x) / 2;
        p.offset.y = -p.page_offset.y - p.str_max.y;

        p.title_offset_y = -p.page_offset.y - p.size.y - 1.0f;

        max_y = std::max(max_y, p.page_offset.y + p.all_size.y);

        int next_row = (mol_idx + 1) / params.cnvOpt.gridColumnNumber;
        if (last_row != next_row)
        {
            row_y_offset = max_y + 1.0f;
            last_row = next_row;
        }
    }

    if (params.cnvOpt.comment.size() > 0)
    {
        int lines = params.cnvOpt.comment.count('\n') + 1;
        float comment_height = lines * 0.3f;
        max_y += 0.3f;
        title_y = max_y;
        max_y += comment_height;
    }

    MoleculeCdxmlSaver::Bounds b;
    b.min.set(0, 0);

    float w = column_offset[params.cnvOpt.gridColumnNumber - 1] + column_widths[params.cnvOpt.gridColumnNumber - 1];
    w += x_margins_base + params.cnvOpt.marginX / 10.0f;

    b.max.set(w, max_y + y_margins_base);
    saver.beginDocument(&b);

    Array<char> font_attr;
    ArrayOutput font_out(font_attr);

    font_out.printf("<s size=\"%f\"", params.rOpt.titleFontFactor);

    if (params.rOpt.cdxml_context.get() != NULL)
    {
        RenderCdxmlContext& context = *params.rOpt.cdxml_context;
        if (context.fonttable.size() > 0)
        {
            saver.addFontTable(context.fonttable.ptr());
        }
        if (context.colortable.size() > 0)
        {
            saver.addColorTable(context.colortable.ptr());
        }
        if (context.titleFont.size() > 0)
        {
            font_out.printf(" font=\"%s\"", context.titleFont.ptr());
        }
        if (context.titleFace.size() > 0)
        {
            font_out.printf(" face=\"%s\"", context.titleFace.ptr());
        }
    }
    font_out.printf(">");
    font_attr.push(0);

    // if (params.rOtitleFont.size() > 0) {
    //   font_out.printf("id=\"5\" charset=\"iso-8859-1\" name=\"%s\"", params.cnvOpt.titleFont.ptr());
    //   font_attr.push(0);
    //   saver.addFontTable(font_attr.ptr());
    //   /*
    //   * Set font as id 5 always
    //   */

    //   font_attr.clear();
    //   if (params.rOpt.titleFontFactor > 1)
    //      font_out.printf(" font=\"5\" size=\"%.0f\"", params.rOpt.titleFontFactor);
    //   else
    //      font_out.printf(" font=\"5\"");
    //} else {
    //   if (params.rOpt.titleFontFactor > 1)
    //      font_out.printf(" size=\"%.0f\"", params.rOpt.titleFontFactor);
    //}
    // font_attr.push(0);
    saver.beginPage(&b);
    Array<char> title_font;

    for (int mol_idx = 0; mol_idx < mols.size(); ++mol_idx)
    {
        int column = mol_idx % params.cnvOpt.gridColumnNumber;

        Pos& p = positions[mol_idx];
        Vec2f offset = p.offset;
        offset.scale(1 / p.scale);
        saver.saveMoleculeFragment(mols[mol_idx]->asMolecule(), offset, p.scale);

        if (mol_idx < params.titles.size())
        {
            const Array<char>& title = params.titles[mol_idx];

            if (title.size() > 0)
            {
                title_font.clear();
                title_font.readString(font_attr.ptr(), false);
                // Get title bounding box
                float x = params.cnvOpt.titleAlign.getAnchorPoint(p.page_offset.x, column_widths[column], title_widths[mol_idx]);

                const char* alignment_str = "";
                MultilineTextLayout alignment = params.cnvOpt.titleAlign;
                if (alignment.inbox_alignment == MultilineTextLayout::Center)
                    alignment_str = "Center";
                if (alignment.inbox_alignment == MultilineTextLayout::Left)
                    alignment_str = "Left";
                if (alignment.inbox_alignment == MultilineTextLayout::Right)
                    alignment_str = "Right";

                Vec2f title_offset(x, p.title_offset_y);
                title_font.appendString(title.ptr(), true);
                title_font.appendString("</s>", true);

                saver.addCustomText(title_offset, alignment_str, params.rOpt.titleFontFactor, title_font.ptr());
            }
        }
        if (params.rOpt.cdxml_context.get() != NULL)
        {
            RenderCdxmlContext& context = *params.rOpt.cdxml_context;
            if (context.enabled)
            {
                RenderCdxmlContext::PropertyData& data = context.property_data.at(mol_idx);
                float prop_width = prop_widths[mol_idx];
                float key_width = key_widths[mol_idx];
                float prop_offset_y = p.title_offset_y - title_heights[mol_idx];
                float x = params.cnvOpt.titleAlign.getAnchorPoint(p.page_offset.x, column_widths[column], prop_width);

                float prop_offset_key = prop_width * 0.5f;
                float prop_offset_val = prop_offset_key - (prop_width - key_width);
                if (context.keyAlignment == RenderCdxmlContext::ALIGNMENT_LEFT)
                {
                    Vec2f title_offset_key(x - prop_offset_key, prop_offset_y);
                    Vec2f title_offset_val(x + prop_offset_val, prop_offset_y);
                    saver.addCustomText(title_offset_key, "Left", context.propertyFontSize, data.propertyName.ptr());
                    saver.addCustomText(title_offset_val, "Left", context.propertyFontSize, data.propertyValue.ptr());
                }
                else
                {
                    Vec2f title_offset_key(x + prop_offset_val, prop_offset_y);
                    Vec2f title_offset_val(x + prop_offset_val, prop_offset_y);
                    saver.addCustomText(title_offset_key, "Right", context.propertyFontSize, data.propertyName.ptr());
                    saver.addCustomText(title_offset_val, "Left", context.propertyFontSize, data.propertyValue.ptr());
                }
            }
        }
    }

    if (params.cnvOpt.comment.size() > 0)
    {
        Vec2f pos(b.max.x / 2, -title_y);
        saver.addText(pos, params.cnvOpt.comment.ptr());
    }

    saver.endPage();
    saver.endDocument();
}