rcad 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|