Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Sketch Offset: the side of the copy depends on the drawing direction of the contour, not on the sign of the distance

Open
#89 1 comment 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
48/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
rust
Domain
backend

Research direction

Start with Project::offset_entities in crates/qymcad-core/src/model/sketch.rs, then read entity_bulge_loops in crates/qymcad-core/src/model/tess.rs and the offset helpers in crates/qymcad-core/src/offset.rs. Review the offset tests in crates/qymcad-core/tests/modify.rs; their current checks do not verify which side the copy lands on. Done means positive distance produces a consistent side for clockwise and counter-clockwise contours, circles, and rectangles, with tests checking the resulting geometry.

Written by the indexing model from the issue text.

Description

bug sketch

Summary

Sketch Offset puts the copy on a side that depends on the direction the contour was drawn in, not on the sign of the distance. The same +3 gives an outside copy for a clockwise contour and an inside copy for a counter-clockwise one. Circles always grow with a positive distance, while a Rectangle-tool rectangle (and the starter cube sketch) shrinks. So a wall or allowance can silently come out on the wrong side.

The help page (docs/help/en/sketch/20-offset.md) says: "The sign of the distance chooses the side: with one sign the copy lies outside, with the other inside."

Steps to reproduce

  1. Start QymCAD (new document). Double-click Cube. Pick Sketch and choose the XY plane.
  2. With the Line tool, draw square A clockwise: top-left → top-right → bottom-right → bottom-left → back to top-left. Press Esc.
  3. With the Line tool, draw square B of the same size counter-clockwise: top-left → bottom-left → bottom-right → top-right → back to top-left. Press Esc.
  4. Pick Offset (Edit section) with Distance = 3 (the default). Click the 4 sides of A and press Enter. Press Esc twice.
  5. Pick Offset again with Distance = 3. Click the 4 sides of B and press Enter.
  6. Second case: in a sketch, draw a circle Ø8 and offset it by 3. Draw a rectangle with the Rectangle tool and offset it by 3. The cube's own base sketch (Sketch 1) behaves like the rectangle.

Expected

The same +3 puts the copy on the same side (inside or outside) for every closed contour, whatever the drawing direction or the tool used.

Actual

  • Square A (clockwise): the copy is outside, with R3 rounded corners.
  • Square B (counter-clockwise): the copy is inside, 3 mm in from each side.
  • Circle Ø8 at +3 becomes Ø14 (outside). A Rectangle-tool rectangle (and the starter cube sketch) at +3 gets an inside copy.

Root cause analysis

Project::offset_entities in crates/qymcad-core/src/model/sketch.rs:

  • Circles use nr = r + dist, so a positive distance always grows them.
  • Line/arc loops are built by entity_bulge_loops (model/tess.rs) in whatever order the entities chain, and passed as they are to offset::offset_bulge (sketch.rs#L2885-L2886), which calls cavalier_contours parallel_offset(dist). The orientation is never normalised (no signed-area or CCW check). cavalier's offset side follows the polyline's direction, so a positive distance shrinks CCW loops and grows CW loops.

The same module already has an orientation-independent helper for the CAM path: offset::offset_to_side picks the side by comparing areas. The arc-preserving offset_bulge used by the sketch has nothing equivalent. Normalising each loop to CCW (or flipping the sign of dist by the loop's signed area) before offset_bulge would make the side consistent with circles.

False-green tests

In crates/qymcad-core/tests/modify.rs:

  • offset_makes_inner_loop (-2, "Inwards") only checks that a contour is produced. It never checks which side it lands on.
  • offset_loop_with_arc_keeps_arcs is described as "after an outward offset the arcs stay arcs" and uses +1, but it only checks that an arc is produced. The test rectangle comes from add_rect_entity, whose corners are laid counter-clockwise (sketch.rs#L3700-L3705). It's the same call that builds the starter cube sketch (model.rs#L3277). I ran the same steps as this test (10x10 rectangle from 0 to 10, one corner filleted R2, offset +1) and printed the new entities: their bounding box is x 1..9, y 1..9. So the "outward" offset in this test actually goes inward, and neither test can catch this bug.

Environment

  • Commit: 8f66226 (main, 2026-10-06), version 0.1.0, built from source
  • OS: Debian 13.7 (trixie) x86_64 (container)
  • Toolchain: rustc 1.99.0 (stable), OpenCASCADE 7.8.1 (Debian libocct-*-dev 7.8.1+dfsg1-3)
  • Build: OCCT_LIB_DIR=/usr/lib/x86_64-linux-gnu cargo build -p qymcad (debug profile)
  • Display: Xvfb 1600x1000x24, no window manager, WGPU_BACKEND=vulkan (Mesa lavapipe 25.0.7)
  • UI language: English (default), fresh settings

Visual proof

Screenshots are attached in the comment below.

Dominant language
Rust
Stars
543
Forks
27
Avg merge
4h 9m
Merged PRs (30d)
42

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from QymIs-Tech/QymCAD

All issues in QymIs-Tech/QymCAD

Similar issues

More Rust issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.