Skip to content

Commit

Permalink
Fix 2.5D renderer problem when order of walls matters
Browse files Browse the repository at this point in the history
E.g. when the walls have different styles
  • Loading branch information
m-kuhn committed Jan 15, 2016
1 parent ffc80b1 commit a2030d5
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 12 deletions.
20 changes: 20 additions & 0 deletions resources/function_help/json/order_parts
@@ -0,0 +1,20 @@
{
"name": "order_parts",
"type": "function",
"description": "Orders the parts of a MultiGeometry by a given criteria",
"arguments": [
{"arg":"geom","description":"a multi-type geometry"},
{"arg":"orderby","description":"an expression string defining the order criteria"},
{"arg":"ascending","description":"boolean, True for ascending, False for descending"}
],
"examples": [
{
"expression":"order_parts(geom_from_wkt('MultiPolygon (((1 1, 5 1, 5 5, 1 5, 1 1)),((1 1, 9 1, 9 9, 1 9, 1 1)))'), 'area($geometry)', False)",
"returns":"MultiPolygon (((1 1, 9 1, 9 9, 1 9, 1 1)),((1 1, 5 1, 5 5, 1 5, 1 1)))"
},
{
"expression":"order_parts(geom_from_wkt('LineString(1 2, 3 2, 4 3)'), '1', True)",
"returns":"LineString(1 2, 3 2, 4 3)"
}
]
}
66 changes: 66 additions & 0 deletions src/core/qgsexpression.cpp
Expand Up @@ -46,6 +46,7 @@
#include "qgsmultilinestringv2.h"
#include "qgscurvepolygonv2.h"
#include "qgsexpressionprivate.h"
#include "qgsexpressionsorter.h"

#if QT_VERSION < 0x050000
#include <qtextdocument.h>
Expand Down Expand Up @@ -2168,6 +2169,70 @@ static QVariant fcnExtrude( const QVariantList& values, const QgsExpressionConte
return result;
}

static QVariant fcnOrderParts( const QVariantList& values, const QgsExpressionContext* ctx, QgsExpression* parent )
{
if ( values.length() < 2 )
return QVariant();

QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );

if ( !fGeom.isMultipart() )
return values.at( 0 );

QString expString = getStringValue( values.at( 1 ), parent );
bool asc = values.value( 2 ).toBool();

QgsExpressionContext* unconstedContext;
QgsFeature f;
if ( ctx )
{
// ExpressionSorter wants a modifiable expression context, but it will return it in the same shape after
// so no reason to worry
unconstedContext = const_cast<QgsExpressionContext*>( ctx );
f = ctx->feature();
}
else
{
// If there's no context provided, create a fake one
unconstedContext = new QgsExpressionContext();
}

QgsGeometryCollectionV2* collection = dynamic_cast<QgsGeometryCollectionV2*>( fGeom.geometry() );
Q_ASSERT( collection ); // Should have failed the multipart check above

QgsFeatureRequest::OrderBy orderBy;
orderBy.append( QgsFeatureRequest::OrderByClause( expString, asc ) );
QgsExpressionSorter sorter( orderBy );

QList<QgsFeature> partFeatures;
for ( int i = 0; i < collection->partCount(); ++i )
{
f.setGeometry( QgsGeometry( collection->geometryN( i )->clone() ) );
partFeatures << f;
}

sorter.sortFeatures( partFeatures, unconstedContext );

QgsGeometryCollectionV2* orderedGeom = dynamic_cast<QgsGeometryCollectionV2*>( fGeom.geometry()->clone() );

Q_ASSERT( orderedGeom );

while ( orderedGeom->partCount() )
orderedGeom->removeGeometry( 0 );

Q_FOREACH ( const QgsFeature& feature, partFeatures )
{
orderedGeom->addGeometry( feature.constGeometry()->geometry()->clone() );
}

QVariant result = QVariant::fromValue( QgsGeometry( orderedGeom ) );

if ( !ctx )
delete unconstedContext;

return result;
}

static QVariant fcnClosestPoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
{
QgsGeometry fromGeom = getGeometry( values.at( 0 ), parent );
Expand Down Expand Up @@ -2954,6 +3019,7 @@ const QList<QgsExpression::Function*>& QgsExpression::Functions()
<< new StaticFunction( "geometry", 1, fcnGetGeometry, "GeometryGroup", QString(), true )
<< new StaticFunction( "transform", 3, fcnTransformGeometry, "GeometryGroup" )
<< new StaticFunction( "extrude", 3, fcnExtrude, "GeometryGroup", QString() )
<< new StaticFunction( "order_parts", 3, fcnOrderParts, "GeometryGroup", QString() )
<< new StaticFunction( "closest_point", 2, fcnClosestPoint, "GeometryGroup" )
<< new StaticFunction( "shortest_line", 2, fcnShortestLine, "GeometryGroup" )
<< new StaticFunction( "$rownum", 0, fcnRowNumber, "deprecated" )
Expand Down
31 changes: 19 additions & 12 deletions src/core/symbology-ng/qgs25drenderer.cpp
Expand Up @@ -28,10 +28,24 @@
")"

#define WALL_EXPRESSION \
"extrude(" \
" segments_to_lines( exterior_ring( $geometry ) )," \
" cos( radians( eval( @qgis_25d_angle ) ) ) * eval( @qgis_25d_height )," \
" sin( radians( eval( @qgis_25d_angle ) ) ) * eval( @qgis_25d_height )" \
"order_parts( "\
" extrude(" \
" segments_to_lines( exterior_ring( $geometry ) )," \
" cos( radians( eval( @qgis_25d_angle ) ) ) * eval( @qgis_25d_height )," \
" sin( radians( eval( @qgis_25d_angle ) ) ) * eval( @qgis_25d_height )" \
" )," \
" 'distance( $geometry, translate( @map_extent_center, 1000 * @map_extent_width * cos( radians( @qgis_25d_angle + 180 ) ), 1000 * @map_extent_width * sin( radians( @qgis_25d_angle + 180 ) ) ))'," \
" False" \
")"

#define ORDER_BY_EXPRESSION \
"distance(" \
" $geometry," \
" translate(" \
" @map_extent_center," \
" 1000 * @map_extent_width * cos( radians( @qgis_25d_angle + 180 ) )," \
" 1000 * @map_extent_width * sin( radians( @qgis_25d_angle + 180 ) )" \
" )" \
")"

Qgs25DRenderer::Qgs25DRenderer()
Expand Down Expand Up @@ -75,14 +89,7 @@ Qgs25DRenderer::Qgs25DRenderer()

QgsFeatureRequest::OrderBy orderBy;
orderBy << QgsFeatureRequest::OrderByClause(
"distance("
" $geometry,"
" translate("
" @map_extent_center,"
" 1000 * @map_extent_width * cos( radians( @qgis_25d_angle + 180 ) ),"
" 1000 * @map_extent_width * sin( radians( @qgis_25d_angle + 180 ) )"
" )"
")",
ORDER_BY_EXPRESSION,
false );

setOrderBy( orderBy );
Expand Down
3 changes: 3 additions & 0 deletions tests/src/core/testqgsexpression.cpp
Expand Up @@ -586,6 +586,9 @@ class TestQgsExpression: public QObject
QTest::newRow( "extrude geom" ) << "geom_to_wkt(extrude( geom_from_wkt('LineString( 1 2, 3 2, 4 3)'),1,2))" << false << QVariant( "Polygon ((1 2, 3 2, 4 3, 5 5, 4 4, 2 4, 1 2))" );
QTest::newRow( "extrude not geom" ) << "extrude('g',5,6)" << true << QVariant();
QTest::newRow( "extrude null" ) << "extrude(NULL,5,6)" << false << QVariant();
QTest::newRow( "order parts" ) << "geom_to_wkt(order_parts(geom_from_wkt('MultiPolygon (((1 1, 5 1, 5 5, 1 5, 1 1)),((1 1, 9 1, 9 9, 1 9, 1 1)))'), 'area($geometry)', False ) )" << false << QVariant( "MultiPolygon (((1 1, 9 1, 9 9, 1 9, 1 1)),((1 1, 5 1, 5 5, 1 5, 1 1)))" );
QTest::newRow( "order parts not geom" ) << "order_parts('g', 'area($geometry)', False )" << true << QVariant();
QTest::newRow( "order parts single geom" ) << "geom_to_wkt(order_parts(geom_from_wkt('POLYGON((2 0,2 2, 3 2, 3 0, 2 0))'), 'area($geometry)', False))" << false << QVariant( "Polygon ((2 0, 2 2, 3 2, 3 0, 2 0))" );
QTest::newRow( "closest_point geom" ) << "geom_to_wkt(closest_point( geom_from_wkt('LineString( 1 1, 5 1, 5 5 )'),geom_from_wkt('Point( 6 3 )')))" << false << QVariant( "Point (5 3)" );
QTest::newRow( "closest_point not geom" ) << "closest_point('g','b')" << true << QVariant();
QTest::newRow( "closest_point null" ) << "closest_point(NULL,NULL)" << false << QVariant();
Expand Down

0 comments on commit a2030d5

Please sign in to comment.