diff --git a/api/c/indigo-renderer/src/indigo_render2d.cpp b/api/c/indigo-renderer/src/indigo_render2d.cpp index f40519a07e..b97f12f171 100644 --- a/api/c/indigo-renderer/src/indigo_render2d.cpp +++ b/api/c/indigo-renderer/src/indigo_render2d.cpp @@ -376,6 +376,18 @@ void indigoRenderGetCommentPosition(Array& value) value.readString("bottom", true); } +static void indigoSetBondLength(float value) +{ + Indigo& self = indigoGetInstance(); + self.layout_options.setBondLengthPx(value); +} + +static void indigoGetBondLength(float& value) +{ + Indigo& self = indigoGetInstance(); + value = self.layout_options.getBondLengthPx(); +} + RenderCdxmlContext& getCdxmlContext() { RenderParams& rp = indigoRendererGetInstance().renderParams; @@ -437,6 +449,24 @@ CEXPORT int indigoRendererDispose(const qword id) INDIGO_END(-1); } +static void setParams(RenderParams& rp, LayoutOptions& layout_options) +{ + rp.cnvOpt.bondLength = layout_options.bondLength; + rp.cnvOpt.bondLengthUnit = layout_options.bondLengthUnit; + rp.rOpt.ppi = layout_options.ppi; + rp.rOpt.bond_length_px = layout_options.bondLength > EPSILON ? layout_options.getBondLengthPx() : LayoutOptions::DEFAULT_BOND_LENGTH_PX; + if (rp.cnvOpt.outputSheetWidth > 0) + { + rp.cnvOpt.maxHeight = -1; + rp.cnvOpt.maxWidth = UnitsOfMeasure::convertInchesToPx(rp.cnvOpt.outputSheetWidth, layout_options.ppi); + } + else if (rp.cnvOpt.outputSheetHeight > 0) + { + rp.cnvOpt.maxHeight = UnitsOfMeasure::convertInchesToPx(rp.cnvOpt.outputSheetHeight, layout_options.ppi); + rp.cnvOpt.maxWidth = -1; + } +} + CEXPORT int indigoRender(int object, int output) { INDIGO_BEGIN @@ -447,6 +477,8 @@ CEXPORT int indigoRender(int object, int output) rp.clearArrays(); rp.smart_layout = self.smart_layout; + setParams(rp, indigoGetInstance().layout_options); + IndigoObject& obj = self.getObject(object); if (IndigoBaseMolecule::is(obj)) @@ -502,6 +534,8 @@ CEXPORT int indigoRenderGrid(int objects, int* refAtoms, int nColumns, int outpu RenderParams& rp = indigoRendererGetInstance().renderParams; rp.clearArrays(); + setParams(rp, indigoGetInstance().layout_options); + PtrArray& objs = IndigoArray::cast(self.getObject(objects)).objects; if (rp.rOpt.cdxml_context.get() != NULL) { @@ -690,12 +724,6 @@ void IndigoRenderer::setOptionsHandlers() #define cdxmlContext getCdxmlContext() #define indigo indigoGetInstance() - rp.cnvOpt.bondLength = indigo.layout_options.bondLength; - rp.cnvOpt.bondLengthUnit = indigo.layout_options.bondLengthUnit; - rp.rOpt.reactionComponentMarginSize = indigo.layout_options.reactionComponentMarginSize; - rp.rOpt.reactionComponentMarginSizeUnit = indigo.layout_options.reactionComponentMarginSizeUnit; - rp.rOpt.ppi = indigo.layout_options.ppi; - mgr->setOptionHandlerInt("render-comment-offset", SETTER_GETTER_INT_OPTION(rp.cnvOpt.commentOffset)); mgr->setOptionHandlerInt("render-image-width", SETTER_GETTER_INT_OPTION(rp.cnvOpt.width)); mgr->setOptionHandlerInt("render-image-height", SETTER_GETTER_INT_OPTION(rp.cnvOpt.height)); @@ -723,7 +751,7 @@ void IndigoRenderer::setOptionsHandlers() mgr->setOptionHandlerBool("render-highlighted-labels-visible", SETTER_GETTER_BOOL_OPTION(rp.rOpt.highlightedLabelsVisible)); mgr->setOptionHandlerBool("render-bold-bond-detection", SETTER_GETTER_BOOL_OPTION(rp.rOpt.boldBondDetection)); - mgr->setOptionHandlerFloat("render-bond-length", SETTER_GETTER_FLOAT_OPTION(rp.cnvOpt.bondLength)); + mgr->setOptionHandlerFloat("render-bond-length", indigoSetBondLength, indigoGetBondLength); mgr->setOptionHandlerFloat("render-relative-thickness", SET_POSITIVE_FLOAT_OPTION(rp.relativeThickness, "relative thickness must be positive")); mgr->setOptionHandlerFloat("render-bond-line-width", SET_POSITIVE_FLOAT_OPTION(rp.bondLineWidthFactor, "bond line width factor must be positive")); mgr->setOptionHandlerFloat("render-comment-font-size", SETTER_GETTER_FLOAT_OPTION(rp.rOpt.commentFontFactor)); @@ -760,5 +788,24 @@ void IndigoRenderer::setOptionsHandlers() mgr->setOptionHandlerString("render-cdxml-title-face", SETTER_GETTER_STR_OPTION(cdxmlContext.titleFace)); mgr->setOptionHandlerVoid("reset-render-options", indigoRenderResetOptions); + + // ACS style options + mgr->setOptionHandlerFloat("render-font-size", SETTER_GETTER_FLOAT_OPTION(rp.rOpt.fontSize)); + mgr->setOptionHandlerString("render-font-size-unit", Indigo::setUnitsOfMeasure(rp.rOpt.fontSizeUnit), Indigo::getUnitsOfMeasure(rp.rOpt.fontSizeUnit)); + mgr->setOptionHandlerFloat("render-font-size-sub", SETTER_GETTER_FLOAT_OPTION(rp.rOpt.fontSizeSub)); + mgr->setOptionHandlerString("render-font-size-sub-unit", Indigo::setUnitsOfMeasure(rp.rOpt.fontSizeSubUnit), + Indigo::getUnitsOfMeasure(rp.rOpt.fontSizeSubUnit)); + mgr->setOptionHandlerFloat("render-bond-thickness", SETTER_GETTER_FLOAT_OPTION(rp.rOpt.bondThickness)); + mgr->setOptionHandlerString("render-bond-thickness-unit", Indigo::setUnitsOfMeasure(rp.rOpt.bondThicknessUnit), + Indigo::getUnitsOfMeasure(rp.rOpt.bondThicknessUnit)); + mgr->setOptionHandlerFloat("render-bond-spacing", SETTER_GETTER_FLOAT_OPTION(rp.rOpt.bondSpacing)); + mgr->setOptionHandlerFloat("render-stereo-bond-width", SETTER_GETTER_FLOAT_OPTION(rp.rOpt.stereoBondWidth)); + mgr->setOptionHandlerString("render-stereo-bond-width-unit", Indigo::setUnitsOfMeasure(rp.rOpt.stereoBondWidthUnit), + Indigo::getUnitsOfMeasure(rp.rOpt.stereoBondWidthUnit)); + mgr->setOptionHandlerFloat("render-hash-spacing", SETTER_GETTER_FLOAT_OPTION(rp.rOpt.hashSpacing)); + mgr->setOptionHandlerString("render-hash-spacing-unit", Indigo::setUnitsOfMeasure(rp.rOpt.hashSpacingUnit), + Indigo::getUnitsOfMeasure(rp.rOpt.hashSpacingUnit)); + mgr->setOptionHandlerFloat("render-output-sheet-width", SETTER_GETTER_FLOAT_OPTION(rp.cnvOpt.outputSheetWidth)); + mgr->setOptionHandlerFloat("render-output-sheet-height", SETTER_GETTER_FLOAT_OPTION(rp.cnvOpt.outputSheetHeight)); } } diff --git a/api/c/indigo/src/indigo.cpp b/api/c/indigo/src/indigo.cpp index be3f795e3e..971b1afcb4 100644 --- a/api/c/indigo/src/indigo.cpp +++ b/api/c/indigo/src/indigo.cpp @@ -504,6 +504,56 @@ void IndigoPluginContext::validate() // // Options registrator // +IndigoOptionManager::optf_string_t Indigo::setUnitsOfMeasure(UnitsOfMeasure::TYPE& result) +{ + static thread_local auto func = [&result](const char* mode) { + if (strcmp(mode, "pt") == 0) + { + result = UnitsOfMeasure::TYPE::PT; + } + else if (strcmp(mode, "px") == 0) + { + result = UnitsOfMeasure::TYPE::PX; + } + else if (strcmp(mode, "inch") == 0) + { + result = UnitsOfMeasure::TYPE::INCH; + } + else if (strcmp(mode, "cm") == 0) + { + result = UnitsOfMeasure::TYPE::CM; + } + else + { + throw IndigoError("Invalid size unit, should be 'px', 'pt', 'inch' or 'all'"); + } + }; + + return [](const char* mode) -> void { return func(mode); }; +} + +IndigoOptionManager::get_optf_string_t Indigo::getUnitsOfMeasure(const UnitsOfMeasure::TYPE& input) +{ + static thread_local auto func = [&input](Array& result) { + switch (input) + { + case UnitsOfMeasure::TYPE::PT: + result.readString("pt", true); + break; + case UnitsOfMeasure::TYPE::PX: + result.readString("px", true); + break; + case UnitsOfMeasure::TYPE::INCH: + result.readString("inch", true); + break; + case UnitsOfMeasure::TYPE::CM: + result.readString("cm", true); + break; + } + }; + + return [](Array& res) -> void { return func(res); }; +} // // Debug methods diff --git a/api/c/indigo/src/indigo_internal.h b/api/c/indigo/src/indigo_internal.h index bab466f132..6b04c63370 100644 --- a/api/c/indigo/src/indigo_internal.h +++ b/api/c/indigo/src/indigo_internal.h @@ -295,6 +295,9 @@ class DLLEXPORT Indigo // Method that returns temporary buffer that can be returned from Indigo C API methods static TmpData& getThreadTmpData(); + static IndigoOptionManager::optf_string_t setUnitsOfMeasure(UnitsOfMeasure::TYPE& result); + static IndigoOptionManager::get_optf_string_t getUnitsOfMeasure(const UnitsOfMeasure::TYPE& input); + ProductEnumeratorParams rpe_params; MoleculeFingerprintParameters fp_params; PtrArray tautomer_rules; @@ -339,7 +342,6 @@ class DLLEXPORT Indigo int layout_max_iterations = 0; // default is zero -- no limit bool smart_layout = false; - float layout_horintervalfactor = ReactionLayout::DEFAULT_HOR_INTERVAL_FACTOR; bool layout_preserve_existing = false; int layout_orientation = 0; diff --git a/api/c/indigo/src/indigo_layout.cpp b/api/c/indigo/src/indigo_layout.cpp index ed27684f50..fc35c2c9ba 100644 --- a/api/c/indigo/src/indigo_layout.cpp +++ b/api/c/indigo/src/indigo_layout.cpp @@ -28,12 +28,15 @@ #include "layout/reaction_layout.h" #include "reaction/base_reaction.h" +#ifdef _WIN32 +#pragma warning(push, 4) +#endif + CEXPORT int indigoLayout(int object) { INDIGO_BEGIN { IndigoObject& obj = self.getObject(object); - int i; if (IndigoBaseMolecule::is(obj)) { @@ -79,7 +82,7 @@ CEXPORT int indigoLayout(int object) catch (Exception e) { } - for (i = 1; i <= mol->rgroups.getRGroupCount(); i++) + for (int i = 1; i <= mol->rgroups.getRGroupCount(); i++) { RGroup& rgp = mol->rgroups.getRGroup(i); @@ -112,9 +115,6 @@ CEXPORT int indigoLayout(int object) ReactionLayout rl(rxn, self.smart_layout, self.layout_options); rl.setMaxIterations(self.layout_max_iterations); rl.setLayoutOrientation((LAYOUT_ORIENTATION)self.layout_orientation); - // TODO::ACS Why removed? - // rl.bond_length = LayoutOptions::DEFAULT_BOND_LENGTH; - // rl.reaction_margin_size = self.layout_horintervalfactor; if (self.layout_preserve_existing) rl.setPreserveMoleculeLayout(true); rl.make(); @@ -197,3 +197,7 @@ CEXPORT int indigoClean2d(int object) } INDIGO_END(-1); } + +#ifdef _WIN32 +#pragma warning(pop) +#endif diff --git a/api/c/indigo/src/indigo_options.cpp b/api/c/indigo/src/indigo_options.cpp index 41e610c7d7..3c6489ea7c 100644 --- a/api/c/indigo/src/indigo_options.cpp +++ b/api/c/indigo/src/indigo_options.cpp @@ -138,13 +138,13 @@ static void indigoGetEmbeddingUniqueness(Array& value) static void indigoSetLayoutHorIntervalFactor(float value) { Indigo& self = indigoGetInstance(); - self.layout_horintervalfactor = value; + self.layout_options.setMarginSizeInAngstroms(value); } static void indigoGetLayoutHorIntervalFactor(float& value) { Indigo& self = indigoGetInstance(); - value = self.layout_horintervalfactor; + value = self.layout_options.getMarginSizeInAngstroms(); } static void indigoSetAromaticityModel(const char* model) @@ -238,6 +238,7 @@ static void indigoResetBasicOptions() Indigo& self = indigoGetInstance(); self.standardize_options.reset(); self.ionize_options = IonizeOptions(); + self.layout_options.reset(); self.init(); } @@ -261,62 +262,6 @@ void indigoProductEnumeratorGetOneTubeMode(Array& value) value.readString("grid", true); } -bool isEqual(const char* l, const char* r) -{ - return strcmp(l, r) != 0; -} - -IndigoOptionManager::optf_string_t indigoSetUnitsOfMeasure(UnitsOfMeasure::TYPE& result) -{ - static auto func = [&result](const char* mode) { - if (isEqual(mode, "pt")) - { - result = UnitsOfMeasure::TYPE::PT; - } - else if (isEqual(mode, "px")) - { - result = UnitsOfMeasure::TYPE::PX; - } - else if (isEqual(mode, "inch")) - { - result = UnitsOfMeasure::TYPE::INCH; - } - else if (isEqual(mode, "cm")) - { - result = UnitsOfMeasure::TYPE::CM; - } - else - { - throw IndigoError("Invalid size unit, should be 'px', 'pt', 'inch' or 'all'"); - } - }; - - return [](const char* mode) -> void { return func(mode); }; -} - -IndigoOptionManager::get_optf_string_t indigoGetUnitsOfMeasure(const UnitsOfMeasure::TYPE input) -{ - static auto func = [input](Array& result) { - switch (input) - { - case UnitsOfMeasure::TYPE::PT: - result.readString("pt", true); - break; - case UnitsOfMeasure::TYPE::PX: - result.readString("px", true); - break; - case UnitsOfMeasure::TYPE::INCH: - result.readString("inch", true); - break; - case UnitsOfMeasure::TYPE::CM: - result.readString("cm", true); - break; - } - }; - - return [](Array& res) -> void { return func(res); }; -} - void IndigoOptionHandlerSetter::setBasicOptionHandlers(const qword id) { auto mgr = sf::xlock_safe_ptr(indigoGetOptionManager(id)); @@ -442,10 +387,10 @@ void IndigoOptionHandlerSetter::setBasicOptionHandlers(const qword id) mgr->setOptionHandlerBool("transform-layout", SETTER_GETTER_BOOL_OPTION(indigo.rpe_params.transform_is_layout)); mgr->setOptionHandlerFloat("bond-length", SET_POSITIVE_FLOAT_OPTION(indigo.layout_options.bondLength, "bond length must be positive")); - mgr->setOptionHandlerString("bond-length-unit", indigoSetUnitsOfMeasure(indigo.layout_options.bondLengthUnit), - indigoGetUnitsOfMeasure(indigo.layout_options.bondLengthUnit)); + mgr->setOptionHandlerString("bond-length-unit", Indigo::setUnitsOfMeasure(indigo.layout_options.bondLengthUnit), + Indigo::getUnitsOfMeasure(indigo.layout_options.bondLengthUnit)); mgr->setOptionHandlerFloat("reaction-component-margin-size", SETTER_GETTER_FLOAT_OPTION(indigo.layout_options.reactionComponentMarginSize)); - mgr->setOptionHandlerString("reaction-component-margin-size-unit", indigoSetUnitsOfMeasure(indigo.layout_options.reactionComponentMarginSizeUnit), - indigoGetUnitsOfMeasure(indigo.layout_options.reactionComponentMarginSizeUnit)); + mgr->setOptionHandlerString("reaction-component-margin-size-unit", Indigo::setUnitsOfMeasure(indigo.layout_options.reactionComponentMarginSizeUnit), + Indigo::getUnitsOfMeasure(indigo.layout_options.reactionComponentMarginSizeUnit)); mgr->setOptionHandlerInt("image-resolution", SET_POSITIVE_INT_OPTION(indigo.layout_options.ppi, "image resolution ppi must be positive")); } \ No newline at end of file diff --git a/api/tests/integration/ref/layout/acs_style_reaction.py.out b/api/tests/integration/ref/layout/acs_style_reaction.py.out index e9a1468b1b..cecbd70937 100644 --- a/api/tests/integration/ref/layout/acs_style_reaction.py.out +++ b/api/tests/integration/ref/layout/acs_style_reaction.py.out @@ -15,4 +15,4 @@ Molecule #4: Success *** 2389 wrong margin *** -acs_issue_2389.ket.ket:SUCCEED +acs_issue_2389.ket:SUCCEED diff --git a/api/tests/integration/tests/layout/acs_style_reaction.py b/api/tests/integration/tests/layout/acs_style_reaction.py index 8bb2ac28cb..562ab62f79 100644 --- a/api/tests/integration/tests/layout/acs_style_reaction.py +++ b/api/tests/integration/tests/layout/acs_style_reaction.py @@ -72,7 +72,7 @@ def find_diff(a, b): ket = rxn.json() diff = find_diff(ket_ref, ket) if not diff: - print(filename + ".ket:SUCCEED") + print(filename + ":SUCCEED") else: - print(filename + ".ket:FAILED") + print(filename + ":FAILED") print(diff) diff --git a/api/tests/integration/tests/layout/ref/932-agents.ket b/api/tests/integration/tests/layout/ref/932-agents.ket index 02732241e6..3fa3fa661f 100644 --- a/api/tests/integration/tests/layout/ref/932-agents.ket +++ b/api/tests/integration/tests/layout/ref/932-agents.ket @@ -51,7 +51,7 @@ { "type": "plus", "location": [ - 8.400002, + 8.400001, 0.0, 0.0 ] @@ -78,7 +78,7 @@ "mode": "open-angle", "pos": [ { - "x": 13.600001, + "x": 13.6, "y": 0.0, "z": 0.0 }, @@ -150,7 +150,7 @@ { "label": "S", "location": [ - 6.400001, + 6.4, 0.0, 0.0 ] @@ -164,7 +164,7 @@ { "label": "C", "location": [ - 10.400002, + 10.400001, 0.8, 0.0 ] @@ -172,7 +172,7 @@ { "label": "C", "location": [ - 12.000001, + 12.0, 0.8, 0.0 ] @@ -180,7 +180,7 @@ { "label": "C", "location": [ - 12.000001, + 12.0, -0.8, 0.0 ] @@ -188,7 +188,7 @@ { "label": "C", "location": [ - 10.400002, + 10.400001, -0.8, 0.0 ] @@ -231,8 +231,8 @@ { "label": "C", "location": [ - 15.200002, - 2.39282, + 15.200001, + 2.69282, 0.0 ] }, @@ -240,15 +240,15 @@ "label": "C", "location": [ 16.585642, - 1.59282, + 1.89282, 0.0 ] }, { "label": "C", "location": [ - 17.971283, - 2.39282, + 17.971281, + 2.69282, 0.0 ] } @@ -276,8 +276,8 @@ { "label": "C", "location": [ - 20.371281, - 1.99282, + 20.371279, + 2.29282, 0.0 ] } @@ -290,8 +290,8 @@ { "label": "P", "location": [ - 22.771278, - 1.99282, + 22.771276, + 2.29282, 0.0 ] } @@ -304,24 +304,24 @@ { "label": "C", "location": [ - 25.171276, - 2.39282, + 25.171274, + 2.69282, 0.0 ] }, { "label": "C", "location": [ - 26.556917, - 1.59282, + 26.556915, + 1.89282, 0.0 ] }, { "label": "C", "location": [ - 27.942556, - 2.39282, + 27.942554, + 2.69282, 0.0 ] } @@ -349,24 +349,24 @@ { "label": "C", "location": [ - 30.342554, - 2.685641, + 30.342552, + 2.985641, 0.0 ] }, { "label": "C", "location": [ - 31.942554, - 2.685641, + 31.942553, + 2.985641, 0.0 ] }, { "label": "C", "location": [ - 31.142553, - 1.3, + 31.142551, + 1.6, 0.0 ] } @@ -402,7 +402,7 @@ "label": "F", "location": [ 34.342552, - 1.99282, + 2.29282, 0.0 ] } @@ -416,7 +416,7 @@ "label": "I", "location": [ 36.74255, - 1.99282, + 2.29282, 0.0 ] } diff --git a/api/tests/integration/tests/layout/ref/acs_after_layout_default_margin.ket b/api/tests/integration/tests/layout/ref/acs_after_layout_default_margin.ket index 39fbce4a03..25db5ab4b4 100644 --- a/api/tests/integration/tests/layout/ref/acs_after_layout_default_margin.ket +++ b/api/tests/integration/tests/layout/ref/acs_after_layout_default_margin.ket @@ -298,7 +298,7 @@ "label": "N", "location": [ 17.525787, - 4.80503, + 5.10503, 0.0 ] }, @@ -306,7 +306,7 @@ "label": "N", "location": [ 15.925788, - 4.80503, + 5.10503, 0.0 ] }, @@ -314,7 +314,7 @@ "label": "C", "location": [ 14.928204, - 3.5541, + 3.8541, 0.0 ] }, @@ -322,7 +322,7 @@ "label": "C", "location": [ 15.284236, - 1.994215, + 2.294215, 0.0 ] }, @@ -330,7 +330,7 @@ "label": "C", "location": [ 18.523373, - 3.554097, + 3.854097, 0.0 ] }, @@ -338,7 +338,7 @@ "label": "N", "location": [ 16.725786, - 1.3, + 1.6, 0.0 ] }, @@ -346,7 +346,7 @@ "label": "C", "location": [ 18.167337, - 1.994213, + 2.294213, 0.0 ] } diff --git a/api/tests/integration/tests/layout/ref/acs_after_layout_zero_margin.ket b/api/tests/integration/tests/layout/ref/acs_after_layout_zero_margin.ket index e9fa3ff5ad..ebdf125553 100644 --- a/api/tests/integration/tests/layout/ref/acs_after_layout_zero_margin.ket +++ b/api/tests/integration/tests/layout/ref/acs_after_layout_zero_margin.ket @@ -298,7 +298,7 @@ "label": "N", "location": [ 14.325787, - 4.00503, + 4.30503, 0.0 ] }, @@ -306,7 +306,7 @@ "label": "N", "location": [ 12.725787, - 4.00503, + 4.30503, 0.0 ] }, @@ -314,7 +314,7 @@ "label": "C", "location": [ 11.728203, - 2.754099, + 3.0541, 0.0 ] }, @@ -322,7 +322,7 @@ "label": "C", "location": [ 12.084235, - 1.194215, + 1.494215, 0.0 ] }, @@ -330,7 +330,7 @@ "label": "C", "location": [ 15.323371, - 2.754097, + 3.054097, 0.0 ] }, @@ -338,7 +338,7 @@ "label": "N", "location": [ 13.525785, - 0.5, + 0.8, 0.0 ] }, @@ -346,7 +346,7 @@ "label": "C", "location": [ 14.967336, - 1.194212, + 1.494213, 0.0 ] } diff --git a/api/tests/integration/tests/layout/ref/acs_issue_2389.ket b/api/tests/integration/tests/layout/ref/acs_issue_2389.ket index 1a30999a1a..2bbbd9420c 100644 --- a/api/tests/integration/tests/layout/ref/acs_issue_2389.ket +++ b/api/tests/integration/tests/layout/ref/acs_issue_2389.ket @@ -122,7 +122,7 @@ "label": "C", "location": [ 11.200002, - 1.3, + 1.6, 0.0 ] }, @@ -130,7 +130,7 @@ "label": "C", "location": [ 12.800002, - 1.3, + 1.6, 0.0 ] } @@ -152,7 +152,7 @@ "label": "C", "location": [ 15.200003, - 1.3, + 1.6, 0.0 ] }, @@ -160,7 +160,7 @@ "label": "C", "location": [ 16.800003, - 1.3, + 1.6, 0.0 ] } diff --git a/api/tests/integration/tests/rendering/acs_style.py b/api/tests/integration/tests/rendering/acs_style.py new file mode 100644 index 0000000000..e7569cf337 --- /dev/null +++ b/api/tests/integration/tests/rendering/acs_style.py @@ -0,0 +1,75 @@ +import errno +import os +import sys + +sys.path.append( + os.path.normpath( + os.path.join(os.path.abspath(__file__), "..", "..", "..", "common") + ) +) +from env_indigo import Indigo, IndigoRenderer, joinPathPy # noqa +from rendering import checkImageSimilarity + +if not os.path.exists(joinPathPy("out", __file__)): + try: + os.makedirs(joinPathPy("out", __file__)) + except OSError as e: + if e.errno != errno.EEXIST: + raise + +mol_data = """ + Ketcher 9262423222D 1 1.00000 0.00000 0 + + 12 11 0 0 0 0 0 0 0 0999 V2000 + 21.7000 -12.0410 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 22.2000 -11.1750 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 23.2000 -11.1750 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 23.7000 -10.3090 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 23.7000 -12.0410 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.7000 -10.3090 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 20.7000 -10.3090 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 24.7000 -10.3090 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 20.7000 -12.0410 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 24.7000 -12.0410 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 20.2000 -9.4429 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 25.2000 -9.4429 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 0 0 + 2 3 2 0 0 0 + 3 4 1 0 0 0 + 3 5 1 0 0 0 + 2 6 1 0 0 0 + 6 7 1 1 0 0 + 4 8 1 6 0 0 + 1 9 1 0 0 0 + 5 10 1 0 0 0 + 7 11 1 0 0 0 + 8 12 1 0 0 0 +M END + +""" + +indigo = Indigo() +renderer = IndigoRenderer(indigo) + +print("****** Default rendering settings *****") + +indigo.setOption("ignore-stereochemistry-errors", "true") +indigo.setOption("render-background-color", "255, 255, 255") +indigo.setOption("render-output-format", "png") +mol = indigo.loadMolecule(mol_data) +renderer.renderToFile(mol, joinPathPy("out/acs_style_default.png", __file__)) +print(checkImageSimilarity("acs_style_default.png")) + +print("****** Changed ACS settings *****") +indigo.setOption("bond-length", "1.2") +indigo.setOption("bond-length-unit", "inch") +indigo.setOption("render-bond-spacing", "0.5") +indigo.setOption("render-hash-spacing", "15") +indigo.setOption("render-stereo-bond-width", "30") +indigo.setOption("render-font-size", "20") +renderer.renderToFile(mol, joinPathPy("out/acs_style_changed.png", __file__)) +print(checkImageSimilarity("acs_style_changed.png")) + +if isIronPython(): + renderer.Dispose() + indigo.Dispose() diff --git a/api/tests/integration/tests/rendering/ref/linux/acs_style_changed.png b/api/tests/integration/tests/rendering/ref/linux/acs_style_changed.png new file mode 100644 index 0000000000..2c1b7402c4 Binary files /dev/null and b/api/tests/integration/tests/rendering/ref/linux/acs_style_changed.png differ diff --git a/api/tests/integration/tests/rendering/ref/linux/acs_style_default.png b/api/tests/integration/tests/rendering/ref/linux/acs_style_default.png new file mode 100644 index 0000000000..a702e25f33 Binary files /dev/null and b/api/tests/integration/tests/rendering/ref/linux/acs_style_default.png differ diff --git a/api/tests/integration/tests/rendering/ref/mac/acs_style_changed.png b/api/tests/integration/tests/rendering/ref/mac/acs_style_changed.png new file mode 100644 index 0000000000..2c1b7402c4 Binary files /dev/null and b/api/tests/integration/tests/rendering/ref/mac/acs_style_changed.png differ diff --git a/api/tests/integration/tests/rendering/ref/mac/acs_style_default.png b/api/tests/integration/tests/rendering/ref/mac/acs_style_default.png new file mode 100644 index 0000000000..a702e25f33 Binary files /dev/null and b/api/tests/integration/tests/rendering/ref/mac/acs_style_default.png differ diff --git a/api/tests/integration/tests/rendering/ref/win/acs_style_changed.png b/api/tests/integration/tests/rendering/ref/win/acs_style_changed.png new file mode 100644 index 0000000000..2c1b7402c4 Binary files /dev/null and b/api/tests/integration/tests/rendering/ref/win/acs_style_changed.png differ diff --git a/api/tests/integration/tests/rendering/ref/win/acs_style_default.png b/api/tests/integration/tests/rendering/ref/win/acs_style_default.png new file mode 100644 index 0000000000..a702e25f33 Binary files /dev/null and b/api/tests/integration/tests/rendering/ref/win/acs_style_default.png differ diff --git a/core/indigo-core/common/math/algebra.h b/core/indigo-core/common/math/algebra.h index 0c7d2ca0a0..4ad0758735 100644 --- a/core/indigo-core/common/math/algebra.h +++ b/core/indigo-core/common/math/algebra.h @@ -159,6 +159,11 @@ namespace indigo return std::make_pair(x, y) < std::make_pair(a.x, a.y); } + inline float operator*(const Vec2f& a) const + { + return x * a.x + y * a.y; + } + inline Vec2f operator+(const Vec2f& a) const { return Vec2f(x + a.x, y + a.y); @@ -207,6 +212,24 @@ namespace indigo return *this; } + inline float vcos(const Vec2f& a) const + { + float scalar = *this * a; + float ta = length() * a.length(); + if (ta < EPSILON) + ta = EPSILON; + return scalar / ta; + } + + inline float vsin(const Vec2f& a) const + { + float scalar = *this * a; + float ta = lengthSqr() * a.lengthSqr(); + if (ta < EPSILON) + ta = EPSILON; + return sqrt(1 - scalar * scalar / ta); + } + DLLEXPORT bool normalize(); DLLEXPORT bool normalization(const Vec2f& v); diff --git a/core/indigo-core/layout/metalayout.h b/core/indigo-core/layout/metalayout.h index d0a4c45331..67d14cee0a 100644 --- a/core/indigo-core/layout/metalayout.h +++ b/core/indigo-core/layout/metalayout.h @@ -26,7 +26,7 @@ #include #ifdef _WIN32 -#pragma warning(push) +#pragma warning(push, 4) #pragma warning(disable : 4251) #endif @@ -120,9 +120,9 @@ namespace indigo // utility function to use in MoleculeLayout & ReactionLayout void adjustMol(BaseMolecule& mol, const Vec2f& min, const Vec2f& pos) const; - float reactionComponentMarginSize; + float reactionComponentMarginSize; // in angstrom float verticalIntervalFactor; - float bondLength; + float bondLength; // in angstrom DECL_ERROR; @@ -227,6 +227,30 @@ namespace indigo 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 @@ -234,19 +258,41 @@ namespace indigo // 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.6f; // 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 - float bondLength{DEFAULT_BOND_LENGTH}; + float bondLength{DEFAULT_BOND_LENGTH_PX}; UnitsOfMeasure::TYPE bondLengthUnit{UnitsOfMeasure::TYPE::PX}; - float reactionComponentMarginSize{DEFAULT_BOND_LENGTH / 2}; + float reactionComponentMarginSize{DEFAULT_BOND_LENGTH_PX / 2}; UnitsOfMeasure::TYPE reactionComponentMarginSizeUnit{UnitsOfMeasure::TYPE::PX}; int32_t ppi{72}; + void reset() + { + bondLength = DEFAULT_BOND_LENGTH_PX; + bondLengthUnit = UnitsOfMeasure::TYPE::PX; + reactionComponentMarginSize = DEFAULT_BOND_LENGTH_PX / 2; + reactionComponentMarginSizeUnit = UnitsOfMeasure::TYPE::PX; + ppi = 72; + }; + 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 (DEFAULT_BOND_LENGTH * marginSizePt) / bondLengthPt; - } + }; + void setMarginSizeInAngstroms(float value) + { + float angs_to_pt = UnitsOfMeasure::convertToPt(bondLength, bondLengthUnit, ppi) / DEFAULT_BOND_LENGTH; + reactionComponentMarginSize = UnitsOfMeasure::convertPtTo(value * angs_to_pt, reactionComponentMarginSizeUnit, ppi); + }; }; } // namespace indigo diff --git a/core/indigo-core/layout/reaction_layout.h b/core/indigo-core/layout/reaction_layout.h index 806b7a59f2..5a57fc18c1 100644 --- a/core/indigo-core/layout/reaction_layout.h +++ b/core/indigo-core/layout/reaction_layout.h @@ -76,7 +76,7 @@ namespace indigo ReactionLayout(const ReactionLayout& r); // no implicit copy - const float bond_length; + const float bond_length; // in angstrom const float atom_label_margin; const float default_plus_size; const float default_arrow_size; diff --git a/core/indigo-core/layout/src/metalayout.cpp b/core/indigo-core/layout/src/metalayout.cpp index 8e39588f63..cefdc8e43c 100644 --- a/core/indigo-core/layout/src/metalayout.cpp +++ b/core/indigo-core/layout/src/metalayout.cpp @@ -20,6 +20,10 @@ #include "base_cpp/tlscont.h" #include "molecule/molecule.h" +#ifdef _WIN32 +#pragma warning(push, 4) +#endif + using namespace indigo; Metalayout::LayoutLine::LayoutLine() @@ -86,7 +90,7 @@ Metalayout::LayoutLine& Metalayout::newLine() void Metalayout::process() { Vec2f pos; - static const auto atomLabelMarginVertical = bondLength / 2; + const auto atomLabelMarginVertical = bondLength / 2; for (int i = 0; i < _layout.size(); ++i) { LayoutLine& line = _layout[i]; @@ -328,3 +332,7 @@ void Metalayout::adjustMol(BaseMolecule& mol, const Vec2f& min, const Vec2f& pos } } } + +#ifdef _WIN32 +#pragma warning(pop) +#endif diff --git a/core/render2d/render.h b/core/render2d/render.h index 6157da9a24..5369674248 100644 --- a/core/render2d/render.h +++ b/core/render2d/render.h @@ -22,13 +22,17 @@ #include "render_internal.h" #include "render_item_factory.h" +#ifdef _WIN32 +#pragma warning(push, 4) +#endif + namespace indigo { class Render { public: - Render(RenderContext& rc, RenderItemFactory& factory, const CanvasOptions& cnvOpt, int bondLength, bool bondLengthSet); + Render(RenderContext& rc, RenderItemFactory& factory, const CanvasOptions& cnvOpt, int bondLength); virtual ~Render() = 0; DECL_ERROR; @@ -50,9 +54,12 @@ namespace indigo const RenderOptions& _opt; RenderItemFactory& _factory; int _bondLength; - bool _bondLengthSet; }; } // namespace indigo +#ifdef _WIN32 +#pragma warning(pop) +#endif + #endif //__render_h__ diff --git a/core/render2d/render_common.h b/core/render2d/render_common.h index 1263168186..37883f66c9 100644 --- a/core/render2d/render_common.h +++ b/core/render2d/render_common.h @@ -40,6 +40,8 @@ namespace indigo class QueryMolecule; class QueryReaction; class Output; + class RenderOptions; + struct AcsOptions; enum DINGO_MODE { @@ -404,7 +406,7 @@ namespace indigo { public: RenderSettings(); - void init(float sf, float lwf); + void init(float relativeThickness, float bondLineWidthFactor, AcsOptions* acs = nullptr); CP_DECL; TL_CP_DECL(Array, bondDashAromatic); @@ -440,6 +442,8 @@ namespace indigo float graphItemDigitHeight; float graphItemSignLineWidth; float graphItemPlusEdge; + float stereoBondSpace; + float hashSpacing; float fzz[FONT_SIZE_COUNT]; @@ -518,7 +522,7 @@ namespace indigo int maxHeight; int xOffset; int yOffset; - float bondLength; + float bondLength; // in pixels UnitsOfMeasure::TYPE bondLengthUnit; int gridMarginX; int gridMarginY; @@ -531,6 +535,8 @@ namespace indigo COMMENT_POS commentPos; MultilineTextLayout commentAlign; MultilineTextLayout titleAlign; + float outputSheetWidth; + float outputSheetHeight; int gridColumnNumber; @@ -542,7 +548,7 @@ namespace indigo { public: RenderOptions(); - void clear(); + void clearRenderOptions(); Vec3f backgroundColor; Vec3f baseColor; @@ -579,14 +585,37 @@ namespace indigo bool agentsBelowArrow; Array atomColorProp; std::unique_ptr cdxml_context; - float reactionComponentMarginSize; - UnitsOfMeasure::TYPE reactionComponentMarginSizeUnit; + // ACS settings + float bond_length_px; int32_t ppi; + float fontSize; + UnitsOfMeasure::TYPE fontSizeUnit; + float fontSizeSub; + UnitsOfMeasure::TYPE fontSizeSubUnit; + float bondThickness; + UnitsOfMeasure::TYPE bondThicknessUnit; + float bondSpacing; + float stereoBondWidth; + UnitsOfMeasure::TYPE stereoBondWidthUnit; + float hashSpacing; + UnitsOfMeasure::TYPE hashSpacingUnit; private: RenderOptions(const RenderOptions&); }; + struct AcsOptions + { + AcsOptions(); + void clear(); + float bondSpacing; + float fontSizeAngstrom; + float fontSizeSubAngstrom; + float bondThicknessAngstrom; + float stereoBondWidthAngstrom; + float hashSpacingAngstrom; + }; + } // namespace indigo #define QUERY_MOL_BEGIN(mol) \ diff --git a/core/render2d/render_context.h b/core/render2d/render_context.h index 4e5d418abd..1e72edeabd 100644 --- a/core/render2d/render_context.h +++ b/core/render2d/render_context.h @@ -46,7 +46,7 @@ namespace indigo void checkPathNonEmpty() const; - RenderContext(const RenderOptions& opt, float sf, float lwf); + RenderContext(const RenderOptions& opt, float relativeThickness, float bondLineWidthFactor); void setDefaultScale(float scale); void setHDC(PVOID hdc); int getMaxPageSize() const; @@ -82,6 +82,7 @@ namespace indigo void fillHex(const Vec2f& v0, const Vec2f& v1, const Vec2f& v2, const Vec2f& v3, const Vec2f& v4, const Vec2f& v5); void fillQuad(const Vec2f& v0, const Vec2f& v1, const Vec2f& v2, const Vec2f& v3); void fillQuadStripes(const Vec2f& v0r, const Vec2f& v0l, const Vec2f& v1r, const Vec2f& v1l, int cnt); + void fillQuadStripesSpacing(const Vec2f& v0r, const Vec2f& v0l, const Vec2f& v1r, const Vec2f& v1l, float spacing); void fillPentagon(const Vec2f& v0, const Vec2f& v1, const Vec2f& v2, const Vec2f& v3, const Vec2f& v4); void drawQuad(const Vec2f& v0, const Vec2f& v1, const Vec2f& v2, const Vec2f& v3); void drawTriangleZigzag(const Vec2f& v0, const Vec2f& v1, const Vec2f& v2, int cnt); diff --git a/core/render2d/render_grid.h b/core/render2d/render_grid.h index d3ba7eb99f..3677ddf031 100644 --- a/core/render2d/render_grid.h +++ b/core/render2d/render_grid.h @@ -27,7 +27,7 @@ namespace indigo class RenderGrid : Render { public: - RenderGrid(RenderContext& rc, RenderItemFactory& factory, const CanvasOptions& cnvOpt, int bondLength, bool bondLengthSet); + RenderGrid(RenderContext& rc, RenderItemFactory& factory, const CanvasOptions& cnvOpt, int bondLength); ~RenderGrid() override; void draw(); diff --git a/core/render2d/render_single.h b/core/render2d/render_single.h index 841e8d5b2c..6925e847a6 100644 --- a/core/render2d/render_single.h +++ b/core/render2d/render_single.h @@ -27,7 +27,7 @@ namespace indigo class RenderSingle : Render { public: - RenderSingle(RenderContext& rc, RenderItemFactory& factory, const CanvasOptions& cnvOpt, int bondLength, bool bondLengthSet); + RenderSingle(RenderContext& rc, RenderItemFactory& factory, const CanvasOptions& cnvOpt, int bondLength); ~RenderSingle() override; void draw(); diff --git a/core/render2d/src/render.cpp b/core/render2d/src/render.cpp index 7222764f85..9d291a6927 100644 --- a/core/render2d/src/render.cpp +++ b/core/render2d/src/render.cpp @@ -33,9 +33,8 @@ using namespace indigo; IMPL_ERROR(Render, "Render"); -Render::Render(RenderContext& rc, RenderItemFactory& factory, const CanvasOptions& cnvOpt, int bondLength, bool bondLengthSet) - : minMarg(2), _rc(rc), _settings(rc.getRenderSettings()), _cnvOpt(cnvOpt), _opt(rc.opt), _factory(factory), _bondLength(bondLength), - _bondLengthSet(bondLengthSet) +Render::Render(RenderContext& rc, RenderItemFactory& factory, const CanvasOptions& cnvOpt, int bondLength) + : minMarg(2), _rc(rc), _settings(rc.getRenderSettings()), _cnvOpt(cnvOpt), _opt(rc.opt), _factory(factory), _bondLength(bondLength) { } @@ -86,7 +85,7 @@ float Render::_getScale(int w, int h) float Render::_getMaxScale(int w, int h) { - float s = (float)(_bondLength > 0 ? _bondLength : 100); + float s = (float)_bondLength > 0 ? _bondLength : LayoutOptions::DEFAULT_BOND_LENGTH_PX; int maxWidth = _getMaxWidth(); int maxHeight = _getMaxHeight(); int defaultWidth = _getDefaultWidth(s); diff --git a/core/render2d/src/render_cdxml.cpp b/core/render2d/src/render_cdxml.cpp index dd4b9e4378..361a32f1d6 100644 --- a/core/render2d/src/render_cdxml.cpp +++ b/core/render2d/src/render_cdxml.cpp @@ -64,7 +64,8 @@ void _getBounds(RenderParams& params, BaseMolecule& mol, Vec2f& min, Vec2f& max, float bond_length = 1; if (params.cnvOpt.bondLength > 0) - bond_length = params.cnvOpt.bondLength / 100.0f; + bond_length = + UnitsOfMeasure::convertToPx(params.cnvOpt.bondLength, params.cnvOpt.bondLengthUnit, params.rOpt.ppi) / LayoutOptions::DEFAULT_BOND_LENGTH_PX; scale = bond_length / avg_bond_length; diff --git a/core/render2d/src/render_common.cpp b/core/render2d/src/render_common.cpp index ca9d8da45d..219bb646c7 100644 --- a/core/render2d/src/render_common.cpp +++ b/core/render2d/src/render_common.cpp @@ -19,12 +19,17 @@ #include "render_common.h" #include "base_cpp/array.h" #include "base_cpp/obj_array.h" +#include "layout/molecule_layout.h" #include "math/algebra.h" #include "molecule/molecule.h" #include "molecule/query_molecule.h" #include "reaction/query_reaction.h" #include "reaction/reaction.h" +#ifdef _WIN32 +#pragma warning(push, 4) +#endif + using namespace indigo; namespace indigo @@ -282,22 +287,43 @@ RenderSettings::RenderSettings() init(1.0f, 1.0f); } -void RenderSettings::init(float sf, float lwf) +void RenderSettings::init(float relativeThickness, float bondLineWidthFactor, AcsOptions* acs) { - unit = sf / 30; - bondLineWidth = lwf * unit; + unit = relativeThickness / 30; // 1/30 + bondLineWidth = bondLineWidthFactor * unit; bondSpace = 2.5f * unit; + stereoBondSpace = bondSpace; - fzz[FONT_SIZE_LABEL] = unit * 12; - fzz[FONT_SIZE_ATTR] = unit * 8; - fzz[FONT_SIZE_RGROUP_LOGIC] = unit * 12; - fzz[FONT_SIZE_RGROUP_LOGIC_INDEX] = unit * 8; - fzz[FONT_SIZE_INDICES] = unit * 6; - fzz[FONT_SIZE_ATTACHMENT_POINT_INDEX] = unit * 6; - fzz[FONT_SIZE_RSITE_ATTACHMENT_INDEX] = unit * 6; - fzz[FONT_SIZE_COMMENT] = 0; // not used, value taken from RenderOptions.commentFontFactor - fzz[FONT_SIZE_TITLE] = 0; // not used, value taken from RenderOptions.titleFontFactor - fzz[FONT_SIZE_DATA_SGROUP] = unit * 8; + float label_font_size = unit * 12; + if (acs != nullptr) + { + if (acs->bondThicknessAngstrom > 0) + bondLineWidth = acs->bondThicknessAngstrom * bondLineWidthFactor * relativeThickness; + if (acs->fontSizeAngstrom > 0) + label_font_size = acs->fontSizeAngstrom; + if (acs->bondSpacing > 0) + { + bondSpace = acs->bondSpacing / 2.0f; + stereoBondSpace = bondSpace; + } + if (acs->stereoBondWidthAngstrom > 0) + stereoBondSpace = acs->stereoBondWidthAngstrom / 2.0f; + if (acs->hashSpacingAngstrom > 0) + hashSpacing = acs->hashSpacingAngstrom; + } + fzz[FONT_SIZE_LABEL] = label_font_size; + if (acs != nullptr && acs->fontSizeSubAngstrom > 0) + fzz[FONT_SIZE_ATTR] = acs->fontSizeAngstrom; + else + fzz[FONT_SIZE_ATTR] = label_font_size * 2 / 3.0f; // unit * 8; // Subscript + fzz[FONT_SIZE_RGROUP_LOGIC] = label_font_size; + fzz[FONT_SIZE_RGROUP_LOGIC_INDEX] = label_font_size * 2 / 3.0f; // unit * 8; + fzz[FONT_SIZE_INDICES] = label_font_size / 2.0f; // unit * 6; + fzz[FONT_SIZE_ATTACHMENT_POINT_INDEX] = label_font_size / 2.0f; // unit * 6; + fzz[FONT_SIZE_RSITE_ATTACHMENT_INDEX] = label_font_size / 2.0f; // unit * 6; + fzz[FONT_SIZE_COMMENT] = 0; // not used, value taken from RenderOptions.commentFontFactor + fzz[FONT_SIZE_TITLE] = 0; // not used, value taken from RenderOptions.titleFontFactor + fzz[FONT_SIZE_DATA_SGROUP] = label_font_size * 2 / 3.0f; // unit * 8; upperIndexShift = -0.4f; lowerIndexShift = 0.4f; @@ -384,6 +410,8 @@ void CanvasOptions::clear() comment.clear(); titleProp.clear(); titleProp.appendString("^NAME", true); + outputSheetWidth = -1; + outputSheetHeight = -1; } // @@ -431,3 +459,7 @@ float MultilineTextLayout::getAnchorPoint(float area_x, float area_width, float float bbox_x = area_x + (area_width - text_width) * getBboxRelativeOffset(); return bbox_x + text_width * getInboxRelativeOffset(); } + +#ifdef _WIN32 +#pragma warning(pop) +#endif diff --git a/core/render2d/src/render_context.cpp b/core/render2d/src/render_context.cpp index 354d835ff7..928512835c 100644 --- a/core/render2d/src/render_context.cpp +++ b/core/render2d/src/render_context.cpp @@ -119,11 +119,26 @@ void RenderContext::storeAndDestroyMetafile(bool discard) CP_DEF(RenderContext); -RenderContext::RenderContext(const RenderOptions& ropt, float sf, float lwf) +RenderContext::RenderContext(const RenderOptions& ropt, float relativeThickness, float bondLineWidthFactor) : CP_INIT, TL_CP_GET(_fontfamily), TL_CP_GET(transforms), metafileFontsToCurves(false), _cr(NULL), _surface(NULL), _meta_hdc(NULL), opt(ropt), - _pattern(NULL) -{ - _settings.init(sf, lwf); + _pattern(NULL), _settings() +{ + AcsOptions acs; + if (ropt.fontSize > 0) + acs.fontSizeAngstrom = UnitsOfMeasure::convertToPx(ropt.fontSize, ropt.fontSizeUnit, ropt.ppi) / ropt.bond_length_px; + if (ropt.fontSizeSub > 0) + acs.fontSizeSubAngstrom = UnitsOfMeasure::convertToPx(ropt.fontSizeSub, ropt.fontSizeSubUnit, ropt.ppi) / ropt.bond_length_px; + if (ropt.bondThickness > 0) + acs.bondThicknessAngstrom = UnitsOfMeasure::convertToPx(ropt.bondThickness, ropt.bondThicknessUnit, ropt.ppi) / LayoutOptions::DEFAULT_BOND_LENGTH_PX; + if (ropt.stereoBondWidth > 0) + acs.stereoBondWidthAngstrom = + UnitsOfMeasure::convertToPx(ropt.stereoBondWidth, ropt.stereoBondWidthUnit, ropt.ppi) / LayoutOptions::DEFAULT_BOND_LENGTH_PX; + if (ropt.hashSpacing > 0) + acs.hashSpacingAngstrom = UnitsOfMeasure::convertToPx(ropt.hashSpacing, ropt.hashSpacingUnit, ropt.ppi) / LayoutOptions::DEFAULT_BOND_LENGTH_PX; + if (ropt.bondSpacing > 0) + acs.bondSpacing = ropt.bondSpacing; + _settings.init(relativeThickness, bondLineWidthFactor, &acs); + bprintf(_fontfamily, "Arial"); bbmin.x = bbmin.y = 1; bbmax.x = bbmax.y = -1; @@ -642,6 +657,37 @@ void RenderContext::fillQuadStripes(const Vec2f& v0r, const Vec2f& v0l, const Ve cairoCheckStatus(); } +void RenderContext::fillQuadStripesSpacing(const Vec2f& v0r, const Vec2f& v0l, const Vec2f& v1r, const Vec2f& v1l, float spacing) +{ + Vec2f r(v0r), dr; + Vec2f l(v0l), dl; + Vec2f v; + dr.diff(v1r, v0r); + dl.diff(v1l, v0l); + v.diff(v1l, v1r); + float dr_len = dr.lengthSqr(); + float dl_len = dl.lengthSqr(); + + dr.normalize(); + dr.scale(abs(dr.vsin(v)) * spacing); + dl.normalize(); + dl.scale(abs(dl.vsin(v)) * spacing); + + while (true) + { + r.add(dr); + l.add(dl); + if (Vec2f::distSqr(v0r, r) > dr_len || Vec2f::distSqr(v0l, l) > dl_len) + break; + moveTo(r); + lineTo(l); + } + checkPathNonEmpty(); + bbIncludePath(true); + cairo_stroke(_cr); + cairoCheckStatus(); +} + void RenderContext::fillPentagon(const Vec2f& v0, const Vec2f& v1, const Vec2f& v2, const Vec2f& v3, const Vec2f& v4) { moveTo(v0); diff --git a/core/render2d/src/render_grid.cpp b/core/render2d/src/render_grid.cpp index 98c0a08503..129e8bb58b 100644 --- a/core/render2d/src/render_grid.cpp +++ b/core/render2d/src/render_grid.cpp @@ -31,8 +31,8 @@ using namespace indigo; IMPL_ERROR(RenderGrid, "RenderGrid"); -RenderGrid::RenderGrid(RenderContext& rc, RenderItemFactory& factory, const CanvasOptions& cnvOpt, int bondLength, bool bondLengthSet) - : Render(rc, factory, cnvOpt, bondLength, bondLengthSet), nColumns(cnvOpt.gridColumnNumber), comment(-1) +RenderGrid::RenderGrid(RenderContext& rc, RenderItemFactory& factory, const CanvasOptions& cnvOpt, int bondLength) + : Render(rc, factory, cnvOpt, bondLength), nColumns(cnvOpt.gridColumnNumber), comment(-1) { } diff --git a/core/render2d/src/render_internal.cpp b/core/render2d/src/render_internal.cpp index 424732885a..b8ff9af023 100644 --- a/core/render2d/src/render_internal.cpp +++ b/core/render2d/src/render_internal.cpp @@ -29,6 +29,10 @@ #include "reaction/reaction.h" #include "render_context.h" +#ifdef _WIN32 +#pragma warning(push, 4) +#endif + using namespace indigo; #define BOND_STEREO_BOLD 10001 @@ -148,10 +152,10 @@ static bool _isBondWide(const BondDescr& bd) RenderOptions::RenderOptions() { - clear(); + clearRenderOptions(); } -void RenderOptions::clear() +void RenderOptions::clearRenderOptions() { baseColor.set(0, 0, 0); backgroundColor.set(-1, -1, -1); @@ -187,6 +191,33 @@ void RenderOptions::clear() showCycles = false; agentsBelowArrow = true; atomColorProp.clear(); + ppi = 72; + fontSize = -1; + fontSizeUnit = UnitsOfMeasure::PT; + fontSizeSub = -1; + fontSizeSubUnit = UnitsOfMeasure::PT; + bondThickness = -1; + bondThicknessUnit = UnitsOfMeasure::PT; + bondSpacing = -1; + stereoBondWidth = -1; + stereoBondWidthUnit = UnitsOfMeasure::PT; + hashSpacing = -1; + hashSpacingUnit = UnitsOfMeasure::PT; +} + +AcsOptions::AcsOptions() +{ + clear(); +} + +void AcsOptions::clear() +{ + bondSpacing = -1; + fontSizeAngstrom = -1; + fontSizeSubAngstrom = -1; + bondThicknessAngstrom = -1; + stereoBondWidthAngstrom = -1; + hashSpacingAngstrom = -1; } IMPL_ERROR(MoleculeRenderInternal, "molecule render internal"); @@ -3859,7 +3890,7 @@ void MoleculeRenderInternal::_adjustAngle(Vec2f& l, const BondEnd& be1, const Bo const Vec2f& p1 = _ad(be1.aid).pos; const Vec2f& p2 = _ad(be2.aid).pos; const double len = Vec2f::dist(p1, p2); - double w = _settings.bondSpace; + double w = _settings.stereoBondSpace; double tgb = w / len; double csb = sqrt(1 / (1 + tgb * tgb)); double snb = tgb * csb; @@ -3878,7 +3909,7 @@ void MoleculeRenderInternal::_adjustAngle(Vec2f& l, const BondEnd& be1, const Bo void MoleculeRenderInternal::_bondBoldStereo(BondDescr& bd, const BondEnd& be1, const BondEnd& be2) { Vec2f r0(be1.p), l0(be1.p), r1(be2.p), l1(be2.p); - float w = _settings.bondSpace; + float w = _settings.stereoBondSpace; l0.addScaled(bd.norm, -w); r0.addScaled(bd.norm, w); l1.addScaled(bd.norm, -w); @@ -3944,23 +3975,27 @@ void MoleculeRenderInternal::_bondSingle(BondDescr& bd, const BondEnd& be1, cons _bondBoldStereo(bd, be1, be2); return; } + + float lw = _cw.currentLineWidth(); + if (bd.stereodir == 0) + { + _cw.drawLine(be1.p, be2.p); + bd.extP = bd.extN = lw / 2; + return; + } + + // stereo bonds Vec2f l(be2.p), r(be2.p); - float w = _settings.bondSpace; + float w = _settings.stereoBondSpace; l.addScaled(bd.norm, -w); r.addScaled(bd.norm, w); bd.extP = bd.extN = w; - float lw = _cw.currentLineWidth(); Vec2f r0(be1.p), l0(be1.p); l0.addScaled(bd.norm, -lw / 2); r0.addScaled(bd.norm, lw / 2); - if (bd.stereodir == 0) - { - _cw.drawLine(be1.p, be2.p); - bd.extP = bd.extN = lw / 2; - } - else if (bd.stereodir == BOND_UP) + if (bd.stereodir == BOND_UP) { if (_ad(be2.aid).showLabel == false && !bd.isShort) { @@ -3975,8 +4010,16 @@ void MoleculeRenderInternal::_bondSingle(BondDescr& bd, const BondEnd& be1, cons } else if (bd.stereodir == BOND_DOWN) { - int stripeCnt = std::max((int)((len) / lw / 2), 4); - _cw.fillQuadStripes(r0, l0, r, l, stripeCnt); + int constexpr min_count = 4; + if (_settings.hashSpacing > 0 && (int)(len / _settings.hashSpacing) > min_count) + { + _cw.fillQuadStripesSpacing(r0, l0, r, l, _settings.hashSpacing); + } + else + { + int stripeCnt = std::max((int)((len) / lw / 2), min_count); + _cw.fillQuadStripes(r0, l0, r, l, stripeCnt); + } } else if (bd.stereodir == BOND_EITHER) { @@ -4334,3 +4377,7 @@ void MoleculeRenderInternal::_precalcScale() } _scale = std::max(_scale, float(max_output_length) / ((float)10.0 * scale_modificator)); } + +#ifdef _WIN32 +#pragma warning(pop) +#endif diff --git a/core/render2d/src/render_params.cpp b/core/render2d/src/render_params.cpp index 3d757aa436..7c31156d07 100644 --- a/core/render2d/src/render_params.cpp +++ b/core/render2d/src/render_params.cpp @@ -69,7 +69,7 @@ void RenderParams::clear() relativeThickness = 1.0f; bondLineWidthFactor = 1.0f; rmode = RENDER_NONE; - rOpt.clear(); + rOpt.clearRenderOptions(); cnvOpt.clear(); clearArrays(); } @@ -189,9 +189,9 @@ void RenderParamInterface::render(RenderParams& params) RenderContext rc(params.rOpt, params.relativeThickness, params.bondLineWidthFactor); - bool bondLengthSet = params.cnvOpt.bondLength > 0; - int bondLength = (int)(bondLengthSet ? params.cnvOpt.bondLength : 100); - rc.setDefaultScale((float)bondLength); // TODO: fix bondLength type + int bondLength_px = (int)(params.rOpt.bond_length_px > EPSILON ? params.rOpt.bond_length_px : LayoutOptions::DEFAULT_BOND_LENGTH_PX); + + rc.setDefaultScale((float)bondLength_px); // TODO: fix bondLength type RenderItemFactory factory(rc); int obj = -1; @@ -274,14 +274,14 @@ void RenderParamInterface::render(RenderParams& params) if (obj >= 0) { - RenderSingle render(rc, factory, params.cnvOpt, bondLength, bondLengthSet); + RenderSingle render(rc, factory, params.cnvOpt, bondLength_px); render.obj = obj; render.comment = comment; render.draw(); } else { - RenderGrid render(rc, factory, params.cnvOpt, bondLength, bondLengthSet); + RenderGrid render(rc, factory, params.cnvOpt, bondLength_px); render.objs.copy(objs); render.comment = comment; render.titles.copy(titles); diff --git a/core/render2d/src/render_single.cpp b/core/render2d/src/render_single.cpp index 6181b655cb..4881842ea4 100644 --- a/core/render2d/src/render_single.cpp +++ b/core/render2d/src/render_single.cpp @@ -35,8 +35,8 @@ using namespace indigo; IMPL_ERROR(RenderSingle, "RenderSingle"); -RenderSingle::RenderSingle(RenderContext& rc, RenderItemFactory& factory, const CanvasOptions& cnvOpt, int bondLength, bool bondLengthSet) - : comment(-1), Render(rc, factory, cnvOpt, bondLength, bondLengthSet) +RenderSingle::RenderSingle(RenderContext& rc, RenderItemFactory& factory, const CanvasOptions& cnvOpt, int bondLength) + : comment(-1), Render(rc, factory, cnvOpt, bondLength) { }