// Translate branch on 0.1 of vector [v1,v2] void RefinementState::stretchBranch (const Filter &branch, const RefinementState &state, int v1_idx, int v2_idx, int val) { int i; float r, sh = 0.1f * val; const Vec2f &v1 = state.layout[v1_idx]; const Vec2f &v2 = state.layout[v2_idx]; Vec2f d; d.diff(v2, v1); r = d.length(); if (r < EPSILON) throw Error("too small edge"); d.scale(sh / r); if (branch.valid(v1_idx)) d.negate(); layout.clear_resize(state.layout.size()); for (i = _graph.vertexBegin(); i < _graph.vertexEnd(); i = _graph.vertexNext(i)) { if (!branch.valid(i)) layout[i].sum(state.layout[i], d); else layout[i] = state.layout[i]; } }
void _getBounds (RenderParams& params, BaseMolecule &mol, Vec2f &min, Vec2f &max, float &scale) { // Compute average bond length float avg_bond_length = 1; if (mol.edgeCount() > 0) { float bond_length_sum = 0; for (int i = mol.edgeBegin(); i != mol.edgeEnd(); i = mol.edgeNext(i)) { const Edge& edge = mol.getEdge(i); const Vec3f &p1 = mol.getAtomXyz(edge.beg); const Vec3f &p2 = mol.getAtomXyz(edge.end); bond_length_sum += Vec3f::dist(p1, p2); } avg_bond_length = bond_length_sum / mol.edgeCount(); } float bond_length = 1; if (params.cnvOpt.bondLength > 0) bond_length = params.cnvOpt.bondLength / 100.0f; scale = bond_length / avg_bond_length; for (int i = mol.vertexBegin(); i != mol.vertexEnd(); i = mol.vertexNext(i)) { Vec3f &p = mol.getAtomXyz(i); Vec2f p2(p.x, p.y); if (i == mol.vertexBegin()) min = max = p2; else { min.min(p2); max.max(p2); } } min.scale(scale); max.scale(scale); }
void MoleculeLayout::_updateDataSGroups () { // Move Data-SGroups with absolute coordinates according to new position QS_DEF(Array<int>, layout_graph_mapping); layout_graph_mapping.resize(_molecule.vertexEnd()); layout_graph_mapping.fffill(); for (int i = _layout_graph->vertexBegin(); i < _layout_graph->vertexEnd(); i = _layout_graph->vertexNext(i)) { int vi = _layout_graph->getVertexExtIdx(i); layout_graph_mapping[vi] = i; } for (int i = _molecule.sgroups.begin(); i != _molecule.sgroups.end(); i = _molecule.sgroups.next(i)) { SGroup &sg = _molecule.sgroups.getSGroup(i); if (sg.sgroup_type == SGroup::SG_TYPE_DAT) { DataSGroup &group = (DataSGroup &)sg; if (!group.relative) { Vec2f before; _molecule.getSGroupAtomsCenterPoint(group, before); Vec2f after; for (int j = 0; j < group.atoms.size(); j++) { int ai = group.atoms[j]; const LayoutVertex &vert = _layout_graph->getLayoutVertex(layout_graph_mapping[ai]); after.x += vert.pos.x; after.y += vert.pos.y; } if (group.atoms.size() != 0) after.scale(1.0f / group.atoms.size()); Vec2f delta; delta.diff(after, before); group.display_pos.add(delta); } } } }
void Metalayout::adjustMol (BaseMolecule& mol, const Vec2f& min, const Vec2f& pos) { float scaleFactor = getScaleFactor(); // Compute center points for the data sgroups QS_DEF(Array<Vec2f>, data_centers); data_centers.resize(mol.data_sgroups.end()); for (int i = mol.data_sgroups.begin(); i < mol.data_sgroups.end(); i = mol.data_sgroups.next(i)) { BaseMolecule::DataSGroup &group = mol.data_sgroups[i]; if (!group.relative) mol.getSGroupAtomsCenterPoint(group, data_centers[i]); } for (int i = mol.vertexBegin(); i < mol.vertexEnd(); i = mol.vertexNext(i)) { Vec2f v; Vec2f::projectZ(v, mol.getAtomXyz(i)); v.sub(min); v.scale(scaleFactor); v.add(pos); v.y = -v.y; mol.setAtomXyz(i, v.x, v.y, 0); } // Adjust data-sgroup label positions with absolute coordinates for (int i = mol.data_sgroups.begin(); i < mol.data_sgroups.end(); i = mol.data_sgroups.next(i)) { BaseMolecule::DataSGroup &group = mol.data_sgroups[i]; if (!group.relative) { Vec2f new_center; mol.getSGroupAtomsCenterPoint(group, new_center); group.display_pos.add(new_center); group.display_pos.sub(data_centers[i]); } } }
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()); Vec2f offset(0, 0); 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::BOND_LENGTH; title_widths[mol_idx] = title_width; width = __max(width, title_width); } } if (params.rOpt.cdxml_context.get() != NULL) { RenderCdxmlContext& context = params.rOpt.cdxml_context.ref(); 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::BOND_LENGTH; longest_line += _getLongestLineXml(data.propertyValue); float prop_width = longest_line * letter_width / MoleculeCdxmlSaver::BOND_LENGTH; prop_widths[mol_idx] = prop_width; width = __max(width, prop_width); } } column_widths[column] = __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::BOND_LENGTH; //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.ref(); 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::BOND_LENGTH; 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 = __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.ref(); 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, -1, ids); 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.ref(); 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(); }