Skip to content
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

Unexpected crash using: QgsFeatureRenderer.symbolForFeature() #68

Closed
T4mmi opened this issue Mar 4, 2021 · 5 comments
Closed

Unexpected crash using: QgsFeatureRenderer.symbolForFeature() #68

T4mmi opened this issue Mar 4, 2021 · 5 comments
Labels

Comments

@T4mmi
Copy link

T4mmi commented Mar 4, 2021

Hi all,
I'm trying to convert a 2D+Z vector layer to a 3D objet (using VTK) ...
So far I managed to get the geometry right :
qgis3d
but i'm looking to color the 3D object using the iface.mapCanvas() rendering ...

all I could find is to request the QgsSymbol for each feature and collect its color/label/whatever.
maybe there is a better way, but i could not find it

so when i try to call layer.renderer().symbolForFeature(feature, context) I got an unexpected crash ... linked to SIP and python binded methods

# -*- coding: utf-8 -*-
from qgis.core import QgsRenderContext
from qgis.core import QgsVectorLayer
from qgis.core import QgsWkbTypes
from qgis.utils import iface
from vtk import vtkCellArray
from vtk import vtkIntArray
from vtk import vtkPoints
from vtk import vtkPolyData
from vtk.util.numpy_support import numpy_to_vtk

__all__ = ["QgsVectorLayerToPolyData"]


def set_cells(poly: vtkPolyData, cells: vtkCellArray, dim: int):
    if dim == 0:
        poly.SetVerts(cells)
    elif dim == 1:
        poly.SetLines(cells)
    elif dim == 2:
        poly.SetPolys(cells)
    else:
        raise ValueError(f"Invalid data dimension: {dim}")


def QgsVectorLayerToPolyData(layer: QgsVectorLayer, build_lut=False):
    _type = layer.wkbType()
    _dim = QgsWkbTypes.wkbDimensions(_type)

    assert layer.isSpatial()  # i.e. have some geometries (might be empty)
    assert QgsWkbTypes.hasZ(_type)  # i.e. geometries are defined in R^3

    painter = layer.renderer().clone()
    context = QgsRenderContext.fromMapSettings(iface.mapCanvas().mapSettings())

    # Python side mesh primitives
    n, vertices = 0, []
    offsets, connectivity = [0], []
    colors = []
    for f in layer.getFeatures():
        symbol = painter.symbolForFeature(f, context)  # HERE IS THE PROBLEM
        colors.append(int(symbol.color().name().lstrip("#"), base = 16))
        for p in f.geometry().constParts():
            for v in p.vertices():
                vertices.append((v.x(), v.y(), v.z()))
                connectivity.append(n)
                n += 1
            if _dim == 2:  # OGR/WKT polygons duplicates first/last vertex
                del vertices[-1]
                del connectivity[-1]
                n -= 1
            offsets.append(n)

    # VTK/C++ side mesh
    polydata = vtkPolyData()
    points = vtkPoints()
    points.SetData(numpy_to_vtk(vertices, 1))
    cells = vtkCellArray()
    cells.SetData(numpy_to_vtk(offsets, 1), numpy_to_vtk(connectivity, 1))
    scalars = vtkIntArray()
    scalars.SetNumberOfComponents(1)
    scalars.SetName("Legend")
    scalars.SetData(numpy_to_vtk(colors, 1))
    # vtkPolyData generation
    polydata.SetPoints(points)
    set_cells(polydata, cells, _dim)
    polydata.GetCellData().AddArray(scalars)
    return polydata

the full crash repport:

Crash ID: cb1c4f2b11cbd392a38c522a5ed1e194e060e4a0


Stack Trace


QgsExpression::evaluate :
QgsCategorizedSymbolRenderer::valueForFeature :
QgsCategorizedSymbolRenderer::originalSymbolForFeature :
PyInit__core :
PyMethodDef_RawFastCallKeywords :
PyMethodDef_RawFastCallKeywords :
PyEval_EvalFrameDefault :
PyEval_EvalCodeWithName :
PyMethodDef_RawFastCallKeywords :
PyEval_EvalFrameDefault :
PyEval_EvalCodeWithName :
PyMethodDef_RawFastCallKeywords :
PyEval_EvalFrameDefault :
PyEval_EvalCodeWithName :
PyMethodDef_RawFastCallKeywords :
PyEval_EvalFrameDefault :
PyEval_EvalCodeWithName :
PyFunction_FastCallDict :
PyTuple_New :
PyObject_FastCallKeywords :
PyObject_FastCallKeywords :
PyMethodDef_RawFastCallKeywords :
PyEval_EvalFrameDefault :
PyEval_EvalCodeWithName :
PyFunction_FastCallDict :
PyTuple_New :
PyObject_FastCallKeywords :
PyObject_FastCallKeywords :
PyMethodDef_RawFastCallKeywords :
PyEval_EvalFrameDefault :
PyMethodDef_RawFastCallKeywords :
PyEval_EvalFrameDefault :
PyMethodDef_RawFastCallKeywords :
PyEval_EvalFrameDefault :
PyMethodDef_RawFastCallKeywords :
PyEval_EvalFrameDefault :
PyMethodDef_RawFastCallKeywords :
PyEval_EvalFrameDefault :
PyFunction_FastCallDict :
PyMethodDef_RawFastCallDict :
PyObject_Call :
PyInit_QtCore :
PyInit_QtCore :
PyInit_QtCore :
PyInit_QtCore :
PyInit_QtCore :
QMetaObject::activate :
QAction::activate :
QAbstractButton::click :
QAbstractButton::mouseReleaseEvent :
QToolButton::mouseReleaseEvent :
QWidget::event :
QApplicationPrivate::notify_helper :
QApplication::notify :
QgsApplication::notify :
QCoreApplication::notifyInternal2 :
QApplicationPrivate::sendMouseEvent :
QSizePolicy::QSizePolicy :
QSizePolicy::QSizePolicy :
QApplicationPrivate::notify_helper :
QApplication::notify :
QgsApplication::notify :
QCoreApplication::notifyInternal2 :
QGuiApplicationPrivate::processMouseEvent :
QWindowSystemInterface::sendWindowSystemEvents :
QEventDispatcherWin32::processEvents :
UserCallWinProcCheckWow :
DispatchMessageWorker :
QEventDispatcherWin32::processEvents :
qt_plugin_query_metadata :
QEventLoop::exec :
QCoreApplication::exec :
main :
BaseThreadInitThunk :
RtlUserThreadStart :




QGIS Info
QGIS Version: 3.16.2-Hannover
QGIS code revision: f1660f9da5
Compiled against Qt: 5.11.2
Running against Qt: 5.11.2
Compiled against GDAL: 3.1.4
Running against GDAL: 3.1.4



System Info
CPU Type: x86_64
Kernel Type: winnt
Kernel Version: 10.0.17763
@T4mmi T4mmi changed the title Extract symbol for feature using: QgsFeatureRenderer.symbolForFeature() Unexpected crash using: QgsFeatureRenderer.symbolForFeature() Mar 4, 2021
@gioman
Copy link

gioman commented Mar 4, 2021

@T4mmi is this a question?

@gioman gioman added the bug label Mar 4, 2021
@T4mmi
Copy link
Author

T4mmi commented Mar 4, 2021

I have no idea ... I feel like this is a bug BUT I'm far from understanding everything that happens under the hood so it might be just a bad use of this functionnality ....

I had almost the same behavior (SIP-related crash) using the non-const iterator in the geometry parts loop for p in f.geometry().constParts(): that i solved using for p in f.geometry().constParts(): instead ... but here I don't see any workaround so asked for help ...

@gioman
Copy link

gioman commented Mar 4, 2021

@T4mmi if you are looking for feedback you should write in the QGIS developers mailing list, not here.

@T4mmi
Copy link
Author

T4mmi commented Mar 4, 2021

Ok, thanks, will do !

[edit] following the comment on dev-list I opened the issue on the QGIS repo : qgis/QGIS#42027

@T4mmi T4mmi closed this as completed Mar 4, 2021
@T4mmi
Copy link
Author

T4mmi commented Mar 4, 2021

The answer from mailling list solved the problem :

you need to use it within a startRender() and stopRender() section:

renderContext = QgsRenderContext()
renderContext.setExtent(layer.extent())
renderer = layer.renderer().clone()
renderer.startRender(renderContext, layer.fields())
for feature in layer.getFeatures():
     symbol = renderer.symbolForFeature(feature, renderContext)
renderer.stopRender()

it might be a nice warning to add in the documentation)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants