23 #define M_DEG2RAD 0.0174532925
29 if ( mCacheFaceIndex != -1 && mCacheFaceIndex < mTriangularMesh.triangles().count() )
31 QgsVector res = interpolatedValuePrivate( mCacheFaceIndex, point );
32 if ( isVectorValid( res ) )
34 activeFaceFilter( res, mCacheFaceIndex );
40 QList<int> potentialFaceIndexes = mTriangularMesh.faceIndexesForRectangle(
QgsRectangle( point, point ) );
42 for (
const int faceIndex : potentialFaceIndexes )
44 QgsVector res = interpolatedValuePrivate( faceIndex, point );
45 if ( isVectorValid( res ) )
47 mCacheFaceIndex = faceIndex;
48 activeFaceFilter( res, mCacheFaceIndex );
54 return (
QgsVector( std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN() ) );
58 QgsMeshVectorValueInterpolator &QgsMeshVectorValueInterpolator::operator=(
const QgsMeshVectorValueInterpolator &other )
60 mTriangularMesh = other.mTriangularMesh;
61 mDatasetValues = other.mDatasetValues;
62 mActiveFaceFlagValues = other.mActiveFaceFlagValues;
63 mFaceCache = other.mFaceCache;
64 mCacheFaceIndex = other.mCacheFaceIndex;
65 mUseScalarActiveFaceFlagValues = other.mUseScalarActiveFaceFlagValues;
70 QgsMeshVectorValueInterpolatorFromVertex::
72 QgsMeshVectorValueInterpolator( triangularMesh, datasetVectorValues )
77 QgsMeshVectorValueInterpolatorFromVertex::
78 QgsMeshVectorValueInterpolatorFromVertex(
const QgsTriangularMesh &triangularMesh,
81 QgsMeshVectorValueInterpolator( triangularMesh, datasetVectorValues, scalarActiveFaceFlagValues )
86 QgsMeshVectorValueInterpolatorFromVertex::QgsMeshVectorValueInterpolatorFromVertex(
const QgsMeshVectorValueInterpolatorFromVertex &other ):
87 QgsMeshVectorValueInterpolator( other )
90 QgsMeshVectorValueInterpolatorFromVertex *QgsMeshVectorValueInterpolatorFromVertex::clone()
92 return new QgsMeshVectorValueInterpolatorFromVertex( *
this );
95 QgsMeshVectorValueInterpolatorFromVertex &QgsMeshVectorValueInterpolatorFromVertex::
96 operator=(
const QgsMeshVectorValueInterpolatorFromVertex &other )
98 QgsMeshVectorValueInterpolator::operator=( other );
102 QgsVector QgsMeshVectorValueInterpolatorFromVertex::interpolatedValuePrivate(
int faceIndex,
const QgsPointXY point )
const
104 QgsMeshFace face = mTriangularMesh.triangles().at( faceIndex );
111 mDatasetValues.value( face.at( 0 ) ).y() );
114 mDatasetValues.value( face.at( 1 ) ).y() );
117 mDatasetValues.value( face.at( 2 ) ).y() );
119 return QgsMeshLayerUtils::interpolateVectorFromVerticesData(
129 QgsMeshVectorValueInterpolator::QgsMeshVectorValueInterpolator(
const QgsTriangularMesh &triangularMesh,
131 mTriangularMesh( triangularMesh ),
132 mDatasetValues( datasetVectorValues ),
133 mUseScalarActiveFaceFlagValues( false )
136 QgsMeshVectorValueInterpolator::QgsMeshVectorValueInterpolator(
const QgsTriangularMesh &triangularMesh,
139 mTriangularMesh( triangularMesh ),
140 mDatasetValues( datasetVectorValues ),
141 mActiveFaceFlagValues( scalarActiveFaceFlagValues ),
142 mUseScalarActiveFaceFlagValues( true )
145 QgsMeshVectorValueInterpolator::QgsMeshVectorValueInterpolator(
const QgsMeshVectorValueInterpolator &other ):
146 mTriangularMesh( other.mTriangularMesh ),
147 mDatasetValues( other.mDatasetValues ),
148 mActiveFaceFlagValues( other.mActiveFaceFlagValues ),
149 mFaceCache( other.mFaceCache ),
150 mCacheFaceIndex( other.mCacheFaceIndex ),
151 mUseScalarActiveFaceFlagValues( other.mUseScalarActiveFaceFlagValues )
154 void QgsMeshVectorValueInterpolator::updateCacheFaceIndex(
const QgsPointXY &point )
const
158 mCacheFaceIndex = mTriangularMesh.faceIndexForPoint_v2( point );
162 bool QgsMeshVectorValueInterpolator::isVectorValid(
const QgsVector &v )
const
164 return !( std::isnan( v.
x() ) || std::isnan( v.
y() ) );
168 void QgsMeshVectorValueInterpolator::activeFaceFilter(
QgsVector &vector,
int faceIndex )
const
170 if ( mUseScalarActiveFaceFlagValues && ! mActiveFaceFlagValues.active( mTriangularMesh.trianglesToNativeFaces()[faceIndex] ) )
171 vector =
QgsVector( std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN() ) ;
174 QSize QgsMeshStreamField::size()
const
179 QPoint QgsMeshStreamField::topLeft()
const
181 return mFieldTopLeftInDeviceCoordinates;
184 int QgsMeshStreamField::resolution()
const
186 return mFieldResolution;
189 QgsPointXY QgsMeshStreamField::positionToMapCoordinates(
const QPoint &pixelPosition,
const QgsPointXY &positionInPixel )
191 QgsPointXY mapPoint = mMapToFieldPixel.toMapCoordinates( pixelPosition );
192 mapPoint = mapPoint +
QgsVector( positionInPixel.
x() * mMapToFieldPixel.mapUnitsPerPixel(),
193 positionInPixel.
y() * mMapToFieldPixel.mapUnitsPerPixel() );
197 QgsMeshStreamField::QgsMeshStreamField(
202 double magnitudeMaximum,
bool dataIsOnVertices,
206 mFieldResolution( resolution ),
207 mVectorColoring( vectorColoring ),
208 mLayerExtent( layerExtent ),
209 mMaximumMagnitude( magnitudeMaximum ),
210 mRenderContext( rendererContext )
212 if ( dataIsOnVertices )
214 if ( scalarActiveFaceFlagValues.
isValid() )
215 mVectorValueInterpolator.reset(
new QgsMeshVectorValueInterpolatorFromVertex( triangularMesh,
217 scalarActiveFaceFlagValues ) );
219 mVectorValueInterpolator.reset(
new QgsMeshVectorValueInterpolatorFromVertex( triangularMesh,
220 dataSetVectorValues ) );
224 if ( scalarActiveFaceFlagValues.
isValid() )
225 mVectorValueInterpolator.reset(
new QgsMeshVectorValueInterpolatorFromFace( triangularMesh,
227 scalarActiveFaceFlagValues ) );
229 mVectorValueInterpolator.reset(
new QgsMeshVectorValueInterpolatorFromFace( triangularMesh,
230 dataSetVectorValues ) );
234 QgsMeshStreamField::QgsMeshStreamField(
const QgsMeshStreamField &other ):
235 mFieldSize( other.mFieldSize ),
236 mFieldResolution( other.mFieldResolution ),
238 mTraceImage( other.mTraceImage ),
239 mMapToFieldPixel( other.mMapToFieldPixel ),
240 mVectorColoring( other.mVectorColoring ),
241 mPixelFillingCount( other.mPixelFillingCount ),
242 mMaxPixelFillingCount( other.mMaxPixelFillingCount ),
243 mLayerExtent( other.mLayerExtent ),
244 mMapExtent( other.mMapExtent ),
245 mFieldTopLeftInDeviceCoordinates( other.mFieldTopLeftInDeviceCoordinates ),
246 mValid( other.mValid ),
247 mMaximumMagnitude( other.mMaximumMagnitude ),
248 mPixelFillingDensity( other.mPixelFillingDensity ),
249 mMinMagFilter( other.mMinMagFilter ),
250 mMaxMagFilter( other.mMaxMagFilter ),
251 mRenderContext( other.mRenderContext ),
252 mMinimizeFieldSize( other.mMinimizeFieldSize )
254 mPainter.reset(
new QPainter( &mTraceImage ) );
255 mVectorValueInterpolator =
256 std::unique_ptr<QgsMeshVectorValueInterpolator>( other.mVectorValueInterpolator->clone() );
259 QgsMeshStreamField::~QgsMeshStreamField()
265 void QgsMeshStreamField::updateSize(
const QgsRenderContext &renderContext )
278 layerExtent = mMapExtent;
282 if ( mMinimizeFieldSize )
283 interestZoneExtent = layerExtent.
intersect( mMapExtent );
285 interestZoneExtent = mMapExtent;
290 mFieldSize = QSize();
291 mFieldTopLeftInDeviceCoordinates = QPoint();
297 QgsRectangle fieldInterestZoneInDeviceCoordinates = QgsMeshLayerUtils::boundingBoxToScreenRectangle( deviceMapToPixel, interestZoneExtent );
298 mFieldTopLeftInDeviceCoordinates = QPoint(
int( fieldInterestZoneInDeviceCoordinates.
xMinimum() ),
int( fieldInterestZoneInDeviceCoordinates.
yMinimum() ) );
299 int fieldWidthInDeviceCoordinate = int( fieldInterestZoneInDeviceCoordinates.
width() );
300 int fieldHeightInDeviceCoordinate = int ( fieldInterestZoneInDeviceCoordinates.
height() );
302 int fieldWidth = int( fieldWidthInDeviceCoordinate / mFieldResolution );
303 int fieldHeight = int( fieldHeightInDeviceCoordinate / mFieldResolution );
306 if ( fieldWidthInDeviceCoordinate % mFieldResolution > 0 )
308 if ( fieldHeightInDeviceCoordinate % mFieldResolution > 0 )
311 if ( fieldWidth == 0 || fieldHeight == 0 )
313 mFieldSize = QSize();
317 mFieldSize.setWidth( fieldWidth );
318 mFieldSize.setHeight( fieldHeight );
321 double mapUnitPerFieldPixel;
322 if ( interestZoneExtent.
width() > 0 )
323 mapUnitPerFieldPixel = deviceMapToPixel.
mapUnitsPerPixel() * mFieldResolution * mFieldSize.width() / ( fieldWidthInDeviceCoordinate / mFieldResolution ) ;
325 mapUnitPerFieldPixel = 1e-8;
327 int fieldRightDevice = mFieldTopLeftInDeviceCoordinates.x() + mFieldSize.width() * mFieldResolution;
328 int fieldBottomDevice = mFieldTopLeftInDeviceCoordinates.y() + mFieldSize.height() * mFieldResolution;
331 int fieldTopDevice = mFieldTopLeftInDeviceCoordinates.
x();
332 int fieldLeftDevice = mFieldTopLeftInDeviceCoordinates.y();
335 double xc = ( fieldRightBottomMap.
x() + fieldTopLeftMap.
x() ) / 2;
336 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 )
366 addTrace( mMapToFieldPixel.transform( startPoint ).toQPointF().toPoint() );
370 void QgsMeshStreamField::addRandomTraces()
372 if ( mMaximumMagnitude > 0 )
373 while ( mPixelFillingCount < mMaxPixelFillingCount && !mRenderContext.renderingStopped() )
377 void QgsMeshStreamField::addRandomTrace()
382 int xRandom = 1 + std::rand() / int( ( RAND_MAX + 1u ) / uint( mFieldSize.width() ) ) ;
383 int yRandom = 1 + std::rand() / int ( ( RAND_MAX + 1u ) / uint( mFieldSize.height() ) ) ;
384 addTrace( QPoint( xRandom, yRandom ) );
387 void QgsMeshStreamField::addGriddedTraces(
int dx,
int dy )
390 while ( i < mFieldSize.width() && !mRenderContext.renderingStopped() )
393 while ( j < mFieldSize.height() && !mRenderContext.renderingStopped() )
395 addTrace( QPoint( i, j ) );
406 for (
auto f : qgis::as_const( facesInExtent ) )
409 for (
auto i : qgis::as_const( face ) )
410 vertices.insert( i );
413 for (
auto i : qgis::as_const( vertices ) )
415 addTrace( mesh.
vertices().at( i ) );
419 void QgsMeshStreamField::addTrace( QPoint startPixel )
425 if ( isTraceExists( startPixel ) || isTraceOutside( startPixel ) )
428 if ( !mVectorValueInterpolator )
431 if ( !( mMaximumMagnitude > 0 ) )
434 mPainter->setPen( mPen );
440 std::list<QPair<QPoint, FieldData>> chunkTrace;
442 QPoint currentPixel = startPixel;
447 while ( !mRenderContext.renderingStopped() )
450 vector = mVectorValueInterpolator->vectorValue( mapPosition ) ;
452 if ( std::isnan( vector.
x() ) || std::isnan( vector.
y() ) )
454 mPixelFillingCount++;
455 setChunkTrace( chunkTrace );
456 drawChunkTrace( chunkTrace );
464 QgsVector vu = vector / mMaximumMagnitude * 2;
465 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 );
1179 void QgsMeshParticleTracesField::setStumpFactor(
int sf )
1182 mStumpImage = QImage( mFieldSize * mFieldResolution, QImage::Format_ARGB32 );
1183 mStumpImage.fill( QColor( 0, 0, 0, mStumpFactor ) );
1186 QPoint QgsMeshParticleTracesField::direction( QPoint position )
const
1188 int i = position.x();
1189 int j = position.y();
1190 if ( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() )
1192 int dir =
static_cast<int>( mDirectionField[j * mFieldSize.width() + i] );
1193 if ( dir != 0 && dir < 10 )
1194 return QPoint( ( dir - 1 ) % 3 - 1, ( dir - 1 ) / 3 - 1 );
1196 return QPoint( 0, 0 );
1199 float QgsMeshParticleTracesField::time( QPoint position )
const
1201 int i = position.x();
1202 int j = position.y();
1203 if ( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() )
1205 return mTimeField[j * mFieldSize.width() + i];
1210 float QgsMeshParticleTracesField::magnitude( QPoint position )
const
1212 int i = position.x();
1213 int j = position.y();
1214 if ( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() )
1216 return mMagnitudeField[j * mFieldSize.width() + i];
1221 void QgsMeshParticleTracesField::drawParticleTrace(
const QgsMeshTraceParticle &particle )
1223 const std::list<QPoint> &tail = particle.tail;
1224 if ( tail.size() == 0 )
1226 double iniWidth = mParticleSize;
1227 double finWidth = 0;
1229 size_t pixelCount = tail.size();
1231 double transparency = 1;
1232 if ( mStumpParticleWithLifeTime )
1233 transparency = sin( M_PI * particle.lifeTime / mParticlesLifeTime );
1236 if ( pixelCount > 1 )
1237 dw = ( iniWidth - finWidth ) / ( pixelCount );
1241 auto ip1 = std::prev( tail.end() );
1242 auto ip2 = std::prev( ip1 );
1244 while ( ip1 != tail.begin() )
1246 QPointF p1 = fieldToDevice( ( *ip1 ) );
1247 QPointF p2 = fieldToDevice( ( *ip2 ) );
1248 QColor traceColor = mVectorColoring.color( magnitude( *ip1 ) );
1249 traceColor.setAlphaF( traceColor.alphaF()*transparency );
1250 mPen.setColor( traceColor );
1251 mPen.setWidthF( iniWidth - i * dw );
1252 mPainter->setPen( mPen );
1253 mPainter->drawLine( p1, p2 );
1260 void QgsMeshParticleTracesField::setParticlesCount(
int particlesCount )
1262 mParticlesCount = particlesCount;
1268 bool dataIsOnVertices,
1273 mRendererContext( rendererContext )
1275 mParticleField = std::unique_ptr<QgsMeshParticleTracesField>(
new QgsMeshParticleTracesField( triangularMesh,
1276 dataSetVectorValues,
1277 scalarActiveFaceFlagValues,
1283 mParticleField->updateSize( rendererContext ) ;
1287 mRendererContext( rendererContext )
1294 bool vectorDataOnVertices;
1304 if ( ( cache->mDatasetGroupsCount == datasetGroupCount ) &&
1305 ( cache->mActiveVectorDatasetIndex == datasetIndex ) )
1307 vectorDatasetValues = cache->mVectorDatasetValues;
1308 scalarActiveFaceFlagValues = cache->mScalarActiveFaceFlagValues;
1309 magMax = cache->mVectorDatasetMagMaximum;
1320 if ( vectorDataOnVertices )
1325 vectorDatasetValues = QgsMeshLayerUtils::datasetValues( layer, datasetIndex, 0, count );
1333 mParticleField = std::unique_ptr<QgsMeshParticleTracesField>(
new QgsMeshParticleTracesField( ( *layer->
triangularMesh() ),
1334 vectorDatasetValues,
1335 scalarActiveFaceFlagValues,
1338 vectorDataOnVertices,
1342 mParticleField->setMinimizeFieldSize(
false );
1343 mParticleField->updateSize( mRendererContext );
1347 mRendererContext( other.mRendererContext ),
1349 mVpixMax( other.mVpixMax ),
1350 mParticleLifeTime( other.mParticleLifeTime )
1352 mParticleField = std::unique_ptr<QgsMeshParticleTracesField>(
1353 new QgsMeshParticleTracesField( *other.mParticleField ) );
1359 mParticleField->setParticlesCount( count );
1360 mParticleField->addRandomParticles();
1365 mParticleField->moveParticles();
1366 return mParticleField->image();
1376 updateFieldParameter();
1382 updateFieldParameter();
1387 mParticleLifeTime = particleLifeTime;
1388 updateFieldParameter();
1393 mParticleField->setParticlesColor(
c );
1398 mParticleField->setParticleSize( width );
1403 mParticleField->setTailFactor( fct );
1408 mParticleField->setMinTailLength( l );
1417 mParticleField->setStumpFactor(
int( 255 * p ) );
1422 mParticleField.reset(
new QgsMeshParticleTracesField( *mParticleField ) );
1423 const_cast<QgsRenderContext &
>( mRendererContext ) = other.mRendererContext;
1425 mVpixMax = other.mVpixMax;
1426 mParticleLifeTime = other.mParticleLifeTime;
1431 void QgsMeshVectorTraceAnimationGenerator::updateFieldParameter()
1433 double fieldTimeStep = mVpixMax / mFPS;
1434 double fieldLifeTime = mParticleLifeTime * mFPS * fieldTimeStep;
1435 mParticleField->setTimeStep( fieldTimeStep );
1436 mParticleField->setParticlesLifeTime( fieldLifeTime );
1439 QgsMeshVectorTraceRenderer::QgsMeshVectorTraceRenderer(
1443 bool dataIsOnVertices,
1448 mRendererContext( rendererContext )
1450 mParticleField = std::unique_ptr<QgsMeshParticleTracesField>(
new QgsMeshParticleTracesField( triangularMesh,
1451 dataSetVectorValues,
1452 scalarActiveFaceFlagValues,
1458 mParticleField->updateSize( rendererContext ) ;
1461 settings.
lineWidth(), QgsUnitTypes::RenderUnit::RenderMillimeters ) );
1463 mParticleField->setTailFactor( 1 );
1464 mParticleField->setStumpParticleWithLifeTime(
false );
1467 mParticleField->addRandomParticles();
1468 mParticleField->moveParticles();
1471 void QgsMeshVectorTraceRenderer::draw()
1473 if ( mRendererContext.renderingStopped() )
1475 mRendererContext.painter()->drawImage( mParticleField->topLeft(), mParticleField->image() );