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

View File

@ -59,6 +59,11 @@ public:
} }
} }
const CBBOX2D &GetBBox() const
{
return m_bbox;
}
void Clear(); void Clear();
const LIST_OBJECT2D &GetList() const { return m_objects; } 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(); 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, void C3D_RENDER_RAYTRACING::Reload( REPORTER* aStatusReporter,
REPORTER* aWarningReporter, REPORTER* aWarningReporter,
bool aOnlyLoadCopperAndShapes ) bool aOnlyLoadCopperAndShapes )
@ -470,8 +487,10 @@ void C3D_RENDER_RAYTRACING::Reload( REPORTER* aStatusReporter,
// ///////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
delete m_outlineBoard2dObjects; delete m_outlineBoard2dObjects;
delete m_antioutlineBoard2dObjects;
m_outlineBoard2dObjects = new CCONTAINER2D; m_outlineBoard2dObjects = new CCONTAINER2D;
m_antioutlineBoard2dObjects = new CBVHCONTAINER2D;
if( !aOnlyLoadCopperAndShapes ) if( !aOnlyLoadCopperAndShapes )
{ {
@ -488,6 +507,29 @@ void C3D_RENDER_RAYTRACING::Reload( REPORTER* aStatusReporter,
divFactor = m_boardAdapter.GetStats_Med_Hole_Diameter3DU() * 8.0f; divFactor = m_boardAdapter.GetStats_Med_Hole_Diameter3DU() * 8.0f;
SHAPE_POLY_SET boardPolyCopy = m_boardAdapter.GetBoardPoly(); 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 ); boardPolyCopy.Fracture( SHAPE_POLY_SET::PM_FAST );
for( int iOutlinePolyIdx = 0; iOutlinePolyIdx < outlineCount; iOutlinePolyIdx++ ) 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() ) if( object2d_B->empty() )
{ {
delete object2d_B; delete object2d_B;
@ -545,14 +604,6 @@ void C3D_RENDER_RAYTRACING::Reload( REPORTER* aStatusReporter,
if( object2d_B == CSGITEM_EMPTY ) 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, CLAYERITEM *objPtr = new CLAYERITEM( object2d_A,
m_boardAdapter.GetLayerBottomZpos3DU( F_Cu ), m_boardAdapter.GetLayerBottomZpos3DU( F_Cu ),
m_boardAdapter.GetLayerBottomZpos3DU( B_Cu ) ); m_boardAdapter.GetLayerBottomZpos3DU( B_Cu ) );
@ -560,7 +611,6 @@ void C3D_RENDER_RAYTRACING::Reload( REPORTER* aStatusReporter,
objPtr->SetMaterial( &m_materials.m_EpoxyBoard ); objPtr->SetMaterial( &m_materials.m_EpoxyBoard );
objPtr->SetColor( ConvertSRGBToLinear( (SFVEC3F)m_boardAdapter.m_BoardBodyColor ) ); objPtr->SetColor( ConvertSRGBToLinear( (SFVEC3F)m_boardAdapter.m_BoardBodyColor ) );
m_object_container.Add( objPtr ); m_object_container.Add( objPtr );
#endif
} }
else else
{ {
@ -601,6 +651,21 @@ void C3D_RENDER_RAYTRACING::Reload( REPORTER* aStatusReporter,
{ {
const COBJECT2D *hole2d = static_cast<const COBJECT2D *>(*hole); 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() ) switch( hole2d->GetObjectType() )
{ {
case OBJECT2D_TYPE::FILLED_CIRCLE: case OBJECT2D_TYPE::FILLED_CIRCLE:
@ -642,7 +707,7 @@ void C3D_RENDER_RAYTRACING::Reload( REPORTER* aStatusReporter,
if( aOnlyLoadCopperAndShapes && !IsCopperLayer( layer_id ) ) if( aOnlyLoadCopperAndShapes && !IsCopperLayer( layer_id ) )
continue; 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) ) if( (layer_id == B_Mask) || (layer_id == F_Mask) )
continue; continue;
@ -1099,6 +1164,8 @@ void C3D_RENDER_RAYTRACING::insert3DPadHole( const D_PAD* aPad )
if( !hasHole ) if( !hasHole )
return; return;
CONST_LIST_OBJECT2D antiOutlineIntersectionList;
const float topZ = m_boardAdapter.GetLayerBottomZpos3DU( F_Cu ) + const float topZ = m_boardAdapter.GetLayerBottomZpos3DU( F_Cu ) +
m_boardAdapter.GetCopperThickness3DU(); m_boardAdapter.GetCopperThickness3DU();
@ -1112,6 +1179,7 @@ void C3D_RENDER_RAYTRACING::insert3DPadHole( const D_PAD* aPad )
int innerRadius = drillsize.x / 2; int innerRadius = drillsize.x / 2;
int outerRadius = innerRadius + m_boardAdapter.GetHolePlatingThicknessBIU(); int outerRadius = innerRadius + m_boardAdapter.GetHolePlatingThicknessBIU();
CRING2D *ring = new CRING2D( center, CRING2D *ring = new CRING2D( center,
innerRadius * m_boardAdapter.BiuTo3Dunits(), innerRadius * m_boardAdapter.BiuTo3Dunits(),
outerRadius * m_boardAdapter.BiuTo3Dunits(), outerRadius * m_boardAdapter.BiuTo3Dunits(),
@ -1120,6 +1188,40 @@ void C3D_RENDER_RAYTRACING::insert3DPadHole( const D_PAD* aPad )
m_containerWithObjectsToDelete.Add( ring ); m_containerWithObjectsToDelete.Add( ring );
object2d_A = 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 else // Oblong hole
{ {
@ -1173,6 +1275,14 @@ void C3D_RENDER_RAYTRACING::insert3DPadHole( const D_PAD* aPad )
m_containerWithObjectsToDelete.Add( outerSeg ); m_containerWithObjectsToDelete.Add( outerSeg );
object2d_A = itemCSG2d; 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() ) if( object2d_B->empty() )
{ {
delete object2d_B; 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.x = 0;
m_oldWindowsSize.y = 0; m_oldWindowsSize.y = 0;
m_outlineBoard2dObjects = NULL; m_outlineBoard2dObjects = NULL;
m_antioutlineBoard2dObjects = NULL;
m_firstHitinfo = NULL; m_firstHitinfo = NULL;
m_shaderBuffer = NULL; m_shaderBuffer = NULL;
m_camera_light = NULL; m_camera_light = NULL;
@ -85,6 +86,9 @@ C3D_RENDER_RAYTRACING::~C3D_RENDER_RAYTRACING()
delete m_outlineBoard2dObjects; delete m_outlineBoard2dObjects;
m_outlineBoard2dObjects = NULL; m_outlineBoard2dObjects = NULL;
delete m_antioutlineBoard2dObjects;
m_antioutlineBoard2dObjects = NULL;
delete[] m_shaderBuffer; delete[] m_shaderBuffer;
m_shaderBuffer = NULL; m_shaderBuffer = NULL;

View File

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

View File

@ -90,6 +90,7 @@ bool CITEMLAYERCSG2D::Intersect( const RAYSEG2D &aSegRay,
float currentRayDist; float currentRayDist;
SFVEC2F currentRayPos; SFVEC2F currentRayPos;
SFVEC2F currentNormal; SFVEC2F currentNormal;
RAYSEG2D currentRay = aSegRay;
if( m_objectA->IsPointInside( aSegRay.m_Start ) ) if( m_objectA->IsPointInside( aSegRay.m_Start ) )
{ {
@ -103,18 +104,20 @@ bool CITEMLAYERCSG2D::Intersect( const RAYSEG2D &aSegRay,
if( !m_objectA->Intersect( aSegRay, &currentRayDist, &currentNormal ) ) if( !m_objectA->Intersect( aSegRay, &currentRayDist, &currentNormal ) )
return false; 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) ); //wxASSERT( (currentRayDist >= 0.0f) && (currentRayDist <= 1.0f) );
// move through the union of subtracted regions // move through the union of subtracted regions
bool hitSubRegion = false;
if( m_objectB ) if( m_objectB )
{ {
while(1) for( unsigned int l = 0; l < 4; ++l )
{ {
bool wasInsideSubVol = false; bool wasInsideSubVol = false;
@ -123,60 +126,41 @@ bool CITEMLAYERCSG2D::Intersect( const RAYSEG2D &aSegRay,
{ {
if( ((const COBJECT2D *)(*m_objectB)[i])->IsPointInside( currentRayPos ) ) 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 // ray point is inside a subtracted region, so move it to the end of the
// subtracted region // subtracted region
float hitDist; float hitDist;
if( !((const COBJECT2D *)(*m_objectB)[i])->Intersect( aSegRay, SFVEC2F tmpNormal;
if( !((const COBJECT2D *)(*m_objectB)[i])->Intersect( currentRay,
&hitDist, &hitDist,
&currentNormal ) ) &tmpNormal ) )
return false; // ray hit main object but did not leave subtracted volume return false; // ray hit main object but did not leave subtracted volume
wxASSERT( hitDist <= 1.0f ); wxASSERT( hitDist <= 1.0f );
if( hitDist > currentRayDist ) 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; 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 ) if( !wasInsideSubVol )
break; // ray has succesfully passed through all subtracted regions {
if( currentRayDist >= 1.0f )
break; 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; *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; 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 // At this moment, the point is not inside a hole, so check if it is
// inside the polygon // inside the polygon
for( unsigned int i = 0; i < m_outers_and_holes.m_Outers.size(); i++ ) 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 ) ) if( polygon_IsPointInside( m_outers_and_holes.m_Outers[i], aPoint ) )
return true; return true;