Quantcast
Channel: Rhino Developer - McNeel Forum
Viewing all articles
Browse latest Browse all 8547

Clipping of Surfaces During Dynamic Draw with Gumball

$
0
0

@robert.beck12569 wrote:

Hello,

I am working on a C++ plugin that allows a user to manipulate surfaces in real time utilizing a polyhedral mesh. I am attempting to have the user manipulate a Gumball object to help them move vertices on the mesh. The issue I am having is that the surfaces that I generate with the dynamic draw method end up clipped at certain angles. My guess is this has something to do with the clipping planes, but I am not sure what that would be. The following image shows the surface with no clipping:

From a different angle, the same surface looks like this:

Here is the relevant code that performs the drawing:

VertexGumballGetXForm.hpp

class VertexGumballGetXForm : public CRhinoGetXform
{
public:
	VertexGumballGetXForm(MeshSurfaces* a_MeshSurfaces, const CRhinoGetObject& a_VertObjects, int a_NumThreads);
	~VertexGumballGetXForm() = default;

	CRhinoGet::result moveGumball();
	void updateMeshSurfaces();

	// m_GumballDC Wrapper Methods
	void Disable();
	void Enable(unsigned int a_DocSerialNumber);
	void EnableGumballDraw(bool a_Enable);
	const ON_Xform PreTransform();
	void setBaseGumball();

	void updateGumball();

	// Overrides
	BOOL CalculateTransform(CRhinoViewport& vp, const ON_3dPoint& pt, ON_Xform& xform);
	void OnMouseDown(CRhinoViewport& vp, UINT flags, const ON_3dPoint& pt, const ON_2iPoint* p);
	void OnMouseMove(CRhinoViewport& vp, UINT flags, const ON_3dPoint& pt, const ON_2iPoint* p);
	void DynamicDraw(CRhinoDisplayPipeline& dp, const ON_3dPoint& pt);

private:
	// Initial data
	const CRhinoCommandContext&			  m_Context;

	MeshSurfaces*						  m_MeshSurfaces;
	MeshType							  m_Mesh;
	ON_Mesh								  m_OnMesh; //TODO:	 This probably is not needed anymore

	std::vector<ON_3dPoint>				  m_InitialVertPositions;
	std::vector<int>					  m_ModifiedVertIndices;
	std::vector<VertexHandle>			  m_ModifiedVertHandles;
	std::vector<struct Handle>			  m_ModifiedNurbsHandles;

	// Used for dynamic draw updates
	bool								  m_Draw;
	bool								  m_Hidden;

	ON_Mesh								  m_UpdateMesh;
	ON_Mesh								  m_StaticMesh;
	std::vector<ON_3dPoint>				  m_UpdatedVertPositions;
	ON_3dVector							  m_TranslationDirection;
	std::vector<NurbsSurfaceToHandlePair> m_UpdatedNurbs;

	NurbsSurfaceToHandlePairBuilder*	  m_NurbsSurfaceToHandlePairBuilder;

	CRhinoGumballDisplayConduit*          m_GumballDC;
	CRhinoGumball*						  m_Gumball;

	void initializeVertData(const CRhinoGetObject& a_VertObjects);
	void initializeUpdateMesh();
	void initializeGumballDC(const CRhinoGetObject& a_VertObjects);
	void initializeGumball(const CRhinoGetObject& a_VertObjects);
	void updateUpdatedNurbs();
	void initializeModifiedNurbsHandles();

	void hide();
	void hideSurfacePatches();
	void hideMeshObject();
	void show();
	void showSurfacePatches();
	void showMeshObject();
};

VertexGumballGetXForm.cpp

VertexGumballGetXForm::VertexGumballGetXForm(MeshSurfaces* a_MeshSurfaces, const CRhinoGetObject& a_VertObjects, int a_NumThreads) :
	m_MeshSurfaces(a_MeshSurfaces),
	m_Mesh(MeshType(*a_MeshSurfaces->getMesh())),
	m_OnMesh(ON_Mesh(*a_MeshSurfaces->getOnMesh())),
	m_Context(a_MeshSurfaces->getContext()),
	m_NurbsSurfaceToHandlePairBuilder(new NurbsSurfaceToHandlePairBuilder(a_NumThreads)),
	m_Draw(false),
	m_Hidden(false),
	m_TranslationDirection(ON_3dVector(0, 0, 0))
{
	initializeVertData(a_VertObjects);
	initializeGumball(a_VertObjects);
	initializeGumballDC(a_VertObjects);
	updateUpdatedNurbs();	//TODO: Find better way to get Handles?
	initializeModifiedNurbsHandles();
	//SetBasePoint(m_InitialVertPositions.at(0));	  // Sets base point to first vertex (Note: at least one vertex will be selected)
	//DrawLineFromPoint(m_InitialVertPositions.at(0), true);
	this->AppendObjects(a_VertObjects);
}

/*
 *  Input: A CRhinoGetObject containing data for vertices selected by user
 *
 *	Initializes m_ModifiedVertIndices, m_ModifiedVertHandles, m_InitialVertPositions,
 *  and m_UpdatedVertPositions
 */
void VertexGumballGetXForm::initializeVertData(const CRhinoGetObject& a_VertObjects)
{
	int t_NumVerts = a_VertObjects.ObjectCount();
	for (int i = 0; i < t_NumVerts; ++i)
	{
		// Grab vertex index
		CRhinoObjRef t_VertRef = a_VertObjects.Object(i);
		int			 t_VertIndex = t_VertRef.GeometryComponentIndex().m_index;
		m_ModifiedVertIndices.push_back(t_VertIndex);

		// Grab vertex handle
		m_ModifiedVertHandles.push_back(VertexHandle(m_ModifiedVertIndices.at(i)));

		// Grab initial vertex position
		ON_3dPoint t_VertPosition = m_MeshSurfaces->getOnMesh()->m_dV[t_VertIndex];
		m_InitialVertPositions.push_back(t_VertPosition);
		m_UpdatedVertPositions.push_back(t_VertPosition);
	}
}

void VertexGumballGetXForm::initializeGumballDC(const CRhinoGetObject& a_VertObjects)
{
	m_GumballDC = new CRhinoGumballDisplayConduit();
}

void VertexGumballGetXForm::initializeGumball(const CRhinoGetObject& a_VertObjects)
{
	ON_BoundingBox t_BBox = getBoundingBox(a_VertObjects);
	m_Gumball = new CRhinoGumball();
	m_Gumball->SetFromBoundingBox(t_BBox);
			 
	// Turn off rotation
	m_Gumball->m_appearance.m_bEnableXRotate = false;
	m_Gumball->m_appearance.m_bEnableYRotate = false;
	m_Gumball->m_appearance.m_bEnableZRotate = false;
			 
	// Turn off scale
	m_Gumball->m_appearance.m_bEnableXScale = false;
	m_Gumball->m_appearance.m_bEnableYScale = false;
	m_Gumball->m_appearance.m_bEnableZScale = false;
}

/*
 *	Updates the collection of ON_NurbsSurface to new positions
 *  based on changes made in the mesh
 */
void VertexGumballGetXForm::updateUpdatedNurbs()
{
	// Calculate new points
	m_UpdatedVertPositions = m_InitialVertPositions;
	for (size_t i = 0; i < m_UpdatedVertPositions.size(); ++i)
	{
		ON_3dPoint t_NewPt = m_UpdatedVertPositions.at(i);
		t_NewPt.x = t_NewPt.x + m_TranslationDirection.x;
		t_NewPt.y = t_NewPt.y + m_TranslationDirection.y;
		t_NewPt.z = t_NewPt.z + m_TranslationDirection.z;
		m_UpdatedVertPositions.at(i) = t_NewPt;
	}

	//OnMesh
	for (size_t i = 0; i < m_ModifiedVertIndices.size(); ++i)
	{
		int t_VertIndex = m_ModifiedVertIndices.at(i);
		ON_3dPoint t_NewVert = m_UpdatedVertPositions.at(i);
		m_OnMesh.SetVertex(t_VertIndex, t_NewVert);
	}

	//Need to invalidate things so they may be recalculated
	m_OnMesh.InvalidateVertexBoundingBox();
	m_OnMesh.InvalidateVertexNormalBoundingBox();
	m_OnMesh.InvalidateCurvatureStats();
	m_OnMesh.m_FN.SetCount(0);
	m_OnMesh.m_N.SetCount(0);
	m_OnMesh.ComputeFaceNormals();
	m_OnMesh.ComputeVertexNormals();
	m_OnMesh.SetClosed(-1);

	//Mesh
	for (size_t i = 0; i < m_UpdatedVertPositions.size(); ++i)
	{
		// New vertex position
		OpenMesh::Vec3d t_NewVert((m_UpdatedVertPositions.at(i).x),
			(m_UpdatedVertPositions.at(i).y),
			(m_UpdatedVertPositions.at(i).z));


		m_Mesh.set_point(m_ModifiedVertHandles.at(i), t_NewVert);
	}

	m_UpdatedNurbs = m_NurbsSurfaceToHandlePairBuilder->buildNurbsSurfaceToHandlePairs(m_Mesh, m_ModifiedVertHandles);
}

void VertexGumballGetXForm::initializeModifiedNurbsHandles()
{
	std::set<struct Handle> t_Handles;
	for (NurbsSurfaceToHandlePair t_Pair : m_UpdatedNurbs)
	{
		t_Handles.emplace(t_Pair.m_Handle);
	}

	m_ModifiedNurbsHandles = std::vector<struct Handle>(t_Handles.begin(), t_Handles.end());
}

CRhinoGet::result VertexGumballGetXForm::moveGumball()
{
	if (m_GumballDC == 0)
		return CRhinoGet::cancel;

	if (!m_GumballDC->PreTransform().IsIdentity())
	{
		m_bHaveXform = TRUE;
		m_xform = m_GumballDC->PreTransform();
	}

	SetBasePoint(m_GumballDC->BaseGumball().m_frame.m_plane.Origin(), false);

	const_cast<CRhinoXformObjectList&>(ObjectList()).EnableDisplayFeedback(true);
	if (!m_xform.IsIdentity())
		const_cast<CRhinoXformObjectList&>(ObjectList()).UpdateDisplayFeedbackXform(m_xform);

	SetGetPointCursor(RhinoApp().m_default_cursor);
	CRhinoGet::result t_Result = GetPoint(0, true);

	const_cast<CRhinoXformObjectList&>(ObjectList()).EnableDisplayFeedback(false);

	return t_Result;
}

/*
 *  Called after the user confirms the new locations of the selected vertices.
 */
void VertexGumballGetXForm::updateMeshSurfaces()
{
	if (m_Hidden)
	{
		show();
	}
	m_MeshSurfaces->update(m_UpdatedNurbs, m_Mesh, m_ModifiedVertHandles, m_OnMesh);
}

void VertexGumballGetXForm::show()
{
	showSurfacePatches();
	showMeshObject();
	m_Hidden = false;
}

void VertexGumballGetXForm::showSurfacePatches()
{
	m_MeshSurfaces->showSurfacePatches(m_ModifiedNurbsHandles);
}

void VertexGumballGetXForm::showMeshObject()
{
	m_MeshSurfaces->showMeshObject();
}

void VertexGumballGetXForm::Disable()
{
	m_GumballDC->Disable();
}

void VertexGumballGetXForm::Enable(unsigned int a_DocSerialNumber)
{
	m_GumballDC->Enable(a_DocSerialNumber);
}

void VertexGumballGetXForm::EnableGumballDraw(bool a_Enable)
{
	m_GumballDC->EnableGumballDraw(a_Enable);
}

const ON_Xform VertexGumballGetXForm::PreTransform()
{
	return m_GumballDC->PreTransform();
}

void VertexGumballGetXForm::setBaseGumball()
{
	m_GumballDC->SetBaseGumball(*m_Gumball);
}

void VertexGumballGetXForm::updateGumball()
{
	if (!m_GumballDC->m_drag_settings.m_bRelocateGumball)
	{
		ON_Xform xform = m_GumballDC->TotalTransform();
		m_GumballDC->SetPreTransform(xform);
	}

	// update location of base gumball
	CRhinoGumballFrame t_GumballDCFrame = m_GumballDC->Gumball().m_frame;
	CRhinoGumballFrame t_GumballFrame = m_Gumball->m_frame;
	t_GumballFrame.m_plane = t_GumballDCFrame.m_plane;
	t_GumballFrame.m_scale_grip_distance = t_GumballDCFrame.m_scale_grip_distance;
	m_Gumball->m_frame = t_GumballFrame;
}

/*
 *  Input:  CRhinoViewport: Rhino Viewport
 *			ON_3dPoint: The 3d location of the mouse pointer
 *			ON_Xform: The resulting Xform is stored here
 *
 *	Output: BOOL: TRUE for Xform != IdentityTransform
 */
BOOL VertexGumballGetXForm::CalculateTransform(CRhinoViewport& vp, const ON_3dPoint& pt, ON_Xform& xform)
{
	if (m_GumballDC == 0)
		return FALSE;

	if (m_GumballDC->m_drag_settings.m_bRelocateGumball)
		xform = m_GumballDC->PreTransform();
	else
		xform = m_GumballDC->TotalTransform();

	m_TranslationDirection = ON_3dVector(xform.m_xform[0][3], xform.m_xform[1][3], xform.m_xform[2][3]);

	return xform.IsValid() ? TRUE : FALSE;

	//m_TranslationDirection = pt - m_basepoint;
	//if (m_TranslationDirection.IsTiny())
	//	xform = ON_Xform::IdentityTransformation;
	//else
	//	xform = ON_Xform::TranslationTransformation(m_TranslationDirection);
	//return (xform.IsValid()) ? TRUE : FALSE;
}

void VertexGumballGetXForm::OnMouseDown(CRhinoViewport& vp, UINT flags, const ON_3dPoint& pt, const ON_2iPoint* p)
{
	if (p == 0 || m_GumballDC == 0 || m_GumballDC->m_pick_result.m_gumball_mode != gb_mode_nothing)
		return;

	m_GumballDC->m_pick_result.SetToDefaultPickResult();

	CRhinoPickContext t_PickContext;
	t_PickContext.m_view = vp.ParentView();
	t_PickContext.m_pick_style = CRhinoPickContext::point_pick;
	if (vp.SetClippingRegionTransformation(p->x, p->y, t_PickContext.m_pick_region))
	{
		vp.VP().GetFrustumLine(p->x, p->y, t_PickContext.m_pick_line);
		t_PickContext.UpdateClippingPlanes();
		m_GumballDC->PickGumball(t_PickContext, this);
	}
}

/*
 *	Create Nurbs Surfaces each time the mouse pointer is moved
 */
void VertexGumballGetXForm::OnMouseMove(CRhinoViewport& vp, UINT flags, const ON_3dPoint& pt, const ON_2iPoint* p)
{
	if (p == 0 || m_GumballDC == 0 || m_GumballDC->m_pick_result.m_gumball_mode == gb_mode_nothing)
		return;

	m_GumballDC->CheckShiftAndControlKeys();

	ON_Line t_WorldLine;
	if (!vp.VP().GetFrustumLine(p->x, p->y, t_WorldLine))
		t_WorldLine = ON_Line(ON_UNSET_POINT, ON_UNSET_POINT);

	bool t_Success = m_GumballDC->UpdateGumball(pt, t_WorldLine);
	if (t_Success)
	{
		ON_Xform t_Xform;
		m_Draw = false;

		if (CalculateTransform(vp, pt, t_Xform))
		{
			updateUpdatedNurbs();
			m_Draw = true;
		}
		CRhinoGetXform::OnMouseMove(vp, flags, pt, p);
	}
}

/*
 *	Draw the Mesh and Nurbs Surfaces (with Zebras) to the viewport
 */
void VertexGumballGetXForm::DynamicDraw(CRhinoDisplayPipeline& dp, const ON_3dPoint& pt)
{
	if (m_Draw)
	{
		if (!m_Hidden)
		{
			hide();
		}

		//TODO: Draw only modified portion of Mesh
		// Draw Mesh
		dp.DrawMesh(m_OnMesh, true, false, nullptr);

		// Draw Surfaces
		const CRhinoZebraAnalysisSettings& t_ZebraSettings = RhinoApp().AppSettings().ZebraAnalysisSettings();
		const ON_MeshParameters& t_MeshParameters = m_Context.Document()->Properties().AnalysisMeshSettings();
		const ON_Color& t_Color = RhinoApp().AppSettings().SelectedObjectColor();

		for (NurbsSurfaceToHandlePair t_Current : m_UpdatedNurbs)
		{
			ON_Brep* t_Brep = t_Current.m_NurbsSurface.BrepForm();
			dp.DrawZebraPreview(t_Brep, t_ZebraSettings, t_MeshParameters, t_Color, nullptr);
			delete t_Brep;
		}

	//	const CDisplayPipelineAttributes* attrs = dp.DisplayAttrs();
	//	CDisplayPipelineMaterial dpm = *attrs->m_pMaterial;
	//	dp.SetupDisplayMaterial(dpm, m_Context.m_doc);
	//	dp.SetupDisplayMaterial(dpm, &m_doc, nullptr);

	//	//int wireframe_density = 5;
	//	for (size_t i = 0; i < patches.size(); i++)
	//	{
	//		ON_Brep* b = patches.at(i).BrepForm();
	//		dp.DrawShadedBrep(b, &dpm, nullptr);
	//		delete b;
	//	}
	}

	CRhinoGetXform::DynamicDraw(dp, pt);
}

/*
 *  Hides the Document Surfaces and Mesh before the user moves the vertices.
 */
void VertexGumballGetXForm::hide()
{
	//TODO: hide unaffected patches (except for first ring around)?
	hideSurfacePatches();
	hideMeshObject();
	m_Hidden = true;
}

void VertexGumballGetXForm::hideSurfacePatches()
{
	m_MeshSurfaces->hideSurfacePatches(m_ModifiedNurbsHandles);
}

void VertexGumballGetXForm::hideMeshObject()
{
	m_MeshSurfaces->hideMeshObject(); 
}

In the above code, I made use of the example code offered by Rhino on using CRhinoGetXform for dynamic draw as well as the ones for Gumball display.

I appreciate any and all help in trying to solve this issue.

Posts: 4

Participants: 2

Read full topic


Viewing all articles
Browse latest Browse all 8547

Trending Articles