visualdynamics.core.mesh¶
mesh
¶
Plate meshes built from planes, and solid meshes built from blocks.
A structure made of flat plates — a box, a channel, a bracket — is
described most simply as the planes it is made of: each a rectangle at
its mid-thickness, meshed into rectangular plate elements and put in an
element group of its own. plane makes one; assemble joins them into one
geometry and merges the nodes they share, so the plates are tied along
the lines where their mid-surfaces meet (Brandon, 2026-09-26, for the
BARC example). Where mid-surfaces do not meet — a bolted foot sitting on
a wall — nothing is shared, and the join is a rigid link
(fem.RIGID) between a node on each.
Each element group is then given a material and a thickness
(fem.GroupProperties, or the Element Groups table) and fem.Model.from_geometry builds the model.
Nodes on a shared line coincide because both planes divide it the same way: give planes that meet the same element size.
Functions:
| Name | Description |
|---|---|
plane |
A rectangle meshed into four-node plate elements, in one element group. |
block |
A rectangular block meshed into eight-node bricks, in one element |
landing |
Which of |
join |
Put |
assemble |
One geometry from several, joined in turn ( |
tie |
Tie a patch of elements rigidly to what lies under it (Tie): every |
Classes¶
Functions:¶
plane
¶
plane(corner: ArrayLike, edge_a: ArrayLike, edge_b: ArrayLike, size: float, name: str = '', *, unit: str | None = 'm') -> Geometry
A rectangle meshed into four-node plate elements, in one element group.
Each edge is divided evenly into the whole number of elements that
comes nearest size, so the elements come out close to square and
close to that size (Brandon, 2026-09-26: even spacing, roughly square
elements, and nothing to lay out by hand). Planes that meet along a
line divide it the same way, since it is the same length in both, so
assemble ties them there.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
corner
|
array_like
|
One corner, (x, y, z). |
required |
edge_a
|
array_like
|
The two edges from that corner, as vectors: their lengths are the rectangle's sides. They must be perpendicular — the plate element is a rectangle. |
required |
edge_b
|
array_like
|
The two edges from that corner, as vectors: their lengths are the rectangle's sides. They must be perpendicular — the plate element is a rectangle. |
required |
size
|
float
|
The element size aimed at. |
required |
name
|
str
|
The element group's name — the part this plane is. |
''
|
unit
|
str or None
|
The unit every length given here is in. The geometry holds them in SI, as any geometry with its units defined does, and remembers this one; None leaves them as given, units undefined. |
'm'
|
Returns:
| Type | Description |
|---|---|
Geometry
|
Nodes numbered from 1, one element group holding every element. |
Source code in src/visualdynamics/core/mesh.py
block
¶
block(corner: ArrayLike, edge_a: ArrayLike, edge_b: ArrayLike, edge_c: ArrayLike, size: float, name: str = '', *, unit: str | None = 'm', holes: Sequence[Any] = (), hole_name: str | None = None) -> Geometry
A rectangular block meshed into eight-node bricks, in one element group.
plane one dimension up (2026-09-30, for the four-unit frame
example): a corner and three perpendicular edges, each divided
evenly into the whole number of elements nearest size, so the
bricks come out close to cubes. Blocks that meet over a face divide
it the same way, since it is the same rectangle in both, so
assemble ties them there — give blocks that meet the same size.
Holes are cut the way a structured mesh can cut them: every brick
whose center lies within a hole's radius of its axis leaves the
block. A hole is (center, radius, axis) with the center a point on
the axis and the axis 0, 1 or 2 for the edge it runs along;
(center, radius, axis, depth) for a blind hole that depth from the
face the axis enters at; and a fifth item names the element group
its bricks go to instead of leaving — a threaded insert, given its
own material in the Element Groups table — or is None for a void. A hole with
no fifth item takes hole_name. Holes apply in order, a later one
over an earlier: a through hole, then an insert named to the same
radius part way down, then a void of the insert's bore, is a
threaded insert in a drilled hole. The nodes on a hole's rim — the
ones its bricks share with the bricks beside them — are then moved
radially onto the circle, a node on the block's own face sliding
along that face to where the circle meets it, so a hole is round to
within the polygon its rim nodes make rather than stair-stepped
(a hole centered on the block's edge is a round-over and keeps its
steps; its corner brick cannot follow an arc): a
stair-stepped hole in a member six bricks wide was anywhere from
three to four bricks across as its center fell, and the frame's
modes wandered by ten percent with it (2026-09-30).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
corner
|
array_like
|
One corner, (x, y, z). |
required |
edge_a
|
array_like
|
The three edges from that corner, as vectors: their lengths are the block's sides. They must be perpendicular. |
required |
edge_b
|
array_like
|
The three edges from that corner, as vectors: their lengths are the block's sides. They must be perpendicular. |
required |
edge_c
|
array_like
|
The three edges from that corner, as vectors: their lengths are the block's sides. They must be perpendicular. |
required |
size
|
float
|
The element size aimed at. |
required |
name
|
str
|
The element group's name — the part this is. |
''
|
unit
|
str or None
|
The unit every length given here is in, as for |
'm'
|
holes
|
sequence of tuple
|
Cylindrical holes, as above, in the same unit and the same frame. |
()
|
hole_name
|
str
|
The element group the bricks of a hole that names none go to; None removes them. |
None
|
Returns:
| Type | Description |
|---|---|
Geometry
|
Nodes numbered from 1; one element group, and one more for each name the holes put bricks in. |
Source code in src/visualdynamics/core/mesh.py
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 | |
landing
¶
landing(geometry: Geometry, part: Geometry, tolerance: float | None = None) -> tuple[ndarray, ndarray]
Which of part's nodes fall on a node of geometry, and which one
— what join does with them, asked without joining: Add Plane's
reading says how many nodes a plane would share before it is added.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
geometry
|
Geometry
|
Where the part would go, and the part. |
required |
part
|
Geometry
|
Where the part would go, and the part. |
required |
tolerance
|
float
|
As |
None
|
Returns:
| Type | Description |
|---|---|
(ndarray of bool, ndarray of int)
|
Per node of the part: whether it lands, and the row in
|
Source code in src/visualdynamics/core/mesh.py
group_families
¶
group_families(geometry: Geometry, group_id: int) -> set[str]
The element families an element group of geometry holds: empty for an
element group with no elements yet.
Source code in src/visualdynamics/core/mesh.py
group_refusal
¶
Why part cannot join geometry by element group name, or None.
An element group holds one element family (Geometry.mixed_groups), and a
part whose element group is named like one already holding another family
would make it two at once: a plate added under the name of an element group
of bricks was one element group, deleted whole from either family's row in
the tree (Brandon, 2026-10-02). The one rule join refuses by and
the Add pane reads before it offers Add.
Source code in src/visualdynamics/core/mesh.py
already_there
¶
How many of part's elements join would leave out for being
elements already there — every corner on a node already there, the
cell already filled — so a reading can say it before the Add.
Source code in src/visualdynamics/core/mesh.py
join
¶
Put part into geometry, in place: each of the part's nodes that
falls on a node already there becomes that node, the rest are added
after the highest id, and the part's elements follow them. The nodes
already there keep their ids — data linked to the geometry names
them — which is what makes this the way a plane is added to a model
under construction (Add Plane) as well as how assemble builds one.
An element group of the part named like one already in the geometry joins it:
the five planes of a box, each named 'box', are one part, given its
material once. An unnamed element group is always an element group of its own. A
named element group holding another element family is refused
(group_refusal): an element group holds one family.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
geometry
|
Geometry
|
Where the part goes; changed in place. |
required |
part
|
Geometry
|
What goes in. Its coordinates must mean what the geometry's do: both SI (units defined) or both as given. |
required |
tolerance
|
float
|
How close a node must be to one already there to be it, in meters once units are defined. Defaults to a millionth of the size of the two together. |
None
|
Returns:
| Type | Description |
|---|---|
dict
|
'added', the nodes added; 'shared', the part's nodes that fell on nodes already there; 'elements', the elements added; 'duplicates', the part's elements left out for being elements already there; 'groups', the ids of the element groups they went into. |
Source code in src/visualdynamics/core/mesh.py
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 | |
assemble
¶
One geometry from several, joined in turn (join): nodes numbered
from 1 in the order they arrive, a node falling on one already there
becoming it — so planes meeting along a line are tied there — and
element groups of the same name one element group. Unnamed element groups stay apart.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*parts
|
Geometry
|
The pieces, in the same length unit. |
()
|
tolerance
|
float
|
How close nodes must be to be one, in meters (as the geometry holds them). Defaults to a millionth of the assembly's size. |
None
|
Returns:
| Type | Description |
|---|---|
Geometry
|
|
Source code in src/visualdynamics/core/mesh.py
tie
¶
tie(geometry: Geometry, elements: Any, to: Any, group: str | None = None) -> dict
Tie a patch of elements rigidly to what lies under it (Tie): every
node of elements joined by a rigid, massless link to the nearest
node of to, the links added to a rigid element group. A bolted joint is the
use (Brandon, 2026-09-26): select the elements under a washer, tie
them to the part below — one step per bolt where two clicks per link
had been the only way.
A node the patch shares with the target is already joined and is left alone. Each link runs from the target's node to the patch's, so the patch follows the part it is bolted to.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
geometry
|
Geometry
|
Changed in place. |
required |
elements
|
sequence of int
|
The patch, by element id. |
required |
to
|
str, int or sequence of int
|
What to tie to: an element group, by name or id — its nearest nodes — or a second patch, by element ids. |
required |
group
|
str
|
The element group the links go into, by name, made rigid if new. Defaults to the geometry's first rigid element group, or a new one named 'ties'. |
None
|
Returns:
| Type | Description |
|---|---|
dict
|
'links', how many were added; 'shared', the patch's nodes left alone because the target holds them already; 'group', the id of the element group the links went into. |
Source code in src/visualdynamics/core/mesh.py
519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 | |