30#define M_DEG2RAD 0.0174532925 
   36  if ( mCacheFaceIndex != -1 && mCacheFaceIndex < mTriangularMesh.triangles().count() )
 
   38    QgsVector res = interpolatedValuePrivate( mCacheFaceIndex, point );
 
   39    if ( isVectorValid( res ) )
 
   41      activeFaceFilter( res, mCacheFaceIndex );
 
   47  QList<int> potentialFaceIndexes = mTriangularMesh.faceIndexesForRectangle( 
QgsRectangle( point, point ) );
 
   49  for ( 
const int faceIndex : potentialFaceIndexes )
 
   51    QgsVector res = interpolatedValuePrivate( faceIndex, point );
 
   52    if ( isVectorValid( res ) )
 
   54      mCacheFaceIndex = faceIndex;
 
   55      activeFaceFilter( res, mCacheFaceIndex );
 
   61  return ( 
QgsVector( std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN() ) );
 
   65QgsMeshVectorValueInterpolator &QgsMeshVectorValueInterpolator::operator=( 
const QgsMeshVectorValueInterpolator &other )
 
   67  mTriangularMesh = other.mTriangularMesh;
 
   68  mDatasetValues = other.mDatasetValues;
 
   69  mActiveFaceFlagValues = other.mActiveFaceFlagValues;
 
   70  mFaceCache = other.mFaceCache;
 
   71  mCacheFaceIndex = other.mCacheFaceIndex;
 
   72  mUseScalarActiveFaceFlagValues = other.mUseScalarActiveFaceFlagValues;
 
   77QgsMeshVectorValueInterpolatorFromVertex::
 
   79  : QgsMeshVectorValueInterpolator( triangularMesh, datasetVectorValues )
 
   84QgsMeshVectorValueInterpolatorFromVertex::
 
   88  : QgsMeshVectorValueInterpolator( triangularMesh, datasetVectorValues, scalarActiveFaceFlagValues )
 
   93QgsMeshVectorValueInterpolatorFromVertex::QgsMeshVectorValueInterpolatorFromVertex( 
const QgsMeshVectorValueInterpolatorFromVertex &other ):
 
   94  QgsMeshVectorValueInterpolator( other )
 
   97QgsMeshVectorValueInterpolatorFromVertex *QgsMeshVectorValueInterpolatorFromVertex::clone()
 
   99  return new QgsMeshVectorValueInterpolatorFromVertex( *
this );
 
  102QgsMeshVectorValueInterpolatorFromVertex &QgsMeshVectorValueInterpolatorFromVertex::
 
  103operator=( 
const QgsMeshVectorValueInterpolatorFromVertex &other )
 
  105  QgsMeshVectorValueInterpolator::operator=( other );
 
  109QgsVector QgsMeshVectorValueInterpolatorFromVertex::interpolatedValuePrivate( 
int faceIndex, 
const QgsPointXY point )
 const 
  111  QgsMeshFace face = mTriangularMesh.triangles().at( faceIndex );
 
  118                            mDatasetValues.value( face.at( 0 ) ).y() );
 
  121                            mDatasetValues.value( face.at( 1 ) ).y() );
 
  124                            mDatasetValues.value( face.at( 2 ) ).y() );
 
  126  return QgsMeshLayerUtils::interpolateVectorFromVerticesData(
 
  136QgsMeshVectorValueInterpolator::QgsMeshVectorValueInterpolator( 
const QgsTriangularMesh &triangularMesh,
 
  138  : mTriangularMesh( triangularMesh )
 
  139  , mDatasetValues( datasetVectorValues )
 
  140  , mUseScalarActiveFaceFlagValues( false )
 
  143QgsMeshVectorValueInterpolator::QgsMeshVectorValueInterpolator( 
const QgsTriangularMesh &triangularMesh,
 
  146  : mTriangularMesh( triangularMesh )
 
  147  , mDatasetValues( datasetVectorValues )
 
  148  , mActiveFaceFlagValues( scalarActiveFaceFlagValues )
 
  149  , mUseScalarActiveFaceFlagValues( true )
 
  152QgsMeshVectorValueInterpolator::QgsMeshVectorValueInterpolator( 
const QgsMeshVectorValueInterpolator &other )
 
  153  : mTriangularMesh( other.mTriangularMesh )
 
  154  , mDatasetValues( other.mDatasetValues )
 
  155  , mActiveFaceFlagValues( other.mActiveFaceFlagValues )
 
  156  , mFaceCache( other.mFaceCache )
 
  157  , mCacheFaceIndex( other.mCacheFaceIndex )
 
  158  , mUseScalarActiveFaceFlagValues( other.mUseScalarActiveFaceFlagValues )
 
  161void QgsMeshVectorValueInterpolator::updateCacheFaceIndex( 
const QgsPointXY &point )
 const 
  163  if ( ! QgsMeshUtils::isInTriangleFace( point, mFaceCache, mTriangularMesh.vertices() ) )
 
  165    mCacheFaceIndex = mTriangularMesh.faceIndexForPoint_v2( point );
 
  169bool QgsMeshVectorValueInterpolator::isVectorValid( 
const QgsVector &v )
 const 
  171  return !( std::isnan( v.
x() ) || std::isnan( v.
y() ) );
 
  175void QgsMeshVectorValueInterpolator::activeFaceFilter( 
QgsVector &vector, 
int faceIndex )
 const 
  177  if ( mUseScalarActiveFaceFlagValues && ! mActiveFaceFlagValues.active( mTriangularMesh.trianglesToNativeFaces()[faceIndex] ) )
 
  178    vector = 
QgsVector( std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN() ) ;
 
  181QSize QgsMeshStreamField::size()
 const 
  186QPoint QgsMeshStreamField::topLeft()
 const 
  188  return mFieldTopLeftInDeviceCoordinates;
 
  191int QgsMeshStreamField::resolution()
 const 
  193  return mFieldResolution;
 
  196QgsPointXY QgsMeshStreamField::positionToMapCoordinates( 
const QPoint &pixelPosition, 
const QgsPointXY &positionInPixel )
 
  198  QgsPointXY mapPoint = mMapToFieldPixel.toMapCoordinates( pixelPosition );
 
  199  mapPoint = mapPoint + 
QgsVector( positionInPixel.
x() * mMapToFieldPixel.mapUnitsPerPixel(),
 
  200                                   positionInPixel.
y() * mMapToFieldPixel.mapUnitsPerPixel() );
 
  204QgsMeshStreamField::QgsMeshStreamField(
 
  209  double magnitudeMaximum,
 
  210  bool dataIsOnVertices,
 
  214  : mFieldResolution( resolution )
 
  215  , mVectorColoring( vectorColoring )
 
  216  , mRenderContext( rendererContext )
 
  217  , mLayerExtent( layerExtent )
 
  218  , mMaximumMagnitude( magnitudeMaximum )
 
  220  if ( dataIsOnVertices )
 
  222    if ( scalarActiveFaceFlagValues.
isValid() )
 
  223      mVectorValueInterpolator.reset( 
new QgsMeshVectorValueInterpolatorFromVertex(
 
  226                                        scalarActiveFaceFlagValues ) );
 
  228      mVectorValueInterpolator.reset( 
new QgsMeshVectorValueInterpolatorFromVertex(
 
  230                                        dataSetVectorValues ) );
 
  234    if ( scalarActiveFaceFlagValues.
isValid() )
 
  235      mVectorValueInterpolator.reset( 
new QgsMeshVectorValueInterpolatorFromFace(
 
  238                                        scalarActiveFaceFlagValues ) );
 
  240      mVectorValueInterpolator.reset( 
new QgsMeshVectorValueInterpolatorFromFace(
 
  242                                        dataSetVectorValues ) );
 
  246QgsMeshStreamField::QgsMeshStreamField( 
const QgsMeshStreamField &other )
 
  247  : mFieldSize( other.mFieldSize )
 
  248  , mFieldResolution( other.mFieldResolution )
 
  250  , mTraceImage( other.mTraceImage )
 
  251  , mMapToFieldPixel( other.mMapToFieldPixel )
 
  252  , mOutputExtent( other.mOutputExtent )
 
  253  , mVectorColoring( other.mVectorColoring )
 
  254  , mDirectionField( other.mDirectionField )
 
  255  , mRenderContext( other.mRenderContext )
 
  256  , mPixelFillingCount( other.mPixelFillingCount )
 
  257  , mMaxPixelFillingCount( other.mMaxPixelFillingCount )
 
  258  , mLayerExtent( other.mLayerExtent )
 
  259  , mMapExtent( other.mMapExtent )
 
  260  , mFieldTopLeftInDeviceCoordinates( other.mFieldTopLeftInDeviceCoordinates )
 
  261  , mValid( other.mValid )
 
  262  , mMaximumMagnitude( other.mMaximumMagnitude )
 
  263  , mPixelFillingDensity( other.mPixelFillingDensity )
 
  264  , mMinMagFilter( other.mMinMagFilter )
 
  265  , mMaxMagFilter( other.mMaxMagFilter )
 
  266  , mMinimizeFieldSize( other.mMinimizeFieldSize )
 
  268  mPainter.reset( 
new QPainter( &mTraceImage ) );
 
  269  mVectorValueInterpolator =
 
  270    std::unique_ptr<QgsMeshVectorValueInterpolator>( other.mVectorValueInterpolator->clone() );
 
  273QgsMeshStreamField::~QgsMeshStreamField()
 
  294    layerExtent = mMapExtent;
 
  298  if ( mMinimizeFieldSize )
 
  299    interestZoneExtent = layerExtent.
intersect( mMapExtent );
 
  301    interestZoneExtent = mMapExtent;
 
  306    mFieldSize = QSize();
 
  307    mFieldTopLeftInDeviceCoordinates = QPoint();
 
  312  QgsRectangle fieldInterestZoneInDeviceCoordinates = QgsMeshLayerUtils::boundingBoxToScreenRectangle( deviceMapToPixel, interestZoneExtent );
 
  313  mFieldTopLeftInDeviceCoordinates =
 
  314    QPoint( 
static_cast<int>( std::round( fieldInterestZoneInDeviceCoordinates.
xMinimum() ) ),
 
  315            static_cast<int>( std::round( fieldInterestZoneInDeviceCoordinates.
yMinimum() ) ) );
 
  316  int fieldWidthInDeviceCoordinate = int( fieldInterestZoneInDeviceCoordinates.
width() );
 
  317  int fieldHeightInDeviceCoordinate = int ( fieldInterestZoneInDeviceCoordinates.
height() );
 
  319  int fieldWidth = int( fieldWidthInDeviceCoordinate / mFieldResolution );
 
  320  int fieldHeight = int( fieldHeightInDeviceCoordinate / mFieldResolution );
 
  323  if ( fieldWidthInDeviceCoordinate % mFieldResolution > 0 )
 
  325  if ( fieldHeightInDeviceCoordinate % mFieldResolution > 0 )
 
  328  if ( fieldWidth == 0 || fieldHeight == 0 )
 
  330    mFieldSize = QSize();
 
  335    mFieldSize.setWidth( fieldWidth );
 
  336    mFieldSize.setHeight( fieldHeight );
 
  342    mOutputExtent = 
QgsRectangle( std::min( {pt1.
x(), pt2.
x(), pt3.
x(), pt4.
x()} ),
 
  343                                  std::min( {pt1.
y(), pt2.
y(), pt3.
y(), pt4.
y()} ),
 
  344                                  std::max( {pt1.
x(), pt2.
x(), pt3.
x(), pt4.
x()} ),
 
  345                                  std::max( {pt1.
y(), pt2.
y(), pt3.
y(), pt4.
y()} ),
 
  349  double mapUnitPerFieldPixel;
 
  350  if ( interestZoneExtent.
width() > 0 )
 
  351    mapUnitPerFieldPixel = deviceMapToPixel.
mapUnitsPerPixel() * mFieldResolution * mFieldSize.width() /
 
  352                           ( fieldWidthInDeviceCoordinate / 
static_cast<double>( mFieldResolution ) ) ;
 
  354    mapUnitPerFieldPixel = 1e-8;
 
  356  int fieldRightDevice = mFieldTopLeftInDeviceCoordinates.x() + mFieldSize.width() * mFieldResolution;
 
  357  int fieldBottomDevice = mFieldTopLeftInDeviceCoordinates.y() + mFieldSize.height() * mFieldResolution;
 
  360  int fieldTopDevice = mFieldTopLeftInDeviceCoordinates.
x();
 
  361  int fieldLeftDevice = mFieldTopLeftInDeviceCoordinates.y();
 
  364  double xc = ( fieldRightBottomMap.
x() + fieldTopLeftMap.
x() ) / 2;
 
  365  double yc = ( fieldTopLeftMap.
y() + fieldRightBottomMap.
y() ) / 2;
 
  379void QgsMeshStreamField::updateSize( 
const QgsRenderContext &renderContext, 
int resolution )
 
  381  if ( renderContext.
mapExtent() == mMapExtent && resolution == mFieldResolution )
 
  383  mFieldResolution = resolution;
 
  385  updateSize( renderContext );
 
  388bool QgsMeshStreamField::isValid()
 const 
  393void QgsMeshStreamField::addTrace( 
QgsPointXY startPoint )
 
  395  addTrace( mMapToFieldPixel.transform( startPoint ).toQPointF().toPoint() );
 
  399void QgsMeshStreamField::addRandomTraces()
 
  401  if ( mMaximumMagnitude > 0 )
 
  402    while ( ( mPixelFillingCount < mMaxPixelFillingCount ) &&
 
  403            ( !mRenderContext.feedback() ||
 
  404              !mRenderContext.feedback()->isCanceled() ||
 
  405              !mRenderContext.renderingStopped() ) )
 
  409void QgsMeshStreamField::addRandomTrace()
 
  414  int xRandom =  1 + std::rand() / int( ( RAND_MAX + 1u ) / uint( mFieldSize.width() ) )  ;
 
  415  int yRandom = 1 + std::rand() / int ( ( RAND_MAX + 1u ) / uint( mFieldSize.height() ) ) ;
 
  416  addTrace( QPoint( xRandom, yRandom ) );
 
  419void QgsMeshStreamField::addGriddedTraces( 
int dx, 
int dy )
 
  422  while ( i < mFieldSize.width() && mRenderContext.feedback() && !mRenderContext.feedback()->isCanceled() )
 
  425    while ( j < mFieldSize.height() && mRenderContext.feedback() && !mRenderContext.feedback()->isCanceled() )
 
  427      addTrace( QPoint( i, j ) );
 
  438  for ( 
auto f : std::as_const( facesInExtent ) )
 
  441    for ( 
auto i : std::as_const( face ) )
 
  442      vertices.insert( i );
 
  445  for ( 
auto i : std::as_const( vertices ) )
 
  447    addTrace( mesh.
vertices().at( i ) );
 
  451void QgsMeshStreamField::addTrace( QPoint startPixel )
 
  457  if ( isTraceExists( startPixel ) || isTraceOutside( startPixel ) )
 
  460  if ( !mVectorValueInterpolator )
 
  463  if ( !( mMaximumMagnitude > 0 ) )
 
  466  mPainter->setPen( mPen );
 
  472  std::list<QPair<QPoint, FieldData>> chunkTrace;
 
  474  QPoint currentPixel = startPixel;
 
  482    vector = mVectorValueInterpolator->vectorValue( mapPosition ) ;
 
  484    if ( std::isnan( vector.
x() ) || std::isnan( vector.
y() ) )
 
  486      mPixelFillingCount++;
 
  487      setChunkTrace( chunkTrace );
 
  495    QgsVector vu = vector / mMaximumMagnitude * 2;
 
  496    data.magnitude = vector.
length();
 
  500    double Vu = data.magnitude / mMaximumMagnitude * 2; 
 
  505      addPixelToChunkTrace( currentPixel, data, chunkTrace );
 
  506      simplifyChunkTrace( chunkTrace );
 
  507      setChunkTrace( chunkTrace );
 
  515    if ( nextPosition.
x() > 1 )
 
  517    if ( nextPosition.
x() < -1 )
 
  519    if ( nextPosition.
y() > 1 )
 
  521    if ( nextPosition.
y() < -1 )
 
  524    if ( incX != 0 || incY != 0 )
 
  526      data.directionX = incX;
 
  527      data.directionY = -incY;
 
  529      if ( chunkTrace.empty() )
 
  531        storeInField( QPair<QPoint, FieldData>( currentPixel, data ) );
 
  533      if ( addPixelToChunkTrace( currentPixel, data, chunkTrace ) )
 
  535        setChunkTrace( chunkTrace );
 
  536        clearChunkTrace( chunkTrace );
 
  540      currentPixel += QPoint( incX, -incY );
 
  541      x1 = nextPosition.
x() - 2 * incX;
 
  542      y1 = nextPosition.
y() - 2 * incY;
 
  573          x2 = x1 + ( 1 -  y1 ) * Vx / fabs( Vy ) ;
 
  575          x2 = x1 + ( 1 + y1 ) * Vx / fabs( Vy ) ;
 
  577          y2 = y1 + ( 1 - x1 ) * Vy / fabs( Vx ) ;
 
  579          y2 = y1 + ( 1 + x1 ) * Vy / fabs( Vx ) ;
 
  598      double dl = sqrt( dx * dx + dy * dy );
 
  600      data.time += 
static_cast<float>( dl / Vu ) ; 
 
  601      if ( data.time > 10000 ) 
 
  603        addPixelToChunkTrace( currentPixel, data, chunkTrace );
 
  604        setChunkTrace( chunkTrace );
 
  612    if ( isTraceExists( currentPixel ) )
 
  615      setChunkTrace( chunkTrace );
 
  616      addPixelToChunkTrace( currentPixel, data, chunkTrace );
 
  620    if ( isTraceOutside( currentPixel ) )
 
  622      setChunkTrace( chunkTrace );
 
  626    if ( mRenderContext.feedback() && mRenderContext.feedback()->isCanceled() )
 
  629    if ( mRenderContext.renderingStopped() )
 
  633  drawTrace( startPixel );
 
  636void QgsMeshStreamField::setResolution( 
int width )
 
  638  mFieldResolution = width;
 
  641QSize QgsMeshStreamField::imageSize()
 const 
  643  return mFieldSize * mFieldResolution;
 
  646QPointF QgsMeshStreamField::fieldToDevice( 
const QPoint &pixel )
 const 
  649  p = mFieldResolution * p + QPointF( mFieldResolution - 1, mFieldResolution - 1 ) / 2;
 
  653bool QgsMeshStreamField::addPixelToChunkTrace( QPoint &pixel,
 
  654    QgsMeshStreamField::FieldData &data,
 
  655    std::list<QPair<QPoint, QgsMeshStreamField::FieldData> > &chunkTrace )
 
  657  chunkTrace.emplace_back( pixel, data );
 
  658  if ( chunkTrace.size() == 3 )
 
  660    simplifyChunkTrace( chunkTrace );
 
  666void QgsMeshStreamlinesField::initField()
 
  668  mField = QVector<bool>( mFieldSize.width() * mFieldSize.height(), 
false );
 
  669  mDirectionField = QVector<unsigned char>( mFieldSize.width() * mFieldSize.height(), 
static_cast<unsigned char>( 
int( 0 ) ) );
 
  673void QgsMeshStreamlinesField::initImage()
 
  675  mTraceImage = QImage();
 
  676  switch ( mVectorColoring.coloringMethod() )
 
  680      QSize imgSize = mFieldSize * mFieldResolution;
 
  684      std::unique_ptr<QgsMeshLayerInterpolator> mScalarInterpolator(
 
  685        new QgsMeshLayerInterpolator(
 
  688          mScalarActiveFaceFlagValues,
 
  696      if ( imgSize.isValid() )
 
  698        std::unique_ptr<QgsRasterBlock> bl( renderer.block( 0, mOutputExtent, imgSize.width(), imgSize.height(), mFeedBack ) );
 
  699        mTraceImage = bl->image();
 
  705      mTraceImage = QImage( mFieldSize * mFieldResolution, QImage::Format_ARGB32_Premultiplied );
 
  706      QColor col = mVectorColoring.singleColor();
 
  707      mTraceImage.fill( col );
 
  712  if ( !mTraceImage.isNull() )
 
  714    mPainter.reset( 
new QPainter( &mTraceImage ) );
 
  715    mPainter->setRenderHint( QPainter::Antialiasing, 
true );
 
  717    mDrawingTraceImage = QImage( mTraceImage.size(), QImage::Format_ARGB32_Premultiplied );
 
  718    mDrawingTraceImage.fill( Qt::transparent );
 
  719    mDrawingTracePainter.reset( 
new QPainter( &mDrawingTraceImage ) );
 
  720    mDrawingTracePainter->setRenderHint( QPainter::Antialiasing, 
true );
 
  724void QgsMeshStreamField::clearChunkTrace( std::list<QPair<QPoint, QgsMeshStreamField::FieldData> > &chunkTrace )
 
  726  auto one_before_end = std::prev( chunkTrace.end() );
 
  727  chunkTrace.erase( chunkTrace.begin(), one_before_end );
 
  730void QgsMeshStreamField::simplifyChunkTrace( std::list<QPair<QPoint, FieldData> > &chunkTrace )
 
  732  if ( chunkTrace.size() != 3 )
 
  735  auto ip3 = chunkTrace.begin();
 
  739  while ( ip3 != chunkTrace.end() && ip2 != chunkTrace.end() )
 
  741    QPoint v1 = ( *ip1 ).first - ( *ip2 ).first;
 
  742    QPoint v2 = ( *ip2 ).first - ( *ip3 ).first;
 
  743    if ( v1.x()*v2.x() + v1.y()*v2.y() == 0 )
 
  745      ( *ip1 ).second.time += ( ( *ip2 ).second.time ) / 2;
 
  746      ( *ip3 ).second.time += ( ( *ip2 ).second.time ) / 2;
 
  747      ( *ip1 ).second.directionX += ( *ip2 ).second.directionX;
 
  748      ( *ip1 ).second.directionY += ( *ip2 ).second.directionY;
 
  749      chunkTrace.erase( ip2 );
 
  756QgsMeshStreamlinesField::QgsMeshStreamlinesField( 
const QgsTriangularMesh &triangularMesh,
 
  761    bool dataIsOnVertices,
 
  764  : QgsMeshStreamField(
 
  767      scalarActiveFaceFlagValues,
 
  773  , mMagValues( QgsMeshLayerUtils::calculateMagnitudes( datasetVectorValues ) )
 
  777QgsMeshStreamlinesField::QgsMeshStreamlinesField(
 
  781  const QVector<double> &datasetMagValues,
 
  783  QgsMeshLayerRendererFeedback *feedBack,
 
  785  bool dataIsOnVertices,
 
  788  : QgsMeshStreamField(
 
  791      scalarActiveFaceFlagValues,
 
  797  , mTriangularMesh( triangularMesh )
 
  798  , mMagValues( datasetMagValues )
 
  799  , mScalarActiveFaceFlagValues( scalarActiveFaceFlagValues )
 
  801  , mFeedBack( feedBack )
 
  805void QgsMeshStreamlinesField::compose()
 
  809  mPainter->setCompositionMode( QPainter::CompositionMode_DestinationIn );
 
  810  mPainter->drawImage( 0, 0, mDrawingTraceImage );
 
  813void QgsMeshStreamlinesField::storeInField( 
const QPair<QPoint, FieldData> pixelData )
 
  815  int i = pixelData.first.x();
 
  816  int j = pixelData.first.y();
 
  817  if ( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() )
 
  819    mField[j * mFieldSize.width() + i] = 
true;
 
  820    int d = pixelData.second.directionX + 2 + ( pixelData.second.directionY + 1 ) * 3;
 
  821    mDirectionField[j * mFieldSize.width() + i] = 
static_cast<unsigned char>( d );
 
  825void QgsMeshStreamField::setChunkTrace( std::list<QPair<QPoint, FieldData> > &chunkTrace )
 
  827  auto p = chunkTrace.begin();
 
  828  while ( p != chunkTrace.end() )
 
  830    storeInField( ( *p ) );
 
  831    mPixelFillingCount++;
 
  836void QgsMeshStreamlinesField::drawTrace( 
const QPoint &start )
 const 
  838  if ( !isTraceExists( start ) || isTraceOutside( start ) )
 
  841  if ( !mDrawingTracePainter )
 
  846  int fieldWidth = mFieldSize.width();
 
  847  QSet<QgsPointXY> path;
 
  848  unsigned char dir = 0;
 
  849  unsigned char prevDir = mDirectionField.at( pt1.y() * fieldWidth  + pt1.x() );
 
  851  QVector<double> xPoly;
 
  852  QVector<double> yPoly;
 
  853  QPointF devicePt = fieldToDevice( pt1 );
 
  854  xPoly.append( devicePt.x() );
 
  855  yPoly.append( devicePt.y() );
 
  857  while ( isTraceExists( curPt ) && !isTraceOutside( curPt ) && !path.contains( curPt ) )
 
  859    dir = mDirectionField.at( curPt.y() * fieldWidth  + curPt.x() );
 
  863    const QPoint curPtDir( ( dir - 1 ) % 3 - 1, ( dir - 1 ) / 3 - 1 );
 
  864    const QPoint pt2 = curPt + curPtDir;
 
  866    if ( dir != prevDir )
 
  868      path.insert( curPt );
 
  869      devicePt = fieldToDevice( curPt );
 
  870      xPoly.append( devicePt.x() );
 
  871      yPoly.append( devicePt.y() );
 
  877  if ( ! isTraceExists( curPt ) || isTraceOutside( curPt ) )
 
  880    devicePt = fieldToDevice( curPt - QPoint( ( dir - 1 ) % 3 - 1, ( dir - 1 ) / 3 - 1 ) );
 
  881    xPoly.append( devicePt.x() );
 
  882    yPoly.append( devicePt.y() );
 
  886  geom = geom.simplify( 1.5 * mFieldResolution ).smooth( 1, 0.25, -1.0, 45 );
 
  888  pen.setColor( QColor( 0, 0, 0, 255 ) );
 
  889  mDrawingTracePainter->setPen( pen );
 
  890  mDrawingTracePainter->drawPolyline( geom.asQPolygonF() );
 
  893bool QgsMeshStreamlinesField::isTraceExists( 
const QPoint &pixel )
 const 
  897  if ( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() )
 
  899    return mField[j * mFieldSize.width() + i];
 
  905bool QgsMeshStreamField::isTraceOutside( 
const QPoint &pixel )
 const 
  910  return !( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() );
 
  913void QgsMeshStreamField::setMinimizeFieldSize( 
bool minimizeFieldSize )
 
  915  mMinimizeFieldSize = minimizeFieldSize;
 
  918QgsMeshStreamField &QgsMeshStreamField::operator=( 
const QgsMeshStreamField &other )
 
  920  mFieldSize = other.mFieldSize ;
 
  921  mFieldResolution = other.mFieldResolution;
 
  923  mTraceImage = other.mTraceImage ;
 
  924  mMapToFieldPixel = other.mMapToFieldPixel ;
 
  925  mOutputExtent = other.mOutputExtent;
 
  926  mVectorColoring = other.mVectorColoring;
 
  927  mDirectionField = other.mDirectionField;
 
  928  mRenderContext = other.mRenderContext;
 
  929  mPixelFillingCount = other.mPixelFillingCount ;
 
  930  mMaxPixelFillingCount = other.mMaxPixelFillingCount ;
 
  931  mLayerExtent = other.mLayerExtent ;
 
  932  mMapExtent = other.mMapExtent;
 
  933  mFieldTopLeftInDeviceCoordinates = other.mFieldTopLeftInDeviceCoordinates ;
 
  934  mValid = other.mValid ;
 
  935  mMaximumMagnitude = other.mMaximumMagnitude ;
 
  936  mPixelFillingDensity = other.mPixelFillingDensity ;
 
  937  mMinMagFilter = other.mMinMagFilter ;
 
  938  mMaxMagFilter = other.mMaxMagFilter ;
 
  939  mMinimizeFieldSize = other.mMinimizeFieldSize ;
 
  940  mVectorValueInterpolator =
 
  941    std::unique_ptr<QgsMeshVectorValueInterpolator>( other.mVectorValueInterpolator->clone() );
 
  943  mPainter.reset( 
new QPainter( &mTraceImage ) );
 
  948void QgsMeshStreamField::initImage()
 
  950  mTraceImage = QImage( mFieldSize * mFieldResolution, QImage::Format_ARGB32 );
 
  951  if ( !mTraceImage.isNull() )
 
  953    mTraceImage.fill( 0X00000000 );
 
  954    mPainter.reset( 
new QPainter( &mTraceImage ) );
 
  955    mPainter->setRenderHint( QPainter::Antialiasing, 
true );
 
  956    mPainter->setPen( mPen );
 
  960bool QgsMeshStreamField::filterMag( 
double value )
 const 
  962  return ( mMinMagFilter < 0 || value > mMinMagFilter ) && ( mMaxMagFilter < 0 || value < mMaxMagFilter );
 
  965QImage QgsMeshStreamField::image()
 const 
  967  if ( mTraceImage.isNull() )
 
  969  return mTraceImage.scaled( mFieldSize * mFieldResolution, Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
 
  972void QgsMeshStreamField::setPixelFillingDensity( 
double maxFilling )
 
  974  mPixelFillingDensity = maxFilling;
 
  975  mMaxPixelFillingCount = int( mPixelFillingDensity * mFieldSize.width() * mFieldSize.height() );
 
  978void QgsMeshStreamField::setColor( QColor color )
 
  980  mPen.setColor( color );
 
  983void QgsMeshStreamField::setLineWidth( 
double width )
 
  985  mPen.setWidthF( width );
 
  988void QgsMeshStreamField::setFilter( 
double min, 
double max )
 
  994QgsMeshVectorValueInterpolatorFromFace::QgsMeshVectorValueInterpolatorFromFace( 
const QgsTriangularMesh &triangularMesh, 
const QgsMeshDataBlock &datasetVectorValues ):
 
  995  QgsMeshVectorValueInterpolator( triangularMesh, datasetVectorValues )
 
  999  QgsMeshVectorValueInterpolator( triangularMesh, datasetVectorValues, scalarActiveFaceFlagValues )
 
 1002QgsMeshVectorValueInterpolatorFromFace::QgsMeshVectorValueInterpolatorFromFace( 
const QgsMeshVectorValueInterpolatorFromFace &other ):
 
 1003  QgsMeshVectorValueInterpolator( other )
 
 1006QgsMeshVectorValueInterpolatorFromFace *QgsMeshVectorValueInterpolatorFromFace::clone()
 
 1008  return new QgsMeshVectorValueInterpolatorFromFace( *
this );
 
 1011QgsMeshVectorValueInterpolatorFromFace &QgsMeshVectorValueInterpolatorFromFace::operator=( 
const QgsMeshVectorValueInterpolatorFromFace &other )
 
 1013  QgsMeshVectorValueInterpolator::operator=( other );
 
 1017QgsVector QgsMeshVectorValueInterpolatorFromFace::interpolatedValuePrivate( 
int faceIndex, 
const QgsPointXY point )
 const 
 1019  QgsMeshFace face = mTriangularMesh.triangles().at( faceIndex );
 
 1025  QgsVector vect = 
QgsVector( mDatasetValues.value( mTriangularMesh.trianglesToNativeFaces().at( faceIndex ) ).x(),
 
 1026                              mDatasetValues.value( mTriangularMesh.trianglesToNativeFaces().at( faceIndex ) ).y() );
 
 1028  return QgsMeshLayerUtils::interpolateVectorFromFacesData(
 
 1036QgsMeshVectorStreamlineRenderer::QgsMeshVectorStreamlineRenderer(
 
 1040  bool dataIsOnVertices,
 
 1044  QgsMeshVectorStreamlineRenderer(
 
 1046    dataSetVectorValues,
 
 1047    scalarActiveFaceFlagValues,
 
 1048    QgsMeshLayerUtils::calculateMagnitudes( dataSetVectorValues ),
 
 1050    settings, rendererContext,
 
 1056QgsMeshVectorStreamlineRenderer::QgsMeshVectorStreamlineRenderer( 
const QgsTriangularMesh &triangularMesh,
 
 1059    const QVector<double> &datasetMagValues,
 
 1060    bool dataIsOnVertices,
 
 1063    const QgsRectangle &layerExtent, QgsMeshLayerRendererFeedback *feedBack,
 
 1065  mRendererContext( rendererContext )
 
 1067  mStreamlineField.reset(
 
 1068    new QgsMeshStreamlinesField(
 
 1070      dataSetVectorValues,
 
 1071      scalarActiveFaceFlagValues,
 
 1080  mStreamlineField->updateSize( rendererContext );
 
 1084  mStreamlineField->setColor( settings.
color() );
 
 1094        mStreamlineField->addTracesOnMesh( triangularMesh, rendererContext.
mapExtent() );
 
 1097      mStreamlineField->addRandomTraces();
 
 1102void QgsMeshVectorStreamlineRenderer::draw()
 
 1104  if ( mRendererContext.renderingStopped() )
 
 1106  mStreamlineField->compose();
 
 1107  mRendererContext.painter()->drawImage( mStreamlineField->topLeft(), mStreamlineField->image() );
 
 1110QgsMeshParticleTracesField::QgsMeshParticleTracesField( 
const QgsTriangularMesh &triangularMesh,
 
 1115    bool dataIsOnVertices,
 
 1118  QgsMeshStreamField( triangularMesh,
 
 1119                      datasetVectorValues,
 
 1120                      scalarActiveFaceFlagValues,
 
 1127  std::srand( uint( ::time( 
nullptr ) ) );
 
 1128  mPen.setCapStyle( Qt::RoundCap );
 
 1131QgsMeshParticleTracesField::QgsMeshParticleTracesField( 
const QgsMeshParticleTracesField &other )
 
 1132  : QgsMeshStreamField( other )
 
 1133  , mTimeField( other.mTimeField )
 
 1134  , mMagnitudeField( other.mMagnitudeField )
 
 1135  , mParticles( other.mParticles )
 
 1136  , mStumpImage( other.mStumpImage )
 
 1137  , mTimeStep( other.mTimeStep )
 
 1138  , mParticlesLifeTime( other.mParticlesLifeTime )
 
 1139  , mParticlesCount( other.mParticlesCount )
 
 1140  , mTailFactor( other.mTailFactor )
 
 1141  , mMinTailLength( other.mMinTailLength )
 
 1142  , mParticleColor( other.mParticleColor )
 
 1143  , mParticleSize( other.mParticleSize )
 
 1144  , mStumpFactor( other.mStumpFactor )
 
 1145  , mStumpParticleWithLifeTime( other.mStumpParticleWithLifeTime )
 
 1148void QgsMeshParticleTracesField::addParticle( 
const QPoint &startPoint, 
double lifeTime )
 
 1150  addTrace( startPoint );
 
 1151  if ( time( startPoint ) > 0 )
 
 1153    QgsMeshTraceParticle p;
 
 1154    p.lifeTime = lifeTime;
 
 1155    p.position = startPoint;
 
 1156    mParticles.append( p );
 
 1161void QgsMeshParticleTracesField::addParticleXY( 
const QgsPointXY &startPoint, 
double lifeTime )
 
 1163  addParticle( mMapToFieldPixel.transform( startPoint ).toQPointF().toPoint(), lifeTime );
 
 1166void QgsMeshParticleTracesField::moveParticles()
 
 1169  for ( 
auto &p : mParticles )
 
 1171    double spentTime = p.remainingTime; 
 
 1172    size_t countAdded = 0;
 
 1173    while ( spentTime < mTimeStep && p.lifeTime > 0 )
 
 1175      double timeToSpend = double( time( p.position ) );
 
 1176      if ( timeToSpend > 0 )
 
 1178        p.lifeTime -= timeToSpend;
 
 1179        spentTime += timeToSpend;
 
 1180        QPoint dir = direction( p.position );
 
 1181        if ( p.lifeTime > 0 )
 
 1184          p.tail.emplace_back( p.position );
 
 1199    if ( p.lifeTime <= 0 )
 
 1207      p.remainingTime = spentTime - mTimeStep;
 
 1208      while ( 
static_cast<int>( p.tail.size() )  >  mMinTailLength &&
 
 1209              static_cast<double>( p.tail.size() ) > ( 
static_cast<double>( countAdded ) * mTailFactor ) )
 
 1210        p.tail.erase( p.tail.begin() );
 
 1211      drawParticleTrace( p );
 
 1217  while ( i < mParticles.count() )
 
 1219    if ( mParticles.at( i ).tail.size() == 0 )
 
 1220      mParticles.removeAt( i );
 
 1226  if ( mParticles.count() < mParticlesCount )
 
 1227    addRandomParticles();
 
 1230void QgsMeshParticleTracesField::addRandomParticles()
 
 1235  if ( mParticlesCount < 0 ) 
 
 1237    addParticleXY( 
QgsPointXY( mMapToFieldPixel.xCenter(), mMapToFieldPixel.yCenter() ), mParticlesLifeTime );
 
 1241  int count = mParticlesCount - mParticles.count();
 
 1243  for ( 
int i = 0; i < count; ++i )
 
 1245    int xRandom =  1 + std::rand() / int( ( RAND_MAX + 1u ) / uint( mFieldSize.width() ) )  ;
 
 1246    int yRandom = 1 + std::rand() / int ( ( RAND_MAX + 1u ) / uint( mFieldSize.height() ) ) ;
 
 1247    double lifeTime = ( std::rand() / ( ( RAND_MAX + 1u ) / mParticlesLifeTime ) );
 
 1248    addParticle( QPoint( xRandom, yRandom ), lifeTime );
 
 1252void QgsMeshParticleTracesField::storeInField( 
const QPair<QPoint, QgsMeshStreamField::FieldData> pixelData )
 
 1254  int i = pixelData.first.x();
 
 1255  int j = pixelData.first.y();
 
 1256  if ( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() )
 
 1258    mTimeField[j * mFieldSize.width() + i] = pixelData.second.time;
 
 1259    int d = pixelData.second.directionX + 2 + ( pixelData.second.directionY + 1 ) * 3;
 
 1260    mDirectionField[j * mFieldSize.width() + i] = 
static_cast<unsigned char>( d );
 
 1261    mMagnitudeField[j * mFieldSize.width() + i] = 
static_cast<float>( pixelData.second.magnitude );
 
 1265void QgsMeshParticleTracesField::initField()
 
 1267  mTimeField = QVector<float>( mFieldSize.width() * mFieldSize.height(), -1 );
 
 1268  mDirectionField = QVector<unsigned char>( mFieldSize.width() * mFieldSize.height(), 
static_cast<unsigned char>( 
int( 0 ) ) );
 
 1269  mMagnitudeField = QVector<float>( mFieldSize.width() * mFieldSize.height(), 0 );
 
 1271  mStumpImage = QImage( mFieldSize * mFieldResolution, QImage::Format_ARGB32 );
 
 1272  mStumpImage.fill( QColor( 0, 0, 0, mStumpFactor ) ); 
 
 1275bool QgsMeshParticleTracesField::isTraceExists( 
const QPoint &pixel )
 const 
 1279  if ( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() )
 
 1281    return mTimeField[j * mFieldSize.width() + i] >= 0;
 
 1287void QgsMeshParticleTracesField::setStumpParticleWithLifeTime( 
bool stumpParticleWithLifeTime )
 
 1289  mStumpParticleWithLifeTime = stumpParticleWithLifeTime;
 
 1292void QgsMeshParticleTracesField::setParticlesColor( 
const QColor &
c )
 
 1294  mVectorColoring.setColor( 
c );
 
 1297QgsMeshParticleTracesField &QgsMeshParticleTracesField::operator=( 
const QgsMeshParticleTracesField &other )
 
 1299  QgsMeshStreamField::operator=( other );
 
 1300  mTimeField = other.mTimeField;
 
 1301  mMagnitudeField = other.mMagnitudeField;
 
 1302  mDirectionField = other.mDirectionField;
 
 1303  mParticles = other.mParticles;
 
 1304  mStumpImage = other.mStumpImage;
 
 1305  mTimeStep = other.mTimeStep;
 
 1306  mParticlesLifeTime = other.mParticlesLifeTime;
 
 1307  mParticlesCount = other.mParticlesCount;
 
 1308  mMinTailLength = other.mMinTailLength;
 
 1309  mTailFactor = other.mTailFactor;
 
 1310  mParticleColor = other.mParticleColor;
 
 1311  mParticleSize = other.mParticleSize;
 
 1312  mStumpFactor = other.mStumpFactor;
 
 1313  mStumpParticleWithLifeTime = other.mStumpParticleWithLifeTime;
 
 1318void QgsMeshParticleTracesField::setMinTailLength( 
int minTailLength )
 
 1320  mMinTailLength = minTailLength;
 
 1323void QgsMeshParticleTracesField::setTailFactor( 
double tailFactor )
 
 1325  mTailFactor = tailFactor;
 
 1328void QgsMeshParticleTracesField::setParticleSize( 
double particleSize )
 
 1330  mParticleSize = particleSize;
 
 1333void QgsMeshParticleTracesField::setTimeStep( 
double timeStep )
 
 1335  mTimeStep = timeStep;
 
 1338void QgsMeshParticleTracesField::setParticlesLifeTime( 
double particlesLifeTime )
 
 1340  mParticlesLifeTime = particlesLifeTime;
 
 1343QImage QgsMeshParticleTracesField::imageRendered()
 const 
 1348void QgsMeshParticleTracesField::stump()
 
 1353  mPainter->setCompositionMode( QPainter::CompositionMode_DestinationIn );
 
 1354  mPainter->drawImage( QPoint( 0, 0 ), mStumpImage );
 
 1357void QgsMeshParticleTracesField::setStumpFactor( 
int sf )
 
 1360  mStumpImage = QImage( mFieldSize * mFieldResolution, QImage::Format_ARGB32 );
 
 1361  mStumpImage.fill( QColor( 0, 0, 0, mStumpFactor ) );
 
 1364QPoint QgsMeshParticleTracesField::direction( QPoint position )
 const 
 1366  int i = position.x();
 
 1367  int j = position.y();
 
 1368  if ( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() )
 
 1370    int dir = 
static_cast<int>( mDirectionField[j * mFieldSize.width() + i] );
 
 1371    if ( dir != 0 && dir < 10 )
 
 1372      return QPoint( ( dir - 1 ) % 3 - 1, ( dir - 1 ) / 3 - 1 );
 
 1374  return QPoint( 0, 0 );
 
 1377float QgsMeshParticleTracesField::time( QPoint position )
 const 
 1379  int i = position.x();
 
 1380  int j = position.y();
 
 1381  if ( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() )
 
 1383    return mTimeField[j * mFieldSize.width() + i];
 
 1388float QgsMeshParticleTracesField::magnitude( QPoint position )
 const 
 1390  int i = position.x();
 
 1391  int j = position.y();
 
 1392  if ( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() )
 
 1394    return mMagnitudeField[j * mFieldSize.width() + i];
 
 1399void QgsMeshParticleTracesField::drawParticleTrace( 
const QgsMeshTraceParticle &particle )
 
 1403  const std::list<QPoint> &tail = particle.tail;
 
 1404  if ( tail.size() == 0 )
 
 1406  double iniWidth = mParticleSize;
 
 1408  size_t pixelCount = tail.size();
 
 1410  double transparency = 1;
 
 1411  if ( mStumpParticleWithLifeTime )
 
 1412    transparency = sin( M_PI * particle.lifeTime / mParticlesLifeTime );
 
 1415  if ( pixelCount > 1 )
 
 1416    dw = iniWidth   / 
static_cast<double>( pixelCount );
 
 1420  auto ip1 = std::prev( tail.end() );
 
 1421  auto ip2 = std::prev( ip1 );
 
 1423  while ( ip1 != tail.begin() )
 
 1425    QPointF p1 = fieldToDevice( ( *ip1 ) );
 
 1426    QPointF p2 = fieldToDevice( ( *ip2 ) );
 
 1427    QColor traceColor = mVectorColoring.color( magnitude( *ip1 ) );
 
 1428    traceColor.setAlphaF( traceColor.alphaF()*transparency );
 
 1429    mPen.setColor( traceColor );
 
 1430    mPen.setWidthF( iniWidth - i * dw );
 
 1431    mPainter->setPen( mPen );
 
 1432    mPainter->drawLine( p1, p2 );
 
 1439void QgsMeshParticleTracesField::setParticlesCount( 
int particlesCount )
 
 1441  mParticlesCount = particlesCount;
 
 1447    bool dataIsOnVertices,
 
 1452  : mParticleField( new QgsMeshParticleTracesField(
 
 1454                      dataSetVectorValues,
 
 1455                      scalarActiveFaceFlagValues,
 
 1460                      vectorSettings.vectorStrokeColoring() ) )
 
 1461  , mRendererContext( rendererContext )
 
 1463  mParticleField->updateSize( rendererContext ) ;
 
 1467  mRendererContext( rendererContext )
 
 1474  bool vectorDataOnVertices;
 
 1484  if ( ( cache->mDatasetGroupsCount == datasetGroupCount ) &&
 
 1485       ( cache->mActiveVectorDatasetIndex == datasetIndex ) )
 
 1487    vectorDatasetValues = cache->mVectorDatasetValues;
 
 1488    scalarActiveFaceFlagValues = cache->mScalarActiveFaceFlagValues;
 
 1489    magMax = cache->mVectorDatasetMagMaximum;
 
 1500    if ( vectorDataOnVertices )
 
 1505    vectorDatasetValues = QgsMeshLayerUtils::datasetValues( layer, datasetIndex, 0, count );
 
 1513  mParticleField = std::unique_ptr<QgsMeshParticleTracesField>( 
new QgsMeshParticleTracesField( ( *layer->
triangularMesh() ),
 
 1514                   vectorDatasetValues,
 
 1515                   scalarActiveFaceFlagValues,
 
 1518                   vectorDataOnVertices,
 
 1522  mParticleField->setMinimizeFieldSize( 
false );
 
 1523  mParticleField->updateSize( mRendererContext );
 
 1527  : mParticleField( new QgsMeshParticleTracesField( *other.mParticleField ) )
 
 1528  , mRendererContext( other.mRendererContext )
 
 1529  , mFPS( other.mFPS )
 
 1530  , mVpixMax( other.mVpixMax )
 
 1531  , mParticleLifeTime( other.mParticleLifeTime )
 
 1540  mParticleField->setParticlesCount( count );
 
 1541  mParticleField->addRandomParticles();
 
 1546  mParticleField->moveParticles();
 
 1547  return mParticleField->image();
 
 1557  updateFieldParameter();
 
 1563  updateFieldParameter();
 
 1568  mParticleLifeTime = particleLifeTime;
 
 1569  updateFieldParameter();
 
 1574  mParticleField->setParticlesColor( 
c );
 
 1579  mParticleField->setParticleSize( width );
 
 1584  mParticleField->setTailFactor( fct );
 
 1589  mParticleField->setMinTailLength( l );
 
 1598  mParticleField->setStumpFactor( 
int( 255 * p ) );
 
 1603  mParticleField.reset( 
new QgsMeshParticleTracesField( *( other.mParticleField ) ) );
 
 1604  const_cast<QgsRenderContext &
>( mRendererContext ) = other.mRendererContext;
 
 1606  mVpixMax = other.mVpixMax;
 
 1607  mParticleLifeTime = other.mParticleLifeTime;
 
 1612void QgsMeshVectorTraceAnimationGenerator::updateFieldParameter()
 
 1614  double fieldTimeStep = mVpixMax / 
static_cast<double>( mFPS );
 
 1615  double fieldLifeTime = mParticleLifeTime * mFPS * fieldTimeStep;
 
 1616  mParticleField->setTimeStep( fieldTimeStep );
 
 1617  mParticleField->setParticlesLifeTime( fieldLifeTime );
 
 1620QgsMeshVectorTraceRenderer::QgsMeshVectorTraceRenderer(
 
 1624  bool dataIsOnVertices,
 
 1629  :  mParticleField( new QgsMeshParticleTracesField(
 
 1631                       dataSetVectorValues,
 
 1632                       scalarActiveFaceFlagValues,
 
 1637                       settings.vectorStrokeColoring() ) )
 
 1638  , mRendererContext( rendererContext )
 
 1641  mParticleField->updateSize( rendererContext ) ;
 
 1646  mParticleField->setTailFactor( 1 );
 
 1647  mParticleField->setStumpParticleWithLifeTime( 
false );
 
 1650  mParticleField->addRandomParticles();
 
 1651  mParticleField->moveParticles();
 
 1654void QgsMeshVectorTraceRenderer::draw()
 
 1656  if ( mRendererContext.renderingStopped() )
 
 1658  mRendererContext.painter()->drawImage( mParticleField->topLeft(), mParticleField->image() );
 
@ Millimeters
Millimeters.
 
QgsVertexIterator vertices() const
Returns a read-only, Java-style iterator for traversal of vertices of all the geometry,...
 
A ramp shader will color a raster pixel based on a list of values ranges in a ramp.
 
Custom exception class for Coordinate Reference System related exceptions.
 
A geometry is the spatial representation of a feature.
 
Class defining color to render mesh datasets.
 
@ ColorRamp
Render with a color ramp.
 
@ SingleColor
Render with a single color.
 
Line string geometry type, with support for z-dimension and m-values.
 
Perform transforms between map coordinates and device coordinates.
 
double mapUnitsPerPixel() const
Returns the current map units per pixel.
 
QgsPointXY toMapCoordinates(int x, int y) const
Transforms device coordinates to map (world) coordinates.
 
double mapRotation() const
Returns the current map rotation in degrees (clockwise).
 
QgsMeshDataBlock is a block of integers/doubles that can be used to retrieve: active flags (e....
 
bool isValid() const
Whether the block is valid.
 
QgsMeshDatasetIndex is index that identifies the dataset group (e.g.
 
int group() const
Returns a group index.
 
virtual QgsMeshDatasetGroupMetadata datasetGroupMetadata(int groupIndex) const =0
Returns dataset group metadata.
 
virtual QgsMeshDataBlock areFacesActive(QgsMeshDatasetIndex index, int faceIndex, int count) const =0
Returns whether the faces are active for particular dataset.
 
virtual int datasetGroupCount() const =0
Returns number of datasets groups loaded.
 
Represents a mesh layer supporting display of data on structured or unstructured meshes.
 
QgsRectangle extent() const override
Returns the extent of the layer.
 
QgsMeshRendererSettings rendererSettings() const
Returns renderer settings.
 
QgsMeshDatasetIndex activeVectorDatasetAtTime(const QgsDateTimeRange &timeRange, int group=-1) const
Returns dataset index from active vector group depending on the time range If the temporal properties...
 
void reload() override
Synchronises with changes in the datasource.
 
QgsMesh * nativeMesh()
Returns native mesh (nullptr before rendering or calling to updateMesh)
 
QgsMeshDataProvider * dataProvider() override
Returns the layer's data provider, it may be nullptr.
 
QgsTriangularMesh * triangularMesh(double minimumTriangleSize=0) const
Returns triangular mesh (nullptr before rendering or calling to updateMesh).
 
QgsMeshLayerRendererCache * rendererCache()
Returns native mesh (nullptr before rendering)
 
QgsMeshRendererVectorSettings vectorSettings(int groupIndex) const
Returns renderer settings.
 
Represents a renderer settings for vector datasets.
 
int userGridCellWidth() const
Returns width in pixels of user grid cell.
 
QgsMeshRendererVectorTracesSettings tracesSettings() const
Returns settings for vector rendered with traces.
 
QColor color() const
Returns color used for drawing arrows.
 
int userGridCellHeight() const
Returns height in pixels of user grid cell.
 
double lineWidth() const
Returns line width of the arrow (in millimeters)
 
double filterMax() const
Returns filter value for vector magnitudes.
 
QgsInterpolatedLineColor vectorStrokeColoring() const
Returns the stroke coloring used to render vector datasets.
 
bool isOnUserDefinedGrid() const
Returns whether vectors are drawn on user-defined grid.
 
double filterMin() const
Returns filter value for vector magnitudes.
 
QgsMeshRendererVectorStreamlineSettings streamLinesSettings() const
Returns settings for vector rendered with streamlines.
 
SeedingStartPointsMethod seedingMethod() const
Returns the method used for seeding start points of strealines.
 
@ Random
Seeds start points randomly on the mesh.
 
@ MeshGridded
Seeds start points on the vertices mesh or user regular grid.
 
double seedingDensity() const
Returns the density used for seeding start points.
 
Qgis::RenderUnit maximumTailLengthUnit() const
Returns the maximum tail length unit.
 
double maximumTailLength() const
Returns the maximum tail length.
 
int particlesCount() const
Returns particles count.
 
A wrapper for QgsMeshParticuleTracesField used to render the particles.
 
void setParticlesLifeTime(double particleLifeTime)
Sets maximum life time of particles in seconds.
 
QgsMeshVectorTraceAnimationGenerator & operator=(const QgsMeshVectorTraceAnimationGenerator &other)
 
void setMinimumTailLength(int l)
Sets the minimum tail length.
 
void setTailPersitence(double p)
Sets the visual persistence of the tail.
 
void setParticlesColor(const QColor &c)
Sets colors of particle.
 
QImage imageRendered()
Moves all the particles using frame per second (fps) to calculate the displacement and return the ren...
 
void setTailFactor(double fct)
Sets the tail factor, used to adjust the length of the tail. 0 : minimum length, >1 increase the tail...
 
void setFPS(int FPS)
Sets the number of frames per seconds that will be rendered.
 
QgsMeshVectorTraceAnimationGenerator(const QgsTriangularMesh &triangularMesh, const QgsMeshDataBlock &dataSetVectorValues, const QgsMeshDataBlock &scalarActiveFaceFlagValues, bool dataIsOnVertices, const QgsRenderContext &rendererContext, const QgsRectangle &layerExtent, double magMax, const QgsMeshRendererVectorSettings &vectorSettings)
Constructor to use from QgsMeshVectorRenderer.
 
void setParticlesSize(double width)
Sets particle size in px.
 
void setMaxSpeedPixel(int max)
Sets the max number of pixels that can be go through by the particles in 1 second.
 
void seedRandomParticles(int count)
seeds particles in the vector fields
 
A class to represent a 2D point.
 
Point geometry type, with support for z-dimension and m-values.
 
Interface for all raster shaders.
 
void setRasterShaderFunction(QgsRasterShaderFunction *function)
A public method that allows the user to set their own shader function.
 
A rectangle specified with double values.
 
QgsRectangle intersect(const QgsRectangle &rect) const
Returns the intersection with the given rectangle.
 
Contains information about the context of a rendering operation.
 
double convertToPainterUnits(double size, Qgis::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
 
QgsRectangle mapExtent() const
Returns the original extent of the map being rendered.
 
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
 
void setMapToPixel(const QgsMapToPixel &mtp)
Sets the context's map to pixel transform, which transforms between map coordinates and device coordi...
 
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
 
Scoped object for saving and restoring a QPainter object's state.
 
Raster renderer pipe for single band pseudocolor.
 
const QgsDateTimeRange & temporalRange() const
Returns the datetime range for the object.
 
Triangular/Derived Mesh is mesh with vertices in map coordinates.
 
const QVector< QgsMeshFace > & triangles() const
Returns triangles.
 
const QVector< QgsMeshVertex > & vertices() const
Returns vertices in map coordinate system.
 
QList< int > faceIndexesForRectangle(const QgsRectangle &rectangle) const
Finds indexes of triangles intersecting given bounding box It uses spatial indexing.
 
A class to represent a vector.
 
double y() const
Returns the vector's y-component.
 
QgsVector rotateBy(double rot) const
Rotates the vector by a specified angle.
 
double x() const
Returns the vector's x-component.
 
double length() const
Returns the length of the vector.
 
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
 
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
 
QVector< int > QgsMeshFace
List of vertex indexes.
 
QVector< QgsMeshVertex > vertices
 
QVector< QgsMeshFace > faces