@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