35#define M_DEG2RAD 0.0174532925
41 if ( mCacheFaceIndex != -1 && mCacheFaceIndex < mTriangularMesh.triangles().count() )
43 QgsVector res = interpolatedValuePrivate( mCacheFaceIndex, point );
44 if ( isVectorValid( res ) )
46 activeFaceFilter( res, mCacheFaceIndex );
52 QList<int> potentialFaceIndexes = mTriangularMesh.faceIndexesForRectangle(
QgsRectangle( point, point ) );
54 for (
const int faceIndex : potentialFaceIndexes )
56 QgsVector res = interpolatedValuePrivate( faceIndex, point );
57 if ( isVectorValid( res ) )
59 mCacheFaceIndex = faceIndex;
60 activeFaceFilter( res, mCacheFaceIndex );
66 return (
QgsVector( std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN() ) );
69QgsMeshVectorValueInterpolator &QgsMeshVectorValueInterpolator::operator=(
const QgsMeshVectorValueInterpolator &other )
74 mTriangularMesh = other.mTriangularMesh;
75 mDatasetValues = other.mDatasetValues;
76 mActiveFaceFlagValues = other.mActiveFaceFlagValues;
77 mFaceCache = other.mFaceCache;
78 mCacheFaceIndex = other.mCacheFaceIndex;
79 mUseScalarActiveFaceFlagValues = other.mUseScalarActiveFaceFlagValues;
84QgsMeshVectorValueInterpolatorFromVertex::QgsMeshVectorValueInterpolatorFromVertex(
const QgsTriangularMesh &triangularMesh,
const QgsMeshDataBlock &datasetVectorValues )
85 : QgsMeshVectorValueInterpolator( triangularMesh, datasetVectorValues )
88QgsMeshVectorValueInterpolatorFromVertex::QgsMeshVectorValueInterpolatorFromVertex(
91 : QgsMeshVectorValueInterpolator( triangularMesh, datasetVectorValues, scalarActiveFaceFlagValues )
94QgsMeshVectorValueInterpolatorFromVertex::QgsMeshVectorValueInterpolatorFromVertex(
const QgsMeshVectorValueInterpolatorFromVertex &other )
95 : QgsMeshVectorValueInterpolator( other )
98QgsMeshVectorValueInterpolatorFromVertex *QgsMeshVectorValueInterpolatorFromVertex::clone()
100 return new QgsMeshVectorValueInterpolatorFromVertex( *
this );
103QgsMeshVectorValueInterpolatorFromVertex &QgsMeshVectorValueInterpolatorFromVertex::operator=(
const QgsMeshVectorValueInterpolatorFromVertex &other )
105 QgsMeshVectorValueInterpolator::operator=( other );
109QgsVector QgsMeshVectorValueInterpolatorFromVertex::interpolatedValuePrivate(
int faceIndex,
const QgsPointXY point )
const
111 QgsMeshFace face = mTriangularMesh.triangles().at( faceIndex );
117 QgsVector v1 =
QgsVector( mDatasetValues.value( face.at( 0 ) ).x(), mDatasetValues.value( face.at( 0 ) ).y() );
119 QgsVector v2 =
QgsVector( mDatasetValues.value( face.at( 1 ) ).x(), mDatasetValues.value( face.at( 1 ) ).y() );
121 QgsVector v3 =
QgsVector( mDatasetValues.value( face.at( 2 ) ).x(), mDatasetValues.value( face.at( 2 ) ).y() );
123 return QgsMeshLayerUtils::interpolateVectorFromVerticesData( p1, p2, p3, v1, v2, v3, point );
127 : mTriangularMesh( triangularMesh )
128 , mDatasetValues( datasetVectorValues )
132 : mTriangularMesh( triangularMesh )
133 , mDatasetValues( datasetVectorValues )
134 , mActiveFaceFlagValues( scalarActiveFaceFlagValues )
135 , mUseScalarActiveFaceFlagValues( true )
138QgsMeshVectorValueInterpolator::QgsMeshVectorValueInterpolator(
const QgsMeshVectorValueInterpolator &other )
139 : mTriangularMesh( other.mTriangularMesh )
140 , mDatasetValues( other.mDatasetValues )
141 , mActiveFaceFlagValues( other.mActiveFaceFlagValues )
142 , mFaceCache( other.mFaceCache )
143 , mCacheFaceIndex( other.mCacheFaceIndex )
144 , mUseScalarActiveFaceFlagValues( other.mUseScalarActiveFaceFlagValues )
147void QgsMeshVectorValueInterpolator::updateCacheFaceIndex(
const QgsPointXY &point )
const
151 mCacheFaceIndex = mTriangularMesh.faceIndexForPoint_v2( point );
155bool QgsMeshVectorValueInterpolator::isVectorValid(
const QgsVector &v )
const
157 return !( std::isnan( v.
x() ) || std::isnan( v.
y() ) );
160void QgsMeshVectorValueInterpolator::activeFaceFilter(
QgsVector &vector,
int faceIndex )
const
162 if ( mUseScalarActiveFaceFlagValues && !mActiveFaceFlagValues.active( mTriangularMesh.trianglesToNativeFaces()[faceIndex] ) )
163 vector =
QgsVector( std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN() );
166QSize QgsMeshStreamField::size()
const
171QPoint QgsMeshStreamField::topLeft()
const
173 return mFieldTopLeftInDeviceCoordinates;
176int QgsMeshStreamField::resolution()
const
178 return mFieldResolution;
181QgsPointXY QgsMeshStreamField::positionToMapCoordinates(
const QPoint &pixelPosition,
const QgsPointXY &positionInPixel )
183 QgsPointXY mapPoint = mMapToFieldPixel.toMapCoordinates( pixelPosition );
184 mapPoint = mapPoint +
QgsVector( positionInPixel.
x() * mMapToFieldPixel.mapUnitsPerPixel(), positionInPixel.
y() * mMapToFieldPixel.mapUnitsPerPixel() );
188QgsMeshStreamField::QgsMeshStreamField(
193 double magnitudeMaximum,
194 bool dataIsOnVertices,
199 : mFieldResolution( resolution )
200 , mVectorColoring( vectorColoring )
201 , mRenderContext( rendererContext )
202 , mLayerExtent( layerExtent )
203 , mMaximumMagnitude( magnitudeMaximum )
205 if ( dataIsOnVertices )
207 if ( scalarActiveFaceFlagValues.
isValid() )
208 mVectorValueInterpolator = std::make_unique<QgsMeshVectorValueInterpolatorFromVertex>( triangularMesh, dataSetVectorValues, scalarActiveFaceFlagValues );
210 mVectorValueInterpolator = std::make_unique<QgsMeshVectorValueInterpolatorFromVertex>( triangularMesh, dataSetVectorValues );
214 if ( scalarActiveFaceFlagValues.
isValid() )
215 mVectorValueInterpolator = std::make_unique<QgsMeshVectorValueInterpolatorFromFace>( triangularMesh, dataSetVectorValues, scalarActiveFaceFlagValues );
217 mVectorValueInterpolator = std::make_unique<QgsMeshVectorValueInterpolatorFromFace>( triangularMesh, dataSetVectorValues );
221QgsMeshStreamField::QgsMeshStreamField(
const QgsMeshStreamField &other )
222 : mFieldSize( other.mFieldSize )
223 , mFieldResolution( other.mFieldResolution )
225 , mTraceImage( other.mTraceImage )
226 , mMapToFieldPixel( other.mMapToFieldPixel )
227 , mOutputExtent( other.mOutputExtent )
228 , mVectorColoring( other.mVectorColoring )
229 , mDirectionField( other.mDirectionField )
230 , mRenderContext( other.mRenderContext )
231 , mPixelFillingCount( other.mPixelFillingCount )
232 , mMaxPixelFillingCount( other.mMaxPixelFillingCount )
233 , mLayerExtent( other.mLayerExtent )
234 , mMapExtent( other.mMapExtent )
235 , mFieldTopLeftInDeviceCoordinates( other.mFieldTopLeftInDeviceCoordinates )
236 , mValid( other.mValid )
237 , mMaximumMagnitude( other.mMaximumMagnitude )
238 , mPixelFillingDensity( other.mPixelFillingDensity )
239 , mMinMagFilter( other.mMinMagFilter )
240 , mMaxMagFilter( other.mMaxMagFilter )
241 , mMinimizeFieldSize( other.mMinimizeFieldSize )
243 mPainter = std::make_unique<QPainter>( &mTraceImage );
244 mVectorValueInterpolator = std::unique_ptr<QgsMeshVectorValueInterpolator>( other.mVectorValueInterpolator->clone() );
247QgsMeshStreamField::~QgsMeshStreamField()
268 layerExtent = mMapExtent;
272 if ( mMinimizeFieldSize )
273 interestZoneExtent = layerExtent.
intersect( mMapExtent );
275 interestZoneExtent = mMapExtent;
280 mFieldSize = QSize();
281 mFieldTopLeftInDeviceCoordinates = QPoint();
286 QgsRectangle fieldInterestZoneInDeviceCoordinates = QgsMeshLayerUtils::boundingBoxToScreenRectangle( deviceMapToPixel, interestZoneExtent );
287 mFieldTopLeftInDeviceCoordinates
288 = QPoint(
static_cast<int>( std::round( fieldInterestZoneInDeviceCoordinates.
xMinimum() ) ),
static_cast<int>( std::round( fieldInterestZoneInDeviceCoordinates.
yMinimum() ) ) );
289 int fieldWidthInDeviceCoordinate = int( fieldInterestZoneInDeviceCoordinates.
width() );
290 int fieldHeightInDeviceCoordinate = int( fieldInterestZoneInDeviceCoordinates.
height() );
292 int fieldWidth = int( fieldWidthInDeviceCoordinate / mFieldResolution );
293 int fieldHeight = int( fieldHeightInDeviceCoordinate / mFieldResolution );
296 if ( fieldWidthInDeviceCoordinate % mFieldResolution > 0 )
298 if ( fieldHeightInDeviceCoordinate % mFieldResolution > 0 )
301 if ( fieldWidth == 0 || fieldHeight == 0 )
303 mFieldSize = QSize();
308 mFieldSize.setWidth( fieldWidth );
309 mFieldSize.setHeight( fieldHeight );
316 std::min( { pt1.
x(), pt2.
x(), pt3.
x(), pt4.
x() } ),
317 std::min( { pt1.
y(), pt2.
y(), pt3.
y(), pt4.
y() } ),
318 std::max( { pt1.
x(), pt2.
x(), pt3.
x(), pt4.
x() } ),
319 std::max( { pt1.
y(), pt2.
y(), pt3.
y(), pt4.
y() } ),
324 double mapUnitPerFieldPixel;
325 if ( interestZoneExtent.
width() > 0 )
326 mapUnitPerFieldPixel = deviceMapToPixel.
mapUnitsPerPixel() * mFieldResolution * mFieldSize.width() / ( fieldWidthInDeviceCoordinate /
static_cast<double>( mFieldResolution ) );
328 mapUnitPerFieldPixel = 1e-8;
330 int fieldRightDevice = mFieldTopLeftInDeviceCoordinates.x() + mFieldSize.width() * mFieldResolution;
331 int fieldBottomDevice = mFieldTopLeftInDeviceCoordinates.y() + mFieldSize.height() * mFieldResolution;
334 int fieldTopDevice = mFieldTopLeftInDeviceCoordinates.
x();
335 int fieldLeftDevice = mFieldTopLeftInDeviceCoordinates.y();
338 double xc = ( fieldRightBottomMap.
x() + fieldTopLeftMap.
x() ) / 2;
339 double yc = ( fieldTopLeftMap.
y() + fieldRightBottomMap.
y() ) / 2;
341 mMapToFieldPixel =
QgsMapToPixel( mapUnitPerFieldPixel, xc, yc, fieldWidth, fieldHeight, deviceMapToPixel.
mapRotation() );
347void QgsMeshStreamField::updateSize(
const QgsRenderContext &renderContext,
int resolution )
349 if ( renderContext.
mapExtent() == mMapExtent && resolution == mFieldResolution )
351 mFieldResolution = resolution;
353 updateSize( renderContext );
356bool QgsMeshStreamField::isValid()
const
361void QgsMeshStreamField::addTrace(
QgsPointXY startPoint )
363 addTrace( mMapToFieldPixel.transform( startPoint ).toQPointF().toPoint() );
367void QgsMeshStreamField::addRandomTraces()
369 if ( mMaximumMagnitude > 0 )
370 while ( ( mPixelFillingCount < mMaxPixelFillingCount ) && ( !mRenderContext.feedback() || !mRenderContext.feedback()->isCanceled() || !mRenderContext.renderingStopped() ) )
374void QgsMeshStreamField::addRandomTrace()
379 int xRandom = 1 + std::rand() / int( ( RAND_MAX + 1u ) / uint( mFieldSize.width() ) );
380 int yRandom = 1 + std::rand() / int( ( RAND_MAX + 1u ) / uint( mFieldSize.height() ) );
381 addTrace( QPoint( xRandom, yRandom ) );
384void QgsMeshStreamField::addGriddedTraces(
int dx,
int dy )
387 while ( i < mFieldSize.width() && mRenderContext.feedback() && !mRenderContext.feedback()->isCanceled() )
390 while ( j < mFieldSize.height() && mRenderContext.feedback() && !mRenderContext.feedback()->isCanceled() )
392 addTrace( QPoint( i, j ) );
403 for (
auto f : std::as_const( facesInExtent ) )
406 for (
auto i : std::as_const( face ) )
407 vertices.insert( i );
410 for (
auto i : std::as_const( vertices ) )
412 addTrace( mesh.
vertices().at( i ) );
416void QgsMeshStreamField::addTrace( QPoint startPixel )
422 if ( isTraceExists( startPixel ) || isTraceOutside( startPixel ) )
425 if ( !mVectorValueInterpolator )
428 if ( !( mMaximumMagnitude > 0 ) )
431 mPainter->setPen( mPen );
437 std::list<QPair<QPoint, FieldData>> chunkTrace;
439 QPoint currentPixel = startPixel;
447 vector = mVectorValueInterpolator->vectorValue( mapPosition );
449 if ( std::isnan( vector.
x() ) || std::isnan( vector.
y() ) )
451 mPixelFillingCount++;
452 setChunkTrace( chunkTrace );
460 QgsVector vu = vector / mMaximumMagnitude * 2;
461 data.magnitude = vector.
length();
465 double Vu = data.magnitude / mMaximumMagnitude * 2;
470 addPixelToChunkTrace( currentPixel, data, chunkTrace );
471 simplifyChunkTrace( chunkTrace );
472 setChunkTrace( chunkTrace );
480 if ( nextPosition.
x() > 1 )
482 if ( nextPosition.
x() < -1 )
484 if ( nextPosition.
y() > 1 )
486 if ( nextPosition.
y() < -1 )
489 if ( incX != 0 || incY != 0 )
491 data.directionX = incX;
492 data.directionY = -incY;
494 if ( chunkTrace.empty() )
496 storeInField( QPair<QPoint, FieldData>( currentPixel, data ) );
498 if ( addPixelToChunkTrace( currentPixel, data, chunkTrace ) )
500 setChunkTrace( chunkTrace );
501 clearChunkTrace( chunkTrace );
505 currentPixel += QPoint( incX, -incY );
506 x1 = nextPosition.
x() - 2 * incX;
507 y1 = nextPosition.
y() - 2 * incY;
538 x2 = x1 + ( 1 - y1 ) * Vx / fabs( Vy );
540 x2 = x1 + ( 1 + y1 ) * Vx / fabs( Vy );
542 y2 = y1 + ( 1 - x1 ) * Vy / fabs( Vx );
544 y2 = y1 + ( 1 + x1 ) * Vy / fabs( Vx );
562 double dl = sqrt( dx * dx + dy * dy );
564 data.time +=
static_cast<float>( dl / Vu );
565 if ( data.time > 10000 )
567 addPixelToChunkTrace( currentPixel, data, chunkTrace );
568 setChunkTrace( chunkTrace );
576 if ( isTraceExists( currentPixel ) )
579 setChunkTrace( chunkTrace );
580 addPixelToChunkTrace( currentPixel, data, chunkTrace );
584 if ( isTraceOutside( currentPixel ) )
586 setChunkTrace( chunkTrace );
590 if ( mRenderContext.feedback() && mRenderContext.feedback()->isCanceled() )
593 if ( mRenderContext.renderingStopped() )
597 drawTrace( startPixel );
600void QgsMeshStreamField::setResolution(
int width )
602 mFieldResolution = width;
605QSize QgsMeshStreamField::imageSize()
const
607 return mFieldSize * mFieldResolution;
610QPointF QgsMeshStreamField::fieldToDevice(
const QPoint &pixel )
const
613 p = mFieldResolution * p + QPointF( mFieldResolution - 1, mFieldResolution - 1 ) / 2;
617bool QgsMeshStreamField::addPixelToChunkTrace( QPoint &pixel, QgsMeshStreamField::FieldData &data, std::list<QPair<QPoint, QgsMeshStreamField::FieldData> > &chunkTrace )
619 chunkTrace.emplace_back( pixel, data );
620 if ( chunkTrace.size() == 3 )
622 simplifyChunkTrace( chunkTrace );
628void QgsMeshStreamlinesField::initField()
630 mField = QVector<bool>( mFieldSize.width() * mFieldSize.height(),
false );
631 mDirectionField = QVector<unsigned char>( mFieldSize.width() * mFieldSize.height(),
static_cast<unsigned char>(
int( 0 ) ) );
635void QgsMeshStreamlinesField::initImage()
637 mTraceImage = QImage();
638 switch ( mVectorColoring.coloringMethod() )
642 QSize imgSize = mFieldSize * mFieldResolution;
646 auto mScalarInterpolator = std::make_unique<QgsMeshLayerInterpolator>( mTriangularMesh, mMagValues, mScalarActiveFaceFlagValues, mDataType, fieldContext, imgSize );
651 if ( imgSize.isValid() )
653 std::unique_ptr<QgsRasterBlock> bl( renderer.block( 0, mOutputExtent, imgSize.width(), imgSize.height(), mFeedBack ) );
654 mTraceImage = bl->image();
660 mTraceImage = QImage( mFieldSize * mFieldResolution, QImage::Format_ARGB32_Premultiplied );
661 QColor col = mVectorColoring.singleColor();
662 mTraceImage.fill( col );
667 if ( !mTraceImage.isNull() )
669 mPainter = std::make_unique<QPainter>( &mTraceImage );
670 mPainter->setRenderHint( QPainter::Antialiasing,
true );
672 mDrawingTraceImage = QImage( mTraceImage.size(), QImage::Format_ARGB32_Premultiplied );
673 mDrawingTraceImage.fill( Qt::transparent );
674 mDrawingTracePainter = std::make_unique<QPainter>( &mDrawingTraceImage );
675 mDrawingTracePainter->setRenderHint( QPainter::Antialiasing,
true );
679void QgsMeshStreamField::clearChunkTrace( std::list<QPair<QPoint, QgsMeshStreamField::FieldData> > &chunkTrace )
681 auto one_before_end = std::prev( chunkTrace.end() );
682 chunkTrace.erase( chunkTrace.begin(), one_before_end );
685void QgsMeshStreamField::simplifyChunkTrace( std::list<QPair<QPoint, FieldData> > &chunkTrace )
687 if ( chunkTrace.size() != 3 )
690 auto ip3 = chunkTrace.begin();
694 while ( ip3 != chunkTrace.end() && ip2 != chunkTrace.end() )
696 QPoint v1 = ( *ip1 ).first - ( *ip2 ).first;
697 QPoint v2 = ( *ip2 ).first - ( *ip3 ).first;
698 if ( v1.x() * v2.x() + v1.y() * v2.y() == 0 )
700 ( *ip1 ).second.time += ( ( *ip2 ).second.time ) / 2;
701 ( *ip3 ).second.time += ( ( *ip2 ).second.time ) / 2;
702 ( *ip1 ).second.directionX += ( *ip2 ).second.directionX;
703 ( *ip1 ).second.directionY += ( *ip2 ).second.directionY;
704 chunkTrace.erase( ip2 );
711QgsMeshStreamlinesField::QgsMeshStreamlinesField(
717 bool dataIsOnVertices,
721 : QgsMeshStreamField( triangularMesh, datasetVectorValues, scalarActiveFaceFlagValues, layerExtent, magMax, dataIsOnVertices, rendererContext, vectorColoring )
722 , mMagValues( QgsMeshLayerUtils::calculateMagnitudes( datasetVectorValues ) )
725QgsMeshStreamlinesField::QgsMeshStreamlinesField(
729 const QVector<double> &datasetMagValues,
731 QgsMeshLayerRendererFeedback *feedBack,
733 bool dataIsOnVertices,
737 : QgsMeshStreamField( triangularMesh, datasetVectorValues, scalarActiveFaceFlagValues, layerExtent, magMax, dataIsOnVertices, rendererContext, vectorColoring )
738 , mTriangularMesh( triangularMesh )
739 , mMagValues( datasetMagValues )
740 , mScalarActiveFaceFlagValues( scalarActiveFaceFlagValues )
742 , mFeedBack( feedBack )
745void QgsMeshStreamlinesField::compose()
749 mPainter->setCompositionMode( QPainter::CompositionMode_DestinationIn );
750 mPainter->drawImage( 0, 0, mDrawingTraceImage );
753void QgsMeshStreamlinesField::storeInField(
const QPair<QPoint, FieldData> pixelData )
755 int i = pixelData.first.x();
756 int j = pixelData.first.y();
757 if ( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() )
759 mField[j * mFieldSize.width() + i] =
true;
760 int d = pixelData.second.directionX + 2 + ( pixelData.second.directionY + 1 ) * 3;
761 mDirectionField[j * mFieldSize.width() + i] =
static_cast<unsigned char>( d );
765void QgsMeshStreamField::setChunkTrace( std::list<QPair<QPoint, FieldData> > &chunkTrace )
767 auto p = chunkTrace.begin();
768 while ( p != chunkTrace.end() )
770 storeInField( ( *p ) );
771 mPixelFillingCount++;
776void QgsMeshStreamlinesField::drawTrace(
const QPoint &start )
const
778 if ( !isTraceExists( start ) || isTraceOutside( start ) )
781 if ( !mDrawingTracePainter )
786 int fieldWidth = mFieldSize.width();
787 QSet<QgsPointXY> path;
788 unsigned char dir = 0;
789 unsigned char prevDir = mDirectionField.at( pt1.y() * fieldWidth + pt1.x() );
791 QVector<double> xPoly;
792 QVector<double> yPoly;
793 QPointF devicePt = fieldToDevice( pt1 );
794 xPoly.append( devicePt.x() );
795 yPoly.append( devicePt.y() );
797 while ( isTraceExists( curPt ) && !isTraceOutside( curPt ) && !path.contains( curPt ) )
799 dir = mDirectionField.at( curPt.y() * fieldWidth + curPt.x() );
803 const QPoint curPtDir( ( dir - 1 ) % 3 - 1, ( dir - 1 ) / 3 - 1 );
804 const QPoint pt2 = curPt + curPtDir;
806 if ( dir != prevDir )
808 path.insert( curPt );
809 devicePt = fieldToDevice( curPt );
810 xPoly.append( devicePt.x() );
811 yPoly.append( devicePt.y() );
817 if ( !isTraceExists( curPt ) || isTraceOutside( curPt ) )
820 devicePt = fieldToDevice( curPt - QPoint( ( dir - 1 ) % 3 - 1, ( dir - 1 ) / 3 - 1 ) );
821 xPoly.append( devicePt.x() );
822 yPoly.append( devicePt.y() );
826 geom = geom.simplify( 1.5 * mFieldResolution ).smooth( 1, 0.25, -1.0, 45 );
828 pen.setColor( QColor( 0, 0, 0, 255 ) );
829 mDrawingTracePainter->setPen( pen );
830 mDrawingTracePainter->drawPolyline( geom.asQPolygonF() );
833bool QgsMeshStreamlinesField::isTraceExists(
const QPoint &pixel )
const
837 if ( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() )
839 return mField[j * mFieldSize.width() + i];
845bool QgsMeshStreamField::isTraceOutside(
const QPoint &pixel )
const
850 return !( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() );
853void QgsMeshStreamField::setMinimizeFieldSize(
bool minimizeFieldSize )
855 mMinimizeFieldSize = minimizeFieldSize;
858QgsMeshStreamField &QgsMeshStreamField::operator=(
const QgsMeshStreamField &other )
860 if ( &other ==
this )
863 mFieldSize = other.mFieldSize;
864 mFieldResolution = other.mFieldResolution;
866 mTraceImage = other.mTraceImage;
867 mMapToFieldPixel = other.mMapToFieldPixel;
868 mOutputExtent = other.mOutputExtent;
869 mVectorColoring = other.mVectorColoring;
870 mDirectionField = other.mDirectionField;
871 mRenderContext = other.mRenderContext;
872 mPixelFillingCount = other.mPixelFillingCount;
873 mMaxPixelFillingCount = other.mMaxPixelFillingCount;
874 mLayerExtent = other.mLayerExtent;
875 mMapExtent = other.mMapExtent;
876 mFieldTopLeftInDeviceCoordinates = other.mFieldTopLeftInDeviceCoordinates;
877 mValid = other.mValid;
878 mMaximumMagnitude = other.mMaximumMagnitude;
879 mPixelFillingDensity = other.mPixelFillingDensity;
880 mMinMagFilter = other.mMinMagFilter;
881 mMaxMagFilter = other.mMaxMagFilter;
882 mMinimizeFieldSize = other.mMinimizeFieldSize;
883 mVectorValueInterpolator = std::unique_ptr<QgsMeshVectorValueInterpolator>( other.mVectorValueInterpolator->clone() );
885 mPainter = std::make_unique<QPainter>( &mTraceImage );
890void QgsMeshStreamField::initImage()
892 mTraceImage = QImage( mFieldSize * mFieldResolution, QImage::Format_ARGB32 );
893 if ( !mTraceImage.isNull() )
895 mTraceImage.fill( 0X00000000 );
896 mPainter = std::make_unique<QPainter>( &mTraceImage );
897 mPainter->setRenderHint( QPainter::Antialiasing,
true );
898 mPainter->setPen( mPen );
902bool QgsMeshStreamField::filterMag(
double value )
const
904 return ( mMinMagFilter < 0 || value > mMinMagFilter ) && ( mMaxMagFilter < 0 || value < mMaxMagFilter );
907QImage QgsMeshStreamField::image()
const
909 if ( mTraceImage.isNull() )
911 return mTraceImage.scaled( mFieldSize * mFieldResolution, Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
914void QgsMeshStreamField::setPixelFillingDensity(
double maxFilling )
916 mPixelFillingDensity = maxFilling;
917 mMaxPixelFillingCount = int( mPixelFillingDensity * mFieldSize.width() * mFieldSize.height() );
920void QgsMeshStreamField::setColor( QColor color )
922 mPen.setColor( color );
925void QgsMeshStreamField::setLineWidth(
double width )
927 mPen.setWidthF( width );
930void QgsMeshStreamField::setFilter(
double min,
double max )
936QgsMeshVectorValueInterpolatorFromFace::QgsMeshVectorValueInterpolatorFromFace(
const QgsTriangularMesh &triangularMesh,
const QgsMeshDataBlock &datasetVectorValues )
937 : QgsMeshVectorValueInterpolator( triangularMesh, datasetVectorValues )
940QgsMeshVectorValueInterpolatorFromFace::QgsMeshVectorValueInterpolatorFromFace(
943 : QgsMeshVectorValueInterpolator( triangularMesh, datasetVectorValues, scalarActiveFaceFlagValues )
946QgsMeshVectorValueInterpolatorFromFace::QgsMeshVectorValueInterpolatorFromFace(
const QgsMeshVectorValueInterpolatorFromFace &other )
947 : QgsMeshVectorValueInterpolator( other )
950QgsMeshVectorValueInterpolatorFromFace *QgsMeshVectorValueInterpolatorFromFace::clone()
952 return new QgsMeshVectorValueInterpolatorFromFace( *
this );
955QgsMeshVectorValueInterpolatorFromFace &QgsMeshVectorValueInterpolatorFromFace::operator=(
const QgsMeshVectorValueInterpolatorFromFace &other )
957 QgsMeshVectorValueInterpolator::operator=( other );
961QgsVector QgsMeshVectorValueInterpolatorFromFace::interpolatedValuePrivate(
int faceIndex,
const QgsPointXY point )
const
963 QgsMeshFace face = mTriangularMesh.triangles().at( faceIndex );
969 QgsVector vect =
QgsVector( mDatasetValues.value( mTriangularMesh.trianglesToNativeFaces().at( faceIndex ) ).x(), mDatasetValues.value( mTriangularMesh.trianglesToNativeFaces().at( faceIndex ) ).y() );
971 return QgsMeshLayerUtils::interpolateVectorFromFacesData( p1, p2, p3, vect, point );
974QgsMeshVectorStreamlineRenderer::QgsMeshVectorStreamlineRenderer(
978 bool dataIsOnVertices,
984 : QgsMeshVectorStreamlineRenderer( triangularMesh, dataSetVectorValues, scalarActiveFaceFlagValues, QgsMeshLayerUtils::calculateMagnitudes( dataSetVectorValues ), dataIsOnVertices, settings, rendererContext, layerExtent, nullptr, magMax )
987QgsMeshVectorStreamlineRenderer::QgsMeshVectorStreamlineRenderer(
991 const QVector<double> &datasetMagValues,
992 bool dataIsOnVertices,
996 QgsMeshLayerRendererFeedback *feedBack,
999 : mRendererContext( rendererContext )
1001 mStreamlineField = std::make_unique<QgsMeshStreamlinesField>(
1003 triangularMesh, dataSetVectorValues, scalarActiveFaceFlagValues, datasetMagValues, layerExtent, feedBack, magMax, dataIsOnVertices, rendererContext, settings.
vectorStrokeColoring()
1006 mStreamlineField->updateSize( rendererContext );
1009 mStreamlineField->setColor( settings.
color() );
1019 mStreamlineField->addTracesOnMesh( triangularMesh, rendererContext.
mapExtent() );
1022 mStreamlineField->addRandomTraces();
1027void QgsMeshVectorStreamlineRenderer::draw()
1029 if ( mRendererContext.renderingStopped() )
1031 mStreamlineField->compose();
1032 mRendererContext.painter()->drawImage( mStreamlineField->topLeft(), mStreamlineField->image() );
1035QgsMeshParticleTracesField::QgsMeshParticleTracesField(
1041 bool dataIsOnVertices,
1045 : QgsMeshStreamField( triangularMesh, datasetVectorValues, scalarActiveFaceFlagValues, layerExtent, magMax, dataIsOnVertices, rendererContext, vectorColoring )
1047 std::srand( uint( ::time(
nullptr ) ) );
1048 mPen.setCapStyle( Qt::RoundCap );
1051QgsMeshParticleTracesField::QgsMeshParticleTracesField(
const QgsMeshParticleTracesField &other )
1052 : QgsMeshStreamField( other )
1053 , mTimeField( other.mTimeField )
1054 , mMagnitudeField( other.mMagnitudeField )
1055 , mParticles( other.mParticles )
1056 , mStumpImage( other.mStumpImage )
1057 , mTimeStep( other.mTimeStep )
1058 , mParticlesLifeTime( other.mParticlesLifeTime )
1059 , mParticlesCount( other.mParticlesCount )
1060 , mTailFactor( other.mTailFactor )
1061 , mMinTailLength( other.mMinTailLength )
1062 , mParticleColor( other.mParticleColor )
1063 , mParticleSize( other.mParticleSize )
1064 , mStumpFactor( other.mStumpFactor )
1065 , mStumpParticleWithLifeTime( other.mStumpParticleWithLifeTime )
1068void QgsMeshParticleTracesField::addParticle(
const QPoint &startPoint,
double lifeTime )
1070 addTrace( startPoint );
1071 if ( time( startPoint ) > 0 )
1073 QgsMeshTraceParticle p;
1074 p.lifeTime = lifeTime;
1075 p.position = startPoint;
1076 mParticles.append( p );
1080void QgsMeshParticleTracesField::addParticleXY(
const QgsPointXY &startPoint,
double lifeTime )
1082 addParticle( mMapToFieldPixel.transform( startPoint ).toQPointF().toPoint(), lifeTime );
1085void QgsMeshParticleTracesField::moveParticles()
1088 for (
auto &p : mParticles )
1090 double spentTime = p.remainingTime;
1091 size_t countAdded = 0;
1092 while ( spentTime < mTimeStep && p.lifeTime > 0 )
1094 double timeToSpend = double( time( p.position ) );
1095 if ( timeToSpend > 0 )
1097 p.lifeTime -= timeToSpend;
1098 spentTime += timeToSpend;
1099 QPoint dir = direction( p.position );
1100 if ( p.lifeTime > 0 )
1103 p.tail.emplace_back( p.position );
1118 if ( p.lifeTime <= 0 )
1126 p.remainingTime = spentTime - mTimeStep;
1127 while (
static_cast<int>( p.tail.size() ) > mMinTailLength &&
static_cast<double>( p.tail.size() ) > (
static_cast<double>( countAdded ) * mTailFactor ) )
1128 p.tail.erase( p.tail.begin() );
1129 drawParticleTrace( p );
1135 while ( i < mParticles.count() )
1137 if ( mParticles.at( i ).tail.size() == 0 )
1138 mParticles.removeAt( i );
1144 if ( mParticles.count() < mParticlesCount )
1145 addRandomParticles();
1148void QgsMeshParticleTracesField::addRandomParticles()
1153 if ( mParticlesCount < 0 )
1155 addParticleXY(
QgsPointXY( mMapToFieldPixel.xCenter(), mMapToFieldPixel.yCenter() ), mParticlesLifeTime );
1159 int count = mParticlesCount - mParticles.count();
1161 for (
int i = 0; i < count; ++i )
1163 int xRandom = 1 + std::rand() / int( ( RAND_MAX + 1u ) / uint( mFieldSize.width() ) );
1164 int yRandom = 1 + std::rand() / int( ( RAND_MAX + 1u ) / uint( mFieldSize.height() ) );
1165 double lifeTime = ( std::rand() / ( ( RAND_MAX + 1u ) / mParticlesLifeTime ) );
1166 addParticle( QPoint( xRandom, yRandom ), lifeTime );
1170void QgsMeshParticleTracesField::storeInField(
const QPair<QPoint, QgsMeshStreamField::FieldData> pixelData )
1172 int i = pixelData.first.x();
1173 int j = pixelData.first.y();
1174 if ( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() )
1176 mTimeField[j * mFieldSize.width() + i] = pixelData.second.time;
1177 int d = pixelData.second.directionX + 2 + ( pixelData.second.directionY + 1 ) * 3;
1178 mDirectionField[j * mFieldSize.width() + i] =
static_cast<unsigned char>( d );
1179 mMagnitudeField[j * mFieldSize.width() + i] =
static_cast<float>( pixelData.second.magnitude );
1183void QgsMeshParticleTracesField::initField()
1185 mTimeField = QVector<float>( mFieldSize.width() * mFieldSize.height(), -1 );
1186 mDirectionField = QVector<unsigned char>( mFieldSize.width() * mFieldSize.height(),
static_cast<unsigned char>(
int( 0 ) ) );
1187 mMagnitudeField = QVector<float>( mFieldSize.width() * mFieldSize.height(), 0 );
1189 mStumpImage = QImage( mFieldSize * mFieldResolution, QImage::Format_ARGB32 );
1190 mStumpImage.fill( QColor( 0, 0, 0, mStumpFactor ) );
1193bool QgsMeshParticleTracesField::isTraceExists(
const QPoint &pixel )
const
1197 if ( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() )
1199 return mTimeField[j * mFieldSize.width() + i] >= 0;
1205void QgsMeshParticleTracesField::setStumpParticleWithLifeTime(
bool stumpParticleWithLifeTime )
1207 mStumpParticleWithLifeTime = stumpParticleWithLifeTime;
1210void QgsMeshParticleTracesField::setParticlesColor(
const QColor &
c )
1212 mVectorColoring.setColor(
c );
1215QgsMeshParticleTracesField &QgsMeshParticleTracesField::operator=(
const QgsMeshParticleTracesField &other )
1217 if ( &other ==
this )
1220 QgsMeshStreamField::operator=( other );
1221 mTimeField = other.mTimeField;
1222 mMagnitudeField = other.mMagnitudeField;
1223 mDirectionField = other.mDirectionField;
1224 mParticles = other.mParticles;
1225 mStumpImage = other.mStumpImage;
1226 mTimeStep = other.mTimeStep;
1227 mParticlesLifeTime = other.mParticlesLifeTime;
1228 mParticlesCount = other.mParticlesCount;
1229 mMinTailLength = other.mMinTailLength;
1230 mTailFactor = other.mTailFactor;
1231 mParticleColor = other.mParticleColor;
1232 mParticleSize = other.mParticleSize;
1233 mStumpFactor = other.mStumpFactor;
1234 mStumpParticleWithLifeTime = other.mStumpParticleWithLifeTime;
1239void QgsMeshParticleTracesField::setMinTailLength(
int minTailLength )
1241 mMinTailLength = minTailLength;
1244void QgsMeshParticleTracesField::setTailFactor(
double tailFactor )
1246 mTailFactor = tailFactor;
1249void QgsMeshParticleTracesField::setParticleSize(
double particleSize )
1251 mParticleSize = particleSize;
1254void QgsMeshParticleTracesField::setTimeStep(
double timeStep )
1256 mTimeStep = timeStep;
1259void QgsMeshParticleTracesField::setParticlesLifeTime(
double particlesLifeTime )
1261 mParticlesLifeTime = particlesLifeTime;
1264QImage QgsMeshParticleTracesField::imageRendered()
const
1269void QgsMeshParticleTracesField::stump()
1274 mPainter->setCompositionMode( QPainter::CompositionMode_DestinationIn );
1275 mPainter->drawImage( QPoint( 0, 0 ), mStumpImage );
1278void QgsMeshParticleTracesField::setStumpFactor(
int sf )
1281 mStumpImage = QImage( mFieldSize * mFieldResolution, QImage::Format_ARGB32 );
1282 mStumpImage.fill( QColor( 0, 0, 0, mStumpFactor ) );
1285QPoint QgsMeshParticleTracesField::direction( QPoint position )
const
1287 int i = position.x();
1288 int j = position.y();
1289 if ( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() )
1291 int dir =
static_cast<int>( mDirectionField[j * mFieldSize.width() + i] );
1292 if ( dir != 0 && dir < 10 )
1293 return QPoint( ( dir - 1 ) % 3 - 1, ( dir - 1 ) / 3 - 1 );
1295 return QPoint( 0, 0 );
1298float QgsMeshParticleTracesField::time( QPoint position )
const
1300 int i = position.x();
1301 int j = position.y();
1302 if ( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() )
1304 return mTimeField[j * mFieldSize.width() + i];
1309float QgsMeshParticleTracesField::magnitude( QPoint position )
const
1311 int i = position.x();
1312 int j = position.y();
1313 if ( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() )
1315 return mMagnitudeField[j * mFieldSize.width() + i];
1320void QgsMeshParticleTracesField::drawParticleTrace(
const QgsMeshTraceParticle &particle )
1324 const std::list<QPoint> &tail = particle.tail;
1325 if ( tail.size() == 0 )
1327 double iniWidth = mParticleSize;
1329 size_t pixelCount = tail.size();
1331 double transparency = 1;
1332 if ( mStumpParticleWithLifeTime )
1333 transparency = sin( M_PI * particle.lifeTime / mParticlesLifeTime );
1336 if ( pixelCount > 1 )
1337 dw = iniWidth /
static_cast<double>( pixelCount );
1341 auto ip1 = std::prev( tail.end() );
1342 auto ip2 = std::prev( ip1 );
1344 while ( ip1 != tail.begin() )
1346 QPointF p1 = fieldToDevice( ( *ip1 ) );
1347 QPointF p2 = fieldToDevice( ( *ip2 ) );
1348 QColor traceColor = mVectorColoring.color( magnitude( *ip1 ) );
1349 traceColor.setAlphaF( traceColor.alphaF() * transparency );
1350 mPen.setColor( traceColor );
1351 mPen.setWidthF( iniWidth - i * dw );
1352 mPainter->setPen( mPen );
1353 mPainter->drawLine( p1, p2 );
1360void QgsMeshParticleTracesField::setParticlesCount(
int particlesCount )
1362 mParticlesCount = particlesCount;
1369 bool dataIsOnVertices,
1376 new QgsMeshParticleTracesField( triangularMesh, dataSetVectorValues, scalarActiveFaceFlagValues, layerExtent, magMax, dataIsOnVertices, rendererContext, vectorSettings.vectorStrokeColoring() )
1378 , mRendererContext( rendererContext )
1380 mParticleField->updateSize( rendererContext );
1384 : mRendererContext( rendererContext )
1391 bool vectorDataOnVertices;
1401 if ( ( cache->mDatasetGroupsCount == datasetGroupCount ) && ( cache->mActiveVectorDatasetIndex == datasetIndex ) )
1403 vectorDatasetValues = cache->mVectorDatasetValues;
1404 scalarActiveFaceFlagValues = cache->mScalarActiveFaceFlagValues;
1405 magMax = cache->mVectorDatasetMagMaximum;
1406 vectorDataOnVertices = cache->mVectorDataType == QgsMeshDatasetGroupMetadata::DataOnVertices;
1410 const QgsMeshDatasetGroupMetadata metadata = layer->dataProvider()->datasetGroupMetadata( datasetIndex.group() );
1411 magMax = metadata.maximum();
1412 vectorDataOnVertices = metadata.dataType() == QgsMeshDatasetGroupMetadata::DataOnVertices;
1415 if ( vectorDataOnVertices )
1416 count = layer->nativeMesh()->vertices.count();
1418 count = layer->nativeMesh()->faces.count();
1420 vectorDatasetValues = QgsMeshLayerUtils::datasetValues( layer, datasetIndex, 0, count );
1422 scalarActiveFaceFlagValues = layer->dataProvider()->areFacesActive( datasetIndex, 0, layer->nativeMesh()->faces.count() );
1425 mParticleField = std::make_unique<
1426 QgsMeshParticleTracesField>( ( *layer->
triangularMesh() ), vectorDatasetValues, scalarActiveFaceFlagValues, layer->
extent(), magMax, vectorDataOnVertices, rendererContext, vectorSettings.
vectorStrokeColoring() );
1428 mParticleField->setMinimizeFieldSize(
false );
1429 mParticleField->updateSize( mRendererContext );
1433 : mParticleField( new QgsMeshParticleTracesField( *other.mParticleField ) )
1434 , mRendererContext( other.mRendererContext )
1435 , mFPS( other.mFPS )
1436 , mVpixMax( other.mVpixMax )
1437 , mParticleLifeTime( other.mParticleLifeTime )
1444 mParticleField->setParticlesCount( count );
1445 mParticleField->addRandomParticles();
1450 mParticleField->moveParticles();
1451 return mParticleField->image();
1461 updateFieldParameter();
1467 updateFieldParameter();
1472 mParticleLifeTime = particleLifeTime;
1473 updateFieldParameter();
1478 mParticleField->setParticlesColor(
c );
1483 mParticleField->setParticleSize( width );
1488 mParticleField->setTailFactor( fct );
1493 mParticleField->setMinTailLength( l );
1502 mParticleField->setStumpFactor(
int( 255 * p ) );
1507 mParticleField = std::make_unique<QgsMeshParticleTracesField>( *( other.mParticleField ) );
1508 const_cast<QgsRenderContext &
>( mRendererContext ) = other.mRendererContext;
1510 mVpixMax = other.mVpixMax;
1511 mParticleLifeTime = other.mParticleLifeTime;
1516void QgsMeshVectorTraceAnimationGenerator::updateFieldParameter()
1518 double fieldTimeStep = mVpixMax /
static_cast<double>( mFPS );
1519 double fieldLifeTime = mParticleLifeTime * mFPS * fieldTimeStep;
1520 mParticleField->setTimeStep( fieldTimeStep );
1521 mParticleField->setParticlesLifeTime( fieldLifeTime );
1524QgsMeshVectorTraceRenderer::QgsMeshVectorTraceRenderer(
1528 bool dataIsOnVertices,
1535 new QgsMeshParticleTracesField( triangularMesh, dataSetVectorValues, scalarActiveFaceFlagValues, layerExtent, magMax, dataIsOnVertices, rendererContext, settings.vectorStrokeColoring() )
1537 , mRendererContext( rendererContext )
1539 mParticleField->updateSize( rendererContext );
1543 mParticleField->setTailFactor( 1 );
1544 mParticleField->setStumpParticleWithLifeTime(
false );
1549 mParticleField->addRandomParticles();
1550 mParticleField->moveParticles();
1553void QgsMeshVectorTraceRenderer::draw()
1555 if ( mRendererContext.renderingStopped() )
1557 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.
Defines color interpolation for rendering 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).
A block of integers/doubles from a mesh dataset.
bool isValid() const
Whether the block is valid.
An index that identifies the dataset group (e.g.
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.
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.
static bool isInTriangleFace(const QgsPointXY point, const QgsMeshFace &face, const QVector< QgsMeshVertex > &vertices)
Tests if point p is on the face defined with vertices.
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
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.
A triangular/derived 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.
Represent a 2-dimensional 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.