RhinoCutupSurface thread issues


#1

Hi
I have example where the brep which is produced with RhinoCutupSurface is invalid if RhinoCutupSurface is called from second thread. If I call IsValid on the result brep from the second thread it returns true so I aspect the brep to be valid. Then after the second thread ends, I am trying to add the result brep to the rhino document from the main thread , but adding the brep to the document fails, i.e I am getting message box which says : " CRhinoDoc::AddBrepObject - brep.IsValid is false. Brep not added".

If RhinoCutupSurface is called from the main thread with the same input, then the brep is valid and it is successfully added to the rhino document.

So , does this means that RhinoCutupSurface has some issues when called from second thread, cause my understading is that this is allowable to generate geometry on second thread as long as uou do not touch the rhino document.

To test the code example use the 3dm file in the following link 3dm fileand then select the surface and the curve when prompted.
Here is the test code :

    class CCommandTestRhinoCutUpSurface : public CRhinoCommand
    {
     public:
	CCommandTestRhinoCutUpSurface() {}
	~CCommandTestRhinoCutUpSurface() {}
	UUID CommandUUID()
	{
		// {CE2524D1-4B11-44CF-971C-5135CF322F71}
		static const GUID TestRhinoCutUpSurfaceCommand_UUID =
		{ 0xCE2524D1, 0x4B11, 0x44CF, { 0x97, 0x1C, 0x51, 0x35, 0xCF, 0x32, 0x2F, 0x71 } };
		return TestRhinoCutUpSurfaceCommand_UUID;
	}
	const wchar_t* EnglishCommandName() { return L"TestRhinoCutUpSurface"; }
	const wchar_t* LocalCommandName() { return L"TestRhinoCutUpSurface"; }
	CRhinoCommand::result RunCommand( const CRhinoCommandContext& );
};

    // The one and only CCommandTestRhinoCutUpBrep object
     static class CCommandTestRhinoCutUpSurface theTestRhinoCutUpSurfaceCommand;

    struct DataForThread
    {
	const ON_Surface* srf;
	ON_SimpleArray<ON_Curve*> crvs;
	ON_Brep* resultBrep;
	
    };


    DWORD WINAPI ThreadFunc( LPVOID lpParam ) 
    {

	DataForThread * data = ((DataForThread*)lpParam); 

	ON_SimpleArray<ON_Brep*> brepArray;

	RhinoCutUpSurface(*data->srf, true, data->crvs, 0.01, 0.02, brepArray);

	if(brepArray.Count()!=0)
	{
		ON_Brep* theFirstBrep=brepArray[0];
		// here it says is valid
		bool isValid = theFirstBrep->IsValid();
		data->resultBrep = theFirstBrep->Duplicate();		
	}	

     return 0;
    } 


    DataForThread g_data;

     CRhinoCommand::result CCommandTestRhinoCutUpSurface::RunCommand( const CRhinoCommandContext& context )
    {
	//select surface
	CRhinoGetObject gs1;
	gs1.SetCommandPrompt(L"Select the surface" );
	gs1.SetGeometryFilter( CRhinoGetObject::surface_object );
	gs1.GetObjects( 1, 1 );
	if( gs1.CommandResult() != CRhinoCommand::success )
		return gs1.CommandResult();

	const ON_Surface* srf = gs1.Object(0).Surface();   

	g_data.srf = srf;

    // select curve

	CRhinoGetObject go;
	go.SetCommandPrompt( L"Select curve" );
	go.SetGeometryFilter( CRhinoGetObject::curve_object );
	go.GetObjects( 1, 1 );
	if( go.CommandResult() != success )
		return go.CommandResult();

	const CRhinoObjRef& obj_ref = go.Object(0);
	const ON_Curve* crv = obj_ref.Curve();

	ON_SimpleArray<ON_Curve*> arrayCurvs;
	arrayCurvs.Append(crv->DuplicateCurve());
	g_data.crvs = arrayCurvs;


	// NO problem when the brep is generated fro mthe main thread  
	ON_SimpleArray<ON_Brep*> brepArray;

	RhinoCutUpSurface(*srf, true, arrayCurvs, 0.01, 0.02, brepArray);

	if(brepArray.Count()==0)
		return CRhinoCommand::failure;

	ON_Brep* theFirstBrep=brepArray[0];
	bool isValid = theFirstBrep->IsValid();
	
	
	RhinoApp().ActiveDoc()->AddBrepObject(*theFirstBrep);
	RhinoApp().ActiveDoc()->Redraw();


	// Create thread , and generate brep with RhinoCutUpSurface in second thread
	HANDLE handleThread = CreateThread( NULL, 0, 
		ThreadFunc, &g_data, 0, NULL); 

	WaitForSingleObject(handleThread, INFINITE);

	// try to add the brep to document that was generated in second thread
	// here it says is invalid and AddBrepObject fails
	bool isValidThreadBrep = g_data.resultBrep->IsValid();
	RhinoApp().ActiveDoc()->AddBrepObject(*g_data.resultBrep);
	RhinoApp().ActiveDoc()->Redraw();

	return CRhinoCommand::success;
    }

(Dale Fugier) #2

Hi Elizabeta,

I just ran your code in both 32-bit and 64-bit Rhino 5 SR5, and I am not getting any kind of error.

In general, though, if you are going to perform a operation on some geometry in a thread, it is best to make a copy of the geometry and then throw it away when you are finished.


#3

Hi Dale
I am using Rhino4 SR9, can you try on Rhino4


(Dale Fugier) #4

I can - but if there is a problem, there will be nothing I can do about it…


#5

still, I just want to know if it is a issue in Rhino4, or just something I see on my computer. looking forward your answer thank you


(Dale Fugier) #6

Yes I can repeat the problem in Rhino 4 SR9.


(Steve Baer) #7

We put effort into V5 to make calculations like this more “thread-safe” though I’m not exactly sure what is going wrong in your case. If you are going to do geometry calculations in background threads, I would recommend using V5.