3D-Viewer: OpenGL, remove outline polygons where it intersects a hole at edge of board

This commit is contained in:
Mario Luzeiro 2020-11-04 09:36:41 +00:00 committed by Wayne Stambaugh
parent 4b6c602537
commit 89fea36ddd
15 changed files with 189 additions and 67 deletions

View File

@ -565,6 +565,9 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
AddPadsShapesWithClearanceToContainer( module, m_platedpads_container2D_B_Cu, B_Cu, 0,
true, false, true );
}
m_platedpads_container2D_F_Cu->BuildBVH();
m_platedpads_container2D_B_Cu->BuildBVH();
}
// Add footprints PADs poly contourns (vertical outlines)

View File

@ -272,7 +272,8 @@ CLAYERS_OGL_DISP_LISTS *C3D_RENDER_OGL_LEGACY::generate_holes_display_list(
const SHAPE_POLY_SET &aPoly,
float aZtop,
float aZbot,
bool aInvertFaces )
bool aInvertFaces,
const CBVHCONTAINER2D *aThroughHoles )
{
CLAYERS_OGL_DISP_LISTS *ret = NULL;
@ -319,7 +320,8 @@ CLAYERS_OGL_DISP_LISTS *C3D_RENDER_OGL_LEGACY::generate_holes_display_list(
aZbot,
aZtop,
m_boardAdapter.BiuTo3Dunits(),
aInvertFaces );
aInvertFaces,
aThroughHoles );
}
ret = new CLAYERS_OGL_DISP_LISTS( *layerTriangles,
@ -336,7 +338,8 @@ CLAYERS_OGL_DISP_LISTS *C3D_RENDER_OGL_LEGACY::generate_holes_display_list(
CLAYERS_OGL_DISP_LISTS* C3D_RENDER_OGL_LEGACY::generateLayerListFromContainer( const CBVHCONTAINER2D *aContainer,
const SHAPE_POLY_SET *aPolyList,
PCB_LAYER_ID aLayerId )
PCB_LAYER_ID aLayerId,
const CBVHCONTAINER2D *aThroughHoles )
{
if( aContainer == nullptr )
return nullptr;
@ -402,7 +405,8 @@ CLAYERS_OGL_DISP_LISTS* C3D_RENDER_OGL_LEGACY::generateLayerListFromContainer( c
if( aPolyList )
if( aPolyList->OutlineCount() > 0 )
layerTriangles->AddToMiddleContourns( *aPolyList, layer_z_bot, layer_z_top,
m_boardAdapter.BiuTo3Dunits(), false );
m_boardAdapter.BiuTo3Dunits(), false,
aThroughHoles );
// Create display list
// /////////////////////////////////////////////////////////////////////
return new CLAYERS_OGL_DISP_LISTS( *layerTriangles, m_ogl_circle_texture,
@ -410,7 +414,7 @@ CLAYERS_OGL_DISP_LISTS* C3D_RENDER_OGL_LEGACY::generateLayerListFromContainer( c
}
CLAYERS_OGL_DISP_LISTS* C3D_RENDER_OGL_LEGACY::createBoard( const SHAPE_POLY_SET& aBoardPoly )
CLAYERS_OGL_DISP_LISTS* C3D_RENDER_OGL_LEGACY::createBoard( const SHAPE_POLY_SET& aBoardPoly, const CBVHCONTAINER2D *aThroughHoles )
{
CLAYERS_OGL_DISP_LISTS* dispLists = nullptr;
CCONTAINER2D boardContainer;
@ -461,7 +465,8 @@ CLAYERS_OGL_DISP_LISTS* C3D_RENDER_OGL_LEGACY::createBoard( const SHAPE_POLY_SET
layer_z_bot,
layer_z_top,
m_boardAdapter.BiuTo3Dunits(),
false );
false,
aThroughHoles );
dispLists = new CLAYERS_OGL_DISP_LISTS( *layerTriangles,
m_ogl_circle_texture,
@ -497,7 +502,7 @@ void C3D_RENDER_OGL_LEGACY::reload( REPORTER* aStatusReporter, REPORTER* aWarnin
// Create Board
// /////////////////////////////////////////////////////////////////////////
m_ogl_disp_list_board = createBoard( m_boardAdapter.GetBoardPoly() );
m_ogl_disp_list_board = createBoard( m_boardAdapter.GetBoardPoly(), &m_boardAdapter.GetThroughHole_Inner() );
m_anti_board_poly.RemoveAllContours();
m_anti_board_poly.NewOutline();
@ -533,7 +538,8 @@ void C3D_RENDER_OGL_LEGACY::reload( REPORTER* aStatusReporter, REPORTER* aWarnin
outerPolyTHT,
1.0f,
0.0f,
false );
false,
&m_boardAdapter.GetThroughHole_Inner() );
m_ogl_disp_list_through_holes_vias_outer = generate_holes_display_list(
m_boardAdapter.GetThroughHole_Vias_Outer().GetList(),
@ -632,16 +638,31 @@ void C3D_RENDER_OGL_LEGACY::reload( REPORTER* aStatusReporter, REPORTER* aWarnin
SHAPE_POLY_SET polyListSubtracted;
polyListSubtracted = *aPolyList;
polyListSubtracted.BooleanIntersection( m_boardAdapter.GetBoardPoly(), SHAPE_POLY_SET::PM_FAST );
if( ( layer_id != B_Mask ) &&
( layer_id != F_Mask ) )
if( ( layer_id != B_Paste ) && ( layer_id != F_Paste ) )
{
polyListSubtracted.BooleanSubtract( m_boardAdapter.GetThroughHole_Outer_poly(), SHAPE_POLY_SET::PM_FAST );
polyListSubtracted.BooleanSubtract( m_boardAdapter.GetThroughHole_Outer_poly_NPTH(), SHAPE_POLY_SET::PM_FAST );
polyListSubtracted.BooleanIntersection( m_boardAdapter.GetBoardPoly(), SHAPE_POLY_SET::PM_FAST );
if( ( layer_id != B_Mask ) && ( layer_id != F_Mask ) )
{
polyListSubtracted.BooleanSubtract( m_boardAdapter.GetThroughHole_Outer_poly(), SHAPE_POLY_SET::PM_FAST );
polyListSubtracted.BooleanSubtract( m_boardAdapter.GetThroughHole_Outer_poly_NPTH(), SHAPE_POLY_SET::PM_FAST );
}
if( m_boardAdapter.GetFlag( FL_SUBTRACT_MASK_FROM_SILK ) )
{
if( ( ( layer_id == B_SilkS ) && ( map_poly.find( B_Mask ) != map_poly.end() ) ) )
polyListSubtracted.BooleanSubtract( *map_poly.at( B_Mask ), SHAPE_POLY_SET::PM_FAST );
else
if( ( ( layer_id == F_SilkS ) && ( map_poly.find( F_Mask ) != map_poly.end() ) ) )
polyListSubtracted.BooleanSubtract( *map_poly.at( F_Mask ), SHAPE_POLY_SET::PM_FAST );
}
}
CLAYERS_OGL_DISP_LISTS* oglList = generateLayerListFromContainer( container2d, &polyListSubtracted, layer_id );
CLAYERS_OGL_DISP_LISTS* oglList = generateLayerListFromContainer( container2d,
&polyListSubtracted,
layer_id,
&m_boardAdapter.GetThroughHole_Inner() );
if( oglList != nullptr )
m_ogl_disp_lists_layers[layer_id] = oglList;

View File

@ -857,9 +857,14 @@ bool C3D_RENDER_OGL_LEGACY::Redraw(
pLayerDispList->GetZTop() - pLayerDispList->GetZBot() );
}
if( m_ogl_disp_list_anti_board )
CLAYERS_OGL_DISP_LISTS* ogl_disp_list_anti_board = m_ogl_disp_list_anti_board;
if( ( layer_id == B_Paste ) || ( layer_id == F_Paste ) )
ogl_disp_list_anti_board = nullptr;
if( ogl_disp_list_anti_board )
{
m_ogl_disp_list_anti_board->ApplyScalePosition( pLayerDispList->GetZBot(),
ogl_disp_list_anti_board->ApplyScalePosition( pLayerDispList->GetZBot(),
pLayerDispList->GetZTop() - pLayerDispList->GetZBot() );
}
@ -878,7 +883,7 @@ bool C3D_RENDER_OGL_LEGACY::Redraw(
drawMiddleSegments,
pLayerDispListMask,
dispListThroughHolesOuter,
m_ogl_disp_list_anti_board );
ogl_disp_list_anti_board );
}
else
{
@ -889,7 +894,7 @@ bool C3D_RENDER_OGL_LEGACY::Redraw(
drawMiddleSegments,
nullptr,
dispListThroughHolesOuter,
m_ogl_disp_list_anti_board );
ogl_disp_list_anti_board );
}
else
{
@ -899,7 +904,7 @@ bool C3D_RENDER_OGL_LEGACY::Redraw(
{
pLayerDispList->DrawAllCameraCulledSubtractLayer(
drawMiddleSegments,
m_ogl_disp_list_anti_board );
ogl_disp_list_anti_board );
}
}
}

View File

@ -73,7 +73,7 @@ public:
private:
bool initializeOpenGL();
CLAYERS_OGL_DISP_LISTS* createBoard( const SHAPE_POLY_SET& aBoardPoly );
CLAYERS_OGL_DISP_LISTS* createBoard( const SHAPE_POLY_SET& aBoardPoly, const CBVHCONTAINER2D *aThroughHoles = nullptr );
void reload( REPORTER* aStatusReporter, REPORTER* aWarningReporter );
void ogl_set_arrow_material();
@ -122,11 +122,13 @@ private:
const SHAPE_POLY_SET &aPoly,
float aZtop,
float aZbot,
bool aInvertFaces );
bool aInvertFaces,
const CBVHCONTAINER2D *aThroughHoles = nullptr );
CLAYERS_OGL_DISP_LISTS* generateLayerListFromContainer( const CBVHCONTAINER2D *aContainer,
CLAYERS_OGL_DISP_LISTS* generateLayerListFromContainer( const CBVHCONTAINER2D *aContainer,
const SHAPE_POLY_SET *aPolyList,
PCB_LAYER_ID aLayerId );
PCB_LAYER_ID aLayerId,
const CBVHCONTAINER2D *aThroughHoles = nullptr );
void add_triangle_top_bot( CLAYER_TRIANGLES *aDst,
const SFVEC2F &v0,

View File

@ -148,7 +148,8 @@ CLAYER_TRIANGLES::~CLAYER_TRIANGLES()
void CLAYER_TRIANGLES::AddToMiddleContourns( const std::vector< SFVEC2F > &aContournPoints,
float zBot,
float zTop,
bool aInvertFaceDirection )
bool aInvertFaceDirection,
const CBVHCONTAINER2D *aThroughHoles )
{
if( aContournPoints.size() >= 4 )
{
@ -220,6 +221,10 @@ void CLAYER_TRIANGLES::AddToMiddleContourns( const std::vector< SFVEC2F > &aCont
const SFVEC2F &v0 = aContournPoints[i + 0];
const SFVEC2F &v1 = aContournPoints[i + 1];
if( aThroughHoles && aThroughHoles->IntersectAny( RAYSEG2D( v0, v1 ) ) )
continue;
else
//if( aThroughHoles && aThroughHoles->IntersectAny( RAYSEG2D( v0, v1 ) ) )
{
std::lock_guard<std::mutex> lock( m_middle_layer_lock );
m_layer_middle_contourns_quads->AddQuad( SFVEC3F( v0.x, v0.y, zTop ),
@ -238,7 +243,8 @@ void CLAYER_TRIANGLES::AddToMiddleContourns( const SHAPE_LINE_CHAIN &outlinePath
float zBot,
float zTop,
double aBiuTo3Du,
bool aInvertFaceDirection )
bool aInvertFaceDirection,
const CBVHCONTAINER2D *aThroughHoles )
{
std::vector< SFVEC2F >contournPoints;
@ -270,7 +276,7 @@ void CLAYER_TRIANGLES::AddToMiddleContourns( const SHAPE_LINE_CHAIN &outlinePath
if( lastV != contournPoints[0] )
contournPoints.push_back( contournPoints[0] );
AddToMiddleContourns( contournPoints, zBot, zTop, aInvertFaceDirection );
AddToMiddleContourns( contournPoints, zBot, zTop, aInvertFaceDirection, aThroughHoles );
}
@ -278,7 +284,8 @@ void CLAYER_TRIANGLES::AddToMiddleContourns( const SHAPE_POLY_SET &aPolySet,
float zBot,
float zTop,
double aBiuTo3Du,
bool aInvertFaceDirection )
bool aInvertFaceDirection,
const CBVHCONTAINER2D *aThroughHoles )
{
if( aPolySet.OutlineCount() == 0 )
return;
@ -309,13 +316,13 @@ void CLAYER_TRIANGLES::AddToMiddleContourns( const SHAPE_POLY_SET &aPolySet,
// Add outline
const SHAPE_LINE_CHAIN& pathOutline = aPolySet.COutline( i );
AddToMiddleContourns( pathOutline, zBot, zTop, aBiuTo3Du, aInvertFaceDirection );
AddToMiddleContourns( pathOutline, zBot, zTop, aBiuTo3Du, aInvertFaceDirection, aThroughHoles );
// Add holes for this outline
for( int h = 0; h < aPolySet.HoleCount( i ); ++h )
{
const SHAPE_LINE_CHAIN &hole = aPolySet.CHole( i, h );
AddToMiddleContourns( hole, zBot, zTop, aBiuTo3Du, aInvertFaceDirection );
AddToMiddleContourns( hole, zBot, zTop, aBiuTo3Du, aInvertFaceDirection, aThroughHoles );
}
}
}

View File

@ -34,6 +34,7 @@
#include <plugins/3dapi/xv3d_types.h>
#include <geometry/shape_line_chain.h>
#include <geometry/shape_poly_set.h>
#include <3d_render_raytracing/accelerators/ccontainer2d.h>
#include <vector>
#include <mutex>
@ -162,18 +163,21 @@ public:
float zBot,
float zTop,
double aBiuTo3Du,
bool aInvertFaceDirection );
bool aInvertFaceDirection,
const CBVHCONTAINER2D *aThroughHoles = nullptr );
void AddToMiddleContourns( const SHAPE_POLY_SET &aPolySet,
float zBot,
float zTop,
double aBiuTo3Du,
bool aInvertFaceDirection );
bool aInvertFaceDirection,
const CBVHCONTAINER2D *aThroughHoles = nullptr );
void AddToMiddleContourns( const std::vector< SFVEC2F > &aContournPoints,
float zBot,
float zTop,
bool aInvertFaceDirection );
bool aInvertFaceDirection,
const CBVHCONTAINER2D *aThroughHoles = nullptr );
std::mutex m_middle_layer_lock;

View File

@ -154,6 +154,12 @@ void CCONTAINER2D::GetListObjectsIntersects( const CBBOX2D & aBBox,
}
bool CCONTAINER2D::IntersectAny( const RAYSEG2D &aSegRay ) const
{
// !TODO:
return false;
}
// /////////////////////////////////////////////////////////////////////////////
@ -388,6 +394,56 @@ void CBVHCONTAINER2D::recursiveBuild_MIDDLE_SPLIT( BVH_CONTAINER_NODE_2D *aNodeP
}
bool CBVHCONTAINER2D::IntersectAny( const RAYSEG2D &aSegRay ) const
{
wxASSERT( m_isInitialized == true );
if( m_Tree )
return recursiveIntersectAny( m_Tree, aSegRay );
return false;
}
bool CBVHCONTAINER2D::recursiveIntersectAny( const BVH_CONTAINER_NODE_2D *aNode,
const RAYSEG2D &aSegRay ) const
{
wxASSERT( aNode != NULL );
if( aNode->m_BBox.Inside( aSegRay.m_Start ) ||
aNode->m_BBox.Inside( aSegRay.m_End ) ||
aNode->m_BBox.Intersect( aSegRay ) )
{
if( !aNode->m_LeafList.empty() )
{
wxASSERT( aNode->m_Children[0] == NULL );
wxASSERT( aNode->m_Children[1] == NULL );
// Leaf
for( const COBJECT2D *obj : aNode->m_LeafList )
{
if( obj->IsPointInside( aSegRay.m_Start ) ||
obj->IsPointInside( aSegRay.m_End ) ||
obj->Intersect( aSegRay, nullptr, nullptr ) )
return true;
}
}
else
{
wxASSERT( aNode->m_Children[0] != NULL );
wxASSERT( aNode->m_Children[1] != NULL );
// Node
if( recursiveIntersectAny( aNode->m_Children[0], aSegRay ) )
return true;
if( recursiveIntersectAny( aNode->m_Children[1], aSegRay ) )
return true;
}
}
return false;
}
void CBVHCONTAINER2D::GetListObjectsIntersects( const CBBOX2D &aBBox,
CONST_LIST_OBJECT2D &aOutList ) const
{

View File

@ -76,6 +76,13 @@ public:
virtual void GetListObjectsIntersects( const CBBOX2D & aBBox,
CONST_LIST_OBJECT2D &aOutList ) const = 0;
/**
* @brief IntersectAny - Intersect and check if a segment ray hits a object or is inside it
* @param aSegRay - a segment to intersect with objects
* @return true - if it hits any of the objects or is inside any object
*/
virtual bool IntersectAny( const RAYSEG2D &aSegRay ) const = 0;
private:
std::mutex m_lock;
};
@ -89,6 +96,8 @@ public:
// Imported from CGENERICCONTAINER2D
void GetListObjectsIntersects( const CBBOX2D & aBBox,
CONST_LIST_OBJECT2D &aOutList ) const override;
bool IntersectAny( const RAYSEG2D &aSegRay ) const override;
};
@ -120,12 +129,16 @@ private:
void recursiveGetListObjectsIntersects( const BVH_CONTAINER_NODE_2D *aNode,
const CBBOX2D & aBBox,
CONST_LIST_OBJECT2D &aOutList ) const;
bool recursiveIntersectAny( const BVH_CONTAINER_NODE_2D *aNode,
const RAYSEG2D &aSegRay ) const;
public:
// Imported from CGENERICCONTAINER2D
void GetListObjectsIntersects( const CBBOX2D & aBBox,
CONST_LIST_OBJECT2D &aOutList ) const override;
bool IntersectAny( const RAYSEG2D &aSegRay ) const override;
};
#endif // _CCONTAINER2D_H_

View File

@ -68,9 +68,6 @@ bool CFILLEDCIRCLE2D::Intersect( const RAYSEG2D &aSegRay,
float *aOutT,
SFVEC2F *aNormalOut ) const
{
wxASSERT( aOutT );
wxASSERT( aNormalOut );
// This code used directly from Steve Marschner's CS667 framework
// http://cs665pd.googlecode.com/svn/trunk/photon/sphere.cpp
@ -111,11 +108,13 @@ bool CFILLEDCIRCLE2D::Intersect( const RAYSEG2D &aSegRay,
wxASSERT( (t > 0.0f) && (t <= aSegRay.m_Length) );
// Convert the intersection to a normalized 0.0 .. 1.0
*aOutT = t / aSegRay.m_Length;
if( aOutT )
*aOutT = t / aSegRay.m_Length;
const SFVEC2F hitPoint = aSegRay.at( t );
*aNormalOut = (hitPoint - m_center) / m_radius;
if( aNormalOut )
*aNormalOut = (hitPoint - m_center) / m_radius;
return true;
}

View File

@ -81,9 +81,6 @@ bool CITEMLAYERCSG2D::Intersect( const RAYSEG2D &aSegRay,
float *aOutT,
SFVEC2F *aNormalOut ) const
{
wxASSERT( aOutT );
wxASSERT( aNormalOut );
if( m_objectA->GetObjectType() == OBJECT2D_TYPE::DUMMYBLOCK )
return false;
@ -147,8 +144,12 @@ bool CITEMLAYERCSG2D::Intersect( const RAYSEG2D &aSegRay,
}
}
*aNormalOut = currentNormal;
*aOutT = glm::min( glm::max( glm::length( currentRayPos - aSegRay.m_Start ) / aSegRay.m_Length, 0.0f ), 1.0f );
if( aNormalOut )
*aNormalOut = currentNormal;
if( aOutT )
*aOutT = glm::min( glm::max( glm::length( currentRayPos - aSegRay.m_Start ) / aSegRay.m_Length, 0.0f ), 1.0f );
return true;
}

View File

@ -172,11 +172,14 @@ bool CPOLYGONBLOCK2D::Intersect( const RAYSEG2D &aSegRay,
{
wxASSERT( (tMin >= 0.0f) && (tMin <= 1.0f) );
*aOutT = tMin;
*aNormalOut = glm::normalize(
m_open_segments[hitIndex].m_Normals.m_Start * hitU +
m_open_segments[hitIndex].m_Normals.m_End *
(1.0f - hitU) );
if( aOutT )
*aOutT = tMin;
if( aNormalOut )
*aNormalOut = glm::normalize(
m_open_segments[hitIndex].m_Normals.m_Start * hitU +
m_open_segments[hitIndex].m_Normals.m_End *
(1.0f - hitU) );
return true;
}

View File

@ -136,9 +136,6 @@ bool CPOLYGON4PTS2D::Intersect( const RAYSEG2D &aSegRay,
float *aOutT,
SFVEC2F *aNormalOut ) const
{
wxASSERT( aOutT );
wxASSERT( aNormalOut );
bool hited = false;
unsigned int hitIndex;
float bestHitT;
@ -160,8 +157,11 @@ bool CPOLYGON4PTS2D::Intersect( const RAYSEG2D &aSegRay,
{
wxASSERT( (bestHitT >= 0.0f) && (bestHitT <= 1.0f) );
*aOutT = bestHitT;
*aNormalOut = m_seg_normal[hitIndex];
if( aOutT )
*aOutT = bestHitT;
if( aNormalOut )
*aNormalOut = m_seg_normal[hitIndex];
return true;
}

View File

@ -101,8 +101,11 @@ bool CRING2D::Intersect( const RAYSEG2D &aSegRay,
if( (t > FLT_EPSILON) && (t < aSegRay.m_Length) )
{
SFVEC2F hitPoint = aSegRay.at( t );
*aNormalOut = (hitPoint - m_center) / m_outer_radius;
if( aNormalOut )
{
SFVEC2F hitPoint = aSegRay.at( t );
*aNormalOut = (hitPoint - m_center) / m_outer_radius;
}
}
else
{
@ -118,9 +121,12 @@ bool CRING2D::Intersect( const RAYSEG2D &aSegRay,
{
t = t2_inner;
const SFVEC2F hitPoint = aSegRay.at( t2_inner );
if( aNormalOut )
{
const SFVEC2F hitPoint = aSegRay.at( t2_inner );
*aNormalOut = (m_center - hitPoint) / m_inner_radius;
*aNormalOut = (m_center - hitPoint) / m_inner_radius;
}
}
else
return false;
@ -132,7 +138,8 @@ bool CRING2D::Intersect( const RAYSEG2D &aSegRay,
wxASSERT( (t > 0.0f) && (t <= aSegRay.m_Length) );
// Convert the intersection to a normalized 0.0 .. 1.0
*aOutT = t / aSegRay.m_Length;
if( aOutT )
*aOutT = t / aSegRay.m_Length;
return true;
}

View File

@ -134,9 +134,6 @@ bool CROUNDSEGMENT2D::Intersect( const RAYSEG2D &aSegRay,
float *aOutT,
SFVEC2F *aNormalOut ) const
{
wxASSERT( aOutT );
wxASSERT( aNormalOut );
const bool start_is_inside = IsPointInside( aSegRay.m_Start );
const bool end_is_inside = IsPointInside( aSegRay.m_End );
@ -274,16 +271,22 @@ bool CROUNDSEGMENT2D::Intersect( const RAYSEG2D &aSegRay,
{
if( !start_is_inside )
{
*aOutT = closerHitT;
if( aOutT )
*aOutT = closerHitT;
//wxASSERT( (closerHitT > 0.0f) && (closerHitT <= 1.0f) );
*aNormalOut = closerHitNormal;
if( aNormalOut )
*aNormalOut = closerHitNormal;
}
else
{
wxASSERT( (farHitT >= 0.0f) && (farHitT <= 1.0f) );
*aOutT = farHitT;
*aNormalOut = -farHitNormal; // the normal started inside, so invert it
if( aOutT )
*aOutT = farHitT;
if( aNormalOut )
*aNormalOut = -farHitNormal; // the normal started inside, so invert it
}
}

View File

@ -86,8 +86,6 @@ bool CTRIANGLE2D::Intersect( const RAYSEG2D &aSegRay,
float *aOutT,
SFVEC2F *aNormalOut ) const
{
wxASSERT( aOutT );
wxASSERT( aNormalOut );
return false;
}