mirror of
https://github.com/gumyr/build123d.git
synced 2025-12-24 03:10:24 -08:00
Replaced Grid/HexLocations centered for align
This commit is contained in:
parent
0ee290c816
commit
c8928a8e68
6 changed files with 61 additions and 42 deletions
|
|
@ -61,7 +61,7 @@ class Hinge(Compound):
|
||||||
with BuildPart() as hinge_profile:
|
with BuildPart() as hinge_profile:
|
||||||
with BuildSketch():
|
with BuildSketch():
|
||||||
for i, loc in enumerate(
|
for i, loc in enumerate(
|
||||||
GridLocations(0, length / 5, 1, 5, centered=(False, False))
|
GridLocations(0, length / 5, 1, 5, align=(Align.MIN, Align.MIN))
|
||||||
):
|
):
|
||||||
if i % 2 == inner:
|
if i % 2 == inner:
|
||||||
with Locations(loc):
|
with Locations(loc):
|
||||||
|
|
|
||||||
|
|
@ -55,8 +55,8 @@ tutorial is the joints and not the CAD operations to create objects, this code i
|
||||||
described in detail.
|
described in detail.
|
||||||
|
|
||||||
.. literalinclude:: tutorial_joints.py
|
.. literalinclude:: tutorial_joints.py
|
||||||
:lines: 27,32-132
|
:lines: 27,32-130
|
||||||
:emphasize-lines: 3-102
|
:emphasize-lines: 3-100
|
||||||
|
|
||||||
Once the two leaves have been created they will look as follows:
|
Once the two leaves have been created they will look as follows:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ from math import sqrt, pi
|
||||||
from typing import Iterable, Union
|
from typing import Iterable, Union
|
||||||
import logging
|
import logging
|
||||||
from build123d.build_enums import (
|
from build123d.build_enums import (
|
||||||
|
Align,
|
||||||
Select,
|
Select,
|
||||||
Kind,
|
Kind,
|
||||||
Keep,
|
Keep,
|
||||||
|
|
@ -410,14 +411,14 @@ class LocationList:
|
||||||
class HexLocations(LocationList):
|
class HexLocations(LocationList):
|
||||||
"""Location Context: Hex Array
|
"""Location Context: Hex Array
|
||||||
|
|
||||||
Creates a context of hexagon array of points.
|
Creates a context of hexagon array of locations for Part or Sketch
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
diagonal: tip to tip size of hexagon ( must be > 0)
|
diagonal: tip to tip size of hexagon ( must be > 0)
|
||||||
xCount: number of points ( > 0 )
|
xCount: number of points ( > 0 )
|
||||||
yCount: number of points ( > 0 )
|
yCount: number of points ( > 0 )
|
||||||
centered: specify centering along each axis.
|
align (tuple[Align, Align], optional): align min, center, or max of object.
|
||||||
offset (VectorLike): offset to apply to all locations. Defaults to (0,0).
|
Defaults to (Align.CENTER, Align.CENTER).
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
ValueError: Spacing and count must be > 0
|
ValueError: Spacing and count must be > 0
|
||||||
|
|
@ -428,15 +429,20 @@ class HexLocations(LocationList):
|
||||||
diagonal: float,
|
diagonal: float,
|
||||||
x_count: int,
|
x_count: int,
|
||||||
y_count: int,
|
y_count: int,
|
||||||
centered: tuple[bool, bool] = (True, True),
|
align: tuple[Align, Align] = (Align.CENTER, Align.CENTER),
|
||||||
offset: VectorLike = (0, 0),
|
|
||||||
):
|
):
|
||||||
x_spacing = 3 * diagonal / 4
|
x_spacing = 3 * diagonal / 4
|
||||||
y_spacing = diagonal * sqrt(3) / 2
|
y_spacing = diagonal * sqrt(3) / 2
|
||||||
if x_spacing <= 0 or y_spacing <= 0 or x_count < 1 or y_count < 1:
|
if x_spacing <= 0 or y_spacing <= 0 or x_count < 1 or y_count < 1:
|
||||||
raise ValueError("Spacing and count must be > 0 ")
|
raise ValueError("Spacing and count must be > 0 ")
|
||||||
|
|
||||||
points = [] # coordinates relative to bottom left point
|
self.diagonal = diagonal
|
||||||
|
self.x_count = x_count
|
||||||
|
self.y_count = y_count
|
||||||
|
self.align = align
|
||||||
|
|
||||||
|
# Generate the raw coordinates relative to bottom left point
|
||||||
|
points = ShapeList()
|
||||||
for x_val in range(0, x_count, 2):
|
for x_val in range(0, x_count, 2):
|
||||||
for y_val in range(y_count):
|
for y_val in range(y_count):
|
||||||
points.append(
|
points.append(
|
||||||
|
|
@ -446,15 +452,28 @@ class HexLocations(LocationList):
|
||||||
for y_val in range(y_count):
|
for y_val in range(y_count):
|
||||||
points.append(Vector(x_spacing * x_val, y_spacing * y_val + y_spacing))
|
points.append(Vector(x_spacing * x_val, y_spacing * y_val + y_spacing))
|
||||||
|
|
||||||
# shift points down and left relative to origin if requested
|
# Determine the minimum point and size of the array
|
||||||
offset = Vector(offset)
|
sorted_points = [points.sort_by(Axis.X), points.sort_by(Axis.Y)]
|
||||||
if centered[0]:
|
size = [
|
||||||
offset += Vector(-x_spacing * (x_count - 1) * 0.5, 0)
|
sorted_points[0][-1].X - sorted_points[0][0].X,
|
||||||
if centered[1]:
|
sorted_points[1][-1].Y - sorted_points[1][0].Y,
|
||||||
offset += Vector(0, -y_spacing * y_count * 0.5)
|
]
|
||||||
points = [x + offset for x in points]
|
min_corner = Vector(sorted_points[0][0].X, sorted_points[1][0].Y)
|
||||||
|
|
||||||
# convert to locations and store the reference plane
|
# Calculate the amount to offset the array to align it
|
||||||
|
align_offset = []
|
||||||
|
for i in range(2):
|
||||||
|
if align[i] == Align.MIN:
|
||||||
|
align_offset.append(0)
|
||||||
|
elif align[i] == Align.CENTER:
|
||||||
|
align_offset.append(-size[i] / 2)
|
||||||
|
elif align[i] == Align.MAX:
|
||||||
|
align_offset.append(-size[i])
|
||||||
|
|
||||||
|
# Align the points
|
||||||
|
points = [point + Vector(*align_offset) - min_corner for point in points]
|
||||||
|
|
||||||
|
# Convert to locations and store the reference plane
|
||||||
local_locations = [Location(point) for point in points]
|
local_locations = [Location(point) for point in points]
|
||||||
|
|
||||||
self.local_locations = Locations._move_to_existing(local_locations)
|
self.local_locations = Locations._move_to_existing(local_locations)
|
||||||
|
|
@ -470,7 +489,7 @@ class HexLocations(LocationList):
|
||||||
class PolarLocations(LocationList):
|
class PolarLocations(LocationList):
|
||||||
"""Location Context: Polar Array
|
"""Location Context: Polar Array
|
||||||
|
|
||||||
Push a polar array of locations to Part or Sketch
|
Creates a context of polar array of locations for Part or Sketch
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
radius (float): array radius
|
radius (float): array radius
|
||||||
|
|
@ -515,7 +534,7 @@ class PolarLocations(LocationList):
|
||||||
class Locations(LocationList):
|
class Locations(LocationList):
|
||||||
"""Location Context: Push Points
|
"""Location Context: Push Points
|
||||||
|
|
||||||
Push sequence of locations to Part or Sketch
|
Creates a context of locations for Part or Sketch
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
pts (Union[VectorLike, Vertex, Location]): sequence of points to push
|
pts (Union[VectorLike, Vertex, Location]): sequence of points to push
|
||||||
|
|
@ -571,15 +590,15 @@ class Locations(LocationList):
|
||||||
class GridLocations(LocationList):
|
class GridLocations(LocationList):
|
||||||
"""Location Context: Rectangular Array
|
"""Location Context: Rectangular Array
|
||||||
|
|
||||||
Push a rectangular array of locations to Part or Sketch
|
Creates a context of rectangular array of locations for Part or Sketch
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
x_spacing (float): horizontal spacing
|
x_spacing (float): horizontal spacing
|
||||||
y_spacing (float): vertical spacing
|
y_spacing (float): vertical spacing
|
||||||
x_count (int): number of horizontal points
|
x_count (int): number of horizontal points
|
||||||
y_count (int): number of vertical points
|
y_count (int): number of vertical points
|
||||||
centered: specify centering along each axis.
|
align (tuple[Align, Align], optional): align min, center, or max of object.
|
||||||
offset (VectorLike): offset to apply to all locations. Defaults to (0,0).
|
Defaults to (Align.CENTER, Align.CENTER).
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
ValueError: Either x or y count must be greater than or equal to one.
|
ValueError: Either x or y count must be greater than or equal to one.
|
||||||
|
|
@ -591,8 +610,7 @@ class GridLocations(LocationList):
|
||||||
y_spacing: float,
|
y_spacing: float,
|
||||||
x_count: int,
|
x_count: int,
|
||||||
y_count: int,
|
y_count: int,
|
||||||
centered: tuple[bool, bool] = (True, True),
|
align: tuple[Align, Align] = (Align.CENTER, Align.CENTER),
|
||||||
offset: VectorLike = (0, 0),
|
|
||||||
):
|
):
|
||||||
if x_count < 1 or y_count < 1:
|
if x_count < 1 or y_count < 1:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
|
|
@ -602,15 +620,17 @@ class GridLocations(LocationList):
|
||||||
self.y_spacing = y_spacing
|
self.y_spacing = y_spacing
|
||||||
self.x_count = x_count
|
self.x_count = x_count
|
||||||
self.y_count = y_count
|
self.y_count = y_count
|
||||||
self.centered = centered
|
self.align = align
|
||||||
self.offset = Vector(offset)
|
|
||||||
|
|
||||||
center_x_offset = (
|
size = [x_spacing * (x_count - 1), y_spacing * (y_count - 1)]
|
||||||
x_spacing * (x_count - 1) / 2 if centered[0] else 0 + self.offset.X
|
align_offset = []
|
||||||
)
|
for i in range(2):
|
||||||
center_y_offset = (
|
if align[i] == Align.MIN:
|
||||||
y_spacing * (y_count - 1) / 2 if centered[1] else 0 + self.offset.Y
|
align_offset.append(0)
|
||||||
)
|
elif align[i] == Align.CENTER:
|
||||||
|
align_offset.append(-size[i] / 2)
|
||||||
|
elif align[i] == Align.MAX:
|
||||||
|
align_offset.append(-size[i])
|
||||||
|
|
||||||
# Create the list of local locations
|
# Create the list of local locations
|
||||||
local_locations = []
|
local_locations = []
|
||||||
|
|
@ -618,8 +638,8 @@ class GridLocations(LocationList):
|
||||||
local_locations.append(
|
local_locations.append(
|
||||||
Location(
|
Location(
|
||||||
Vector(
|
Vector(
|
||||||
i * x_spacing - center_x_offset,
|
i * x_spacing + align_offset[0],
|
||||||
j * y_spacing - center_y_offset,
|
j * y_spacing + align_offset[1],
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ desc:
|
||||||
|
|
||||||
TODO:
|
TODO:
|
||||||
- add TwistExtrude, ProjectText
|
- add TwistExtrude, ProjectText
|
||||||
- add centered to wedge
|
|
||||||
|
|
||||||
license:
|
license:
|
||||||
|
|
||||||
|
|
@ -256,8 +255,8 @@ class BasePartObject(Compound):
|
||||||
Args:
|
Args:
|
||||||
solid (Solid): object to create
|
solid (Solid): object to create
|
||||||
rotation (RotationLike, optional): angles to rotate about axes. Defaults to (0, 0, 0).
|
rotation (RotationLike, optional): angles to rotate about axes. Defaults to (0, 0, 0).
|
||||||
centered (tuple[bool, bool, bool], optional): center about axes.
|
align (tuple[Align, Align, Align], optional): align min, center, or max of object.
|
||||||
Defaults to (True, True, True).
|
Defaults to (Align.CENTER, Align.CENTER, Align.CENTER).
|
||||||
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
|
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -375,7 +375,7 @@ class TestBuilderExit(unittest.TestCase):
|
||||||
class TestLocations(unittest.TestCase):
|
class TestLocations(unittest.TestCase):
|
||||||
def test_no_centering(self):
|
def test_no_centering(self):
|
||||||
with BuildSketch():
|
with BuildSketch():
|
||||||
with GridLocations(4, 4, 2, 2, centered=(False, False)) as l:
|
with GridLocations(4, 4, 2, 2, align=(Align.MIN, Align.MIN)) as l:
|
||||||
pts = [loc.to_tuple()[0] for loc in l.locations]
|
pts = [loc.to_tuple()[0] for loc in l.locations]
|
||||||
self.assertTupleAlmostEquals(pts[0], (0, 0, 0), 5)
|
self.assertTupleAlmostEquals(pts[0], (0, 0, 0), 5)
|
||||||
self.assertTupleAlmostEquals(pts[1], (0, 4, 0), 5)
|
self.assertTupleAlmostEquals(pts[1], (0, 4, 0), 5)
|
||||||
|
|
@ -384,7 +384,7 @@ class TestLocations(unittest.TestCase):
|
||||||
|
|
||||||
def test_centering(self):
|
def test_centering(self):
|
||||||
with BuildSketch():
|
with BuildSketch():
|
||||||
with GridLocations(4, 4, 2, 2, centered=(True, True)) as l:
|
with GridLocations(4, 4, 2, 2, align=(Align.CENTER, Align.CENTER)) as l:
|
||||||
pts = [loc.to_tuple()[0] for loc in l.locations]
|
pts = [loc.to_tuple()[0] for loc in l.locations]
|
||||||
self.assertTupleAlmostEquals(pts[0], (-2, -2, 0), 5)
|
self.assertTupleAlmostEquals(pts[0], (-2, -2, 0), 5)
|
||||||
self.assertTupleAlmostEquals(pts[1], (-2, 2, 0), 5)
|
self.assertTupleAlmostEquals(pts[1], (-2, 2, 0), 5)
|
||||||
|
|
|
||||||
|
|
@ -274,17 +274,17 @@ class HexArrayTests(unittest.TestCase):
|
||||||
def test_hexarray_in_sketch(self):
|
def test_hexarray_in_sketch(self):
|
||||||
with BuildSketch() as test:
|
with BuildSketch() as test:
|
||||||
Rectangle(70, 70)
|
Rectangle(70, 70)
|
||||||
with HexLocations(20, 4, 3, centered=(True, True)):
|
with HexLocations(20, 4, 3, align=(Align.CENTER, Align.CENTER)):
|
||||||
Circle(5, mode=Mode.SUBTRACT)
|
Circle(5, mode=Mode.SUBTRACT)
|
||||||
self.assertAlmostEqual(test.sketch.area, 70**2 - 12 * 25 * pi, 5)
|
self.assertAlmostEqual(test.sketch.area, 70**2 - 12 * 25 * pi, 5)
|
||||||
|
|
||||||
def test_error(self):
|
def test_error(self):
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
with BuildSketch():
|
with BuildSketch():
|
||||||
with HexLocations(20, 0, 3, centered=(True, True)):
|
with HexLocations(20, 0, 3, align=(Align.CENTER, Align.CENTER)):
|
||||||
pass
|
pass
|
||||||
with BuildSketch():
|
with BuildSketch():
|
||||||
with HexLocations(20, 1, -3, centered=(True, True)):
|
with HexLocations(20, 1, -3, align=(Align.CENTER, Align.CENTER)):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue