Open gumyr opened 1 year ago
A solver would be great to have.
One way to explicitly represent it in the builder API would be to have a dedicated "BuildConstrainedLine" context of some sort, with objects to create partially-specified shapes and relationships between them.
Using an example sketch from jamarzka on the Discord:
You could write this sketch out something like this:
with BuildPart() as constraint_based_arrowhead:
with BuildSketch():
with BuildConstrainedLine():
outer_left = FreeLine()
outer_right = FreeLine()
inner_left = FreeLine()
inner_right = FreeLine()
top_arc = FreeArc(
center = (0, 1.5),
radius = 0.125,
dir = Direction.CLOCKWISE)
left_arc = FreeArc(
center = (None, -0.4375),
radius = 0.1875,
dir = Direction.CLOCKWISE)
right_arc = FreeArc(
center = (None, -0.4375),
radius = 0.1875,
dir = Direction.CLOCKWISE)
middle_arc = FreeArc(
center = (0, 0),
radius = 0.25,
dir = Direction.ANTICLOCKWISE)
ConstrainTangent(left_arc @ 1, outer_left @ 0)
ConstrainTangent(outer_left @ 1, top_arc @ 0)
ConstrainTangent(top_arc @ 1, outer_right @ 0)
ConstrainTangent(outer_right @ 1, right_arc @ 0)
ConstrainTangent(right_arc @ 1, inner_right @ 0)
ConstrainTangent(inner_right @ 1, middle_arc @ 0)
ConstrainTangent(middle_arc @ 1, inner_left @ 0)
ConstrainTangent(inner_left @ 1, left_arc @ 0)
ConstrainNoOverlap(outer_left, outer_right, inner_left, inner_right)
ConstrainDistance(left_arc, right_arc, 19,
mode = DistanceMode.FARTHEST_POINT)
extrude(amount = 1)
One of the defining features of constraints is that they don't exist in isolation; If a sketch is fully constrained except for one part with unconstrained geometry, that could be trivially found via math or use of a specific definition of the geometry (JernArc
vs ThreePointArc
for example).
The interesting things happen when two or more unconstrained geometries interact. I imagine the constraint API being defined as one of the following two options:
Fuzzy
. So for example, JernArc(start=(0,0), tangent=(1,0), radius=10, arc_size=Fuzzy(300) )
Fuzzy
parameters can also be unspecified, allowing for Fuzzy()
& Fuzzy(x)
Fuzzy
is inherited, so if a JernArc
is fuzzy, and the @
/%
/^
operators are used, then the value is fuzzy.FuzzyJernArc
ect.I'll use 1 for my example, but the idea is the same for 2. The general idea is that fuzzy geometry is tracked separately until enough parameters are provided to solve them.
with BuildPart() as bp:
with BuildSketch() as bs:
line_a = Line([(0,0), (1,0)])
line_b = Line([(3,2), (4,2)])
arc_a = JernArc(
start = line_a @ 1,
tangent = line_b % 1,
radius = Fuzzy(1),
arc_size = Fuzzy(90)
)
# Everything will resolve here since enough parameters have been provided
arc_b = JernArc (
start = line_b @ 0,
tangent = line_b % 0,
radius = Fuzzy(1),
arc_size = Fuzzy(90),
end_of_arc = arc_a @ 1,
)
Internally this could be tracked by a flag on classes, and interactions between fuzzy and non-fuzzy geometry could throw an error.
Although not required frequently, having the capability to use a solver while creating a drawing (likely only BuildLine) would be an important addition.
@fpq473 shows a solvespace example:
where dragged refers to a list of parameters that are being dragged; these are the ones that we should put as close as possible to their initial positions.
Here are a couple proposals for how solvespace might be integrated in b3d: 1) From @johnmeacham:
2) From @fpq473:
Initial Proposal
At first glance, it seems as though having BuildLine accept constraints as parameters such as points or radii in addition to fixed values would fit the best. All constraints would be evaluated when BuildLine exits resulting in concrete object. Getting constraints to work with all BuildLine objects could be challenging though.
It might look something like:
The
BuildLine.__exit__
could fail if there is no solution, otherwisesketch_builder
would have a new Face to work with as normal.Would this be the type of thing the community is looking for?