24 if ( mCacheFaceIndex != -1 && mCacheFaceIndex < mTriangularMesh.triangles().count() )
26 QgsVector res = interpolatedValuePrivate( mCacheFaceIndex, point );
27 if ( isVectorValid( res ) )
29 activeFaceFilter( res, mCacheFaceIndex );
35 QList<int> potentialFaceIndexes = mTriangularMesh.faceIndexesForRectangle(
QgsRectangle( point, point ) );
37 for (
const int faceIndex : potentialFaceIndexes )
39 QgsVector res = interpolatedValuePrivate( faceIndex, point );
40 if ( isVectorValid( res ) )
42 mCacheFaceIndex = faceIndex;
43 activeFaceFilter( res, mCacheFaceIndex );
49 return (
QgsVector( std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN() ) );
53 QgsMeshVectorValueInterpolator &QgsMeshVectorValueInterpolator::operator=(
const QgsMeshVectorValueInterpolator &other )
55 mTriangularMesh = other.mTriangularMesh;
56 mDatasetValues = other.mDatasetValues;
57 mActiveFaceFlagValues = other.mActiveFaceFlagValues;
58 mFaceCache = other.mFaceCache;
59 mCacheFaceIndex = other.mCacheFaceIndex;
60 mUseScalarActiveFaceFlagValues = other.mUseScalarActiveFaceFlagValues;
65 QgsMeshVectorValueInterpolatorFromVertex::
67 QgsMeshVectorValueInterpolator( triangularMesh, datasetVectorValues )
72 QgsMeshVectorValueInterpolatorFromVertex::
73 QgsMeshVectorValueInterpolatorFromVertex(
const QgsTriangularMesh &triangularMesh,
76 QgsMeshVectorValueInterpolator( triangularMesh, datasetVectorValues, scalarActiveFaceFlagValues )
81 QgsMeshVectorValueInterpolatorFromVertex::QgsMeshVectorValueInterpolatorFromVertex(
const QgsMeshVectorValueInterpolatorFromVertex &other ):
82 QgsMeshVectorValueInterpolator( other )
85 QgsMeshVectorValueInterpolatorFromVertex *QgsMeshVectorValueInterpolatorFromVertex::clone()
87 return new QgsMeshVectorValueInterpolatorFromVertex( *
this );
90 QgsMeshVectorValueInterpolatorFromVertex &QgsMeshVectorValueInterpolatorFromVertex::
91 operator=(
const QgsMeshVectorValueInterpolatorFromVertex &other )
93 QgsMeshVectorValueInterpolator::operator=( other );
97 QgsVector QgsMeshVectorValueInterpolatorFromVertex::interpolatedValuePrivate(
int faceIndex,
const QgsPointXY point )
const
99 QgsMeshFace face = mTriangularMesh.triangles().at( faceIndex );
106 mDatasetValues.value( face.at( 0 ) ).y() );
109 mDatasetValues.value( face.at( 1 ) ).y() );
112 mDatasetValues.value( face.at( 2 ) ).y() );
114 return QgsMeshLayerUtils::interpolateVectorFromVerticesData(
124 QgsMeshVectorValueInterpolator::QgsMeshVectorValueInterpolator(
const QgsTriangularMesh &triangularMesh,
126 mTriangularMesh( triangularMesh ),
127 mDatasetValues( datasetVectorValues ),
128 mUseScalarActiveFaceFlagValues( false )
131 QgsMeshVectorValueInterpolator::QgsMeshVectorValueInterpolator(
const QgsTriangularMesh &triangularMesh,
134 mTriangularMesh( triangularMesh ),
135 mDatasetValues( datasetVectorValues ),
136 mActiveFaceFlagValues( scalarActiveFaceFlagValues ),
137 mUseScalarActiveFaceFlagValues( true )
140 QgsMeshVectorValueInterpolator::QgsMeshVectorValueInterpolator(
const QgsMeshVectorValueInterpolator &other ):
141 mTriangularMesh( other.mTriangularMesh ),
142 mDatasetValues( other.mDatasetValues ),
143 mActiveFaceFlagValues( other.mActiveFaceFlagValues ),
144 mFaceCache( other.mFaceCache ),
145 mCacheFaceIndex( other.mCacheFaceIndex ),
146 mUseScalarActiveFaceFlagValues( other.mUseScalarActiveFaceFlagValues )
149 void QgsMeshVectorValueInterpolator::updateCacheFaceIndex(
const QgsPointXY &point )
const
153 mCacheFaceIndex = mTriangularMesh.faceIndexForPoint_v2( point );
157 bool QgsMeshVectorValueInterpolator::isVectorValid(
const QgsVector &v )
const
159 return !( std::isnan( v.
x() ) || std::isnan( v.
y() ) );
163 void QgsMeshVectorValueInterpolator::activeFaceFilter(
QgsVector &vector,
int faceIndex )
const
165 if ( mUseScalarActiveFaceFlagValues && ! mActiveFaceFlagValues.active( mTriangularMesh.trianglesToNativeFaces()[faceIndex] ) )
166 vector =
QgsVector( std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN() ) ;
169 QSize QgsMeshStreamField::size()
const
174 QPoint QgsMeshStreamField::topLeft()
const
176 return mFieldTopLeftInDeviceCoordinates;
179 int QgsMeshStreamField::resolution()
const
181 return mFieldResolution;
184 QgsPointXY QgsMeshStreamField::positionToMapCoordinates(
const QPoint &pixelPosition,
const QgsPointXY &positionInPixel )
186 QgsPointXY mapPoint = mMapToFieldPixel.toMapCoordinates( pixelPosition );
187 mapPoint = mapPoint +
QgsVector( positionInPixel.
x() * mMapToFieldPixel.mapUnitsPerPixel(),
188 positionInPixel.
y() * mMapToFieldPixel.mapUnitsPerPixel() );
192 QgsMeshStreamField::QgsMeshStreamField(
197 double magnitudeMaximum,
bool dataIsOnVertices,
201 mFieldResolution( resolution ),
202 mVectorColoring( vectorColoring ),
203 mLayerExtent( layerExtent ),
204 mMaximumMagnitude( magnitudeMaximum ),
205 mRenderContext( rendererContext )
207 if ( dataIsOnVertices )
209 if ( scalarActiveFaceFlagValues.
isValid() )
210 mVectorValueInterpolator.reset(
new QgsMeshVectorValueInterpolatorFromVertex( triangularMesh,
212 scalarActiveFaceFlagValues ) );
214 mVectorValueInterpolator.reset(
new QgsMeshVectorValueInterpolatorFromVertex( triangularMesh,
215 dataSetVectorValues ) );
219 if ( scalarActiveFaceFlagValues.
isValid() )
220 mVectorValueInterpolator.reset(
new QgsMeshVectorValueInterpolatorFromFace( triangularMesh,
222 scalarActiveFaceFlagValues ) );
224 mVectorValueInterpolator.reset(
new QgsMeshVectorValueInterpolatorFromFace( triangularMesh,
225 dataSetVectorValues ) );
229 QgsMeshStreamField::QgsMeshStreamField(
const QgsMeshStreamField &other ):
230 mFieldSize( other.mFieldSize ),
231 mFieldResolution( other.mFieldResolution ),
233 mTraceImage( other.mTraceImage ),
234 mMapToFieldPixel( other.mMapToFieldPixel ),
235 mVectorColoring( other.mVectorColoring ),
236 mPixelFillingCount( other.mPixelFillingCount ),
237 mMaxPixelFillingCount( other.mMaxPixelFillingCount ),
238 mLayerExtent( other.mLayerExtent ),
239 mMapExtent( other.mMapExtent ),
240 mFieldTopLeftInDeviceCoordinates( other.mFieldTopLeftInDeviceCoordinates ),
241 mValid( other.mValid ),
242 mMaximumMagnitude( other.mMaximumMagnitude ),
243 mPixelFillingDensity( other.mPixelFillingDensity ),
244 mMinMagFilter( other.mMinMagFilter ),
245 mMaxMagFilter( other.mMaxMagFilter ),
246 mRenderContext( other.mRenderContext ),
247 mMinimizeFieldSize( other.mMinimizeFieldSize )
249 mPainter.reset(
new QPainter( &mTraceImage ) );
250 mVectorValueInterpolator =
251 std::unique_ptr<QgsMeshVectorValueInterpolator>( other.mVectorValueInterpolator->clone() );
254 QgsMeshStreamField::~QgsMeshStreamField()
260 void QgsMeshStreamField::updateSize(
const QgsRenderContext &renderContext )
273 layerExtent = mMapExtent;
277 if ( mMinimizeFieldSize )
278 interestZoneExtent = layerExtent.
intersect( mMapExtent );
280 interestZoneExtent = mMapExtent;
285 mFieldSize = QSize();
286 mFieldTopLeftInDeviceCoordinates = QPoint();
298 mFieldTopLeftInDeviceCoordinates = interestZoneTopLeft.
toQPointF().toPoint();
299 QPoint mFieldBottomRightInDeviceCoordinates = interestZoneBottomRight.
toQPointF().toPoint();
300 int fieldWidthInDeviceCoordinate = mFieldBottomRightInDeviceCoordinates.x() - mFieldTopLeftInDeviceCoordinates.x();
301 int fieldHeightInDeviceCoordinate = mFieldBottomRightInDeviceCoordinates.y() - mFieldTopLeftInDeviceCoordinates.y();
303 int fieldWidth = int( fieldWidthInDeviceCoordinate / mFieldResolution );
304 int fieldHeight = int( fieldHeightInDeviceCoordinate / mFieldResolution );
307 if ( fieldWidthInDeviceCoordinate % mFieldResolution > 0 )
309 if ( fieldHeightInDeviceCoordinate % mFieldResolution > 0 )
312 if ( fieldWidth == 0 || fieldHeight == 0 )
314 mFieldSize = QSize();
318 mFieldSize.setWidth( fieldWidth );
319 mFieldSize.setHeight( fieldHeight );
323 double mapUnitPerFieldPixel;
324 if ( interestZoneExtent.
width() > 0 )
325 mapUnitPerFieldPixel = interestZoneExtent.
width() / fieldWidthInDeviceCoordinate * mFieldResolution;
327 mapUnitPerFieldPixel = 1e-8;
329 int fieldRightDevice = mFieldTopLeftInDeviceCoordinates.x() + mFieldSize.width() * mFieldResolution;
330 int fieldBottomDevice = mFieldTopLeftInDeviceCoordinates.y() + mFieldSize.height() * mFieldResolution;
333 int fieldTopDevice = mFieldTopLeftInDeviceCoordinates.
x();
334 int fieldLeftDevice = mFieldTopLeftInDeviceCoordinates.y();
337 double xc = ( fieldRightBottomMap.
x() + fieldTopLeftMap.
x() ) / 2;
338 double yc = ( fieldTopLeftMap.
y() + fieldRightBottomMap.
y() ) / 2;
350 void QgsMeshStreamField::updateSize(
const QgsRenderContext &renderContext,
int resolution )
352 if ( renderContext.
mapExtent() == mMapExtent && resolution == mFieldResolution )
354 mFieldResolution = resolution;
356 updateSize( renderContext );
359 bool QgsMeshStreamField::isValid()
const
364 void QgsMeshStreamField::addTrace(
QgsPointXY startPoint )
367 sp = mMapToFieldPixel.transform( startPoint ).toQPointF().toPoint();
368 addTrace( mMapToFieldPixel.transform( startPoint ).toQPointF().toPoint() );
372 void QgsMeshStreamField::addRandomTraces()
374 if ( mMaximumMagnitude > 0 )
375 while ( mPixelFillingCount < mMaxPixelFillingCount && !mRenderContext.renderingStopped() )
379 void QgsMeshStreamField::addRandomTrace()
384 int xRandom = 1 + std::rand() / int( ( RAND_MAX + 1u ) / uint( mFieldSize.width() ) ) ;
385 int yRandom = 1 + std::rand() / int ( ( RAND_MAX + 1u ) / uint( mFieldSize.height() ) ) ;
386 addTrace( QPoint( xRandom, yRandom ) );
389 void QgsMeshStreamField::addGriddedTraces(
int dx,
int dy )
392 while ( i < mFieldSize.width() && !mRenderContext.renderingStopped() )
395 while ( j < mFieldSize.height() && !mRenderContext.renderingStopped() )
397 addTrace( QPoint( i, j ) );
408 for (
auto f : qgis::as_const( facesInExtent ) )
411 for (
auto i : qgis::as_const( face ) )
412 vertices.insert( i );
415 for (
auto i : qgis::as_const( vertices ) )
417 addTrace( mesh.
vertices().at( i ) );
421 void QgsMeshStreamField::addTrace( QPoint startPixel )
427 if ( isTraceExists( startPixel ) || isTraceOutside( startPixel ) )
430 if ( !mVectorValueInterpolator )
433 if ( !( mMaximumMagnitude > 0 ) )
436 mPainter->setPen( mPen );
442 std::list<QPair<QPoint, FieldData>> chunkTrace;
444 QPoint currentPixel = startPixel;
449 while ( !mRenderContext.renderingStopped() )
452 vector = mVectorValueInterpolator->vectorValue( mapPosition ) ;
454 if ( std::isnan( vector.
x() ) || std::isnan( vector.
y() ) )
456 mPixelFillingCount++;
457 setChunkTrace( chunkTrace );
458 drawChunkTrace( chunkTrace );
465 QgsVector vu = vector / mMaximumMagnitude * 2;
466 data.magnitude = vector.
length();
469 double Vu = data.magnitude / mMaximumMagnitude * 2;
474 addPixelToChunkTrace( currentPixel, data, chunkTrace );
475 simplifyChunkTrace( chunkTrace );
476 setChunkTrace( chunkTrace );
477 drawChunkTrace( chunkTrace );
485 if ( nextPosition.
x() > 1 )
487 if ( nextPosition.
x() < -1 )
489 if ( nextPosition.
y() > 1 )
491 if ( nextPosition.
y() < -1 )
496 if ( incX != 0 || incY != 0 )
498 data.directionX = incX;
499 data.directionY = -incY;
501 if ( chunkTrace.empty() )
503 storeInField( QPair<QPoint, FieldData>( currentPixel, data ) );
505 if ( addPixelToChunkTrace( currentPixel, data, chunkTrace ) )
507 setChunkTrace( chunkTrace );
508 drawChunkTrace( chunkTrace );
509 clearChunkTrace( chunkTrace );
513 currentPixel += QPoint( incX, -incY );
514 x1 = nextPosition.
x() - 2 * incX;
515 y1 = nextPosition.
y() - 2 * incY;
545 x2 = x1 + ( 1 - y1 ) * Vx / fabs( Vy ) ;
547 x2 = x1 + ( 1 + y1 ) * Vx / fabs( Vy ) ;
549 y2 = y1 + ( 1 - x1 ) * Vy / fabs( Vx ) ;
551 y2 = y1 + ( 1 + x1 ) * Vy / fabs( Vx ) ;
578 double dl = sqrt( dx * dx + dy * dy );
580 data.time += dl / Vu ;
581 if ( data.time > 10000 )
583 addPixelToChunkTrace( currentPixel, data, chunkTrace );
584 setChunkTrace( chunkTrace );
585 drawChunkTrace( chunkTrace );
593 if ( isTraceExists( currentPixel ) )
596 setChunkTrace( chunkTrace );
597 addPixelToChunkTrace( currentPixel, data, chunkTrace );
598 drawChunkTrace( chunkTrace );
602 if ( isTraceOutside( currentPixel ) )
604 setChunkTrace( chunkTrace );
605 drawChunkTrace( chunkTrace );
611 void QgsMeshStreamField::setResolution(
int width )
613 mFieldResolution = width;
616 QSize QgsMeshStreamField::imageSize()
const
618 return mFieldSize * mFieldResolution;
621 QPointF QgsMeshStreamField::fieldToDevice(
const QPoint &pixel )
const
624 p = mFieldResolution * p + QPointF( mFieldResolution - 1, mFieldResolution - 1 ) / 2;
628 bool QgsMeshStreamField::addPixelToChunkTrace( QPoint &pixel,
629 QgsMeshStreamField::FieldData &data,
630 std::list<QPair<QPoint, QgsMeshStreamField::FieldData> > &chunkTrace )
632 chunkTrace.emplace_back( pixel, data );
633 if ( chunkTrace.size() == 3 )
635 simplifyChunkTrace( chunkTrace );
641 void QgsMeshStreamlinesField::initField()
643 mField = QVector<bool>( mFieldSize.width() * mFieldSize.height(),
false );
647 QgsMeshStreamlinesField::QgsMeshStreamlinesField(
const QgsTriangularMesh &triangularMesh,
652 bool dataIsOnVertices,
655 QgsMeshStreamField( triangularMesh,
657 scalarActiveFaceFlagValues,
665 QgsMeshStreamlinesField::QgsMeshStreamlinesField(
const QgsMeshStreamlinesField &other ):
666 QgsMeshStreamField( other ),
667 mField( other.mField )
670 QgsMeshStreamlinesField &QgsMeshStreamlinesField::operator=(
const QgsMeshStreamlinesField &other )
672 QgsMeshStreamField::operator=( other );
673 mField = other.mField;
677 void QgsMeshStreamlinesField::storeInField(
const QPair<QPoint, FieldData> pixelData )
679 int i = pixelData.first.x();
680 int j = pixelData.first.y();
681 if ( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() )
683 mField[j * mFieldSize.width() + i] =
true;
687 void QgsMeshStreamField::setChunkTrace( std::list<QPair<QPoint, FieldData> > &chunkTrace )
689 auto p = chunkTrace.begin();
690 while ( p != chunkTrace.end() )
692 storeInField( ( *p ) );
693 mPixelFillingCount++;
698 void QgsMeshStreamlinesField::drawChunkTrace(
const std::list<QPair<QPoint, QgsMeshStreamField::FieldData> > &chunkTrace )
700 auto p1 = chunkTrace.begin();
703 while ( p2 != chunkTrace.end() )
705 double mag1 = ( *p1 ).second.magnitude;
706 double mag2 = ( *p2 ).second.magnitude;
707 if ( filterMag( mag1 ) && filterMag( mag2 ) )
709 QPen pen = mPainter->pen();
710 pen.setColor( mVectorColoring.color( ( mag1 + mag2 ) / 2 ) );
711 mPainter->setPen( pen );
712 mPainter->drawLine( fieldToDevice( ( *p1 ).first ), fieldToDevice( ( *p2 ).first ) );
720 void QgsMeshStreamField::clearChunkTrace( std::list<QPair<QPoint, QgsMeshStreamField::FieldData> > &chunkTrace )
722 auto one_before_end = std::prev( chunkTrace.end() );
723 chunkTrace.erase( chunkTrace.begin(), one_before_end );
726 void QgsMeshStreamField::simplifyChunkTrace( std::list<QPair<QPoint, FieldData> > &shunkTrace )
728 if ( shunkTrace.size() != 3 )
731 auto ip3 = shunkTrace.begin();
735 while ( ip3 != shunkTrace.end() && ip2 != shunkTrace.end() )
737 QPoint v1 = ( *ip1 ).first - ( *ip2 ).first;
738 QPoint v2 = ( *ip2 ).first - ( *ip3 ).first;
739 if ( v1.x()*v2.x() + v1.y()*v2.y() == 0 )
741 ( *ip1 ).second.time += ( ( *ip2 ).second.time ) / 2;
742 ( *ip3 ).second.time += ( ( *ip2 ).second.time ) / 2;
743 ( *ip1 ).second.directionX += ( *ip2 ).second.directionX;
744 ( *ip1 ).second.directionY += ( *ip2 ).second.directionY;
745 shunkTrace.erase( ip2 );
752 bool QgsMeshStreamlinesField::isTraceExists(
const QPoint &pixel )
const
756 if ( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() )
758 return mField[j * mFieldSize.width() + i];
764 bool QgsMeshStreamField::isTraceOutside(
const QPoint &pixel )
const
768 if ( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() )
775 void QgsMeshStreamField::setMinimizeFieldSize(
bool minimizeFieldSize )
777 mMinimizeFieldSize = minimizeFieldSize;
780 QgsMeshStreamField &QgsMeshStreamField::operator=(
const QgsMeshStreamField &other )
782 mFieldSize = other.mFieldSize ;
783 mFieldResolution = other.mFieldResolution;
785 mTraceImage = other.mTraceImage ;
786 mMapToFieldPixel = other.mMapToFieldPixel ;
787 mVectorColoring = other.mVectorColoring;
788 mPixelFillingCount = other.mPixelFillingCount ;
789 mMaxPixelFillingCount = other.mMaxPixelFillingCount ;
790 mLayerExtent = other.mLayerExtent ;
791 mMapExtent = other.mMapExtent;
792 mFieldTopLeftInDeviceCoordinates = other.mFieldTopLeftInDeviceCoordinates ;
793 mValid = other.mValid ;
794 mMaximumMagnitude = other.mMaximumMagnitude ;
795 mPixelFillingDensity = other.mPixelFillingDensity ;
796 mMinMagFilter = other.mMinMagFilter ;
797 mMaxMagFilter = other.mMaxMagFilter ;
798 mMinimizeFieldSize = other.mMinimizeFieldSize ;
799 mVectorValueInterpolator =
800 std::unique_ptr<QgsMeshVectorValueInterpolator>( other.mVectorValueInterpolator->clone() );
802 mPainter.reset(
new QPainter( &mTraceImage ) );
807 void QgsMeshStreamField::initImage()
810 mTraceImage = QImage( mFieldSize * mFieldResolution, QImage::Format_ARGB32 );
811 mTraceImage.fill( 0X00000000 );
813 mPainter.reset(
new QPainter( &mTraceImage ) );
814 mPainter->setRenderHint( QPainter::Antialiasing,
true );
815 mPainter->setPen( mPen );
818 bool QgsMeshStreamField::filterMag(
double value )
const
820 return ( mMinMagFilter < 0 || value > mMinMagFilter ) && ( mMaxMagFilter < 0 || value < mMaxMagFilter );
823 QImage QgsMeshStreamField::image()
825 return mTraceImage.scaled( mFieldSize * mFieldResolution, Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
828 void QgsMeshStreamField::setPixelFillingDensity(
double maxFilling )
830 mPixelFillingDensity = maxFilling;
831 mMaxPixelFillingCount = int( mPixelFillingDensity * mFieldSize.width() * mFieldSize.height() );
834 void QgsMeshStreamField::setColor( QColor color )
836 mPen.setColor( color );
839 void QgsMeshStreamField::setLineWidth(
double width )
841 mPen.setWidthF( width );
844 void QgsMeshStreamField::setFilter(
double min,
double max )
850 QgsMeshVectorValueInterpolatorFromFace::QgsMeshVectorValueInterpolatorFromFace(
const QgsTriangularMesh &triangularMesh,
const QgsMeshDataBlock &datasetVectorValues ):
851 QgsMeshVectorValueInterpolator( triangularMesh, datasetVectorValues )
855 QgsMeshVectorValueInterpolator( triangularMesh, datasetVectorValues, scalarActiveFaceFlagValues )
858 QgsMeshVectorValueInterpolatorFromFace::QgsMeshVectorValueInterpolatorFromFace(
const QgsMeshVectorValueInterpolatorFromFace &other ):
859 QgsMeshVectorValueInterpolator( other )
862 QgsMeshVectorValueInterpolatorFromFace *QgsMeshVectorValueInterpolatorFromFace::clone()
864 return new QgsMeshVectorValueInterpolatorFromFace( *
this );
867 QgsMeshVectorValueInterpolatorFromFace &QgsMeshVectorValueInterpolatorFromFace::operator=(
const QgsMeshVectorValueInterpolatorFromFace &other )
869 QgsMeshVectorValueInterpolator::operator=( other );
873 QgsVector QgsMeshVectorValueInterpolatorFromFace::interpolatedValuePrivate(
int faceIndex,
const QgsPointXY point )
const
875 QgsMeshFace face = mTriangularMesh.triangles().at( faceIndex );
881 QgsVector vect =
QgsVector( mDatasetValues.value( mTriangularMesh.trianglesToNativeFaces().at( faceIndex ) ).x(),
882 mDatasetValues.value( mTriangularMesh.trianglesToNativeFaces().at( faceIndex ) ).y() );
884 return QgsMeshLayerUtils::interpolateVectorFromFacesData(
892 QgsMeshVectorStreamlineRenderer::QgsMeshVectorStreamlineRenderer(
896 bool dataIsOnVertices,
900 mRendererContext( rendererContext )
902 mStreamlineField.reset(
new QgsMeshStreamlinesField( triangularMesh,
904 scalarActiveFaceFlagValues,
911 mStreamlineField->updateSize( rendererContext );
914 QgsUnitTypes::RenderUnit::RenderMillimeters ) ) ;
915 mStreamlineField->setColor( settings.
color() );
924 mStreamlineField->addTracesOnMesh( triangularMesh, rendererContext.
mapExtent() );
927 mStreamlineField->addRandomTraces();
932 void QgsMeshVectorStreamlineRenderer::draw()
934 if ( mRendererContext.renderingStopped() )
936 mRendererContext.painter()->drawImage( mStreamlineField->topLeft(), mStreamlineField->image() );
939 QgsMeshParticleTracesField::QgsMeshParticleTracesField(
const QgsTriangularMesh &triangularMesh,
944 bool dataIsOnVertices,
947 QgsMeshStreamField( triangularMesh,
949 scalarActiveFaceFlagValues,
956 std::srand( uint( ::time(
nullptr ) ) );
957 mPen.setCapStyle( Qt::RoundCap );
960 QgsMeshParticleTracesField::QgsMeshParticleTracesField(
const QgsMeshParticleTracesField &other ):
961 QgsMeshStreamField( other ),
962 mTimeField( other.mTimeField ),
963 mMagnitudeField( other.mMagnitudeField ),
964 mDirectionField( other.mDirectionField ),
965 mParticles( other.mParticles ),
966 mStumpImage( other.mStumpImage ),
967 mTimeStep( other.mTimeStep ),
968 mParticlesLifeTime( other.mParticlesLifeTime ),
969 mParticlesCount( other.mParticlesCount ),
970 mTailFactor( other.mTailFactor ),
971 mParticleColor( other.mParticleColor ),
972 mParticleSize( other.mParticleSize ),
973 mStumpFactor( other.mStumpFactor )
976 void QgsMeshParticleTracesField::addParticle(
const QPoint &startPoint,
double lifeTime )
978 addTrace( startPoint );
979 if ( time( startPoint ) > 0 )
981 QgsMeshTraceParticle p;
982 p.lifeTime = lifeTime;
983 p.position = startPoint;
984 mParticles.append( p );
989 void QgsMeshParticleTracesField::addParticleXY(
const QgsPointXY &startPoint,
double lifeTime )
991 addParticle( mMapToFieldPixel.transform( startPoint ).toQPointF().toPoint(), lifeTime );
994 void QgsMeshParticleTracesField::moveParticles()
997 for (
auto &p : mParticles )
999 double spentTime = p.remainingTime;
1000 size_t countAdded = 0;
1001 while ( spentTime < mTimeStep && p.lifeTime > 0 )
1003 double timeToSpend = double( time( p.position ) );
1004 if ( timeToSpend > 0 )
1006 p.lifeTime -= timeToSpend;
1007 spentTime += timeToSpend;
1008 QPoint dir = direction( p.position );
1009 if ( p.lifeTime > 0 )
1012 p.tail.emplace_back( p.position );
1027 if ( p.lifeTime <= 0 )
1035 p.remainingTime = spentTime - mTimeStep;
1036 while (
int( p.tail.size() ) > mMinTailLength && p.tail.size() > countAdded * mTailFactor )
1037 p.tail.erase( p.tail.begin() );
1038 drawParticleTrace( p );
1044 while ( i < mParticles.count() )
1046 if ( mParticles.at( i ).tail.size() == 0 )
1047 mParticles.removeAt( i );
1053 if ( mParticles.count() < mParticlesCount )
1054 addRandomParticles();
1057 void QgsMeshParticleTracesField::addRandomParticles()
1062 if ( mParticlesCount < 0 )
1064 addParticleXY(
QgsPointXY( mMapToFieldPixel.xCenter(), mMapToFieldPixel.yCenter() ), mParticlesLifeTime );
1068 int count = mParticlesCount - mParticles.count();
1070 for (
int i = 0; i < count; ++i )
1072 int xRandom = 1 + std::rand() / int( ( RAND_MAX + 1u ) / uint( mFieldSize.width() ) ) ;
1073 int yRandom = 1 + std::rand() / int ( ( RAND_MAX + 1u ) / uint( mFieldSize.height() ) ) ;
1074 double lifeTime = ( std::rand() / ( ( RAND_MAX + 1u ) / mParticlesLifeTime ) );
1075 addParticle( QPoint( xRandom, yRandom ), lifeTime );
1079 void QgsMeshParticleTracesField::storeInField(
const QPair<QPoint, QgsMeshStreamField::FieldData> pixelData )
1081 int i = pixelData.first.x();
1082 int j = pixelData.first.y();
1083 if ( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() )
1085 mTimeField[j * mFieldSize.width() + i] = pixelData.second.time;
1086 int d = pixelData.second.directionX + 2 + ( pixelData.second.directionY + 1 ) * 3;
1087 mDirectionField[j * mFieldSize.width() + i] =
static_cast<char>( d );
1088 mMagnitudeField[j * mFieldSize.width() + i] = pixelData.second.magnitude;
1092 void QgsMeshParticleTracesField::initField()
1094 mTimeField = QVector<float>( mFieldSize.width() * mFieldSize.height(), -1 );
1095 mDirectionField = QVector<char>( mFieldSize.width() * mFieldSize.height(),
static_cast<char>(
int( 0 ) ) );
1096 mMagnitudeField = QVector<float>( mFieldSize.width() * mFieldSize.height(), 0 );
1098 mStumpImage = QImage( mFieldSize * mFieldResolution, QImage::Format_ARGB32 );
1099 mStumpImage.fill( QColor( 0, 0, 0, mStumpFactor ) );
1102 bool QgsMeshParticleTracesField::isTraceExists(
const QPoint &pixel )
const
1106 if ( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() )
1108 return mTimeField[j * mFieldSize.width() + i] >= 0;
1114 void QgsMeshParticleTracesField::setStumpParticleWithLifeTime(
bool stumpParticleWithLifeTime )
1116 mStumpParticleWithLifeTime = stumpParticleWithLifeTime;
1119 void QgsMeshParticleTracesField::setParticlesColor(
const QColor &
c )
1121 mVectorColoring.setColor(
c );
1124 void QgsMeshParticleTracesField::setMinTailLength(
int minTailLength )
1126 mMinTailLength = minTailLength;
1129 QgsMeshParticleTracesField &QgsMeshParticleTracesField::operator=(
const QgsMeshParticleTracesField &other )
1131 QgsMeshStreamField::operator=( other );
1132 mTimeField = other.mTimeField;
1133 mDirectionField = other.mDirectionField;
1134 mParticles = other.mParticles;
1135 mStumpImage = other.mStumpImage;
1136 mTimeStep = other.mTimeStep;
1137 mParticlesLifeTime = other.mParticlesLifeTime;
1138 mParticlesCount = other.mParticlesCount;
1139 mTailFactor = other.mTailFactor;
1140 mParticleColor = other.mParticleColor;
1141 mParticleSize = other.mParticleSize;
1142 mStumpFactor = other.mStumpFactor;
1147 void QgsMeshParticleTracesField::setTailFactor(
double tailFactor )
1149 mTailFactor = tailFactor;
1152 void QgsMeshParticleTracesField::setParticleSize(
double particleSize )
1154 mParticleSize = particleSize;
1157 void QgsMeshParticleTracesField::setTimeStep(
double timeStep )
1159 mTimeStep = timeStep;
1162 void QgsMeshParticleTracesField::setParticlesLifeTime(
double particlesLifeTime )
1164 mParticlesLifeTime = particlesLifeTime;
1167 QImage QgsMeshParticleTracesField::imageRendered()
const
1172 void QgsMeshParticleTracesField::stump()
1175 mPainter->setCompositionMode( QPainter::CompositionMode_DestinationIn );
1176 mPainter->drawImage( QPoint( 0, 0 ), mStumpImage );
1177 mPainter->restore();
1180 void QgsMeshParticleTracesField::setStumpFactor(
int sf )
1183 mStumpImage = QImage( mFieldSize * mFieldResolution, QImage::Format_ARGB32 );
1184 mStumpImage.fill( QColor( 0, 0, 0, mStumpFactor ) );
1187 QPoint QgsMeshParticleTracesField::direction( QPoint position )
const
1189 int i = position.x();
1190 int j = position.y();
1191 if ( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() )
1193 int dir =
static_cast<int>( mDirectionField[j * mFieldSize.width() + i] );
1194 if ( dir != 0 && dir < 10 )
1195 return QPoint( ( dir - 1 ) % 3 - 1, ( dir - 1 ) / 3 - 1 );
1197 return QPoint( 0, 0 );
1200 float QgsMeshParticleTracesField::time( QPoint position )
const
1202 int i = position.x();
1203 int j = position.y();
1204 if ( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() )
1206 return mTimeField[j * mFieldSize.width() + i];
1211 float QgsMeshParticleTracesField::magnitude( QPoint position )
const
1213 int i = position.x();
1214 int j = position.y();
1215 if ( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() )
1217 return mMagnitudeField[j * mFieldSize.width() + i];
1222 void QgsMeshParticleTracesField::drawParticleTrace(
const QgsMeshTraceParticle &particle )
1224 const std::list<QPoint> &tail = particle.tail;
1225 if ( tail.size() == 0 )
1227 double iniWidth = mParticleSize;
1228 double finWidth = 0;
1230 size_t pixelCount = tail.size();
1232 double transparency = 1;
1233 if ( mStumpParticleWithLifeTime )
1234 transparency = sin( M_PI * particle.lifeTime / mParticlesLifeTime );
1237 if ( pixelCount > 1 )
1238 dw = ( iniWidth - finWidth ) / ( pixelCount );
1242 auto ip1 = std::prev( tail.end() );
1243 auto ip2 = std::prev( ip1 );
1245 while ( ip1 != tail.begin() )
1247 QPointF p1 = fieldToDevice( ( *ip1 ) );
1248 QPointF p2 = fieldToDevice( ( *ip2 ) );
1249 QColor traceColor = mVectorColoring.color( magnitude( *ip1 ) );
1250 traceColor.setAlphaF( traceColor.alphaF()*transparency );
1251 mPen.setColor( traceColor );
1252 mPen.setWidthF( iniWidth - i * dw );
1253 mPainter->setPen( mPen );
1254 mPainter->drawLine( p1, p2 );
1261 void QgsMeshParticleTracesField::setParticlesCount(
int particlesCount )
1263 mParticlesCount = particlesCount;
1269 bool dataIsOnVertices,
1274 mRendererContext( rendererContext )
1276 mParticleField = std::unique_ptr<QgsMeshParticleTracesField>(
new QgsMeshParticleTracesField( triangularMesh,
1277 dataSetVectorValues,
1278 scalarActiveFaceFlagValues,
1284 mParticleField->updateSize( rendererContext ) ;
1288 mRendererContext( rendererContext )
1295 bool vectorDataOnVertices;
1305 if ( ( cache->mDatasetGroupsCount == datasetGroupCount ) &&
1306 ( cache->mActiveVectorDatasetIndex == datasetIndex ) )
1308 vectorDatasetValues = cache->mVectorDatasetValues;
1309 scalarActiveFaceFlagValues = cache->mScalarActiveFaceFlagValues;
1310 magMax = cache->mVectorDatasetMagMaximum;
1321 if ( vectorDataOnVertices )
1326 vectorDatasetValues = QgsMeshLayerUtils::datasetValues( layer, datasetIndex, 0, count );
1334 mParticleField = std::unique_ptr<QgsMeshParticleTracesField>(
new QgsMeshParticleTracesField( ( *layer->
triangularMesh() ),
1335 vectorDatasetValues,
1336 scalarActiveFaceFlagValues,
1339 vectorDataOnVertices,
1343 mParticleField->setMinimizeFieldSize(
false );
1344 mParticleField->updateSize( mRendererContext );
1348 mRendererContext( other.mRendererContext ),
1350 mVpixMax( other.mVpixMax ),
1351 mParticleLifeTime( other.mParticleLifeTime )
1353 mParticleField = std::unique_ptr<QgsMeshParticleTracesField>(
1354 new QgsMeshParticleTracesField( *other.mParticleField ) );
1360 mParticleField->setParticlesCount( count );
1361 mParticleField->addRandomParticles();
1366 mParticleField->moveParticles();
1367 return mParticleField->image();
1377 updateFieldParameter();
1383 updateFieldParameter();
1388 mParticleLifeTime = particleLifeTime;
1389 updateFieldParameter();
1394 mParticleField->setParticlesColor(
c );
1399 mParticleField->setParticleSize( width );
1404 mParticleField->setTailFactor( fct );
1409 mParticleField->setMinTailLength( l );
1418 mParticleField->setStumpFactor(
int( 255 * p ) );
1423 mParticleField.reset(
new QgsMeshParticleTracesField( *mParticleField ) );
1424 const_cast<QgsRenderContext &
>( mRendererContext ) = other.mRendererContext;
1426 mVpixMax = other.mVpixMax;
1427 mParticleLifeTime = other.mParticleLifeTime;
1432 void QgsMeshVectorTraceAnimationGenerator::updateFieldParameter()
1434 double fieldTimeStep = mVpixMax / mFPS;
1435 double fieldLifeTime = mParticleLifeTime * mFPS * fieldTimeStep;
1436 mParticleField->setTimeStep( fieldTimeStep );
1437 mParticleField->setParticlesLifeTime( fieldLifeTime );
1440 QgsMeshVectorTraceRenderer::QgsMeshVectorTraceRenderer(
1444 bool dataIsOnVertices,
1449 mRendererContext( rendererContext )
1451 mParticleField = std::unique_ptr<QgsMeshParticleTracesField>(
new QgsMeshParticleTracesField( triangularMesh,
1452 dataSetVectorValues,
1453 scalarActiveFaceFlagValues,
1459 mParticleField->updateSize( rendererContext ) ;
1462 settings.
lineWidth(), QgsUnitTypes::RenderUnit::RenderMillimeters ) );
1464 mParticleField->setTailFactor( 1 );
1465 mParticleField->setStumpParticleWithLifeTime(
false );
1468 mParticleField->addRandomParticles();
1469 mParticleField->moveParticles();
1472 void QgsMeshVectorTraceRenderer::draw()
1474 if ( mRendererContext.renderingStopped() )
1476 mRendererContext.painter()->drawImage( mParticleField->topLeft(), mParticleField->image() );