-
Notifications
You must be signed in to change notification settings - Fork 387
Create Plane from Location #1912
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
Merged
adam-urbanczyk
merged 27 commits into
CadQuery:master
from
Joschua-Conrad:plane-from-location
Oct 30, 2025
Merged
Changes from all commits
Commits
Show all changes
27 commits
Select commit
Hold shift + click to select a range
b4903d4
Added new __init__ multimethod of Plane
Joschua-Conrad 6195872
Changed type hints of exisitng Plane.__init__
Joschua-Conrad 8fe6267
Introduced test of new Plane.__init__
Joschua-Conrad 871fd11
Comments on introduced test
Joschua-Conrad aed6fb1
Test now has only a single initial Plane to start conversiosn from
Joschua-Conrad ba6abe4
Tests pass now, after enforcing that tested xDir and normal are ortho…
Joschua-Conrad 95608fe
New constructor is now also available as property
Joschua-Conrad c531964
Removed obsolete test code lines
Joschua-Conrad 86b4d40
Removed redundant test parametrizations
Joschua-Conrad d4b3b2d
Gave new Plane.__init__ a more elaborate logic.
Joschua-Conrad c94bd36
Fixed rotation order in new Plane.__init__
Joschua-Conrad 371655b
Added more test parametrizations
Joschua-Conrad f102c36
Comment
Joschua-Conrad f3437f7
Resolved all flake8 linting warnings: whitespace only
Joschua-Conrad afc7e1f
Ran black
Joschua-Conrad fc84aca
Again supporting keyword arguments on Plane.__init__
Joschua-Conrad f53e871
Tried adding multimethod support to docs, but output still looks bad
Joschua-Conrad 69ed038
Reverted changes made to support multidispatch in sphinx
Joschua-Conrad b5df9cf
Turned new Plane.__init__ into a class method
Joschua-Conrad 607bb83
More assertions on expected Location properites
Joschua-Conrad 1043dcf
Re-ran black
Joschua-Conrad 7513047
Ran black, but this time with the correct CQ-custom black fork
Joschua-Conrad 198e32e
Fixed mypy error
Joschua-Conrad cd99615
Changed new constructor from classmethod to multimethod
Joschua-Conrad 9a1e326
Fix typo in comment
Joschua-Conrad 8d8c2f5
Fix typo in comment
Joschua-Conrad e5b9c30
Changes as requested by PR review of @lorenzncode
Joschua-Conrad File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,137 @@ | ||
| from cadquery.occ_impl.geom import Location, Plane, Vector | ||
| import pytest | ||
| import itertools | ||
|
|
||
|
|
||
| # Conversion can be triggered from explicit constructor, or from property | ||
| @pytest.mark.parametrize( | ||
| ["useproperty",], [(False,), (True,),], | ||
| ) | ||
| # Create different test cases from different initial plane. | ||
| # Testing the different components is mainly useful for debugging if things | ||
| # do not work. | ||
| # Arguments to Plane.__init__ along with expected rotations in a converted | ||
| # Location object are given here. | ||
| @pytest.mark.parametrize( | ||
| ["plargs", "expectedrot"], | ||
| [ | ||
| # Default plane | ||
| (((3, 5, 6),), (0, 0, 0),), | ||
| # Just xDir specified, but never parallel to the default normal | ||
| (((3, 5, 6), (1, 0, 0),), (0, 0, 0),), | ||
| (((3, 5, 6), (0, 1, 0),), (0, 0, 90),), | ||
| # xDir and normal specified. | ||
| # Omit normals, that were included as default, and ones which | ||
| # have no component orthogonal to xDir | ||
| (((3, 5, 6), (1, 0, 0), (0, 1, 0),), (-90, 0, 0),), | ||
| (((3, 5, 6), (0, 1, 0), (1, 0, 0),), (90, 0, 90),), | ||
| # Just xDir, but with multiple vector components | ||
| (((3, 5, 6), (1, 1, 0),), (0, 0, 45),), | ||
| (((3, 5, 6), (1, 0, 1),), (0, -45, 0),), | ||
| (((3, 5, 6), (0, 1, 1),), (0, -45, 90),), | ||
| # Multiple components in xdir and normal | ||
| # Starting from here, there are no known golden Location rotations, | ||
| # as normal is made orthogonal to xDir and as rotational angles | ||
| # are non-trivial. | ||
| (((3, 5, 6), (1, 1, 0), (1, 0, 1),), None,), | ||
| (((3, 5, 6), (1, 1, 0), (0, 1, 1),), None,), | ||
| (((3, 5, 6), (1, 0, 1), (1, 1, 0),), None,), | ||
| (((3, 5, 6), (1, 0, 1), (0, 1, 1),), None,), | ||
| (((3, 5, 6), (0, 1, 1), (1, 1, 0),), None,), | ||
| (((3, 5, 6), (0, 1, 1), (1, 0, 1),), None,), | ||
| # Same, but introduce negative directions | ||
| (((3, 5, 6), (-1, 1, 0), (-1, 0, -1),), None,), | ||
| (((3, 5, 6), (1, -1, 0), (0, -1, -1),), None,), | ||
| (((3, 5, 6), (1, 0, -1), (1, -1, 0),), None,), | ||
| (((3, 5, 6), (1, 0, -1), (0, -1, 1),), None,), | ||
| (((3, 5, 6), (0, -1, -1), (-1, 1, 0),), None,), | ||
| (((3, 5, 6), (0, -1, -1), (1, 0, -1),), None,), | ||
| # Vectors with random non-trivial directions | ||
| (((3, 5, 6), (2, 4, 7), (9, 8, 1),), None,), | ||
| ], | ||
| ) | ||
| def test_Plane_from_Location(plargs, expectedrot, useproperty): | ||
| # Test conversion between Plane and Location by converting multiple | ||
| # times between them, such that two Plane and two Location can be | ||
| # compared respectively. | ||
|
|
||
| # If there are three things in plargs, ensure that xDir and normal are | ||
| # orthogonal. That should be ensured by an exception in Plane.__init__. | ||
| # This here makes the normal orthogonal to xDir by subtracting its | ||
| # projection on xDir. | ||
| # If no normal is given, the default normal is assumed. | ||
| # Packed and unpacked arguments to Plane are kept the same. | ||
| if len(plargs) == 1: | ||
| (origin,) = plargs | ||
| elif len(plargs) == 2: | ||
| plargs = ( | ||
| *plargs, | ||
| (0, 0, 1), | ||
| ) | ||
| # If len(plargs) was 2, it is now 3, and the normal still needs to be | ||
| # made orthogonal to xDir. | ||
| if len(plargs) == 3: | ||
| origin, xDir, normal = plargs | ||
| xDir = Vector(xDir) | ||
| normal = Vector(normal) | ||
| normal -= normal.projectToLine(xDir) | ||
| xDir = xDir.toTuple() | ||
| normal = normal.toTuple() | ||
| plargs = ( | ||
| origin, | ||
| xDir, | ||
| normal, | ||
| ) | ||
|
|
||
| # Start from random Plane with classical __init__ | ||
| # Use keyword arguments on purpose, as they still need to work after | ||
| # having @multidispatch added to that __init__. | ||
| # Test that on cases, where plargs has three elements and was unpacked. | ||
| if len(plargs) == 3: | ||
| originalpl = Plane(origin=origin, xDir=xDir, normal=normal) | ||
| else: | ||
| originalpl = Plane(*plargs) | ||
|
|
||
| # Convert back and forth, such that comparable pairs are created. | ||
| # Depending on test fixture, call constructor directly or use properties | ||
| if useproperty: | ||
| locforth = originalpl.location | ||
| plback = locforth.plane | ||
| locback = plback.location | ||
| else: | ||
| locforth = Location(originalpl) | ||
| plback = Plane(locforth) | ||
| locback = Location(plback) | ||
|
|
||
| # Create raw locations, which are flat tuples of raw numbers, suitable for | ||
| # assertion with pytest.approx | ||
| locraws = list() | ||
| for loc in (locforth, locback): | ||
| loc = loc.toTuple() | ||
| loc = tuple(itertools.chain(*loc)) | ||
| locraws.append(loc) | ||
|
|
||
| # Same for planes | ||
| plraws = list() | ||
| for pl in (originalpl, plback): | ||
| pl = ( | ||
| pl.origin.toTuple(), | ||
| pl.xDir.toTuple(), | ||
| pl.yDir.toTuple(), | ||
| pl.zDir.toTuple(), | ||
| ) | ||
| pl = tuple(itertools.chain(*pl)) | ||
| plraws.append(pl) | ||
|
|
||
| # Assert the properties of the location object. | ||
| # Asserting on one Location is enough, as equality to the other one is | ||
| # asserted below. | ||
| # First, its origin shall be the same | ||
| assert locraws[0][0:3] == pytest.approx(origin) | ||
| # Then rotations are asserted from manual values | ||
| if expectedrot is not None: | ||
| assert locraws[0][3:6] == pytest.approx(expectedrot) | ||
|
|
||
| # Assert that pairs of Plane or Location are equal after conversion | ||
| assert locraws[0] == pytest.approx(locraws[1]) | ||
| assert plraws[0] == pytest.approx(plraws[1]) |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.