LineString class
A LineString is a curve with linear interpolation between points.
class LineString extends Geometry with IterableMixin<Point>, _GeometryContainerMixin { List<Point> _points; _init(points) { if (points == null || points.isEmpty) { _points = null; } else { _require(points.length >= 2, "illegal number of points, got ${points.length}"); _require(points.every((p) => p != null && !p.isEmpty), "points must not contain null values or empty points"); _points = new List.from(points,growable:false); } } /** * Creates a new linestring. * * Creates an empty linestring if [points] is null or empty. * * Throws an [ArgumentError] if [points] contains only one * point or if it contains null values or empty points. */ LineString(List<Point> points) { _init(points); } /** * Creates a new line. * * A line is a linestring with exactly two non-null, non-empty, * non-equal [points]. * * Throws an [ArgumentError] if one of these conditions isn't met. */ LineString.line(List<Point> points) { _require(points != null); _require(points.length == 2); _require(points.every((p) => p != null && ! p.isEmpty)); _require(! points.first.equals2D(points.last)); _points = new List.from(points,growable:false); } /** * Creates a new linear ring. * * A linear ring is a linestring that is both closed and simple. * As a consequence, it must have at least four nodes. * * Throws an [ArgumentError] if the [points] passed in do not represent * a linear ring. */ LineString.ring(List<Point> points) { _init(points); _require(!this.isEmpty, "a ring can't be empty"); _require(this.length >= 4, "a ring must have at least four nodes"); _require(this.isClosed, "a ring must be closed"); //TODO: not yet implemented //_require(this.isSimple, "a ring must be simple"); } /** * Creates a new linestring from the WKT string [wkt]. * * Throws a [WKTError] if [wkt] isn't a valid representation of * a [LineString]. */ factory LineString.wkt(String wkt) { var g = parseWKT(wkt); if (g is! LineString) { throw new WKTError("WKT string doesn't represent a LineString"); } return g; } /** * Creates an empty linestring. */ factory LineString.empty() => _EMPTY_LINESTRING; Iterator<Point> get iterator => _points == null ? [].iterator : _points.iterator; @override String get geometryType => "LineString"; @override int get dimension => 1; /** * Replies the number of points in this linestring. * * See also [length] */ @specification(name:"numPoints()") int numPoints() => length; /** * Replies the n-th point this linestring. * * See also [elementAt] */ @specification(name:"pointN()") Point pointN(int n) => elementAt(n); /** * Replies the (spatial) length of this line string. */ @specification(name:"length()") //TODO: implement num get spatialLength { throw new UnimplementedError(); } /** * Replies the start point of this linestring. * * See also the Dart'ish property [first]. * * Throws a [StateError] if this linestring is empty. */ @specification(name:"StartPoint()") Point get startPoint => first; /** * Replies the end point of this linestring. * * See also the Dart'ish property [last]. * * Throws a [StateError] if this linestring is empty. */ @specification(name:"EndPoint()") Point get endPoint => last; /** * Replies true if this linestring isn't empty and its * first and last points are equal (with respect to the xy-coordinates) */ bool get isClosed { if (this.isEmpty) return false; return first.equals2D(last); } /** * Replies true if this linestring is closed and simple. * */ //TODO: implement bool get isRing { throw new UnimplementedError(); } _writeWKT(writer, {bool withZ:false, bool withM:false}) { if (isEmpty) { writer.empty(); } else { writer.lparen(); for (int i=0; i< length; i++) { if (i > 0) {writer.comma(); writer.blank();} this.elementAt(i)._writeCoordinates(writer, withZ: withZ, withM: withM); } writer.rparen(); } } _writeTaggedWKT(writer, {bool withZ:false, bool withM:false}) { writer.write("LINESTRING"); writer.blank(); if (! isEmpty) { writer.ordinateSpecification(withZ: withZ, withM: withM); } _writeWKT(writer, withZ: is3D, withM: isMeasured); } /** * The boundary is empty if this linestring [isEmpty] * or [isClosed]. Otherwise it consists of a * [MultiPoint] with the two end points. */ @override Geometry get boundary { if (this.isEmpty) return new GeometryCollection.empty(); if (this.isClosed) return new GeometryCollection.empty(); return new MultiPoint([first, last]); } }
Extends
Geometry > Geometry_IterableMixin > Geometry_IterableMixin__GeometryContainerMixin > LineString
Subclasses
Constructors
new LineString(List<Point> points) #
Creates a new linestring.
Creates an empty linestring if points is null or empty.
Throws an ArgumentError
if
points contains only one
point or if it contains null values or empty points.
LineString(List<Point> points) { _init(points); }
factory LineString.empty() #
Creates an empty linestring.
factory LineString.empty() => _EMPTY_LINESTRING;
new LineString.line(List<Point> points) #
Creates a new line.
A line is a linestring with exactly two non-null, non-empty, non-equal points.
Throws an ArgumentError
if one of these conditions isn't met.
LineString.line(List<Point> points) { _require(points != null); _require(points.length == 2); _require(points.every((p) => p != null && ! p.isEmpty)); _require(! points.first.equals2D(points.last)); _points = new List.from(points,growable:false); }
new LineString.ring(List<Point> points) #
Creates a new linear ring.
A linear ring is a linestring that is both closed and simple. As a consequence, it must have at least four nodes.
Throws an ArgumentError
if the
points passed in do not represent
a linear ring.
LineString.ring(List<Point> points) { _init(points); _require(!this.isEmpty, "a ring can't be empty"); _require(this.length >= 4, "a ring must have at least four nodes"); _require(this.isClosed, "a ring must be closed"); //TODO: not yet implemented //_require(this.isSimple, "a ring must be simple"); }
factory LineString.wkt(String wkt) #
Creates a new linestring from the WKT string wkt.
Throws a WKTError if wkt isn't a valid representation of a LineString.
factory LineString.wkt(String wkt) { var g = parseWKT(wkt); if (g is! LineString) { throw new WKTError("WKT string doesn't represent a LineString"); } return g; }
Properties
final String asText #
A WKT representation of the geometry
@specification(name:"asText()") String get asText { var buffer = new StringBuffer(); var writer = new _WKTWriter(buffer); _writeTaggedWKT(writer, withZ: is3D, withM: isMeasured); return buffer.toString(); }
final Geometry boundary #
The boundary is empty if this linestring isEmpty
or isClosed. Otherwise it consists of a
MultiPoint with the two end points.
@override Geometry get boundary { if (this.isEmpty) return new GeometryCollection.empty(); if (this.isClosed) return new GeometryCollection.empty(); return new MultiPoint([first, last]); }
final int dimension #
The inherent dimension of this geometric object, which must be less than or equal to the coordinate dimension. In non-homogeneous collections, this will return the largest topological dimension of the contained objects.
@override int get dimension => 1;
final Point endPoint #
Replies the end point of this linestring.
See also the Dart'ish property last
.
Throws a StateError
if this linestring is empty.
@specification(name:"EndPoint()") Point get endPoint => last;
final E first #
final String geometryType #
Returns the name of the instantiable subtype of Geometry of which this geometric object is an instantiable member. The name of the subtype of Geometry is returned as a string.
@override String get geometryType => "LineString";
final bool is3D #
A collection of geometries is considered 3D if every child geometry has a non-null z-component.
The value of this property is computed upon first access and then cached. Subsequent reads of the property efficiently reply the cached value.
@override bool get is3D { if (_is3D == null) _computeIs3D(); return _is3D; }
final bool isClosed #
Replies true if this linestring isn't empty and its first and last points are equal (with respect to the xy-coordinates)
bool get isClosed { if (this.isEmpty) return false; return first.equals2D(last); }
final bool isEmpty #
Returns 1 true if this geometric object is the empty Geometry.
bool get isEmpty => !iterator.moveNext();
final bool isMeasured #
A collection of geometries is considered measured if every child geometry has an m-component.
The value of this property is computed upon first access and then cached. Subsequent reads of the property efficiently reply the cached value.
@override bool get isMeasured { if (_isMeasured == null) _computeIsMeasured(); return _isMeasured; }
final bool isRing #
Replies true if this linestring is closed and simple.
bool get isRing { throw new UnimplementedError(); }
final bool isSimple #
Returns true if this geometric object has no anomalous geometric points, such as self intersection or self tangency.
@specification(name:"isSimple()") bool get isSimple;
final E last #
final int length #
final E single #
Returns the single element in this
.
If this
is empty or has more than one element throws a StateError
.
E get single { Iterator it = iterator; if (!it.moveNext()) throw new StateError("No elements"); E result = it.current; if (it.moveNext()) throw new StateError("More than one element"); return result; }
final num spatialLength #
Replies the (spatial) length of this line string.
@specification(name:"length()") //TODO: implement num get spatialLength { throw new UnimplementedError(); }
int get SRID #
Returns the Spatial Reference System ID for this geometric object.
@specification(name:"srid()") int get SRID => _srid;
Operators
dynamic operator [](int n) #
operator [](int n) => this.elementAt(n);
Methods
bool any(bool f(E element)) #
bool contains(E element) #
E elementAt(int index) #
Returns the indexth element.
If [this] [Iterable] has fewer than
index elements throws a
RangeError
.
Note: if this
does not have a deterministic iteration order then the
function may simply return any element without any iteration if there are
at least
index elements in this
.
E elementAt(int index) { if (index is! int || index < 0) throw new RangeError.value(index); int remaining = index; for (E element in this) { if (remaining == 0) return element; remaining--; } throw new RangeError.value(index); }
bool every(bool f(E element)) #
Iterable expand(Iterable f(E element)) #
Expand each element of this Iterable
into zero or more elements.
The resulting Iterable will run through the elements returned by f for each element of this, in order.
The returned Iterable
is lazy, and will call
f for each element
of this every time it's iterated.
Iterable expand(Iterable f(E element)) => new ExpandIterable<E, dynamic>(this, f);
E firstWhere(bool test(E value), {E orElse()}) #
Returns the first element that satisfies the given predicate f
.
If none matches, the result of invoking the
orElse function is
returned. By default, when
orElse is null
, a StateError
is
thrown.
E firstWhere(bool test(E value), { E orElse() }) { // TODO(floitsch): check that arguments are of correct type? for (E element in this) { if (test(element)) return element; } if (orElse != null) return orElse(); throw new StateError("No matching element"); }
dynamic fold(initialValue, combine(previousValue, E element)) #
Reduces a collection to a single value by iteratively combining each element of the collection with an existing value using the provided function.
Use initialValue as the initial value, and the function combine to create a new value from the previous one and an element.
Example of calculating the sum of an iterable:
iterable.fold(0, (prev, element) => prev + element);
dynamic fold(var initialValue, dynamic combine(var previousValue, E element)) { var value = initialValue; for (E element in this) value = combine(value, element); return value; }
void forEach(void f(E element)) #
String join([String separator]) #
Converts each element to a String
and concatenates the strings.
Converts each element to a String
by calling Object.toString
on it.
Then concatenates the strings, optionally separated by the
separator
string.
String join([String separator]) { Iterator<E> iterator = this.iterator; if (!iterator.moveNext()) return ""; StringBuffer buffer = new StringBuffer(); if (separator == null || separator == "") { do { buffer.write("${iterator.current}"); } while (iterator.moveNext()); } else { buffer.write("${iterator.current}"); while (iterator.moveNext()) { buffer.write(separator); buffer.write("${iterator.current}"); } } return buffer.toString(); }
E lastWhere(bool test(E value), {E orElse()}) #
Returns the last element that satisfies the given predicate f
.
If none matches, the result of invoking the
orElse function is
returned. By default, when
orElse is null
, a StateError
is
thrown.
E lastWhere(bool test(E value), {E orElse()}) { // TODO(floitsch): check that arguments are of correct type? E result = null; bool foundMatching = false; for (E element in this) { if (test(element)) { result = element; foundMatching = true; } } if (foundMatching) return result; if (orElse != null) return orElse(); throw new StateError("No matching element"); }
Iterable map(f(E element)) #
Returns a lazy Iterable
where each element e
of this
is replaced
by the result of f(e)
.
This method returns a view of the mapped elements. As long as the
returned Iterable
is not iterated over, the supplied function
f will
not be invoked. The transformed elements will not be cached. Iterating
multiple times over the the returned Iterable
will invoke the supplied
function
f multiple times on the same element.
Iterable map(f(E element)) => new MappedIterable<E, dynamic>(this, f);
int numPoints() #
Replies the number of points in this linestring.
See also length
@specification(name:"numPoints()") int numPoints() => length;
Point pointN(int n) #
Replies the n-th point this linestring.
See also elementAt
@specification(name:"pointN()") Point pointN(int n) => elementAt(n);
E reduce(E combine(E value, E element)) #
Reduces a collection to a single value by iteratively combining elements of the collection using the provided function.
Example of calculating the sum of an iterable:
iterable.reduce((value, element) => value + element);
E reduce(E combine(E value, E element)) { Iterator<E> iterator = this.iterator; if (!iterator.moveNext()) { throw new StateError("No elements"); } E value = iterator.current; while (iterator.moveNext()) { value = combine(value, iterator.current); } return value; }
E singleWhere(bool test(E value)) #
Returns the single element that satisfies f
. If no or more than one
element match then a StateError
is thrown.
E singleWhere(bool test(E value)) { // TODO(floitsch): check that argument is of correct type? E result = null; bool foundMatching = false; for (E element in this) { if (test(element)) { if (foundMatching) { throw new StateError("More than one matching element"); } result = element; foundMatching = true; } } if (foundMatching) return result; throw new StateError("No matching element"); }
Iterable<E> skip(int n) #
Iterable<E> skipWhile(bool test(E value)) #
Returns an Iterable
that skips elements while
test is satisfied.
The filtering happens lazily. Every new Iterator
of the returned
Iterable
will iterate over all elements of this
.
As long as the iterator's elements do not satisfy
test they are
discarded. Once an element satisfies the
test the iterator stops testing
and uses every element unconditionally.
Iterable<E> skipWhile(bool test(E value)) { return new SkipWhileIterable<E>(this, test); }
Iterable<E> take(int n) #
Iterable<E> takeWhile(bool test(E value)) #
Returns an Iterable
that stops once
test is not satisfied anymore.
The filtering happens lazily. Every new Iterator
of the returned
Iterable
will start iterating over the elements of this
.
When the iterator encounters an element e
that does not satisfy
test,
it discards e
and moves into the finished state. That is, it will not
ask or provide any more elements.
Iterable<E> takeWhile(bool test(E value)) { return new TakeWhileIterable<E>(this, test); }
List<E> toList({bool growable: true}) #
Set<E> toSet() #
Iterable<E> where(bool f(E element)) #
Returns a lazy Iterable
with all elements that satisfy the
predicate
f.
This method returns a view of the mapped elements. As long as the
returned Iterable
is not iterated over, the supplied function
f will
not be invoked. Iterating will not cache results, and thus iterating
multiple times over the the returned Iterable
will invoke the supplied
function
f multiple times on the same element.
Iterable<E> where(bool f(E element)) => new WhereIterable<E>(this, f);