core/indigo-core/layout/metalayout.h (270 lines of code) (raw):

/**************************************************************************** * Copyright (C) from 2009 to Present EPAM Systems. * * This file is part of Indigo toolkit. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ***************************************************************************/ #ifndef __metalayout_h__ #define __metalayout_h__ #include "base_cpp/obj_array.h" #include "base_cpp/reusable_obj_array.h" #include "math/algebra.h" #include "molecule/elements.h" #include <cstdint> #ifdef _WIN32 #pragma warning(push, 4) #pragma warning(disable : 4251) #endif namespace indigo { class BaseMolecule; class DLLEXPORT Metalayout { public: struct DLLEXPORT LayoutItem { enum class ItemVerticalAlign { ECenter, ETop, EBottom }; enum class Type { EMolecule = 0, ESpace = 1 }; LayoutItem() { clear(); } void clear() { verticalAlign = ItemVerticalAlign::ECenter; type = Type::EMolecule; id = 0; isMoleculeFragment = false; min.zero(); max.zero(); scaledSize.zero(); scaledOffset.zero(); scaleFactor.zero(); minScaledSize.zero(); } Type type; int id; bool isMoleculeFragment; ItemVerticalAlign verticalAlign; Vec2f min, max; Vec2f scaledSize, scaledOffset, minScaledSize; Vec2f scaleFactor; }; class DLLEXPORT LayoutLine { public: LayoutLine(); ~LayoutLine(); void clear(); ObjArray<LayoutItem> items; float height; float top_height; float bottom_height; float width; private: LayoutLine(const LayoutLine&); }; Metalayout(); void clear(); bool isEmpty() const; void prepare(); // calculates averageBondLength and scaleFactor float getAverageBondLength() const; float getScaleFactor() const; const Vec2f& getContentSize() const; void process(); LayoutLine& newLine(); static void getBoundRect(Vec2f& min, Vec2f& max, BaseMolecule& mol); void calcContentSize(); void scaleMoleculesSize(); void* context; void (*cb_process)(LayoutItem& item, const Vec2f& pos, void* context); BaseMolecule& (*cb_getMol)(int id, void* context); static float getTotalMoleculeBondLength(BaseMolecule& mol); static float getTotalMoleculeClosestDist(BaseMolecule& mol); // utility function to use in MoleculeLayout & ReactionLayout void adjustMol(BaseMolecule& mol, const Vec2f& min, const Vec2f& pos) const; float reactionComponentMarginSize; // in angstrom float verticalIntervalFactor; float bondLength; // in angstrom DECL_ERROR; private: Vec2f _contentSize; float _avel, _scaleFactor, _offset; float _getAverageBondLength(); ReusableObjArray<LayoutLine> _layout; }; struct UnitsOfMeasure { enum TYPE { PT, PX, INCH, CM }; static constexpr float INCH_TO_CM = 2.54f; static constexpr float INCH_TO_PT = 72.0f; static float convertInchesToPx(const float inches, const int32_t ppi) { return inches * ppi; } static float convertPxToInches(const float pixels, const int32_t ppi) { return pixels / ppi; } static float convertToPx(const float input, const TYPE units, const int32_t ppi) { switch (units) { case (PT): return convertInchesToPx(input / INCH_TO_PT, ppi); break; case (INCH): return convertInchesToPx(input, ppi); break; case (CM): return convertInchesToPx(input / INCH_TO_CM, ppi); break; default: return input; } } static float convertToPt(const float input, const TYPE units, const int32_t ppi) { switch (units) { case (PX): return convertPxToInches(input, ppi) * INCH_TO_PT; break; case (INCH): return input * INCH_TO_PT; break; case (CM): return (input * INCH_TO_PT) / INCH_TO_CM; break; default: return input; } } static float convertToInches(const float input, const TYPE units, const int32_t ppi) { switch (units) { case (PT): return input / INCH_TO_PT; break; case (PX): return convertPxToInches(input, ppi); break; case (CM): return input / INCH_TO_CM; break; default: return input; } } static float convertToCm(const float input, const TYPE units, const int32_t ppi) { switch (units) { case (PT): return (input * INCH_TO_CM) / INCH_TO_PT; break; case (INCH): return input * INCH_TO_CM; break; case (PX): return convertPxToInches(input, ppi) * INCH_TO_CM; break; default: return input; } } static float convertPtTo(float pt, UnitsOfMeasure::TYPE unit, int32_t ppi) { switch (unit) { case UnitsOfMeasure::CM: return UnitsOfMeasure::convertToCm(pt, UnitsOfMeasure::PT, ppi); break; case UnitsOfMeasure::PT: return pt; break; case UnitsOfMeasure::INCH: return UnitsOfMeasure::convertToInches(pt, UnitsOfMeasure::PT, ppi); break; case UnitsOfMeasure::PX: return UnitsOfMeasure::convertToPx(pt, UnitsOfMeasure::PT, ppi); break; } throw Exception("Unknown unit of measure: %d", unit); }; static float convertToAngstrom(float input, TYPE units, int32_t ppi, float bond_length_px) { return convertToPx(input, units, ppi) / bond_length_px; }; }; struct LayoutOptions { // FIXME: The value is 1.6 instead of 1.0 due to backward compatibility, needs to be refactored static constexpr float DEFAULT_BOND_LENGTH = 1.0f; // default length of inter-chemical bonds static constexpr float DEFAULT_MONOMER_BOND_LENGTH = 1.5f; // default length of inter-chemical bonds static constexpr float DEFAULT_PLUS_SIZE = DEFAULT_BOND_LENGTH / 2; static constexpr float DEFAULT_BOND_LENGTH_PX = 100.0f; // 100 pixel static constexpr float DEFAULT_FONT_SIZE_PX = DEFAULT_BOND_LENGTH_PX * 0.4f; static constexpr int32_t DEFAULT_PPI = 72; float bondLength{DEFAULT_BOND_LENGTH_PX}; UnitsOfMeasure::TYPE bondLengthUnit{UnitsOfMeasure::TYPE::PX}; float reactionComponentMarginSize{DEFAULT_BOND_LENGTH_PX / 2}; UnitsOfMeasure::TYPE reactionComponentMarginSizeUnit{UnitsOfMeasure::TYPE::PX}; int32_t ppi{72}; float fontSize{-1}; UnitsOfMeasure::TYPE fontSizeUnit{UnitsOfMeasure::PT}; float fontSizeSub{-1}; UnitsOfMeasure::TYPE fontSizeSubUnit{UnitsOfMeasure::PT}; LABEL_MODE labelMode{LABEL_MODE_TERMINAL_HETERO}; void reset() { bondLength = DEFAULT_BOND_LENGTH_PX; bondLengthUnit = UnitsOfMeasure::TYPE::PX; reactionComponentMarginSize = DEFAULT_BOND_LENGTH_PX / 2; reactionComponentMarginSizeUnit = UnitsOfMeasure::TYPE::PX; ppi = DEFAULT_PPI; fontSize = -1; fontSizeUnit = UnitsOfMeasure::PT; fontSizeSub = -1; fontSizeSubUnit = UnitsOfMeasure::PT; labelMode = LABEL_MODE_TERMINAL_HETERO; }; float getBondLengthPx() { return UnitsOfMeasure::convertToPx(bondLength, bondLengthUnit, ppi); }; void setBondLengthPx(float value) { bondLength = UnitsOfMeasure::convertPtTo(UnitsOfMeasure::INCH_TO_PT * value / ppi, bondLengthUnit, ppi); }; float getMarginSizeInAngstroms() const { auto marginSizePt = UnitsOfMeasure::convertToPt(reactionComponentMarginSize, reactionComponentMarginSizeUnit, ppi); auto bondLengthPt = UnitsOfMeasure::convertToPt(bondLength, bondLengthUnit, ppi); return marginSizePt / bondLengthPt; }; void setMarginSizeInAngstroms(float value) { float angs_to_pt = UnitsOfMeasure::convertToPt(bondLength, bondLengthUnit, ppi); reactionComponentMarginSize = UnitsOfMeasure::convertPtTo(value * angs_to_pt, reactionComponentMarginSizeUnit, ppi); }; float getFontSizeInAngstroms() const { auto fontSizePt = UnitsOfMeasure::convertToPt(fontSize, fontSizeUnit, ppi); auto bondLengthPt = UnitsOfMeasure::convertToPt(bondLength, bondLengthUnit, ppi); return fontSizePt / bondLengthPt; }; }; } // namespace indigo #ifdef _WIN32 #pragma warning(pop) #endif #endif //__metalayout_h__