35QgsPointCloudClassifiedRendererModel::QgsPointCloudClassifiedRendererModel( QObject *parent )
 
   36  : QAbstractItemModel( parent )
 
   37  , mMimeFormat( QStringLiteral( 
"application/x-qgspointcloudclassifiedrenderermodel" ) )
 
   43  if ( !mCategories.empty() )
 
   45    beginRemoveRows( QModelIndex(), 0, std::max< int >( mCategories.size() - 1, 0 ) );
 
   49  if ( categories.size() > 0 )
 
   51    beginInsertRows( QModelIndex(), 0, categories.size() - 1 );
 
   52    mCategories = categories;
 
   59  const int idx = mCategories.size();
 
   60  beginInsertRows( QModelIndex(), idx, idx );
 
   61  mCategories.append( cat );
 
   64  emit categoriesChanged();
 
   69  const int row = index.row();
 
   70  if ( row >= mCategories.size() )
 
   74  return mCategories.at( row );
 
   77Qt::ItemFlags QgsPointCloudClassifiedRendererModel::flags( 
const QModelIndex &index )
 const 
   79  if ( !index.isValid() || mCategories.empty() )
 
   81    return Qt::ItemIsDropEnabled;
 
   84  Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable;
 
   85  if ( index.column() == 1 )
 
   87    flags |= Qt::ItemIsEditable;
 
   89  else if ( index.column() == 2 )
 
   91    flags |= Qt::ItemIsEditable;
 
   96Qt::DropActions QgsPointCloudClassifiedRendererModel::supportedDropActions()
 const 
   98  return Qt::MoveAction;
 
  101QVariant QgsPointCloudClassifiedRendererModel::data( 
const QModelIndex &index, 
int role )
 const 
  103  if ( !index.isValid() || mCategories.empty() )
 
  110    case Qt::CheckStateRole:
 
  112      if ( index.column() == 0 )
 
  114        return category.
renderState() ? Qt::Checked : Qt::Unchecked;
 
  119    case Qt::DisplayRole:
 
  120    case Qt::ToolTipRole:
 
  122      switch ( index.column() )
 
  126          return QString::number( category.
value() );
 
  129          return category.
label();
 
  131          const float value = mPercentages.value( category.
value(), -1 );
 
  135          else if ( value != 0 && std::round( value * 10 ) < 1 )
 
  136            str = QStringLiteral( 
"< " ) + QLocale().toString( 0.1, 
'f', 1 );
 
  138            str = QLocale().toString( mPercentages.value( category.
value() ), 
'f', 1 );
 
  144    case Qt::DecorationRole:
 
  146      if ( index.column() == 0 )
 
  150        pix.fill( category.
color() );
 
  156    case Qt::TextAlignmentRole:
 
  158      if ( index.column() == 0 )
 
  159        return static_cast<Qt::Alignment::Int
>( Qt::AlignHCenter );
 
  160      if ( index.column() == 3 )
 
  161        return static_cast<Qt::Alignment::Int
>( Qt::AlignRight );
 
  162      return static_cast<Qt::Alignment::Int
>( Qt::AlignLeft );
 
  167      switch ( index.column() )
 
  171          return QString::number( category.
value() );
 
  175          return category.
label();
 
  184bool QgsPointCloudClassifiedRendererModel::setData( 
const QModelIndex &index, 
const QVariant &value, 
int role )
 
  186  if ( !index.isValid() )
 
  189  if ( index.column() == 0 && role == Qt::CheckStateRole )
 
  191    mCategories[ index.row() ].setRenderState( value == Qt::Checked );
 
  192    emit dataChanged( index, index );
 
  193    emit categoriesChanged();
 
  197  if ( role != Qt::EditRole )
 
  200  switch ( index.column() )
 
  204      const int val = value.toInt();
 
  205      mCategories[ index.row() ].setValue( val );
 
  210      mCategories[ index.row() ].setLabel( value.toString() );
 
  217  emit dataChanged( index, index );
 
  218  emit categoriesChanged();
 
  222QVariant QgsPointCloudClassifiedRendererModel::headerData( 
int section, Qt::Orientation orientation, 
int role )
 const 
  224  if ( orientation == Qt::Horizontal && role == Qt::DisplayRole && section >= 0 && section < 4 )
 
  227    lst << tr( 
"Color" ) << tr( 
"Value" ) << tr( 
"Legend" ) << tr( 
"Percentage" );
 
  228    return lst.value( section );
 
  233int QgsPointCloudClassifiedRendererModel::rowCount( 
const QModelIndex &parent )
 const 
  235  if ( parent.isValid() )
 
  239  return mCategories.size();
 
  242int QgsPointCloudClassifiedRendererModel::columnCount( 
const QModelIndex &index )
 const 
  248QModelIndex QgsPointCloudClassifiedRendererModel::index( 
int row, 
int column, 
const QModelIndex &parent )
 const 
  250  if ( hasIndex( row, column, parent ) )
 
  252    return createIndex( row, column );
 
  254  return QModelIndex();
 
  257QModelIndex QgsPointCloudClassifiedRendererModel::parent( 
const QModelIndex &index )
 const 
  260  return QModelIndex();
 
  263QStringList QgsPointCloudClassifiedRendererModel::mimeTypes()
 const 
  266  types << mMimeFormat;
 
  270QMimeData *QgsPointCloudClassifiedRendererModel::mimeData( 
const QModelIndexList &indexes )
 const 
  272  QMimeData *mimeData = 
new QMimeData();
 
  273  QByteArray encodedData;
 
  275  QDataStream stream( &encodedData, QIODevice::WriteOnly );
 
  278  const auto constIndexes = indexes;
 
  279  for ( 
const QModelIndex &index : constIndexes )
 
  281    if ( !index.isValid() || index.column() != 0 )
 
  284    stream << index.row();
 
  286  mimeData->setData( mMimeFormat, encodedData );
 
  290bool QgsPointCloudClassifiedRendererModel::dropMimeData( 
const QMimeData *data, Qt::DropAction action, 
int row, 
int column, 
const QModelIndex &parent )
 
  294  if ( action != Qt::MoveAction )
 
  297  if ( !data->hasFormat( mMimeFormat ) )
 
  300  QByteArray encodedData = data->data( mMimeFormat );
 
  301  QDataStream stream( &encodedData, QIODevice::ReadOnly );
 
  304  while ( !stream.atEnd() )
 
  311  int to = parent.row();
 
  315    to = mCategories.size(); 
 
  316  for ( 
int i = rows.size() - 1; i >= 0; i-- )
 
  322    if ( !( rows[i] < 0 ||  rows[i] >= mCategories.size() || t < 0 || t >= mCategories.size() ) )
 
  324      mCategories.move( rows[i], t );
 
  328    for ( 
int j = 0; j < i; j++ )
 
  330      if ( to < rows[j] && rows[i] > rows[j] )
 
  337  emit dataChanged( createIndex( 0, 0 ), createIndex( mCategories.size(), 0 ) );
 
  338  emit categoriesChanged();
 
  342void QgsPointCloudClassifiedRendererModel::deleteRows( QList<int> rows )
 
  344  std::sort( rows.begin(), rows.end() ); 
 
  345  for ( 
int i = rows.size() - 1; i >= 0; i-- )
 
  347    beginRemoveRows( QModelIndex(), rows[i], rows[i] );
 
  348    mCategories.removeAt( rows[i] );
 
  351  emit categoriesChanged();
 
  354void QgsPointCloudClassifiedRendererModel::removeAllRows()
 
  356  beginRemoveRows( QModelIndex(), 0, mCategories.size() - 1 );
 
  359  emit categoriesChanged();
 
  362void QgsPointCloudClassifiedRendererModel::setCategoryColor( 
int row, 
const QColor &color )
 
  364  mCategories[row].setColor( color );
 
  365  emit dataChanged( createIndex( row, 0 ), createIndex( row, 0 ) );
 
  366  emit categoriesChanged();
 
  370QgsPointCloudClassifiedRendererViewStyle::QgsPointCloudClassifiedRendererViewStyle( QWidget *parent )
 
  374void QgsPointCloudClassifiedRendererViewStyle::drawPrimitive( PrimitiveElement element, 
const QStyleOption *option, QPainter *painter, 
const QWidget *widget )
 const 
  376  if ( element == QStyle::PE_IndicatorItemViewItemDrop && !option->rect.isNull() )
 
  378    QStyleOption opt( *option );
 
  379    opt.rect.setLeft( 0 );
 
  381    opt.rect.setHeight( 0 );
 
  383      opt.rect.setRight( widget->width() );
 
  384    QProxyStyle::drawPrimitive( element, &opt, painter, widget );
 
  387  QProxyStyle::drawPrimitive( element, option, painter, widget );
 
  396  mAttributeComboBox->setAllowEmptyAttributeName( 
true );
 
  399  mModel = 
new QgsPointCloudClassifiedRendererModel( 
this );
 
  403    mAttributeComboBox->setLayer( layer );
 
  405    setFromRenderer( layer->
renderer() );
 
  408  viewCategories->setModel( mModel );
 
  409  viewCategories->resizeColumnToContents( 0 );
 
  410  viewCategories->resizeColumnToContents( 1 );
 
  411  viewCategories->resizeColumnToContents( 2 );
 
  413  viewCategories->setStyle( 
new QgsPointCloudClassifiedRendererViewStyle( viewCategories ) );
 
  416           this, &QgsPointCloudClassifiedRendererWidget::attributeChanged );
 
  417  connect( mModel, &QgsPointCloudClassifiedRendererModel::categoriesChanged, 
this, &QgsPointCloudClassifiedRendererWidget::emitWidgetChanged );
 
  419  connect( viewCategories, &QAbstractItemView::doubleClicked, 
this, &QgsPointCloudClassifiedRendererWidget::categoriesDoubleClicked );
 
  420  connect( btnAddCategories, &QAbstractButton::clicked, 
this, &QgsPointCloudClassifiedRendererWidget::addCategories );
 
  421  connect( btnDeleteCategories, &QAbstractButton::clicked, 
this, &QgsPointCloudClassifiedRendererWidget::deleteCategories );
 
  422  connect( btnDeleteAllCategories, &QAbstractButton::clicked, 
this, &QgsPointCloudClassifiedRendererWidget::deleteAllCategories );
 
  423  connect( btnAddCategory, &QAbstractButton::clicked, 
this, &QgsPointCloudClassifiedRendererWidget::addCategory );
 
  429  return new QgsPointCloudClassifiedRendererWidget( layer, style );
 
  439  std::unique_ptr< QgsPointCloudClassifiedRenderer > renderer = std::make_unique< QgsPointCloudClassifiedRenderer >();
 
  440  renderer->setAttribute( mAttributeComboBox->currentAttribute() );
 
  441  renderer->setCategories( mModel->categories() );
 
  443  return renderer.release();
 
  448  return mModel->categories();
 
  451QString QgsPointCloudClassifiedRendererWidget::attribute()
 
  453  return mAttributeComboBox->currentAttribute();
 
  456void QgsPointCloudClassifiedRendererWidget::attributeChanged()
 
  458  if ( mBlockChangedSignal )
 
  461  mBlockChangedSignal = 
true;
 
  462  mModel->removeAllRows();
 
  463  mBlockChangedSignal = 
false;
 
  467void QgsPointCloudClassifiedRendererWidget::emitWidgetChanged()
 
  469  if ( mBlockChangedSignal )
 
  472  updateCategoriesPercentages();
 
  473  emit widgetChanged();
 
  476void QgsPointCloudClassifiedRendererWidget::categoriesDoubleClicked( 
const QModelIndex &idx )
 
  478  if ( idx.isValid() && idx.column() == 0 )
 
  479    changeCategorySymbol();
 
  482void QgsPointCloudClassifiedRendererWidget::addCategories()
 
  484  if ( !mLayer || !mLayer->dataProvider() )
 
  488  const QString currentAttribute = mAttributeComboBox->currentAttribute();
 
  490  const QList<int> providerCategories = stats.
classesOf( currentAttribute );
 
  494  const bool isClassificationAttribute = ! currentAttribute.compare( QStringLiteral( 
"Classification" ), Qt::CaseInsensitive );
 
  497  mBlockChangedSignal = 
true;
 
  498  for ( 
const int &providerCategory : providerCategories )
 
  504      if ( 
c.value() == providerCategory )
 
  515    if ( isClassificationAttribute )
 
  519        if ( 
c.value() == providerCategory )
 
  527    mModel->addCategory( category );
 
  529  mBlockChangedSignal = 
false;
 
  533void QgsPointCloudClassifiedRendererWidget::addCategory()
 
  539  mModel->addCategory( cat );
 
  542void QgsPointCloudClassifiedRendererWidget::deleteCategories()
 
  544  const QList<int> categoryIndexes = selectedCategories();
 
  545  mModel->deleteRows( categoryIndexes );
 
  548void QgsPointCloudClassifiedRendererWidget::deleteAllCategories()
 
  550  mModel->removeAllRows();
 
  555  mBlockChangedSignal = 
true;
 
  558    mModel->setRendererCategories( classifiedRenderer->categories() );
 
  559    mAttributeComboBox->setAttribute( classifiedRenderer->attribute() );
 
  565  mBlockChangedSignal = 
false;
 
  569void QgsPointCloudClassifiedRendererWidget::setFromCategories( 
QgsPointCloudCategoryList categories, 
const QString &attribute )
 
  571  mBlockChangedSignal = 
true;
 
  572  mModel->setRendererCategories( categories );
 
  573  if ( !attribute.isEmpty() )
 
  575    mAttributeComboBox->setAttribute( attribute );
 
  581  mBlockChangedSignal = 
false;
 
  585void QgsPointCloudClassifiedRendererWidget::initialize()
 
  587  if ( mAttributeComboBox->findText( QStringLiteral( 
"Classification" ) ) > -1 )
 
  589    mAttributeComboBox->setAttribute( QStringLiteral( 
"Classification" ) );
 
  593    mAttributeComboBox->setCurrentIndex( mAttributeComboBox->count() > 1 ? 1 : 0 );
 
  595  mModel->removeAllRows();
 
  599void QgsPointCloudClassifiedRendererWidget::changeCategorySymbol()
 
  601  const int row = currentCategoryRow();
 
  617      mModel->setCategoryColor( row, newColor );
 
  624    if ( newColor.isValid() )
 
  626      mModel->setCategoryColor( row, newColor );
 
  631QList<int> QgsPointCloudClassifiedRendererWidget::selectedCategories()
 
  634  const QModelIndexList selectedRows = viewCategories->selectionModel()->selectedRows();
 
  635  for ( 
const QModelIndex &r : selectedRows )
 
  639      rows.append( r.row() );
 
  645int QgsPointCloudClassifiedRendererWidget::currentCategoryRow()
 
  647  const QModelIndex idx = viewCategories->selectionModel()->currentIndex();
 
  648  if ( !idx.isValid() )
 
  653void QgsPointCloudClassifiedRendererWidget::updateCategoriesPercentages()
 
  655  QMap < int, float > percentages;
 
  666    if ( classes.contains( category.
value() ) || statsExact )
 
  667      percentages.insert( category.
value(), ( 
double ) classes.value( category.
value() ) / pointCount * 100 );
 
  669  mModel->updateCategoriesPercentages( percentages );
 
static QgsColorSchemeRegistry * colorSchemeRegistry()
Returns the application's color scheme registry, used for managing color schemes.
 
static QColor getColor(const QColor &initialColor, QWidget *parent, const QString &title=QString(), bool allowOpacity=false)
Returns a color selection from a color dialog.
 
QColor fetchRandomStyleColor() const
Returns a random color for use with a new symbol style (e.g.
 
void attributeChanged(const QString &name)
Emitted when the currently selected attribute changes.
 
@ Char
Character attributes.
 
Represents an individual category (class) from a QgsPointCloudClassifiedRenderer.
 
int value() const
Returns the value corresponding to this category.
 
bool renderState() const
Returns true if the category is currently enabled and should be rendered.
 
QColor color() const
Returns the color which will be used to render this category.
 
QString label() const
Returns the label for this category, which is used to represent the category within legends and the l...
 
Renders point clouds by a classification attribute.
 
Represents a map layer supporting display of point clouds.
 
QgsPointCloudRenderer * renderer()
Returns the 2D renderer for the point cloud.
 
static QgsPointCloudCategoryList classificationAttributeCategories(const QgsPointCloudLayer *layer)
Returns a list of categories using the available Classification classes of a specified layer,...
 
Abstract base class for 2d point cloud renderers.
 
Class used to store statistics of a point cloud dataset.
 
QMap< int, int > availableClasses(const QString &attribute) const
Returns a map containing the count of each class of the attribute attribute If no matching statistic ...
 
QList< int > classesOf(const QString &attribute) const
Returns a list of existing classes which are present for the specified attribute.
 
int sampledPointsCount() const
Returns the number of points used to calculate the statistics.
 
A QProxyStyle subclass which correctly sets the base style to match the QGIS application style,...
 
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window's toolbar icons.
 
int scaleIconSize(int standardSize)
Scales an icon size to compensate for display pixel density, making the icon size hi-dpi friendly,...
 
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
 
QList< QgsPointCloudCategory > QgsPointCloudCategoryList