rcad 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/ext/_rcad/_rcad.cpp +316 -124
- data/lib/rcad.rb +238 -24
- data/lib/rcad/version.rb +1 -1
- metadata +2 -2
data/ext/_rcad/_rcad.cpp
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
#include <sstream>
|
1
2
|
#include <gp_Pnt2d.hxx>
|
2
3
|
#include <gp_Pnt.hxx>
|
3
4
|
#include <gp_Vec.hxx>
|
@@ -5,9 +6,11 @@
|
|
5
6
|
#include <TColgp_Array2OfPnt.hxx>
|
6
7
|
#include <Poly_Triangulation.hxx>
|
7
8
|
#include <Geom_BezierSurface.hxx>
|
9
|
+
#include <Geom_Circle.hxx>
|
8
10
|
#include <GCE2d_MakeSegment.hxx>
|
9
11
|
#include <TopoDS.hxx>
|
10
12
|
#include <BRepPrimAPI_MakeBox.hxx>
|
13
|
+
#include <BRepPrimAPI_MakeCone.hxx>
|
11
14
|
#include <BRepPrimAPI_MakeCylinder.hxx>
|
12
15
|
#include <BRepPrimAPI_MakeSphere.hxx>
|
13
16
|
#include <BRepPrimAPI_MakeTorus.hxx>
|
@@ -29,6 +32,7 @@
|
|
29
32
|
#include <BRepClass3d_SolidClassifier.hxx>
|
30
33
|
#include <BRepTopAdaptor_FClass2d.hxx>
|
31
34
|
#include <BRepMesh_IncrementalMesh.hxx>
|
35
|
+
#include <BRepBndLib.hxx>
|
32
36
|
#include <StlAPI_Reader.hxx>
|
33
37
|
#include <StlAPI_Writer.hxx>
|
34
38
|
#include <Standard_Failure.hxx>
|
@@ -86,17 +90,17 @@ gp_Pnt2d from_ruby<gp_Pnt2d>(Object obj)
|
|
86
90
|
}
|
87
91
|
|
88
92
|
template<>
|
89
|
-
|
93
|
+
gp_XYZ from_ruby<gp_XYZ>(Object obj)
|
90
94
|
{
|
91
95
|
Array ary(obj);
|
92
96
|
|
93
97
|
if (ary.size() == 2) {
|
94
|
-
return
|
98
|
+
return gp_XYZ(
|
95
99
|
from_ruby<Standard_Real>(ary[0]),
|
96
100
|
from_ruby<Standard_Real>(ary[1]),
|
97
101
|
0);
|
98
102
|
} else if (ary.size() == 3) {
|
99
|
-
return
|
103
|
+
return gp_XYZ(
|
100
104
|
from_ruby<Standard_Real>(ary[0]),
|
101
105
|
from_ruby<Standard_Real>(ary[1]),
|
102
106
|
from_ruby<Standard_Real>(ary[2]));
|
@@ -106,6 +110,12 @@ gp_Pnt from_ruby<gp_Pnt>(Object obj)
|
|
106
110
|
}
|
107
111
|
}
|
108
112
|
|
113
|
+
template<>
|
114
|
+
gp_Pnt from_ruby<gp_Pnt>(Object obj)
|
115
|
+
{
|
116
|
+
return gp_Pnt(from_ruby<gp_XYZ>(obj));
|
117
|
+
}
|
118
|
+
|
109
119
|
template<>
|
110
120
|
gp_Vec from_ruby<gp_Vec>(Object obj)
|
111
121
|
{
|
@@ -128,85 +138,177 @@ gp_Dir from_ruby<gp_Dir>(Object obj)
|
|
128
138
|
return gp_Dir(from_ruby<gp_Vec>(obj));
|
129
139
|
}
|
130
140
|
|
131
|
-
|
132
|
-
|
141
|
+
template<>
|
142
|
+
Object to_ruby<gp_Mat>(const gp_Mat &mat)
|
133
143
|
{
|
134
|
-
|
135
|
-
return shape;
|
136
|
-
}
|
144
|
+
Array mat_ary;
|
137
145
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
}
|
146
|
+
for (int i = 1; i <= 3; ++i) {
|
147
|
+
Array row_ary;
|
148
|
+
for (int j = 1; j <= 3; ++j) {
|
149
|
+
row_ary.push(mat(i, j));
|
150
|
+
}
|
144
151
|
|
145
|
-
|
146
|
-
shape = shape.call("render");
|
152
|
+
mat_ary.push(row_ary);
|
147
153
|
}
|
148
154
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
155
|
+
return mat_ary;
|
156
|
+
}
|
157
|
+
|
158
|
+
template<>
|
159
|
+
Object to_ruby<gp_XYZ>(const gp_XYZ &xyz)
|
160
|
+
{
|
161
|
+
Array ary;
|
162
|
+
ary.push(xyz.X());
|
163
|
+
ary.push(xyz.Y());
|
164
|
+
ary.push(xyz.Z());
|
165
|
+
return ary;
|
166
|
+
}
|
167
|
+
|
168
|
+
|
169
|
+
static Standard_Real get_tolerance()
|
170
|
+
{
|
171
|
+
return from_ruby<Standard_Real>(
|
172
|
+
Object(rb_gv_get("$tol")));
|
173
|
+
}
|
174
|
+
|
175
|
+
|
176
|
+
static String transform_to_s(gp_GTrsf self)
|
177
|
+
{
|
178
|
+
gp_Mat vec = self.VectorialPart();
|
179
|
+
gp_XYZ trn = self.TranslationPart();
|
180
|
+
|
181
|
+
std::stringstream s;
|
182
|
+
s << "#<Transform:";
|
183
|
+
|
184
|
+
for (int i = 1; i <= 3; ++i) {
|
185
|
+
for (int j = 1; j <= 3; ++j) {
|
186
|
+
s << vec(i, j)
|
187
|
+
<< ((j < 3) ? ", " : "; ");
|
188
|
+
}
|
154
189
|
}
|
155
190
|
|
156
|
-
|
191
|
+
s << "x=" << trn.X()
|
192
|
+
<< ", y=" << trn.Y()
|
193
|
+
<< ", z=" << trn.Z();
|
194
|
+
|
195
|
+
s << ">";
|
196
|
+
return s.str();
|
157
197
|
}
|
158
198
|
|
159
|
-
static
|
199
|
+
static gp_Mat transform_mat_part(gp_GTrsf self)
|
160
200
|
{
|
161
|
-
|
162
|
-
shape_obj.iv_set("@shape", to_ruby(shape));
|
163
|
-
return shape_obj;
|
201
|
+
return self.VectorialPart();
|
164
202
|
}
|
165
203
|
|
166
|
-
static
|
204
|
+
static void transform_mat_part_set(gp_GTrsf &self, gp_Mat mat)
|
167
205
|
{
|
168
|
-
|
169
|
-
return wrap_rendered_shape(
|
170
|
-
BRepBuilderAPI_Transform(*rendered, transform, Standard_True).Shape());
|
206
|
+
self.SetVectorialPart(mat);
|
171
207
|
}
|
172
208
|
|
173
|
-
|
174
|
-
Standard_Real z)
|
209
|
+
static gp_XYZ transform_ofs_part(gp_GTrsf self)
|
175
210
|
{
|
176
|
-
|
177
|
-
transform.SetTranslation(gp_Vec(x, y, z));
|
178
|
-
return shape_transform(self, transform);
|
211
|
+
return self.TranslationPart();
|
179
212
|
}
|
180
213
|
|
181
|
-
|
214
|
+
static void transform_ofs_part_set(gp_GTrsf &self, gp_XYZ ofs)
|
182
215
|
{
|
183
|
-
|
184
|
-
transform.SetRotation(gp_Ax1(gp_Pnt(), axis), angle);
|
185
|
-
return shape_transform(self, transform);
|
216
|
+
self.SetTranslationPart(ofs);
|
186
217
|
}
|
187
218
|
|
188
|
-
|
219
|
+
static gp_GTrsf transform_multiply(gp_GTrsf self, gp_GTrsf right)
|
220
|
+
{
|
221
|
+
gp_GTrsf gtrsf = self;
|
222
|
+
gtrsf.Multiply(right);
|
223
|
+
return gtrsf;
|
224
|
+
}
|
225
|
+
|
226
|
+
static gp_GTrsf transform_move(gp_GTrsf self, Standard_Real x, Standard_Real y,
|
189
227
|
Standard_Real z)
|
190
228
|
{
|
191
|
-
gp_GTrsf
|
192
|
-
|
229
|
+
gp_GTrsf gtrsf;
|
230
|
+
gtrsf.SetTranslationPart(gp_XYZ(x, y, z));
|
231
|
+
gtrsf.Multiply(self); // gtrsf *= self
|
232
|
+
return gtrsf;
|
233
|
+
}
|
234
|
+
|
235
|
+
static gp_GTrsf transform_rotate(gp_GTrsf self, Standard_Real angle,
|
236
|
+
gp_Dir axis)
|
237
|
+
{
|
238
|
+
gp_Trsf rot;
|
239
|
+
rot.SetRotation(gp_Ax1(gp_Pnt(), axis), angle);
|
240
|
+
|
241
|
+
gp_GTrsf gtrsf(rot);
|
242
|
+
gtrsf.Multiply(self); // gtrsf *= self
|
243
|
+
return gtrsf;
|
244
|
+
}
|
245
|
+
|
246
|
+
static gp_GTrsf transform_scale(gp_GTrsf self,
|
247
|
+
Standard_Real x, Standard_Real y, Standard_Real z)
|
248
|
+
{
|
249
|
+
gp_GTrsf gtrsf;
|
250
|
+
gtrsf.SetVectorialPart(
|
193
251
|
gp_Mat(x, 0, 0,
|
194
252
|
0, y, 0,
|
195
253
|
0, 0, z));
|
196
254
|
|
197
|
-
|
198
|
-
return
|
199
|
-
BRepBuilderAPI_GTransform(*rendered, transform, Standard_True).Shape());
|
255
|
+
gtrsf.Multiply(self); // gtrsf *= self
|
256
|
+
return gtrsf;
|
200
257
|
}
|
201
258
|
|
202
|
-
|
203
|
-
Standard_Real z)
|
259
|
+
static gp_GTrsf transform_mirror(gp_GTrsf self,
|
260
|
+
Standard_Real x, Standard_Real y, Standard_Real z)
|
204
261
|
{
|
205
262
|
gp_Ax2 mirror_plane(gp::Origin(), gp_Dir(x, y, z));
|
206
263
|
|
207
|
-
gp_Trsf
|
208
|
-
|
209
|
-
|
264
|
+
gp_Trsf mirror;
|
265
|
+
mirror.SetMirror(mirror_plane);
|
266
|
+
|
267
|
+
gp_GTrsf gtrsf(mirror);
|
268
|
+
gtrsf.Multiply(self); // gtrsf *= self
|
269
|
+
return gtrsf;
|
270
|
+
}
|
271
|
+
|
272
|
+
static gp_GTrsf transform_inverse(gp_GTrsf self)
|
273
|
+
{
|
274
|
+
gp_GTrsf gtrsf = self;
|
275
|
+
gtrsf.Invert();
|
276
|
+
return gtrsf;
|
277
|
+
}
|
278
|
+
|
279
|
+
|
280
|
+
static Data_Object<TopoDS_Shape> render_shape(Object shape)
|
281
|
+
{
|
282
|
+
if (shape.is_a(rb_cRenderedShape)) {
|
283
|
+
return shape;
|
284
|
+
}
|
285
|
+
|
286
|
+
if (!shape.is_a(rb_cShape)) {
|
287
|
+
String shape_str = shape.to_s();
|
288
|
+
throw Exception(rb_eArgError,
|
289
|
+
"attempt to render %s which is not a Shape",
|
290
|
+
shape_str.c_str());
|
291
|
+
}
|
292
|
+
|
293
|
+
while (shape.is_a(rb_cShape)) {
|
294
|
+
shape = shape.call("render");
|
295
|
+
}
|
296
|
+
|
297
|
+
if (!shape.is_a(rb_cRenderedShape)) {
|
298
|
+
String shape_str = shape.to_s();
|
299
|
+
throw Exception(rb_eArgError,
|
300
|
+
"render returned %s instead of a rendered shape",
|
301
|
+
shape_str.c_str());
|
302
|
+
}
|
303
|
+
|
304
|
+
return shape;
|
305
|
+
}
|
306
|
+
|
307
|
+
// TODO: better to just put things in a Data_Object to begin with, than to
|
308
|
+
// allocate them twice
|
309
|
+
static Object wrap_rendered_shape(const TopoDS_Shape &shape)
|
310
|
+
{
|
311
|
+
return Data_Object<TopoDS_Shape>(new TopoDS_Shape(shape));
|
210
312
|
}
|
211
313
|
|
212
314
|
void shape_write_stl(Object self, String path)
|
@@ -216,10 +318,34 @@ void shape_write_stl(Object self, String path)
|
|
216
318
|
StlAPI_Writer writer;
|
217
319
|
writer.ASCIIMode() = false;
|
218
320
|
writer.RelativeMode() = false;
|
219
|
-
writer.SetDeflection(
|
321
|
+
writer.SetDeflection(get_tolerance());
|
220
322
|
writer.Write(*shape, path.c_str());
|
221
323
|
}
|
222
324
|
|
325
|
+
Object shape__bbox(Object self)
|
326
|
+
{
|
327
|
+
Data_Object<TopoDS_Shape> shape = render_shape(self);
|
328
|
+
|
329
|
+
Standard_Real minXYZ[3];
|
330
|
+
Standard_Real maxXYZ[3];
|
331
|
+
Bnd_Box bbox;
|
332
|
+
BRepBndLib::Add(*shape, bbox);
|
333
|
+
bbox.Get(
|
334
|
+
minXYZ[0], minXYZ[1], minXYZ[2],
|
335
|
+
maxXYZ[0], maxXYZ[1], maxXYZ[2]);
|
336
|
+
|
337
|
+
const Standard_Real gap = bbox.GetGap();
|
338
|
+
for (int i = 0; i < 3; ++i) {
|
339
|
+
minXYZ[i] += gap;
|
340
|
+
maxXYZ[i] -= gap;
|
341
|
+
}
|
342
|
+
|
343
|
+
Array res;
|
344
|
+
res.push(Array(minXYZ));
|
345
|
+
res.push(Array(maxXYZ));
|
346
|
+
return res;
|
347
|
+
}
|
348
|
+
|
223
349
|
|
224
350
|
Object shape_from_stl(String path)
|
225
351
|
{
|
@@ -230,6 +356,17 @@ Object shape_from_stl(String path)
|
|
230
356
|
}
|
231
357
|
|
232
358
|
|
359
|
+
Object transformed_shape_render(Object self)
|
360
|
+
{
|
361
|
+
gp_GTrsf transform = from_ruby<gp_GTrsf>(self.iv_get("@trsf"));
|
362
|
+
|
363
|
+
Object shape = self.iv_get("@shape");
|
364
|
+
Data_Object<TopoDS_Shape> rendered = render_shape(shape);
|
365
|
+
|
366
|
+
return wrap_rendered_shape(
|
367
|
+
BRepBuilderAPI_GTransform(*rendered, transform, Standard_True).Shape());
|
368
|
+
}
|
369
|
+
|
233
370
|
static TopoDS_Wire make_wire_from_path(Array points, Array path)
|
234
371
|
{
|
235
372
|
BRepBuilderAPI_MakeWire wire_maker;
|
@@ -292,6 +429,16 @@ Object box_render(Object self)
|
|
292
429
|
}
|
293
430
|
|
294
431
|
|
432
|
+
Object cone_render(Object self)
|
433
|
+
{
|
434
|
+
Standard_Real height = from_ruby<Standard_Real>(self.iv_get("@height"));
|
435
|
+
Standard_Real dia1 = from_ruby<Standard_Real>(self.iv_get("@bottom_dia"));
|
436
|
+
Standard_Real dia2 = from_ruby<Standard_Real>(self.iv_get("@top_dia"));
|
437
|
+
return to_ruby(
|
438
|
+
BRepPrimAPI_MakeCone(dia1 / 2.0, dia2 / 2.0, height).Shape());
|
439
|
+
}
|
440
|
+
|
441
|
+
|
295
442
|
Object cylinder_render(Object self)
|
296
443
|
{
|
297
444
|
Standard_Real height = from_ruby<Standard_Real>(self.iv_get("@height"));
|
@@ -420,50 +567,21 @@ static bool is_inner_wire_of_face(TopoDS_Wire wire, TopoDS_Face face)
|
|
420
567
|
return (fclass2D.PerformInfinitePoint() != TopAbs_OUT);
|
421
568
|
}
|
422
569
|
|
423
|
-
static TopoDS_Shape
|
424
|
-
|
570
|
+
static TopoDS_Shape extrude_wire(TopoDS_Wire profile, TopoDS_Wire spine,
|
571
|
+
TopoDS_Face spine_support)
|
425
572
|
{
|
426
|
-
|
427
|
-
// 90 degrees.
|
428
|
-
const int num_twist_segments = (int)(fabs(twist) / M_PI_2 + 1);
|
429
|
-
// note that height and twist are doubles so division is not integer
|
430
|
-
// division
|
431
|
-
const Standard_Real seg_height = height / num_twist_segments;
|
432
|
-
const Standard_Real seg_twist = twist / num_twist_segments;
|
433
|
-
|
434
|
-
Handle_Geom_BezierSurface surf_hnd(
|
435
|
-
new Geom_BezierSurface(
|
436
|
-
TColgp_Array2OfPnt(
|
437
|
-
1, num_twist_segments + 1,
|
438
|
-
1, 2)));
|
439
|
-
|
440
|
-
for (int i = 1; i <= num_twist_segments + 1; ++i) {
|
441
|
-
const Standard_Real z = seg_height * (i - 1);
|
442
|
-
const Standard_Real angle = seg_twist * (i - 1);
|
443
|
-
surf_hnd->SetPole(i, 1, gp_Pnt(0, 0, z));
|
444
|
-
surf_hnd->SetPole(i, 2, gp_Pnt(cos(angle), sin(angle), z));
|
445
|
-
}
|
446
|
-
|
447
|
-
TopoDS_Face spine_support =
|
448
|
-
// TODO: tolerance
|
449
|
-
BRepBuilderAPI_MakeFace(surf_hnd, 0, 1, 0, 1,
|
450
|
-
Precision::Confusion());
|
451
|
-
|
452
|
-
Handle_Geom2d_Curve uv_curve_hnd =
|
453
|
-
GCE2d_MakeSegment(gp_Pnt2d(0, 0), gp_Pnt2d(1, 0));
|
454
|
-
TopoDS_Edge spine = BRepBuilderAPI_MakeEdge(uv_curve_hnd, surf_hnd);
|
455
|
-
TopoDS_Wire spine_wire = BRepBuilderAPI_MakeWire(spine);
|
456
|
-
|
457
|
-
|
458
|
-
BRepOffsetAPI_MakePipeShell pipe_maker(spine_wire);
|
573
|
+
BRepOffsetAPI_MakePipeShell pipe_maker(spine);
|
459
574
|
|
460
|
-
if (!
|
461
|
-
|
462
|
-
|
575
|
+
if (!spine_support.IsNull()) {
|
576
|
+
if (!pipe_maker.SetMode(spine_support)) {
|
577
|
+
throw Exception(rb_cOCEError,
|
578
|
+
"failed setting twisted surface-normal for PipeShell");
|
579
|
+
}
|
463
580
|
}
|
464
581
|
|
465
|
-
pipe_maker.Add(
|
466
|
-
|
582
|
+
pipe_maker.Add(profile);
|
583
|
+
const Standard_Real tolerance = get_tolerance();
|
584
|
+
pipe_maker.SetTolerance(tolerance, tolerance);
|
467
585
|
pipe_maker.Build();
|
468
586
|
|
469
587
|
if (!pipe_maker.MakeSolid()) {
|
@@ -473,8 +591,8 @@ static TopoDS_Shape twist_extrude_wire(TopoDS_Wire wire, Standard_Real height,
|
|
473
591
|
return pipe_maker.Shape();
|
474
592
|
}
|
475
593
|
|
476
|
-
static TopoDS_Shape
|
477
|
-
|
594
|
+
static TopoDS_Shape extrude_face(TopoDS_Face profile, TopoDS_Wire spine,
|
595
|
+
TopoDS_Face spine_support)
|
478
596
|
{
|
479
597
|
// extrude outer and inner wires separately, then subtract the inner
|
480
598
|
// shapes from the outer shape. there should be only one outer shape,
|
@@ -488,10 +606,10 @@ static TopoDS_Shape twist_extrude_face(TopoDS_Face face, Standard_Real height,
|
|
488
606
|
|
489
607
|
TopExp_Explorer texp;
|
490
608
|
|
491
|
-
TopoDS_Face orface = TopoDS::Face(
|
609
|
+
TopoDS_Face orface = TopoDS::Face(profile.Oriented(TopAbs_FORWARD));
|
492
610
|
for (texp.Init(orface, TopAbs_WIRE); texp.More(); texp.Next()) {
|
493
611
|
TopoDS_Wire wire = TopoDS::Wire(texp.Current());
|
494
|
-
TopoDS_Shape ext_wire =
|
612
|
+
TopoDS_Shape ext_wire = extrude_wire(wire, spine, spine_support);
|
495
613
|
|
496
614
|
if (is_inner_wire_of_face(wire, orface)) {
|
497
615
|
builder.Add(inner, ext_wire);
|
@@ -503,6 +621,60 @@ static TopoDS_Shape twist_extrude_face(TopoDS_Face face, Standard_Real height,
|
|
503
621
|
return BRepAlgoAPI_Cut(outer, inner).Shape();
|
504
622
|
}
|
505
623
|
|
624
|
+
static TopoDS_Shape extrude_shape(TopoDS_Shape profile, TopoDS_Wire spine,
|
625
|
+
TopoDS_Face spine_support)
|
626
|
+
{
|
627
|
+
BRep_Builder builder;
|
628
|
+
TopoDS_Compound compound;
|
629
|
+
builder.MakeCompound(compound);
|
630
|
+
|
631
|
+
TopExp_Explorer texp;
|
632
|
+
for (texp.Init(profile, TopAbs_FACE); texp.More(); texp.Next()) {
|
633
|
+
builder.Add(compound,
|
634
|
+
extrude_face(
|
635
|
+
TopoDS::Face(texp.Current()), spine, spine_support));
|
636
|
+
}
|
637
|
+
|
638
|
+
return compound;
|
639
|
+
}
|
640
|
+
|
641
|
+
static TopoDS_Shape twist_extrude(TopoDS_Shape shape, Standard_Real height,
|
642
|
+
Standard_Real twist)
|
643
|
+
{
|
644
|
+
// split height into segments. each segment will twist no more than
|
645
|
+
// 90 degrees.
|
646
|
+
const int num_twist_segments = (int)(fabs(twist) / M_PI_2 + 1);
|
647
|
+
// note that height and twist are doubles so division is not integer
|
648
|
+
// division
|
649
|
+
const Standard_Real seg_height = height / num_twist_segments;
|
650
|
+
const Standard_Real seg_twist = twist / num_twist_segments;
|
651
|
+
|
652
|
+
Handle_Geom_BezierSurface surf_hnd(
|
653
|
+
new Geom_BezierSurface(
|
654
|
+
TColgp_Array2OfPnt(
|
655
|
+
1, num_twist_segments + 1,
|
656
|
+
1, 2)));
|
657
|
+
|
658
|
+
for (int i = 1; i <= num_twist_segments + 1; ++i) {
|
659
|
+
const Standard_Real z = seg_height * (i - 1);
|
660
|
+
const Standard_Real angle = seg_twist * (i - 1);
|
661
|
+
surf_hnd->SetPole(i, 1, gp_Pnt(0, 0, z));
|
662
|
+
surf_hnd->SetPole(i, 2, gp_Pnt(cos(angle), sin(angle), z));
|
663
|
+
}
|
664
|
+
|
665
|
+
TopoDS_Face spine_support =
|
666
|
+
// TODO: tolerance
|
667
|
+
BRepBuilderAPI_MakeFace(surf_hnd, 0, 1, 0, 1,
|
668
|
+
Precision::Confusion());
|
669
|
+
|
670
|
+
Handle_Geom2d_Curve uv_curve_hnd =
|
671
|
+
GCE2d_MakeSegment(gp_Pnt2d(0, 0), gp_Pnt2d(1, 0));
|
672
|
+
TopoDS_Edge spine = BRepBuilderAPI_MakeEdge(uv_curve_hnd, surf_hnd);
|
673
|
+
TopoDS_Wire spine_wire = BRepBuilderAPI_MakeWire(spine);
|
674
|
+
|
675
|
+
return extrude_shape(shape, spine_wire, spine_support);
|
676
|
+
}
|
677
|
+
|
506
678
|
// initialize is defined in Ruby code
|
507
679
|
Object linear_extrusion_render(Object self)
|
508
680
|
{
|
@@ -517,38 +689,35 @@ Object linear_extrusion_render(Object self)
|
|
517
689
|
BRepPrimAPI_MakePrism(*shape, gp_Vec(0, 0, height),
|
518
690
|
Standard_True).Shape());
|
519
691
|
} else {
|
520
|
-
|
521
|
-
TopoDS_Compound compound;
|
522
|
-
builder.MakeCompound(compound);
|
523
|
-
|
524
|
-
TopExp_Explorer texp;
|
525
|
-
for (texp.Init(*shape, TopAbs_FACE); texp.More(); texp.Next()) {
|
526
|
-
builder.Add(compound,
|
527
|
-
twist_extrude_face(
|
528
|
-
TopoDS::Face(texp.Current()), height, twist));
|
529
|
-
}
|
530
|
-
|
531
|
-
return wrap_rendered_shape(compound);
|
692
|
+
return wrap_rendered_shape(twist_extrude(*shape, height, twist));
|
532
693
|
}
|
533
694
|
}
|
534
695
|
|
535
696
|
|
536
|
-
// initialize is defined in Ruby code
|
537
697
|
Object revolution_render(Object self)
|
538
698
|
{
|
539
699
|
Object profile = self.iv_get("@profile");
|
540
700
|
Data_Object<TopoDS_Shape> shape = render_shape(profile);
|
541
701
|
|
542
702
|
Object angle = self.iv_get("@angle");
|
703
|
+
|
704
|
+
gp_Circ circ(gp_Ax2(gp::Origin(), -gp::DY(), gp::DX()), 1.0);
|
705
|
+
TopoDS_Edge edge;
|
706
|
+
|
543
707
|
if (angle.is_nil()) {
|
544
|
-
|
545
|
-
BRepPrimAPI_MakeRevol(*shape, gp::OY(), Standard_True).Shape());
|
708
|
+
edge = BRepBuilderAPI_MakeEdge(circ);
|
546
709
|
} else {
|
547
710
|
Standard_Real angle_num = from_ruby<Standard_Real>(angle);
|
548
|
-
|
549
|
-
|
550
|
-
|
711
|
+
angle_num = std::max(angle_num, 0.0);
|
712
|
+
angle_num = std::min(angle_num, M_PI * 2);
|
713
|
+
|
714
|
+
Handle_Geom_Curve curve_hnd(new Geom_Circle(circ));
|
715
|
+
edge = BRepBuilderAPI_MakeEdge(curve_hnd, 0, angle_num);
|
551
716
|
}
|
717
|
+
|
718
|
+
TopoDS_Wire spine = BRepBuilderAPI_MakeWire(edge);
|
719
|
+
return wrap_rendered_shape(
|
720
|
+
extrude_shape(*shape, spine, TopoDS_Face()));
|
552
721
|
}
|
553
722
|
|
554
723
|
|
@@ -581,11 +750,13 @@ static std::vector<gp_Pnt> get_points_from_shapes(Array shapes)
|
|
581
750
|
{
|
582
751
|
std::vector<gp_Pnt> points;
|
583
752
|
|
753
|
+
const Standard_Real tolerance = get_tolerance();
|
754
|
+
|
584
755
|
for (size_t i = 0; i < shapes.size(); ++i) {
|
585
756
|
Data_Object<TopoDS_Shape> shape_obj = render_shape(shapes[i]);
|
586
757
|
const TopoDS_Shape &shape = *shape_obj;
|
587
758
|
|
588
|
-
BRepMesh_IncrementalMesh(shape,
|
759
|
+
BRepMesh_IncrementalMesh(shape, tolerance);
|
589
760
|
|
590
761
|
get_points_from_shape(shape, points);
|
591
762
|
}
|
@@ -594,13 +765,13 @@ static std::vector<gp_Pnt> get_points_from_shapes(Array shapes)
|
|
594
765
|
}
|
595
766
|
|
596
767
|
|
597
|
-
// Sort function object to sort
|
768
|
+
// Sort function object to sort the vertices of a convex polygon
|
598
769
|
// Algorithm from here:
|
599
770
|
// http://stackoverflow.com/a/15104911/2758814
|
600
|
-
class
|
771
|
+
class ConvexPolygonVertexSortComparator
|
601
772
|
{
|
602
773
|
public:
|
603
|
-
|
774
|
+
ConvexPolygonVertexSortComparator(std::vector<gp_Pnt> vertices)
|
604
775
|
: vertices(vertices)
|
605
776
|
{
|
606
777
|
if (vertices.size() == 0) {
|
@@ -673,7 +844,7 @@ static TopoDS_Solid make_solid_from_qhull()
|
|
673
844
|
}
|
674
845
|
|
675
846
|
sort(vertices.begin(), vertices.end(),
|
676
|
-
|
847
|
+
ConvexPolygonVertexSortComparator(vertices));
|
677
848
|
|
678
849
|
BRepBuilderAPI_MakePolygon poly_maker;
|
679
850
|
for (size_t i = 0; i < vertices.size(); ++i) {
|
@@ -734,21 +905,38 @@ static Object _hull(Array shapes)
|
|
734
905
|
extern "C"
|
735
906
|
void Init__rcad()
|
736
907
|
{
|
737
|
-
|
738
|
-
define_class<TopoDS_Shape>("RenderedShape");
|
908
|
+
rb_cRenderedShape = define_class<TopoDS_Shape>("RenderedShape");
|
739
909
|
|
740
910
|
Data_Type<Standard_Failure> rb_cOCEError =
|
741
911
|
define_class("OCEError", rb_eRuntimeError);
|
742
912
|
|
913
|
+
Class rb_cTransform = define_class<gp_GTrsf>("Transform")
|
914
|
+
.add_handler<Standard_Failure>(translate_oce_exception)
|
915
|
+
.define_method("to_s", &transform_to_s)
|
916
|
+
.define_method("mat_part", &transform_mat_part)
|
917
|
+
.define_method("mat_part=", &transform_mat_part_set)
|
918
|
+
.define_method("ofs_part", &transform_ofs_part)
|
919
|
+
.define_method("ofs_part=", &transform_ofs_part_set)
|
920
|
+
.define_method("*", &transform_multiply)
|
921
|
+
.define_method("move", &transform_move)
|
922
|
+
.define_method("rotate", &transform_rotate)
|
923
|
+
.define_method("scale", &transform_scale)
|
924
|
+
.define_method("mirror", &transform_mirror)
|
925
|
+
.define_method("inverse", &transform_inverse);
|
926
|
+
|
927
|
+
rb_const_set(rb_cObject, Identifier("I"), to_ruby<gp_GTrsf>(gp_GTrsf()));
|
928
|
+
|
929
|
+
|
743
930
|
rb_cShape = define_class("Shape")
|
744
931
|
.add_handler<Standard_Failure>(translate_oce_exception)
|
745
|
-
.define_method("move", &shape_move)
|
746
|
-
.define_method("rotate", &shape_rotate)
|
747
|
-
.define_method("scale", &shape_scale)
|
748
|
-
.define_method("mirror", &shape_mirror)
|
749
932
|
.define_method("write_stl", &shape_write_stl)
|
933
|
+
.define_method("_bbox", &shape__bbox)
|
750
934
|
.define_singleton_method("from_stl", &shape_from_stl);
|
751
935
|
|
936
|
+
Class rb_cTransformedShape = define_class("TransformedShape", rb_cShape)
|
937
|
+
.add_handler<Standard_Failure>(translate_oce_exception)
|
938
|
+
.define_method("render", &transformed_shape_render);
|
939
|
+
|
752
940
|
Class rb_cPolygon = define_class("Polygon", rb_cShape)
|
753
941
|
.add_handler<Standard_Failure>(translate_oce_exception)
|
754
942
|
.define_method("render", &polygon_render);
|
@@ -762,6 +950,10 @@ void Init__rcad()
|
|
762
950
|
.add_handler<Standard_Failure>(translate_oce_exception)
|
763
951
|
.define_method("render", &box_render);
|
764
952
|
|
953
|
+
Class rb_cCone = define_class("Cone", rb_cShape)
|
954
|
+
.add_handler<Standard_Failure>(translate_oce_exception)
|
955
|
+
.define_method("render", &cone_render);
|
956
|
+
|
765
957
|
Class rb_cCylinder = define_class("Cylinder", rb_cShape)
|
766
958
|
.add_handler<Standard_Failure>(translate_oce_exception)
|
767
959
|
.define_method("render", &cylinder_render);
|
data/lib/rcad.rb
CHANGED
@@ -29,12 +29,64 @@ class Numeric
|
|
29
29
|
end
|
30
30
|
|
31
31
|
|
32
|
+
# global tolerance value used by C++ extension when rendering shapes
|
33
|
+
$tol = 50.um
|
34
|
+
|
35
|
+
|
32
36
|
def to_polar(r, a)
|
33
37
|
return [r * Math::cos(a), r * Math::sin(a)]
|
34
38
|
end
|
35
39
|
|
36
40
|
|
37
|
-
|
41
|
+
class Transform
|
42
|
+
def move_x(delta)
|
43
|
+
move(delta, 0, 0)
|
44
|
+
end
|
45
|
+
|
46
|
+
def move_y(delta)
|
47
|
+
move(0, delta, 0)
|
48
|
+
end
|
49
|
+
|
50
|
+
def move_z(delta)
|
51
|
+
move(0, 0, delta)
|
52
|
+
end
|
53
|
+
|
54
|
+
def rot_x(angle)
|
55
|
+
rotate(angle, [1, 0, 0])
|
56
|
+
end
|
57
|
+
|
58
|
+
def rot_y(angle)
|
59
|
+
rotate(angle, [0, 1, 0])
|
60
|
+
end
|
61
|
+
|
62
|
+
def rot_z(angle)
|
63
|
+
rotate(angle, [0, 0, 1])
|
64
|
+
end
|
65
|
+
|
66
|
+
def scale_x(factor)
|
67
|
+
scale(factor, 1, 1)
|
68
|
+
end
|
69
|
+
|
70
|
+
def scale_y(factor)
|
71
|
+
scale(1, factor, 1)
|
72
|
+
end
|
73
|
+
|
74
|
+
def scale_z(factor)
|
75
|
+
scale(1, 1, factor)
|
76
|
+
end
|
77
|
+
|
78
|
+
def mirror_x
|
79
|
+
mirror(1, 0, 0)
|
80
|
+
end
|
81
|
+
|
82
|
+
def mirror_y
|
83
|
+
mirror(0, 1, 0)
|
84
|
+
end
|
85
|
+
|
86
|
+
def mirror_z
|
87
|
+
mirror(0, 0, 1)
|
88
|
+
end
|
89
|
+
end
|
38
90
|
|
39
91
|
|
40
92
|
class Shape
|
@@ -63,9 +115,30 @@ class Shape
|
|
63
115
|
$shape = ($shape == nil) ? self : $shape.send($shape_mode, self)
|
64
116
|
end
|
65
117
|
|
118
|
+
p self
|
66
119
|
self
|
67
120
|
end
|
68
121
|
|
122
|
+
def transform(trsf)
|
123
|
+
TransformedShape.new(self, trsf)
|
124
|
+
end
|
125
|
+
|
126
|
+
def move(x, y, z)
|
127
|
+
TransformedShape.new(self, I.move(x, y, z))
|
128
|
+
end
|
129
|
+
|
130
|
+
def rotate(angle, axis)
|
131
|
+
TransformedShape.new(self, I.rotate(angle, axis))
|
132
|
+
end
|
133
|
+
|
134
|
+
def scale(x, y, z)
|
135
|
+
TransformedShape.new(self, I.scale(x, y, z))
|
136
|
+
end
|
137
|
+
|
138
|
+
def mirror(x, y, z)
|
139
|
+
TransformedShape.new(self, I.mirror(x, y, z))
|
140
|
+
end
|
141
|
+
|
69
142
|
def move_x(delta)
|
70
143
|
move(delta, 0, 0)
|
71
144
|
end
|
@@ -118,48 +191,120 @@ class Shape
|
|
118
191
|
LinearExtrusion.new(self, height, twist)
|
119
192
|
end
|
120
193
|
|
121
|
-
def revolve(angle=
|
194
|
+
def revolve(angle=nil)
|
122
195
|
Revolution.new(self, angle)
|
123
196
|
end
|
124
197
|
|
125
198
|
def bbox
|
126
|
-
|
199
|
+
if @bbox == nil
|
200
|
+
@bbox = _bbox
|
201
|
+
end
|
202
|
+
|
203
|
+
@bbox
|
204
|
+
end
|
205
|
+
|
206
|
+
def minx
|
207
|
+
bbox[0][0]
|
127
208
|
end
|
128
209
|
|
129
|
-
def
|
130
|
-
bbox[0]
|
210
|
+
def miny
|
211
|
+
bbox[0][1]
|
131
212
|
end
|
132
213
|
|
133
|
-
def
|
134
|
-
bbox[0]
|
214
|
+
def minz
|
215
|
+
bbox[0][2]
|
135
216
|
end
|
136
217
|
|
137
|
-
def
|
138
|
-
bbox[0]
|
218
|
+
def maxx
|
219
|
+
bbox[1][0]
|
139
220
|
end
|
140
221
|
|
141
|
-
def
|
142
|
-
bbox[1]
|
222
|
+
def maxy
|
223
|
+
bbox[1][1]
|
143
224
|
end
|
144
225
|
|
145
|
-
def
|
146
|
-
bbox[1]
|
226
|
+
def maxz
|
227
|
+
bbox[1][2]
|
147
228
|
end
|
148
229
|
|
149
|
-
def
|
150
|
-
|
230
|
+
def xsize
|
231
|
+
maxx - minx
|
151
232
|
end
|
152
233
|
|
153
|
-
def
|
154
|
-
|
234
|
+
def ysize
|
235
|
+
maxy - miny
|
155
236
|
end
|
156
237
|
|
157
|
-
def
|
158
|
-
|
238
|
+
def zsize
|
239
|
+
maxz - minz
|
159
240
|
end
|
160
241
|
|
161
|
-
def
|
162
|
-
|
242
|
+
def cx
|
243
|
+
(minx + maxx) / 2.0
|
244
|
+
end
|
245
|
+
|
246
|
+
def cy
|
247
|
+
(miny + maxy) / 2.0
|
248
|
+
end
|
249
|
+
|
250
|
+
def cz
|
251
|
+
(minz + maxz) / 2.0
|
252
|
+
end
|
253
|
+
|
254
|
+
def left
|
255
|
+
I.move_x(minx)
|
256
|
+
end
|
257
|
+
|
258
|
+
def right
|
259
|
+
I.move_x(maxx)
|
260
|
+
end
|
261
|
+
|
262
|
+
def front
|
263
|
+
I.move_y(miny)
|
264
|
+
end
|
265
|
+
|
266
|
+
def back
|
267
|
+
I.move_y(maxy)
|
268
|
+
end
|
269
|
+
|
270
|
+
def top
|
271
|
+
I.move_z(maxz)
|
272
|
+
end
|
273
|
+
|
274
|
+
def bottom
|
275
|
+
I.move_z(minz)
|
276
|
+
end
|
277
|
+
|
278
|
+
def xcenter
|
279
|
+
I.move_x(cx)
|
280
|
+
end
|
281
|
+
|
282
|
+
def ycenter
|
283
|
+
I.move_y(cy)
|
284
|
+
end
|
285
|
+
|
286
|
+
def zcenter
|
287
|
+
I.move_z(cz)
|
288
|
+
end
|
289
|
+
|
290
|
+
def center
|
291
|
+
I.move(cx, cy, cz)
|
292
|
+
end
|
293
|
+
|
294
|
+
def align(*align_pts)
|
295
|
+
at = align_pts.pop
|
296
|
+
|
297
|
+
if align_pts.empty?
|
298
|
+
return self.transform(at)
|
299
|
+
end
|
300
|
+
|
301
|
+
combined = align_pts
|
302
|
+
.map { |apt| (apt.is_a? Transform) ? apt : self.send(apt) }
|
303
|
+
.reduce :*
|
304
|
+
|
305
|
+
combined = (yield self) * combined if block_given?
|
306
|
+
|
307
|
+
self.transform(at * combined.inverse)
|
163
308
|
end
|
164
309
|
end
|
165
310
|
|
@@ -221,7 +366,41 @@ at_exit do
|
|
221
366
|
end
|
222
367
|
|
223
368
|
|
224
|
-
class
|
369
|
+
class TransformedShape < Shape
|
370
|
+
attr_reader :shape, :trsf
|
371
|
+
|
372
|
+
def initialize(shape, trsf)
|
373
|
+
@shape = shape
|
374
|
+
@trsf = trsf
|
375
|
+
end
|
376
|
+
|
377
|
+
def to_s
|
378
|
+
sprintf("%s*%s", @trsf, @shape)
|
379
|
+
end
|
380
|
+
|
381
|
+
def transform(trsf)
|
382
|
+
TransformedShape.new(@shape, trsf * @trsf)
|
383
|
+
end
|
384
|
+
|
385
|
+
def move(x, y, z)
|
386
|
+
TransformedShape.new(@shape, @trsf.move(x, y, z))
|
387
|
+
end
|
388
|
+
|
389
|
+
def rotate(angle, axis)
|
390
|
+
TransformedShape.new(@shape, @trsf.rotate(angle, axis))
|
391
|
+
end
|
392
|
+
|
393
|
+
def scale(x, y, z)
|
394
|
+
TransformedShape.new(@shape, @trsf.scale(x, y, z))
|
395
|
+
end
|
396
|
+
|
397
|
+
def mirror(x, y, z)
|
398
|
+
TransformedShape.new(@shape, @trsf.mirror(x, y, z))
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
|
403
|
+
class Polygon < Shape
|
225
404
|
attr_reader :points, :paths
|
226
405
|
|
227
406
|
def initialize(points, paths=nil)
|
@@ -245,13 +424,26 @@ class RegularPolygon < Polygon
|
|
245
424
|
end
|
246
425
|
|
247
426
|
|
248
|
-
class
|
427
|
+
class Rectangle < Polygon
|
428
|
+
# These override Shape.xsize etc.
|
429
|
+
attr_reader :xsize, :ysize
|
430
|
+
|
431
|
+
def initialize(xsize, ysize)
|
432
|
+
@xsize = xsize
|
433
|
+
@ysize = ysize
|
434
|
+
|
435
|
+
super([[0,0], [xsize,0], [xsize,ysize], [0,ysize]])
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
439
|
+
|
440
|
+
class Square < Rectangle
|
249
441
|
attr_reader :size
|
250
442
|
|
251
443
|
def initialize(size)
|
252
444
|
@size = size
|
253
445
|
|
254
|
-
super(
|
446
|
+
super(size, size)
|
255
447
|
end
|
256
448
|
end
|
257
449
|
|
@@ -271,6 +463,7 @@ end
|
|
271
463
|
|
272
464
|
|
273
465
|
class Box < Shape
|
466
|
+
# These override Shape.xsize etc.
|
274
467
|
attr_accessor :xsize, :ysize, :zsize
|
275
468
|
|
276
469
|
def initialize(xsize, ysize, zsize)
|
@@ -287,6 +480,25 @@ class Cube < Box
|
|
287
480
|
end
|
288
481
|
|
289
482
|
|
483
|
+
class Cone < Shape
|
484
|
+
attr_accessor :height, :bottom_dia, :top_dia
|
485
|
+
|
486
|
+
def initialize(height, bottom_dia, top_dia=0)
|
487
|
+
@height = height
|
488
|
+
@bottom_dia = bottom_dia
|
489
|
+
@top_dia = top_dia
|
490
|
+
end
|
491
|
+
|
492
|
+
def bottom_radius
|
493
|
+
bottom_dia / 2.0
|
494
|
+
end
|
495
|
+
|
496
|
+
def top_radius
|
497
|
+
top_dia / 2.0
|
498
|
+
end
|
499
|
+
end
|
500
|
+
|
501
|
+
|
290
502
|
class Cylinder < Shape
|
291
503
|
attr_accessor :height, :dia
|
292
504
|
|
@@ -383,12 +595,14 @@ end
|
|
383
595
|
|
384
596
|
make_maker :polygon, Polygon
|
385
597
|
make_maker :reg_poly, RegularPolygon
|
598
|
+
make_maker :rectangle, Rectangle
|
386
599
|
make_maker :square, Square
|
387
600
|
make_maker :circle, Circle
|
388
601
|
make_maker :text, Text
|
389
602
|
|
390
603
|
make_maker :box, Box
|
391
604
|
make_maker :cube, Cube
|
605
|
+
make_maker :cone, Cone
|
392
606
|
make_maker :cylinder, Cylinder
|
393
607
|
make_maker :sphere, Sphere
|
394
608
|
make_maker :polyhedron, Polyhedron
|
data/lib/rcad/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rcad
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-11-
|
12
|
+
date: 2013-11-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|