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

Line-dasharray Impl. #39

Closed
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
2 changes: 1 addition & 1 deletion lib/src/features/fill_renderer.dart
Expand Up @@ -31,7 +31,7 @@ class FillRenderer extends FeatureRenderer {
final fillPaint = style.fillPaint?.evaluate(evaluationContext);
final outlinePaint = style.outlinePaint?.evaluate(evaluationContext);

final polygons = feature.paths;
final polygons = feature.getPaths();

for (final polygon in polygons) {
if (!context.optimizations.skipInBoundsChecks &&
Expand Down
6 changes: 5 additions & 1 deletion lib/src/features/line_renderer.dart
Expand Up @@ -47,7 +47,11 @@ class LineRenderer extends FeatureRenderer {
effectivePaint.strokeWidth =
context.tileSpaceMapper.widthFromPixelToTile(strokeWidth);

final lines = feature.paths;
final dashLengths = effectivePaint.strokeDashPattern
.map((e) => context.tileSpaceMapper.widthFromPixelToTile(e))
.toList(growable: false);

final lines = feature.getPaths(dashLengths: dashLengths);

for (final line in lines) {
if (!context.optimizations.skipInBoundsChecks &&
Expand Down
2 changes: 1 addition & 1 deletion lib/src/features/symbol_line_renderer.dart
Expand Up @@ -29,7 +29,7 @@ class SymbolLineRenderer extends FeatureRenderer {
return;
}

final lines = feature.paths;
final lines = feature.getPaths();
if (lines.isEmpty) {
return;
}
Expand Down
25 changes: 25 additions & 0 deletions lib/src/model/path_utils.dart
@@ -0,0 +1,25 @@
import 'dart:ui';

import 'ring_number_provider.dart';

extension DashPath on Path {
// convert a path into a dashed path with given intervals
Path dashPath(RingNumberProvider dashArray) {
final Path dest = Path();
for (final PathMetric metric in this.computeMetrics()) {
double distance = .0;
bool draw = true;
while (distance < metric.length) {
final double len = dashArray.next;
if (draw) {
dest.addPath(
metric.extractPath(distance, distance + len), Offset.zero);
}
distance += len;
draw = !draw;
}
}

return dest;
}
}
13 changes: 13 additions & 0 deletions lib/src/model/ring_number_provider.dart
@@ -0,0 +1,13 @@
class RingNumberProvider {
RingNumberProvider(this._vals);

final List<double> _vals;
int _idx = 0;

double get next {
if (_idx >= _vals.length) {
_idx = 0;
}
return _vals[_idx++];
}
}
11 changes: 9 additions & 2 deletions lib/src/model/tile_model.dart
@@ -1,5 +1,7 @@
import 'dart:ui';

import 'ring_number_provider.dart';
import 'path_utils.dart';
import 'geometry_model.dart';
import 'geometry_model_ui.dart';

Expand Down Expand Up @@ -56,7 +58,7 @@ class TileFeature {

bool get hasPoints => type == TileFeatureType.point;

List<Path> get paths {
List<Path> getPaths({List<double> dashLengths = const []}) {
if (type == TileFeatureType.point) {
throw StateError('Cannot get paths from a point feature');
}
Expand All @@ -78,7 +80,12 @@ class TileFeature {
.toList(growable: false);
_modelPolygons = null;
}
return _paths;

if (dashLengths.length >= 2) {
return _paths.map((e) => e.dashPath(RingNumberProvider(dashLengths))).toList();
} else {
return _paths;
}
}
}

Expand Down
34 changes: 27 additions & 7 deletions lib/src/themes/paint_factory.dart
Expand Up @@ -6,14 +6,14 @@ import 'expression/expression.dart';
import 'expression/literal_expression.dart';
import 'expression/numeric_expression.dart';

class PaintExpression extends Expression<Paint> {
class PaintExpression extends Expression<PaintModel> {
final PaintStyle _delegate;

PaintExpression(this._delegate)
: super(_cacheKey(_delegate), _properties(_delegate));

@override
Paint? evaluate(EvaluationContext context) => _delegate.paint(context);
PaintModel? evaluate(EvaluationContext context) => _delegate.paint(context);

@override
bool get isConstant => false;
Expand All @@ -28,21 +28,27 @@ class PaintExpression extends Expression<Paint> {
};
}

class PaintModel extends Paint {
List<double> strokeDashPattern = [];
}

class PaintStyle {
final String id;
final PaintingStyle paintingStyle;
final Expression<double> opacity;
final Expression<double> strokeWidth;
final Expression<Color> color;
final List<double> strokeDashPattern;

PaintStyle(
{required this.id,
required this.paintingStyle,
required this.opacity,
required this.strokeWidth,
required this.color});
required this.color,
required this.strokeDashPattern});

Paint? paint(EvaluationContext context) {
PaintModel? paint(EvaluationContext context) {
final opacity = this.opacity.evaluate(context);
if (opacity != null && opacity <= 0) {
return null;
Expand All @@ -51,7 +57,9 @@ class PaintStyle {
if (color == null) {
return null;
}
final paint = Paint()..style = paintingStyle;
final paint = PaintModel()
..style = paintingStyle
..strokeDashPattern = strokeDashPattern;
if (opacity != null && opacity < 1.0) {
paint.color = color.withOpacity(opacity);
} else {
Expand All @@ -73,7 +81,7 @@ class PaintFactory {
final ExpressionParser expressionParser;
PaintFactory(this.logger) : expressionParser = ExpressionParser(logger);

Expression<Paint>? create(
Expression<PaintModel>? create(
String id, PaintingStyle style, String prefix, paint,
{double? defaultStrokeWidth = 1.0}) {
if (paint == null) {
Expand All @@ -87,11 +95,23 @@ class PaintFactory {
whenNull: () => LiteralExpression(1.0));
final strokeWidth = expressionParser.parse(paint['$prefix-width'],
whenNull: () => LiteralExpression(defaultStrokeWidth));

List<double> dashArray = [];
final dashJson = paint['$prefix-dasharray'];
if (dashJson != null && dashJson is List<num> && dashJson.length >= 2) {
if (dashJson.any((element) => element < .0)) {
logger.warn(() => '$prefix-dasharray contains value < 0');
} else {
dashArray = dashJson.map((e) => e.toDouble()).toList(growable: false);
}
}

return PaintExpression(PaintStyle(
id: id,
paintingStyle: style,
opacity: opacity.asDoubleExpression(),
strokeWidth: strokeWidth.asDoubleExpression(),
color: color.asColorExpression()));
color: color.asColorExpression(),
strokeDashPattern: dashArray));
}
}
9 changes: 5 additions & 4 deletions lib/src/themes/style.dart
Expand Up @@ -4,6 +4,7 @@ import 'dart:math';
import 'dart:ui';

import 'package:flutter/widgets.dart';
import 'package:vector_tile_renderer/src/themes/paint_factory.dart';
import 'expression/expression.dart';

import '../extensions.dart';
Expand All @@ -12,14 +13,14 @@ typedef ColorZoomFunction = Color? Function(double zoom);
typedef TextTransformFunction = String? Function(String? text);

class Style {
final Expression<Paint>? fillPaint;
final Expression<PaintModel>? fillPaint;
final Extrusion? fillExtrusion;
final Expression<Paint>? linePaint;
final Expression<PaintModel>? linePaint;
final LineLayout? lineLayout;
final Expression<Paint>? textPaint;
final Expression<PaintModel>? textPaint;
final TextLayout? textLayout;
final Expression<List<Shadow>>? textHalo;
final Expression<Paint>? outlinePaint;
final Expression<PaintModel>? outlinePaint;

Style(
{this.fillPaint,
Expand Down
2 changes: 1 addition & 1 deletion lib/src/tileset.dart
Expand Up @@ -59,7 +59,7 @@ class TilesetPreprocessor {
if (_initializeGeometry) {
for (final feature in features) {
if (feature.feature.hasPaths) {
feature.feature.paths;
feature.feature.getPaths();
} else if (feature.feature.hasPoints) {
feature.feature.points;
}
Expand Down