Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decode tile features to dart:ui and render in tile space #12

Merged
merged 6 commits into from Feb 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion lib/src/context.dart
Expand Up @@ -2,6 +2,7 @@ import 'dart:ui';

import 'features/feature_renderer.dart';
import 'features/label_space.dart';
import 'features/tile_space_mapper.dart';
import 'logger.dart';
import 'model/tile_model.dart';
import 'tileset.dart';
Expand All @@ -15,7 +16,8 @@ class Context {
final double zoom;
final Rect tileSpace;
final Rect tileClip;
late final LabelSpace labelSpace;
final LabelSpace labelSpace;
late TileSpaceMapper tileSpaceMapper;

Context(this.logger, this.canvas, this.featureRenderer, this.tileset,
this.zoomScaleFactor, this.zoom, this.tileSpace, this.tileClip)
Expand Down
18 changes: 14 additions & 4 deletions lib/src/features/feature_renderer.dart
Expand Up @@ -9,8 +9,13 @@ import 'symbol_line_renderer.dart';
import 'symbol_point_renderer.dart';

abstract class FeatureRenderer {
void render(Context context, ThemeLayerType layerType, Style style,
TileLayer layer, TileFeature feature);
void render(
Context context,
ThemeLayerType layerType,
Style style,
TileLayer layer,
TileFeature feature,
);
}

class FeatureDispatcher extends FeatureRenderer {
Expand All @@ -22,8 +27,13 @@ class FeatureDispatcher extends FeatureRenderer {
: typeToRenderer = createDispatchMapping(logger),
symbolTypeToRenderer = createSymbolDispatchMapping(logger);

void render(Context context, ThemeLayerType layerType, Style style,
TileLayer layer, TileFeature feature) {
void render(
Context context,
ThemeLayerType layerType,
Style style,
TileLayer layer,
TileFeature feature,
) {
final rendererMapping = layerType == ThemeLayerType.symbol
? symbolTypeToRenderer
: typeToRenderer;
Expand Down
66 changes: 42 additions & 24 deletions lib/src/features/line_renderer.dart
@@ -1,46 +1,64 @@
import 'dart:ui';

import '../themes/expression/expression.dart';

import '../../vector_tile_renderer.dart';
import '../constants.dart';
import '../context.dart';
import '../themes/expression/expression.dart';
import '../themes/style.dart';
import 'feature_renderer.dart';
import 'points_extension.dart';

class LineRenderer extends FeatureRenderer {
final Logger logger;

LineRenderer(this.logger);

@override
void render(Context context, ThemeLayerType layerType, Style style,
TileLayer layer, TileFeature feature) {
void render(
Context context,
ThemeLayerType layerType,
Style style,
TileLayer layer,
TileFeature feature,
) {
if (style.linePaint == null) {
logger.warn(() =>
'line does not have a line paint for vector tile layer ${layer.name}');
return;
}
logger.log(() => 'rendering linestring');
final path = Path();
for (final line in feature.lines) {
path.addPolygon(line.toPoints(layer.extent, tileSize), false);
}
if (!_isWithinClip(context, path)) {

final evaluationContext = EvaluationContext(
() => feature.properties,
feature.type,
context.zoom,
logger,
);

final effectivePaint = style.linePaint?.paint(evaluationContext);
if (effectivePaint == null) {
return;
}
var effectivePaint = style.linePaint!.paint(EvaluationContext(
() => feature.properties, feature.type, context.zoom, logger));
if (effectivePaint != null) {
if (context.zoomScaleFactor > 1.0) {
effectivePaint.strokeWidth =
effectivePaint.strokeWidth / context.zoomScaleFactor;

var strokeWidth = effectivePaint.strokeWidth;
if (context.zoomScaleFactor > 1.0) {
strokeWidth = effectivePaint.strokeWidth / context.zoomScaleFactor;
}

// Since we are rendering in tile space, we need to render lines with
// a stroke width in tile space.
effectivePaint.strokeWidth =
context.tileSpaceMapper.widthFromPixelToTile(strokeWidth);

final lines = feature.paths;

if (lines.length == 1) {
logger.log(() => 'rendering linestring');
} else if (lines.length > 1) {
logger.log(() => 'rendering multi-linestring');
}

for (final line in lines) {
if (!context.tileSpaceMapper.isPathWithinTileClip(line)) {
continue;
}
context.canvas.drawPath(path, effectivePaint);

context.canvas.drawPath(line, effectivePaint);
}
}

bool _isWithinClip(Context context, Path path) =>
context.tileClip.overlaps(path.getBounds());
}
11 changes: 0 additions & 11 deletions lib/src/features/points_extension.dart

This file was deleted.

37 changes: 17 additions & 20 deletions lib/src/features/polygon_renderer.dart
@@ -1,59 +1,56 @@
import 'dart:ui';

import '../../vector_tile_renderer.dart';
import '../constants.dart';
import '../context.dart';
import '../themes/expression/expression.dart';
import '../themes/style.dart';
import 'points_extension.dart';
import 'feature_renderer.dart';

class PolygonRenderer extends FeatureRenderer {
final Logger logger;
PolygonRenderer(this.logger);

@override
void render(Context context, ThemeLayerType layerType, Style style,
TileLayer layer, TileFeature feature) {
void render(
Context context,
ThemeLayerType layerType,
Style style,
TileLayer layer,
TileFeature feature,
) {
if (style.fillPaint == null && style.outlinePaint == null) {
logger
.warn(() => 'polygon does not have a fill paint or an outline paint');
return;
}

final polygons = feature.polygons;
final evaluationContext = EvaluationContext(
() => feature.properties,
feature.type,
context.zoom,
logger,
);
final fillPaint = style.fillPaint?.paint(evaluationContext);
final outlinePaint = style.outlinePaint?.paint(evaluationContext);

final polygons = feature.paths;

if (polygons.length == 1) {
logger.log(() => 'rendering polygon');
} else if (polygons.length > 1) {
logger.log(() => 'rendering multi-polygon');
}

for (final polygon in feature.polygons) {
final path = Path();
for (final ring in polygon) {
path.addPolygon(ring.toPoints(layer.extent, tileSize), true);
}
if (!_isWithinClip(context, path)) {
for (final polygon in polygons) {
if (!context.tileSpaceMapper.isPathWithinTileClip(polygon)) {
continue;
}
final fillPaint = style.fillPaint?.paint(evaluationContext);

if (fillPaint != null) {
context.canvas.drawPath(path, fillPaint);
context.canvas.drawPath(polygon, fillPaint);
}
final outlinePaint = style.outlinePaint?.paint(evaluationContext);

if (outlinePaint != null) {
context.canvas.drawPath(path, outlinePaint);
context.canvas.drawPath(polygon, outlinePaint);
}
}
}

bool _isWithinClip(Context context, Path path) =>
context.tileClip.overlaps(path.getBounds());
}