3D-Viewer: raytracing, implement an outline board cut

it cut board items that are outside and on the edge of the board.
Allows castellations render.
This commit is contained in:
Mario Luzeiro 2020-10-29 12:48:45 +00:00 committed by Wayne Stambaugh
parent 18fdcbe61e
commit b06db80151
7 changed files with 168 additions and 56 deletions

View File

@ -170,7 +170,7 @@ class BOARD_ADAPTER
/**
* @brief GetEpoxyThickness3DU - Get the current epoxy thickness
* @return thickness in 3d unities
* @return thickness in 3d units
*/
float GetEpoxyThickness3DU() const noexcept
{
@ -179,7 +179,7 @@ class BOARD_ADAPTER
/**
* @brief GetNonCopperLayerThickness3DU - Get the current non copper layers thickness
* @return thickness in 3d unities of non copperlayers
* @return thickness in 3d units of non copperlayers
*/
float GetNonCopperLayerThickness3DU() const noexcept
{
@ -188,7 +188,7 @@ class BOARD_ADAPTER
/**
* @brief GetCopperThickness3DU - Get the current copper layer thickness
* @return thickness in 3d unities of copperlayers
* @return thickness in 3d units of copperlayers
*/
float GetCopperThickness3DU() const noexcept
{
@ -197,13 +197,13 @@ class BOARD_ADAPTER
/**
* @brief GetCopperThicknessBIU - Get the current copper layer thickness
* @return thickness in board unities
* @return thickness in board units
*/
int GetHolePlatingThicknessBIU() const noexcept;
/**
* @brief GetBoardSizeBIU - Get the board size
* @return size in BIU unities
* @return size in BIU units
*/
wxSize GetBoardSizeBIU() const noexcept
{
@ -211,8 +211,8 @@ class BOARD_ADAPTER
}
/**
* @brief GetBoardPosBIU - Get the board size
* @return size in BIU unities
* @brief GetBoardPosBIU - Get the board center
* @return position in BIU units
*/
wxPoint GetBoardPosBIU() const noexcept
{
@ -336,7 +336,7 @@ class BOARD_ADAPTER
/**
* @brief GetLayerTopZpos3DU - Get the top z position
* @param aLayerId: layer id
* @return position in 3D unities
* @return position in 3D units
*/
float GetLayerTopZpos3DU( PCB_LAYER_ID aLayerId ) const noexcept
{
@ -346,7 +346,7 @@ class BOARD_ADAPTER
/**
* @brief GetLayerBottomZpos3DU - Get the bottom z position
* @param aLayerId: layer id
* @return position in 3D unities
* @return position in 3D units
*/
float GetLayerBottomZpos3DU( PCB_LAYER_ID aLayerId ) const noexcept
{

View File

@ -59,6 +59,11 @@ public:
}
}
const CBBOX2D &GetBBox() const
{
return m_bbox;
}
void Clear();
const LIST_OBJECT2D &GetList() const { return m_objects; }

View File

@ -370,6 +370,21 @@ void C3D_RENDER_RAYTRACING::createItemsFromContainer( const CBVHCONTAINER2D *aCo
}
}
if( !m_antioutlineBoard2dObjects->GetList().empty() )
{
CONST_LIST_OBJECT2D intersectionList;
m_antioutlineBoard2dObjects->GetListObjectsIntersects(
object2d_A->GetBBox(), intersectionList );
if( !intersectionList.empty() )
{
for( const COBJECT2D *obj : intersectionList )
{
object2d_B->push_back( obj );
}
}
}
const MAP_CONTAINER_2D& mapLayers = m_boardAdapter.GetMapLayers();
@ -440,6 +455,8 @@ void C3D_RENDER_RAYTRACING::createItemsFromContainer( const CBVHCONTAINER2D *aCo
}
}
extern void buildBoardBoundingBoxPoly( const BOARD* aBoard, SHAPE_POLY_SET& aOutline );
void C3D_RENDER_RAYTRACING::Reload( REPORTER* aStatusReporter,
REPORTER* aWarningReporter,
bool aOnlyLoadCopperAndShapes )
@ -470,8 +487,10 @@ void C3D_RENDER_RAYTRACING::Reload( REPORTER* aStatusReporter,
// /////////////////////////////////////////////////////////////////////////
delete m_outlineBoard2dObjects;
delete m_antioutlineBoard2dObjects;
m_outlineBoard2dObjects = new CCONTAINER2D;
m_antioutlineBoard2dObjects = new CBVHCONTAINER2D;
if( !aOnlyLoadCopperAndShapes )
{
@ -488,6 +507,29 @@ void C3D_RENDER_RAYTRACING::Reload( REPORTER* aStatusReporter,
divFactor = m_boardAdapter.GetStats_Med_Hole_Diameter3DU() * 8.0f;
SHAPE_POLY_SET boardPolyCopy = m_boardAdapter.GetBoardPoly();
// Calculate an antiboard outline
SHAPE_POLY_SET antiboardPoly;
buildBoardBoundingBoxPoly( m_boardAdapter.GetBoard(), antiboardPoly );
antiboardPoly.BooleanSubtract( boardPolyCopy, SHAPE_POLY_SET::PM_FAST );
antiboardPoly.Fracture( SHAPE_POLY_SET::PM_FAST );
for( int iOutlinePolyIdx = 0; iOutlinePolyIdx < antiboardPoly.OutlineCount(); iOutlinePolyIdx++ )
{
Convert_path_polygon_to_polygon_blocks_and_dummy_blocks(
antiboardPoly,
*m_antioutlineBoard2dObjects,
m_boardAdapter.BiuTo3Dunits(),
divFactor,
*dynamic_cast<const BOARD_ITEM*>( m_boardAdapter.GetBoard() ),
iOutlinePolyIdx );
}
m_antioutlineBoard2dObjects->BuildBVH();
boardPolyCopy.Fracture( SHAPE_POLY_SET::PM_FAST );
for( int iOutlinePolyIdx = 0; iOutlinePolyIdx < outlineCount; iOutlinePolyIdx++ )
@ -537,6 +579,23 @@ void C3D_RENDER_RAYTRACING::Reload( REPORTER* aStatusReporter,
}
}
if( !m_antioutlineBoard2dObjects->GetList().empty() )
{
CONST_LIST_OBJECT2D intersectionList;
m_antioutlineBoard2dObjects->GetListObjectsIntersects(
object2d_A->GetBBox(),
intersectionList );
if( !intersectionList.empty() )
{
for( const COBJECT2D *obj : intersectionList )
{
object2d_B->push_back( obj );
}
}
}
if( object2d_B->empty() )
{
delete object2d_B;
@ -545,14 +604,6 @@ void C3D_RENDER_RAYTRACING::Reload( REPORTER* aStatusReporter,
if( object2d_B == CSGITEM_EMPTY )
{
#if 0
create_3d_object_from( m_object_container, object2d_A,
m_boardAdapter.GetLayerBottomZpos3DU( F_Cu ),
m_boardAdapter.GetLayerBottomZpos3DU( B_Cu ),
&m_materials.m_EpoxyBoard,
g_epoxyColor );
#else
CLAYERITEM *objPtr = new CLAYERITEM( object2d_A,
m_boardAdapter.GetLayerBottomZpos3DU( F_Cu ),
m_boardAdapter.GetLayerBottomZpos3DU( B_Cu ) );
@ -560,7 +611,6 @@ void C3D_RENDER_RAYTRACING::Reload( REPORTER* aStatusReporter,
objPtr->SetMaterial( &m_materials.m_EpoxyBoard );
objPtr->SetColor( ConvertSRGBToLinear( (SFVEC3F)m_boardAdapter.m_BoardBodyColor ) );
m_object_container.Add( objPtr );
#endif
}
else
{
@ -601,6 +651,21 @@ void C3D_RENDER_RAYTRACING::Reload( REPORTER* aStatusReporter,
{
const COBJECT2D *hole2d = static_cast<const COBJECT2D *>(*hole);
if( !m_antioutlineBoard2dObjects->GetList().empty() )
{
CONST_LIST_OBJECT2D intersectionList;
m_antioutlineBoard2dObjects->GetListObjectsIntersects(
hole2d->GetBBox(), intersectionList );
if( !intersectionList.empty() )
{
// Do not add cylinder if it intersects the edge of the board
continue;
}
}
switch( hole2d->GetObjectType() )
{
case OBJECT2D_TYPE::FILLED_CIRCLE:
@ -642,7 +707,7 @@ void C3D_RENDER_RAYTRACING::Reload( REPORTER* aStatusReporter,
if( aOnlyLoadCopperAndShapes && !IsCopperLayer( layer_id ) )
continue;
// Mask kayers are not processed here because they are a special case
// Mask layers are not processed here because they are a special case
if( (layer_id == B_Mask) || (layer_id == F_Mask) )
continue;
@ -1099,6 +1164,8 @@ void C3D_RENDER_RAYTRACING::insert3DPadHole( const D_PAD* aPad )
if( !hasHole )
return;
CONST_LIST_OBJECT2D antiOutlineIntersectionList;
const float topZ = m_boardAdapter.GetLayerBottomZpos3DU( F_Cu ) +
m_boardAdapter.GetCopperThickness3DU();
@ -1112,6 +1179,7 @@ void C3D_RENDER_RAYTRACING::insert3DPadHole( const D_PAD* aPad )
int innerRadius = drillsize.x / 2;
int outerRadius = innerRadius + m_boardAdapter.GetHolePlatingThicknessBIU();
CRING2D *ring = new CRING2D( center,
innerRadius * m_boardAdapter.BiuTo3Dunits(),
outerRadius * m_boardAdapter.BiuTo3Dunits(),
@ -1120,6 +1188,40 @@ void C3D_RENDER_RAYTRACING::insert3DPadHole( const D_PAD* aPad )
m_containerWithObjectsToDelete.Add( ring );
object2d_A = ring;
// If the object (ring) is intersected by an antioutline board,
// it will use instease a CSG of two circles.
if( object2d_A && !m_antioutlineBoard2dObjects->GetList().empty() )
{
m_antioutlineBoard2dObjects->GetListObjectsIntersects(
object2d_A->GetBBox(),
antiOutlineIntersectionList );
}
if( !antiOutlineIntersectionList.empty() )
{
CFILLEDCIRCLE2D *innerCircle = new CFILLEDCIRCLE2D( center,
innerRadius * m_boardAdapter.BiuTo3Dunits(),
*aPad );
CFILLEDCIRCLE2D *outterCircle = new CFILLEDCIRCLE2D( center,
outerRadius * m_boardAdapter.BiuTo3Dunits(),
*aPad );
std::vector<const COBJECT2D *> *object2d_B = new std::vector<const COBJECT2D *>();
object2d_B->push_back( innerCircle );
CITEMLAYERCSG2D *itemCSG2d = new CITEMLAYERCSG2D( outterCircle,
object2d_B,
CSGITEM_FULL,
*aPad );
m_containerWithObjectsToDelete.Add( itemCSG2d );
m_containerWithObjectsToDelete.Add( innerCircle );
m_containerWithObjectsToDelete.Add( outterCircle );
object2d_A = itemCSG2d;
}
}
else // Oblong hole
{
@ -1173,6 +1275,14 @@ void C3D_RENDER_RAYTRACING::insert3DPadHole( const D_PAD* aPad )
m_containerWithObjectsToDelete.Add( outerSeg );
object2d_A = itemCSG2d;
if( object2d_A && !m_antioutlineBoard2dObjects->GetList().empty() )
{
m_antioutlineBoard2dObjects->GetListObjectsIntersects(
object2d_A->GetBBox(),
antiOutlineIntersectionList );
}
}
@ -1204,6 +1314,14 @@ void C3D_RENDER_RAYTRACING::insert3DPadHole( const D_PAD* aPad )
}
}
if( !antiOutlineIntersectionList.empty() )
{
for( const COBJECT2D *obj : antiOutlineIntersectionList )
{
object2d_B->push_back( obj );
}
}
if( object2d_B->empty() )
{
delete object2d_B;

View File

@ -61,6 +61,7 @@ C3D_RENDER_RAYTRACING::C3D_RENDER_RAYTRACING( BOARD_ADAPTER& aAdapter, CCAMERA&
m_oldWindowsSize.x = 0;
m_oldWindowsSize.y = 0;
m_outlineBoard2dObjects = NULL;
m_antioutlineBoard2dObjects = NULL;
m_firstHitinfo = NULL;
m_shaderBuffer = NULL;
m_camera_light = NULL;
@ -85,6 +86,9 @@ C3D_RENDER_RAYTRACING::~C3D_RENDER_RAYTRACING()
delete m_outlineBoard2dObjects;
m_outlineBoard2dObjects = NULL;
delete m_antioutlineBoard2dObjects;
m_antioutlineBoard2dObjects = NULL;
delete[] m_shaderBuffer;
m_shaderBuffer = NULL;

View File

@ -160,6 +160,7 @@ private:
CCONTAINER2D m_containerWithObjectsToDelete;
CCONTAINER2D *m_outlineBoard2dObjects;
CBVHCONTAINER2D *m_antioutlineBoard2dObjects;
CGENERICACCELERATOR *m_accelerator;

View File

@ -90,6 +90,7 @@ bool CITEMLAYERCSG2D::Intersect( const RAYSEG2D &aSegRay,
float currentRayDist;
SFVEC2F currentRayPos;
SFVEC2F currentNormal;
RAYSEG2D currentRay = aSegRay;
if( m_objectA->IsPointInside( aSegRay.m_Start ) )
{
@ -103,18 +104,20 @@ bool CITEMLAYERCSG2D::Intersect( const RAYSEG2D &aSegRay,
if( !m_objectA->Intersect( aSegRay, &currentRayDist, &currentNormal ) )
return false;
currentRayPos = aSegRay.atNormalized( NextFloatDown( currentRayDist ) );
currentRayPos = aSegRay.atNormalized( currentRayDist + 0.01f );
currentRay = RAYSEG2D( currentRayPos, aSegRay.m_End );
}
currentRayDist = 0.0f;
//wxASSERT( (currentRayDist >= 0.0f) && (currentRayDist <= 1.0f) );
// move through the union of subtracted regions
bool hitSubRegion = false;
if( m_objectB )
{
while(1)
for( unsigned int l = 0; l < 4; ++l )
{
bool wasInsideSubVol = false;
@ -123,60 +126,41 @@ bool CITEMLAYERCSG2D::Intersect( const RAYSEG2D &aSegRay,
{
if( ((const COBJECT2D *)(*m_objectB)[i])->IsPointInside( currentRayPos ) )
{
hitSubRegion = true;
// ray point is inside a subtracted region, so move it to the end of the
// subtracted region
float hitDist;
if( !((const COBJECT2D *)(*m_objectB)[i])->Intersect( aSegRay,
SFVEC2F tmpNormal;
if( !((const COBJECT2D *)(*m_objectB)[i])->Intersect( currentRay,
&hitDist,
&currentNormal ) )
&tmpNormal ) )
return false; // ray hit main object but did not leave subtracted volume
wxASSERT( hitDist <= 1.0f );
if( hitDist > currentRayDist )
currentRayDist = hitDist;
currentRayDist += 0.0001f;
// ray has left this specific subtracted object volume
currentRayPos = aSegRay.atNormalized( currentRayDist );
if( m_objectA->IsPointInside( currentRayPos ) )
{
wasInsideSubVol = true;
break;
currentRayPos = currentRay.atNormalized( glm::min( hitDist + 0.0001f, 1.0f ) );
currentRayDist = 0.0001f;
currentRay = RAYSEG2D( currentRayPos, aSegRay.m_End );
currentNormal = tmpNormal * -1.0f;
}
}
}
if( !wasInsideSubVol )
break; // ray has succesfully passed through all subtracted regions
if( currentRayDist >= 1.0f )
{
break;
}
}
//ray is not inside any of the specific subtracted regions
if( hitSubRegion )
{
//if( !m_objectA->IsPointInside( currentRayPos ) )
// return false; // ray got right through the hole in the object!
currentNormal *= -1.0f;
}
else
{
//ray just hit the main object without hitting any holes
}
*aNormalOut = currentNormal;
*aOutT = currentRayDist;
*aOutT = glm::min( glm::max( 1.0f - glm::length( currentRayPos - aSegRay.m_End ) / aSegRay.m_Length, 0.0f ), 1.0f );
return true;
}

View File

@ -207,7 +207,7 @@ bool CPOLYGONBLOCK2D::IsPointInside( const SFVEC2F &aPoint ) const
// At this moment, the point is not inside a hole, so check if it is
// inside the polygon
for( unsigned int i = 0; i < m_outers_and_holes.m_Outers.size(); i++ )
if( !m_outers_and_holes.m_Outers.empty() )
if( !m_outers_and_holes.m_Outers[i].empty() )
if( polygon_IsPointInside( m_outers_and_holes.m_Outers[i], aPoint ) )
return true;