[MSCE C++]请问各位老师:如何实现solidModify功能,

我想实现左键选中实体的某个面(假如是个长方体),然后随着鼠标的移动、实时显示这个面沿法相方向被拉伸的效果,然后点击左键呈现拉伸的效果,请问该怎么做?

SDK例子中exampleSubEntityTool功能只能实现选点、线、面,但是当我重载了databutton功能后,左键就不能选面了

Parents
  • 主要是我在修改实体的例子里面找不到鼠标的操作,无法把鼠标操作和选择的面关联起来

  • 建议您搜索下交互式工具的使用,一个工具要么是用来对整个元素操作的,就用DgnElementSetTool,如果该元素是Solid/SmartSolid,为了提高效率可改用ElementGraphicsTool。如果是操作Solid/SmartSolid中的子实体(SubEntity)则需要用LocateSubEntityTool。

    https://communities.bentley.com/communities/other_communities/bdn_other_communities/w/chinabdn-wiki/43485/microstation

  • DgnElementSetTool和DgnPrimitiveTool的例子我都看过,我现在要做的事情属于交互式修改Solid/SmartSolid中的子实体(SubEntity),肯定是要用LocateSubEntityTool,但是SDK的例子里面没有找到交互修改子实体的内容

  • 肯定是要用LocateSubEntityTool,但是SDK的例子里面没有找到交互修改子实体的内容

    请参考SDK中的例子C:\Program Files\Bentley\MicroStationCONNECTSDK\examples\Elements\exampleSolids\exampleModifyFaceTool.cpp



  • 经过三天以来不断的尝试,很遗憾还是没有成功,同时我发现:(1)重载_OnDynamicFrame、_OnDataButton、_OnResetButton函数时如果函数中包含实体修改内容,就会出现奇怪的结果(如之前的附图),(2)GetPlanarFaceData(&point, &normal1, *subEntity))获取的点坐标point并不在选取的平面上Head bandage,下面是在例子上面修改的代码~~

    struct          TestModifyFaceTool : LocateSubEntityTool
    {
    
    	enum ToolOperation
    	{
    		OP_FaceOffset = 0,
    		OP_FaceTranslate = 1,
    		OP_FaceRotate = 2,
    		OP_FaceDelete = 3,
    		OP_FaceHollow = 4,
    	};
    private:
    	DPoint3d pointDynamic;	//记录实时变化的坐标
    protected:
    
    	ToolOperation   m_operation;
    
    	/*---------------------------------------------------------------------------------**//**
    	* @bsimethod                                                              Bentley Systems
    	+---------------+---------------+---------------+---------------+---------------+------*/
    	TestModifyFaceTool(int cmdName, ToolOperation operation)
    	{
    		SetCmdName(cmdName, 0);
    		m_operation = operation;
    	}
    
    	/*---------------------------------------------------------------------------------**//**
    	* @bsimethod                                                              Bentley Systems
    	+---------------+---------------+---------------+---------------+---------------+------*/
    	virtual bool _CollectCurves() override { return false; } // Tool does not support wire bodies...wire bodies won't be collected.
    	virtual bool _CollectSurfaces() override { return false; } // Tool does not support sheet bodies...sheet bodies won't be collected.
    
    	/*---------------------------------------------------------------------------------**//**
    	* @bsimethod                                                              Bentley Systems
    	+---------------+---------------+---------------+---------------+---------------+------*/
    	virtual BentleyStatus _OnProcessSolidPrimitive(ISolidPrimitivePtr& geomPtr, DisplayPathCR path) override 
    	{ 
    		return ERROR; 
    	} // Promote capped surface to solid body...
    	virtual BentleyStatus _OnProcessPolyface(PolyfaceHeaderPtr& geomPtr, DisplayPathCR path) override 
    	{ 
    		return SUCCESS; 
    	} // Don't convert a closed mesh to a BRep (and don't collect), can be expensive for large meshes...
    
    	/*---------------------------------------------------------------------------------**//**
    	* @bsimethod                                                              Bentley Systems
    	+---------------+---------------+---------------+---------------+---------------+------*/
    	virtual ISubEntity::SubEntityType _GetSubEntityTypeMask() override { return ISubEntity::SubEntityType_Face; }
    	virtual bool _RequireSubEntitySupport() override { return true; } // Require solid w/at least 1 face...
    	virtual bool _AcceptIdentifiesSubEntity() { return OP_FaceHollow != m_operation; } // Solid accept point may also accept first face (except hollow which can apply to entire body)...
    	virtual bool _AllowMissToAccept(DgnButtonEventCR ev) { return (OP_FaceHollow == m_operation ? true : __super::_AllowMissToAccept(ev)); } // Don't require face for hollow...
    
    	/*---------------------------------------------------------------------------------**//**
    	* Return true if this element should be accepted for the modify operation.
    	* @bsimethod                                                              Bentley Systems
    	+---------------+---------------+---------------+---------------+---------------+------*/
    	virtual bool _IsElementValidForOperation(ElementHandleCR eh, HitPathCP path, WStringR cantAcceptReason) override
    	{
    		// Base class implementation returns true if geometry cache isn't empty, which in this case means the cache contains at least 1 BRep solid.
    		// To be valid for modification element should be fully represented by a single solid; reject if there are multiple solid bodies or missing geometry.
    		// NOTE: Simple count test is sufficient (w/o also checking TryGetAsBRep) as override of _Collect and _OnProcess methods have tool only collecting BRep solids.
    		return (__super::_IsElementValidForOperation(eh, path, cantAcceptReason) && 1 == GetElementGraphicsCacheCount(eh) && !IsGeometryMissing(eh));
    	}
    
    	/*---------------------------------------------------------------------------------**//**
    	* @bsimethod                                                              Bentley Systems
    	+---------------+---------------+---------------+---------------+---------------+------*/
    	double GetDistance()
    	{
    		// For testing purposes just use some % of element's range. This value would normally be supplied via tool settings.
    		ScanRangeCP elRange = &GetElementAgenda().GetFirstP()->GetElementCP()->hdr.dhdr.range;
    		DPoint3d    range[2];
    
    		range[0].x = (double)elRange->xlowlim;
    		range[0].y = (double)elRange->ylowlim;
    		range[0].z = (double)elRange->zlowlim;
    		range[1].x = (double)elRange->xhighlim;
    		range[1].y = (double)elRange->yhighlim;
    		range[1].z = (double)elRange->zhighlim;
    
    		return range[0].Distance(range[1]) * 0.1;
    	}
    
    	/*---------------------------------------------------------------------------------**//**
    	* @bsimethod                                                              Bentley Systems
    	+---------------+---------------+---------------+---------------+---------------+------*/
    	double GetAngle()
    	{
    		// For testing purposes just use 10 degrees. This value would normally be supplied via tool settings.
    		return Angle::DegreesToRadians(10.0);
    	}
    
    	/*---------------------------------------------------------------------------------**//**
    	* Perform the solid operation using the accepted faces.
    	* @bsimethod                                                              Bentley Systems
    	+---------------+---------------+---------------+---------------+---------------+------*/
    	StatusInt DoOperation(ISolidKernelEntityPtr& entityPtr, bvector<ISubEntityPtr>& faces)
    	{
    
    		double distance = 0.0;
    		for each (ISubEntityPtr subEntity in faces)
    		{
    			DPoint3d point;
    			DVec3d normal1, normal2;
    			if ((SUCCESS == SolidUtil::GetPlanarFaceData(&point, &normal1, *subEntity)))
    			{
    				normal2.x = pointDynamic.x - point.x;
    				normal2.y = pointDynamic.y - point.y;
    				normal2.z = pointDynamic.z - point.z;
    				distance = std::abs(normal1.x * normal2.x + normal1.y * normal2.y + normal1.z * normal2.z);
    				break;
    			}
    		}
    		bvector<double> offsets;
    
    		offsets.insert(offsets.begin(), faces.size(), distance);
    
    		return SolidUtil::Modify::OffsetFaces(entityPtr, &faces.front(), &offsets.front(), faces.size());
    
    	}
    
    	/*---------------------------------------------------------------------------------**//**
    	* @bsimethod                                                              Bentley Systems
    	+---------------+---------------+---------------+---------------+---------------+------*/
    	virtual StatusInt _OnElementModify(EditElementHandleR eeh) override
    	{
    		bvector<IElementGraphicsPtr>  geomCache;
    
    		// NOTE: Since we setup tool to only collect a single brep, we can just grab first cache entry...
    		ISolidKernelEntityPtr   entityPtr = (SUCCESS == GetElementGraphicsCache(eeh, geomCache) ? TryGetAsBRep(geomCache.front()) : NULL);
    
    		if (!entityPtr.IsValid())
    			return ERROR;
    
    		if (SUCCESS != DoOperation(entityPtr, GetAcceptedSubEntities()))
    			return ERROR;
    
    		return SolidUtil::Convert::BodyToElement(eeh, *entityPtr, &eeh, *eeh.GetModelRef());
    	}
    
    	/*---------------------------------------------------------------------------------**//**
    	* Install a new instance of the tool. Will be called in response to external events
    	* such as undo or by the base class from _OnReinitialize when the tool needs to be
    	* reset to it's initial state.
    	* @bsimethod                                                              Bentley Systems
    	+---------------+---------------+---------------+---------------+---------------+------*/
    	virtual void _OnRestartTool() override
    	{
    		InstallNewInstance(GetToolId(), m_operation);
    	}
    
    	virtual void _OnDynamicFrame(DgnButtonEventCR ev) override
    	{
    		pointDynamic = *ev.GetPoint();
    		if (GetElementAgenda().GetCount() > 0 && GetAcceptedSubEntities().size() > 0)
    		{
    			ElementHandleCP eeh = GetElementAgenda().GetFirstP();	//获取元素
    			bvector<IElementGraphicsPtr>  geomCache;
    			ISolidKernelEntityPtr entityPtr = (SUCCESS == GetElementGraphicsCache(*eeh, geomCache) ? TryGetAsBRep(geomCache.front()) : NULL);
    			if (!entityPtr.IsValid())
    				return;
    			bvector<ISubEntityPtr> faces = GetAcceptedSubEntities();
    			double distance = 0.0;
    			for each (ISubEntityPtr subEntity in faces)
    			{
    				DPoint3d point;
    				DVec3d normal1, normal2;
    				if ((SUCCESS == SolidUtil::GetPlanarFaceData(&point, &normal1, *subEntity)))
    				{
    					normal2.x = pointDynamic.x - point.x;
    					normal2.y = pointDynamic.y - point.y;
    					normal2.z = pointDynamic.z - point.z;
    					distance = std::abs(normal1.x*normal2.x + normal1.y*normal2.y + normal1.z*normal2.z);
    				}
    			}
    			bvector<double> offsets;
    			offsets.insert(offsets.begin(), faces.size(), distance);
    			SolidUtil::Modify::OffsetFaces(entityPtr, &faces.front(), &offsets.front(), faces.size());
    			//if (SUCCESS != SolidUtil::Modify::OffsetFaces(entityPtr, &faces.front(), &offsets.front(), faces.size()))
    		}
    	}
    public:
    
    	/*---------------------------------------------------------------------------------**//**
    	* Method to create and install a new instance of the tool. If InstallTool returns ERROR,
    	* the new tool instance will be freed/invalid. Never call delete on RefCounted classes.
    	* @bsimethod                                                              Bentley Systems
    	+---------------+---------------+---------------+---------------+---------------+------*/
    	static void InstallNewInstance(int toolId, ToolOperation operation)
    	{
    		TestModifyFaceTool* tool = new TestModifyFaceTool(toolId, operation);
    
    		tool->InstallTool();
    	}
    
    }; // TestModifyFaceTool

Reply
  • 经过三天以来不断的尝试,很遗憾还是没有成功,同时我发现:(1)重载_OnDynamicFrame、_OnDataButton、_OnResetButton函数时如果函数中包含实体修改内容,就会出现奇怪的结果(如之前的附图),(2)GetPlanarFaceData(&point, &normal1, *subEntity))获取的点坐标point并不在选取的平面上Head bandage,下面是在例子上面修改的代码~~

    struct          TestModifyFaceTool : LocateSubEntityTool
    {
    
    	enum ToolOperation
    	{
    		OP_FaceOffset = 0,
    		OP_FaceTranslate = 1,
    		OP_FaceRotate = 2,
    		OP_FaceDelete = 3,
    		OP_FaceHollow = 4,
    	};
    private:
    	DPoint3d pointDynamic;	//记录实时变化的坐标
    protected:
    
    	ToolOperation   m_operation;
    
    	/*---------------------------------------------------------------------------------**//**
    	* @bsimethod                                                              Bentley Systems
    	+---------------+---------------+---------------+---------------+---------------+------*/
    	TestModifyFaceTool(int cmdName, ToolOperation operation)
    	{
    		SetCmdName(cmdName, 0);
    		m_operation = operation;
    	}
    
    	/*---------------------------------------------------------------------------------**//**
    	* @bsimethod                                                              Bentley Systems
    	+---------------+---------------+---------------+---------------+---------------+------*/
    	virtual bool _CollectCurves() override { return false; } // Tool does not support wire bodies...wire bodies won't be collected.
    	virtual bool _CollectSurfaces() override { return false; } // Tool does not support sheet bodies...sheet bodies won't be collected.
    
    	/*---------------------------------------------------------------------------------**//**
    	* @bsimethod                                                              Bentley Systems
    	+---------------+---------------+---------------+---------------+---------------+------*/
    	virtual BentleyStatus _OnProcessSolidPrimitive(ISolidPrimitivePtr& geomPtr, DisplayPathCR path) override 
    	{ 
    		return ERROR; 
    	} // Promote capped surface to solid body...
    	virtual BentleyStatus _OnProcessPolyface(PolyfaceHeaderPtr& geomPtr, DisplayPathCR path) override 
    	{ 
    		return SUCCESS; 
    	} // Don't convert a closed mesh to a BRep (and don't collect), can be expensive for large meshes...
    
    	/*---------------------------------------------------------------------------------**//**
    	* @bsimethod                                                              Bentley Systems
    	+---------------+---------------+---------------+---------------+---------------+------*/
    	virtual ISubEntity::SubEntityType _GetSubEntityTypeMask() override { return ISubEntity::SubEntityType_Face; }
    	virtual bool _RequireSubEntitySupport() override { return true; } // Require solid w/at least 1 face...
    	virtual bool _AcceptIdentifiesSubEntity() { return OP_FaceHollow != m_operation; } // Solid accept point may also accept first face (except hollow which can apply to entire body)...
    	virtual bool _AllowMissToAccept(DgnButtonEventCR ev) { return (OP_FaceHollow == m_operation ? true : __super::_AllowMissToAccept(ev)); } // Don't require face for hollow...
    
    	/*---------------------------------------------------------------------------------**//**
    	* Return true if this element should be accepted for the modify operation.
    	* @bsimethod                                                              Bentley Systems
    	+---------------+---------------+---------------+---------------+---------------+------*/
    	virtual bool _IsElementValidForOperation(ElementHandleCR eh, HitPathCP path, WStringR cantAcceptReason) override
    	{
    		// Base class implementation returns true if geometry cache isn't empty, which in this case means the cache contains at least 1 BRep solid.
    		// To be valid for modification element should be fully represented by a single solid; reject if there are multiple solid bodies or missing geometry.
    		// NOTE: Simple count test is sufficient (w/o also checking TryGetAsBRep) as override of _Collect and _OnProcess methods have tool only collecting BRep solids.
    		return (__super::_IsElementValidForOperation(eh, path, cantAcceptReason) && 1 == GetElementGraphicsCacheCount(eh) && !IsGeometryMissing(eh));
    	}
    
    	/*---------------------------------------------------------------------------------**//**
    	* @bsimethod                                                              Bentley Systems
    	+---------------+---------------+---------------+---------------+---------------+------*/
    	double GetDistance()
    	{
    		// For testing purposes just use some % of element's range. This value would normally be supplied via tool settings.
    		ScanRangeCP elRange = &GetElementAgenda().GetFirstP()->GetElementCP()->hdr.dhdr.range;
    		DPoint3d    range[2];
    
    		range[0].x = (double)elRange->xlowlim;
    		range[0].y = (double)elRange->ylowlim;
    		range[0].z = (double)elRange->zlowlim;
    		range[1].x = (double)elRange->xhighlim;
    		range[1].y = (double)elRange->yhighlim;
    		range[1].z = (double)elRange->zhighlim;
    
    		return range[0].Distance(range[1]) * 0.1;
    	}
    
    	/*---------------------------------------------------------------------------------**//**
    	* @bsimethod                                                              Bentley Systems
    	+---------------+---------------+---------------+---------------+---------------+------*/
    	double GetAngle()
    	{
    		// For testing purposes just use 10 degrees. This value would normally be supplied via tool settings.
    		return Angle::DegreesToRadians(10.0);
    	}
    
    	/*---------------------------------------------------------------------------------**//**
    	* Perform the solid operation using the accepted faces.
    	* @bsimethod                                                              Bentley Systems
    	+---------------+---------------+---------------+---------------+---------------+------*/
    	StatusInt DoOperation(ISolidKernelEntityPtr& entityPtr, bvector<ISubEntityPtr>& faces)
    	{
    
    		double distance = 0.0;
    		for each (ISubEntityPtr subEntity in faces)
    		{
    			DPoint3d point;
    			DVec3d normal1, normal2;
    			if ((SUCCESS == SolidUtil::GetPlanarFaceData(&point, &normal1, *subEntity)))
    			{
    				normal2.x = pointDynamic.x - point.x;
    				normal2.y = pointDynamic.y - point.y;
    				normal2.z = pointDynamic.z - point.z;
    				distance = std::abs(normal1.x * normal2.x + normal1.y * normal2.y + normal1.z * normal2.z);
    				break;
    			}
    		}
    		bvector<double> offsets;
    
    		offsets.insert(offsets.begin(), faces.size(), distance);
    
    		return SolidUtil::Modify::OffsetFaces(entityPtr, &faces.front(), &offsets.front(), faces.size());
    
    	}
    
    	/*---------------------------------------------------------------------------------**//**
    	* @bsimethod                                                              Bentley Systems
    	+---------------+---------------+---------------+---------------+---------------+------*/
    	virtual StatusInt _OnElementModify(EditElementHandleR eeh) override
    	{
    		bvector<IElementGraphicsPtr>  geomCache;
    
    		// NOTE: Since we setup tool to only collect a single brep, we can just grab first cache entry...
    		ISolidKernelEntityPtr   entityPtr = (SUCCESS == GetElementGraphicsCache(eeh, geomCache) ? TryGetAsBRep(geomCache.front()) : NULL);
    
    		if (!entityPtr.IsValid())
    			return ERROR;
    
    		if (SUCCESS != DoOperation(entityPtr, GetAcceptedSubEntities()))
    			return ERROR;
    
    		return SolidUtil::Convert::BodyToElement(eeh, *entityPtr, &eeh, *eeh.GetModelRef());
    	}
    
    	/*---------------------------------------------------------------------------------**//**
    	* Install a new instance of the tool. Will be called in response to external events
    	* such as undo or by the base class from _OnReinitialize when the tool needs to be
    	* reset to it's initial state.
    	* @bsimethod                                                              Bentley Systems
    	+---------------+---------------+---------------+---------------+---------------+------*/
    	virtual void _OnRestartTool() override
    	{
    		InstallNewInstance(GetToolId(), m_operation);
    	}
    
    	virtual void _OnDynamicFrame(DgnButtonEventCR ev) override
    	{
    		pointDynamic = *ev.GetPoint();
    		if (GetElementAgenda().GetCount() > 0 && GetAcceptedSubEntities().size() > 0)
    		{
    			ElementHandleCP eeh = GetElementAgenda().GetFirstP();	//获取元素
    			bvector<IElementGraphicsPtr>  geomCache;
    			ISolidKernelEntityPtr entityPtr = (SUCCESS == GetElementGraphicsCache(*eeh, geomCache) ? TryGetAsBRep(geomCache.front()) : NULL);
    			if (!entityPtr.IsValid())
    				return;
    			bvector<ISubEntityPtr> faces = GetAcceptedSubEntities();
    			double distance = 0.0;
    			for each (ISubEntityPtr subEntity in faces)
    			{
    				DPoint3d point;
    				DVec3d normal1, normal2;
    				if ((SUCCESS == SolidUtil::GetPlanarFaceData(&point, &normal1, *subEntity)))
    				{
    					normal2.x = pointDynamic.x - point.x;
    					normal2.y = pointDynamic.y - point.y;
    					normal2.z = pointDynamic.z - point.z;
    					distance = std::abs(normal1.x*normal2.x + normal1.y*normal2.y + normal1.z*normal2.z);
    				}
    			}
    			bvector<double> offsets;
    			offsets.insert(offsets.begin(), faces.size(), distance);
    			SolidUtil::Modify::OffsetFaces(entityPtr, &faces.front(), &offsets.front(), faces.size());
    			//if (SUCCESS != SolidUtil::Modify::OffsetFaces(entityPtr, &faces.front(), &offsets.front(), faces.size()))
    		}
    	}
    public:
    
    	/*---------------------------------------------------------------------------------**//**
    	* Method to create and install a new instance of the tool. If InstallTool returns ERROR,
    	* the new tool instance will be freed/invalid. Never call delete on RefCounted classes.
    	* @bsimethod                                                              Bentley Systems
    	+---------------+---------------+---------------+---------------+---------------+------*/
    	static void InstallNewInstance(int toolId, ToolOperation operation)
    	{
    		TestModifyFaceTool* tool = new TestModifyFaceTool(toolId, operation);
    
    		tool->InstallTool();
    	}
    
    }; // TestModifyFaceTool

Children
No Data