ajhynes7 / scikit-spatial Goto Github PK
View Code? Open in Web Editor NEWSpatial objects and computations based on NumPy arrays.
Home Page: https://scikit-spatial.readthedocs.io
License: Other
Spatial objects and computations based on NumPy arrays.
Home Page: https://scikit-spatial.readthedocs.io
License: Other
Hey!
I create executables with pyinstaller of some projects that use scikit-spatial, however since version 7.1.0 I am having the following error:
File "PyInstaller/loader/pyimod02_importers.py", line 419, in exec_module
File "skspatial/__init__.py", line 7, in <module>
File "importlib/metadata/__init__.py", line 996, in version
File "importlib/metadata/__init__.py", line 969, in distribution
File "importlib/metadata/__init__.py", line 548, in from_name
importlib.metadata.PackageNotFoundError: No package metadata was found for scikit-spatial
This does not occur with the previous version (7.0.0). I suspect that is caused because this change:
d2cdb6d#diff-85bc0bcf937004ff26b6e7bd26a0be35f941eef0f79b5c5329d3cfdf7b55bfc4L10
(I'm using python 3.10)
Thanks!
Hello!
I'm using Line.best_fit
with some tens of thousands to a few hundred thousand points, and I've found that using scipy.sparse.linalg.svds
instead of np.linalg.svd
leads to faster runtimes and lower memory usage. Since only the first eigenvector is needed, computing all of them seems wasteful.
Could this be an improvement? Perhaps use scipy
if available, otherwise fallback to numpy
?
Cheers!
Hi! Wonderful library! Thanks!
Before starting a new PR, I would like to know if it could be of interest or not the addition of a method for the computation of the signed area of a simple polygon whose vertices are described by their 2D cartesian coordinates by means of the shoelace formula.
I was thinking to add this method to the Points
class, but maybe it could be a little off-topic there. Perhaps, it could be just a function in the public measurement
module.
For a particular project, I am using your library and very often I also need to compute the signed area given 2D points and I thought that maybe it could an interesting addition to this library.
I would implement the code in the following way (let's suppose we are within the measurement
module):
def area_signed(points: array_like) -> float:
"""
Compute the signed area of a simple polygon whose vertices are described
by their 2D cartesian coordinates.
Parameters
----------
points : array_like
Input 2D points.
Returns
-------
area_signed : float
The signed area of the polygon.
Raises
------
ValueError
If the points are not 2D.
If there are fewer than three points.
References
----------
https://en.wikipedia.org/wiki/Shoelace_formula
https://alexkritchevsky.com/2018/08/06/oriented-area.html#solution
https://rosettacode.org/wiki/Shoelace_formula_for_polygonal_area#Python
"""
points = Points(points)
if points.dimension != 2:
raise ValueError("The points must be 2D.")
if points.shape[0] < 3:
raise ValueError("There must be at least 3 points.")
x = points[:, 0]
y = points[:, 1]
return sum(x[i-1]*y[i] - x[i]*y[i-1] for i in range(len(points))) / 2
I believe it should be just the user's responsibility to check if the order of the points does not result in a self-overlapping polygon.
The implementation of the shoelace algorithm follows the approach suggested here. It's an elegant and I think also clear one-liner. But maybe the Numpy approach could be faster for a large amount of points (I haven't had the opportunity to compare the performance yet).
No worries if this feature is not of interest.
Have a nice weekend!
Dear @ajhynes7,
very beautiful library! Simple and very useful!
I am not finding a method for computing the point-line distance. I am a little bit surprised that such a method is not implemented. But for sure I am wrong.
Thanks!
from skspatial.objects import Line, Point, Vector
from skspatial.plotting import plot_2d
import math
import numpy as np
def get_direction(compass_deg):
rad = math.pi * compass_deg / 180
y = math.cos(rad)
x = math.sin(rad)
print(f'{round(x, 3)},{round(y, 3)}')
return x, y
point_1=Point([0, 0])
point_2=Point([0, 1])
line_1 = Line(point_1, direction=get_direction(270))
line_2 = Line(point_2, direction=get_direction(92))
point_12 = Point(line_1.intersect_line(line_2))
_, ax = plot_2d(
line_1.plotter(t_2=30),
line_2.plotter(t_2=30),
point_1.plotter(c='k'),
point_2.plotter(c='k'),
point_12.plotter(s=75, zorder=3, c='red'),
)
_ = ax.axis('equal')
Lines have opposite direction, but somehow intersect:
line_1.intersect_line(line_2)
# (~28.6, ~0)
>>> Point([2.86362533e+01, 5.26039439e-15])
LineSegment class can't plot in 2D nor in 3D. You can verify this as simple as:
`linesegment = LineSegment(Point([0, 1, 1]),Point([0, 2, 2]))
plot_3d(
linesegment.plotter()
)
Output:
AttributeError Traceback (most recent call last)
Cell In[95], line 4
1 linesegment = LineSegment(Point([0, 1]),Point([0, 2]))
3 plot_3d(
----> 4 linesegment.plotter()
5 )
AttributeError: 'LineSegment' object has no attribute 'plotter'`
Hi!
This is not an issue, but just a discussion.
Have you ever thought about adding Ellipsoid
and Ellipse
classes? Similar to the Sphere
/Circle
classes, we could create a _BaseEllipsoid
class which is inherited by both Ellipsoid
and Ellipse
classes. I am glad to help if you consider this valuable.
By the way, what about adding the Discussions
tab for this library? Maybe it's too early?
Thanks!
I'm using scikit-spatial to as a "geometry engine" of sort for some code of mine, that draws 2D parts.
I need to fillet (with a known radius):
To fillet the 2 lines I offset them of the fillet radius, and project the point of intersection (center) on the two lines, getting 2 points (start and end of the arc). This works with no issues.
To fillet 2 circles I was going to do something similar, offsetting the circles in this case, finding the intersection (one of two); the thing is I can't really project the center on the circles, so I tried drawing a third circle with the intersection as a center and getting the tangent point of interest.
This is geometrically sound, but when I do it I find 2 points of intersections, which is not correct; I determined it's caused by floating point error/rounding - depending of the circles diameters and the fillet radius it can be bigger or smaller.
Btw: this would've happened filleting the 2 lines too had I used a circle instead of projecting the center to get start and end of the arc.
So now I think I have two choice: find a way to deal with floating point rounding, or find some other way to get the tangency points, one that does not involve a third circle - maybe something with triangles and stuff.
Does someone have an idea of how to tackle this problem? I'm testing some fancy geometry, but I'm open to suggestions - floating point rounding included.
Thanks.
I have a large point cloud that and i want to create a best fit plane however i'm running out of memory.
In plane.py can an update be made to the API to allow for the option of using a reduced form of the matrix?
I have made a local update below to get around the memor error for the moment.
u, _, _ = np.linalg.svd(points_centered.T, full_matrices=False)
Hey,
I'm a bit confused about the following:
plane = Plane.best_fit(points_down[inliers, :3])
min_ = np.min(points_down[inliers, :3], axis=0)
max_ = np.max(points_down[inliers, :3], axis=0)
points = Points(points_down[inliers, :3])
plot_3d( points.plotter(c='k', s=50, depthshade=False),
plane.plotter(alpha=0.2, lims_x=(min_[0], max_[0]), lims_y=(min_[1], max_[1])),
)
The output looks like:
It seems to fit the points correctly, but the calculated values defining the plane are not within the same range as the original ones. Am I missing something? The fitted plane is perpendicular to the z=0 plane. Maybe this causes meshgrid problems to calculate values for z?
Thanks in advance.
I have scikit-spatial 6.1.0
and Python 3.8.10 un Ubuntu 20.04.3 MATE. Basic examples work, matplotlib
works, but plot_3d
fails to produce anything. I was trying this example: https://scikit-spatial.readthedocs.io/en/stable/gallery/projection/plot_vector_line.html
Hi! I hope everything's fine!
I was wondering the following, but let me know if it makes sense to you or not, please. Thanks!
The Plane
object already has the project_vector
method. However, very often I need the projected line (and not only its vector) because I need to use the specific Line
's methods.
Would it make sense to you to add a project_line
method to the Plane
object? I was thinking to write something similar to the following (I have omitted both documentation and error handling, now I just want to give you an idea):
def project_line(plane: Plane, line: Line) -> Line:
direction = plane.project_vector(line.direction)
point = plane.project_point(line.point)
return Line(point=point, direction=direction)
Bye!
Hi,
Great repo! Thanks a lot!
I get an error with the newest release. If in a jupyer-notebook I try to create a Point
the cell get stuck.
I don't get any error message from your library, the only error message is a warning that comes from ipython:
DeprecationWarning: `should_run_async` will not call `transform_cell` automatically in the future. Please pass the result to `transformed_cell` argument and any exception that happen during thetransform in `preprocessing_exc_tuple` in IPython 7.17 and above.
and to reproduce it the minimal code is:
from skspatial.objects import Point
Point([0, 0])
If I downgrade ipython below 7.17 or to scikit-spatial=5.2.0 everything works fine. My OS is manajro 21.0
best,
Lorenzo
It would be really handy, in case there might be an object which describes a closed line. This way, for example, only plausible intersections could be calculated.
Is such an feature conceivable or do you think it is not useful?
Hi, I'm working with planes and I would like to know what is the best way with skspatial library to compute Plane object from normal vector and plane.
Thanks.
Hi,
Thanks for this interesting package. Any plan for Cylinder.best_fit?
This algorithm always works well in any data:
https://github.com/Buzzolan/Visual_Computing/blob/4a43faa1b0887a09dd8418f32982b27e821013e8/RobustFitting/LSGE/lscylinder.m
Hi! I hope everything's ok!
scikit-spatial
already provides all the tools necessary to compute the distance between two parallel planes. However, I was thinking about adding a method to the Plane
class to directly compute such a distance. It's just about having a quicker way for doing it.
Does it sound pointless to you? If it doesn't, I will take care of the PR and the method's signature could be something like the following one:
def distance(self, other: Plane) -> np.float64:
"""
Return the distance to another parallel plane.
Parameters
----------
other : Plane
Other parallel plane.
Returns
-------
np.float64
Distance between the planes.
Raises
------
ValueError
If planes are not parallel.
"""
...
Thanks!
Hi!
The link to Inge Söderkvist's Algorithm seems to be broken. Kindly provide information about the algorithm used for the same. Thanks!
The link on the documentation page leads to a 404: https://www.ltu.se/cms_fs/1.51590!/svd-fitting.pdf
Thanks
Hi,
I'd like to ask if you could add intersectionn check between circles.
Right now it's possible to find intersection point between two lines, or between a line and a circle, but not between two circles.
Would it be possible? Thanks anyway.
I find scikit-spatial a useful tool for me, so thanks for it.
Hello.
I think it would be useful to have the same method as the plane object. It would take a set of points and fit them to a sphere with a least squares method. The code is simple and I would like to contribute.
Is there a way to use >3 points for projecting points onto the best fit plane?
When I want to use scikit-spatial with other packages, it conflicts by importlib-metadata.
Latest version of importlib-metadata is 4.x but scikit-spatial foces 1.x.
Other packages usually force importlib-metadata version over 3.x
Hi @ajhynes7!
The angle_between
method allows to compute the unsigned angle between two either 2D or 3D vectors, while the angle_signed
computes the signed angle but supports 2D vectors only.
I had a use case where I needed to compute the signed angle between two 3D vectors. Would you be interested in changing the angle_signed
method to support 3D vectors as well? If you wouldn't, don't worry, I understand.
I was thinking about the following solution that does not break the current interface. Only the angle_signed
method would be modified.
I would add the keyword argument positive_direction
or plane_normal
which is a Vector
that is necessary to actually determine if the angle between two 3D vectors is positive or not. Its default value is None
. This vector is just the normal of the plane where the two 3D vectors lie. We need to validate this input to actually check if it's a Vector
and normal.
If the user provides two 2D vectors, the method works as it is now and the positive_direction
argument is ignored regardless of its value.
If the user provides two 3D vectors and the positive_direction
is not None
, then the cross product of the two input vectors is computed and eventually the cosine similarity is computed between the cross product and the positive_direction
vector which will be used to determine the sign of the angle.
If positive_direction
is None
a positive angle will be always returned.
Thanks!
I searched and found that future import is only enabled after python version 3.7 whereas mine is 3.6.6
Please help resolve the issue. Thanks!
Any chance of getting a Polygon class with simple methods: polygon or point inside polygon?
I just installed scikit-spatial
with pip3
on Ubuntu 18.04 and Python 3.6.9. A simple example with points works, but:
>>> from skspatial.objects import Cylinder
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: cannot import name 'Cylinder'
Hi @ajhynes7
I just came across this repository. I have been working on a package called pygal
which wraps a bunch of the algorithms available in CGAL.
I was also thinking of making a scikit
style package out of it -- then i discovered yours.
Maybe there is some way to get a collaboration going?
I am not sure what that would look like though. One difficulty is that CGAL likes to use a multi-precision number type which doesn't necessarily map directly to a double ...
Here is the package: https://github.com/wolfv/pygal
Cheers
hello, thanks for your great job.
have any way to use scikit-spatial with python3.6.x?
Encountered an issue and not sure what's going on here. The lines all plot correctly, but the distance measurement is off. Lines are parallel because line_1.intersect_line(line_2)
raises that exception ValueError: The lines must not be parallel.
# line 1
line_1 = Line(point=Point([ 449. , 1570.5]), direction=Vector([0., 1.]))
# line 2
line_2 = Line(point=Point([0.000000e+00, 1.276087e+14])
d = line_1.distance_line(line_2) # 449.0
# correct answer = 108.0
Hi,
I was wondering why you choose to raise a ValueError when the .intersect_line() or .intersect_circle(), well, don't have intersecting points.
I'm curious if there is any particular reason, as far I remember 0 points of intersection is still "correct" (no intersections). so I'd expect an empty list to be returned instead.
I can work around this, but I'm curious about why it behaves like this.
Hello ajhynes7,
Thanks for you amazing work in this repository! Do you plan to add polyhedron geometry in this repository? According to my limit knowledge, there is no python library that is treating 3D geometry object as convenient as shapely library.
Hello,
When I slice the vector object its dimension attribute doesn't change.
a = Vector([1,1,0.1])
print(a[:-1].dimension, a[:-1].shape, a.size, a[:-1].size)
3 (2,) 3 2
Hello! I generate a plane from points and make a plane from point and normal. Then I make an intersection line with Plane.intersect_plane
. When I try to find an intersection point of the intersection line and a line from points, which was used to making a first plane I get an error
565 if not self.is_coplanar(other, tol=tol):
--> 566 raise ValueError("The lines must be coplanar.")
568 # Vector from line A to line B.
569 vector_ab = Vector.from_points(self.point, other.point)
ValueError: The lines must be coplanar.
Dependabot couldn't authenticate with https://pypi.python.org/simple/.
You can provide authentication details in your Dependabot dashboard by clicking into the account menu (in the top right) and selecting 'Config variables'.
I was wondering if it could be possible to implement defining Circle() from 3 points.
I found this "https://stackoverflow.com/questions/52990094" and was wondering if it could became a builtin.
I also found this: "Sympy https://docs.sympy.org/latest/modules/geometry/ellipses.html#sympy.geometry.ellipse.Circle."
I feel like it would be good to have it built in scikit-spatial, would it be possible?
edit:
I'll leave this one here, but I'm now using 2 points and the sagitta to determine the circle (works better in my application).
I can't really start asking new methods every time I'd like them, and .intersect_circle already was a game changer.
Would it be the right direction for scikit-spatial to have more general 2D methods?
It shouldn't overlap too much with other projects ... I think.
Hello. Great work with this library. Unfortunately I did find an issue where the mesh generated for cylinders only has the correct radius if the cylinder's vector is axis-aligned. For cylinders with arbitrary vectors the radius is smaller than requested. You can see this with the following minimal example:
from matplotlib import pyplot as plt
from skspatial.objects import Cylinder, Sphere
fig = plt.figure()
ax = fig.add_subplot(111, projection="3d")
center = [0, 0, 0]
ax.plot_wireframe(*Sphere(center, 1).to_mesh())
ax.plot_wireframe(*Cylinder(center, [1, 0, 0], 1).to_mesh(4, 32), color='g')
ax.plot_wireframe(*Cylinder(center, [0.707, .707, 0], 1).to_mesh(4, 32), color='r')
ax.set_xlim((-3, 3))
ax.set_ylim((-3, 3))
ax.set_zlim((-3, 3))
plt.tight_layout()
plt.show()
The green cylinder has the correct radius, matching the blue sphere, but the red cylinder is too small by a factor of 0.707.
Hi,
great work.
Is it possible to add an object "cylinder" which can be oriented arbitrarily in 3d cartesian space?
Kind regards,
Jonas
Is this possible to define a Vector from an arbitrary angle? I searched the docs but couldn't find anything.
I need to have Line that starts from a given point and have a known angle, so I was wondering if one can define a Vector that way.
I came up with:
import cmath
import math
angle = 53
r = 10 # anything goes
pt = cmath.rect(r, math.radians(angle))
v = Vector([pt.real, pt.imag])
(ok, I could convert to radians without importing math)
But I kind of dislike it, a proper Vector method would be cleaner.
If it's not already possible, could it be added to the Vector class?
Thanks.
This code snippet:
cylinder = Cylinder([0, 0, 0], [0, 0, 1], 1)
line = Line([2, 2, 2], [3, 3, 3])
print(cylinder.intersect_line(line))
produces:
(Point([-0.70710678, -0.70710678, -0.70710678]), Point([0.70710678, 0.70710678, 0.70710678]))
This doesn't seem to be correct. The line intersects the cylinder at [0.70710678, 0.70710678, 0.70710678] and [0, 0, 0]:
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.