Thread safety

Istvan Csanady's picture

I am running OCCT in a multithreaded environment. When I am running boolean operations on multiple threads (and by this I don't mean the runParallel option of BRepAlgoAPI_Algo), I experience crashes, despite there are no shared data between those threads (I make copies of the shapes, for every thread). I assume, that without any shared data, any algorithm should be able to run parallel. Can this issue caused by some non-thread-safe static variables, or singleton implementations in OCCT?

msv's picture

Some questions to precise environment

Which platform do you use? Which memory manager do you use (controlled by variable MMGT_OPT)?
It would be worth to catch the error condition in debugger to trace the stack.

Istvan Csanady's picture

I use the system provided

I use the system provided allocator. Unfortunately this issue causing sporadic crashes. I am debugging, and I will update you when I know more.

Istvan Csanady's picture

Callstack

Here is a sample callstack, it usually crashes here:
#0 0x000000010029072c in GeomInt_ParLeastSquareOfMyGradientOfTheComputeLineBezierOfWLApprox::MakeTAA(math_Vector&, math_Vector&) ()
#1 0x000000010028dec0 in GeomInt_ParLeastSquareOfMyGradientOfTheComputeLineBezierOfWLApprox::Perform(math_Vector const&) at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/AppParCurves_LeastSquare.gxx:558
#2 0x000000010027edc8 in GeomInt_ParFunctionOfMyGradientOfTheComputeLineBezierOfWLApprox::Perform(math_Vector const&) at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/AppParCurves_Function.gxx:268
#3 0x0000000100284118 in GeomInt_ParFunctionOfMyGradientOfTheComputeLineBezierOfWLApprox::Values(math_Vector const&, double&, math_Vector&) at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/AppParCurves_Function.gxx:589
#4 0x00000001004567c4 in math_BFGS::Perform(math_MultipleVarFunctionWithGradient&, math_Vector const&) at /Users/icsanady/occt_git/occt/src/math/math_BFGS.cxx:187
#5 0x000000010027842c in GeomInt_Gradient_BFGSOfMyGradientOfTheComputeLineBezierOfWLApprox::GeomInt_Gradient_BFGSOfMyGradientOfTheComputeLineBezierOfWLApprox(math_MultipleVarFunctionWithGradient&, math_Vector const&, double, double, double, int) [inlined] at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/AppParCurves_Gradient_BFGS.gxx:31
#6 0x00000001002783f4 in GeomInt_Gradient_BFGSOfMyGradientOfTheComputeLineBezierOfWLApprox::GeomInt_Gradient_BFGSOfMyGradientOfTheComputeLineBezierOfWLApprox(math_MultipleVarFunctionWithGradient&, math_Vector const&, double, double, double, int) at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/AppParCurves_Gradient_BFGS.gxx:32
#7 0x000000010027b03c in GeomInt_MyGradientOfTheComputeLineBezierOfWLApprox::GeomInt_MyGradientOfTheComputeLineBezierOfWLApprox(GeomInt_TheMultiLineOfWLApprox const&, int, int, Handle_AppParCurves_HArray1OfConstraintCouple const&, math_Vector&, int, double, double, int) at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/AppParCurves_Gradient.gxx:186
#8 0x00000001002ae664 in GeomInt_TheComputeLineBezierOfWLApprox::Compute(GeomInt_TheMultiLineOfWLApprox const&, int, int, math_Vector&, double&, double&) at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/Approx_ComputeLine.gxx:920
#9 0x00000001002adac8 in GeomInt_TheComputeLineBezierOfWLApprox::Perform(GeomInt_TheMultiLineOfWLApprox const&) at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/Approx_ComputeLine.gxx:779
#10 0x00000001002c2b64 in GeomInt_WLApprox::Perform(IntSurf_Quadric const&, Handle_Adaptor3d_HSurface const&, Handle_IntPatch_WLine const&, unsigned int, unsigned int, unsigned int, int, int) at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/ApproxInt_Approx.gxx:1058
#11 0x00000001002c1b8c in GeomInt_WLApprox::Perform(Handle_Adaptor3d_HSurface const&, Handle_Adaptor3d_HSurface const&, Handle_IntPatch_WLine const&, unsigned int, unsigned int, unsigned int, int, int) at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/ApproxInt_Approx.gxx:637
#12 0x000000010018121c in IntTools_FaceFace::MakeCurve(int, Handle_Adaptor3d_TopolTool const&, Handle_Adaptor3d_TopolTool const&) at /Users/icsanady/occt_git/occt/src/IntTools/IntTools_FaceFace.cxx:1977
#13 0x000000010017e8a8 in IntTools_FaceFace::Perform(TopoDS_Face const&, TopoDS_Face const&) at /Users/icsanady/occt_git/occt/src/IntTools/IntTools_FaceFace.cxx:776
#14 0x0000000100124ca0 in BOPCol_TBBFunctor >::operator()(serial_range const&) const [inlined] at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/BOPCol_TBB.hxx:150
#15 0x0000000100124c58 in BOPCol_TBBCnt >, BOPCol_NCVector >::Perform(unsigned int, BOPCol_NCVector&) at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/BOPCol_TBB.hxx:190
#16 0x000000010011bc1c in BOPAlgo_PaveFiller::PerformFF() at /Users/icsanady/occt_git/occt/src/BOPAlgo/BOPAlgo_PaveFiller_6.cxx:273
#17 0x000000010010eb28 in BOPAlgo_PaveFiller::PerformInternal() at /Users/icsanady/occt_git/occt/src/BOPAlgo/BOPAlgo_PaveFiller.cxx:305
#18 0x000000010010e750 in BOPAlgo_PaveFiller::Perform() at /Users/icsanady/occt_git/occt/src/BOPAlgo/BOPAlgo_PaveFiller.cxx:205

msv's picture

Need to use dynamic data race analyzer

Istvan, I had a look at top function in the stack and did not found visible static variables. It is needed to use a tool for dynamic recognition of data races, such as Intel Parallel Inspector or Valgrind. I recommend you to switch development to Linux or Windows and find an error there. If there is an error in OCCT code it can be revealed by such a tool even if it is not reproduced in release mode on this platform.

msv's picture

One idea to check

Istvan, I have found one not good peace of code. Could you check it?
Please, open the file AppParCurves_BSpGradient.gxx and find there the static variable "islambdadefined". Try to make it the field member (non-static) in the class AppParCurves_BSpGradient. I think it could help, as in the current version it is possible that the fields mylambda1 and mylambda2 in the class AppParCurves_BSpFunction can be used uninitialized.

Istvan Csanady's picture

I have tried, no success. The

I have tried, no success. The problem still exists. Anyways, this is a potential problem, so still should be fixed.

msv's picture

The bug 0025711 has been

The bug 0025711 has been created to fix the potential problem.

Istvan Csanady's picture

Additional info: the problem

Additional info: the problem only occurs, when I am intersecting cylindrical surfaces. With BSpline surfaces it works well. It always crashes at AppParCurves_Function::Perform 1st line, before even running math_Vector::operator=

Here is a dissassembly (x86 64bit, iOS simulator):

GeomInt_ParFunctionOfMyGradientOfTheComputeLineBezierOfWLApprox::Perform(math_Vector const&) at AppParCurves_Function.gxx:262:
0x102027550: pushq %rbp
0x102027551: movq %rsp, %rbp
0x102027554: subq $0x663e0, %rsp
0x10202755b: movq %rdi, -0x8(%rbp)
0x10202755f: movq %rsi, -0x10(%rbp)
0x102027563: movq -0x8(%rbp), %rsi
0x102027567: movq %rsi, %rdi
0x10202756a: addq $0xc0, %rdi
0x102027571: movq -0x10(%rbp), %rax
0x102027575: movq %rsi, -0x65ba0(%rbp) //IT CRASHES HERE
0x10202757c: movq %rax, %rsi
0x10202757f: callq 0x1028bb5d0 ; symbol stub for: math_Vector::operator=(math_Vector const&)
0x102027584: movq -0x65ba0(%rbp), %rsi
0x10202758b: addq $0x8828, %rsi
0x102027592: movq -0x65ba0(%rbp), %rdi
0x102027599: addq $0xc0, %rdi
0x1020275a0: movq %rdi, -0x65ba8(%rbp)
0x1020275a7: movq %rsi, %rdi
0x1020275aa: movq -0x65ba8(%rbp), %rsi
0x1020275b1: movq %rax, -0x65bb0(%rbp)
0x1020275b8: callq 0x102034ce0 ; GeomInt_ParLeastSquareOfMyGradientOfTheComputeLineBezierOfWLApprox::Perform(math_Vector const&) at AppParCurves_LeastSquare.gxx:427
0x1020275bd: movq -0x65ba0(%rbp), %rax
0x1020275c4: addq $0x8828, %rax

And a callstack:

#0 0x0000000102027575 in GeomInt_ParFunctionOfMyGradientOfTheComputeLineBezierOfWLApprox::Perform(math_Vector const&) at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/AppParCurves_Function.gxx:265
#1 0x000000010202c14c in GeomInt_ParFunctionOfMyGradientOfTheComputeLineBezierOfWLApprox::Values(math_Vector const&, double&, math_Vector&) at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/AppParCurves_Function.gxx:589
#2 0x0000000102444f36 in math_BFGS::Perform(math_MultipleVarFunctionWithGradient&, math_Vector const&) at /Users/icsanady/occt_git/occt/src/math/math_BFGS.cxx:187
#3 0x0000000102020950 in GeomInt_Gradient_BFGSOfMyGradientOfTheComputeLineBezierOfWLApprox::GeomInt_Gradient_BFGSOfMyGradientOfTheComputeLineBezierOfWLApprox(math_MultipleVarFunctionWithGradient&, math_Vector const&, double, double, double, int) at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/AppParCurves_Gradient_BFGS.gxx:31
#4 0x00000001020209c9 in GeomInt_Gradient_BFGSOfMyGradientOfTheComputeLineBezierOfWLApprox::GeomInt_Gradient_BFGSOfMyGradientOfTheComputeLineBezierOfWLApprox(math_MultipleVarFunctionWithGradient&, math_Vector const&, double, double, double, int) at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/AppParCurves_Gradient_BFGS.gxx:32
#5 0x0000000102023bbe in GeomInt_MyGradientOfTheComputeLineBezierOfWLApprox::GeomInt_MyGradientOfTheComputeLineBezierOfWLApprox(GeomInt_TheMultiLineOfWLApprox const&, int, int, Handle_AppParCurves_HArray1OfConstraintCouple const&, math_Vector&, int, double, double, int) at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/AppParCurves_Gradient.gxx:186
#6 0x000000010202405a in GeomInt_MyGradientOfTheComputeLineBezierOfWLApprox::GeomInt_MyGradientOfTheComputeLineBezierOfWLApprox(GeomInt_TheMultiLineOfWLApprox const&, int, int, Handle_AppParCurves_HArray1OfConstraintCouple const&, math_Vector&, int, double, double, int) at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/AppParCurves_Gradient.gxx:209
#7 0x000000010205da19 in GeomInt_TheComputeLineBezierOfWLApprox::Compute(GeomInt_TheMultiLineOfWLApprox const&, int, int, math_Vector&, double&, double&) at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/Approx_ComputeLine.gxx:920
#8 0x000000010205c954 in GeomInt_TheComputeLineBezierOfWLApprox::Perform(GeomInt_TheMultiLineOfWLApprox const&) at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/Approx_ComputeLine.gxx:779
#9 0x000000010207c219 in GeomInt_WLApprox::Perform(IntSurf_Quadric const&, Handle_Adaptor3d_HSurface const&, Handle_IntPatch_WLine const&, unsigned int, unsigned int, unsigned int, int, int) at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/ApproxInt_Approx.gxx:1058
#10 0x000000010207a83f in GeomInt_WLApprox::Perform(Handle_Adaptor3d_HSurface const&, Handle_Adaptor3d_HSurface const&, Handle_IntPatch_WLine const&, unsigned int, unsigned int, unsigned int, int, int) at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/ApproxInt_Approx.gxx:637
#11 0x00000001026a3895 in IntTools_FaceFace::MakeCurve(int, Handle_Adaptor3d_TopolTool const&, Handle_Adaptor3d_TopolTool const&) at /Users/icsanady/occt_git/occt/src/IntTools/IntTools_FaceFace.cxx:1977
#12 0x000000010269b216 in IntTools_FaceFace::Perform(TopoDS_Face const&, TopoDS_Face const&) at /Users/icsanady/occt_git/occt/src/IntTools/IntTools_FaceFace.cxx:776
#13 0x0000000102608bf2 in BOPAlgo_FaceFace::Perform() at /Users/icsanady/occt_git/occt/src/BOPAlgo/BOPAlgo_PaveFiller_6.cxx:156
#14 0x0000000102607970 in BOPCol_TBBFunctor >::operator()(serial_range const&) const at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/BOPCol_TBB.hxx:150
#15 0x00000001026007a8 in BOPCol_TBBCnt >, BOPCol_NCVector >::Perform(unsigned int, BOPCol_NCVector&) at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/BOPCol_TBB.hxx:190
#16 0x00000001025f5598 in BOPAlgo_PaveFiller::PerformFF() at /Users/icsanady/occt_git/occt/src/BOPAlgo/BOPAlgo_PaveFiller_6.cxx:273
#17 0x00000001025dee93 in BOPAlgo_PaveFiller::PerformInternal() at /Users/icsanady/occt_git/occt/src/BOPAlgo/BOPAlgo_PaveFiller.cxx:305
#18 0x00000001025dea3d in BOPAlgo_PaveFiller::Perform() at /Users/icsanady/occt_git/occt/src/BOPAlgo/BOPAlgo_PaveFiller.cxx:205

msv's picture

It seems we have the fact of

It seems we have the fact of calling of virtual function of a not-fully-constructed instance of variable.
The ctor of the class math_BFGS calls the non-virtual method Perform. The perform, on its turn, calls virtual method IsSolutionReached.
But in our case, the object of derived class AppParCurves_Gradient_BFGS is constructed. See AppParCurves_Gradient_BFGS.gxx:21.
Here we have two mistakes:
1) The method Perform will be called twice;
2) The first time Perform is called when initialization of the class has not yet been completed, and it leads to the call of virtual method (which? base or redefined one? is it defined by C++ standard?).

Dear Istvan, you can try to provide solution for this trouble, or, please simply register a bug track item.

Istvan Csanady's picture

You are right, this seems to

You are right, this seems to be a serious issue, virtual methods should never be called from constructors. I will try to provide a fix.

barbier's picture

Base virtual method is

Base virtual method is called, see
http://www.stroustrup.com/bs_faq2.html#vcall
A simple solution here is to drop the constructor with StartingPoint, it is called only once AFAICT.

Istvan Csanady's picture

Yes, this is what I am doing

Yes, this is what I am doing right now. I will provide the fix soon.

barbier's picture

scan-build

scan-build is able to detect such problems, it reports similar problems in math_Powell.cxx math_NewtonMinimum.cxx math_NewtonFunctionSetRoot.cxx math_BissecNewton.cxx math_FRPR.cxx math_FunctionSetRoot.cxx math_FunctionSetRoot.cxx math_BrentMinimum.cxx

It also complains about Delete being called by virtual destructors.

msv's picture

The bug #25720 has been

Thank you. The bug #25720 has been created for this problem.

Istvan Csanady's picture

I am experiencing crashes

I am experiencing crashes again. Is this the same problem, that barbier revealed?

#0 0x00000001004ebdf0 in math_Matrix::math_Matrix(int, int, int, int) [inlined] at /Users/icsanady/occt_git/occt/src/math/math_Matrix.cxx:53
#1 0x00000001004ebdf0 in math_Matrix::math_Matrix(int, int, int, int) at /Users/icsanady/occt_git/occt/src/math/math_Matrix.cxx:57
#2 0x00000001004f25bc in math_SVD::math_SVD(math_Matrix const&) at /Users/icsanady/occt_git/occt/src/math/math_SVD.cxx:34
#3 0x00000001004e7838 in SearchDirection(math_Matrix const&, math_Vector const&, math_Vector const&, unsigned int, math_Vector const&, math_Vector&, double&) at /Users/icsanady/occt_git/occt/src/math/math_FunctionSetRoot.cxx:368
#4 0x00000001004e5450 in math_FunctionSetRoot::Perform(math_FunctionSetWithDerivatives&, math_Vector const&, math_Vector const&, math_Vector const&, unsigned int) at /Users/icsanady/occt_git/occt/src/math/math_FunctionSetRoot.cxx:788
#5 0x0000000100335e6c in GeomInt_TheImpPrmSvSurfacesOfWLApprox::Compute(double&, double&, double&, double&, gp_Pnt&, gp_Vec&, gp_Vec2d&, gp_Vec2d&) at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/ApproxInt_ImpPrmSvSurfaces.gxx:320
#6 0x0000000100335108 in GeomInt_TheImpPrmSvSurfacesOfWLApprox::TangencyOnSurf1(double, double, double, double, gp_Vec2d&) at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/ApproxInt_ImpPrmSvSurfaces.gxx:93
#7 0x0000000100338650 in GeomInt_TheMultiLineOfWLApprox::Tangency(int, TColgp_Array1OfVec&, TColgp_Array1OfVec2d&) const at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/ApproxInt_MultiLine.gxx:307
#8 0x00000001002eac80 in GeomInt_BSpParLeastSquareOfMyBSplGradientOfTheComputeLineOfWLApprox::Affect(GeomInt_TheMultiLineOfWLApprox const&, int, AppParCurves_Constraint&, math_Vector&, math_Vector&) at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/AppParCurves_LeastSquare.gxx:943
#9 0x00000001002e6004 in GeomInt_BSpParLeastSquareOfMyBSplGradientOfTheComputeLineOfWLApprox::Init(GeomInt_TheMultiLineOfWLApprox const&, int, int) at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/AppParCurves_LeastSquare.gxx:267
#10 0x00000001002e96b0 in GeomInt_BSpParLeastSquareOfMyBSplGradientOfTheComputeLineOfWLApprox::GeomInt_BSpParLeastSquareOfMyBSplGradientOfTheComputeLineOfWLApprox(GeomInt_TheMultiLineOfWLApprox const&, int, int, AppParCurves_Constraint, AppParCurves_Constraint, int) at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/AppParCurves_LeastSquare.gxx:125
#11 0x0000000100330550 in GeomInt_TheComputeLineOfWLApprox::Interpol(GeomInt_TheMultiLineOfWLApprox const&) at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/Approx_BSplComputeLine.gxx:1322
#12 0x000000010032fa58 in GeomInt_TheComputeLineOfWLApprox::Compute(GeomInt_TheMultiLineOfWLApprox const&, int, int, math_Vector&, TColStd_Array1OfReal const&, TColStd_Array1OfInteger&) at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/Approx_BSplComputeLine.gxx:914
#13 0x000000010032e5e0 in GeomInt_TheComputeLineOfWLApprox::Perform(GeomInt_TheMultiLineOfWLApprox const&) at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/Approx_BSplComputeLine.gxx:676
#14 0x000000010033c830 in GeomInt_WLApprox::Perform(Handle_Adaptor3d_HSurface const&, IntSurf_Quadric const&, Handle_IntPatch_WLine const&, unsigned int, unsigned int, unsigned int, int, int) at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/ApproxInt_Approx.gxx:850
#15 0x000000010033c188 in GeomInt_WLApprox::Perform(Handle_Adaptor3d_HSurface const&, Handle_Adaptor3d_HSurface const&, Handle_IntPatch_WLine const&, unsigned int, unsigned int, unsigned int, int, int) at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/ApproxInt_Approx.gxx:634
#16 0x00000001001f8d98 in IntTools_FaceFace::MakeCurve(int, Handle_Adaptor3d_TopolTool const&, Handle_Adaptor3d_TopolTool const&) at /Users/icsanady/occt_git/occt/src/IntTools/IntTools_FaceFace.cxx:1977
#17 0x00000001001f6810 in IntTools_FaceFace::Perform(TopoDS_Face const&, TopoDS_Face const&) at /Users/icsanady/occt_git/occt/src/IntTools/IntTools_FaceFace.cxx:776
#18 0x000000010019c768 in BOPCol_TBBFunctor >::operator()(serial_range const&) const [inlined] at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/BOPCol_TBB.hxx:150
#19 0x000000010019c720 in BOPCol_TBBCnt >, BOPCol_NCVector >::Perform(unsigned int, BOPCol_NCVector&) at /Users/icsanady/occt_git/occt/adm/mac/xcd/../../../inc/BOPCol_TBB.hxx:190
#20 0x00000001001938d0 in BOPAlgo_PaveFiller::PerformFF() at /Users/icsanady/occt_git/occt/src/BOPAlgo/BOPAlgo_PaveFiller_6.cxx:273
#21 0x000000010018687c in BOPAlgo_PaveFiller::PerformInternal() at /Users/icsanady/occt_git/occt/src/BOPAlgo/BOPAlgo_PaveFiller.cxx:305
#22 0x00000001001864a4 in BOPAlgo_PaveFiller::Perform() at /Users/icsanady/occt_git/occt/src/BOPAlgo/BOPAlgo_PaveFiller.cxx:205

msv's picture

No, this seems to have

No, this seems to have another cause.

Istvan Csanady's picture

I have submitted a fix.

I have submitted a fix. #25719 Thank you for your cooperation.

msv's picture

Did the fix solve your

Did the fix solve your problem?

Istvan Csanady's picture

Yes, thank you.

Yes, thank you very much, I really appreciate your help.

abv's picture

Suggest using Valgrind or other dynamic code analysis tool

Hello Istvan,

I suggest you to use some dynamic code analysis tool capable of checking your program for concurrency issues, such as Valgrind (works on Linux, but should be also available on Mac OS X) or Intel Parallel Inspector.

The parallel mode of BOP algo has been checked like this and is expected to work fine. Apart of this mode, some algorithms in OCCT may still use static data which may cause data races or other issues.

If you find the reason, please share your knowledge with us (the fix would be welcome, too!). Alternatively, you can apply to our services for us to perform this analysis.

Andrey

Istvan Csanady's picture

Unfortunately I can't use

Unfortunately I can't use valgrind on iOS, and the tools provided by Apple are not revealing any problem. Of course I will submit the fix, if it turns out that the problem is in OCCT.

www.opencascade.com

Copyright 2011-2019
OPEN CASCADE SAS
Contact us