-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix $length in labels #9063
Fix $length in labels #9063
Conversation
Thanks for looking at this one @mhugo! I haven't looked over your pr yet, but I have been thinking about this issue for some time. The problem is that this same underlying issue keeps popping up over and over as more parts of code use expressions and don't have the proper setup for the distance area, and getting this info to them is more and more intrusive. I think the ultimate solution here would be to take advantage of expression contexts, as they always have proper knowledge of both the project settings AND the layer settings, and in a safe way. So we could store the ellipsoid, length, area settings from project in the project expression context scope, and then add the layer specific crs info when the layer scope gets added, and use these together to automatically create the correct QgsDistanceArea for the expression. This would mean ALL expressions, regardless of where they are, would be guaranteed to have the correct ellipsoid setup and return consistent calculations. What do you think about this approach? |
@nyalldawson Oh yes it seems way cleaner to use expression contexts for that ! Thanks for the suggestion. I'll work on it. |
@nyalldawson I've updated the PR. It seems cleaner. I've added a "_project" variable in the project scope, as it is done with the "layer" variable in a layer scope, because I needed a way to access "project->transformContext" (see https://github.com/qgis/QGIS/pull/9063/files#diff-32b4ab0f3d67d8d2708ae40f27886ea9R328) Tell me what you think |
This is looking great! I'm a little concerned about thread safety with the use of project and layer here though. I think we can avoid this by:
That leaves just the transform context to handle. I think we could safely make this metatyped and again store as just another (hidden) context variable. QgsCoordinateTransformContext is implicitly shared, so copies are cheap. This means we could eliminate the raw QgsProject access, and everything should be gauranteed thread safe. What do you think? Lastly, I think we may need to force a call to initGeomCalculator on first expression evaluation if the expression has not been previously prepared. This would gaurantee that ALL expressions are correct from now on, even if the expression hasn't been previously prepared. |
@nyalldawson Thanks for your feedback.
It would need to make QgsCoordinateTransformContext a QObject, but that should not hurt. One variable for each parameter is better than one opaque variable "project", I agree.
You mean just in case the contract stated in the documentation does not hold ? ("\note prepare() should be called before calling this method") |
I don't think that's necessary for metatyping - e.g. QgsRectangle is metatyped but isn't a QObject.
Yeah, just to be safe. I'd be surprised if even in core qgis we always prepare expressions, not to mention 3rd party scripts/plugins.*
|
a3e4bd8
to
32dd4a5
Compare
@nyalldawson Updated PR. The following variables are now used:
I've also added a qWarning in evaluate if prepare() has not been called before |
Looks absolutely perfect to me... Great stuff! |
@nyalldawson Thanks for your enthusiasm :) There was something else missing: setGeomCalculator(), setDistanceUnits() and setAreaUnits() on QgsExpression have now priority on variables set in the expression context for the building of a geometry calculator to avoid any regression. And calling prepare() in evaluate() revealed a bug that should be fixed by 110eb98 |
Is the warning necessary since the preparation is done in the function right after? |
@roya0045 I would say the warning is here to help us fix calls to QgsExpression and make sure prepare() is called before evaluate(). |
Use the project expression scope to access project parameters (ellipsoid and distance/area units)
Look also for the attribute in the feature, as it is done by evalNode()
setGeomCalculator, setDistanceUnits and setAreaUnits have now precedence over expression scopes.
Description
This fixes https://issues.qgis.org/issues/19355.
The fix in itself is quite simple, but the main problem is to have access to distance and area units parameters from within QgsPalLayerSettings.
Since access to QgsProject::instance() is not recommended (for good reasons), I had to add members to QgsRenderContext and QgsMapSettings in order to propagate these parameters.
Review welcomed !
Checklist
fixes #11111
in the commit message next to the description[FEATURE]
in the commit message[needs-docs]
in the commit message and contain sufficient information in the commit message to be documentedscripts/prepare-commit.sh
script before each commit