Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
98 changes: 98 additions & 0 deletions content/pages/docs/kcl-lang/edge-references.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
---
title: "Face API Edge References"
excerpt: "Identifying edges by their surrounding faces in KCL."
layout: manual
---

The face API identifies an edge from the faces around it instead of relying on
the edge's position in a body's internal ordering. This makes references more
stable when earlier modeling operations change the body's topology.

For most solid edges, the two adjacent faces uniquely identify the edge. Put
those faces in `sideFaces`:

```kcl,norun
fillet(
body001,
radius = 2,
edges = [{
sideFaces = [region001.tags.bottom, endCap]
}],
)
```

The faces in `sideFaces` run along the length of the edge. An operation can
split an edge into multiple edges that still have the same side faces. To select
one split, add an `endFaces` entry for a face touching the end of the intended
edge:

```kcl,norun
{
sideFaces = [region001.tags.bottom, region001.tags.right],
endFaces = [startCap]
}
```

Some solid-modeling topology can leave multiple edges with the same side and
end faces. In that case, `index` selects one of the remaining matches using a
zero-based index:

```kcl,norun
{
sideFaces = [region001.tags.bottom, endCap],
index = 1
}
```

Prefer `sideFaces` alone when it is unambiguous. Add `endFaces` when an edge has
been split, and use `index` only when the face information still leaves more
than one match. When a Face API selection supplies an edge-reference object,
keep the fields it provides rather than converting the selection to legacy
edge helpers.

An edge-reference object does not have to identify exactly one edge. A broader
reference can intentionally match multiple edges so that an operation applies
to all of them. Add `endFaces` or `index` only when the operation should target
a smaller subset of those matches.

Surface bodies do not always provide two side faces or useful end faces. Their
edge references can therefore contain a single `sideFaces` entry and rely on
`index` more often to choose a boundary edge.

The same edge-reference object can be used by operations such as `fillet`,
`chamfer`, `revolve`, `helix`, and `mirror3d` where their parameter accepts an
edge.

Sketch segments remain direct references, such as `sketch001.line1`. Edge
reference objects are for edges on generated bodies, where adjacent face tags
provide a stable description of the intended geometry.

## Edges involving generated faces

Fillets and chamfers create new faces that can form part of edges used by later
operations. Add `tag` to the edge-treatment operation to name its generated
face, then use that tag in the later edge reference. The existing operation
produces the face and should remain in the model; selecting one of its generated
faces does not mean replacing the operation itself.

For example, this fillet targets the edge shared by the existing chamfer face
and the extrusion's end cap:

```kcl,norun
chamfer001 = chamfer(
body001,
edges = [{
sideFaces = [region001.tags.right, region001.tags.bottom]
}],
length = 4,
tag = $chamferFace,
)

fillet001 = fillet(
body001,
edges = [{
sideFaces = [chamferFace, endCap]
}],
radius = 2,
)
```
1 change: 1 addition & 0 deletions content/pages/docs/kcl-lang/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ things in a more tutorial fashion. See also our documentation of the [standard l
* [Arrays and ranges](/docs/kcl-lang/arrays)
* [Enums](/docs/kcl-lang/enums)
* [Sketch on Face](/docs/kcl-lang/sketch-on-face)
* [Edge references](/docs/kcl-lang/edge-references)
* [Projects and modules](/docs/kcl-lang/modules)
* [Attributes](/docs/kcl-lang/attributes)
* [Python-to-KCL Cheat Sheet](/docs/kcl-lang/python-cheat-sheet)
Expand Down
30 changes: 15 additions & 15 deletions content/pages/docs/kcl-samples/angle-gauge/main.kcl
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,13 @@ gaugeProfileSketch = sketch(on = XY) {
vertical(lowerRightOuterEdge)

horizontalDistance([
bottomOuterEdge.end,
bottomOuterEdge.start
]) == gaugeDepth
bottomOuterEdge.end,
bottomOuterEdge.start
]) == gaugeDepth
verticalDistance([
lowerRightOuterEdge.end,
lowerRightOuterEdge.start
]) == lowerCutoutStartY
lowerRightOuterEdge.end,
lowerRightOuterEdge.start
]) == lowerCutoutStartY

// Angled cutout profile.
cutoutAngledEdge = line(start = [var 1.5in, var 0.19in], end = [var 0.5in, var 0.37in])
Expand Down Expand Up @@ -89,18 +89,18 @@ gaugeProfileSketch = sketch(on = XY) {
horizontal(cutoutAngleReferenceEdge)
vertical(cutoutLeftVerticalEdge)
angleDimension(
lines = [
cutoutAngleReferenceEdge,
cutoutAngledEdge
],
sector = 1,
) == cutoutAngle
lines = [
cutoutAngleReferenceEdge,
cutoutAngledEdge
],
sector = 1,
) == cutoutAngle

horizontalDistance([cutoutTopEdge.start, cutoutTopEdge.end]) == cutoutDepth
verticalDistance([
rightCutoutConstructionEdge.end,
rightCutoutConstructionEdge.start
]) == cutoutWidth
rightCutoutConstructionEdge.end,
rightCutoutConstructionEdge.start
]) == cutoutWidth
verticalDistance([leftOuterEdge.start, leftOuterEdge.end]) == gaugeWidth
coincident([
rightCutoutConstructionEdge.end,
Expand Down
12 changes: 6 additions & 6 deletions content/pages/docs/kcl-samples/bracket-with-slot/main.kcl
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,9 @@ tabHoleSketch = sketch(on = tabHolePlane) {
])
horizontal(countersinkGuide)
horizontalDistance([
countersinkGuide.start,
countersinkGuide.end
]) == countersinkOuterDiameter / 2
countersinkGuide.start,
countersinkGuide.end
]) == countersinkOuterDiameter / 2

coincident([
fastenerCircle.center,
Expand Down Expand Up @@ -246,9 +246,9 @@ slotProfile = sketch(on = XY) {
vertical(rightBottomGuide)

horizontalDistance([
slotCenterline.start,
slotCenterline.end
]) == slotOverallLength
slotCenterline.start,
slotCenterline.end
]) == slotOverallLength
radius(arc2) == slotWidth / 2
radius(arc4) == slotWidth / 2
coincident([
Expand Down
30 changes: 15 additions & 15 deletions content/pages/docs/kcl-samples/ceiling-fan/main.kcl
Original file line number Diff line number Diff line change
Expand Up @@ -143,23 +143,23 @@ bladeProfile = sketch(on = bladePlane) {
verticalDistance([bladeAxisSpan.start, bladeAxisSpan.end]) == bladeSpanLength - bladeTipRadius
verticalDistance([bladeAxisTip.start, bladeAxisTip.end]) == bladeTipRadius
horizontalDistance([
rootGuideRight.start,
rootGuideRight.end
]) == bladeRootHalfWidth
rootGuideRight.start,
rootGuideRight.end
]) == bladeRootHalfWidth
horizontalDistance([rootGuideLeft.start, rootGuideLeft.end]) == bladeRootHalfWidth
horizontalDistance([
neckGuideRight.start,
neckGuideRight.end
]) == bladeNeckHalfWidth
neckGuideRight.start,
neckGuideRight.end
]) == bladeNeckHalfWidth
horizontalDistance([neckGuideLeft.start, neckGuideLeft.end]) == bladeNeckHalfWidth
horizontalDistance([
tipCenterGuideRight.start,
tipCenterGuideRight.end
]) == bladeTipFlatHalfWidth
tipCenterGuideRight.start,
tipCenterGuideRight.end
]) == bladeTipFlatHalfWidth
horizontalDistance([
tipCenterGuideLeft.start,
tipCenterGuideLeft.end
]) == bladeTipFlatHalfWidth
tipCenterGuideLeft.start,
tipCenterGuideLeft.end
]) == bladeTipFlatHalfWidth
}

// Step 2: extrude the solved blade blank.
Expand Down Expand Up @@ -199,9 +199,9 @@ voidProfile = sketch(on = YZ) {
vertical(outerEdge)
tangent([bottomEdge, innerArc])
verticalDistance([
baseOffsetGuide.start,
baseOffsetGuide.end
]) == voidCutoutBottomOffset
baseOffsetGuide.start,
baseOffsetGuide.end
]) == voidCutoutBottomOffset

verticalDistance([arcRiseGuide.start, arcRiseGuide.end]) == voidCutoutHeight
horizontalDistance([topEdge.start, topEdge.end]) == voidCutoutLength
Expand Down
78 changes: 39 additions & 39 deletions content/pages/docs/kcl-samples/cold-plate/main.kcl
Original file line number Diff line number Diff line change
Expand Up @@ -314,42 +314,42 @@ copperTubePath = sketch(on = offsetPlane(XY, offset = tubeDiameter)) {
horizontalDistance([inletGuide.start, inletGuide.end]) == tubeInletX
verticalDistance([inletGuide.start, inletGuide.end]) == tubeLowerPassY
horizontalDistance([
rightLowerLoopGuide.start,
rightLowerLoopGuide.end
]) == tubeRightLoopX
rightLowerLoopGuide.start,
rightLowerLoopGuide.end
]) == tubeRightLoopX
verticalDistance([
rightLowerLoopGuide.start,
rightLowerLoopGuide.end
]) == tubeLowerLoopCenterY
rightLowerLoopGuide.start,
rightLowerLoopGuide.end
]) == tubeLowerLoopCenterY
horizontalDistance([leftLoopGuide.start, leftLoopGuide.end]) == tubeLeftLoopX
verticalDistance([leftLoopGuide.start, leftLoopGuide.end]) == 0in
horizontalDistance([
rightUpperLoopGuide.start,
rightUpperLoopGuide.end
]) == tubeRightLoopX
rightUpperLoopGuide.start,
rightUpperLoopGuide.end
]) == tubeRightLoopX
verticalDistance([
rightUpperLoopGuide.start,
rightUpperLoopGuide.end
]) == tubeUpperLoopCenterY
rightUpperLoopGuide.start,
rightUpperLoopGuide.end
]) == tubeUpperLoopCenterY
horizontalDistance([outletGuide.start, outletGuide.end]) == tubeInletX
verticalDistance([outletGuide.start, outletGuide.end]) == tubeUpperPassY
distance([
rightLowerArcStartGuide.start,
rightLowerArcStartGuide.end
]) == bendRadius
rightLowerArcStartGuide.start,
rightLowerArcStartGuide.end
]) == bendRadius
equalLength([
rightLowerArcStartGuide,
rightLowerArcEndGuide
])
distance([
leftArcStartGuide.start,
leftArcStartGuide.end
]) == bendRadius
leftArcStartGuide.start,
leftArcStartGuide.end
]) == bendRadius
equalLength([leftArcStartGuide, leftArcEndGuide])
distance([
rightUpperArcStartGuide.start,
rightUpperArcStartGuide.end
]) == bendRadius
rightUpperArcStartGuide.start,
rightUpperArcStartGuide.end
]) == bendRadius
equalLength([
rightUpperArcStartGuide,
rightUpperArcEndGuide
Expand Down Expand Up @@ -389,21 +389,21 @@ brazedCapProfile = sketch(on = YZ) {
tangent([arc3, line4])
vertical(line4)
horizontalDistance([
bottomCenterGuide.start,
bottomCenterGuide.end
]) == secondGrooveCenterY
bottomCenterGuide.start,
bottomCenterGuide.end
]) == secondGrooveCenterY
verticalDistance([
bottomCenterGuide.start,
bottomCenterGuide.end
]) == grooveFloorZ
bottomCenterGuide.start,
bottomCenterGuide.end
]) == grooveFloorZ
horizontalDistance([
topCenterGuide.start,
topCenterGuide.end
]) == secondGrooveCenterY
topCenterGuide.start,
topCenterGuide.end
]) == secondGrooveCenterY
verticalDistance([
topCenterGuide.start,
topCenterGuide.end
]) == plateTopZ + tubeDiameter * 0.75
topCenterGuide.start,
topCenterGuide.end
]) == plateTopZ + tubeDiameter * 0.75
distance([line2.start, line2.end]) == grooveWallHeight
equalLength([line2, line4])
radius(arc3) == tubeOuterRadius
Expand Down Expand Up @@ -453,13 +453,13 @@ tubeSectionSketch = sketch(on = offsetPlane(YZ, offset = tubeInletX)) {
horizontalDistance([centerGuide.start, centerGuide.end]) == tubeLowerPassY
verticalDistance([centerGuide.start, centerGuide.end]) == grooveFloorZ
horizontalDistance([
outerRadiusGuide.start,
outerRadiusGuide.end
]) == tubeOuterRadius
outerRadiusGuide.start,
outerRadiusGuide.end
]) == tubeOuterRadius
horizontalDistance([
innerRadiusGuide.start,
innerRadiusGuide.end
]) == tubeInnerRadius
innerRadiusGuide.start,
innerRadiusGuide.end
]) == tubeInnerRadius
}

tubeSectionProfile = region(segments = [tubeSectionSketch.outerCircle])
Expand Down
Loading
Loading