Giter Club home page Giter Club logo

scikit-spatial's Introduction

Welcome!

I'm a software developer with a background in mechanical and computer engineering. I'm currently a backend developer with CoLab Software in St. John's NL, Canada.

I'm most experienced with Python, and lately I've been interested in Julia and Rust.

I love playing Ultimate 🥏

scikit-spatial's People

Contributors

ajhynes7 avatar cristianopizzamiglio avatar edyazbec avatar laclouis5 avatar martxelo avatar pre-commit-ci[bot] avatar pyup-bot avatar volkoshkursk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

scikit-spatial's Issues

NameError: name 'Vector' is not defined

  1. When I import normally using "from skspatial.objects import Plane" it will raise SyntaxError: future feature annotations is not defined:
    Traceback (most recent call last):
    File "", line 971, in _find_and_load
    File "", line 955, in _find_and_load_unlocked
    File "", line 665, in _load_unlocked
    File "", line 678, in exec_module
    File "", line 219, in _call_with_frames_removed
    File "/home/user/miniconda3/envs/nestinet/lib/python3.6/site-packages/skspatial/objects/init.py", line 3, in
    from skspatial.objects.circle import Circle
    File "/home/user/miniconda3/envs/nestinet/lib/python3.6/site-packages/skspatial/objects/circle.py", line 11, in
    from skspatial.objects._base_sphere import _BaseSphere
    File "/home/user/miniconda3/envs/nestinet/lib/python3.6/site-packages/skspatial/objects/_base_sphere.py", line 10, in
    from skspatial.objects.point import Point
    File "/home/user/miniconda3/envs/nestinet/lib/python3.6/site-packages/skspatial/objects/point.py", line 8, in
    from skspatial.objects.vector import Vector
    File "/home/user/miniconda3/envs/nestinet/lib/python3.6/site-packages/skspatial/objects/vector.py", line 3
    from future import annotations
    ^
    SyntaxError: future feature annotations is not defined

I searched and found that future import is only enabled after python version 3.7 whereas mine is 3.6.6

  1. Then I tried to comment the line which is exist only in vector.py "from future import annotations", it raises error NameError: name 'Vector' is not defined:
    Traceback (most recent call last):
    File "", line 971, in _find_and_load
    File "", line 955, in _find_and_load_unlocked
    File "", line 665, in _load_unlocked
    File "", line 678, in exec_module
    File "", line 219, in _call_with_frames_removed
    File "/home/user/miniconda3/envs/nestinet/lib/python3.6/site-packages/skspatial/objects/init.py", line 3, in
    from skspatial.objects.circle import Circle
    File "/home/user/miniconda3/envs/nestinet/lib/python3.6/site-packages/skspatial/objects/circle.py", line 11, in
    from skspatial.objects._base_sphere import _BaseSphere
    File "/home/user/miniconda3/envs/nestinet/lib/python3.6/site-packages/skspatial/objects/_base_sphere.py", line 10, in
    from skspatial.objects.point import Point
    File "/home/user/miniconda3/envs/nestinet/lib/python3.6/site-packages/skspatial/objects/point.py", line 8, in
    from skspatial.objects.vector import Vector
    File "/home/user/miniconda3/envs/nestinet/lib/python3.6/site-packages/skspatial/objects/vector.py", line 18, in
    class Vector(_BaseArray1D):
    File "/home/user/miniconda3/envs/nestinet/lib/python3.6/site-packages/skspatial/objects/vector.py", line 74, in Vector
    def from_points(cls, point_a: array_like, point_b: array_like) -> Vector:
    NameError: name 'Vector' is not defined
    python-BaseException

Please help resolve the issue. Thanks!

Method for computing the distance between two parallel planes?

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!

best_fit for sphere object

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.

How to add axes labels to plot?

Hi, I was wondering if there is a way to add labels to the axes to better orient myself to the plot? The desired outcome would be something like this (highlighted by red circles)

image
Thank you for your time!

Why use importlib-metadata version 1.x?

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

Why raising ValueError instead of returning an empty list?

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.

Is this intersection correct?

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]:

cylinder

intersection with cylinder

Hi,
great work.
Is it possible to add an object "cylinder" which can be oriented arbitrarily in 3d cartesian space?
Kind regards,
Jonas

Polygon object

Any chance of getting a Polygon class with simple methods: polygon or point inside polygon?

`Line.distance_line` bug?

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

collab with `pygal`?

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

Vector from angle

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.

Slicing the Vector

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

error when using scikit-spatial=6..0.0 and ipython>7.17

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

Add object for line segment (closed line)

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?

AttributeError: 'LineSegment' object has no attribute 'plotter'

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'`

`Ellipse`/`Ellipsoid` classes

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!

`angle_signed` for 3D Vectors

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!

Faster Line.best_fit with scipy.sparse.linalg.svds

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!

intersection line are not complanar with line in plane

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.

Mesh for cylinders has wrong radius if not axis-aligned.

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.

SkSpatialCylinderProblem

2D geometry problem: fillet two curves

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):

  • 2 lines
  • 2 circles
  • 1 line and 1 circle

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.

Point - Line Distance Method

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!

[enhancement] Projection of a line onto a plane.

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!

Intersection between 2 Circles

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.

Plane from normal vector and point.

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.

python3.6.x

hello, thanks for your great job.
have any way to use scikit-spatial with python3.6.x?

Do you plan to add polyhedron object?

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.

Wrong line intersection point calculation

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')

image

Lines have opposite direction, but somehow intersect:

line_1.intersect_line(line_2)
# (~28.6, ~0)
>>> Point([2.86362533e+01, 5.26039439e-15])

[enhancement] Signed Area - Shoelace Formula

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!

Problem with pyinstaller with version 7.1.0

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!

Value range for fitted plane is not right

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:

image

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.

ImportError: cannot import name 'Cylinder'

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'

[Feature request] defining a Circle() from 3 points

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.