The new QgsRenderContext::TextRenderFormat enum controls how text
should be handled during a render operation, e.g. whether to render
text as outlines (paths) or keep it as real text objects.
Deprecate previous arguments in QgsTextRenderer which handled
this same use case.
This allows us to make the setting vary per-render, instead of
having a single global flag controlling the setting. Ultimately
this will allow us to have different behaviour within the
canvas renders vs print layout exports.
Refs #3975
Fixes an issue identified in the upcoming QGIS Map Design 2nd ed
(spoiler alert!) where it's impossible to utilise label text
substitutions if you also want to use word wrapping.
This isn't possible to directly fix, because we need to evaluate
the full label expression (including the word wrapping component)
in order to actually HAVE text to substitute into.
So, a new setting has been added to the label formatting tab
allowing users to directly set an auto-wrapping line ideal
line size. This is applied AFTER label text evaluation, substitutions,
and the 'wrap text on' character, so it can play correctly well with
all these other settings. This also has the nice side-effect
of making auto label text wrapping more accessible to new
users/those unfamiliar with the wordwrap expression function.
Fixes#20007, and cleans up a chapter of QMD 2ed ;)
This forces Python code and plugins to become datum transform
aware, and given that upgrading python code is easy (just
add QgsProject.instance() as a new argument to the constructor)
it's relatively painless to force this on PyQGIS users.
Also fix upgrade the easy QgsCoordinateTransform c++ constructors
where the project is available, or where using QgsProject::instance()
is safe to do.
For others, just avoid the deprecated warnings until we can
get access to the correct project instance where the transform
is being constructed.
Because feature.geometry().geometry() is confusing, and impossible
to search for in python code (e.g. is input.geometry() a QgsGeometry
or a QgsAbstractGeometry?)
But more importantantly: also add a const version
QgsGeometry::constGet(). The non-const
version is slow, since it now forces a detach to avoid corrupting
geometries (since QgsGeometry is shared, it's not safe to directly
access its primitive QgsAbstractGeometry and start messing with
it without first detaching). This is a big risk in the 2.x API
which could potentially corrupt feature geometries with unexpected
outcomes.
Update all uses to constGet where possible.
Geometries are passed as const reference and returned by value.
This make using the API easier and reduces the risk of ownership
problems.
The overhead is minimal due to implicit sharing.
Fix https://github.com/qgis/qgis3.0_api/issues/68
Historically the configuration used to be stored in layer's custom properties, but that does not scale
beyond simple rendering and so rule-based labeling introduced storage of configuration natively in XML elements.
That left us with two different ways of reading/writing labeling configurations. This work makes all configuration
to use native XML elements.
To keep compatibility of 2.x projects, reading of configuration from custom properties is preserved.
This commit also adds Python APIs for direct manipulation of labeling configuration through vector layer's
setLabeling() and labeling() calls.
Another bit to make core library independent from QgsProject::instance().
Until now labeling engine configuration was taken from project singleton.
Removed legacy methods from QgsPalLabeling - the class now does not have
any more member variables/methods, it is just a bunch of helper functions.
(PR #4384)
Instead of requiring all linestrings to be constructed by
first creating QgsPointSequence (requiring creation or
conversion of points to QgsPointV2), allow construction
of LineStrings directly from vectors of values (fastest!)
or lists of QgsPoint.
Likely results in speedups for lots of geometry operations,
but using the same layer as earlier tested for densify
improvements the densify operation time dropped further
from 25 seconds to 15 seconds.
Because
- OTF reprojection is mature and stable
- Should be no cost when not required - transforms are shortcut
when not required
- Reduces code complexity
- Canvas OTF support was being incorrectly used as a flag for
whether measurements should be made in ellipsoidal mode. Instead
the project's ellipsoid setting should be checked for this.
- Should simplify behavior for new users
Why?
- no benefits to QScopedPointer over std::unique_ptr
- unlike QScopedPointer, std::unique_ptr has no overhead
over regular pointers
- using standard language features makes it more likely that
compilers can optimise this use and static analysers can
correctly handle code using unique_ptrs
- QScopedPointer has an (IMO) uncertain future (given that
Qt is dropping features which have become part of the c++
standard). Better to port now before wider use of QScopedPointer
in the codebase!
These were not being used by QGIS code (always left at default 1.0
value), and removing them from the api allows us to simplify lots
of code. It also makes QgsRenderContext scaling much less confusing.
Moves all the drawing code out of labeling into a new class
which just handles rendering text. This allows other parts
of the code to utilise all the advanced formatting options
that labeling supports, eg rendering text with shadows,
buffers and backgrounds.
The order of the elements is irrelevant and duplicate elements are unwanted. It
is therefore a perfect candidate for a set instead of a list. This prevents
filtering for duplicates manually be replacing some filer codes with (more
performant) builtin methods of QSet.
Now all evaluate/prepare/etc methods must be called using QgsExpressionContexts
Also remove most remaining traces of special variables. This brings some
user facing changes, such that existing expressions may need to be
updated if they used these old special variables (eg $scale,
$feature). These changes are noted in doc/qgis3_user_changes.dox
so that we can include them in the release notes.
The option was not working with perimeter placements as perimeter placements alter
the label feature geometry to be a boundary linestring - hence no labels where
ever inside this boundary.
Accordingly this refactors how the force label inside polygon option functions.
Now QgsLabelFeatures can have a permissible zone geometry set, such that any
label candidates outside of this permissible zone are discarded.
This approach is more flexible as it could also be used for more labeling options
in future, eg discarding label candidates which are too far from a centroid or
something.
Sponsored by Andreas Neumann
* Remove deprecated Qgis::WKBType and API cleanup
Renames QgsWKBTypes to QgsWkbTypes
Replaces usage of the enums:
* Qgis::WKBType with QgsWkbTypes::Type
* Qgis::GeometryType with QgsWkbTypes::GeometryType
Their values should be forward compatible (a fact that was already
explited up to now by casting between the types)
Renames some SSLxxx to SslXxx and URIxxx to UriXxx
* Fix build warnings and simplify type handling
* Add a fixer to rewrite imports
* The forgotten rebase conflictThe forgotten rebase conflicts
* QgsDataSourcURI > QgsDataSourceUri
* QgsWKBTypes > QgsWkbTypes
* Qgis.WKBGeom > QgsWkbTypes.Geom
* Further python fixes
* Guess what... Qgis::wkbDimensions != QgsWkbTypes::wkbDimensions
* Fix tests
* Python 3 updates
* [travis] pull request caching cannot be disabled
so at least use it in r/w mode
* Fix python3 print in plugins
All pointer based methods have been removed.
Now we have only:
void setGeometry( const QgsGeometry& geom )
and
QgsGeometry geometry() const
Benefits include avoiding a whole lot of tricky pointer lifetime
issues, potential memory leaks, and finally closing #777, which
has survived for over 9 years!...
Impacts on PyQGIS code:
- no more need for the messy
g = QgsGeometry( feature.geometry() )
workaround, just use g = feature.geometry() instead
- IMPORTANT: you can no longer test whether a feature has geometry
using `if f.geometry():`, since QgsFeature::geometry() will
*always* return an object. Instead, use
`if not f.geometry().isEmpty():`, or preferably the new method
`if not f.hasGeometry():`
Fix#777