-
Notifications
You must be signed in to change notification settings - Fork 22
/
bottle.rs
225 lines (180 loc) · 9.65 KB
/
bottle.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
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
use cxx::UniquePtr;
use opencascade_sys::ffi::{
cylinder_to_surface, ellipse_to_HandleGeom2d_Curve, ellipse_value, gp_Ax2_ctor, gp_Ax2d_ctor,
gp_Ax3_from_gp_Ax2, gp_DZ, gp_Dir2d_ctor, gp_OX, handle_geom_plane_location,
new_HandleGeomCurve_from_HandleGeom_TrimmedCurve, new_HandleGeomPlane_from_HandleGeomSurface,
new_list_of_shape, new_point, new_point_2d, new_transform, new_vec, shape_list_append_face,
type_name, write_stl, BRepAlgoAPI_Fuse_ctor, BRepBuilderAPI_MakeEdge_CurveSurface2d,
BRepBuilderAPI_MakeEdge_HandleGeomCurve, BRepBuilderAPI_MakeFace_wire,
BRepBuilderAPI_MakeWire_ctor, BRepBuilderAPI_MakeWire_edge_edge,
BRepBuilderAPI_MakeWire_edge_edge_edge, BRepBuilderAPI_Transform_ctor,
BRepFilletAPI_MakeFillet_ctor, BRepLibBuildCurves3d, BRepMesh_IncrementalMesh_ctor,
BRepOffsetAPI_MakeThickSolid_ctor, BRepOffsetAPI_ThruSections_ctor,
BRepPrimAPI_MakeCylinder_ctor, BRepPrimAPI_MakePrism_ctor, BRep_Builder_ctor,
BRep_Builder_upcast_to_topods_builder, BRep_Tool_Surface, DynamicType, ExplorerCurrentShape,
GCE2d_MakeSegment_point_point, GC_MakeArcOfCircle_Value, GC_MakeArcOfCircle_point_point_point,
GC_MakeSegment_Value, GC_MakeSegment_point_point, Geom2d_Ellipse_ctor,
Geom2d_TrimmedCurve_ctor, Geom_CylindricalSurface_ctor, HandleGeom2d_TrimmedCurve_to_curve,
MakeThickSolidByJoin, StlAPI_Writer_ctor, TopAbs_ShapeEnum, TopExp_Explorer_ctor,
TopoDS_Compound_as_shape, TopoDS_Compound_ctor, TopoDS_Face, TopoDS_Face_to_owned,
TopoDS_cast_to_edge, TopoDS_cast_to_face, TopoDS_cast_to_wire,
};
// All dimensions are in millimeters.
pub fn main() {
let height = 70.0;
let width = 50.0;
let thickness = 30.0;
// Define the points making up the bottle's profile.
let point_1 = new_point(-width / 2.0, 0.0, 0.0);
let point_2 = new_point(-width / 2.0, -thickness / 4.0, 0.0);
let point_3 = new_point(0.0, -thickness / 2.0, 0.0);
let point_4 = new_point(width / 2.0, -thickness / 4.0, 0.0);
let point_5 = new_point(width / 2.0, 0.0, 0.0);
// Define the arcs and segments of the profile.
let arc = GC_MakeArcOfCircle_point_point_point(&point_2, &point_3, &point_4);
let segment_1 = GC_MakeSegment_point_point(&point_1, &point_2);
let segment_2 = GC_MakeSegment_point_point(&point_4, &point_5);
let mut edge_1 = BRepBuilderAPI_MakeEdge_HandleGeomCurve(
&new_HandleGeomCurve_from_HandleGeom_TrimmedCurve(&GC_MakeSegment_Value(&segment_1)),
);
let mut edge_2 = BRepBuilderAPI_MakeEdge_HandleGeomCurve(
&new_HandleGeomCurve_from_HandleGeom_TrimmedCurve(&GC_MakeArcOfCircle_Value(&arc)),
);
let mut edge_3 = BRepBuilderAPI_MakeEdge_HandleGeomCurve(
&new_HandleGeomCurve_from_HandleGeom_TrimmedCurve(&GC_MakeSegment_Value(&segment_2)),
);
let mut wire = BRepBuilderAPI_MakeWire_edge_edge_edge(
edge_1.pin_mut().Edge(),
edge_2.pin_mut().Edge(),
edge_3.pin_mut().Edge(),
);
let x_axis = gp_OX();
let mut transform = new_transform();
transform.pin_mut().set_mirror_axis(x_axis);
// We're calling Shape() here instead of Wire(), hope that's okay.
let mut brep_transform =
BRepBuilderAPI_Transform_ctor(wire.pin_mut().Shape(), &transform, false);
let mirrored_shape = brep_transform.pin_mut().Shape();
let mirrored_wire = TopoDS_cast_to_wire(mirrored_shape);
let mut make_wire = BRepBuilderAPI_MakeWire_ctor();
make_wire.pin_mut().add_wire(wire.pin_mut().Wire());
make_wire.pin_mut().add_wire(mirrored_wire);
let wire_profile = make_wire.pin_mut().Wire();
let mut face_profile = BRepBuilderAPI_MakeFace_wire(wire_profile, false);
let prism_vec = new_vec(0.0, 0.0, height);
// We're calling Shape here instead of Face(), hope that's also okay.
let mut body =
BRepPrimAPI_MakePrism_ctor(face_profile.pin_mut().Shape(), &prism_vec, false, true);
let mut make_fillet = BRepFilletAPI_MakeFillet_ctor(body.pin_mut().Shape());
let mut edge_explorer =
TopExp_Explorer_ctor(body.pin_mut().Shape(), TopAbs_ShapeEnum::TopAbs_EDGE);
while edge_explorer.More() {
let edge = TopoDS_cast_to_edge(edge_explorer.Current());
make_fillet.pin_mut().add_edge(thickness / 12.0, edge);
edge_explorer.pin_mut().Next();
}
let body_shape = make_fillet.pin_mut().Shape();
// Make the bottle neck
let neck_location = new_point(0.0, 0.0, height);
let neck_axis = gp_DZ();
let neck_coord_system = gp_Ax2_ctor(&neck_location, neck_axis);
let neck_radius = thickness / 4.0;
let neck_height = height / 10.0;
let mut cylinder = BRepPrimAPI_MakeCylinder_ctor(&neck_coord_system, neck_radius, neck_height);
let cylinder_shape = cylinder.pin_mut().Shape();
let mut fuse_neck = BRepAlgoAPI_Fuse_ctor(body_shape, cylinder_shape);
let body_shape = fuse_neck.pin_mut().Shape();
// Make the bottle hollow
let mut face_explorer = TopExp_Explorer_ctor(body_shape, TopAbs_ShapeEnum::TopAbs_FACE);
let mut z_max = -1.0;
let mut top_face: Option<UniquePtr<TopoDS_Face>> = None;
while face_explorer.More() {
let shape = ExplorerCurrentShape(&face_explorer);
let face = TopoDS_cast_to_face(&shape);
let surface = BRep_Tool_Surface(face);
let dynamic_type = DynamicType(&surface);
let name = type_name(dynamic_type);
if name == "Geom_Plane" {
let plane_handle = new_HandleGeomPlane_from_HandleGeomSurface(&surface);
let plane_location = handle_geom_plane_location(&plane_handle);
let plane_z = plane_location.Z();
if plane_z > z_max {
z_max = plane_z;
top_face = Some(TopoDS_Face_to_owned(face));
}
}
face_explorer.pin_mut().Next();
}
let top_face = top_face.unwrap();
let mut faces_to_remove = new_list_of_shape();
shape_list_append_face(faces_to_remove.pin_mut(), &top_face);
let mut solid_maker = BRepOffsetAPI_MakeThickSolid_ctor();
MakeThickSolidByJoin(
solid_maker.pin_mut(),
body_shape,
&faces_to_remove,
-thickness / 50.0,
1.0e-3,
);
let body_shape = solid_maker.pin_mut().Shape();
// Create the threading
let cylinder_axis = gp_Ax3_from_gp_Ax2(&neck_coord_system);
let cylinder_1 = Geom_CylindricalSurface_ctor(&cylinder_axis, neck_radius * 0.99);
let cylinder_1 = cylinder_to_surface(&cylinder_1);
let cylinder_2 = Geom_CylindricalSurface_ctor(&cylinder_axis, neck_radius * 1.05);
let cylinder_2 = cylinder_to_surface(&cylinder_2);
let a_pnt = new_point_2d(std::f64::consts::TAU, neck_height / 2.0);
let a_dir = gp_Dir2d_ctor(std::f64::consts::TAU, neck_height / 4.0);
let thread_axis = gp_Ax2d_ctor(&a_pnt, &a_dir);
let a_major = std::f64::consts::TAU;
let a_minor = neck_height / 10.0;
let ellipse_1 = Geom2d_Ellipse_ctor(&thread_axis, a_major, a_minor);
let ellipse_1_handle = ellipse_to_HandleGeom2d_Curve(&ellipse_1);
let ellipse_2 = Geom2d_Ellipse_ctor(&thread_axis, a_major, a_minor / 4.0);
let ellipse_2_handle = ellipse_to_HandleGeom2d_Curve(&ellipse_2);
let arc_1 = Geom2d_TrimmedCurve_ctor(&ellipse_1_handle, 0.0, std::f64::consts::PI);
let arc_1 = HandleGeom2d_TrimmedCurve_to_curve(&arc_1);
let arc_2 = Geom2d_TrimmedCurve_ctor(&ellipse_2_handle, 0.0, std::f64::consts::PI);
let arc_2 = HandleGeom2d_TrimmedCurve_to_curve(&arc_2);
let ellipse_point_1 = ellipse_value(&ellipse_1, 0.0);
let ellipse_point_2 = ellipse_value(&ellipse_1, std::f64::consts::PI);
let thread_segment = GCE2d_MakeSegment_point_point(&ellipse_point_1, &ellipse_point_2);
let thread_segment = HandleGeom2d_TrimmedCurve_to_curve(&thread_segment);
let mut edge_1_on_surface_1 = BRepBuilderAPI_MakeEdge_CurveSurface2d(&arc_1, &cylinder_1);
let mut edge_2_on_surface_1 =
BRepBuilderAPI_MakeEdge_CurveSurface2d(&thread_segment, &cylinder_1);
let mut edge_1_on_surface_2 = BRepBuilderAPI_MakeEdge_CurveSurface2d(&arc_2, &cylinder_2);
let mut edge_2_on_surface_2 =
BRepBuilderAPI_MakeEdge_CurveSurface2d(&thread_segment, &cylinder_2);
let mut threading_wire_1 = BRepBuilderAPI_MakeWire_edge_edge(
edge_1_on_surface_1.pin_mut().Edge(),
edge_2_on_surface_1.pin_mut().Edge(),
);
let mut threading_wire_2 = BRepBuilderAPI_MakeWire_edge_edge(
edge_1_on_surface_2.pin_mut().Edge(),
edge_2_on_surface_2.pin_mut().Edge(),
);
// TODO - does calling Shape() work here instead of Wire()?
BRepLibBuildCurves3d(threading_wire_1.pin_mut().Shape());
BRepLibBuildCurves3d(threading_wire_2.pin_mut().Shape());
let is_solid = true;
let mut threading_loft = BRepOffsetAPI_ThruSections_ctor(is_solid);
threading_loft.pin_mut().AddWire(threading_wire_1.pin_mut().Wire());
threading_loft.pin_mut().AddWire(threading_wire_2.pin_mut().Wire());
threading_loft.pin_mut().CheckCompatibility(false);
let threading_shape = threading_loft.pin_mut().Shape();
// Build the resulting compound
let mut compound = TopoDS_Compound_ctor();
let builder = BRep_Builder_ctor();
let builder = BRep_Builder_upcast_to_topods_builder(&builder);
builder.MakeCompound(compound.pin_mut());
let mut compound_shape = TopoDS_Compound_as_shape(compound);
builder.Add(compound_shape.pin_mut(), body_shape);
builder.Add(compound_shape.pin_mut(), threading_shape);
let final_shape = compound_shape;
// Export to an STL file
let mut stl_writer = StlAPI_Writer_ctor();
let triangulation = BRepMesh_IncrementalMesh_ctor(&final_shape, 0.01);
let success = write_stl(stl_writer.pin_mut(), triangulation.Shape(), "bottle.stl".to_owned());
println!("Done! Success = {success}");
}