26 #define M_DEG2RAD 0.0174532925
36 if ( mCacheFaceIndex != -1 && mCacheFaceIndex < mTriangularMesh.triangles().count() )
38 QgsVector res = interpolatedValuePrivate( mCacheFaceIndex, point );
39 if ( isVectorValid( res ) )
41 activeFaceFilter( res, mCacheFaceIndex );
47 QList<int> potentialFaceIndexes = mTriangularMesh.faceIndexesForRectangle(
QgsRectangle( point, point ) );
49 for (
const int faceIndex : potentialFaceIndexes )
51 QgsVector res = interpolatedValuePrivate( faceIndex, point );
52 if ( isVectorValid( res ) )
54 mCacheFaceIndex = faceIndex;
55 activeFaceFilter( res, mCacheFaceIndex );
61 return (
QgsVector( std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN() ) );
65 QgsMeshVectorValueInterpolator &QgsMeshVectorValueInterpolator::operator=(
const QgsMeshVectorValueInterpolator &other )
67 mTriangularMesh = other.mTriangularMesh;
68 mDatasetValues = other.mDatasetValues;
69 mActiveFaceFlagValues = other.mActiveFaceFlagValues;
70 mFaceCache = other.mFaceCache;
71 mCacheFaceIndex = other.mCacheFaceIndex;
72 mUseScalarActiveFaceFlagValues = other.mUseScalarActiveFaceFlagValues;
77 QgsMeshVectorValueInterpolatorFromVertex::
79 QgsMeshVectorValueInterpolator( triangularMesh, datasetVectorValues )
84 QgsMeshVectorValueInterpolatorFromVertex::
85 QgsMeshVectorValueInterpolatorFromVertex(
const QgsTriangularMesh &triangularMesh,
88 QgsMeshVectorValueInterpolator( triangularMesh, datasetVectorValues, scalarActiveFaceFlagValues )
93 QgsMeshVectorValueInterpolatorFromVertex::QgsMeshVectorValueInterpolatorFromVertex(
const QgsMeshVectorValueInterpolatorFromVertex &other ):
94 QgsMeshVectorValueInterpolator( other )
97 QgsMeshVectorValueInterpolatorFromVertex *QgsMeshVectorValueInterpolatorFromVertex::clone()
99 return new QgsMeshVectorValueInterpolatorFromVertex( *
this );
102 QgsMeshVectorValueInterpolatorFromVertex &QgsMeshVectorValueInterpolatorFromVertex::
103 operator=(
const QgsMeshVectorValueInterpolatorFromVertex &other )
105 QgsMeshVectorValueInterpolator::operator=( other );
109 QgsVector QgsMeshVectorValueInterpolatorFromVertex::interpolatedValuePrivate(
int faceIndex,
const QgsPointXY point )
const
111 QgsMeshFace face = mTriangularMesh.triangles().at( faceIndex );
118 mDatasetValues.value( face.at( 0 ) ).y() );
121 mDatasetValues.value( face.at( 1 ) ).y() );
124 mDatasetValues.value( face.at( 2 ) ).y() );
126 return QgsMeshLayerUtils::interpolateVectorFromVerticesData(
136 QgsMeshVectorValueInterpolator::QgsMeshVectorValueInterpolator(
const QgsTriangularMesh &triangularMesh,
138 mTriangularMesh( triangularMesh ),
139 mDatasetValues( datasetVectorValues ),
140 mUseScalarActiveFaceFlagValues( false )
143 QgsMeshVectorValueInterpolator::QgsMeshVectorValueInterpolator(
const QgsTriangularMesh &triangularMesh,
146 mTriangularMesh( triangularMesh ),
147 mDatasetValues( datasetVectorValues ),
148 mActiveFaceFlagValues( scalarActiveFaceFlagValues ),
149 mUseScalarActiveFaceFlagValues( true )
152 QgsMeshVectorValueInterpolator::QgsMeshVectorValueInterpolator(
const QgsMeshVectorValueInterpolator &other ):
153 mTriangularMesh( other.mTriangularMesh ),
154 mDatasetValues( other.mDatasetValues ),
155 mActiveFaceFlagValues( other.mActiveFaceFlagValues ),
156 mFaceCache( other.mFaceCache ),
157 mCacheFaceIndex( other.mCacheFaceIndex ),
158 mUseScalarActiveFaceFlagValues( other.mUseScalarActiveFaceFlagValues )
161 void QgsMeshVectorValueInterpolator::updateCacheFaceIndex(
const QgsPointXY &point )
const
165 mCacheFaceIndex = mTriangularMesh.faceIndexForPoint_v2( point );
169 bool QgsMeshVectorValueInterpolator::isVectorValid(
const QgsVector &v )
const
171 return !( std::isnan( v.
x() ) || std::isnan( v.
y() ) );
175 void QgsMeshVectorValueInterpolator::activeFaceFilter(
QgsVector &vector,
int faceIndex )
const
177 if ( mUseScalarActiveFaceFlagValues && ! mActiveFaceFlagValues.active( mTriangularMesh.trianglesToNativeFaces()[faceIndex] ) )
178 vector =
QgsVector( std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN() ) ;
181 QSize QgsMeshStreamField::size()
const
186 QPoint QgsMeshStreamField::topLeft()
const
188 return mFieldTopLeftInDeviceCoordinates;
191 int QgsMeshStreamField::resolution()
const
193 return mFieldResolution;
196 QgsPointXY QgsMeshStreamField::positionToMapCoordinates(
const QPoint &pixelPosition,
const QgsPointXY &positionInPixel )
198 QgsPointXY mapPoint = mMapToFieldPixel.toMapCoordinates( pixelPosition );
199 mapPoint = mapPoint +
QgsVector( positionInPixel.
x() * mMapToFieldPixel.mapUnitsPerPixel(),
200 positionInPixel.
y() * mMapToFieldPixel.mapUnitsPerPixel() );
204 QgsMeshStreamField::QgsMeshStreamField(
209 double magnitudeMaximum,
bool dataIsOnVertices,
213 mFieldResolution( resolution ),
214 mVectorColoring( vectorColoring ),
215 mLayerExtent( layerExtent ),
216 mMaximumMagnitude( magnitudeMaximum ),
217 mRenderContext( rendererContext )
219 if ( dataIsOnVertices )
221 if ( scalarActiveFaceFlagValues.
isValid() )
222 mVectorValueInterpolator.reset(
new QgsMeshVectorValueInterpolatorFromVertex( triangularMesh,
224 scalarActiveFaceFlagValues ) );
226 mVectorValueInterpolator.reset(
new QgsMeshVectorValueInterpolatorFromVertex( triangularMesh,
227 dataSetVectorValues ) );
231 if ( scalarActiveFaceFlagValues.
isValid() )
232 mVectorValueInterpolator.reset(
new QgsMeshVectorValueInterpolatorFromFace( triangularMesh,
234 scalarActiveFaceFlagValues ) );
236 mVectorValueInterpolator.reset(
new QgsMeshVectorValueInterpolatorFromFace( triangularMesh,
237 dataSetVectorValues ) );
241 QgsMeshStreamField::QgsMeshStreamField(
const QgsMeshStreamField &other ):
242 mFieldSize( other.mFieldSize ),
243 mFieldResolution( other.mFieldResolution ),
245 mTraceImage( other.mTraceImage ),
246 mMapToFieldPixel( other.mMapToFieldPixel ),
247 mVectorColoring( other.mVectorColoring ),
248 mPixelFillingCount( other.mPixelFillingCount ),
249 mMaxPixelFillingCount( other.mMaxPixelFillingCount ),
250 mLayerExtent( other.mLayerExtent ),
251 mMapExtent( other.mMapExtent ),
252 mFieldTopLeftInDeviceCoordinates( other.mFieldTopLeftInDeviceCoordinates ),
253 mValid( other.mValid ),
254 mMaximumMagnitude( other.mMaximumMagnitude ),
255 mPixelFillingDensity( other.mPixelFillingDensity ),
256 mMinMagFilter( other.mMinMagFilter ),
257 mMaxMagFilter( other.mMaxMagFilter ),
258 mRenderContext( other.mRenderContext ),
259 mMinimizeFieldSize( other.mMinimizeFieldSize )
261 mPainter.reset(
new QPainter( &mTraceImage ) );
262 mVectorValueInterpolator =
263 std::unique_ptr<QgsMeshVectorValueInterpolator>( other.mVectorValueInterpolator->clone() );
266 QgsMeshStreamField::~QgsMeshStreamField()
272 void QgsMeshStreamField::updateSize(
const QgsRenderContext &renderContext )
285 layerExtent = mMapExtent;
289 if ( mMinimizeFieldSize )
290 interestZoneExtent = layerExtent.
intersect( mMapExtent );
292 interestZoneExtent = mMapExtent;
297 mFieldSize = QSize();
298 mFieldTopLeftInDeviceCoordinates = QPoint();
304 QgsRectangle fieldInterestZoneInDeviceCoordinates = QgsMeshLayerUtils::boundingBoxToScreenRectangle( deviceMapToPixel, interestZoneExtent );
305 mFieldTopLeftInDeviceCoordinates = QPoint(
int( fieldInterestZoneInDeviceCoordinates.
xMinimum() ),
int( fieldInterestZoneInDeviceCoordinates.
yMinimum() ) );
306 int fieldWidthInDeviceCoordinate = int( fieldInterestZoneInDeviceCoordinates.
width() );
307 int fieldHeightInDeviceCoordinate = int ( fieldInterestZoneInDeviceCoordinates.
height() );
309 int fieldWidth = int( fieldWidthInDeviceCoordinate / mFieldResolution );
310 int fieldHeight = int( fieldHeightInDeviceCoordinate / mFieldResolution );
313 if ( fieldWidthInDeviceCoordinate % mFieldResolution > 0 )
315 if ( fieldHeightInDeviceCoordinate % mFieldResolution > 0 )
318 if ( fieldWidth == 0 || fieldHeight == 0 )
320 mFieldSize = QSize();
324 mFieldSize.setWidth( fieldWidth );
325 mFieldSize.setHeight( fieldHeight );
328 double mapUnitPerFieldPixel;
329 if ( interestZoneExtent.
width() > 0 )
330 mapUnitPerFieldPixel = deviceMapToPixel.
mapUnitsPerPixel() * mFieldResolution * mFieldSize.width() / ( fieldWidthInDeviceCoordinate / mFieldResolution ) ;
332 mapUnitPerFieldPixel = 1e-8;
334 int fieldRightDevice = mFieldTopLeftInDeviceCoordinates.x() + mFieldSize.width() * mFieldResolution;
335 int fieldBottomDevice = mFieldTopLeftInDeviceCoordinates.y() + mFieldSize.height() * mFieldResolution;
338 int fieldTopDevice = mFieldTopLeftInDeviceCoordinates.
x();
339 int fieldLeftDevice = mFieldTopLeftInDeviceCoordinates.y();
342 double xc = ( fieldRightBottomMap.
x() + fieldTopLeftMap.
x() ) / 2;
343 double yc = ( fieldTopLeftMap.
y() + fieldRightBottomMap.
y() ) / 2;
357 void QgsMeshStreamField::updateSize(
const QgsRenderContext &renderContext,
int resolution )
359 if ( renderContext.
mapExtent() == mMapExtent && resolution == mFieldResolution )
361 mFieldResolution = resolution;
363 updateSize( renderContext );
366 bool QgsMeshStreamField::isValid()
const
371 void QgsMeshStreamField::addTrace(
QgsPointXY startPoint )
373 addTrace( mMapToFieldPixel.transform( startPoint ).toQPointF().toPoint() );
377 void QgsMeshStreamField::addRandomTraces()
379 if ( mMaximumMagnitude > 0 )
380 while ( mPixelFillingCount < mMaxPixelFillingCount && !mRenderContext.renderingStopped() )
384 void QgsMeshStreamField::addRandomTrace()
389 int xRandom = 1 + std::rand() / int( ( RAND_MAX + 1u ) / uint( mFieldSize.width() ) ) ;
390 int yRandom = 1 + std::rand() / int ( ( RAND_MAX + 1u ) / uint( mFieldSize.height() ) ) ;
391 addTrace( QPoint( xRandom, yRandom ) );
394 void QgsMeshStreamField::addGriddedTraces(
int dx,
int dy )
397 while ( i < mFieldSize.width() && !mRenderContext.renderingStopped() )
400 while ( j < mFieldSize.height() && !mRenderContext.renderingStopped() )
402 addTrace( QPoint( i, j ) );
413 for (
auto f : qgis::as_const( facesInExtent ) )
416 for (
auto i : qgis::as_const( face ) )
417 vertices.insert( i );
420 for (
auto i : qgis::as_const( vertices ) )
422 addTrace( mesh.
vertices().at( i ) );
426 void QgsMeshStreamField::addTrace( QPoint startPixel )
432 if ( isTraceExists( startPixel ) || isTraceOutside( startPixel ) )
435 if ( !mVectorValueInterpolator )
438 if ( !( mMaximumMagnitude > 0 ) )
441 mPainter->setPen( mPen );
447 std::list<QPair<QPoint, FieldData>> chunkTrace;
449 QPoint currentPixel = startPixel;
454 while ( !mRenderContext.renderingStopped() )
457 vector = mVectorValueInterpolator->vectorValue( mapPosition ) ;
459 if ( std::isnan( vector.
x() ) || std::isnan( vector.
y() ) )
461 mPixelFillingCount++;
462 setChunkTrace( chunkTrace );
463 drawChunkTrace( chunkTrace );
471 QgsVector vu = vector / mMaximumMagnitude * 2;
472 data.magnitude = vector.
length();
476 double Vu = data.magnitude / mMaximumMagnitude * 2;
481 addPixelToChunkTrace( currentPixel, data, chunkTrace );
482 simplifyChunkTrace( chunkTrace );
483 setChunkTrace( chunkTrace );
484 drawChunkTrace( chunkTrace );
492 if ( nextPosition.
x() > 1 )
494 if ( nextPosition.
x() < -1 )
496 if ( nextPosition.
y() > 1 )
498 if ( nextPosition.
y() < -1 )
503 if ( incX != 0 || incY != 0 )
505 data.directionX = incX;
506 data.directionY = -incY;
508 if ( chunkTrace.empty() )
510 storeInField( QPair<QPoint, FieldData>( currentPixel, data ) );
512 if ( addPixelToChunkTrace( currentPixel, data, chunkTrace ) )
514 setChunkTrace( chunkTrace );
515 drawChunkTrace( chunkTrace );
516 clearChunkTrace( chunkTrace );
520 currentPixel += QPoint( incX, -incY );
521 x1 = nextPosition.
x() - 2 * incX;
522 y1 = nextPosition.
y() - 2 * incY;
552 x2 = x1 + ( 1 - y1 ) * Vx / fabs( Vy ) ;
554 x2 = x1 + ( 1 + y1 ) * Vx / fabs( Vy ) ;
556 y2 = y1 + ( 1 - x1 ) * Vy / fabs( Vx ) ;
558 y2 = y1 + ( 1 + x1 ) * Vy / fabs( Vx ) ;
585 double dl = sqrt( dx * dx + dy * dy );
587 data.time += dl / Vu ;
588 if ( data.time > 10000 )
590 addPixelToChunkTrace( currentPixel, data, chunkTrace );
591 setChunkTrace( chunkTrace );
592 drawChunkTrace( chunkTrace );
600 if ( isTraceExists( currentPixel ) )
603 setChunkTrace( chunkTrace );
604 addPixelToChunkTrace( currentPixel, data, chunkTrace );
605 drawChunkTrace( chunkTrace );
609 if ( isTraceOutside( currentPixel ) )
611 setChunkTrace( chunkTrace );
612 drawChunkTrace( chunkTrace );
618 void QgsMeshStreamField::setResolution(
int width )
620 mFieldResolution = width;
623 QSize QgsMeshStreamField::imageSize()
const
625 return mFieldSize * mFieldResolution;
628 QPointF QgsMeshStreamField::fieldToDevice(
const QPoint &pixel )
const
631 p = mFieldResolution * p + QPointF( mFieldResolution - 1, mFieldResolution - 1 ) / 2;
635 bool QgsMeshStreamField::addPixelToChunkTrace( QPoint &pixel,
636 QgsMeshStreamField::FieldData &data,
637 std::list<QPair<QPoint, QgsMeshStreamField::FieldData> > &chunkTrace )
639 chunkTrace.emplace_back( pixel, data );
640 if ( chunkTrace.size() == 3 )
642 simplifyChunkTrace( chunkTrace );
648 void QgsMeshStreamlinesField::initField()
650 mField = QVector<bool>( mFieldSize.width() * mFieldSize.height(),
false );
654 QgsMeshStreamlinesField::QgsMeshStreamlinesField(
const QgsTriangularMesh &triangularMesh,
659 bool dataIsOnVertices,
662 QgsMeshStreamField( triangularMesh,
664 scalarActiveFaceFlagValues,
672 QgsMeshStreamlinesField::QgsMeshStreamlinesField(
const QgsMeshStreamlinesField &other ):
673 QgsMeshStreamField( other ),
674 mField( other.mField )
677 QgsMeshStreamlinesField &QgsMeshStreamlinesField::operator=(
const QgsMeshStreamlinesField &other )
679 QgsMeshStreamField::operator=( other );
680 mField = other.mField;
684 void QgsMeshStreamlinesField::storeInField(
const QPair<QPoint, FieldData> pixelData )
686 int i = pixelData.first.x();
687 int j = pixelData.first.y();
688 if ( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() )
690 mField[j * mFieldSize.width() + i] =
true;
694 void QgsMeshStreamField::setChunkTrace( std::list<QPair<QPoint, FieldData> > &chunkTrace )
696 auto p = chunkTrace.begin();
697 while ( p != chunkTrace.end() )
699 storeInField( ( *p ) );
700 mPixelFillingCount++;
705 void QgsMeshStreamlinesField::drawChunkTrace(
const std::list<QPair<QPoint, QgsMeshStreamField::FieldData> > &chunkTrace )
707 auto p1 = chunkTrace.begin();
710 while ( p2 != chunkTrace.end() )
712 double mag1 = ( *p1 ).second.magnitude;
713 double mag2 = ( *p2 ).second.magnitude;
714 if ( filterMag( mag1 ) && filterMag( mag2 ) )
716 QPen pen = mPainter->pen();
717 pen.setColor( mVectorColoring.color( ( mag1 + mag2 ) / 2 ) );
718 mPainter->setPen( pen );
719 mPainter->drawLine( fieldToDevice( ( *p1 ).first ), fieldToDevice( ( *p2 ).first ) );
727 void QgsMeshStreamField::clearChunkTrace( std::list<QPair<QPoint, QgsMeshStreamField::FieldData> > &chunkTrace )
729 auto one_before_end = std::prev( chunkTrace.end() );
730 chunkTrace.erase( chunkTrace.begin(), one_before_end );
733 void QgsMeshStreamField::simplifyChunkTrace( std::list<QPair<QPoint, FieldData> > &shunkTrace )
735 if ( shunkTrace.size() != 3 )
738 auto ip3 = shunkTrace.begin();
742 while ( ip3 != shunkTrace.end() && ip2 != shunkTrace.end() )
744 QPoint v1 = ( *ip1 ).first - ( *ip2 ).first;
745 QPoint v2 = ( *ip2 ).first - ( *ip3 ).first;
746 if ( v1.x()*v2.x() + v1.y()*v2.y() == 0 )
748 ( *ip1 ).second.time += ( ( *ip2 ).second.time ) / 2;
749 ( *ip3 ).second.time += ( ( *ip2 ).second.time ) / 2;
750 ( *ip1 ).second.directionX += ( *ip2 ).second.directionX;
751 ( *ip1 ).second.directionY += ( *ip2 ).second.directionY;
752 shunkTrace.erase( ip2 );
759 bool QgsMeshStreamlinesField::isTraceExists(
const QPoint &pixel )
const
763 if ( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() )
765 return mField[j * mFieldSize.width() + i];
771 bool QgsMeshStreamField::isTraceOutside(
const QPoint &pixel )
const
775 if ( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() )
782 void QgsMeshStreamField::setMinimizeFieldSize(
bool minimizeFieldSize )
784 mMinimizeFieldSize = minimizeFieldSize;
787 QgsMeshStreamField &QgsMeshStreamField::operator=(
const QgsMeshStreamField &other )
789 mFieldSize = other.mFieldSize ;
790 mFieldResolution = other.mFieldResolution;
792 mTraceImage = other.mTraceImage ;
793 mMapToFieldPixel = other.mMapToFieldPixel ;
794 mVectorColoring = other.mVectorColoring;
795 mPixelFillingCount = other.mPixelFillingCount ;
796 mMaxPixelFillingCount = other.mMaxPixelFillingCount ;
797 mLayerExtent = other.mLayerExtent ;
798 mMapExtent = other.mMapExtent;
799 mFieldTopLeftInDeviceCoordinates = other.mFieldTopLeftInDeviceCoordinates ;
800 mValid = other.mValid ;
801 mMaximumMagnitude = other.mMaximumMagnitude ;
802 mPixelFillingDensity = other.mPixelFillingDensity ;
803 mMinMagFilter = other.mMinMagFilter ;
804 mMaxMagFilter = other.mMaxMagFilter ;
805 mMinimizeFieldSize = other.mMinimizeFieldSize ;
806 mVectorValueInterpolator =
807 std::unique_ptr<QgsMeshVectorValueInterpolator>( other.mVectorValueInterpolator->clone() );
809 mPainter.reset(
new QPainter( &mTraceImage ) );
814 void QgsMeshStreamField::initImage()
817 mTraceImage = QImage( mFieldSize * mFieldResolution, QImage::Format_ARGB32 );
818 mTraceImage.fill( 0X00000000 );
820 mPainter.reset(
new QPainter( &mTraceImage ) );
821 mPainter->setRenderHint( QPainter::Antialiasing,
true );
822 mPainter->setPen( mPen );
825 bool QgsMeshStreamField::filterMag(
double value )
const
827 return ( mMinMagFilter < 0 || value > mMinMagFilter ) && ( mMaxMagFilter < 0 || value < mMaxMagFilter );
830 QImage QgsMeshStreamField::image()
832 return mTraceImage.scaled( mFieldSize * mFieldResolution, Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
835 void QgsMeshStreamField::setPixelFillingDensity(
double maxFilling )
837 mPixelFillingDensity = maxFilling;
838 mMaxPixelFillingCount = int( mPixelFillingDensity * mFieldSize.width() * mFieldSize.height() );
841 void QgsMeshStreamField::setColor( QColor color )
843 mPen.setColor( color );
846 void QgsMeshStreamField::setLineWidth(
double width )
848 mPen.setWidthF( width );
851 void QgsMeshStreamField::setFilter(
double min,
double max )
857 QgsMeshVectorValueInterpolatorFromFace::QgsMeshVectorValueInterpolatorFromFace(
const QgsTriangularMesh &triangularMesh,
const QgsMeshDataBlock &datasetVectorValues ):
858 QgsMeshVectorValueInterpolator( triangularMesh, datasetVectorValues )
862 QgsMeshVectorValueInterpolator( triangularMesh, datasetVectorValues, scalarActiveFaceFlagValues )
865 QgsMeshVectorValueInterpolatorFromFace::QgsMeshVectorValueInterpolatorFromFace(
const QgsMeshVectorValueInterpolatorFromFace &other ):
866 QgsMeshVectorValueInterpolator( other )
869 QgsMeshVectorValueInterpolatorFromFace *QgsMeshVectorValueInterpolatorFromFace::clone()
871 return new QgsMeshVectorValueInterpolatorFromFace( *
this );
874 QgsMeshVectorValueInterpolatorFromFace &QgsMeshVectorValueInterpolatorFromFace::operator=(
const QgsMeshVectorValueInterpolatorFromFace &other )
876 QgsMeshVectorValueInterpolator::operator=( other );
880 QgsVector QgsMeshVectorValueInterpolatorFromFace::interpolatedValuePrivate(
int faceIndex,
const QgsPointXY point )
const
882 QgsMeshFace face = mTriangularMesh.triangles().at( faceIndex );
888 QgsVector vect =
QgsVector( mDatasetValues.value( mTriangularMesh.trianglesToNativeFaces().at( faceIndex ) ).x(),
889 mDatasetValues.value( mTriangularMesh.trianglesToNativeFaces().at( faceIndex ) ).y() );
891 return QgsMeshLayerUtils::interpolateVectorFromFacesData(
899 QgsMeshVectorStreamlineRenderer::QgsMeshVectorStreamlineRenderer(
903 bool dataIsOnVertices,
907 mRendererContext( rendererContext )
909 mStreamlineField.reset(
new QgsMeshStreamlinesField( triangularMesh,
911 scalarActiveFaceFlagValues,
918 mStreamlineField->updateSize( rendererContext );
921 QgsUnitTypes::RenderUnit::RenderMillimeters ) ) ;
922 mStreamlineField->setColor( settings.
color() );
931 mStreamlineField->addTracesOnMesh( triangularMesh, rendererContext.
mapExtent() );
934 mStreamlineField->addRandomTraces();
939 void QgsMeshVectorStreamlineRenderer::draw()
941 if ( mRendererContext.renderingStopped() )
943 mRendererContext.painter()->drawImage( mStreamlineField->topLeft(), mStreamlineField->image() );
946 QgsMeshParticleTracesField::QgsMeshParticleTracesField(
const QgsTriangularMesh &triangularMesh,
951 bool dataIsOnVertices,
954 QgsMeshStreamField( triangularMesh,
956 scalarActiveFaceFlagValues,
963 std::srand( uint( ::time(
nullptr ) ) );
964 mPen.setCapStyle( Qt::RoundCap );
967 QgsMeshParticleTracesField::QgsMeshParticleTracesField(
const QgsMeshParticleTracesField &other ):
968 QgsMeshStreamField( other ),
969 mTimeField( other.mTimeField ),
970 mMagnitudeField( other.mMagnitudeField ),
971 mDirectionField( other.mDirectionField ),
972 mParticles( other.mParticles ),
973 mStumpImage( other.mStumpImage ),
974 mTimeStep( other.mTimeStep ),
975 mParticlesLifeTime( other.mParticlesLifeTime ),
976 mParticlesCount( other.mParticlesCount ),
977 mTailFactor( other.mTailFactor ),
978 mParticleColor( other.mParticleColor ),
979 mParticleSize( other.mParticleSize ),
980 mStumpFactor( other.mStumpFactor )
983 void QgsMeshParticleTracesField::addParticle(
const QPoint &startPoint,
double lifeTime )
985 addTrace( startPoint );
986 if ( time( startPoint ) > 0 )
988 QgsMeshTraceParticle p;
989 p.lifeTime = lifeTime;
990 p.position = startPoint;
991 mParticles.append( p );
996 void QgsMeshParticleTracesField::addParticleXY(
const QgsPointXY &startPoint,
double lifeTime )
998 addParticle( mMapToFieldPixel.transform( startPoint ).toQPointF().toPoint(), lifeTime );
1001 void QgsMeshParticleTracesField::moveParticles()
1004 for (
auto &p : mParticles )
1006 double spentTime = p.remainingTime;
1007 size_t countAdded = 0;
1008 while ( spentTime < mTimeStep && p.lifeTime > 0 )
1010 double timeToSpend = double( time( p.position ) );
1011 if ( timeToSpend > 0 )
1013 p.lifeTime -= timeToSpend;
1014 spentTime += timeToSpend;
1015 QPoint dir = direction( p.position );
1016 if ( p.lifeTime > 0 )
1019 p.tail.emplace_back( p.position );
1034 if ( p.lifeTime <= 0 )
1042 p.remainingTime = spentTime - mTimeStep;
1043 while (
int( p.tail.size() ) > mMinTailLength && p.tail.size() > countAdded * mTailFactor )
1044 p.tail.erase( p.tail.begin() );
1045 drawParticleTrace( p );
1051 while ( i < mParticles.count() )
1053 if ( mParticles.at( i ).tail.size() == 0 )
1054 mParticles.removeAt( i );
1060 if ( mParticles.count() < mParticlesCount )
1061 addRandomParticles();
1064 void QgsMeshParticleTracesField::addRandomParticles()
1069 if ( mParticlesCount < 0 )
1071 addParticleXY(
QgsPointXY( mMapToFieldPixel.xCenter(), mMapToFieldPixel.yCenter() ), mParticlesLifeTime );
1075 int count = mParticlesCount - mParticles.count();
1077 for (
int i = 0; i < count; ++i )
1079 int xRandom = 1 + std::rand() / int( ( RAND_MAX + 1u ) / uint( mFieldSize.width() ) ) ;
1080 int yRandom = 1 + std::rand() / int ( ( RAND_MAX + 1u ) / uint( mFieldSize.height() ) ) ;
1081 double lifeTime = ( std::rand() / ( ( RAND_MAX + 1u ) / mParticlesLifeTime ) );
1082 addParticle( QPoint( xRandom, yRandom ), lifeTime );
1086 void QgsMeshParticleTracesField::storeInField(
const QPair<QPoint, QgsMeshStreamField::FieldData> pixelData )
1088 int i = pixelData.first.x();
1089 int j = pixelData.first.y();
1090 if ( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() )
1092 mTimeField[j * mFieldSize.width() + i] = pixelData.second.time;
1093 int d = pixelData.second.directionX + 2 + ( pixelData.second.directionY + 1 ) * 3;
1094 mDirectionField[j * mFieldSize.width() + i] =
static_cast<char>( d );
1095 mMagnitudeField[j * mFieldSize.width() + i] = pixelData.second.magnitude;
1099 void QgsMeshParticleTracesField::initField()
1101 mTimeField = QVector<float>( mFieldSize.width() * mFieldSize.height(), -1 );
1102 mDirectionField = QVector<char>( mFieldSize.width() * mFieldSize.height(),
static_cast<char>(
int( 0 ) ) );
1103 mMagnitudeField = QVector<float>( mFieldSize.width() * mFieldSize.height(), 0 );
1105 mStumpImage = QImage( mFieldSize * mFieldResolution, QImage::Format_ARGB32 );
1106 mStumpImage.fill( QColor( 0, 0, 0, mStumpFactor ) );
1109 bool QgsMeshParticleTracesField::isTraceExists(
const QPoint &pixel )
const
1113 if ( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() )
1115 return mTimeField[j * mFieldSize.width() + i] >= 0;
1121 void QgsMeshParticleTracesField::setStumpParticleWithLifeTime(
bool stumpParticleWithLifeTime )
1123 mStumpParticleWithLifeTime = stumpParticleWithLifeTime;
1126 void QgsMeshParticleTracesField::setParticlesColor(
const QColor &
c )
1128 mVectorColoring.setColor(
c );
1131 void QgsMeshParticleTracesField::setMinTailLength(
int minTailLength )
1133 mMinTailLength = minTailLength;
1136 QgsMeshParticleTracesField &QgsMeshParticleTracesField::operator=(
const QgsMeshParticleTracesField &other )
1138 QgsMeshStreamField::operator=( other );
1139 mTimeField = other.mTimeField;
1140 mDirectionField = other.mDirectionField;
1141 mParticles = other.mParticles;
1142 mStumpImage = other.mStumpImage;
1143 mTimeStep = other.mTimeStep;
1144 mParticlesLifeTime = other.mParticlesLifeTime;
1145 mParticlesCount = other.mParticlesCount;
1146 mTailFactor = other.mTailFactor;
1147 mParticleColor = other.mParticleColor;
1148 mParticleSize = other.mParticleSize;
1149 mStumpFactor = other.mStumpFactor;
1154 void QgsMeshParticleTracesField::setTailFactor(
double tailFactor )
1156 mTailFactor = tailFactor;
1159 void QgsMeshParticleTracesField::setParticleSize(
double particleSize )
1161 mParticleSize = particleSize;
1164 void QgsMeshParticleTracesField::setTimeStep(
double timeStep )
1166 mTimeStep = timeStep;
1169 void QgsMeshParticleTracesField::setParticlesLifeTime(
double particlesLifeTime )
1171 mParticlesLifeTime = particlesLifeTime;
1174 QImage QgsMeshParticleTracesField::imageRendered()
const
1179 void QgsMeshParticleTracesField::stump()
1182 mPainter->setCompositionMode( QPainter::CompositionMode_DestinationIn );
1183 mPainter->drawImage( QPoint( 0, 0 ), mStumpImage );
1186 void QgsMeshParticleTracesField::setStumpFactor(
int sf )
1189 mStumpImage = QImage( mFieldSize * mFieldResolution, QImage::Format_ARGB32 );
1190 mStumpImage.fill( QColor( 0, 0, 0, mStumpFactor ) );
1193 QPoint QgsMeshParticleTracesField::direction( QPoint position )
const
1195 int i = position.x();
1196 int j = position.y();
1197 if ( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() )
1199 int dir =
static_cast<int>( mDirectionField[j * mFieldSize.width() + i] );
1200 if ( dir != 0 && dir < 10 )
1201 return QPoint( ( dir - 1 ) % 3 - 1, ( dir - 1 ) / 3 - 1 );
1203 return QPoint( 0, 0 );
1206 float QgsMeshParticleTracesField::time( QPoint position )
const
1208 int i = position.x();
1209 int j = position.y();
1210 if ( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() )
1212 return mTimeField[j * mFieldSize.width() + i];
1217 float QgsMeshParticleTracesField::magnitude( QPoint position )
const
1219 int i = position.x();
1220 int j = position.y();
1221 if ( i >= 0 && i < mFieldSize.width() && j >= 0 && j < mFieldSize.height() )
1223 return mMagnitudeField[j * mFieldSize.width() + i];
1228 void QgsMeshParticleTracesField::drawParticleTrace(
const QgsMeshTraceParticle &particle )
1230 const std::list<QPoint> &tail = particle.tail;
1231 if ( tail.size() == 0 )
1233 double iniWidth = mParticleSize;
1234 double finWidth = 0;
1236 size_t pixelCount = tail.size();
1238 double transparency = 1;
1239 if ( mStumpParticleWithLifeTime )
1240 transparency = sin( M_PI * particle.lifeTime / mParticlesLifeTime );
1243 if ( pixelCount > 1 )
1244 dw = ( iniWidth - finWidth ) / ( pixelCount );
1248 auto ip1 = std::prev( tail.end() );
1249 auto ip2 = std::prev( ip1 );
1251 while ( ip1 != tail.begin() )
1253 QPointF p1 = fieldToDevice( ( *ip1 ) );
1254 QPointF p2 = fieldToDevice( ( *ip2 ) );
1255 QColor traceColor = mVectorColoring.color( magnitude( *ip1 ) );
1256 traceColor.setAlphaF( traceColor.alphaF()*transparency );
1257 mPen.setColor( traceColor );
1258 mPen.setWidthF( iniWidth - i * dw );
1259 mPainter->setPen( mPen );
1260 mPainter->drawLine( p1, p2 );
1267 void QgsMeshParticleTracesField::setParticlesCount(
int particlesCount )
1269 mParticlesCount = particlesCount;
1275 bool dataIsOnVertices,
1280 mRendererContext( rendererContext )
1282 mParticleField = std::unique_ptr<QgsMeshParticleTracesField>(
new QgsMeshParticleTracesField( triangularMesh,
1283 dataSetVectorValues,
1284 scalarActiveFaceFlagValues,
1290 mParticleField->updateSize( rendererContext ) ;
1294 mRendererContext( rendererContext )
1301 bool vectorDataOnVertices;
1311 if ( ( cache->mDatasetGroupsCount == datasetGroupCount ) &&
1312 ( cache->mActiveVectorDatasetIndex == datasetIndex ) )
1314 vectorDatasetValues = cache->mVectorDatasetValues;
1315 scalarActiveFaceFlagValues = cache->mScalarActiveFaceFlagValues;
1316 magMax = cache->mVectorDatasetMagMaximum;
1327 if ( vectorDataOnVertices )
1332 vectorDatasetValues = QgsMeshLayerUtils::datasetValues( layer, datasetIndex, 0, count );
1340 mParticleField = std::unique_ptr<QgsMeshParticleTracesField>(
new QgsMeshParticleTracesField( ( *layer->
triangularMesh() ),
1341 vectorDatasetValues,
1342 scalarActiveFaceFlagValues,
1345 vectorDataOnVertices,
1349 mParticleField->setMinimizeFieldSize(
false );
1350 mParticleField->updateSize( mRendererContext );
1354 mRendererContext( other.mRendererContext ),
1356 mVpixMax( other.mVpixMax ),
1357 mParticleLifeTime( other.mParticleLifeTime )
1359 mParticleField = std::unique_ptr<QgsMeshParticleTracesField>(
1360 new QgsMeshParticleTracesField( *other.mParticleField ) );
1366 mParticleField->setParticlesCount( count );
1367 mParticleField->addRandomParticles();
1372 mParticleField->moveParticles();
1373 return mParticleField->image();
1383 updateFieldParameter();
1389 updateFieldParameter();
1394 mParticleLifeTime = particleLifeTime;
1395 updateFieldParameter();
1400 mParticleField->setParticlesColor(
c );
1405 mParticleField->setParticleSize( width );
1410 mParticleField->setTailFactor( fct );
1415 mParticleField->setMinTailLength( l );
1424 mParticleField->setStumpFactor(
int( 255 * p ) );
1429 mParticleField.reset(
new QgsMeshParticleTracesField( *mParticleField ) );
1430 const_cast<QgsRenderContext &
>( mRendererContext ) = other.mRendererContext;
1432 mVpixMax = other.mVpixMax;
1433 mParticleLifeTime = other.mParticleLifeTime;
1438 void QgsMeshVectorTraceAnimationGenerator::updateFieldParameter()
1440 double fieldTimeStep = mVpixMax / mFPS;
1441 double fieldLifeTime = mParticleLifeTime * mFPS * fieldTimeStep;
1442 mParticleField->setTimeStep( fieldTimeStep );
1443 mParticleField->setParticlesLifeTime( fieldLifeTime );
1446 QgsMeshVectorTraceRenderer::QgsMeshVectorTraceRenderer(
1450 bool dataIsOnVertices,
1455 mRendererContext( rendererContext )
1457 mParticleField = std::unique_ptr<QgsMeshParticleTracesField>(
new QgsMeshParticleTracesField( triangularMesh,
1458 dataSetVectorValues,
1459 scalarActiveFaceFlagValues,
1465 mParticleField->updateSize( rendererContext ) ;
1468 settings.
lineWidth(), QgsUnitTypes::RenderUnit::RenderMillimeters ) );
1470 mParticleField->setTailFactor( 1 );
1471 mParticleField->setStumpParticleWithLifeTime(
false );
1474 mParticleField->addRandomParticles();
1475 mParticleField->moveParticles();
1478 void QgsMeshVectorTraceRenderer::draw()
1480 if ( mRendererContext.renderingStopped() )
1482 mRendererContext.painter()->drawImage( mParticleField->topLeft(), mParticleField->image() );
QgsVertexIterator vertices() const
Returns a read-only, Java-style iterator for traversal of vertices of all the geometry,...
Custom exception class for Coordinate Reference System related exceptions.
Class defining color to render mesh datasets.
Perform transforms between map coordinates and device coordinates.
double mapUnitsPerPixel() const
Returns current map units per pixel.
QgsPointXY toMapCoordinates(int x, int y) const
Transform device coordinates to map (world) coordinates.
double mapRotation() const
Returns current map rotation in degrees (clockwise)
QgsMeshDataBlock is a block of integers/doubles that can be used to retrieve: active flags (e....
bool isValid() const
Whether the block is valid.
QgsMeshDatasetIndex is index that identifies the dataset group (e.g.
int group() const
Returns a group index.
virtual QgsMeshDatasetGroupMetadata datasetGroupMetadata(int groupIndex) const =0
Returns dataset group metadata.
virtual QgsMeshDataBlock areFacesActive(QgsMeshDatasetIndex index, int faceIndex, int count) const =0
Returns whether the faces are active for particular dataset.
virtual int datasetGroupCount() const =0
Returns number of datasets groups loaded.
Represents a mesh layer supporting display of data on structured or unstructured meshes.
QgsRectangle extent() const override
Returns the extent of the layer.
QgsMeshRendererSettings rendererSettings() const
Returns renderer settings.
void reload() override
Synchronises with changes in the datasource.
QgsMesh * nativeMesh()
Returns native mesh (nullptr before rendering or calling to updateMesh)
QgsMeshDatasetIndex activeVectorDatasetAtTime(const QgsDateTimeRange &timeRange) const
Returns dataset index from active vector group depending on the time range If the temporal properties...
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.
double maximumTailLength() const
Returns the maximum tail length.
QgsUnitTypes::RenderUnit maximumTailLengthUnit() const
Returns the maximum tail length unit.
int particlesCount() const
Returns particles count.
A wrapper for QgsMeshParticuleTracesField used to render the particles.
void setParticlesLifeTime(double particleLifeTime)
Sets maximum life time of particles in seconds.
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.
QgsMeshVectorTraceAnimationGenerator & operator=(const QgsMeshVectorTraceAnimationGenerator &other)
Assignment operator.
void seedRandomParticles(int count)
seeds particles in the vector fields
A class to represent a 2D point.
Point geometry type, with support for z-dimension and m-values.
A rectangle specified with double values.
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
QgsRectangle intersect(const QgsRectangle &rect) const
Returns the intersection with the given rectangle.
Contains information about the context of a rendering operation.
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
QgsRectangle mapExtent() const
Returns the original extent of the map being rendered.
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to painter units (pixels).
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
Scoped object for saving and restoring a QPainter object's state.
const QgsDateTimeRange & temporalRange() const
Returns the datetime range for the object.
Triangular/Derived Mesh is mesh with vertices in map coordinates.
const QVector< QgsMeshFace > & triangles() const
Returns triangles.
const QVector< QgsMeshVertex > & vertices() const
Returns vertices in map coordinate system.
QList< int > faceIndexesForRectangle(const QgsRectangle &rectangle) const
Finds indexes of triangles intersecting given bounding box It uses spatial indexing.
A class to represent a vector.
QgsVector rotateBy(double rot) const SIP_HOLDGIL
Rotates the vector by a specified angle.
double y() const SIP_HOLDGIL
Returns the vector's y-component.
double x() const SIP_HOLDGIL
Returns the vector's x-component.
double length() const SIP_HOLDGIL
Returns the length of the vector.
bool isInTriangleFace(const QgsPointXY point, const QgsMeshFace &face, const QVector< QgsMeshVertex > &vertices)
Tests if point p is on the face defined with vertices.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
QVector< int > QgsMeshFace
List of vertex indexes.
QVector< QgsMeshVertex > vertices
QVector< QgsMeshFace > faces