Skip to content
Permalink
Browse files

Fix 2.5D renderer problem when order of walls matters

E.g. when the walls have different styles
  • Loading branch information
m-kuhn committed Jan 15, 2016
1 parent ffc80b1 commit a2030d53fe62110676f5d03c4ea04c605a382dea
@@ -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)"
}
]
}
@@ -46,6 +46,7 @@
#include "qgsmultilinestringv2.h"
#include "qgscurvepolygonv2.h"
#include "qgsexpressionprivate.h"
#include "qgsexpressionsorter.h"

#if QT_VERSION < 0x050000
#include <qtextdocument.h>
@@ -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 );
@@ -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" )
@@ -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()
@@ -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 );
@@ -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();

0 comments on commit a2030d5

Please sign in to comment.
You can’t perform that action at this time.