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

fix location_at, position_at and tangent_at with PositionMode.LENGTH for Wire #680

Merged
merged 2 commits into from
Aug 30, 2024

Conversation

danieledapo
Copy link
Contributor

@danieledapo danieledapo commented Aug 30, 2024

Apparently Wire use a different parametrization than Edge because Edge has its LastParameter being the length of the Edge while Wirehas LastParameter being the numer of Edges with the fractional part being the parameter inside the edge.

The way the patch works is to always divide the distance provided by the user by the real length of the Wire/Edge so that we get a parameter in [0..1] which we can then pass straight to param_at to get the real parameter.

Fixes #572

@danieledapo
Copy link
Contributor Author

danieledapo commented Aug 30, 2024

Note: this makes the Edge version slower because we're doing calculation that it would not need, but I do not know if it's worth it to have something like the following in each method

if isinstance(self, Wire):
    parameter = self.param_at(distance / self.length)
else: # edge
   parameter = distance

but let me know what you think.

EDIT: this doesn't work because Edge.make_circle(2) has the same parametrization as of Edge.make_circle(1) or any other circle of any radius (it likely uses the start and end angle as the first and last parameter) which means we still have to do the division.

@gumyr
Copy link
Owner

gumyr commented Aug 30, 2024

Without any changes to the code, consider this test:

circle_wire = Wire(
    [
        Edge.make_circle(1, start_angle=0, end_angle=180),
        Edge.make_circle(1, start_angle=180, end_angle=360),
    ]
)
p1 = circle_wire.position_at(pi, position_mode=PositionMode.LENGTH)
p2 = circle_wire.position_at(pi / circle_wire.length)
print(p1, p2)

circle_edge = Edge.make_circle(1)
p3 = circle_edge.position_at(pi, position_mode=PositionMode.LENGTH)
p4 = circle_edge.position_at(pi / circle_edge.length)
print(p3, p4)
Vector(-0.9026853619331, -0.4303012170001, 0) Vector(-1, 0, 0)
Vector(-1, 0, 0) Vector(-1, 0, 0)

From this I conclude that the Edge case is currently correct and the Wire case is incorrect for PositionMode.LENGTH. Do we agree on this?

If so, position_at, tangent_at and location_at need different implementations for the Edge and Wire classes; therefore, these methods shouldn't be in the Mixin1D class.

@danieledapo
Copy link
Contributor Author

From this I conclude that the Edge case is currently correct and the Wire case is incorrect for PositionMode.LENGTH. Do we agree on this?

Unfortunately, this test passes on my machine so I'm not quite sure how to debug it. I've committed and pushed it, let's see what the CI says.

image

@gumyr gumyr merged commit 55a6e8b into gumyr:dev Aug 30, 2024
11 checks passed
@gumyr
Copy link
Owner

gumyr commented Aug 30, 2024

I erroneously recalled that the param_at was really expensive but when I measured it that isn't so - looks like a nice fix. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

position_at doesn't get the correct position with Wires and PositionMode.LENGTH
2 participants