From b06db80151d11f3ee0c67f10d466a1e9ed1ee9fd Mon Sep 17 00:00:00 2001 From: Mario Luzeiro Date: Thu, 29 Oct 2020 12:48:45 +0000 Subject: [PATCH] 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. --- 3d-viewer/3d_canvas/board_adapter.h | 18 +-- .../accelerators/ccontainer2d.h | 5 + .../c3d_render_createscene.cpp | 138 ++++++++++++++++-- .../c3d_render_raytracing.cpp | 4 + .../c3d_render_raytracing.h | 1 + .../shapes2D/citemlayercsg2d.cpp | 56 +++---- .../shapes2D/cpolygon2d.cpp | 2 +- 7 files changed, 168 insertions(+), 56 deletions(-) diff --git a/3d-viewer/3d_canvas/board_adapter.h b/3d-viewer/3d_canvas/board_adapter.h index 31226668ae..8bda3bc2cf 100644 --- a/3d-viewer/3d_canvas/board_adapter.h +++ b/3d-viewer/3d_canvas/board_adapter.h @@ -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 { diff --git a/3d-viewer/3d_rendering/3d_render_raytracing/accelerators/ccontainer2d.h b/3d-viewer/3d_rendering/3d_render_raytracing/accelerators/ccontainer2d.h index 54b660afc3..4693fcc654 100644 --- a/3d-viewer/3d_rendering/3d_render_raytracing/accelerators/ccontainer2d.h +++ b/3d-viewer/3d_rendering/3d_render_raytracing/accelerators/ccontainer2d.h @@ -59,6 +59,11 @@ public: } } + const CBBOX2D &GetBBox() const + { + return m_bbox; + } + void Clear(); const LIST_OBJECT2D &GetList() const { return m_objects; } diff --git a/3d-viewer/3d_rendering/3d_render_raytracing/c3d_render_createscene.cpp b/3d-viewer/3d_rendering/3d_render_raytracing/c3d_render_createscene.cpp index 1bebdec12b..2215383cc9 100644 --- a/3d-viewer/3d_rendering/3d_render_raytracing/c3d_render_createscene.cpp +++ b/3d-viewer/3d_rendering/3d_render_raytracing/c3d_render_createscene.cpp @@ -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( 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(*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 *object2d_B = new std::vector(); + 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; diff --git a/3d-viewer/3d_rendering/3d_render_raytracing/c3d_render_raytracing.cpp b/3d-viewer/3d_rendering/3d_render_raytracing/c3d_render_raytracing.cpp index 24912997e3..990562170d 100644 --- a/3d-viewer/3d_rendering/3d_render_raytracing/c3d_render_raytracing.cpp +++ b/3d-viewer/3d_rendering/3d_render_raytracing/c3d_render_raytracing.cpp @@ -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; diff --git a/3d-viewer/3d_rendering/3d_render_raytracing/c3d_render_raytracing.h b/3d-viewer/3d_rendering/3d_render_raytracing/c3d_render_raytracing.h index 40e330b50b..1b7afb616b 100644 --- a/3d-viewer/3d_rendering/3d_render_raytracing/c3d_render_raytracing.h +++ b/3d-viewer/3d_rendering/3d_render_raytracing/c3d_render_raytracing.h @@ -160,6 +160,7 @@ private: CCONTAINER2D m_containerWithObjectsToDelete; CCONTAINER2D *m_outlineBoard2dObjects; + CBVHCONTAINER2D *m_antioutlineBoard2dObjects; CGENERICACCELERATOR *m_accelerator; diff --git a/3d-viewer/3d_rendering/3d_render_raytracing/shapes2D/citemlayercsg2d.cpp b/3d-viewer/3d_rendering/3d_render_raytracing/shapes2D/citemlayercsg2d.cpp index 1f78886b6a..3bbead7b99 100644 --- a/3d-viewer/3d_rendering/3d_render_raytracing/shapes2D/citemlayercsg2d.cpp +++ b/3d-viewer/3d_rendering/3d_render_raytracing/shapes2D/citemlayercsg2d.cpp @@ -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, ¤tRayDist, ¤tNormal ) ) 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, - ¤tNormal ) ) + &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; } diff --git a/3d-viewer/3d_rendering/3d_render_raytracing/shapes2D/cpolygon2d.cpp b/3d-viewer/3d_rendering/3d_render_raytracing/shapes2D/cpolygon2d.cpp index 0e308d5911..fcae0106c0 100644 --- a/3d-viewer/3d_rendering/3d_render_raytracing/shapes2D/cpolygon2d.cpp +++ b/3d-viewer/3d_rendering/3d_render_raytracing/shapes2D/cpolygon2d.cpp @@ -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;