Skip to content

Commit

Permalink
Add transform_points method to Line
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrew Hynes committed Mar 12, 2019
1 parent c442a19 commit 6df8e00
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 2 deletions.
43 changes: 42 additions & 1 deletion skspatial/objects/line.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import numpy as np
from dpcontracts import require, ensure, types

from skspatial.transformation import mean_center
from skspatial.transformation import mean_center, normalize_dimension
from .base_line_plane import _BaseLinePlane
from .point import Point
from .vector import Vector
Expand Down Expand Up @@ -297,6 +297,7 @@ def intersect_line(self, other):

@classmethod
@types(points=np.ndarray)
@require("The points are all finite.", lambda args: np.isfinite(args.points).all())
@require("There must be at least two points.", lambda args: args.points.shape[0] >= 2)
@ensure("The output must be a line.", lambda _, result: isinstance(result, Line))
def best_fit(cls, points):
Expand Down Expand Up @@ -334,3 +335,43 @@ def best_fit(cls, points):
direction = Vector(vh[0, :])

return cls(centroid, direction)

@types(points=np.ndarray)
@require("The points are all finite.", lambda args: np.isfinite(args.points).all())
@ensure("There is one coordinate for each input point.", lambda args, result: result.size == args.points.shape[0])
@ensure("The output is a 1D array.", lambda _, result: result.ndim == 1)
@ensure("The coordinates are all finite.", lambda _, result: np.isfinite(result).all())
def transform_points(self, points):
"""
Transform points to a one-dimensional coordinate system defined by a line.
The point on the line acts as the origin of the coordinate system.
The line is analagous to an x-axis. The output coordinates represent the
x-values of points on this line.
Parameters
----------
points : ndarray
(n, d) array of n points with dimension d.
Returns
-------
coordinates : ndarray
One-dimensional coordinates.
Examples
--------
>>> from skspatial.objects import Line
>>> line = Line(point=[0, 0], vector=[1, 0])
>>> points = np.array([[10, 2], [3, 4], [-5, 5]])
>>> line.transform_points(points)
array([10., 3., -5.])
"""
vectors_to_points = normalize_dimension(points) - self.point
coordinates = np.apply_along_axis(np.dot, 1, vectors_to_points, self.direction)

return coordinates
38 changes: 37 additions & 1 deletion skspatial/transformation.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import numpy as np
from dpcontracts import require, ensure, types

from skspatial.objects import Point


@types(points=np.ndarray)
@require("The input must be a 2D array of points", lambda args: args.points.ndim == 2)
Expand Down Expand Up @@ -77,7 +79,41 @@ def mean_center(points):
"""
centroid = get_centroid(points)

points_centered = points - centroid

return points_centered, centroid


@ensure("The output is an ndarray.", lambda _, result: isinstance(result, np.ndarray))
def normalize_dimension(seq_points):
"""
Normalize the dimension of a set of points.
Each point is converted to a `Point` object.
The Point objects are then stacked into one ndarray.
Parameters
----------
seq_points : sequence
Sequence of array_like objects.
Returns
-------
ndarray
Each row corresponds to a point in the input sequence.
Examples
--------
>>> from skspatial.transformation import normalize_dimension
>>> seq_points = ([1], [1, 2], [1, 2, 3])
>>> normalize_dimension(seq_points)
array([[1., 0., 0.],
[1., 2., 0.],
[1., 2., 3.]])
"""
list_points = [Point(x) for x in seq_points]

return np.vstack(list_points)

0 comments on commit 6df8e00

Please sign in to comment.