Skip to content

Commit

Permalink
fix #35147 QgsMeshLayer map canvas rotation rendering (#38795)
Browse files Browse the repository at this point in the history
fix #35147 QgsMeshLayer map canvas rotation rendering
  • Loading branch information
PeterPetrik committed Sep 17, 2020
1 parent 5ca4ef8 commit fce4b27
Show file tree
Hide file tree
Showing 24 changed files with 106 additions and 48 deletions.
2 changes: 1 addition & 1 deletion python/core/auto_generated/qgsmaptopixel.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ Set map rotation in degrees (clockwise)

double mapRotation() const;
%Docstring
Returns current map rotation in degrees
Returns current map rotation in degrees (clockwise)

.. versionadded:: 2.8
%End
Expand Down
11 changes: 5 additions & 6 deletions src/core/mesh/qgsmeshlayerrenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,11 @@ void QgsMeshLayerRenderer::calculateOutputSize()
{
// figure out image size
QgsRenderContext &context = *renderContext();
QgsRectangle extent = context.mapExtent();
QgsMapToPixel mapToPixel = context.mapToPixel();
QgsPointXY topleft = mapToPixel.transform( extent.xMinimum(), extent.yMaximum() );
QgsPointXY bottomright = mapToPixel.transform( extent.xMaximum(), extent.yMinimum() );
int width = int( bottomright.x() - topleft.x() );
int height = int( bottomright.y() - topleft.y() );
const QgsRectangle extent = context.mapExtent();
const QgsMapToPixel mapToPixel = context.mapToPixel();
const QgsRectangle screenBBox = QgsMeshLayerUtils::boundingBoxToScreenRectangle( mapToPixel, extent );
int width = int( screenBBox.width() );
int height = int( screenBBox.height() );
mOutputSize = QSize( width, height );
}

Expand Down
46 changes: 33 additions & 13 deletions src/core/mesh/qgsmeshlayerutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,20 +197,40 @@ QVector<double> QgsMeshLayerUtils::calculateMagnitudes( const QgsMeshDataBlock &
return ret;
}

void QgsMeshLayerUtils::boundingBoxToScreenRectangle( const QgsMapToPixel &mtp,
const QSize &outputSize,
const QgsRectangle &bbox,
int &leftLim,
int &rightLim,
int &topLim,
int &bottomLim )
QgsRectangle QgsMeshLayerUtils::boundingBoxToScreenRectangle(
const QgsMapToPixel &mtp,
const QgsRectangle &bbox
)
{
QgsPointXY ll = mtp.transform( bbox.xMinimum(), bbox.yMinimum() );
QgsPointXY ur = mtp.transform( bbox.xMaximum(), bbox.yMaximum() );
topLim = std::max( int( ur.y() ), 0 );
bottomLim = std::min( int( ll.y() ), outputSize.height() - 1 );
leftLim = std::max( int( ll.x() ), 0 );
rightLim = std::min( int( ur.x() ), outputSize.width() - 1 );
const QgsPointXY topLeft = mtp.transform( bbox.xMinimum(), bbox.yMaximum() );
const QgsPointXY topRight = mtp.transform( bbox.xMaximum(), bbox.yMaximum() );
const QgsPointXY bottomLeft = mtp.transform( bbox.xMinimum(), bbox.yMinimum() );
const QgsPointXY bottomRight = mtp.transform( bbox.xMaximum(), bbox.yMinimum() );

double xMin = std::min( {topLeft.x(), topRight.x(), bottomLeft.x(), bottomRight.x()} );
double xMax = std::max( {topLeft.x(), topRight.x(), bottomLeft.x(), bottomRight.x()} );
double yMin = std::min( {topLeft.y(), topRight.y(), bottomLeft.y(), bottomRight.y()} );
double yMax = std::max( {topLeft.y(), topRight.y(), bottomLeft.y(), bottomRight.y()} );

QgsRectangle ret( xMin, yMin, xMax, yMax );
return ret;
}

void QgsMeshLayerUtils::boundingBoxToScreenRectangle(
const QgsMapToPixel &mtp,
const QSize &outputSize,
const QgsRectangle &bbox,
int &leftLim,
int &rightLim,
int &bottomLim,
int &topLim )
{
const QgsRectangle screenBBox = boundingBoxToScreenRectangle( mtp, bbox );

bottomLim = std::max( int( screenBBox.yMinimum() ), 0 );
topLim = std::min( int( screenBBox.yMaximum() ), outputSize.height() - 1 );
leftLim = std::max( int( screenBBox.xMinimum() ), 0 );
rightLim = std::min( int( screenBBox.xMaximum() ), outputSize.width() - 1 );
}

static void lamTol( double &lam )
Expand Down
23 changes: 18 additions & 5 deletions src/core/mesh/qgsmeshlayerutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,16 +115,29 @@ class CORE_EXPORT QgsMeshLayerUtils
* \param mtp actual renderer map to pixel
* \param outputSize actual renderer output size
* \param bbox bounding box in map coordinates
* \param leftLim minimum x coordinate in pixel
* \param rightLim maximum x coordinate in pixel
* \param topLim minimum y coordinate in pixel
* \param bottomLim maximum y coordinate in pixel
* \param leftLim minimum x coordinate in pixel, clipped by 0
* \param rightLim maximum x coordinate in pixel, clipped by outputSize width
* \param bottomLim minimum y coordinate in pixel, clipped by 0
* \param topLim maximum y coordinate in pixel, clipped by outputSize height
*/
static void boundingBoxToScreenRectangle(
const QgsMapToPixel &mtp,
const QSize &outputSize,
const QgsRectangle &bbox,
int &leftLim, int &rightLim, int &topLim, int &bottomLim );
int &leftLim,
int &rightLim,
int &bottomLim,
int &topLim );

/**
* Transformes the bounding box to rectangle in screen coordinates (in pixels)
* \param mtp actual renderer map to pixel
* \param bbox bounding box in map coordinates
*/
static QgsRectangle boundingBoxToScreenRectangle(
const QgsMapToPixel &mtp,
const QgsRectangle &bbox
);

/**
* Interpolates value based on known values on the vertices of a edge
Expand Down
32 changes: 16 additions & 16 deletions src/core/mesh/qgsmeshtracerenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
#include "qgsmeshlayerrenderer.h"
///@cond PRIVATE

#ifndef M_DEG2RAD
#define M_DEG2RAD 0.0174532925
#endif


QgsVector QgsMeshVectorValueInterpolator::vectorValue( const QgsPointXY &point ) const
{
if ( mCacheFaceIndex != -1 && mCacheFaceIndex < mTriangularMesh.triangles().count() )
Expand Down Expand Up @@ -268,7 +273,7 @@ void QgsMeshStreamField::updateSize( const QgsRenderContext &renderContext )
}
catch ( QgsCsException &cse )
{
Q_UNUSED( cse );
Q_UNUSED( cse )
//if the transform fails, consider the whole map
layerExtent = mMapExtent;
}
Expand All @@ -288,17 +293,11 @@ void QgsMeshStreamField::updateSize( const QgsRenderContext &renderContext )
return;
}

QgsPointXY interestZoneTopLeft;
QgsPointXY interestZoneBottomRight;

interestZoneTopLeft = deviceMapToPixel.transform( QgsPointXY( interestZoneExtent.xMinimum(), interestZoneExtent.yMaximum() ) );
interestZoneBottomRight = deviceMapToPixel.transform( QgsPointXY( interestZoneExtent.xMaximum(), interestZoneExtent.yMinimum() ) );


mFieldTopLeftInDeviceCoordinates = interestZoneTopLeft.toQPointF().toPoint();
QPoint mFieldBottomRightInDeviceCoordinates = interestZoneBottomRight.toQPointF().toPoint();
int fieldWidthInDeviceCoordinate = mFieldBottomRightInDeviceCoordinates.x() - mFieldTopLeftInDeviceCoordinates.x();
int fieldHeightInDeviceCoordinate = mFieldBottomRightInDeviceCoordinates.y() - mFieldTopLeftInDeviceCoordinates.y();
QgsRectangle fieldInterestZoneInDeviceCoordinates = QgsMeshLayerUtils::boundingBoxToScreenRectangle( deviceMapToPixel, interestZoneExtent );
mFieldTopLeftInDeviceCoordinates = QPoint( int( fieldInterestZoneInDeviceCoordinates.xMinimum() ), int( fieldInterestZoneInDeviceCoordinates.yMinimum() ) );
int fieldWidthInDeviceCoordinate = int( fieldInterestZoneInDeviceCoordinates.width() );
int fieldHeightInDeviceCoordinate = int ( fieldInterestZoneInDeviceCoordinates.height() );

int fieldWidth = int( fieldWidthInDeviceCoordinate / mFieldResolution );
int fieldHeight = int( fieldHeightInDeviceCoordinate / mFieldResolution );
Expand All @@ -319,10 +318,9 @@ void QgsMeshStreamField::updateSize( const QgsRenderContext &renderContext )
mFieldSize.setHeight( fieldHeight );
}


double mapUnitPerFieldPixel;
if ( interestZoneExtent.width() > 0 )
mapUnitPerFieldPixel = interestZoneExtent.width() / fieldWidthInDeviceCoordinate * mFieldResolution;
mapUnitPerFieldPixel = deviceMapToPixel.mapUnitsPerPixel() * mFieldResolution * mFieldSize.width() / ( fieldWidthInDeviceCoordinate / mFieldResolution ) ;
else
mapUnitPerFieldPixel = 1e-8;

Expand All @@ -341,7 +339,9 @@ void QgsMeshStreamField::updateSize( const QgsRenderContext &renderContext )
xc,
yc,
fieldWidth,
fieldHeight, 0 );
fieldHeight,
deviceMapToPixel.mapRotation()
);

initField();
mValid = true;
Expand All @@ -363,8 +363,6 @@ bool QgsMeshStreamField::isValid() const

void QgsMeshStreamField::addTrace( QgsPointXY startPoint )
{
QPoint sp;
sp = mMapToFieldPixel.transform( startPoint ).toQPointF().toPoint();
addTrace( mMapToFieldPixel.transform( startPoint ).toQPointF().toPoint() );
}

Expand Down Expand Up @@ -462,8 +460,10 @@ void QgsMeshStreamField::addTrace( QPoint startPixel )
/* nondimensional value : Vu=2 when the particle need dt=1 to go through a pixel with the mMagMax magnitude
* The nondimensional size of the side of a pixel is 2
*/
vector = vector.rotateBy( -mMapToFieldPixel.mapRotation() * M_DEG2RAD );
QgsVector vu = vector / mMaximumMagnitude * 2;
data.magnitude = vector.length();

double Vx = vu.x();
double Vy = vu.y();
double Vu = data.magnitude / mMaximumMagnitude * 2; //nondimensional vector magnitude
Expand Down
5 changes: 4 additions & 1 deletion src/core/mesh/qgsmeshtracerenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,10 @@ class QgsMeshVectorValueInterpolator
//! Destructor
virtual ~QgsMeshVectorValueInterpolator() = default;

//! Returns the interpolated vector
/**
* Returns the interpolated vector
* \param point point in map coordinates
*/
virtual QgsVector vectorValue( const QgsPointXY &point ) const;

//! Assignment operator
Expand Down
10 changes: 8 additions & 2 deletions src/core/mesh/qgsmeshvectorrenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@

///@cond PRIVATE

#ifndef M_DEG2RAD
#define M_DEG2RAD 0.0174532925
#endif

inline double mag( double input )
{
if ( input < 0.0 )
Expand Down Expand Up @@ -146,7 +150,8 @@ bool QgsMeshVectorArrowRenderer::calcVectorLineEnd(

// Determine the angle of the vector, counter-clockwise, from east
// (and associated trigs)
double vectorAngle = -1.0 * atan( ( -1.0 * yVal ) / xVal );
double vectorAngle = -1.0 * atan( ( -1.0 * yVal ) / xVal ) - mContext.mapToPixel().mapRotation() * M_DEG2RAD;

cosAlpha = cos( vectorAngle ) * mag( xVal );
sinAlpha = sin( vectorAngle ) * mag( xVal );

Expand Down Expand Up @@ -487,7 +492,8 @@ QgsMeshVectorRenderer *QgsMeshVectorRenderer::makeVectorRenderer(
datasetMagMinimumValue,
dataType,
settings,
context, size );
context,
size );
break;
case QgsMeshRendererVectorSettings::Streamlines:
renderer = new QgsMeshVectorStreamlineRenderer(
Expand Down
2 changes: 1 addition & 1 deletion src/core/qgsmaptopixel.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ class CORE_EXPORT QgsMapToPixel
void setMapRotation( double degrees, double cx, double cy );

/**
* Returns current map rotation in degrees
* Returns current map rotation in degrees (clockwise)
* \since QGIS 2.8
*/
double mapRotation() const;
Expand Down
23 changes: 20 additions & 3 deletions tests/src/core/testqgsmeshlayerrenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class TestQgsMeshRenderer : public QObject
void cleanupTestCase();// will be called after the last testfunction was executed.
void init(); // will be called before each testfunction is executed.
void cleanup() {} // will be called after every testfunction.
bool imageCheck( const QString &testType, QgsMeshLayer *layer );
bool imageCheck( const QString &testType, QgsMeshLayer *layer, double rotation = 0.0 );
QString readFile( const QString &fname ) const;


Expand Down Expand Up @@ -228,12 +228,14 @@ QString TestQgsMeshRenderer::readFile( const QString &fname ) const
return uri;
}

bool TestQgsMeshRenderer::imageCheck( const QString &testType, QgsMeshLayer *layer )
bool TestQgsMeshRenderer::imageCheck( const QString &testType, QgsMeshLayer *layer, double rotation )
{
mReport += "<h2>" + testType + "</h2>\n";
mMapSettings->setExtent( layer->extent() );
mMapSettings->setDestinationCrs( layer->crs() );
mMapSettings->setExtent( layer->extent() );
mMapSettings->setRotation( rotation );
mMapSettings->setOutputDpi( 96 );

QgsRenderChecker myChecker;
myChecker.setControlPathPrefix( QStringLiteral( "mesh" ) );
myChecker.setControlName( "expected_" + testType );
Expand All @@ -253,6 +255,7 @@ void TestQgsMeshRenderer::test_native_mesh_rendering()
rendererSettings.setNativeMeshSettings( settings );
mMemoryLayer->setRendererSettings( rendererSettings );
QVERIFY( imageCheck( "quad_and_triangle_native_mesh", mMemoryLayer ) );
QVERIFY( imageCheck( "quad_and_triangle_native_mesh_rotated_45", mMemoryLayer, 45.0 ) );
}

void TestQgsMeshRenderer::test_native_mesh_renderingWithClipping()
Expand Down Expand Up @@ -287,6 +290,7 @@ void TestQgsMeshRenderer::test_triangular_mesh_rendering()
rendererSettings.setTriangularMeshSettings( settings );
mMemoryLayer->setRendererSettings( rendererSettings );
QVERIFY( imageCheck( "quad_and_triangle_triangular_mesh", mMemoryLayer ) );
QVERIFY( imageCheck( "quad_and_triangle_triangular_mesh_rotated_45", mMemoryLayer, 45.0 ) );
}

void TestQgsMeshRenderer::test_edge_mesh_rendering()
Expand Down Expand Up @@ -319,6 +323,7 @@ void TestQgsMeshRenderer::test_1d_vertex_scalar_dataset_rendering()
mMemory1DLayer->setStaticScalarDatasetIndex( ds );

QVERIFY( imageCheck( "lines_vertex_scalar_dataset", mMemory1DLayer ) );
QVERIFY( imageCheck( "lines_vertex_scalar_dataset_rotated_45", mMemory1DLayer, 45 ) );
}

void TestQgsMeshRenderer::test_1d_vertex_vector_dataset_rendering()
Expand All @@ -337,6 +342,7 @@ void TestQgsMeshRenderer::test_1d_vertex_vector_dataset_rendering()
mMemory1DLayer->setStaticVectorDatasetIndex( ds );

QVERIFY( imageCheck( "lines_vertex_vector_dataset", mMemory1DLayer ) );
QVERIFY( imageCheck( "lines_vertex_vector_dataset_rotated_45", mMemory1DLayer, 45 ) );
}

void TestQgsMeshRenderer::test_1d_edge_scalar_dataset_rendering()
Expand All @@ -357,6 +363,7 @@ void TestQgsMeshRenderer::test_1d_edge_scalar_dataset_rendering()
mMemory1DLayer->setStaticScalarDatasetIndex( ds );

QVERIFY( imageCheck( "lines_edge_scalar_dataset", mMemory1DLayer ) );
QVERIFY( imageCheck( "lines_edge_scalar_dataset_rotated_45", mMemory1DLayer, 45 ) );
}

void TestQgsMeshRenderer::test_1d_edge_vector_dataset_rendering()
Expand All @@ -370,6 +377,7 @@ void TestQgsMeshRenderer::test_1d_edge_vector_dataset_rendering()
mMemory1DLayer->setStaticVectorDatasetIndex( ds );

QVERIFY( imageCheck( "lines_edge_vector_dataset", mMemory1DLayer ) );
QVERIFY( imageCheck( "lines_edge_vector_dataset_rotated_45", mMemory1DLayer, 45 ) );
}

void TestQgsMeshRenderer::test_vertex_scalar_dataset_rendering()
Expand All @@ -383,6 +391,7 @@ void TestQgsMeshRenderer::test_vertex_scalar_dataset_rendering()
mMemoryLayer->setStaticScalarDatasetIndex( ds );

QVERIFY( imageCheck( "quad_and_triangle_vertex_scalar_dataset", mMemoryLayer ) );
QVERIFY( imageCheck( "quad_and_triangle_vertex_scalar_dataset_rotated_45", mMemoryLayer, 45.0 ) );
}

void TestQgsMeshRenderer::test_vertex_vector_dataset_rendering()
Expand All @@ -401,6 +410,7 @@ void TestQgsMeshRenderer::test_vertex_vector_dataset_rendering()
mMemoryLayer->setStaticVectorDatasetIndex( ds );

QVERIFY( imageCheck( "quad_and_triangle_vertex_vector_dataset", mMemoryLayer ) );
QVERIFY( imageCheck( "quad_and_triangle_vertex_vector_dataset_rotated_45", mMemoryLayer, 45.0 ) );
}

void TestQgsMeshRenderer::test_vertex_vector_dataset_colorRamp_rendering()
Expand Down Expand Up @@ -433,6 +443,7 @@ void TestQgsMeshRenderer::test_face_scalar_dataset_rendering()
mMemoryLayer->setStaticScalarDatasetIndex( ds );

QVERIFY( imageCheck( "quad_and_triangle_face_scalar_dataset", mMemoryLayer ) );
QVERIFY( imageCheck( "quad_and_triangle_face_scalar_dataset_rotated_45", mMemoryLayer, 45.0 ) );
}

void TestQgsMeshRenderer::test_face_scalar_dataset_interpolated_neighbour_average_rendering()
Expand Down Expand Up @@ -463,6 +474,7 @@ void TestQgsMeshRenderer::test_face_vector_dataset_rendering()
mMemoryLayer->setStaticVectorDatasetIndex( ds );

QVERIFY( imageCheck( "quad_and_triangle_face_vector_dataset", mMemoryLayer ) );
QVERIFY( imageCheck( "quad_and_triangle_face_vector_dataset_rotated_45", mMemoryLayer, 45.0 ) );
}

void TestQgsMeshRenderer::test_vertex_scalar_dataset_with_inactive_face_rendering()
Expand Down Expand Up @@ -496,6 +508,7 @@ void TestQgsMeshRenderer::test_face_vector_on_user_grid()
mMemoryLayer->setStaticVectorDatasetIndex( ds );

QVERIFY( imageCheck( "quad_and_triangle_face_vector_user_grid_dataset", mMemoryLayer ) );
QVERIFY( imageCheck( "quad_and_triangle_face_vector_user_grid_dataset_rotated_45", mMemoryLayer, 45.0 ) );
}

void TestQgsMeshRenderer::test_face_vector_on_user_grid_streamlines()
Expand All @@ -516,6 +529,7 @@ void TestQgsMeshRenderer::test_face_vector_on_user_grid_streamlines()
mMemoryLayer->setStaticVectorDatasetIndex( ds );

QVERIFY( imageCheck( "quad_and_triangle_face_vector_user_grid_dataset_streamlines", mMemoryLayer ) );
QVERIFY( imageCheck( "quad_and_triangle_face_vector_user_grid_dataset_streamlines_rotated_45", mMemoryLayer, 45.0 ) );
}

void TestQgsMeshRenderer::test_vertex_vector_on_user_grid()
Expand All @@ -537,6 +551,7 @@ void TestQgsMeshRenderer::test_vertex_vector_on_user_grid()
mMemoryLayer->setStaticVectorDatasetIndex( ds );

QVERIFY( imageCheck( "quad_and_triangle_vertex_vector_user_grid_dataset", mMemoryLayer ) );
QVERIFY( imageCheck( "quad_and_triangle_vertex_vector_user_grid_dataset_rotated_45", mMemoryLayer, 45.0 ) );
}

void TestQgsMeshRenderer::test_vertex_vector_on_user_grid_streamlines()
Expand All @@ -558,6 +573,7 @@ void TestQgsMeshRenderer::test_vertex_vector_on_user_grid_streamlines()
mMemoryLayer->setStaticVectorDatasetIndex( ds );

QVERIFY( imageCheck( "quad_and_triangle_vertex_vector_user_grid_dataset_streamlines", mMemoryLayer ) );
QVERIFY( imageCheck( "quad_and_triangle_vertex_vector_user_grid_dataset_streamlines_rotated_45", mMemoryLayer, 45.0 ) );
}

void TestQgsMeshRenderer::test_vertex_vector_on_user_grid_streamlines_colorRamp()
Expand Down Expand Up @@ -606,6 +622,7 @@ void TestQgsMeshRenderer::test_vertex_vector_traces()
mMemoryLayer->setStaticVectorDatasetIndex( ds );

QVERIFY( imageCheck( "quad_and_triangle_vertex_vector_traces", mMemoryLayer ) );
QVERIFY( imageCheck( "quad_and_triangle_vertex_vector_traces_rotated_45", mMemoryLayer, 45.0 ) );
}

void TestQgsMeshRenderer::test_vertex_vector_traces_colorRamp()
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit fce4b27

Please sign in to comment.