Skip to content
Snippets Groups Projects
Commit 6aa82dfe authored by m.puchner's avatar m.puchner
Browse files

Merge branch 'UnitHandling' into 'develop'

Unit handling in layer oriented sample editor

See merge request !415
parents ae7af93b 9cdcb043
No related branches found
No related tags found
1 merge request!415Unit handling in layer oriented sample editor
Pipeline #47619 passed
Showing
with 373 additions and 78 deletions
......@@ -25,6 +25,7 @@ const QString S_POS = "Pos";
const QString S_DEFAULT_FUNCTIONALITIES = "DefaultFunctionalities";
const QString S_SINGLE_INSTRUMENT_MODE = "SingleInstrumentMode";
const QString S_SINGLE_SAMPLE_MODE = "SingleSampleMode";
const QString S_DEFAULT_UNIT_IS_ANGSTROM = "DefaultUnitIsAngstrom";
} // namespace
bool ApplicationSettings::useNativeFileDialog() const
......@@ -86,6 +87,16 @@ void ApplicationSettings::setDefaultIsSingleSampleMode(bool b)
QSettings().setValue(S_SINGLE_SAMPLE_MODE, b);
}
bool ApplicationSettings::defaultUnitIsAngstrom() const
{
return QSettings().value(S_DEFAULT_UNIT_IS_ANGSTROM, false).toBool();
}
void ApplicationSettings::setDefaultUnitIsAngstrom(bool b) const
{
QSettings().setValue(S_DEFAULT_UNIT_IS_ANGSTROM, b);
}
void ApplicationSettings::saveWindowSizeAndPos(const QWidget* w)
{
ASSERT(!w->objectName().isEmpty());
......
......@@ -41,6 +41,9 @@ public:
bool defaultIsSingleSampleMode() const;
void setDefaultIsSingleSampleMode(bool b);
bool defaultUnitIsAngstrom() const;
void setDefaultUnitIsAngstrom(bool b) const;
void saveWindowSizeAndPos(const QWidget* w);
void loadWindowSizeAndPos(QWidget* w);
};
......
......@@ -103,14 +103,14 @@ SelectionDescriptor<RotationItem*> ItemWithParticles::rotationMethod()
d.currentItem = [=]() -> RotationItem* { return rotationItem(); };
d.setCurrentIndex = [=](int current) {
d.currentIndexSetter = [=](int current) {
if (auto item = getItem(T_TRANSFORMATION))
model()->removeItem(item);
if (current > 0)
createTransformationItem()->setRotationType(map[current].second);
};
d.currentIndex = [=]() {
d.currentIndexGetter = [=]() {
auto item = rotationItem();
if (item == nullptr)
return 0;
......
......@@ -129,7 +129,7 @@ SelectionDescriptor<InterferenceItem*> ParticleLayoutItem::interference() const
d.currentItem = [=] { return dynamic_cast<InterferenceItem*>(getItem(T_INTERFERENCE)); };
d.setCurrentIndex = [=](int current) {
d.currentIndexSetter = [=](int current) {
if (auto item = getItem(T_INTERFERENCE))
model()->removeItem(item);
if (current > 0)
......@@ -137,7 +137,7 @@ SelectionDescriptor<InterferenceItem*> ParticleLayoutItem::interference() const
T_INTERFERENCE);
};
d.currentIndex = [=]() {
d.currentIndexGetter = [=]() {
if (auto item = dynamic_cast<InterferenceItem*>(getItem(T_INTERFERENCE)))
for (int i = 1; i < map.size(); i++)
if (map[i].second == item->modelType())
......
......@@ -23,6 +23,18 @@
using std::function;
//! Abstract base class for SelectionDescriptor to ease referencing.
class AbstractSelectionDescriptor {
public:
virtual ~AbstractSelectionDescriptor() = default;
//! Set currently selected option
virtual void setCurrentIndex(int newIndex) const = 0;
//! Get currently selected option
virtual int currentIndex() const = 0;
};
//! Describes a selection (various possibilities and the current one).
//!
//! Usually a selection is presented as a combo box.
......@@ -38,7 +50,7 @@ using std::function;
//! By using this class, the underlying data scheme is hidden from the user of the data. This e.g.
//! eases SessionItem migration. The underlying implementation can be a GroupItem, a simple pointer
//! member, a std::variant or any other construction to define a selection.
template <typename T> class SelectionDescriptor {
template <typename T> class SelectionDescriptor : public AbstractSelectionDescriptor {
public:
SelectionDescriptor() = default;
......@@ -51,7 +63,7 @@ public:
{
label = item->displayName();
options = item->value().value<ComboProperty>().getValues();
setCurrentIndex = [=](int index) {
currentIndexSetter = [=](int index) {
ComboProperty comboProperty = item->value().value<ComboProperty>();
if (comboProperty.currentIndex() != index) {
......@@ -59,18 +71,22 @@ public:
item->setValue(QVariant::fromValue<ComboProperty>(comboProperty));
}
};
currentIndex = [=] { return item->value().value<ComboProperty>().currentIndex(); };
currentIndexGetter = [=] { return item->value().value<ComboProperty>().currentIndex(); };
if constexpr (std::is_pointer<T>::value)
currentItem = [=] { return dynamic_cast<T>(item->currentItem()); };
}
QString label; //!< A label text (short, no trailing colon)
QString tooltip; //!< Tooltip text
QStringList options; //!< List of options, usually presented as combo entries
function<void(int)> setCurrentIndex; //!< Function to set currently selected option
function<int()> currentIndex; //!< Function to get currently selected option
function<T()> currentItem; //!< Function to get currently selected item
virtual void setCurrentIndex(int newIndex) const override { currentIndexSetter(newIndex); }
virtual int currentIndex() const override { return currentIndexGetter(); }
QString label; //!< A label text (short, no trailing colon)
QString tooltip; //!< Tooltip text
QStringList options; //!< List of options, usually presented as combo entries
function<void(int)> currentIndexSetter; //!< Function to set currently selected option
function<int()> currentIndexGetter; //!< Function to get currently selected option
function<T()> currentItem; //!< Function to get currently selected item
};
#endif // BORNAGAIN_GUI_MODELS_SELECTIONDESCRIPTOR_H
......@@ -63,15 +63,15 @@ QString unitAsString(const Unit& unit)
case Unit::nanometer:
return "nm";
case Unit::nanometerPower2:
return "nm²";
return u8"nm\u00B2";
case Unit::nanometerPowerMinus2:
return "1/nm²";
return u8"1/nm\u00B2";
case Unit::angstrom:
return "\303\205";
return u8"\u00c5";
case Unit::angstromPower2:
return "\303\205²";
return u8"\u00c5\u00B2";
case Unit::angstromPowerMinus2:
return "1/\303\205²";
return u8"1/\u00c5\u00B2";
case Unit::degree:
return "°";
case Unit::radiant:
......
......@@ -20,6 +20,7 @@
#include "GUI/Views/SampleDesigner/MultiLayerForm.h"
#include "GUI/Views/SampleDesigner/SampleEditorController.h"
#include "GUI/Application/Application.h"
#include <QBoxLayout>
#include <QScrollArea>
......@@ -29,7 +30,7 @@ LayerOrientedSampleEditor::LayerOrientedSampleEditor(QWidget* parent)
, m_undoAction(nullptr)
, m_redoAction(nullptr)
, m_showInlineEditButtonsAction(nullptr)
, m_asAngstrom(nullptr)
, m_asAngstromAction(nullptr)
, m_currentMultiLayerItem(nullptr)
{
setAttribute(Qt::WA_StyledBackground, true);
......@@ -55,11 +56,29 @@ LayerOrientedSampleEditor::LayerOrientedSampleEditor(QWidget* parent)
m_showInlineEditButtonsAction->setChecked(false);
m_toolbar->addAction(m_showInlineEditButtonsAction);
m_asAngstrom = new QAction("A", this);
connect(m_asAngstrom, &QAction::toggled, this, &LayerOrientedSampleEditor::onAsAngstromToggled);
m_asAngstrom->setCheckable(true);
m_asAngstrom->setChecked(false);
m_toolbar->addAction(m_asAngstrom);
m_asAngstromAction = new QAction(this);
m_asAngstromAction->setIcon(QIcon(":/images/unit_angstrom.svg"));
m_asAngstromAction->setToolTip(u8"Use \u00c5ngstrom as unit (where applicable)");
connect(m_asAngstromAction, &QAction::toggled, this,
&LayerOrientedSampleEditor::onUnitActionToggled);
m_asAngstromAction->setCheckable(true);
auto* asNanometerAction = new QAction(this);
asNanometerAction->setIcon(QIcon(":/images/unit_nm.svg"));
asNanometerAction->setToolTip("Use nanometer as unit (where applicable)");
connect(asNanometerAction, &QAction::toggled, this,
&LayerOrientedSampleEditor::onUnitActionToggled);
asNanometerAction->setCheckable(true);
auto* ag = new QActionGroup(this);
ag->addAction(asNanometerAction);
ag->addAction(m_asAngstromAction);
if (baApp->settings().defaultUnitIsAngstrom())
m_asAngstromAction->setChecked(true);
else
asNanometerAction->setChecked(true);
m_toolbar->addActions(ag->actions());
}
LayerOrientedSampleEditor::~LayerOrientedSampleEditor()
......@@ -108,6 +127,7 @@ void LayerOrientedSampleEditor::setCurrentSample(MultiLayerItem* multiLayerItem)
m_currentMultiLayerWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
m_scrollArea->setWidget(m_currentMultiLayerWidget);
m_currentMultiLayerWidget->showInlineEditButtons(m_showInlineEditButtonsAction->isChecked());
m_currentMultiLayerWidget->setUseAngstrom(m_asAngstromAction->isChecked());
updateActionEnabling();
}
......@@ -123,10 +143,10 @@ void LayerOrientedSampleEditor::onShowInlineEditButtonsToggled(bool checked)
m_currentMultiLayerWidget->showInlineEditButtons(checked);
}
void LayerOrientedSampleEditor::onAsAngstromToggled()
void LayerOrientedSampleEditor::onUnitActionToggled()
{
if (m_currentMultiLayerWidget)
m_currentMultiLayerWidget->useAngstrom(m_asAngstrom->isChecked());
m_currentMultiLayerWidget->setUseAngstrom(m_asAngstromAction->isChecked());
}
void LayerOrientedSampleEditor::createLayerColors() // #baLayerEditor move to better place
......
......@@ -36,7 +36,7 @@ public:
private:
void updateActionEnabling();
void onShowInlineEditButtonsToggled(bool checked);
void onAsAngstromToggled();
void onUnitActionToggled();
void createLayerColors();
QWidget* createEmptyWidget();
......@@ -48,7 +48,7 @@ private:
QAction* m_undoAction; // dedicated to the current sample
QAction* m_redoAction;
QAction* m_showInlineEditButtonsAction;
QAction* m_asAngstrom; // #baLayerEditor better two autoexclusive actions?
QAction* m_asAngstromAction;
MultiLayerItem* m_currentMultiLayerItem = nullptr;
QMap<MultiLayerItem*, SampleEditorController*> m_editControllers;
};
......
......@@ -94,7 +94,6 @@ void MesoCrystalForm::onBasisComboChanged()
const QString newClassName = m_basisCombo->currentData().toString();
m_ec->setMesoCrystalBasis(this, newClassName);
createBasisWidgets();
}
void MesoCrystalForm::createBasisWidgets()
......
......@@ -32,12 +32,12 @@ public:
void enableStructureEditing(bool b);
MesoCrystalItem* mesoCrystalItem() const;
void createBasisWidgets();
private:
QComboBox* createBasisCombo(QWidget* parent, ItemWithParticles* current);
void onBasisComboChanged();
void createBasisWidgets();
QFormLayout* m_layout;
MesoCrystalItem* m_item;
......
......@@ -55,7 +55,11 @@ public:
MultiLayerForm::MultiLayerForm(QWidget* parent, MultiLayerItem* multiLayerItem,
SampleEditorController* ec)
: QWidget(parent), m_multiLayerItem(multiLayerItem), m_ec(ec)
: QWidget(parent)
, m_multiLayerItem(multiLayerItem)
, m_ec(ec)
, m_useAngstrom(false)
, m_useRadiant(false)
{
setObjectName("MultiLayerForm"); // important for style sheet addressing
setAttribute(Qt::WA_StyledBackground, true);
......@@ -187,12 +191,8 @@ void MultiLayerForm::updateRowVisibilities()
c->updateLayerPositionDependentElements();
}
void MultiLayerForm::ensureVisible(QWidget* /*w*/)
{
// #baLayerEditor implement ensureVisible
}
void MultiLayerForm::useAngstrom(bool angstrom)
void MultiLayerForm::updateUnits()
{
const auto set = [](DoubleSpinBox* spinbox, Unit valueUnit, Unit displayUnit) {
if (spinbox->baseUnit() == valueUnit)
......@@ -200,7 +200,7 @@ void MultiLayerForm::useAngstrom(bool angstrom)
};
for (auto* editor : findChildren<DoubleSpinBox*>()) {
if (angstrom) {
if (m_useAngstrom) {
set(editor, Unit::nanometer, Unit::angstrom);
set(editor, Unit::angstrom, Unit::angstrom);
set(editor, Unit::nanometerPower2, Unit::angstromPower2);
......@@ -215,20 +215,8 @@ void MultiLayerForm::useAngstrom(bool angstrom)
set(editor, Unit::nanometerPowerMinus2, Unit::nanometerPowerMinus2);
set(editor, Unit::angstromPowerMinus2, Unit::nanometerPowerMinus2);
}
}
for (auto* label : findChildren<QLabel*>())
LayerEditorUtils::updateLabelUnit(label);
}
void MultiLayerForm::useRadiant(bool radiant)
{
const auto set = [](DoubleSpinBox* spinbox, Unit valueUnit, Unit displayUnit) {
if (spinbox->baseUnit() == valueUnit)
spinbox->setDisplayUnit(displayUnit);
};
for (auto* editor : findChildren<DoubleSpinBox*>()) {
if (radiant) {
if (m_useRadiant) {
set(editor, Unit::degree, Unit::radiant);
set(editor, Unit::radiant, Unit::radiant);
} else {
......@@ -236,6 +224,35 @@ void MultiLayerForm::useRadiant(bool radiant)
set(editor, Unit::radiant, Unit::degree);
}
}
for (auto* label : findChildren<QLabel*>())
LayerEditorUtils::updateLabelUnit(label);
}
void MultiLayerForm::ensureVisible(QWidget* /*w*/)
{
// #baLayerEditor implement ensureVisible
}
void MultiLayerForm::setUseAngstrom(bool angstrom)
{
m_useAngstrom = angstrom;
updateUnits();
}
bool MultiLayerForm::useAngstrom() const
{
return m_useAngstrom;
}
void MultiLayerForm::setUseRadiant(bool radiant)
{
m_useRadiant = radiant;
updateUnits();
}
bool MultiLayerForm::useRadiant() const
{
return m_useRadiant;
}
void MultiLayerForm::showAddLayerButtons(bool show)
......
......@@ -48,13 +48,18 @@ public:
void updateRowVisibilities();
//! Update the presented units in all contained widgets according to current settings.
void updateUnits();
void ensureVisible(QWidget* w);
//! Show values in Angstrom or nanometers
void useAngstrom(bool angstrom);
void setUseAngstrom(bool angstrom);
bool useAngstrom() const;
//! Show values in radiants or degrees
void useRadiant(bool radiant);
void setUseRadiant(bool radiant);
bool useRadiant() const;
//! Shows or hides the "Add Layer" buttons.
void showAddLayerButtons(bool show);
......@@ -70,6 +75,8 @@ private:
MultiLayerItem* m_multiLayerItem; //!< Ptr is borrowed, don't delete
SampleEditorController* m_ec; //!< Ptr is borrowed, don't delete
bool m_showInlineEditButtons = false;
bool m_useAngstrom;
bool m_useRadiant;
QList<QPushButton*> m_addLayerButtons;
};
......
......@@ -113,7 +113,6 @@ void ParticleCoreShellForm::onCoreComboChanged()
const QString newClassName = core.formFactorCombo->currentData().toString();
m_ec->setCoreFormFactor(this, newClassName);
createCoreWidgets();
}
void ParticleCoreShellForm::onShellComboChanged()
......@@ -123,7 +122,6 @@ void ParticleCoreShellForm::onShellComboChanged()
const QString newClassName = shell.formFactorCombo->currentData().toString();
m_ec->setShellFormFactor(this, newClassName);
createShellWidgets();
}
void ParticleCoreShellForm::createCoreWidgets()
......
......@@ -34,11 +34,12 @@ public:
void enableStructureEditing(bool b);
ParticleCoreShellItem* coreShellItem() const;
void createCoreWidgets();
void createShellWidgets();
private:
void onCoreComboChanged();
void onShellComboChanged();
void createCoreWidgets();
void createShellWidgets();
private:
ParticleCoreShellItem* m_item;
......
......@@ -60,6 +60,7 @@ void SampleEditorController::addLayer(LayerItem* before)
ASSERT(m_multiLayerForm);
m_multiLayerForm->onLayerAdded(layer);
m_multiLayerForm->updateUnits();
}
void SampleEditorController::addLayout(LayerForm* layerItemWidget)
......@@ -68,6 +69,7 @@ void SampleEditorController::addLayout(LayerForm* layerItemWidget)
layerItemWidget->layerItem()->model()->insertItem<ParticleLayoutItem>(
layerItemWidget->layerItem());
layerItemWidget->onLayoutAdded(newLayoutItem);
m_multiLayerForm->updateUnits();
}
void SampleEditorController::removeLayer(LayerItem* layerItem)
......@@ -101,6 +103,7 @@ void SampleEditorController::addParticle(ParticleLayoutItem* layoutItem, const Q
for (auto w : m_multiLayerForm->findChildren<ParticleLayoutForm*>())
if (w->layoutItem() == layoutItem)
w->onParticleAdded(newItem);
m_multiLayerForm->updateUnits();
}
void SampleEditorController::addParticle(ParticleCompositionItem* compositionItem,
......@@ -125,6 +128,7 @@ void SampleEditorController::addParticle(ParticleCompositionItem* compositionIte
for (auto c : m_multiLayerForm->findChildren<ParticleCompositionForm*>())
if (c->compositionItem() == compositionItem)
c->onParticleAdded(newItem);
m_multiLayerForm->updateUnits();
}
void SampleEditorController::setCoreFormFactor(ParticleCoreShellForm* widget,
......@@ -141,6 +145,8 @@ void SampleEditorController::setCoreFormFactor(ParticleCoreShellForm* widget,
particleCoreShell->createCore();
particleCoreShell->core()->setFormFactor(formFactorModelType);
widget->createCoreWidgets();
m_multiLayerForm->updateUnits();
}
void SampleEditorController::setShellFormFactor(ParticleCoreShellForm* widget,
......@@ -157,6 +163,8 @@ void SampleEditorController::setShellFormFactor(ParticleCoreShellForm* widget,
particleCoreShell->createShell();
particleCoreShell->shell()->setFormFactor(formFactorModelType);
widget->createShellWidgets();
m_multiLayerForm->updateUnits();
}
void SampleEditorController::removeParticle(ItemWithParticles* item)
......@@ -226,6 +234,14 @@ void SampleEditorController::setInt(int newValue, UIntDescriptor d)
d.set(newValue);
}
void SampleEditorController::setCurrentIndex(SelectionContainerForm* widget, int index,
const AbstractSelectionDescriptor& d)
{
d.setCurrentIndex(index);
widget->createDoubleEdits();
m_multiLayerForm->updateUnits();
}
QUndoStack* SampleEditorController::undoStack()
{
return &m_undoStack;
......@@ -284,30 +300,22 @@ void SampleEditorController::setMesoCrystalBasis(MesoCrystalForm* widget, const
return;
}
if (classname == ParticleCompositionItem::M_TYPE) {
if (classname == ParticleCompositionItem::M_TYPE)
meso->createBasis<ParticleCompositionItem>();
return;
}
if (classname == MesoCrystalItem::M_TYPE) {
else if (classname == MesoCrystalItem::M_TYPE)
meso->createBasis<MesoCrystalItem>();
return;
}
if (classname == ParticleCoreShellItem::M_TYPE) {
else if (classname == ParticleCoreShellItem::M_TYPE)
meso->createBasis<ParticleCoreShellItem>();
return;
}
if (ItemCatalog::isFormFactorModelType(classname)) {
else if (ItemCatalog::isFormFactorModelType(classname)) {
auto* particle = dynamic_cast<ParticleItem*>(meso->basisParticle());
if (particle == nullptr)
particle = meso->createBasis<ParticleItem>();
particle->setFormFactor(classname);
return;
}
widget->createBasisWidgets();
m_multiLayerForm->updateUnits();
}
void SampleEditorController::selectInterference(ParticleLayoutItem* layoutItem, int newIndex)
......@@ -315,4 +323,5 @@ void SampleEditorController::selectInterference(ParticleLayoutItem* layoutItem,
// #baLayerEditor ++ change the visibility of particle density (compare to
// ParticleLayoutItem::updateDensityAppearance() and ParticleLayoutItem::updateDensityValue())
layoutItem->interference().setCurrentIndex(newIndex);
m_multiLayerForm->updateUnits();
}
......@@ -29,6 +29,8 @@ class ParticleCompositionItem;
class DoubleDescriptor;
class UIntDescriptor;
class ItemWithMaterial;
class SelectionContainerForm;
class AbstractSelectionDescriptor;
//! Class to modify a sample from the layer oriented sample editor.
//!
......@@ -72,11 +74,8 @@ public:
void setDoubleFromUndo(double newValue, const QString& path);
void setInt(int newValue, UIntDescriptor d);
template <typename SelectionDescriptorClass>
void setCurrentIndex(int index, SelectionDescriptorClass d)
{
d.setCurrentIndex(index);
}
void setCurrentIndex(SelectionContainerForm* widget, int index,
const AbstractSelectionDescriptor& d);
void selectMaterial(ItemWithMaterial* item, const QString& newMaterialIdentifier);
void setMaterialValue(ItemWithMaterial* item, double newValue, DoubleDescriptor d);
......
......@@ -67,12 +67,15 @@ public:
QObject::connect(m_combo, QOverload<int>::of(&QComboBox::currentIndexChanged),
[=](int current) {
clear();
ec->setCurrentIndex(current, d);
LayerEditorUtils::addMultiPropertyToGrid(m_gridLayout, 1,
currentValues(), m_ec, true);
ec->setCurrentIndex(this, current, d);
});
m_gridLayout->addWidget(m_combo, 1, 0);
createDoubleEdits();
}
void createDoubleEdits()
{
LayerEditorUtils::addMultiPropertyToGrid(m_gridLayout, 1, currentValues(), m_ec, true);
}
......
......@@ -67,6 +67,8 @@
<file>images/1D_OK.png</file>
<file>images/2D_OK.png</file>
<file>images/warning_16x16.png</file>
<file>images/unit_nm.svg</file>
<file>images/unit_angstrom.svg</file>
<file>styles/Native.stylesheet</file>
<file>styles/Base.stylesheet</file>
<file>styles/Dark.stylesheet</file>
......
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
sodipodi:docname="unit_angstrom.svg"
id="svg4"
viewBox="0 0 24 24"
height="24"
width="24"
version="1.1"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<metadata
id="metadata10">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs8" />
<sodipodi:namedview
inkscape:current-layer="svg4"
inkscape:window-maximized="0"
inkscape:window-y="0"
inkscape:window-x="571"
inkscape:cy="8.9136878"
inkscape:cx="-11.340889"
inkscape:zoom="23.895834"
showgrid="false"
id="namedview6"
inkscape:window-height="1561"
inkscape:window-width="2637"
inkscape:pageshadow="2"
inkscape:pageopacity="0"
guidetolerance="10"
gridtolerance="10"
objecttolerance="10"
borderopacity="1"
bordercolor="#666666"
pagecolor="#ffffff"
inkscape:pagecheckerboard="0" />
<g
id="g25714"
transform="rotate(-90,11.950788,12.329164)">
<path
style="fill:#838686;fill-opacity:1;stroke-width:0.196516"
id="path2"
d="M 3.9822142,4.1255449 H 3.3643168 c -0.042657,0 -0.092715,-0.1089236 -0.091571,0.9956408 l 0.014333,13.8413253 c 0.00114,1.104564 0.03458,1.163034 0.077237,1.163034 h 0.6178974 c 0.042657,0 0.062904,0.06708 0.062904,-1.037489 V 5.2885789 c 0,-1.1045695 -0.020247,-1.163034 -0.062904,-1.163034"
sodipodi:nodetypes="csssssssc" />
<path
style="fill:#838686;fill-opacity:1;stroke-width:0.110498"
id="path2-9"
d="M 8.2962914,4.1342801 H 4.3102157 c -0.275181,0 -0.5981043,-0.00534 -0.5907253,0.048796 l 0.092465,0.678357 c 0.00738,0.054134 0.2230785,0.057 0.4982594,0.057 h 3.9860757 c 0.2751801,0 0.4057931,0.00329 0.4057931,-0.050847 v -0.676306 c 0,-0.054134 -0.1306064,-0.057 -0.4057931,-0.057"
sodipodi:nodetypes="csssssssc" />
<path
style="fill:#838686;fill-opacity:1;stroke-width:0.110498"
id="path2-9-9"
d="M 7.885445,19.374909 H 3.8993691 c -0.275181,0 -0.5981043,-0.0053 -0.5907253,0.0488 l 0.092465,0.678357 c 0.00738,0.05413 0.2230785,0.057 0.4982594,0.057 H 7.885444 c 0.27518,0 0.405793,0.0033 0.405793,-0.05085 V 19.43191 c 0,-0.05413 -0.130606,-0.057 -0.405793,-0.057"
sodipodi:nodetypes="csssssssc" />
<path
style="fill:#838686;fill-opacity:1;stroke-width:0.110498"
id="path2-9-3"
d="M 8.0629922,11.326098 H 4.0769165 c -0.275181,0 -0.5981043,-0.0053 -0.5907253,0.0488 l 0.092465,0.678357 c 0.00738,0.05413 0.2230785,0.057 0.4982594,0.057 h 3.9860757 c 0.2751799,0 0.4057929,0.0033 0.4057929,-0.05085 v -0.676306 c 0,-0.05413 -0.130606,-0.057 -0.4057929,-0.057"
sodipodi:nodetypes="csssssssc" />
<path
style="fill:#838686;fill-opacity:1;stroke-width:0.0689405"
id="path2-5"
d="M 6.0347219,6.4005264 H 4.2306985 c -0.124542,0 -0.270691,-0.00459 -0.267351,0.041969 l 0.04185,0.5834502 c 0.0033,0.046561 0.100961,0.049025 0.225503,0.049025 h 1.8040234 c 0.124541,0 0.183654,0.00283 0.183654,-0.043733 V 6.4495515 c 0,-0.046561 -0.05911,-0.049025 -0.183654,-0.049025"
sodipodi:nodetypes="csssssssc" />
<path
style="fill:#838686;fill-opacity:1;stroke-width:0.0689405"
id="path2-5-6"
d="M 5.9953181,8.8086125 H 4.1912947 c -0.124542,0 -0.270691,-0.0046 -0.267351,0.04197 l 0.04185,0.58345 c 0.0033,0.04656 0.100961,0.04903 0.225503,0.04903 h 1.8040234 c 0.124541,0 0.183654,0.0028 0.183654,-0.04373 v -0.581686 c 0,-0.04656 -0.05911,-0.04903 -0.183654,-0.04903"
sodipodi:nodetypes="csssssssc" />
<path
style="fill:#838686;fill-opacity:1;stroke-width:0.0689405"
id="path2-5-5"
d="M 6.0371665,13.894711 H 4.2331431 c -0.124542,0 -0.270691,-0.0046 -0.267351,0.04197 l 0.04185,0.583451 c 0.0033,0.04656 0.100961,0.04903 0.225503,0.04903 h 1.8040234 c 0.124541,0 0.183654,0.0028 0.183654,-0.04373 v -0.581694 c 0,-0.04656 -0.05911,-0.04903 -0.183654,-0.04903"
sodipodi:nodetypes="csssssssc" />
<path
style="fill:#838686;fill-opacity:1;stroke-width:0.0689405"
id="path2-5-66"
d="M 5.9743941,16.481405 H 4.1703707 c -0.124542,0 -0.270691,-0.0046 -0.267351,0.04197 l 0.04185,0.58345 c 0.0033,0.04656 0.100961,0.04903 0.225503,0.04903 h 1.8040234 c 0.124541,0 0.183654,0.0028 0.183654,-0.04373 v -0.581686 c 0,-0.04656 -0.05911,-0.04902 -0.183654,-0.04902"
sodipodi:nodetypes="csssssssc" />
</g>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:10.6667px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000000;fill-opacity:1;stroke:none"
x="7.323452"
y="12.721884"
id="text1686"><tspan
sodipodi:role="line"
id="tspan1684"
x="7.323452"
y="12.721884">Å</tspan></text>
</svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
sodipodi:docname="unit_nm.svg"
id="svg4"
viewBox="0 0 24 24"
height="24"
width="24"
version="1.1"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<metadata
id="metadata10">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs8" />
<sodipodi:namedview
inkscape:current-layer="svg4"
inkscape:window-maximized="0"
inkscape:window-y="0"
inkscape:window-x="571"
inkscape:cy="20.840453"
inkscape:cx="27.034001"
inkscape:zoom="23.895834"
showgrid="false"
id="namedview6"
inkscape:window-height="1561"
inkscape:window-width="2637"
inkscape:pageshadow="2"
inkscape:pageopacity="0"
guidetolerance="10"
gridtolerance="10"
objecttolerance="10"
borderopacity="1"
bordercolor="#666666"
pagecolor="#ffffff"
inkscape:pagecheckerboard="0" />
<g
id="g25714"
transform="rotate(-90,11.950788,12.329164)">
<path
style="fill:#838686;fill-opacity:1;stroke-width:0.196516"
id="path2"
d="M 3.9822142,4.1255449 H 3.3643168 c -0.042657,0 -0.092715,-0.1089236 -0.091571,0.9956408 l 0.014333,13.8413253 c 0.00114,1.104564 0.03458,1.163034 0.077237,1.163034 h 0.6178974 c 0.042657,0 0.062904,0.06708 0.062904,-1.037489 V 5.2885789 c 0,-1.1045695 -0.020247,-1.163034 -0.062904,-1.163034"
sodipodi:nodetypes="csssssssc" />
<path
style="fill:#838686;fill-opacity:1;stroke-width:0.110498"
id="path2-9"
d="M 8.2962914,4.1342801 H 4.3102157 c -0.275181,0 -0.5981043,-0.00534 -0.5907253,0.048796 l 0.092465,0.678357 c 0.00738,0.054134 0.2230785,0.057 0.4982594,0.057 h 3.9860757 c 0.2751801,0 0.4057931,0.00329 0.4057931,-0.050847 v -0.676306 c 0,-0.054134 -0.1306064,-0.057 -0.4057931,-0.057"
sodipodi:nodetypes="csssssssc" />
<path
style="fill:#838686;fill-opacity:1;stroke-width:0.110498"
id="path2-9-9"
d="M 7.885445,19.374909 H 3.8993691 c -0.275181,0 -0.5981043,-0.0053 -0.5907253,0.0488 l 0.092465,0.678357 c 0.00738,0.05413 0.2230785,0.057 0.4982594,0.057 H 7.885444 c 0.27518,0 0.405793,0.0033 0.405793,-0.05085 V 19.43191 c 0,-0.05413 -0.130606,-0.057 -0.405793,-0.057"
sodipodi:nodetypes="csssssssc" />
<path
style="fill:#838686;fill-opacity:1;stroke-width:0.110498"
id="path2-9-3"
d="M 8.0629922,11.326098 H 4.0769165 c -0.275181,0 -0.5981043,-0.0053 -0.5907253,0.0488 l 0.092465,0.678357 c 0.00738,0.05413 0.2230785,0.057 0.4982594,0.057 h 3.9860757 c 0.2751799,0 0.4057929,0.0033 0.4057929,-0.05085 v -0.676306 c 0,-0.05413 -0.130606,-0.057 -0.4057929,-0.057"
sodipodi:nodetypes="csssssssc" />
<path
style="fill:#838686;fill-opacity:1;stroke-width:0.0689405"
id="path2-5"
d="M 6.0347219,6.4005264 H 4.2306985 c -0.124542,0 -0.270691,-0.00459 -0.267351,0.041969 l 0.04185,0.5834502 c 0.0033,0.046561 0.100961,0.049025 0.225503,0.049025 h 1.8040234 c 0.124541,0 0.183654,0.00283 0.183654,-0.043733 V 6.4495515 c 0,-0.046561 -0.05911,-0.049025 -0.183654,-0.049025"
sodipodi:nodetypes="csssssssc" />
<path
style="fill:#838686;fill-opacity:1;stroke-width:0.0689405"
id="path2-5-6"
d="M 5.9953181,8.8086125 H 4.1912947 c -0.124542,0 -0.270691,-0.0046 -0.267351,0.04197 l 0.04185,0.58345 c 0.0033,0.04656 0.100961,0.04903 0.225503,0.04903 h 1.8040234 c 0.124541,0 0.183654,0.0028 0.183654,-0.04373 v -0.581686 c 0,-0.04656 -0.05911,-0.04903 -0.183654,-0.04903"
sodipodi:nodetypes="csssssssc" />
<path
style="fill:#838686;fill-opacity:1;stroke-width:0.0689405"
id="path2-5-5"
d="M 6.0371665,13.894711 H 4.2331431 c -0.124542,0 -0.270691,-0.0046 -0.267351,0.04197 l 0.04185,0.583451 c 0.0033,0.04656 0.100961,0.04903 0.225503,0.04903 h 1.8040234 c 0.124541,0 0.183654,0.0028 0.183654,-0.04373 v -0.581694 c 0,-0.04656 -0.05911,-0.04903 -0.183654,-0.04903"
sodipodi:nodetypes="csssssssc" />
<path
style="fill:#838686;fill-opacity:1;stroke-width:0.0689405"
id="path2-5-66"
d="M 5.9743941,16.481405 H 4.1703707 c -0.124542,0 -0.270691,-0.0046 -0.267351,0.04197 l 0.04185,0.58345 c 0.0033,0.04656 0.100961,0.04903 0.225503,0.04903 h 1.8040234 c 0.124541,0 0.183654,0.0028 0.183654,-0.04373 v -0.581686 c 0,-0.04656 -0.05911,-0.04902 -0.183654,-0.04902"
sodipodi:nodetypes="csssssssc" />
</g>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:10.6667px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000000;fill-opacity:1;stroke:none"
x="2.4690492"
y="10.545773"
id="text1686"><tspan
sodipodi:role="line"
id="tspan1684"
x="2.4690492"
y="10.545773">nm</tspan></text>
</svg>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment