Skip to content

Commit 641d0aa

Browse files
committed
feat(sweep): enhance sweep functionality to support round corners
1 parent cb567db commit 641d0aa

File tree

11 files changed

+81
-19
lines changed

11 files changed

+81
-19
lines changed

cpp/src/factory.cpp

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <BRepFilletAPI_MakeFillet.hxx>
1111
#include <BRepFilletAPI_MakeChamfer.hxx>
1212
#include <BRepOffsetAPI_MakePipe.hxx>
13+
#include <BRepOffsetAPI_MakePipeShell.hxx>
1314
#include <BRepPrimAPI_MakeBox.hxx>
1415
#include <BRepBuilderAPI_MakeWire.hxx>
1516
#include <BRepPrimAPI_MakePrism.hxx>
@@ -200,9 +201,29 @@ class ShapeFactory
200201
return ShapeResult{cylinder.Solid(), true, ""};
201202
}
202203

203-
static ShapeResult sweep(const TopoDS_Shape &profile, const TopoDS_Wire &wire)
204+
static ShapeResult sweep(const ShapeArray &sections, const TopoDS_Wire &path, bool isFrenet, bool isForceC1)
204205
{
205-
BRepOffsetAPI_MakePipe pipe(wire, profile);
206+
BRepOffsetAPI_MakePipeShell pipe(path);
207+
if (isFrenet) {
208+
pipe.SetMode(isFrenet);
209+
}
210+
211+
if (isForceC1) {
212+
pipe.SetTransitionMode(BRepBuilderAPI_RoundCorner);
213+
pipe.SetForceApproxC1(isForceC1);
214+
} else {
215+
pipe.SetTransitionMode(BRepBuilderAPI_RightCorner);
216+
}
217+
218+
std::vector<TopoDS_Shape> shapesVec = vecFromJSArray<TopoDS_Shape>(sections);
219+
for (const auto &shape : shapesVec)
220+
{
221+
pipe.Add(shape);
222+
}
223+
224+
pipe.Build();
225+
pipe.MakeSolid();
226+
206227
if (!pipe.IsDone())
207228
{
208229
return ShapeResult{TopoDS_Shape(), false, "Failed to sweep profile"};
@@ -445,6 +466,9 @@ class ShapeFactory
445466
}
446467

447468
static ShapeResult booleanOperate(BRepAlgoAPI_BooleanOperation& boolOperater, const ShapeArray &args, const ShapeArray& tools) {
469+
boolOperater.SetRunParallel(true);
470+
boolOperater.SetFuzzyValue(1e-6);
471+
boolOperater.SetToFillHistory(false);
448472
std::vector<TopoDS_Shape> argsVec = vecFromJSArray<TopoDS_Shape>(args);
449473
TopTools_ListOfShape argsList;
450474
for (auto shape : argsVec) {
@@ -463,24 +487,22 @@ class ShapeFactory
463487
if (!boolOperater.IsDone()) {
464488
return ShapeResult{TopoDS_Shape(), false, "Failed to build boolean operation"};
465489
}
490+
boolOperater.SimplifyResult();
466491
return ShapeResult{boolOperater.Shape(), true, ""};
467492
}
468493

469494
static ShapeResult booleanCommon(const ShapeArray &args, const ShapeArray& tools) {
470495
BRepAlgoAPI_Common api;
471-
api.SetRunParallel(true);
472496
return booleanOperate(api, args, tools);
473497
}
474498

475499
static ShapeResult booleanCut(const ShapeArray &args, const ShapeArray& tools) {
476500
BRepAlgoAPI_Cut api;
477-
api.SetRunParallel(true);
478501
return booleanOperate(api, args, tools);
479502
}
480503

481504
static ShapeResult booleanFuse(const ShapeArray &args, const ShapeArray& tools) {
482505
BRepAlgoAPI_Fuse api;
483-
api.SetRunParallel(true);
484506
return booleanOperate(api, args, tools);
485507
}
486508

packages/chili-core/src/i18n/en.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ export default {
170170
"model.visible": "Visible",
171171
"option.command.repeat": "Repeat",
172172
"option.command.isFace": "Face",
173+
"option.command.isRoundCorner": "Round Corner",
173174
"option.command.thickness": "Thickness",
174175
"option.command.isConnected": "Connected",
175176
"option.command.isConvertInstance": "Convert Instance",
@@ -188,8 +189,10 @@ export default {
188189
"prompt.select.faces": "Please select faces",
189190
"prompt.select.models": "Please select models",
190191
"prompt.select.noModelSelected": "No model selected",
192+
"prompt.select.section": "Please select section",
191193
"prompt.select.shape": "Please select shape",
192194
"prompt.select.solids": "Please select solids",
195+
"prompt.select.path": "Please select path",
193196
"prompt.select.vertexes": "Please select vertexes",
194197
"prompt.select.wires": "Please select wires",
195198
"toast.snap.notFoundValidPoint": "No valid point",

packages/chili-core/src/i18n/keys.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ const I18N_KEYS = [
169169
"prompt.pickRadius",
170170
"option.command.repeat",
171171
"option.command.isFace",
172+
"option.command.isRoundCorner",
172173
"option.command.thickness",
173174
"option.command.isConnected",
174175
"option.command.isConvertInstance",
@@ -182,8 +183,10 @@ const I18N_KEYS = [
182183
"prompt.select.faces",
183184
"prompt.select.models",
184185
"prompt.select.noModelSelected",
186+
"prompt.select.section",
185187
"prompt.select.shape",
186188
"prompt.select.solids",
189+
"prompt.select.path",
187190
"prompt.select.vertexes",
188191
"prompt.select.wires",
189192
"properties.group.transform",

packages/chili-core/src/i18n/zh-cn.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ export default {
171171
"option.command.repeat": "重复",
172172
"option.command.isFace": "面",
173173
"option.command.thickness": "厚度",
174+
"option.command.isRoundCorner": "圆角",
174175
"option.command.isConnected": "相连",
175176
"option.command.isConvertInstance": "转为实例",
176177
"option.command.insertPoint": "插入点",
@@ -187,8 +188,10 @@ export default {
187188
"prompt.select.faces": "请选择面",
188189
"prompt.select.models": "请选择模型",
189190
"prompt.select.noModelSelected": "未选择任何模型",
191+
"prompt.select.section": "请选择截面",
190192
"prompt.select.shape": "选择形状",
191193
"prompt.select.solids": "请选择实体",
194+
"prompt.select.path": "请选择路径",
192195
"prompt.select.vertexes": "请选择点",
193196
"prompt.select.wires": "请选择线",
194197
"toast.snap.notFoundValidPoint": "未找到有效的点",

packages/chili-core/src/shape/shapeFactory.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export interface IShapeFactory {
3434
wire(edges: IEdge[]): Result<IWire>;
3535
prism(shape: IShape, vec: XYZ): Result<IShape>;
3636
fuse(bottom: IShape, top: IShape): Result<IShape>;
37-
sweep(profile: IShape, path: IWire): Result<IShape>;
37+
sweep(profile: IShape[], path: IWire, isRoundCorner: boolean): Result<IShape>;
3838
revolve(profile: IShape, axis: Ray, angle: number): Result<IShape>;
3939
booleanCommon(shape1: IShape, shape2: IShape): Result<IShape>;
4040
booleanCut(shape1: IShape, shape2: IShape): Result<IShape>;

packages/chili-wasm/lib/chili-wasm.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -585,11 +585,11 @@ interface EmbindModule {
585585
ShapeResult: {};
586586
ShapeFactory: {
587587
makeThickSolidBySimple(_0: TopoDS_Shape, _1: number): ShapeResult;
588-
sweep(_0: TopoDS_Shape, _1: TopoDS_Wire): ShapeResult;
589588
polygon(_0: Array<Vector3>): ShapeResult;
590589
bezier(_0: Array<Vector3>, _1: Array<number>): ShapeResult;
591590
fillet(_0: TopoDS_Shape, _1: Array<number>, _2: number): ShapeResult;
592591
chamfer(_0: TopoDS_Shape, _1: Array<number>, _2: number): ShapeResult;
592+
sweep(_0: Array<TopoDS_Shape>, _1: TopoDS_Wire, _2: boolean, _3: boolean): ShapeResult;
593593
makeThickSolidByJoin(_0: TopoDS_Shape, _1: Array<TopoDS_Shape>, _2: number): ShapeResult;
594594
booleanCommon(_0: Array<TopoDS_Shape>, _1: Array<TopoDS_Shape>): ShapeResult;
595595
booleanCut(_0: Array<TopoDS_Shape>, _1: Array<TopoDS_Shape>): ShapeResult;
206 KB
Binary file not shown.

packages/chili-wasm/src/factory.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,9 +236,9 @@ export class ShapeFactory implements IShapeFactory {
236236
wasm.ShapeFactory.booleanFuse(ensureOccShape(bottom), ensureOccShape(top)),
237237
);
238238
}
239-
sweep(profile: IShape, path: IWire): Result<IShape> {
239+
sweep(profile: IShape[], path: IWire, isRound: boolean): Result<IShape> {
240240
return convertShapeResult(
241-
wasm.ShapeFactory.sweep(ensureOccShape(profile)[0], ensureOccShape(path)[0]),
241+
wasm.ShapeFactory.sweep(ensureOccShape(profile), ensureOccShape(path)[0], true, isRound),
242242
);
243243
}
244244
revolve(profile: IShape, axis: Ray, angle: number): Result<IShape> {

packages/chili/src/bodys/sweep.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
ShapeType,
1414
} from "chili-core";
1515

16-
@Serializer.register(["document", "profile", "path"])
16+
@Serializer.register(["document", "profile", "path", "round"])
1717
export class SweepedNode extends ParameterShapeNode {
1818
override display(): I18nKeys {
1919
return "body.sweep";
@@ -23,7 +23,7 @@ export class SweepedNode extends ParameterShapeNode {
2323
get profile() {
2424
return this.getPrivateValue("profile");
2525
}
26-
set profile(value: IShape) {
26+
set profile(value: IShape[]) {
2727
this.setPropertyEmitShapeChanged("profile", value);
2828
}
2929

@@ -35,10 +35,22 @@ export class SweepedNode extends ParameterShapeNode {
3535
this.setPropertyEmitShapeChanged("path", value);
3636
}
3737

38-
constructor(document: IDocument, profile: IShape, path: IWire | IEdge) {
38+
@Serializer.serialze()
39+
get round() {
40+
return this.getPrivateValue("round");
41+
}
42+
set round(value: boolean) {
43+
this.setPropertyEmitShapeChanged("round", value);
44+
}
45+
46+
constructor(document: IDocument, profile: (IWire | IEdge)[], path: IWire | IEdge, round: boolean) {
3947
super(document);
40-
this.setPrivateValue("profile", profile);
48+
this.setPrivateValue(
49+
"profile",
50+
profile.map((p) => this.ensureWire(p)),
51+
);
4152
this.setPrivateValue("path", this.ensureWire(path));
53+
this.setPrivateValue("round", round);
4254
}
4355

4456
private ensureWire(path: IEdge | IWire) {
@@ -50,6 +62,6 @@ export class SweepedNode extends ParameterShapeNode {
5062
}
5163

5264
override generateShape(): Result<IShape> {
53-
return this.document.application.shapeFactory.sweep(this.profile, this.path);
65+
return this.document.application.shapeFactory.sweep(this.profile, this.path, this.round);
5466
}
5567
}

packages/chili/src/commands/create/sweep.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Part of the Chili3d Project, under the AGPL-3.0 License.
22
// See LICENSE file in the project root for full license information.
33

4-
import { GeometryNode, IWire, ShapeType, command } from "chili-core";
4+
import { GeometryNode, IWire, Property, ShapeType, command } from "chili-core";
55
import { SweepedNode } from "../../bodys";
66
import { IStep } from "../../step";
77
import { SelectShapeStep } from "../../step/selectStep";
@@ -12,16 +12,27 @@ import { CreateCommand } from "../createCommand";
1212
icon: "icon-sweep",
1313
})
1414
export class Sweep extends CreateCommand {
15+
@Property.define("option.command.isRoundCorner")
16+
get round() {
17+
return this.getPrivateValue("round", false);
18+
}
19+
20+
set round(value: boolean) {
21+
this.setProperty("round", value);
22+
}
23+
1524
protected override geometryNode(): GeometryNode {
16-
const shape = this.transformdFirstShape(this.stepDatas[0], false);
25+
const shape = this.transformdShapes(this.stepDatas[0], false) as IWire[];
1726
const path = this.transformdFirstShape(this.stepDatas[1], false) as IWire;
18-
return new SweepedNode(this.document, shape, path);
27+
return new SweepedNode(this.document, shape, path, this.round);
1928
}
2029

2130
protected override getSteps(): IStep[] {
2231
return [
23-
new SelectShapeStep(ShapeType.Edge | ShapeType.Wire | ShapeType.Face, "prompt.select.shape"),
24-
new SelectShapeStep(ShapeType.Edge | ShapeType.Wire, "prompt.select.edges", {
32+
new SelectShapeStep(ShapeType.Edge | ShapeType.Wire, "prompt.select.section", {
33+
multiple: true,
34+
}),
35+
new SelectShapeStep(ShapeType.Edge | ShapeType.Wire, "prompt.select.path", {
2536
keepSelection: true,
2637
}),
2738
];

packages/chili/src/commands/multistepCommand.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,14 @@ export abstract class MultistepCommand extends CancelableCommand {
119119
return shape;
120120
}
121121

122+
protected transformdShapes(step: SnapResult, shouldDispose = true) {
123+
return step.shapes.map((s) => {
124+
const shape = s.shape.transformedMul(s.transform);
125+
if (shouldDispose) this.disposeStack.add(shape);
126+
return shape;
127+
});
128+
}
129+
122130
protected abstract getSteps(): IStep[];
123131

124132
protected abstract executeMainTask(): void;

0 commit comments

Comments
 (0)