1 // Created on: 2008-05-30
2 // Created by: Vladislav ROMASHKO
3 // Copyright (c) 2008-2012 OPEN CASCADE SAS
5 // The content of this file is subject to the Open CASCADE Technology Public
6 // License Version 6.5 (the "License"). You may not use the content of this file
7 // except in compliance with the License. Please obtain a copy of the License
8 // at http://www.opencascade.org and read it completely before using this file.
10 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
11 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
13 // The Original Code and all software distributed under the License is
14 // distributed on an "AS IS" basis, without warranty of any kind, and the
15 // Initial Developer hereby disclaims all such warranties, including without
16 // limitation, any warranties of merchantability, fitness for a particular
17 // purpose or non-infringement. Please see the License for the specific terms
18 // and conditions governing the rights and limitations under the License.
21 #include <Voxel_FastConverter.ixx>
23 #include <Bnd_Box.hxx>
24 #include <BRep_Tool.hxx>
25 #include <BRepBndLib.hxx>
26 #include <BRepMesh.hxx>
29 #include <TopoDS_Face.hxx>
30 #include <TopExp_Explorer.hxx>
32 #include <gp_Lin2d.hxx>
33 #include <gce_MakePln.hxx>
36 #include <Poly_Triangulation.hxx>
37 #include <IntAna2d_AnaIntersection.hxx>
39 // Printing the progress in stdout.
42 Voxel_FastConverter::Voxel_FastConverter(const TopoDS_Shape& shape,
43 Voxel_ROctBoolDS& voxels,
44 const Standard_Real deflection,
45 const Standard_Integer nbx,
46 const Standard_Integer nby,
47 const Standard_Integer nbz,
48 const Standard_Integer nbthreads)
49 :myShape(shape),myVoxels(&voxels),
50 myDeflection(deflection),
51 myNbX(nbx),myNbY(nby),myNbZ(nbz),
52 myNbThreads(nbthreads),myIsBool(2),
58 Voxel_FastConverter::Voxel_FastConverter(const TopoDS_Shape& shape,
60 const Standard_Real deflection,
61 const Standard_Integer nbx,
62 const Standard_Integer nby,
63 const Standard_Integer nbz,
64 const Standard_Integer nbthreads)
65 :myShape(shape),myVoxels(&voxels),
66 myDeflection(deflection),
67 myNbX(nbx),myNbY(nby),myNbZ(nbz),
68 myNbThreads(nbthreads),myIsBool(1),
74 Voxel_FastConverter::Voxel_FastConverter(const TopoDS_Shape& shape,
75 Voxel_ColorDS& voxels,
76 const Standard_Real deflection,
77 const Standard_Integer nbx,
78 const Standard_Integer nby,
79 const Standard_Integer nbz,
80 const Standard_Integer nbthreads)
81 :myShape(shape),myVoxels(&voxels),
82 myDeflection(deflection),
83 myNbX(nbx),myNbY(nby),myNbZ(nbz),
84 myNbThreads(nbthreads),myIsBool(0),
90 void Voxel_FastConverter::Init()
97 // Check number of splits.
98 Voxel_DS* voxels = (Voxel_DS*) myVoxels;
99 if (voxels->GetNbX() != myNbX || voxels->GetNbY() != myNbY || voxels->GetNbZ() != myNbZ)
101 // Compute boundary box of the shape
103 BRepBndLib::Add(myShape, box);
105 // Define the voxel model by means of the boundary box of shape
106 Standard_Real xmin, ymin, zmin, xmax, ymax, zmax;
107 box.Get(xmin, ymin, zmin, xmax, ymax, zmax);
109 // Initialize the voxels.
111 ((Voxel_ROctBoolDS*) voxels)->Init(xmin, ymin, zmin, xmax - xmin, ymax - ymin, zmax - zmin, myNbX, myNbY, myNbZ);
112 else if (myIsBool == 1)
113 ((Voxel_BoolDS*) voxels)->Init(xmin, ymin, zmin, xmax - xmin, ymax - ymin, zmax - zmin, myNbX, myNbY, myNbZ);
114 else if (myIsBool == 0)
115 ((Voxel_ColorDS*) voxels)->Init(xmin, ymin, zmin, xmax - xmin, ymax - ymin, zmax - zmin, myNbX, myNbY, myNbZ);
118 // Check presence of triangulation.
120 Standard_Boolean triangulate = Standard_False;
121 TopExp_Explorer expl(myShape, TopAbs_FACE);
122 for (; expl.More(); expl.Next())
124 const TopoDS_Face & F = TopoDS::Face(expl.Current());
125 Handle(Poly_Triangulation) T = BRep_Tool::Triangulation(F, L);
126 if (T.IsNull() || (T->Deflection() > myDeflection))
128 triangulate = Standard_True;
133 // Re-create the triangulation.
136 BRepMesh::Mesh(myShape, myDeflection);
139 // Compute the number of triangles.
141 expl.Init(myShape, TopAbs_FACE);
142 for (; expl.More(); expl.Next())
144 const TopoDS_Face & F = TopoDS::Face(expl.Current());
145 Handle(Poly_Triangulation) T = BRep_Tool::Triangulation(F, L);
146 if (T.IsNull() == Standard_False)
147 myNbTriangles += T->NbTriangles();
152 void Voxel_FastConverter::Destroy()
157 Standard_Boolean Voxel_FastConverter::Convert(Standard_Integer& progress,
158 const Standard_Integer ithread)
164 printf("Progress = %d \r", progress);
167 if (myNbX <= 0 || myNbY <= 0 || myNbZ <= 0)
168 return Standard_False;
170 // Half of diagonal of a voxel
171 Voxel_DS* ds = (Voxel_DS*) myVoxels;
172 Standard_Real dx = ds->GetXLen() / (Standard_Real) ds->GetNbX(),
173 dy = ds->GetYLen() / (Standard_Real) ds->GetNbY(),
174 dz = ds->GetZLen() / (Standard_Real) ds->GetNbZ();
175 Standard_Real hdiagonal = sqrt(dx * dx + dy * dy + dz * dz);
178 // Compute the scope of triangles for current thread
179 Standard_Integer start_thread_triangle = 1, end_thread_triangle = myNbTriangles, ithread_triangle = 0;
180 start_thread_triangle = (ithread - 1) * (myNbTriangles / myNbThreads) + 1;
181 end_thread_triangle = (ithread - 0) * (myNbTriangles / myNbThreads);
185 Standard_Integer iprogress = 0, prev_progress = 0;
186 Standard_Integer n1, n2, n3;
187 Standard_Integer ixmin, iymin, izmin, ixmax, iymax, izmax;
188 Standard_Real xmin, ymin, zmin, xmax, ymax, zmax;
189 TopExp_Explorer expl(myShape, TopAbs_FACE);
190 for (; expl.More(); expl.Next())
192 const TopoDS_Face & F = TopoDS::Face(expl.Current());
193 Handle(Poly_Triangulation) T = BRep_Tool::Triangulation(F, L);
198 Standard_Boolean transform = !L.IsIdentity();
200 trsf = L.Transformation();
202 const TColgp_Array1OfPnt& nodes = T->Nodes();
203 const Poly_Array1OfTriangle& triangles = T->Triangles();
204 Standard_Integer itriangle = triangles.Lower(), nb_triangles = triangles.Upper();
205 for (; itriangle <= nb_triangles; itriangle++)
208 if (ithread_triangle < start_thread_triangle || ithread_triangle > end_thread_triangle)
211 const Poly_Triangle& t = triangles.Value(itriangle);
213 gp_Pnt p1 = nodes.Value(n1);
214 gp_Pnt p2 = nodes.Value(n2);
215 gp_Pnt p3 = nodes.Value(n3);
223 // Get boundary box of the triangle
224 GetBndBox(p1, p2, p3, xmin, ymin, zmin, xmax, ymax, zmax);
226 // Find the range of voxels inside the boudary box of the triangle.
227 if (!ds->GetVoxel(xmin, ymin, zmin, ixmin, iymin, izmin))
229 if (!ds->GetVoxel(xmax, ymax, zmax, ixmax, iymax, izmax))
232 // Refuse voxels for whom distance from their center to plane of triangle is greater than half of diagonal.
233 // Make a line from center of each voxel to the center of triangle and
234 // compute intersection of the line with sides of triangle.
235 // Refuse the voxel in case of intersection.
236 gce_MakePln mkPlane(p1, p2, p3);
237 if (!mkPlane.IsDone())
239 gp_Pln plane = mkPlane.Value();
240 ComputeVoxelsNearTriangle(plane, p1, p2, p3, hdiagonal, ixmin, iymin, izmin, ixmax, iymax, izmax);
246 progress = (Standard_Integer) ( (Standard_Real) iprogress / (Standard_Real) myNbTriangles * 100.0 );
249 if (ithread == 1 && prev_progress != progress)
251 printf("Progress = %d \r", progress);
252 prev_progress = progress;
256 } // iteration of triangles
257 } // iteration of faces
263 printf("Progress = %d \r", progress);
265 return Standard_True;
268 Standard_Boolean Voxel_FastConverter::FillInVolume(const Standard_Byte inner,
269 const Standard_Integer ithread)
271 Voxel_DS* ds = (Voxel_DS*) myVoxels;
272 Standard_Integer ix, iy, iz, nbx = ds->GetNbX(), nby = ds->GetNbY(), nbz = ds->GetNbZ();
273 Standard_Boolean prev_surface, surface, volume;
277 // Fill-in internal voxels by the value "inner"
278 for (ix = 0; ix < nbx; ix++)
280 for (iy = 0; iy < nby; iy++)
282 // Check existence of volume.
283 volume = Standard_False;
284 surface = Standard_False;
285 prev_surface = Standard_False;
286 for (iz = 0; iz < nbz; iz++)
288 surface = (myIsBool == 1) ?
289 ((Voxel_BoolDS*)myVoxels)->Get(ix, iy, iz) == Standard_True :
290 ((Voxel_ColorDS*)myVoxels)->Get(ix, iy, iz) > 0;
291 if (prev_surface && !surface)
295 prev_surface = surface;
300 // Fill-in the volume.
301 volume = Standard_False;
302 surface = Standard_False;
303 prev_surface = Standard_False;
304 for (iz = 0; iz < nbz; iz++)
306 surface = (myIsBool == 1) ?
307 ((Voxel_BoolDS*)myVoxels)->Get(ix, iy, iz) == Standard_True :
308 ((Voxel_ColorDS*)myVoxels)->Get(ix, iy, iz) > 0;
309 if (prev_surface && !surface)
313 if (volume && !surface)
315 (myIsBool == 1) ? ((Voxel_BoolDS*)myVoxels)->Set(ix, iy, iz, inner) :
316 ((Voxel_ColorDS*)myVoxels)->Set(ix, iy, iz, inner);
318 prev_surface = surface;
325 // Set value of interbal voxels to 0 ("inner" = 0)
326 Standard_Boolean next_surface;
327 for (ix = 0; ix < nbx; ix++)
329 for (iy = 0; iy < nby; iy++)
331 volume = Standard_False;
332 surface = Standard_False;
333 prev_surface = Standard_False;
334 next_surface = Standard_False;
335 for (iz = 0; iz < nbz; iz++)
337 surface = (myIsBool == 1) ?
338 ((Voxel_BoolDS*)myVoxels)->Get(ix, iy, iz) == Standard_True :
339 ((Voxel_ColorDS*)myVoxels)->Get(ix, iy, iz) > 0;
340 if (prev_surface != surface)
344 if (volume && iz + 1 < nbz)
346 next_surface = (myIsBool == 1) ?
347 ((Voxel_BoolDS*)myVoxels)->Get(ix, iy, iz + 1) == Standard_True :
348 ((Voxel_ColorDS*)myVoxels)->Get(ix, iy, iz + 1) > 0;
350 if (volume && prev_surface == surface && next_surface)
352 (myIsBool == 1) ? ((Voxel_BoolDS*)myVoxels)->Set(ix, iy, iz, inner) :
353 ((Voxel_ColorDS*)myVoxels)->Set(ix, iy, iz, inner);
355 prev_surface = surface;
361 return Standard_True;
364 void Voxel_FastConverter::GetBndBox(const gp_Pnt& p1,
372 Standard_Real& zmax) const
409 // This method is copied from Voxel_ShapeIntersector.cxx
410 static Standard_Boolean mayIntersect(const gp_Pnt2d& p11, const gp_Pnt2d& p12,
411 const gp_Pnt2d& p21, const gp_Pnt2d& p22)
413 if (p11.X() > p21.X() && p11.X() > p22.X() && p12.X() > p21.X() && p12.X() > p22.X())
414 return Standard_False;
415 if (p11.X() < p21.X() && p11.X() < p22.X() && p12.X() < p21.X() && p12.X() < p22.X())
416 return Standard_False;
417 if (p11.Y() > p21.Y() && p11.Y() > p22.Y() && p12.Y() > p21.Y() && p12.Y() > p22.Y())
418 return Standard_False;
419 if (p11.Y() < p21.Y() && p11.Y() < p22.Y() && p12.Y() < p21.Y() && p12.Y() < p22.Y())
420 return Standard_False;
421 return Standard_True;
424 void Voxel_FastConverter::ComputeVoxelsNearTriangle(const gp_Pln& plane,
428 const Standard_Real hdiagonal,
429 const Standard_Integer ixmin,
430 const Standard_Integer iymin,
431 const Standard_Integer izmin,
432 const Standard_Integer ixmax,
433 const Standard_Integer iymax,
434 const Standard_Integer izmax) const
437 Standard_Real xc, yc, zc, uc, vc, u1, v1, u2, v2, u3, v3;
438 Standard_Integer ix, iy, iz;
439 IntAna2d_AnaIntersection intersector2d;
441 // Project points of triangle onto the plane
442 ElSLib::Parameters(plane, p1, u1, v1);
443 ElSLib::Parameters(plane, p2, u2, v2);
444 ElSLib::Parameters(plane, p3, u3, v3);
446 // Make lines of triangle
447 gp_Pnt2d p2d1(u1, v1), p2d2(u2, v2), p2d3(u3, v3), p2dt((u1+u2+u3)/3.0,(v1+v2+v3)/3.0), p2dc;
448 gp_Vec2d v2d12(p2d1, p2d2), v2d23(p2d2, p2d3), v2d31(p2d3, p2d1);
449 gp_Lin2d L1(p2d1, v2d12), L2(p2d2, v2d23), L3(p2d3, v2d31), Lv;
450 Standard_Real d1 = p2d1.Distance(p2d2) - Precision::Confusion(),
451 d2 = p2d2.Distance(p2d3) - Precision::Confusion(),
452 d3 = p2d3.Distance(p2d1) - Precision::Confusion(), dv;
454 Voxel_DS* ds = (Voxel_DS*) myVoxels;
455 for (ix = ixmin; ix <= ixmax; ix++)
457 for (iy = iymin; iy <= iymax; iy++)
459 for (iz = izmin; iz <= izmax; iz++)
461 ds->GetCenter(ix, iy, iz, xc, yc, zc);
462 pc.SetCoord(xc, yc, zc);
463 if (plane.Distance(pc) < hdiagonal)
465 ElSLib::Parameters(plane, pc, uc, vc);
466 p2dc.SetCoord(uc, vc);
468 gp_Vec2d v2dct(p2dc, p2dt);
469 dv = v2dct.Magnitude() - Precision::Confusion();
470 Lv.SetLocation(p2dc);
471 Lv.SetDirection(v2dct);
474 if (mayIntersect(p2d1, p2d2, p2dc, p2dt))
476 intersector2d.Perform(Lv, L1);
477 if (intersector2d.IsDone() && !intersector2d.ParallelElements() && intersector2d.NbPoints())
479 const IntAna2d_IntPoint& i2d = intersector2d.Point(1);
480 Standard_Real param1 = i2d.ParamOnFirst();
481 Standard_Real param2 = i2d.ParamOnSecond();
482 if (param1 > Precision::Confusion() && param1 < dv &&
483 param2 > Precision::Confusion() && param2 < d1)
491 if (mayIntersect(p2d2, p2d3, p2dc, p2dt))
493 intersector2d.Perform(Lv, L2);
494 if (intersector2d.IsDone() && !intersector2d.ParallelElements() && intersector2d.NbPoints())
496 const IntAna2d_IntPoint& i2d = intersector2d.Point(1);
497 Standard_Real param1 = i2d.ParamOnFirst();
498 Standard_Real param2 = i2d.ParamOnSecond();
499 if (param1 > Precision::Confusion() && param1 < dv &&
500 param2 > Precision::Confusion() && param2 < d2)
508 if (mayIntersect(p2d3, p2d1, p2dc, p2dt))
510 intersector2d.Perform(Lv, L3);
511 if (intersector2d.IsDone() && !intersector2d.ParallelElements() && intersector2d.NbPoints())
513 const IntAna2d_IntPoint& i2d = intersector2d.Point(1);
514 Standard_Real param1 = i2d.ParamOnFirst();
515 Standard_Real param2 = i2d.ParamOnSecond();
516 if (param1 > Precision::Confusion() && param1 < dv &&
517 param2 > Precision::Confusion() && param2 < d3)
524 // Set positive value to this voxel:
528 ((Voxel_ColorDS*) myVoxels)->Set(ix, iy, iz, 15);
531 ((Voxel_BoolDS*) myVoxels)->Set(ix, iy, iz, Standard_True);
535 //((Voxel_ROctBoolDS*) myVoxels)->Set(ix, iy, iz, Standard_True);
537 // Check intersection between the triangle & sub-voxels of the voxel.
538 Standard_Real hdiagonal2 = hdiagonal / 2.0, hdiagonal4 = hdiagonal / 4.0;
539 for (Standard_Integer i = 0; i < 8; i++)
541 ((Voxel_ROctBoolDS*) myVoxels)->GetCenter(ix, iy, iz, i, xc, yc, zc);
542 pc.SetCoord(xc, yc, zc);
543 if (plane.Distance(pc) < hdiagonal2)
545 ElSLib::Parameters(plane, pc, uc, vc);
546 p2dc.SetCoord(uc, vc);
548 gp_Vec2d v2dct(p2dc, p2dt);
549 dv = v2dct.Magnitude() - Precision::Confusion();
550 Lv.SetLocation(p2dc);
551 Lv.SetDirection(v2dct);
554 if (mayIntersect(p2d1, p2d2, p2dc, p2dt))
556 intersector2d.Perform(Lv, L1);
557 if (intersector2d.IsDone() && !intersector2d.ParallelElements() && intersector2d.NbPoints())
559 const IntAna2d_IntPoint& i2d = intersector2d.Point(1);
560 Standard_Real param1 = i2d.ParamOnFirst();
561 Standard_Real param2 = i2d.ParamOnSecond();
562 if (param1 > Precision::Confusion() && param1 < dv &&
563 param2 > Precision::Confusion() && param2 < d1)
571 if (mayIntersect(p2d2, p2d3, p2dc, p2dt))
573 intersector2d.Perform(Lv, L2);
574 if (intersector2d.IsDone() && !intersector2d.ParallelElements() && intersector2d.NbPoints())
576 const IntAna2d_IntPoint& i2d = intersector2d.Point(1);
577 Standard_Real param1 = i2d.ParamOnFirst();
578 Standard_Real param2 = i2d.ParamOnSecond();
579 if (param1 > Precision::Confusion() && param1 < dv &&
580 param2 > Precision::Confusion() && param2 < d2)
588 if (mayIntersect(p2d3, p2d1, p2dc, p2dt))
590 intersector2d.Perform(Lv, L3);
591 if (intersector2d.IsDone() && !intersector2d.ParallelElements() && intersector2d.NbPoints())
593 const IntAna2d_IntPoint& i2d = intersector2d.Point(1);
594 Standard_Real param1 = i2d.ParamOnFirst();
595 Standard_Real param2 = i2d.ParamOnSecond();
596 if (param1 > Precision::Confusion() && param1 < dv &&
597 param2 > Precision::Confusion() && param2 < d3)
604 //((Voxel_ROctBoolDS*) myVoxels)->Set(ix, iy, iz, i, Standard_True);
606 // Check intersection between the triangle & sub-voxels of the sub-voxel.
607 for (Standard_Integer j = 0; j < 8; j++)
609 ((Voxel_ROctBoolDS*) myVoxels)->GetCenter(ix, iy, iz, i, j, xc, yc, zc);
610 pc.SetCoord(xc, yc, zc);
611 if (plane.Distance(pc) < hdiagonal4)
613 ElSLib::Parameters(plane, pc, uc, vc);
614 p2dc.SetCoord(uc, vc);
616 gp_Vec2d v2dct(p2dc, p2dt);
617 dv = v2dct.Magnitude() - Precision::Confusion();
618 Lv.SetLocation(p2dc);
619 Lv.SetDirection(v2dct);
622 if (mayIntersect(p2d1, p2d2, p2dc, p2dt))
624 intersector2d.Perform(Lv, L1);
625 if (intersector2d.IsDone() && !intersector2d.ParallelElements() && intersector2d.NbPoints())
627 const IntAna2d_IntPoint& i2d = intersector2d.Point(1);
628 Standard_Real param1 = i2d.ParamOnFirst();
629 Standard_Real param2 = i2d.ParamOnSecond();
630 if (param1 > Precision::Confusion() && param1 < dv &&
631 param2 > Precision::Confusion() && param2 < d1)
639 if (mayIntersect(p2d2, p2d3, p2dc, p2dt))
641 intersector2d.Perform(Lv, L2);
642 if (intersector2d.IsDone() && !intersector2d.ParallelElements() && intersector2d.NbPoints())
644 const IntAna2d_IntPoint& i2d = intersector2d.Point(1);
645 Standard_Real param1 = i2d.ParamOnFirst();
646 Standard_Real param2 = i2d.ParamOnSecond();
647 if (param1 > Precision::Confusion() && param1 < dv &&
648 param2 > Precision::Confusion() && param2 < d2)
656 if (mayIntersect(p2d3, p2d1, p2dc, p2dt))
658 intersector2d.Perform(Lv, L3);
659 if (intersector2d.IsDone() && !intersector2d.ParallelElements() && intersector2d.NbPoints())
661 const IntAna2d_IntPoint& i2d = intersector2d.Point(1);
662 Standard_Real param1 = i2d.ParamOnFirst();
663 Standard_Real param2 = i2d.ParamOnSecond();
664 if (param1 > Precision::Confusion() && param1 < dv &&
665 param2 > Precision::Confusion() && param2 < d3)
672 ((Voxel_ROctBoolDS*) myVoxels)->Set(ix, iy, iz, i, j, Standard_True);
674 } // End of "Check level 2".
677 } // End of "Check level 1".