Skip to content

Conversation

@dl3sdo
Copy link
Member

@dl3sdo dl3sdo commented Mar 18, 2023

Mapper sometimes needs to handle symbol properties that are not part of Mapper's own set of symbol properties and that need to be applied when importing objects.
Example: horizontal and vertical text alignment is a symbol property in OCAD but an object property in Mapper.
Mapper uses auxiliary data structures to temporarily store those symbol properties for later applying them on object import.
This change adds a QVariantHash element to the Symbol base class that allows a flexible and type safe storage of auxiliary symbol properties.
These auxiliary symbol properties are neither saved to a map file nor loaded from it.

The second commit applies the auxiliary symbol properties to the DXF import where text object properties like the text itself, alignment and rotation were previously imported by putting them into a string and transporting the string via the description property of the related text symbol.
Besides being an awkward design the approach suffers from multiple deficiencies: the auxiliary string was not removed from the description field, the rotation angle was rounded (e.g., -17.2 became 20) and the way of constructing and parsing the string was unnecessary complex.
Note that this commit replaces #2135.

The third commit applies the auxiliary symbol properties to the import of OCAD maps.
Auxiliary symbol properties are replacing the text_halign_map and text_valign_map hashes that were used to store OCAD's symbol properties for horizontal and vertical text alignment for being applied later to text object import.

This PR is a POC to demonstrate a possible way of preserving symbol/object related properties until object creation.

Auxiliary symbol properties could be considered with respect to #2082 and #1639.

@dl3sdo dl3sdo marked this pull request as draft March 18, 2023 21:52
@dl3sdo dl3sdo force-pushed the auxiliary-symbol-properties branch from fa730df to d2790d9 Compare December 1, 2024 11:08
@dl3sdo dl3sdo force-pushed the auxiliary-symbol-properties branch from d2790d9 to b5ef334 Compare January 12, 2025 22:01
@dl3sdo dl3sdo force-pushed the auxiliary-symbol-properties branch from b5ef334 to 13a86c8 Compare January 21, 2025 13:58
@dl3sdo dl3sdo requested a review from dg0yt January 21, 2025 15:40
Copy link
Member

@dg0yt dg0yt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Early notes.

bool is_hidden; /// \see isHidden()
bool is_protected; /// \see isProtected()
bool is_rotatable = false;
QVariantHash auxiliary_properties; /// Auxiliary properties for import of objects (e.g., .ocd, .dxf files). Auxiliary properties are not saved in a map file.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QVariantHash means QHash<QString,QVariant>. Given that the use of this member is tightly scoped to the import of objects, i.e. to particular importers, I would prefer an int key type with named constants (from the actual importer) instant of arbitrary strings. This helps to detect typos at compile time and is cheaper than QString. And with QHash instead of any array-like structure, it should still be robust and convenient enough.

Suggested change
QVariantHash auxiliary_properties; /// Auxiliary properties for import of objects (e.g., .ocd, .dxf files). Auxiliary properties are not saved in a map file.
QHash<int,QVariant> auxiliary_properties; /// For temporary use during import. Not to be saved on export.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

t->setText(getObjectText(ocd_object));
t->setRotation(convertAngle(ocd_object.angle));
t->setHorizontalAlignment(text_halign_map.value(symbol));
t->setHorizontalAlignment((symbol->getAuxiliaryProperty(QLatin1String("HAlign")).value<TextObject::HorizontalAlignment>()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the suggested int keys, this becomes something like

Suggested change
t->setHorizontalAlignment((symbol->getAuxiliaryProperty(QLatin1String("HAlign")).value<TextObject::HorizontalAlignment>()));
t->setHorizontalAlignment(symbol->getAuxiliaryProperty(OcdFileImportProperties::HAlign).value<TextObject::HorizontalAlignment>());

Still longer than the original code... the generalization isn't beneficial here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, I put the enums in the source files. I'm not sure whether the anonymous namespaces around are superfluous.

Comment on lines 547 to 551
/**
* Returns and then removes an auxiliary property of this symbol.
*/
QVariant consumeAuxiliaryProperty(QString key);

/**
* Returns and then removes an auxiliary property of this symbol or returns a default value.
*/
QVariant consumeAuxiliaryProperty(QString key, QVariant default_value);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tend to suggest a single clearAuxiliaryProperties() instead of the consume... pattern. This function could be called for all symbols at the end of an import if necessary and appropriate.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

FILEFORMAT_ASSERT(split < length);

auto label = description.right(length - split - 1);
auto label = symbol->consumeAuxiliaryProperty(QLatin1String("label")).toString();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't test now, but I guess that this shows the potential and the missing pieces:
Putting the label into the description was a hack, but it helped to assign objects with the same label to a a single symbol. Probably also on a second and third import into the same map.

This could be covered with an automated test: a test vector file with to identical objects, imported twice. At the end there must be a map with four objects with one symbol.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Due to my understanding of OgrFileImport::getSymbolForLabel() objects with the same color and font size are assigned to a single symbol, the label as well as anchor and angle are always overwritten.
My proposal would not change the current behaviour, IMO.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@dl3sdo
Copy link
Member Author

dl3sdo commented Feb 2, 2025

Test file:
DXFTextImport.zip

@dl3sdo
Copy link
Member Author

dl3sdo commented Apr 6, 2025

Adding an automated test as proposed by @dg0yt shows an interesting behaviour (maybe a bug in my version of OGR):
The import of the angle as done by auto angle = OGR_ST_GetParamDbl(tool, OGRSTLabelAngle, &is_null);
will return

  • -1.12 for -1.1234
  • 1.12 for 1.1234
  • 17.2 for -17.234
  • 53.2 for 53.234
  • -348.0 for -348.456

I assume that this is the root cause (if I understand "%.3g" correctly):
In ogrdxflayer.cpp

if (dfAngle != 0.0)
{
    CPLsnprintf(szBuffer, sizeof(szBuffer), "%.3g", dfAngle);
    osStyle += CPLString().Printf(",a:%s", szBuffer);
}

@dl3sdo
Copy link
Member Author

dl3sdo commented Apr 6, 2025

Note:
Text alignment for MTEXT objects uses code 71.
The anchor import as done by OGR_ST_GetParamNum(tool, OGRSTLabelAnchor, &is_null) applies a mapping of 71 codes according to {-1, 7, 8, 9, 4, 5, 6, 1, 2, 3} in ogrdxflayer.cpp.

Code 71 due to AutoCAD 2012 DXF Reference

1 = Top left; 2 = Top center; 3 = Top right
4 = Middle left; 5 = Middle center; 6 = Middle right
7 = Bottom left; 8 = Bottom center; 9 = Bottom right

Note: Revise void applyLabelAnchor(int anchor, TextObject* text_object)

@dl3sdo dl3sdo force-pushed the auxiliary-symbol-properties branch from e89b490 to c5bdadc Compare April 6, 2025 14:07
@dl3sdo dl3sdo marked this pull request as ready for review April 6, 2025 15:22
@dl3sdo dl3sdo force-pushed the auxiliary-symbol-properties branch from c5bdadc to 39ebb69 Compare May 19, 2025 07:59
@dl3sdo
Copy link
Member Author

dl3sdo commented May 19, 2025

Rebased to resolve merge conflicts.
@dg0yt: maybe this is a candidate for 0.96: it's already partly reviewed by you, no translations are affected and a test case exists.

@dl3sdo dl3sdo force-pushed the auxiliary-symbol-properties branch from 39ebb69 to 487d168 Compare December 15, 2025 20:29
@dl3sdo dl3sdo added this to the v0.9.7 milestone Dec 15, 2025
Mapper sometimes needs to handle symbol properties that are not part of
Mapper's own set of symbol properties and that need to be applied when
importing objects.
Example: horizontal and vertical text alignment is a symbol property in
OCAD but an object property in Mapper.
Extend the Symbol base class for storing auxiliary symbol properties
that are neither saved to a map file nor loaded from it.
Text object properties like the text itself, alignment and rotation were
imported by putting them into a string and transporting the string via
the description property of the related text symbol.
This approach suffers from multiple deficiencies: the auxiliary string
was not removed from the description field, the rotation angle was
rounded (e.g., -17.2 became 20) and the way of constructing and parsing
the string was unnecessary complex.
Use the auxiliary symbol properties instead to transport the object
properties.
Auxiliary symbol properties are replacing the text_halign_map and
text_valign_map hashes that were used to store OCAD's symbol properties
for horizontal and vertical text alignment for being applied later to
text object import.
@dl3sdo dl3sdo force-pushed the auxiliary-symbol-properties branch from 0a8367d to 37b09a5 Compare December 23, 2025 09:48
@dl3sdo
Copy link
Member Author

dl3sdo commented Dec 23, 2025

I propose to merge #2421 first.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants