3D Viewer: complete refactor of the 3D viewer.

* Split and rewrite the preview window and canvas.
* Create a new class for handling the board information.
* Adds new render targets: openGL, legacy, and ray tracing.
* Render targets take full advantage of the new 3D plugins system and 3D cache
  for a fast 3D model loading.
* Faster board loading.
* New OpenGL render is faster than the old one.
* New ray tracing render target with a post processing shader.
* Use of new 3D plugins (WRL, X3D, STEP and IGES) and 3D model caching.
* Preview of 3D model while browsing the file name.
* 3D preview of the footprint while adding / align 3D shapes.
* Render of 3D models according to attributes: Normal, Normal+Insert, Virtual.
* Pivot rotation centered in one point over the PCB board.
* Shortcuts keys improved for XYZ orientation..
* Animated camera.
This commit is contained in:
Mrio Luzeiro 2016-07-19 13:35:25 -04:00 committed by Wayne Stambaugh
parent fd42d76e2f
commit d8eab321f7
210 changed files with 29099 additions and 23264 deletions

View File

@ -1,233 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2012 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2012 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file 3d_aux.cpp
*/
#include <fctsys.h>
#include <common.h>
#include <trigo.h>
#include <wxBasePcbFrame.h>
#include <class_board_design_settings.h>
#include <class_zone.h>
#include <class_text_mod.h>
#include <class_module.h>
#include <class_drawsegment.h>
#include <class_pcb_text.h>
#include <3d_viewer.h>
#include <3d_canvas.h>
#include <info3d_visu.h>
#include <trackball.h>
void S3D_MASTER::ObjectCoordsTo3DUnits( std::vector< S3D_VERTEX >& aVertices )
{
/* adjust object scale, rotation and offset position */
for( unsigned ii = 0; ii < aVertices.size(); ii++ )
{
aVertices[ii].x *= m_MatScale.x;
aVertices[ii].y *= m_MatScale.y;
aVertices[ii].z *= m_MatScale.z;
// adjust rotation
if( m_MatRotation.x )
{
double a = aVertices[ii].y;
double b = aVertices[ii].z;
RotatePoint( &a, &b, m_MatRotation.x * 10 );
aVertices[ii].y = (float)a;
aVertices[ii].z = (float)b;
}
if( m_MatRotation.y )
{
double a = aVertices[ii].z;
double b = aVertices[ii].x;
RotatePoint( &a, &b, m_MatRotation.x * 10 );
aVertices[ii].z = (float)a;
aVertices[ii].x = (float)b;
}
if( m_MatRotation.z )
{
double a = aVertices[ii].x;
double b = aVertices[ii].y;
RotatePoint( &a, &b, m_MatRotation.x * 10 );
aVertices[ii].x = (float)a;
aVertices[ii].y = (float)b;
}
/* adjust offset position (offset is given in UNIT 3D (0.1 inch) */
aVertices[ii].x += m_MatPosition.x * SCALE_3D_CONV;
aVertices[ii].y += m_MatPosition.y * SCALE_3D_CONV;
aVertices[ii].z += m_MatPosition.z * SCALE_3D_CONV;
}
}
void TransfertToGLlist( std::vector< S3D_VERTEX >& aVertices, double aBiuTo3DUnits )
{
unsigned ii;
GLfloat ax, ay, az, bx, by, bz, nx, ny, nz, r;
/* ignore faces with less than 3 points */
if( aVertices.size() < 3 )
return;
/* calculate normal direction */
ax = aVertices[1].x - aVertices[0].x;
ay = aVertices[1].y - aVertices[0].y;
az = aVertices[1].z - aVertices[0].z;
bx = aVertices[2].x - aVertices[0].x;
by = aVertices[2].y - aVertices[0].y;
bz = aVertices[2].z - aVertices[0].z;
nx = ay * bz - az * by;
ny = az * bx - ax * bz;
nz = ax * by - ay * bx;
r = sqrt( nx * nx + ny * ny + nz * nz );
if( r >= 0.000001 ) /* avoid division by zero */
{
nx /= r;
ny /= r;
nz /= r;
glNormal3f( nx, ny, nz );
}
/* glBegin/glEnd */
switch( aVertices.size() )
{
case 3:
glBegin( GL_TRIANGLES );
break;
case 4:
glBegin( GL_QUADS );
break;
default:
glBegin( GL_POLYGON );
break;
}
/* draw polygon/triangle/quad */
for( ii = 0; ii < aVertices.size(); ii++ )
{
glVertex3d( aVertices[ii].x * aBiuTo3DUnits,
aVertices[ii].y * aBiuTo3DUnits,
aVertices[ii].z * aBiuTo3DUnits );
}
glEnd();
}
S3DPOINT_VALUE_CTRL::S3DPOINT_VALUE_CTRL( wxWindow* aParent, wxBoxSizer* aBoxSizer )
{
wxString text;
wxFlexGridSizer* gridSizer = new wxFlexGridSizer( 0, 2, 0, 0 );
gridSizer->AddGrowableCol( 1 );
gridSizer->SetFlexibleDirection( wxHORIZONTAL );
gridSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
aBoxSizer->Add( gridSizer, 0, wxEXPAND, 5 );
wxStaticText* msgtitle = new wxStaticText( aParent, wxID_ANY, wxT( "X:" ) );
gridSizer->Add( msgtitle, 0, wxALL , 5 );
m_XValueCtrl = new wxTextCtrl( aParent, wxID_ANY, wxEmptyString,
wxDefaultPosition,wxDefaultSize, 0 );
gridSizer->Add( m_XValueCtrl, 0, wxALL|wxEXPAND, 5 );
msgtitle = new wxStaticText( aParent, wxID_ANY, wxT( "Y:" ), wxDefaultPosition,
wxDefaultSize, 0 );
gridSizer->Add( msgtitle, 0, wxALL, 5 );
m_YValueCtrl = new wxTextCtrl( aParent, wxID_ANY, wxEmptyString,
wxDefaultPosition, wxDefaultSize, 0 );
gridSizer->Add( m_YValueCtrl, 0, wxALL|wxEXPAND, 5 );
msgtitle = new wxStaticText( aParent, wxID_ANY, wxT( "Z:" ), wxDefaultPosition,
wxDefaultSize, 0 );
gridSizer->Add( msgtitle, 0, wxALL, 5 );
m_ZValueCtrl = new wxTextCtrl( aParent, wxID_ANY, wxEmptyString,
wxDefaultPosition, wxDefaultSize, 0 );
gridSizer->Add( m_ZValueCtrl, 0, wxALL|wxEXPAND, 5 );
}
S3DPOINT_VALUE_CTRL::~S3DPOINT_VALUE_CTRL()
{
// Nothing to delete: all items are managed by the parent window.
}
S3DPOINT S3DPOINT_VALUE_CTRL::GetValue()
{
S3DPOINT value;
double dtmp;
m_XValueCtrl->GetValue().ToDouble( &dtmp );
value.x = dtmp;
m_YValueCtrl->GetValue().ToDouble( &dtmp );
value.y = dtmp;
m_ZValueCtrl->GetValue().ToDouble( &dtmp );
value.z = dtmp;
return value;
}
void S3DPOINT_VALUE_CTRL::SetValue( S3DPOINT vertex )
{
wxString text;
text.Printf( wxT( "%f" ), vertex.x );
m_XValueCtrl->Clear();
m_XValueCtrl->AppendText( text );
text.Printf( wxT( "%f" ), vertex.y );
m_YValueCtrl->Clear();
m_YValueCtrl->AppendText( text );
text.Printf( wxT( "%f" ), vertex.z );
m_ZValueCtrl->Clear();
m_ZValueCtrl->AppendText( text );
}
void S3DPOINT_VALUE_CTRL::Enable( bool onoff )
{
m_XValueCtrl->Enable( onoff );
m_YValueCtrl->Enable( onoff );
m_ZValueCtrl->Enable( onoff );
}

View File

@ -224,10 +224,10 @@ SCENEGRAPH* S3D_CACHE::load( const wxString& aModelFile, S3D_CACHE_ENTRY** aCach
if( mi != m_CacheMap.end() )
{
wxFileName fname( full3Dpath );
bool reload = false;
if( fname.FileExists() )
{
if( fname.FileExists() ) // Only check if file exists. If not, it will
{ // use the same model in cache.
bool reload = false;
wxDateTime fmdate = fname.GetModificationTime();
if( fmdate != mi->second->modTime )
@ -242,20 +242,20 @@ SCENEGRAPH* S3D_CACHE::load( const wxString& aModelFile, S3D_CACHE_ENTRY** aCach
reload = true;
}
}
}
if( reload )
{
if( NULL != mi->second->sceneData )
if( reload )
{
S3D::DestroyNode( mi->second->sceneData );
mi->second->sceneData = NULL;
if( NULL != mi->second->sceneData )
{
S3D::DestroyNode( mi->second->sceneData );
mi->second->sceneData = NULL;
}
if( NULL != mi->second->renderData )
S3D::Destroy3DModel( &mi->second->renderData );
mi->second->sceneData = m_Plugins->Load3DModel( full3Dpath, mi->second->pluginInfo );
}
if( NULL != mi->second->renderData )
S3D::Destroy3DModel( &mi->second->renderData );
mi->second->sceneData = m_Plugins->Load3DModel( full3Dpath, mi->second->pluginInfo );
}
if( NULL != aCachePtr )

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@gmail.com>
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 2004 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
@ -39,14 +39,10 @@
struct S3D_INFO
{
SGPOINT scale; ///< scaling factors for the 3D footprint shape
SGPOINT rotation; ///< an X,Y,Z rotation (unit = degrees) for the 3D shape
SGPOINT offset; ///< an offset (unit = inch) for the 3D shape
// note: the models are treated in a peculiar fashion since it is the
// SCALE which is applied first, followed by the ROTATION and finally
// the TRANSLATION/Offset (S-R-T). The usual order of operations is T-R-S.
wxString filename; ///< The 3D shape filename in 3D library
SGPOINT m_Scale; ///< scaling factors for the 3D footprint shape
SGPOINT m_Rotation; ///< an X,Y,Z rotation (unit = degrees) for the 3D shape
SGPOINT m_Offset; ///< an offset (unit = inch) for the 3D shape
wxString m_Filename; ///< The 3D shape filename in 3D library
};
#endif // INFO_3D_H

View File

@ -1,6 +1,7 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
*
* This program is free software; you can redistribute it and/or
@ -27,8 +28,9 @@
#include "project.h"
#include "3d_cache/3d_info.h"
#include "3d_cache/3d_cache.h"
#include "3d_cache/dialogs/panel_prev_model.h"
#include "3d_cache_dialogs.h"
#include <3d_model_viewer/c3d_model_viewer.h>
#include <common_ogl/cogl_att_list.h>
#define ID_FILE_TREE ( wxID_LAST + 1 )
#define ID_SET_DIR ( ID_FILE_TREE + 1 )
@ -60,15 +62,13 @@ DLG_SELECT_3DMODEL::DLG_SELECT_3DMODEL( wxWindow* aParent, S3D_CACHE* aCacheMana
wxBoxSizer* bSizer0 = new wxBoxSizer( wxVERTICAL );
wxBoxSizer* bSizer1;
bSizer1 = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* bSizer1 = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* bSizer2;
bSizer2 = new wxBoxSizer( wxVERTICAL );
wxBoxSizer* bSizer2 = new wxBoxSizer( wxVERTICAL );
// set to NULL to avoid segfaults when m_FileTree is instantiated
// and wxGenericDirCtrl events are posted
m_preview = NULL;
m_modelViewer = NULL;
dirChoices = NULL;
m_FileTree = new wxGenericDirCtrl( this, ID_FILE_TREE, prevModelSelectDir, wxDefaultPosition,
@ -83,14 +83,12 @@ DLG_SELECT_3DMODEL::DLG_SELECT_3DMODEL( wxWindow* aParent, S3D_CACHE* aCacheMana
bSizer2->Add( m_FileTree, 1, wxEXPAND | wxALL, 5 );
bSizer1->Add( bSizer2, 1, wxEXPAND, 5 );
// m_preview must me instantiated after m_FileTree or else it will not
// function as desired due to the constructor depending on the existence
// of m_FileTree to determine the previewer's configuration
wxBoxSizer* previewSizer;
previewSizer = new wxBoxSizer( wxVERTICAL );
m_preview = new PANEL_PREV_3D( this, m_cache );
previewSizer->Add( m_preview, 1, wxEXPAND | wxALL, 5 );
bSizer1->Add( previewSizer, 0, wxEXPAND, 5 );
m_modelViewer = new C3D_MODEL_VIEWER( this,
COGL_ATT_LIST::GetAttributesList( true ),
m_cache );
m_modelViewer->SetMinSize( wxSize( 512, 384 ) );
bSizer1->Add( m_modelViewer, 0, wxCENTER, 5 );
// create the filter list
if( NULL != m_cache )
@ -133,8 +131,7 @@ DLG_SELECT_3DMODEL::DLG_SELECT_3DMODEL( wxWindow* aParent, S3D_CACHE* aCacheMana
// Add the path choice box and config button
wxBoxSizer* hboxDirChoice = new wxBoxSizer( wxHORIZONTAL );
dirChoices = new wxChoice( this, ID_SET_DIR, wxDefaultPosition,
wxSize( 320, 20 ) );
dirChoices = new wxChoice( this, ID_SET_DIR, wxDefaultPosition, wxSize( 320, 20 ) );
dirChoices->SetMinSize( wxSize( 320, 12 ) );
wxStaticText* stDirChoice = new wxStaticText( this, -1, _( "Paths:" ) );
@ -150,6 +147,7 @@ DLG_SELECT_3DMODEL::DLG_SELECT_3DMODEL( wxWindow* aParent, S3D_CACHE* aCacheMana
hSizer1->AddButton( btn_OK );
hSizer1->AddButton( btn_Cancel );
hSizer1->Realize();
bSizer0->Add( bSizer1, 1, wxALL | wxEXPAND, 5 );
bSizer0->Add( hboxDirChoice, 0, wxALL | wxEXPAND, 5 );
bSizer0->Add( hSizer1, 0, wxALL | wxEXPAND, 5 );
@ -159,6 +157,9 @@ DLG_SELECT_3DMODEL::DLG_SELECT_3DMODEL( wxWindow* aParent, S3D_CACHE* aCacheMana
this->SetSizerAndFit( bSizer0 );
this->Layout();
this->Centre( wxBOTH );
m_modelViewer->Refresh();
m_modelViewer->SetFocus();
}
@ -167,26 +168,30 @@ bool DLG_SELECT_3DMODEL::TransferDataFromWindow()
if( NULL == m_model || NULL == m_FileTree )
return true;
m_model->scale.x = 1.0;
m_model->scale.y = 1.0;
m_model->scale.z = 1.0;
m_model->m_Scale.x = 1.0;
m_model->m_Scale.y = 1.0;
m_model->m_Scale.z = 1.0;
m_model->rotation.x = 0.0;
m_model->rotation.y = 0.0;
m_model->rotation.z = 0.0;
m_model->m_Rotation.x = 0.0;
m_model->m_Rotation.y = 0.0;
m_model->m_Rotation.z = 0.0;
m_model->offset = m_model->rotation;
m_model->filename.clear();
m_model->m_Offset = m_model->m_Rotation;
m_model->m_Filename.clear();
wxString fname = m_FileTree->GetFilePath();
wxString name = m_FileTree->GetFilePath();
if( fname.empty() )
if( name.empty() )
return true;
m_previousDir = m_FileTree->GetPath();
m_previousFilterIndex = m_FileTree->GetFilterIndex();
m_preview->GetModelData( m_model );
// file selection mode: retrieve the filename and specify a
// path relative to one of the config paths
wxFileName fname = m_FileTree->GetFilePath();
fname.Normalize();
m_model->m_Filename = m_resolver->ShortenPath( fname.GetFullPath() );
return true;
}
@ -194,8 +199,8 @@ bool DLG_SELECT_3DMODEL::TransferDataFromWindow()
void DLG_SELECT_3DMODEL::OnSelectionChanged( wxTreeEvent& event )
{
if( NULL != m_preview )
m_preview->UpdateModelName( m_FileTree->GetFilePath() );
if( m_modelViewer )
m_modelViewer->Set3DModel( m_FileTree->GetFilePath() );
event.Skip();
return;
@ -204,8 +209,8 @@ void DLG_SELECT_3DMODEL::OnSelectionChanged( wxTreeEvent& event )
void DLG_SELECT_3DMODEL::OnFileActivated( wxTreeEvent& event )
{
if( NULL != m_preview )
m_preview->UpdateModelName( m_FileTree->GetFilePath() );
if( m_modelViewer )
m_modelViewer->Set3DModel( m_FileTree->GetFilePath() );
event.Skip();
SetEscapeId( wxID_OK );
@ -217,10 +222,8 @@ void DLG_SELECT_3DMODEL::OnFileActivated( wxTreeEvent& event )
void DLG_SELECT_3DMODEL::SetRootDir( wxCommandEvent& event )
{
if( !m_FileTree )
return;
m_FileTree->SetPath( dirChoices->GetString( dirChoices->GetSelection() ) );
if( m_FileTree )
m_FileTree->SetPath( dirChoices->GetString( dirChoices->GetSelection() ) );
return;
}

View File

@ -41,7 +41,7 @@
struct S3D_INFO;
class S3D_CACHE;
class S3D_FILENAME_RESOLVER;
class PANEL_PREV_3D;
class C3D_MODEL_VIEWER;
//class wxGenericDirCtrl;
class DLG_SELECT_3DMODEL : public wxDialog
@ -55,7 +55,7 @@ private:
int& m_previousFilterIndex;
wxGenericDirCtrl* m_FileTree;
PANEL_PREV_3D* m_preview;
C3D_MODEL_VIEWER* m_modelViewer;
wxChoice* dirChoices;
void updateDirChoiceList( void );

View File

@ -1,6 +1,7 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
*
* This program is free software; you can redistribute it and/or
@ -21,29 +22,26 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <3d_model_viewer/c3d_model_viewer.h>
#include <3d_rendering/3d_render_ogl_legacy/c_ogl_3dmodel.h>
/**
* @file panel_prev_model.cpp
*/
#include <3d_canvas/eda_3d_canvas.h>
#include <common_ogl/cogl_att_list.h>
#include <cstdlib>
#include <wx/log.h>
#include <wx/sizer.h>
#include <wx/valnum.h>
#include <wx/choice.h>
#include <wx/filename.h>
#include <wx/glcanvas.h>
#include <wx/dirctrl.h>
#include <glm/glm.hpp>
#include <glm/ext.hpp>
#include <wx/tglbtn.h>
#include "project.h"
#include "3d_cache.h"
#include "3d_info.h"
#include "3d_filename_resolver.h"
#include "plugins/3dapi/ifsg_api.h"
#include "panel_prev_model.h"
#include <class_board.h>
// ensure -360 < rotation < 360
/**
* @brief checkRotation - ensure -360 < rotation < 360
* @param rot: in out parameter
*/
static void checkRotation( double& rot )
{
if( rot >= 360.0 )
@ -62,7 +60,7 @@ static void checkRotation( double& rot )
enum {
ID_SCALEX = wxID_LAST + 1,
ID_SCALEX = ID_KICAD_PANEL_PREV_MODEL_START,
ID_SCALEY,
ID_SCALEZ,
ID_ROTX,
@ -78,20 +76,23 @@ enum {
ID_3D_FRONT,
ID_3D_BACK,
ID_3D_TOP,
ID_3D_BOTTOM
ID_3D_BOTTOM,
ID_3D_END = ID_KICAD_PANEL_PREV_MODEL_END
};
wxBEGIN_EVENT_TABLE( PANEL_PREV_3D, wxPanel)
EVT_TEXT_ENTER( ID_SCALEX, PANEL_PREV_3D::updateOrientation )
EVT_TEXT_ENTER( ID_SCALEY, PANEL_PREV_3D::updateOrientation )
EVT_TEXT_ENTER( ID_SCALEZ, PANEL_PREV_3D::updateOrientation )
EVT_TEXT_ENTER( ID_ROTX, PANEL_PREV_3D::updateOrientation )
EVT_TEXT_ENTER( ID_ROTY, PANEL_PREV_3D::updateOrientation )
EVT_TEXT_ENTER( ID_ROTZ, PANEL_PREV_3D::updateOrientation )
EVT_TEXT_ENTER( ID_OFFX, PANEL_PREV_3D::updateOrientation )
EVT_TEXT_ENTER( ID_OFFY, PANEL_PREV_3D::updateOrientation )
EVT_TEXT_ENTER( ID_OFFZ, PANEL_PREV_3D::updateOrientation )
EVT_BUTTON( ID_3D_ISO, PANEL_PREV_3D::View3DISO )
EVT_TEXT( ID_SCALEX, PANEL_PREV_3D::updateOrientation )
EVT_TEXT( ID_SCALEY, PANEL_PREV_3D::updateOrientation )
EVT_TEXT( ID_SCALEZ, PANEL_PREV_3D::updateOrientation )
EVT_TEXT( ID_ROTX, PANEL_PREV_3D::updateOrientation )
EVT_TEXT( ID_ROTY, PANEL_PREV_3D::updateOrientation )
EVT_TEXT( ID_ROTZ, PANEL_PREV_3D::updateOrientation )
EVT_TEXT( ID_OFFX, PANEL_PREV_3D::updateOrientation )
EVT_TEXT( ID_OFFY, PANEL_PREV_3D::updateOrientation )
EVT_TEXT( ID_OFFZ, PANEL_PREV_3D::updateOrientation )
EVT_TOGGLEBUTTON( ID_3D_ISO, PANEL_PREV_3D::View3DISO )
EVT_BUTTON( ID_3D_UPDATE, PANEL_PREV_3D::View3DUpdate )
EVT_BUTTON( ID_3D_LEFT, PANEL_PREV_3D::View3DLeft )
EVT_BUTTON( ID_3D_RIGHT, PANEL_PREV_3D::View3DRight )
@ -99,19 +100,24 @@ wxBEGIN_EVENT_TABLE( PANEL_PREV_3D, wxPanel)
EVT_BUTTON( ID_3D_BACK, PANEL_PREV_3D::View3DBack )
EVT_BUTTON( ID_3D_TOP, PANEL_PREV_3D::View3DTop )
EVT_BUTTON( ID_3D_BOTTOM, PANEL_PREV_3D::View3DBottom )
EVT_CLOSE( PANEL_PREV_3D::OnCloseWindow )
wxEND_EVENT_TABLE()
PANEL_PREV_3D::PANEL_PREV_3D( wxWindow* aParent, S3D_CACHE* aCacheManager ) :
wxPanel( aParent, -1 ), m_ModelManager( aCacheManager )
PANEL_PREV_3D::PANEL_PREV_3D( wxWindow* aParent,
S3D_CACHE* aCacheManager,
MODULE* aModuleCopy,
std::vector<S3D_INFO> *aParentInfoList ) :
wxPanel( aParent, -1 )
{
if( NULL != m_ModelManager )
m_resolver = m_ModelManager->GetResolver();
if( NULL != aCacheManager )
m_resolver = aCacheManager->GetResolver();
else
m_resolver = NULL;
canvas = NULL;
model = NULL;
m_currentSelectedIdx = -1;
m_parentInfoList = aParentInfoList;
m_previewPane = NULL;
xscale = NULL;
yscale = NULL;
zscale = NULL;
@ -121,54 +127,55 @@ PANEL_PREV_3D::PANEL_PREV_3D( wxWindow* aParent, S3D_CACHE* aCacheManager ) :
xoff = NULL;
yoff = NULL;
zoff = NULL;
currentModelFile.clear();
wxBoxSizer* mainBox = new wxBoxSizer( wxVERTICAL );
wxStaticBoxSizer* vbox = new wxStaticBoxSizer( wxVERTICAL, this, _( "3D Preview" ) );
m_FileTree = NULL;
if( NULL != aParent )
m_FileTree = (wxGenericDirCtrl*)
aParent->FindWindowByLabel( wxT( "3D_MODEL_SELECTOR" ), aParent );
wxFloatingPointValidator< float > valScale( 4 );
valScale.SetRange( 0.0001, 9999.0 );
valScale.SetRange( 0.0001f, 9999.0f );
wxFloatingPointValidator< float > valRotate( 2 );
valRotate.SetRange( -180.0, 180.0 );
valRotate.SetRange( -180.0f, 180.0f );
wxFloatingPointValidator< float > valOffset( 4 );
valOffset.SetRange( -9999.0, 9999.0 );
valOffset.SetRange( -9999.0f, 9999.0f );
wxStaticBoxSizer* vbScale = new wxStaticBoxSizer( wxVERTICAL, this, _( "Scale" ) );
wxStaticBoxSizer* vbRotate = new wxStaticBoxSizer( wxVERTICAL, this, _( "Rotation" ) );
wxStaticBoxSizer* vbOffset = new wxStaticBoxSizer( wxVERTICAL, this, _( "Offset (inches)" ) );
wxStaticBoxSizer* vbScale = new wxStaticBoxSizer( wxVERTICAL, this, _( "Scale" ) );
wxStaticBoxSizer* vbRotate = new wxStaticBoxSizer( wxVERTICAL, this, _( "Rotation (degrees)" ) );
wxStaticBox* modScale = vbScale->GetStaticBox();
const wxString offsetString = _( "Offset " ) + "(" + GetUnitsLabel( g_UserUnit ) + ")";
wxStaticBoxSizer* vbOffset = new wxStaticBoxSizer( wxVERTICAL, this, offsetString );
wxStaticBox* modScale = vbScale->GetStaticBox();
wxStaticBox* modRotate = vbRotate->GetStaticBox();
wxStaticBox* modOffset = vbOffset->GetStaticBox();
wxBoxSizer* hbS1 = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* hbS2 = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* hbS3 = new wxBoxSizer( wxHORIZONTAL );
wxStaticText* txtS1 = new wxStaticText( modScale, -1, wxT( "X:" ) );
wxStaticText* txtS2 = new wxStaticText( modScale, -1, wxT( "Y:" ) );
wxStaticText* txtS3 = new wxStaticText( modScale, -1, wxT( "Z:" ) );
xscale = new wxTextCtrl( modScale, ID_SCALEX, "1.0", wxDefaultPosition, wxDefaultSize,
wxTE_PROCESS_ENTER, valScale );
yscale = new wxTextCtrl( modScale, ID_SCALEY, "1.0", wxDefaultPosition, wxDefaultSize,
wxTE_PROCESS_ENTER, valScale );
zscale = new wxTextCtrl( modScale, ID_SCALEZ, "1.0", wxDefaultPosition, wxDefaultSize,
wxTE_PROCESS_ENTER, valScale );
xscale->SetMaxLength( 9 );
yscale->SetMaxLength( 9 );
zscale->SetMaxLength( 9 );
hbS1->Add( txtS1, 0, wxALL, 2 );
hbS1->Add( xscale, 0, wxALL, 2 );
hbS2->Add( txtS2, 0, wxALL, 2 );
hbS2->Add( yscale, 0, wxALL, 2 );
hbS3->Add( txtS3, 0, wxALL, 2 );
hbS3->Add( zscale, 0, wxALL, 2 );
vbScale->Add( hbS1, 0, wxEXPAND | wxALL, 0 );
vbScale->Add( hbS2, 0, wxEXPAND | wxALL, 0 );
vbScale->Add( hbS3, 0, wxEXPAND | wxALL, 0 );
hbS1->Add( txtS1, 0, wxALIGN_CENTER, 2 );
hbS1->Add( xscale, 0, wxEXPAND | wxLEFT | wxRIGHT, 2 );
hbS2->Add( txtS2, 0, wxALIGN_CENTER, 2 );
hbS2->Add( yscale, 0, wxEXPAND | wxLEFT | wxRIGHT, 2 );
hbS3->Add( txtS3, 0, wxALIGN_CENTER, 2 );
hbS3->Add( zscale, 0, wxEXPAND | wxLEFT | wxRIGHT, 2 );
vbScale->Add( hbS1, 1, wxEXPAND | wxLEFT | wxRIGHT, 6 );
vbScale->Add( hbS2, 1, wxEXPAND | wxLEFT | wxRIGHT, 6 );
vbScale->Add( hbS3, 1, wxEXPAND | wxLEFT | wxRIGHT, 6 );
wxBoxSizer* hbR1 = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* hbR2 = new wxBoxSizer( wxHORIZONTAL );
@ -176,24 +183,26 @@ PANEL_PREV_3D::PANEL_PREV_3D( wxWindow* aParent, S3D_CACHE* aCacheManager ) :
wxStaticText* txtR1 = new wxStaticText( modRotate, -1, wxT( "X:" ) );
wxStaticText* txtR2 = new wxStaticText( modRotate, -1, wxT( "Y:" ) );
wxStaticText* txtR3 = new wxStaticText( modRotate, -1, wxT( "Z:" ) );
xrot = new wxTextCtrl( modRotate, ID_ROTX, "0.0", wxDefaultPosition, wxDefaultSize,
wxTE_PROCESS_ENTER, valRotate );
wxTE_PROCESS_ENTER, valRotate );
yrot = new wxTextCtrl( modRotate, ID_ROTY, "0.0", wxDefaultPosition, wxDefaultSize,
wxTE_PROCESS_ENTER, valRotate );
wxTE_PROCESS_ENTER, valRotate );
zrot = new wxTextCtrl( modRotate, ID_ROTZ, "0.0", wxDefaultPosition, wxDefaultSize,
wxTE_PROCESS_ENTER, valRotate );
wxTE_PROCESS_ENTER, valRotate );
xrot->SetMaxLength( 9 );
yrot->SetMaxLength( 9 );
zrot->SetMaxLength( 9 );
hbR1->Add( txtR1, 0, wxALL, 2 );
hbR1->Add( xrot, 0, wxALL, 2 );
hbR2->Add( txtR2, 0, wxALL, 2 );
hbR2->Add( yrot, 0, wxALL, 2 );
hbR3->Add( txtR3, 0, wxALL, 2 );
hbR3->Add( zrot, 0, wxALL, 2 );
vbRotate->Add( hbR1, 0, wxEXPAND | wxALL, 0 );
vbRotate->Add( hbR2, 0, wxEXPAND | wxALL, 0 );
vbRotate->Add( hbR3, 0, wxEXPAND | wxALL, 0 );
hbR1->Add( txtR1, 1, wxALIGN_CENTER, 2 );
hbR1->Add( xrot, 0, wxEXPAND | wxLEFT | wxRIGHT, 2 );
hbR2->Add( txtR2, 1, wxALIGN_CENTER, 2 );
hbR2->Add( yrot, 0, wxEXPAND | wxLEFT | wxRIGHT, 2 );
hbR3->Add( txtR3, 1, wxALIGN_CENTER, 2 );
hbR3->Add( zrot, 0, wxEXPAND | wxLEFT | wxRIGHT, 2 );
vbRotate->Add( hbR1, 1, wxEXPAND | wxLEFT | wxRIGHT, 6 );
vbRotate->Add( hbR2, 1, wxEXPAND | wxLEFT | wxRIGHT, 6 );
vbRotate->Add( hbR3, 1, wxEXPAND | wxLEFT | wxRIGHT, 6 );
wxBoxSizer* hbO1 = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* hbO2 = new wxBoxSizer( wxHORIZONTAL );
@ -201,24 +210,25 @@ PANEL_PREV_3D::PANEL_PREV_3D( wxWindow* aParent, S3D_CACHE* aCacheManager ) :
wxStaticText* txtO1 = new wxStaticText( modOffset, -1, wxT( "X:" ) );
wxStaticText* txtO2 = new wxStaticText( modOffset, -1, wxT( "Y:" ) );
wxStaticText* txtO3 = new wxStaticText( modOffset, -1, wxT( "Z:" ) );
xoff = new wxTextCtrl( modOffset, ID_OFFX, "0.0", wxDefaultPosition, wxDefaultSize,
wxTE_PROCESS_ENTER, valOffset );
wxTE_PROCESS_ENTER, valOffset );
yoff = new wxTextCtrl( modOffset, ID_OFFY, "0.0", wxDefaultPosition, wxDefaultSize,
wxTE_PROCESS_ENTER, valOffset );
wxTE_PROCESS_ENTER, valOffset );
zoff = new wxTextCtrl( modOffset, ID_OFFZ, "0.0", wxDefaultPosition, wxDefaultSize,
wxTE_PROCESS_ENTER, valOffset );
wxTE_PROCESS_ENTER, valOffset );
xoff->SetMaxLength( 10 );
yoff->SetMaxLength( 10 );
zoff->SetMaxLength( 10 );
hbO1->Add( txtO1, 0, wxALL, 2 );
hbO1->Add( xoff, 0, wxALL, 2 );
hbO2->Add( txtO2, 0, wxALL, 2 );
hbO2->Add( yoff, 0, wxALL, 2 );
hbO3->Add( txtO3, 0, wxALL, 2 );
hbO3->Add( zoff, 0, wxALL, 2 );
vbOffset->Add( hbO1, 0, wxEXPAND | wxALL, 0 );
vbOffset->Add( hbO2, 0, wxEXPAND | wxALL, 0 );
vbOffset->Add( hbO3, 0, wxEXPAND | wxALL, 0 );
hbO1->Add( txtO1, 0, wxALIGN_CENTER, 2 );
hbO1->Add( xoff, 0, wxEXPAND | wxLEFT | wxRIGHT, 2 );
hbO2->Add( txtO2, 0, wxALIGN_CENTER, 2 );
hbO2->Add( yoff, 0, wxEXPAND | wxLEFT | wxRIGHT, 2 );
hbO3->Add( txtO3, 0, wxALIGN_CENTER, 2 );
hbO3->Add( zoff, 0, wxEXPAND | wxLEFT | wxRIGHT, 2 );
vbOffset->Add( hbO1, 1, wxEXPAND | wxLEFT | wxRIGHT, 6 );
vbOffset->Add( hbO2, 1, wxEXPAND | wxLEFT | wxRIGHT, 6 );
vbOffset->Add( hbO3, 1, wxEXPAND | wxLEFT | wxRIGHT, 6 );
// hbox holding orientation data and preview
wxBoxSizer* hbox = new wxBoxSizer( wxHORIZONTAL );
@ -227,215 +237,290 @@ PANEL_PREV_3D::PANEL_PREV_3D( wxWindow* aParent, S3D_CACHE* aCacheManager ) :
// vbox holding the preview and view buttons
wxBoxSizer* vboxPrev = new wxBoxSizer( wxVERTICAL );
vboxOrient->Add( vbScale, 0, wxEXPAND | wxALL, 1 );
vboxOrient->Add( vbRotate, 0, wxEXPAND | wxALL, 1 );
vboxOrient->Add( vbOffset, 0, wxEXPAND | wxALL, 1 );
vboxOrient->Add( vbScale, 1, wxEXPAND | wxLEFT | wxRIGHT, 2 );
vboxOrient->Add( vbRotate, 1, wxEXPAND | wxLEFT | wxRIGHT, 2 );
vboxOrient->Add( vbOffset, 1, wxEXPAND | wxLEFT | wxRIGHT, 2 );
// add preview items
preview = new wxPanel( this, -1 );
wxPanel*preview = new wxPanel( this, -1 );
preview->SetMinSize( wxSize( 400, 250 ) );
preview->SetBackgroundColour( wxColor( 0, 0, 0 ));
vboxPrev->Add( preview, 1, wxEXPAND | wxLEFT | wxRIGHT, 5 );
vboxPrev->Add( preview, 1, wxEXPAND | wxALL, 5 );
// buttons:
wxButton* vFront = new wxButton( this, ID_3D_FRONT, wxT( "F" ) );
wxButton* vBack = new wxButton( this, ID_3D_BACK, wxT( "B" ) );
wxButton* vLeft = new wxButton( this, ID_3D_LEFT, wxT( "L" ) );
wxButton* vRight = new wxButton( this, ID_3D_RIGHT, wxT( "R" ) );
wxButton* vTop = new wxButton( this, ID_3D_TOP, wxT( "T" ) );
wxButton* vBottom = new wxButton( this, ID_3D_BOTTOM, wxT( "B" ) );
wxButton* vISO = new wxButton( this, ID_3D_ISO, wxT( "I" ) );
wxButton* vUpdate = new wxButton( this, ID_3D_UPDATE, wxT( "U" ) );
wxBoxSizer* hbBT = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* hbBB = new wxBoxSizer( wxHORIZONTAL );
hbBT->Add( vISO, 0, wxCENTER | wxALL, 3 );
hbBT->Add( vLeft, 0, wxCENTER | wxALL, 3 );
hbBT->Add( vFront, 0, wxCENTER | wxALL, 3 );
hbBT->Add( vTop, 0, wxCENTER | wxALL, 3 );
hbBT->AddSpacer( 17 );
hbBB->Add( vUpdate, 0, wxCENTER | wxALL, 3 );
hbBB->Add( vRight, 0, wxCENTER | wxALL, 3 );
hbBB->Add( vBack, 0, wxCENTER | wxALL, 3 );
hbBB->Add( vBottom, 0, wxCENTER | wxALL, 3 );
hbBB->AddSpacer( 17 );
wxButton* vFront = new wxButton( this, ID_3D_FRONT );
vFront->SetBitmap( KiBitmap( axis3d_front_xpm ) );
wxButton* vBack = new wxButton( this, ID_3D_BACK );
vBack->SetBitmap( KiBitmap( axis3d_back_xpm ) );
wxButton* vLeft = new wxButton( this, ID_3D_LEFT );
vLeft->SetBitmap( KiBitmap( axis3d_left_xpm ) );
wxButton* vRight = new wxButton( this, ID_3D_RIGHT );
vRight->SetBitmap( KiBitmap( axis3d_right_xpm ) );
wxButton* vTop = new wxButton( this, ID_3D_TOP );
vTop->SetBitmap( KiBitmap( axis3d_top_xpm ) );
wxButton* vBottom = new wxButton( this, ID_3D_BOTTOM );
vBottom->SetBitmap( KiBitmap( axis3d_bottom_xpm ) );
wxToggleButton* vISO = new wxToggleButton( this, ID_3D_ISO, wxT("") );
vISO->SetBitmap( KiBitmap( ortho_xpm ) );
vISO->SetToolTip( _("Change to isometric perspective") );
wxButton* vUpdate = new wxButton( this, ID_3D_UPDATE );
vUpdate->SetBitmap( KiBitmap( reload_xpm ) );
vUpdate->SetToolTip( _("Reload board and 3D models") );
wxGridSizer* gridSizer = new wxGridSizer( 2, 4, 0, 0 );
gridSizer->Add( vISO, 0, wxEXPAND, 3 );
gridSizer->Add( vLeft, 0, wxEXPAND, 3 );
gridSizer->Add( vFront, 0, wxEXPAND, 3 );
gridSizer->Add( vTop, 0, wxEXPAND, 3 );
gridSizer->Add( vUpdate, 0, wxEXPAND, 3 );
gridSizer->Add( vRight, 0, wxEXPAND, 3 );
gridSizer->Add( vBack, 0, wxEXPAND, 3 );
gridSizer->Add( vBottom, 0, wxEXPAND, 3 );
vboxPrev->AddSpacer( 7 );
vboxPrev->Add( hbBT, 0 );
vboxPrev->Add( hbBB, 0 );
vboxPrev->Add( gridSizer, 0, wxCENTER, 0 );
// XXX - Suppress the buttons until the Renderer code is ready.
// vboxPrev->Hide( preview, true );
vboxPrev->Hide( hbBT, true );
vboxPrev->Hide( hbBB, true );
hbox->Add( vboxOrient, 0, wxEXPAND | wxALL, 0 );
hbox->Add( vboxOrient, 0, 0, 2 );
hbox->Add( vboxPrev, 1, wxEXPAND | wxALL, 12 );
vbox->Add( hbox, 1, wxEXPAND );
vbox->Add( hbox, 1, wxEXPAND | wxALL, 0 );
mainBox->Add( vbox, 1, wxEXPAND | wxALL, 5 );
if( NULL != m_FileTree )
{
// NOTE: if/when the File Selector preview is implemented
// we may need to hide the orientation boxes to ensure the
// users have sufficient display area for the browser.
// hbox->Hide( vboxOrient, true );
// XXX -
// NOTE: for now we always suppress the preview and model orientation
// panels while in the file selector
//mainBox->Hide( vbox, true );
hbox->Hide( vboxOrient, true );
vboxPrev->Hide( hbBT, true );
vboxPrev->Hide( hbBB, true );
}
SetSizerAndFit( mainBox );
return;
// Create a dummy board
m_dummyBoard = new BOARD();
m_dummyBoard->Add( (MODULE*)aModuleCopy );
m_copyModule = aModuleCopy;
// Set 3d viewer configuration for preview
m_settings3Dviewer = new CINFO3D_VISU();
// Create the 3D canvas
m_previewPane = new EDA_3D_CANVAS( preview,
COGL_ATT_LIST::GetAttributesList( true ),
m_dummyBoard,
*m_settings3Dviewer,
aCacheManager );
wxSizer* ws = new wxBoxSizer( wxHORIZONTAL );
ws->Add( m_previewPane, 1, wxEXPAND );
preview->SetSizer( ws );
preview->Layout();
ws->FitInside( preview );
m_previewPane->SetFocus(); // Need to catch mouse and keyboard events
}
PANEL_PREV_3D::~PANEL_PREV_3D()
{
if( NULL != canvas )
{
canvas->Clear3DModel();
canvas->Refresh();
canvas->Update();
}
delete m_settings3Dviewer;
m_settings3Dviewer = NULL;
model = NULL;
delete m_dummyBoard;
m_dummyBoard = NULL;
return;
delete m_previewPane;
m_previewPane = NULL;
}
void PANEL_PREV_3D::OnCloseWindow( wxCloseEvent &event )
{
if( m_previewPane )
m_previewPane->Close();
event.Skip();
}
void PANEL_PREV_3D::View3DISO( wxCommandEvent& event )
{
// XXX - TO BE IMPLEMENTED
// std::cout << "Switch to Isometric View\n";
return;
if( m_settings3Dviewer )
{
m_settings3Dviewer->CameraGet().ToggleProjection();
m_previewPane->Refresh();
m_previewPane->SetFocus();
}
}
void PANEL_PREV_3D::View3DUpdate( wxCommandEvent& event )
{
// XXX - TO BE IMPLEMENTED
// std::cout << "Update 3D View\n";
// update the model filename if appropriate
if( NULL != m_FileTree )
if( m_previewPane )
{
wxString modelName = m_FileTree->GetFilePath();
UpdateModelName( modelName );
m_previewPane->ReloadRequest();
m_previewPane->Refresh();
m_previewPane->SetFocus();
}
return;
}
void PANEL_PREV_3D::View3DLeft( wxCommandEvent& event )
{
// XXX - TO BE IMPLEMENTED
// std::cout << "Switch to Left View\n";
return;
if( m_previewPane )
{
m_previewPane->SetView3D( 'X' );
m_previewPane->SetFocus();
}
}
void PANEL_PREV_3D::View3DRight( wxCommandEvent& event )
{
// XXX - TO BE IMPLEMENTED
// std::cout << "Switch to Right View\n";
return;
if( m_previewPane )
{
m_previewPane->SetView3D( 'x' );
m_previewPane->SetFocus();
}
}
void PANEL_PREV_3D::View3DFront( wxCommandEvent& event )
{
// XXX - TO BE IMPLEMENTED
// std::cout << "Switch to Front View\n";
return;
if( m_previewPane )
{
m_previewPane->SetView3D( 'Y' );
m_previewPane->SetFocus();
}
}
void PANEL_PREV_3D::View3DBack( wxCommandEvent& event )
{
// XXX - TO BE IMPLEMENTED
// std::cout << "Switch to Back View\n";
return;
if( m_previewPane )
{
m_previewPane->SetView3D( 'y' );
m_previewPane->SetFocus();
}
}
void PANEL_PREV_3D::View3DTop( wxCommandEvent& event )
{
// XXX - TO BE IMPLEMENTED
// std::cout << "Switch to Top View\n";
return;
if( m_previewPane )
{
m_previewPane->SetView3D( 'z' );
m_previewPane->SetFocus();
}
}
void PANEL_PREV_3D::View3DBottom( wxCommandEvent& event )
{
// XXX - TO BE IMPLEMENTED
// std::cout << "Switch to Bottom View\n";
return;
if( m_previewPane )
{
m_previewPane->SetView3D( 'Z' );
m_previewPane->SetFocus();
}
}
void PANEL_PREV_3D::GetModelData( S3D_INFO* aModel )
void PANEL_PREV_3D::SetModelDataIdx( int idx, bool aReloadPreviewModule )
{
if( NULL == aModel )
return;
wxASSERT( m_parentInfoList != NULL );
// XXX - due to cross-platform differences in wxWidgets, extracting
// scale/rotation/offset only works as expected when the preview
// panel is not embedded in a file selector dialog. This conditional
// execution should be removed once the cross-platform issues are
// fixed.
if( NULL == m_FileTree )
if( m_parentInfoList && (idx >= 0) )
{
SGPOINT scale;
SGPOINT rotation;
SGPOINT offset;
wxASSERT( (unsigned int)idx < (*m_parentInfoList).size() );
getOrientationVars( scale, rotation, offset );
if( (unsigned int)idx < (*m_parentInfoList).size() )
{
m_currentSelectedIdx = -1; // In case that we receive events on the
// next updates, it will set first an
// invalid selection
aModel->scale = scale;
aModel->offset = offset;
aModel->rotation = rotation;
const S3D_INFO *aModel = (const S3D_INFO *)&((*m_parentInfoList)[idx]);
xscale->SetValue( wxString::FromDouble( aModel->m_Scale.x ) );
yscale->SetValue( wxString::FromDouble( aModel->m_Scale.y ) );
zscale->SetValue( wxString::FromDouble( aModel->m_Scale.z ) );
xrot->SetValue( wxString::FromDouble( aModel->m_Rotation.x ) );
yrot->SetValue( wxString::FromDouble( aModel->m_Rotation.y ) );
zrot->SetValue( wxString::FromDouble( aModel->m_Rotation.z ) );
switch( g_UserUnit )
{
case MILLIMETRES:
xoff->SetValue( wxString::FromDouble( aModel->m_Offset.x * 25.4 ) );
yoff->SetValue( wxString::FromDouble( aModel->m_Offset.y * 25.4 ) );
zoff->SetValue( wxString::FromDouble( aModel->m_Offset.z * 25.4 ) );
break;
case INCHES:
xoff->SetValue( wxString::FromDouble( aModel->m_Offset.x ) );
yoff->SetValue( wxString::FromDouble( aModel->m_Offset.y ) );
zoff->SetValue( wxString::FromDouble( aModel->m_Offset.z ) );
break;
case DEGREES:
case UNSCALED_UNITS:
default:
wxASSERT(0);
}
UpdateModelName( aModel->m_Filename );
if( aReloadPreviewModule && m_previewPane )
{
updateListOnModelCopy();
m_previewPane->ReloadRequest();
m_previewPane->Request_refresh();
}
m_currentSelectedIdx = idx;
}
}
// return if we are not in file selection mode
if( NULL == m_FileTree )
return;
// file selection mode: retrieve the filename and specify a
// path relative to one of the config paths
wxFileName fname = m_FileTree->GetFilePath();
fname.Normalize();
aModel->filename = m_resolver->ShortenPath( fname.GetFullPath() );
if( m_previewPane )
m_previewPane->SetFocus();
return;
}
void PANEL_PREV_3D::SetModelData( S3D_INFO const* aModel )
void PANEL_PREV_3D::ResetModelData( bool aReloadPreviewModule )
{
xscale->SetValue( wxString::FromDouble( aModel->scale.x ) );
yscale->SetValue( wxString::FromDouble( aModel->scale.y ) );
zscale->SetValue( wxString::FromDouble( aModel->scale.z ) );
m_currentSelectedIdx = -1;
xrot->SetValue( wxString::FromDouble( aModel->rotation.x ) );
yrot->SetValue( wxString::FromDouble( aModel->rotation.y ) );
zrot->SetValue( wxString::FromDouble( aModel->rotation.z ) );
xscale->SetValue( wxString::FromDouble( 1.0 ) );
yscale->SetValue( wxString::FromDouble( 1.0 ) );
zscale->SetValue( wxString::FromDouble( 1.0 ) );
xoff->SetValue( wxString::FromDouble( aModel->offset.x ) );
yoff->SetValue( wxString::FromDouble( aModel->offset.y ) );
zoff->SetValue( wxString::FromDouble( aModel->offset.z ) );
xrot->SetValue( wxString::FromDouble( 0.0 ) );
yrot->SetValue( wxString::FromDouble( 0.0 ) );
zrot->SetValue( wxString::FromDouble( 0.0 ) );
UpdateModelName( aModel->filename );
xoff->SetValue( wxString::FromDouble( 0.0 ) );
yoff->SetValue( wxString::FromDouble( 0.0 ) );
zoff->SetValue( wxString::FromDouble( 0.0 ) );
return;
// This will update the model on the preview board with the current list of 3d shapes
if( aReloadPreviewModule )
{
updateListOnModelCopy();
if( m_previewPane )
{
m_previewPane->ReloadRequest();
m_previewPane->Request_refresh();
}
}
if( m_previewPane )
m_previewPane->SetFocus();
}
@ -443,102 +528,48 @@ void PANEL_PREV_3D::UpdateModelName( wxString const& aModelName )
{
bool newModel = false;
modelInfo.filename = aModelName;
m_modelInfo.m_Filename = aModelName;
// if the model name is a directory simply clear the current model
if( aModelName.empty() || wxFileName::DirExists( aModelName ) )
{
currentModelFile.clear();
modelInfo.filename.clear();
m_modelInfo.m_Filename.clear();
}
else
{
wxString newModelFile;
newModelFile = m_resolver->ResolvePath( aModelName );
if( m_resolver )
newModelFile = m_resolver->ResolvePath( aModelName );
if( !newModelFile.empty() && newModelFile.Cmp( currentModelFile ) )
newModel = true;
currentModelFile = newModelFile;
modelInfo.filename = currentModelFile;
}
if( currentModelFile.empty() || newModel )
{
if( NULL != canvas )
{
canvas->Clear3DModel();
canvas->Refresh();
canvas->Update();
}
updateListOnModelCopy();
model = NULL;
if( m_previewPane )
{
m_previewPane->ReloadRequest();
m_previewPane->Refresh();
}
if( currentModelFile.empty() )
return;
}
if( NULL != m_ModelManager )
model = m_ModelManager->GetModel( modelInfo.filename );
else
model = NULL;
if( NULL == model )
{
if( NULL != canvas )
{
canvas->Refresh();
canvas->Update();
}
return;
if( m_previewPane )
m_previewPane->Refresh();
}
if( NULL == canvas )
{
canvas = new C3D_MODEL_VIEWER( preview,
COGL_ATT_LIST::GetAttributesList( true ) );
wxSizer* ws = new wxBoxSizer( wxHORIZONTAL );
canvas->Set3DModel( *model );
ws->Add( canvas, 1, wxEXPAND );
preview->SetSizer( ws );
preview->Layout();
ws->FitInside( preview );
// Fixes bug in Windows (XP and possibly others) where the canvas requires the focus
// in order to receive mouse events. Otherwise, the user has to click somewhere on
// the canvas before it will respond to mouse wheel events.
canvas->SetFocus();
return;
}
canvas->Set3DModel( *model );
canvas->Refresh();
canvas->Update();
canvas->SetFocus();
return;
}
void PANEL_PREV_3D::UpdateWindowUI( long flags )
{
/*
XXX -
NOTE: until we figure out how to ensure that a Paint Event is
generated for the File Selector's UI, we cannot display any
preview within the file browser.
if( wxUPDATE_UI_RECURSE == flags && m_FileDlg && m_ModelManager )
{
// check for a change in the current model file
S3D_INFO info;
modelInfo = info;
UpdateModelName( m_FileDlg->GetCurrentlySelectedFilename() );
}
// */
wxPanel::UpdateWindowUI( flags );
if( m_previewPane )
m_previewPane->SetFocus();
return;
}
@ -546,33 +577,41 @@ void PANEL_PREV_3D::UpdateWindowUI( long flags )
void PANEL_PREV_3D::updateOrientation( wxCommandEvent &event )
{
// note: process even if the canvas is NULL since the user may
// edit the filename to provide a valid file
wxTextCtrl *textCtrl = (wxTextCtrl *)event.GetEventObject();
if( textCtrl == NULL )
return;
if( textCtrl->GetLineLength(0) == 0 ) // This will skip the got and event with empty field
return;
if( textCtrl->GetLineLength(0) == 1 )
if( (textCtrl->GetLineText(0).compare( "." ) == 0) ||
(textCtrl->GetLineText(0).compare( "," ) == 0) )
return;
SGPOINT scale;
SGPOINT rotation;
SGPOINT offset;
getOrientationVars( scale, rotation, offset );
modelInfo.scale = scale;
modelInfo.offset = offset;
modelInfo.rotation = rotation;
m_modelInfo.m_Scale = scale;
m_modelInfo.m_Offset = offset;
m_modelInfo.m_Rotation = rotation;
if( NULL == canvas )
return;
canvas->Clear3DModel();
if( NULL != m_ModelManager )
model = m_ModelManager->GetModel( modelInfo.filename );
else
model = NULL;
if( model )
if( m_currentSelectedIdx >= 0 )
{
canvas->Set3DModel( *model );
canvas->Refresh();
canvas->Update();
// This will update the parent list with the new data
(*m_parentInfoList)[m_currentSelectedIdx] = m_modelInfo;
// It will update the copy model in the preview board
updateListOnModelCopy();
// Since the OpenGL render does not need to be reloaded to update the
// shapes position, we just request to redraw again the canvas
if( m_previewPane )
m_previewPane->Refresh();
}
event.Skip();
@ -580,7 +619,7 @@ void PANEL_PREV_3D::updateOrientation( wxCommandEvent &event )
}
void PANEL_PREV_3D::getOrientationVars( SGPOINT& scale, SGPOINT& rotation, SGPOINT& offset )
void PANEL_PREV_3D::getOrientationVars( SGPOINT& aScale, SGPOINT& aRotation, SGPOINT& aOffset )
{
if( NULL == xscale || NULL == yscale || NULL == zscale
|| NULL == xrot || NULL == yrot || NULL == zrot
@ -589,30 +628,74 @@ void PANEL_PREV_3D::getOrientationVars( SGPOINT& scale, SGPOINT& rotation, SGPOI
return;
}
xscale->GetValue().ToDouble( &scale.x );
yscale->GetValue().ToDouble( &scale.y );
zscale->GetValue().ToDouble( &scale.z );
xscale->GetValue().ToDouble( &aScale.x );
yscale->GetValue().ToDouble( &aScale.y );
zscale->GetValue().ToDouble( &aScale.z );
if( 0.0001 > scale.x || 0.0001 > scale.y || 0.0001 > scale.z )
xrot->GetValue().ToDouble( &aRotation.x );
yrot->GetValue().ToDouble( &aRotation.y );
zrot->GetValue().ToDouble( &aRotation.z );
checkRotation( aRotation.x );
checkRotation( aRotation.y );
checkRotation( aRotation.z );
xoff->GetValue().ToDouble( &aOffset.x );
yoff->GetValue().ToDouble( &aOffset.y );
zoff->GetValue().ToDouble( &aOffset.z );
switch( g_UserUnit )
{
wxString errmsg = _("[INFO] invalid scale values; setting all to 1.0");
wxLogMessage( "%s", errmsg.ToUTF8() );
case MILLIMETRES:
// Convert to Inches. Offset is stored in inches.
aOffset.x = aOffset.x / 25.4;
aOffset.y = aOffset.y / 25.4;
aOffset.z = aOffset.z / 25.4;
break;
scale.x = 1.0;
scale.y = 1.0;
scale.z = 1.0;
case INCHES:
// It is already in Inches
break;
case DEGREES:
case UNSCALED_UNITS:
default:
wxASSERT(0);
}
xrot->GetValue().ToDouble( &rotation.x );
yrot->GetValue().ToDouble( &rotation.y );
zrot->GetValue().ToDouble( &rotation.z );
checkRotation( rotation.x );
checkRotation( rotation.y );
checkRotation( rotation.z );
xoff->GetValue().ToDouble( &offset.x );
yoff->GetValue().ToDouble( &offset.y );
zoff->GetValue().ToDouble( &offset.z );
return;
}
void PANEL_PREV_3D::updateListOnModelCopy()
{
bool gotAnInvalidScale = false;
for( unsigned int idx = 0; idx < m_parentInfoList->size(); ++idx )
{
SGPOINT scale = (*m_parentInfoList)[idx].m_Scale;
gotAnInvalidScale |= ( 0.0001 > scale.x || 0.0001 > scale.y || 0.0001 > scale.z );
if( 0.0001 > scale.x )
scale.x = 1.0;
if( 0.0001 > scale.y )
scale.y = 1.0;
if( 0.0001 > scale.y )
scale.y = 1.0;
(*m_parentInfoList)[idx].m_Scale = scale;
}
if( gotAnInvalidScale )
{
wxString errmsg = _("[INFO] invalid scale values; setting invalid to 1.0");
wxLogMessage( "%s", errmsg.ToUTF8() );
}
std::list<S3D_INFO>* draw3D = &m_copyModule->Models();
draw3D->clear();
draw3D->insert( draw3D->end(), m_parentInfoList->begin(), m_parentInfoList->end() );
}

View File

@ -1,6 +1,7 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
*
* This program is free software; you can redistribute it and/or
@ -23,35 +24,51 @@
/**
* @file panel_prev_model.h
* defines a panel which is to be added to a wxFileDialog via SetExtraControl();
* the panel shows a preview of the model being browsed (if preview is supported
* by a plugin) and provides controls to set the offset/rotation/scale of the
* model as per KiCad's current behavior. The panel may also be used in the 3D
* configuration dialog to tune the positioning of the models without invoking
* a file selector dialog.
* @brief Defines a panel which is to be added to a wxFileDialog via
* SetExtraControl();
* The panel shows a preview of the module being edited and provides controls
* to set the offset/rotation/scale of each model 3d shape as per KiCad's
* current behavior. The panel may also be used in the 3D configuration dialog
* to tune the positioning of the models without invoking a file selector dialog.
*/
#ifndef PANEL_PREV_MODEL_H
#define PANEL_PREV_MODEL_H
#include <wx/panel.h>
#include <wx/textctrl.h>
#include "../3d_info.h"
#include <vector>
#include "plugins/3dapi/c3dmodel.h"
#include "3d_cache/3d_info.h"
// Declared classes to create pointers
class S3D_CACHE;
class S3D_FILENAME_RESOLVER;
class C3D_MODEL_VIEWER;
class wxGenericDirCtrl;
class EDA_3D_CANVAS;
class BOARD;
class CINFO3D_VISU;
class MODULE;
class PANEL_PREV_3D : public wxPanel
{
public:
PANEL_PREV_3D( wxWindow* aParent, S3D_CACHE* aCacheManager );
/**
* @brief PANEL_PREV_3D - Creator
* @param aParent: the parent windows (or object)
* @param aCacheManager: the cache manager to use to resolve the 3D model files
* @param aModule: a copy of the original module that is edited. this is for preview propose and
* it will be changes, so dont use the original one.
* @param aParentInfoList: a pointer to the Info list managed by the parent. This list will be
* passed o the aModuleCopy so it will have the updated 3d model shapes list.
*/
PANEL_PREV_3D( wxWindow* aParent,
S3D_CACHE* aCacheManager,
MODULE* aModuleCopy,
std::vector<S3D_INFO> *aParentInfoList = NULL );
~PANEL_PREV_3D();
// 3D views
// 3D views buttons
void View3DISO( wxCommandEvent& event );
void View3DUpdate( wxCommandEvent& event );
void View3DLeft( wxCommandEvent& event );
@ -60,18 +77,28 @@ public:
void View3DBack( wxCommandEvent& event );
void View3DTop( wxCommandEvent& event );
void View3DBottom( wxCommandEvent& event );
// Set / Retrieve model data
void SetModelData( S3D_INFO const* aModel );
void GetModelData( S3D_INFO* aModel );
/**
* @brief SetModelDataIdx - This will set the index of the INFO list that was set on the parent.
* So we will update our values to edit based on the index on that list.
* @param idx - The index that was selected
* @param aReloadPreviewModule: if need to update the preview module
*/
void SetModelDataIdx( int idx, bool aReloadPreviewModule = false );
/**
* @brief ResetModelData - Clear the values and reload the preview board
* @param aReloadPreviewModule: if need to update the preview module
*/
void ResetModelData( bool aReloadPreviewModule = false );
void UpdateModelName( wxString const& aModel );
// Update on change of FileDlg selection
virtual void UpdateWindowUI( long flags = wxUPDATE_UI_NONE );
private:
wxString currentModelFile;
S3D_CACHE* m_ModelManager;
S3D_FILENAME_RESOLVER* m_resolver;
wxGenericDirCtrl* m_FileTree;
wxString currentModelFile; ///< Used to check if the model file was changed
S3D_FILENAME_RESOLVER *m_resolver; ///< Used to get the full path name
// Parameters
wxTextCtrl* xscale;
wxTextCtrl* yscale;
wxTextCtrl* zscale;
@ -81,16 +108,54 @@ private:
wxTextCtrl* xoff;
wxTextCtrl* yoff;
wxTextCtrl* zoff;
wxPanel* preview;
C3D_MODEL_VIEWER* canvas;
S3DMODEL* model;
S3D_INFO modelInfo;
EDA_3D_CANVAS *m_previewPane;
/// The settings that will be used for this 3D viewer canvas
CINFO3D_VISU *m_settings3Dviewer;
/// A dummy board used to store the copy moduled
BOARD *m_dummyBoard;
/// A pointer to a new copy of the original module
MODULE *m_copyModule;
/// A pointer to the parent S3D_INFO list that we will use to copy to the preview module
std::vector<S3D_INFO> *m_parentInfoList;
/// The current selected index of the S3D_INFO list
int m_currentSelectedIdx;
/// Current S3D_INFO that is being edited
S3D_INFO m_modelInfo;
private:
/**
* @brief updateOrientation - it will receive the events from editing the fields
* @param event
*/
void updateOrientation( wxCommandEvent &event );
void getOrientationVars( SGPOINT& scale, SGPOINT& rotation, SGPOINT& offset );
/**
* @brief getOrientationVars - gets the transformation from entries and validate it
* @param aScale: output scale var
* @param aRotation: output rotation var
* @param aOffset: output offset var
*/
void getOrientationVars( SGPOINT& aScale, SGPOINT& aRotation, SGPOINT& aOffset );
/**
* @brief updateListOnModelCopy - copy the current shape list to the copy of module that is on
* the preview dummy board
*/
void updateListOnModelCopy();
/**
* @brief OnCloseWindow - called when the frame is closed
* @param event
*/
void OnCloseWindow( wxCloseEvent &event );
wxDECLARE_EVENT_TABLE();
};

View File

@ -1,739 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file 3d_canvas.cpp
*/
#include <fctsys.h>
#include <trigo.h>
#include <project.h>
#include <gestfich.h>
#include <wx/image.h>
#if !wxUSE_GLCANVAS
#error Please set wxUSE_GLCANVAS to 1 in setup.h.
#endif
#include <wx/dataobj.h>
#include <wx/clipbrd.h>
#include <wx/wupdlock.h>
#ifdef __WINDOWS__
#include <GL/glew.h> // must be included before gl.h
#endif
#include <3d_viewer.h>
#include <3d_canvas.h>
#include <info3d_visu.h>
#include <trackball.h>
#include <3d_viewer_id.h>
#include <gl_context_mgr.h>
#include <textures/text_silk.h>
#include <textures/text_pcb.h>
static const double DELTA_MOVE_STEP = 0.7;
/*
* EDA_3D_CANVAS implementation
*/
BEGIN_EVENT_TABLE( EDA_3D_CANVAS, wxGLCanvas )
EVT_PAINT( EDA_3D_CANVAS::OnPaint )
// key event:
EVT_CHAR( EDA_3D_CANVAS::OnChar )
// mouse events
EVT_RIGHT_DOWN( EDA_3D_CANVAS::OnRightClick )
EVT_MOUSEWHEEL( EDA_3D_CANVAS::OnMouseWheel )
#if wxCHECK_VERSION( 3, 1, 0 ) || defined( USE_OSX_MAGNIFY_EVENT )
EVT_MAGNIFY( EDA_3D_CANVAS::OnMagnify )
#endif
EVT_MOTION( EDA_3D_CANVAS::OnMouseMove )
// other events
EVT_ERASE_BACKGROUND( EDA_3D_CANVAS::OnEraseBackground )
EVT_MENU_RANGE( ID_POPUP_3D_VIEW_START, ID_POPUP_3D_VIEW_END, EDA_3D_CANVAS::OnPopUpMenu )
END_EVENT_TABLE()
// Define an invalid value for some unsigned int indexes
#define INVALID_INDEX GL_INVALID_VALUE
EDA_3D_CANVAS::EDA_3D_CANVAS( EDA_3D_FRAME* parent, int* attribList ) :
wxGLCanvas( parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize,
wxFULL_REPAINT_ON_RESIZE )
{
m_init = false;
m_reportWarnings = true;
m_shadow_init = false;
// set an invalid value to not yet initialized indexes managing
// textures created to enhance 3D rendering
m_text_pcb = m_text_silk = INVALID_INDEX;
m_text_fake_shadow_front = INVALID_INDEX;
m_text_fake_shadow_back = INVALID_INDEX;
m_text_fake_shadow_board = INVALID_INDEX;
// position of the front and back layers
// (will be initialized to a better value later)
m_ZBottom = 0.0;
m_ZTop = 0.0;
m_lightPos = S3D_VERTEX(0.0f, 0.0f, 30.0f);
// Clear all gl list identifiers:
for( int ii = GL_ID_BEGIN; ii < GL_ID_END; ii++ )
m_glLists[ii] = 0;
// Explicitly create a new rendering context instance for this canvas.
m_glRC = GL_CONTEXT_MANAGER::Get().CreateCtx( this );
DisplayStatus();
}
EDA_3D_CANVAS::~EDA_3D_CANVAS()
{
GL_CONTEXT_MANAGER::Get().LockCtx( m_glRC, this );
ClearLists();
m_init = false;
// Free the list of parsers list
for( unsigned int i = 0; i < m_model_parsers_list.size(); i++ )
delete m_model_parsers_list[i];
GL_CONTEXT_MANAGER::Get().UnlockCtx( m_glRC );
GL_CONTEXT_MANAGER::Get().DestroyCtx( m_glRC );
}
void EDA_3D_CANVAS::ClearLists( int aGlList )
{
if( aGlList )
{
if( m_glLists[aGlList] > 0 )
glDeleteLists( m_glLists[aGlList], 1 );
m_glLists[aGlList] = 0;
return;
}
for( int ii = GL_ID_BEGIN; ii < GL_ID_END; ii++ )
{
if( m_glLists[ii] > 0 )
glDeleteLists( m_glLists[ii], 1 );
m_glLists[ii] = 0;
}
// When m_text_fake_shadow_??? is set to INVALID_INDEX, textures are not yet created.
if( m_text_fake_shadow_front != INVALID_INDEX )
glDeleteTextures( 1, &m_text_fake_shadow_front );
if( m_text_fake_shadow_back != INVALID_INDEX )
glDeleteTextures( 1, &m_text_fake_shadow_back );
if( m_text_fake_shadow_board != INVALID_INDEX )
glDeleteTextures( 1, &m_text_fake_shadow_board );
m_shadow_init = false;
}
void EDA_3D_CANVAS::OnChar( wxKeyEvent& event )
{
SetView3D( event.GetKeyCode() );
event.Skip();
}
void EDA_3D_CANVAS::SetView3D( int keycode )
{
int ii;
double delta_move = DELTA_MOVE_STEP * GetPrm3DVisu().m_Zoom;
switch( keycode )
{
case WXK_LEFT:
m_draw3dOffset.x -= delta_move;
break;
case WXK_RIGHT:
m_draw3dOffset.x += delta_move;
break;
case WXK_UP:
m_draw3dOffset.y += delta_move;
break;
case WXK_DOWN:
m_draw3dOffset.y -= delta_move;
break;
case WXK_HOME:
GetPrm3DVisu().m_Zoom = 1.0;
m_draw3dOffset.x = m_draw3dOffset.y = 0;
trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
break;
case WXK_END:
break;
case WXK_F1:
GetPrm3DVisu().m_Zoom /= 1.4;
if( GetPrm3DVisu().m_Zoom <= 0.01 )
GetPrm3DVisu().m_Zoom = 0.01;
break;
case WXK_F2:
GetPrm3DVisu().m_Zoom *= 1.4;
break;
case '+':
break;
case '-':
break;
case 'r':
case 'R':
m_draw3dOffset.x = m_draw3dOffset.y = 0;
for( ii = 0; ii < 4; ii++ )
GetPrm3DVisu().m_Rot[ii] = 0.0;
trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
break;
case 'x':
for( ii = 0; ii < 4; ii++ )
GetPrm3DVisu().m_Rot[ii] = 0.0;
trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
GetPrm3DVisu().m_ROTZ = -90;
GetPrm3DVisu().m_ROTX = -90;
break;
case 'X':
for( ii = 0; ii < 4; ii++ )
GetPrm3DVisu().m_Rot[ii] = 0.0;
trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
GetPrm3DVisu().m_ROTZ = 90;
GetPrm3DVisu().m_ROTX = -90;
break;
case 'y':
for( ii = 0; ii < 4; ii++ )
GetPrm3DVisu().m_Rot[ii] = 0.0;
trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
GetPrm3DVisu().m_ROTX = -90;
break;
case 'Y':
for( ii = 0; ii < 4; ii++ )
GetPrm3DVisu().m_Rot[ii] = 0.0;
trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
GetPrm3DVisu().m_ROTX = -90;
GetPrm3DVisu().m_ROTZ = -180;
break;
case 'z':
for( ii = 0; ii < 4; ii++ )
GetPrm3DVisu().m_Rot[ii] = 0.0;
trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
break;
case 'Z':
for( ii = 0; ii < 4; ii++ )
GetPrm3DVisu().m_Rot[ii] = 0.0;
trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
GetPrm3DVisu().m_ROTX = -180;
break;
default:
return;
}
DisplayStatus();
Refresh( false );
}
void EDA_3D_CANVAS::OnMouseWheel( wxMouseEvent& event )
{
double delta = DELTA_MOVE_STEP * GetPrm3DVisu().m_Zoom;
if ( GetPrm3DVisu().GetFlag( FL_MOUSEWHEEL_PANNING ) )
delta *= 0.05 * event.GetWheelRotation();
else
if ( event.GetWheelRotation() < 0 )
delta = -delta;
if( GetPrm3DVisu().GetFlag( FL_MOUSEWHEEL_PANNING ) )
{
if( event.GetWheelAxis() == wxMOUSE_WHEEL_HORIZONTAL )
m_draw3dOffset.x -= delta;
else
m_draw3dOffset.y -= delta;
}
else if( event.ShiftDown() )
{
m_draw3dOffset.y -= delta;
}
else if( event.ControlDown() )
{
m_draw3dOffset.x += delta;
}
else
{
if( event.GetWheelRotation() > 0 )
{
GetPrm3DVisu().m_Zoom /= 1.4;
if( GetPrm3DVisu().m_Zoom <= 0.01 )
GetPrm3DVisu().m_Zoom = 0.01;
}
else
GetPrm3DVisu().m_Zoom *= 1.4;
}
DisplayStatus();
Refresh( false );
GetPrm3DVisu().m_Beginx = event.GetX();
GetPrm3DVisu().m_Beginy = event.GetY();
}
#if wxCHECK_VERSION( 3, 1, 0 ) || defined( USE_OSX_MAGNIFY_EVENT )
void EDA_3D_CANVAS::OnMagnify( wxMouseEvent& event )
{
double magnification = ( event.GetMagnification() + 1.0f );
GetPrm3DVisu().m_Zoom /= magnification;
if( GetPrm3DVisu().m_Zoom <= 0.01 )
{
GetPrm3DVisu().m_Zoom = 0.01;
}
DisplayStatus();
Refresh( false );
}
#endif
void EDA_3D_CANVAS::OnMouseMove( wxMouseEvent& event )
{
wxSize size( GetClientSize() );
double spin_quat[4];
if( event.Dragging() )
{
if( event.LeftIsDown() )
{
/* drag in progress, simulate trackball */
trackball( spin_quat,
(2.0 * GetPrm3DVisu().m_Beginx - size.x) / size.x,
(size.y - 2.0 * GetPrm3DVisu().m_Beginy) / size.y,
( 2.0 * event.GetX() - size.x) / size.x,
( size.y - 2.0 * event.GetY() ) / size.y );
add_quats( spin_quat, GetPrm3DVisu().m_Quat, GetPrm3DVisu().m_Quat );
}
else if( event.MiddleIsDown() )
{
/* middle button drag -> pan */
/* Current zoom and an additional factor are taken into account
* for the amount of panning. */
const double PAN_FACTOR = 8.0 * GetPrm3DVisu().m_Zoom;
m_draw3dOffset.x -= PAN_FACTOR *
( GetPrm3DVisu().m_Beginx - event.GetX() ) / size.x;
m_draw3dOffset.y -= PAN_FACTOR *
(event.GetY() - GetPrm3DVisu().m_Beginy) / size.y;
}
/* orientation has changed, redraw mesh */
DisplayStatus();
Refresh( false );
}
GetPrm3DVisu().m_Beginx = event.GetX();
GetPrm3DVisu().m_Beginy = event.GetY();
}
void EDA_3D_CANVAS::OnRightClick( wxMouseEvent& event )
{
wxPoint pos;
wxMenu PopUpMenu;
pos.x = event.GetX();
pos.y = event.GetY();
wxMenuItem* item = new wxMenuItem( &PopUpMenu, ID_POPUP_ZOOMIN, _( "Zoom +" ) );
item->SetBitmap( KiBitmap( zoom_in_xpm ));
PopUpMenu.Append( item );
item = new wxMenuItem( &PopUpMenu, ID_POPUP_ZOOMOUT, _( "Zoom -" ) );
item->SetBitmap( KiBitmap( zoom_out_xpm ));
PopUpMenu.Append( item );
PopUpMenu.AppendSeparator();
item = new wxMenuItem( &PopUpMenu, ID_POPUP_VIEW_ZPOS, _( "Top View" ) );
item->SetBitmap( KiBitmap( axis3d_top_xpm ));
PopUpMenu.Append( item );
item = new wxMenuItem( &PopUpMenu, ID_POPUP_VIEW_ZNEG, _( "Bottom View" ) );
item->SetBitmap( KiBitmap( axis3d_bottom_xpm ));
PopUpMenu.Append( item );
PopUpMenu.AppendSeparator();
item = new wxMenuItem( &PopUpMenu, ID_POPUP_VIEW_XPOS, _( "Right View" ) );
item->SetBitmap( KiBitmap( axis3d_right_xpm ));
PopUpMenu.Append( item );
item = new wxMenuItem( &PopUpMenu, ID_POPUP_VIEW_XNEG, _( "Left View" ) );
item->SetBitmap( KiBitmap( axis3d_left_xpm ));
PopUpMenu.Append( item );
PopUpMenu.AppendSeparator();
item = new wxMenuItem( &PopUpMenu, ID_POPUP_VIEW_YPOS, _( "Front View" ) );
item->SetBitmap( KiBitmap( axis3d_front_xpm ));
PopUpMenu.Append( item );
item = new wxMenuItem( &PopUpMenu, ID_POPUP_VIEW_YNEG, _( "Back View" ) );
item->SetBitmap( KiBitmap( axis3d_back_xpm ));
PopUpMenu.Append( item );
PopUpMenu.AppendSeparator();
item = new wxMenuItem( &PopUpMenu, ID_POPUP_MOVE3D_LEFT, _( "Move left <-" ) );
item->SetBitmap( KiBitmap( left_xpm ));
PopUpMenu.Append( item );
item = new wxMenuItem( &PopUpMenu, ID_POPUP_MOVE3D_RIGHT, _( "Move right ->" ) );
item->SetBitmap( KiBitmap( right_xpm ));
PopUpMenu.Append( item );
item = new wxMenuItem( &PopUpMenu, ID_POPUP_MOVE3D_UP, _( "Move Up ^" ) );
item->SetBitmap( KiBitmap( up_xpm ));
PopUpMenu.Append( item );
item = new wxMenuItem( &PopUpMenu, ID_POPUP_MOVE3D_DOWN, _( "Move Down" ) );
item->SetBitmap( KiBitmap( down_xpm ));
PopUpMenu.Append( item );
PopupMenu( &PopUpMenu, pos );
}
void EDA_3D_CANVAS::OnPopUpMenu( wxCommandEvent& event )
{
int key = 0;
switch( event.GetId() )
{
case ID_POPUP_ZOOMIN:
key = WXK_F1;
break;
case ID_POPUP_ZOOMOUT:
key = WXK_F2;
break;
case ID_POPUP_VIEW_XPOS:
key = 'x';
break;
case ID_POPUP_VIEW_XNEG:
key = 'X';
break;
case ID_POPUP_VIEW_YPOS:
key = 'y';
break;
case ID_POPUP_VIEW_YNEG:
key = 'Y';
break;
case ID_POPUP_VIEW_ZPOS:
key = 'z';
break;
case ID_POPUP_VIEW_ZNEG:
key = 'Z';
break;
case ID_POPUP_MOVE3D_LEFT:
key = WXK_LEFT;
break;
case ID_POPUP_MOVE3D_RIGHT:
key = WXK_RIGHT;
break;
case ID_POPUP_MOVE3D_UP:
key = WXK_UP;
break;
case ID_POPUP_MOVE3D_DOWN:
key = WXK_DOWN;
break;
default:
return;
}
SetView3D( key );
}
void EDA_3D_CANVAS::DisplayStatus()
{
wxString msg;
msg.Printf( wxT( "dx %3.2f" ), m_draw3dOffset.x );
Parent()->SetStatusText( msg, 1 );
msg.Printf( wxT( "dy %3.2f" ), m_draw3dOffset.y );
Parent()->SetStatusText( msg, 2 );
msg.Printf( _( "Zoom: %3.1f" ), 45 * GetPrm3DVisu().m_Zoom );
Parent()->SetStatusText( msg, 3 );
}
void EDA_3D_CANVAS::OnPaint( wxPaintEvent& event )
{
wxPaintDC dc( this );
Redraw();
event.Skip();
}
void EDA_3D_CANVAS::OnEraseBackground( wxEraseEvent& event )
{
// Do nothing, to avoid flashing.
}
typedef struct s_sImage
{
unsigned int width;
unsigned int height;
unsigned int bytes_per_pixel; /* 2:RGB16, 3:RGB, 4:RGBA */
unsigned char pixel_data[64 * 64 * 4 + 1];
}tsImage;
GLuint load_and_generate_texture( tsImage *image )
{
GLuint texture;
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
glPixelStorei (GL_PACK_ALIGNMENT, 1);
glGenTextures( 1, &texture );
glBindTexture( GL_TEXTURE_2D, texture );
gluBuild2DMipmaps( GL_TEXTURE_2D, GL_RGBA, image->width, image->height,
GL_RGBA, GL_UNSIGNED_BYTE, image->pixel_data );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
return texture;
}
void EDA_3D_CANVAS::InitGL()
{
if( !m_init )
{
m_init = true;
m_text_pcb = load_and_generate_texture( (tsImage *)&text_pcb );
m_text_silk = load_and_generate_texture( (tsImage *)&text_silk );
GetPrm3DVisu().m_Zoom = 1.0;
m_ZBottom = 1.0;
m_ZTop = 10.0;
glDisable( GL_CULL_FACE ); // show back faces
glEnable( GL_DEPTH_TEST ); // Enable z-buffering
glEnable( GL_ALPHA_TEST );
glEnable( GL_LINE_SMOOTH );
// glEnable(GL_POLYGON_SMOOTH); // creates issues with some graphic cards
glEnable( GL_NORMALIZE );
glEnable( GL_COLOR_MATERIAL );
glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
// speedups
//glEnable( GL_DITHER );
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_DONT_CARE );
glHint( GL_LINE_SMOOTH_HINT, GL_NICEST );
glHint( GL_POLYGON_SMOOTH_HINT, GL_NICEST );
// Initialize alpha blending function.
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
}
}
void EDA_3D_CANVAS::SetLights()
{
// activate light. the source is above the xy plane, at source_pos
GLfloat source_pos[4] = { m_lightPos.x, m_lightPos.y, m_lightPos.z, 0.0f };
GLfloat light_color[4]; // color of lights (RGBA values)
light_color[3] = 1.0;
// Light above the xy plane
light_color[0] = light_color[1] = light_color[2] = 0.0;
glLightfv( GL_LIGHT0, GL_AMBIENT, light_color );
light_color[0] = light_color[1] = light_color[2] = 1.0;
glLightfv( GL_LIGHT0, GL_DIFFUSE, light_color );
light_color[0] = light_color[1] = light_color[2] = 1.0;
glLightfv( GL_LIGHT0, GL_SPECULAR, light_color );
glLightfv( GL_LIGHT0, GL_POSITION, source_pos );
light_color[0] = light_color[1] = light_color[2] = 0.2;
glLightModelfv( GL_LIGHT_MODEL_AMBIENT, light_color );
glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE );
glEnable( GL_LIGHT0 ); // White spot on Z axis ( top )
glEnable( GL_LIGHTING );
}
void EDA_3D_CANVAS::TakeScreenshot( wxCommandEvent& event )
{
static wxFileName fn; // Remember path between saves during this session only.
wxString FullFileName;
wxString file_ext, mask;
bool fmt_is_jpeg = false;
// First time path is set to the project path.
if( !fn.IsOk() )
fn = Parent()->Prj().GetProjectFullName();
if( event.GetId() == ID_MENU_SCREENCOPY_JPEG )
fmt_is_jpeg = true;
if( event.GetId() != ID_TOOL_SCREENCOPY_TOCLIBBOARD )
{
file_ext = fmt_is_jpeg ? wxT( "jpg" ) : wxT( "png" );
mask = wxT( "*." ) + file_ext;
fn.SetExt( file_ext );
FullFileName = EDA_FILE_SELECTOR( _( "3D Image File Name:" ), fn.GetPath(),
fn.GetFullName(), file_ext, mask, this,
wxFD_SAVE | wxFD_OVERWRITE_PROMPT, true );
if( FullFileName.IsEmpty() )
return;
fn = FullFileName;
// Be sure the screen area destroyed by the file dialog is redrawn before making
// a screen copy.
// Without this call, under Linux the screen refresh is made to late.
wxYield();
}
struct viewport_params
{
GLint originx;
GLint originy;
GLint x;
GLint y;
} viewport;
// Be sure we have the latest 3D view (remember 3D view is buffered)
Refresh();
wxYield();
// Build image from the 3D buffer
wxWindowUpdateLocker noUpdates( this );
glGetIntegerv( GL_VIEWPORT, (GLint*) &viewport );
unsigned char* pixelbuffer = (unsigned char*) malloc( viewport.x * viewport.y * 3 );
unsigned char* alphabuffer = (unsigned char*) malloc( viewport.x * viewport.y );
wxImage image_3d( viewport.x, viewport.y );
glPixelStorei( GL_PACK_ALIGNMENT, 1 );
glReadBuffer( GL_BACK_LEFT );
glReadPixels( viewport.originx, viewport.originy,
viewport.x, viewport.y,
GL_RGB, GL_UNSIGNED_BYTE, pixelbuffer );
glReadPixels( viewport.originx, viewport.originy,
viewport.x, viewport.y,
GL_ALPHA, GL_UNSIGNED_BYTE, alphabuffer );
image_3d.SetData( pixelbuffer );
image_3d.SetAlpha( alphabuffer );
image_3d = image_3d.Mirror( false );
wxBitmap bitmap( image_3d );
if( event.GetId() == ID_TOOL_SCREENCOPY_TOCLIBBOARD )
{
if( wxTheClipboard->Open() )
{
wxBitmapDataObject* dobjBmp = new wxBitmapDataObject( bitmap );
if( !wxTheClipboard->SetData( dobjBmp ) )
wxMessageBox( _( "Failed to copy image to clipboard" ) );
wxTheClipboard->Flush(); /* the data in clipboard will stay
* available after the application exits */
wxTheClipboard->Close();
}
}
else
{
wxImage image = bitmap.ConvertToImage();
if( !image.SaveFile( FullFileName,
fmt_is_jpeg ? wxBITMAP_TYPE_JPEG : wxBITMAP_TYPE_PNG ) )
wxMessageBox( _( "Can't save file" ) );
image.Destroy();
}
}

View File

@ -1,375 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2012 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file 3d_viewer.h
*/
#ifndef _3D_CANVAS_H_
#define _3D_CANVAS_H_
#include <wx/glcanvas.h>
#ifdef __WXMAC__
# ifdef __DARWIN__
# include <OpenGL/glu.h>
# else
# include <glu.h>
# endif
#else
# include <GL/glu.h>
#endif
#include <3d_struct.h>
#include <modelparsers.h>
#include <class_module.h>
#include "3d_rendering/3d_render_raytracing/shapes3D/cbbox.h"
class BOARD_DESIGN_SETTINGS;
class EDA_3D_FRAME;
class SHAPE_POLY_SET;
class REPORTER;
class VIA;
class D_PAD;
// We are using GL lists to store layers and other items
// to draw or not
// GL_LIST_ID are the GL lists indexes in m_glLists
enum GL_LIST_ID
{
GL_ID_BEGIN = 0,
GL_ID_AXIS = GL_ID_BEGIN, // list id for 3D axis
GL_ID_GRID, // list id for 3D grid
GL_ID_BOARD, // List id for copper layers
GL_ID_TECH_LAYERS, // List id for non copper layers (masks...)
GL_ID_AUX_LAYERS, // List id for user layers (draw, eco, comment)
GL_ID_3DSHAPES_SOLID_FRONT, // List id for 3D shapes, non transparent entities
GL_ID_3DSHAPES_TRANSP_FRONT,// List id for 3D shapes, transparent entities
GL_ID_3DSHAPES_SOLID_BACK, // List id for 3D shapes, non transparent entities
GL_ID_3DSHAPES_TRANSP_BACK, // List id for 3D shapes, transparent entities
GL_ID_SHADOW_FRONT,
GL_ID_SHADOW_BACK,
GL_ID_SHADOW_BOARD,
GL_ID_BODY, // Body only list
GL_ID_END
};
class EDA_3D_CANVAS : public wxGLCanvas
{
private:
bool m_init;
bool m_reportWarnings; ///< true to report all warnings when building the 3D scene
///< false to report errors only
GLuint m_glLists[GL_ID_END]; ///< GL lists
wxGLContext* m_glRC;
wxRealPoint m_draw3dOffset; ///< offset to draw the 3D mesh.
double m_ZBottom; ///< position of the back layer
double m_ZTop; ///< position of the front layer
GLuint m_text_pcb; ///< an index to the texture generated for pcb texts
GLuint m_text_silk; ///< an index to the texture generated for silk layers
// Index to the textures generated for shadows
bool m_shadow_init;
GLuint m_text_fake_shadow_front;
GLuint m_text_fake_shadow_back;
GLuint m_text_fake_shadow_board;
CBBOX m_boardAABBox; ///< Axis Align Bounding Box of the board
CBBOX m_fastAABBox; ///< Axis Align Bounding Box that contain the other bounding boxes
CBBOX m_fastAABBox_Shadow; ///< A bit scalled version of the m_fastAABBox
S3D_VERTEX m_lightPos;
/// Stores the list of parsers for each new file name (dont repeat files already loaded)
std::vector<S3D_MODEL_PARSER *> m_model_parsers_list;
std::vector<wxString> m_model_filename_list;
void create_and_render_shadow_buffer( GLuint *aDst_gl_texture,
GLuint aTexture_size, bool aDraw_body, int aBlurPasses );
void calcBBox();
public:
EDA_3D_CANVAS( EDA_3D_FRAME* parent, int* attribList = 0 );
~EDA_3D_CANVAS();
EDA_3D_FRAME* Parent() const { return static_cast<EDA_3D_FRAME*>( GetParent() ); }
BOARD* GetBoard() { return Parent()->GetBoard(); }
/**
* Function ClearLists
* Clear the display list.
* @param aGlList = the list to clear.
* if 0 (default) all lists are cleared
*/
void ClearLists( int aGlList = 0 );
// Event functions:
void OnPaint( wxPaintEvent& event );
void OnEraseBackground( wxEraseEvent& event );
void OnChar( wxKeyEvent& event );
void OnMouseWheel( wxMouseEvent& event );
#if wxCHECK_VERSION( 3, 1, 0 ) || defined( USE_OSX_MAGNIFY_EVENT )
void OnMagnify( wxMouseEvent& event );
#endif
void OnMouseMove( wxMouseEvent& event );
void OnRightClick( wxMouseEvent& event );
void OnPopUpMenu( wxCommandEvent& event );
/**
* Function TakeScreenshot
*
* creates a screenshot of the current 3D view and save to file as png or jpeg or image
* is copied to the clipboard
*/
void TakeScreenshot( wxCommandEvent& event );
void OnEnterWindow( wxMouseEvent& event );
// Display functions
void SetView3D( int keycode );
void DisplayStatus();
void Redraw();
void Render();
/**
* Function CreateDrawGL_List
* Prepares the parameters of the OpenGL draw list
* creates the OpenGL draw list items (board, grid ...)
* @param aErrorMessages = a REPORTER which will filled with error messages,
* if any
* @param aActivity = a REPORTER to display activity state
*/
void CreateDrawGL_List( REPORTER* aErrorMessages, REPORTER* aActivity );
void InitGL();
void ReportWarnings( bool aReport ) { m_reportWarnings = aReport; }
void SetLights();
void SetOffset(double aPosX, double aPosY)
{
m_draw3dOffset.x = aPosX;
m_draw3dOffset.y = aPosY;
}
/** @return the INFO3D_VISU which contains the current parameters
* to draw the 3D view og the board
*/
INFO3D_VISU& GetPrm3DVisu() const;
private:
/**
* return true if we are in realistic mode render
*/
bool isRealisticMode() const;
/**
* @return true if aItem should be displayed
* @param aItem = an item of DISPLAY3D_FLG enum
*/
bool isEnabled( DISPLAY3D_FLG aItem ) const;
/** Helper function
* @return true if aLayer should be displayed, false otherwise
*/
bool is3DLayerEnabled( LAYER_ID aLayer ) const;
/**
* @return the size of the board in pcb units
*/
wxSize getBoardSize() const;
/**
* @return the position of the board center in pcb units
*/
wxPoint getBoardCenter() const;
/**
* Helper function setGLTechLayersColor
* Initialize the color to draw the non copper layers
* in realistic mode and normal mode.
*/
void setGLTechLayersColor( LAYER_NUM aLayer );
/**
* Helper function setGLCopperColor
* Initialize the copper color to draw the board
* in realistic mode (a golden yellow color )
*/
void setGLCopperColor();
/**
* Helper function setGLEpoxyColor
* Initialize the color to draw the epoxy body board in realistic mode.
*/
void setGLEpoxyColor( float aTransparency = 1.0 );
/**
* Helper function setGLSolderMaskColor
* Initialize the color to draw the solder mask layers in realistic mode.
*/
void setGLSolderMaskColor( float aTransparency = 1.0 );
/**
* Function buildBoard3DView
* Called by CreateDrawGL_List()
* Populates the OpenGL GL_ID_BOARD draw list with board items only on copper layers.
* 3D footprint shapes, tech layers and aux layers are not on this list
* Fills aErrorMessages with error messages created by some calculation function
* display activity state
* @param aBoardList =
* @param aBodyOnlyList =
* @param aErrorMessages = a REPORTER to add error and warning messages
* created by the build process (can be NULL)
* @param aActivity = a REPORTER to display activity state
*/
void buildBoard3DView( GLuint aBoardList, GLuint aBodyOnlyList,
REPORTER* aErrorMessages, REPORTER* aActivity );
/**
* Function buildTechLayers3DView
* Called by CreateDrawGL_List()
* Populates the OpenGL GL_ID_TECH_LAYERS draw list with items on tech layers
* @param aErrorMessages = a REPORTER to add error and warning messages
* created by the build process (can be NULL)
* @param aActivity = a REPORTER to display activity state
*/
void buildTechLayers3DView( REPORTER* aErrorMessages, REPORTER* aActivity );
/**
* Function buildBoardThroughHolesPolygonList
* Helper funtion to build the list of the board through holes polygons
* @param allBoardHoles = the SHAPE_POLY_SET to populate
* @param aSegCountPerCircle = the number of segments to approximate a circle
* @param aOptimizeLargeCircles = true to use more than aSegCountPerCircle
* for large circles (a large circle dimatere is > 1mm )
*/
void buildBoardThroughHolesPolygonList( SHAPE_POLY_SET& allBoardHoles,
int aSegCountPerCircle, bool aOptimizeLargeCircles );
/**
* Function buildShadowList
* Called by CreateDrawGL_List()
*/
void buildShadowList( GLuint aFrontList, GLuint aBacklist, GLuint aBoardList );
/**
* Function buildFootprintShape3DList
* Called by CreateDrawGL_List()
* Fills the OpenGL GL_ID_3DSHAPES_SOLID and GL_ID_3DSHAPES_TRANSP
* draw lists with 3D footprint shapes
* @param aOpaqueList is the gl list for non transparent items
* @param aTransparentList is the gl list for non transparent items,
* @param aErrorMessages = a REPORTER to add error and warning messages
* created by the build process (can be NULL)
* @param aActivity = a REPORTER to display activity state
* which need to be drawn after all other items
*/
void buildFootprintShape3DList( GLuint aOpaqueList,
GLuint aTransparentList,
REPORTER* aErrorMessages, REPORTER* aActivity );
/**
* Function buildBoard3DAuxLayers
* Called by CreateDrawGL_List()
* Fills the OpenGL GL_ID_AUX_LAYERS draw list
* with items on aux layers only
* @param aErrorMessages = a REPORTER to add error and warning messages
* created by the build process (can be NULL)
* @param aActivity = a REPORTER to display activity state
* which need to be drawn after all other items
*/
void buildBoard3DAuxLayers( REPORTER* aErrorMessages, REPORTER* aActivity );
void draw3DGrid( double aGriSizeMM );
void draw3DAxis();
/**
* Helper function BuildPadShapeThickOutlineAsPolygon:
* Build a pad outline as non filled polygon, to draw pads on silkscreen layer
* with a line thickness = aWidth
* Used only to draw pads outlines on silkscreen layers.
*/
void buildPadShapeThickOutlineAsPolygon( const D_PAD* aPad,
SHAPE_POLY_SET& aCornerBuffer,
int aWidth,
int aCircleToSegmentsCount,
double aCorrectionFactor );
/**
* Helper function draw3DViaHole:
* Draw the via hole:
* Build a vertical hole (a cylinder) between the first and the last via layers
*/
void draw3DViaHole( const VIA * aVia );
/**
* Helper function draw3DPadHole:
* Draw the pad hole:
* Build a vertical hole (round or oblong) between the front and back layers
*/
void draw3DPadHole( const D_PAD * aPad );
/**
* function render3DComponentShape
* insert mesh in gl list
* @param module
* @param aIsRenderingJustNonTransparentObjects = true to load non transparent objects
* @param aIsRenderingJustTransparentObjects = true to load non transparent objects
* in openGL, transparent objects should be drawn *after* non transparent objects
*/
void render3DComponentShape( MODULE* module,
bool aIsRenderingJustNonTransparentObjects,
bool aIsRenderingJustTransparentObjects );
/**
* function read3DComponentShape
* read the 3D component shape(s) of the footprint (physical shape).
* @param module
* @return true if load was succeeded, false otherwise
*/
bool read3DComponentShape( MODULE* module );
/**
* function generateFakeShadowsTextures
* creates shadows of the board an footprints
* for aesthetical purpose
* @param aErrorMessages = a REPORTER to add error and warning messages
* created by the build process (can be NULL)
* @param aActivity = a REPORTER to display activity state
*/
void generateFakeShadowsTextures( REPORTER* aErrorMessages, REPORTER* aActivity );
DECLARE_EVENT_TABLE()
};
void CheckGLError(const char *aFileName, int aLineNumber);
#endif /* _3D_CANVAS_H_ */

View File

@ -0,0 +1,567 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file cinfo3d_visu.cpp
* @brief Handles data related with the board to be visualized
*/
#include "../3d_rendering/ccamera.h"
#include "cinfo3d_visu.h"
#include <3d_rendering/3d_render_raytracing/shapes2D/cpolygon2d.h>
#include <class_board.h>
#include <3d_math.h>
#include "3d_fastmath.h"
#include <colors_selection.h>
/**
* Trace mask used to enable or disable the trace output of this class.
* The debug output can be turned on by setting the WXTRACE environment variable to
* "KI_TRACE_EDA_CINFO3D_VISU". See the wxWidgets documentation on wxLogTrace for
* more information.
*/
const wxChar *CINFO3D_VISU::m_logTrace = wxT( "KI_TRACE_EDA_CINFO3D_VISU" );
CINFO3D_VISU G_null_CINFO3D_VISU;
CINFO3D_VISU::CINFO3D_VISU() :
m_currentCamera( m_trackBallCamera ),
m_trackBallCamera( RANGE_SCALE_3D )
{
wxLogTrace( m_logTrace, wxT( "CINFO3D_VISU::CINFO3D_VISU" ) );
m_board = NULL;
m_3d_model_manager = NULL;
m_3D_grid_type = GRID3D_NONE;
m_drawFlags.resize( FL_LAST, false );
m_render_engine = RENDER_ENGINE_OPENGL_LEGACY;
m_material_mode = MATERIAL_MODE_NORMAL;
m_boardPos = wxPoint();
m_boardSize = wxSize();
m_boardCenter = SFVEC3F();
m_boardBoudingBox.Reset();
m_board2dBBox3DU.Reset();
m_layers_container2D.clear();
m_layers_holes2D.clear();
m_through_holes_inner.Clear();
m_through_holes_outer.Clear();
m_copperLayersCount = -1;
m_epoxyThickness3DU = 0.0f;
m_copperThickness3DU = 0.0f;
m_nonCopperLayerThickness3DU = 0.0f;
m_biuTo3Dunits = 1.0;
m_stats_nr_tracks = 0;
m_stats_nr_vias = 0;
m_stats_via_med_hole_diameter = 0.0f;
m_stats_nr_holes = 0;
m_stats_hole_med_diameter = 0.0f;
m_stats_track_med_width = 0.0f;
m_calc_seg_min_factor3DU = 0.0f;
m_calc_seg_max_factor3DU = 0.0f;
memset( m_layerZcoordTop, 0, sizeof( m_layerZcoordTop ) );
memset( m_layerZcoordBottom, 0, sizeof( m_layerZcoordBottom ) );
SetFlag( FL_USE_REALISTIC_MODE, true );
SetFlag( FL_MODULE_ATTRIBUTES_NORMAL, true );
SetFlag( FL_SHOW_BOARD_BODY, true );
SetFlag( FL_RENDER_OPENGL_COPPER_THICKNESS, true );
SetFlag( FL_MODULE_ATTRIBUTES_NORMAL, true );
SetFlag( FL_MODULE_ATTRIBUTES_NORMAL_INSERT, true );
SetFlag( FL_MODULE_ATTRIBUTES_VIRTUAL, true );
SetFlag( FL_ZONE, true );
SetFlag( FL_SILKSCREEN, true );
SetFlag( FL_SOLDERMASK, true );
m_BgColorBot = SFVEC3D( 0.4, 0.4, 0.5 );
m_BgColorTop = SFVEC3D( 0.8, 0.8, 0.9 );
m_BoardBodyColor = SFVEC3D( 0.4, 0.4, 0.5 );
m_SolderMaskColor = SFVEC3D( 0.1, 0.2, 0.1 );
m_SolderPasteColor = SFVEC3D( 0.4, 0.4, 0.4 );
m_SilkScreenColor = SFVEC3D( 0.9, 0.9, 0.9 );
m_CopperColor = SFVEC3D( 0.75, 0.61, 0.23 );
}
CINFO3D_VISU::~CINFO3D_VISU()
{
destroyLayers();
}
bool CINFO3D_VISU::Is3DLayerEnabled( LAYER_ID aLayer ) const
{
wxASSERT( aLayer < LAYER_ID_COUNT );
DISPLAY3D_FLG flg;
// see if layer needs to be shown
// check the flags
switch( aLayer )
{
case B_Adhes:
case F_Adhes:
flg = FL_ADHESIVE;
break;
case B_Paste:
case F_Paste:
flg = FL_SOLDERPASTE;
break;
case B_SilkS:
case F_SilkS:
flg = FL_SILKSCREEN;
break;
case B_Mask:
case F_Mask:
flg = FL_SOLDERMASK;
break;
case Dwgs_User:
case Cmts_User:
if( GetFlag( FL_USE_REALISTIC_MODE ) )
return false;
flg = FL_COMMENTS;
break;
case Eco1_User:
case Eco2_User:
if( GetFlag( FL_USE_REALISTIC_MODE ) )
return false;
flg = FL_ECO;
break;
case Edge_Cuts:
if( GetFlag( FL_SHOW_BOARD_BODY ) || GetFlag( FL_USE_REALISTIC_MODE ) )
return false;
return true;
break;
case Margin:
if( GetFlag( FL_USE_REALISTIC_MODE ) )
return false;
return true;
break;
case B_Cu:
case F_Cu:
return m_board->GetDesignSettings().IsLayerVisible( aLayer ) ||
GetFlag( FL_USE_REALISTIC_MODE );
break;
default:
// the layer is an internal copper layer, used the visibility
if( GetFlag( FL_SHOW_BOARD_BODY ) &&
(m_render_engine == RENDER_ENGINE_OPENGL_LEGACY) )
{
// Do not render internal layers if it is overlap with the board
// (on OpenGL render)
return false;
}
return m_board->GetDesignSettings().IsLayerVisible( aLayer );
}
// The layer has a flag, return the flag
return GetFlag( flg );
}
bool CINFO3D_VISU::GetFlag( DISPLAY3D_FLG aFlag ) const
{
wxASSERT( aFlag < FL_LAST );
return m_drawFlags[aFlag];
}
void CINFO3D_VISU::SetFlag( DISPLAY3D_FLG aFlag, bool aState )
{
wxASSERT( aFlag < FL_LAST );
m_drawFlags[aFlag] = aState;
}
bool CINFO3D_VISU::ShouldModuleBeDisplayed( MODULE_ATTR_T aModuleAttributs ) const
{
if( ( ( aModuleAttributs == MOD_DEFAULT ) &&
GetFlag( FL_MODULE_ATTRIBUTES_NORMAL ) ) ||
( ( ( aModuleAttributs & MOD_CMS) == MOD_CMS ) &&
GetFlag( FL_MODULE_ATTRIBUTES_NORMAL_INSERT ) ) ||
( ( ( aModuleAttributs & MOD_VIRTUAL) == MOD_VIRTUAL ) &&
GetFlag( FL_MODULE_ATTRIBUTES_VIRTUAL ) ) )
{
return true;
}
return false;
}
// !TODO: define the actual copper thickness by user
#define COPPER_THICKNESS KiROUND( 0.035 * IU_PER_MM ) // for 35 um
#define TECH_LAYER_THICKNESS KiROUND( 0.04 * IU_PER_MM )
int CINFO3D_VISU::GetCopperThicknessBIU() const
{
return COPPER_THICKNESS;
}
// Constant factors used for number of segments approximation calcs
#define MIN_SEG_PER_CIRCLE 12
#define MAX_SEG_PER_CIRCLE 48
#define SEG_MIN_FACTOR_BIU ( 0.10f * IU_PER_MM )
#define SEG_MAX_FACTOR_BIU ( 6.00f * IU_PER_MM )
unsigned int CINFO3D_VISU::GetNrSegmentsCircle( float aDiameter3DU ) const
{
wxASSERT( aDiameter3DU > 0.0f );
unsigned int result = mapf( aDiameter3DU,
m_calc_seg_min_factor3DU, m_calc_seg_max_factor3DU,
(float)MIN_SEG_PER_CIRCLE, (float)MAX_SEG_PER_CIRCLE );
wxASSERT( result > 1 );
return result;
}
unsigned int CINFO3D_VISU::GetNrSegmentsCircle( int aDiameterBUI ) const
{
wxASSERT( aDiameterBUI > 0 );
unsigned int result = mapf( (float)aDiameterBUI,
(float)SEG_MIN_FACTOR_BIU, (float)SEG_MAX_FACTOR_BIU,
(float)MIN_SEG_PER_CIRCLE, (float)MAX_SEG_PER_CIRCLE );
wxASSERT( result > 1 );
return result;
}
double CINFO3D_VISU::GetCircleCorrectionFactor( int aNrSides ) const
{
wxASSERT( aNrSides >= 3 );
return 1.0 / cos( M_PI / ( (double)aNrSides * 2.0 ) );
}
void CINFO3D_VISU::InitSettings( REPORTER *aStatusTextReporter )
{
wxLogTrace( m_logTrace, wxT( "CINFO3D_VISU::InitSettings" ) );
// Calculates the board bounding box
// First, use only the board outlines
EDA_RECT bbbox = m_board->ComputeBoundingBox( true );
// If no outlines, use the board with items
if( ( bbbox.GetWidth() == 0 ) && ( bbbox.GetHeight() == 0 ) )
bbbox = m_board->ComputeBoundingBox( false );
// Gives a non null size to avoid issues in zoom / scale calculations
if( ( bbbox.GetWidth() == 0 ) && ( bbbox.GetHeight() == 0 ) )
bbbox.Inflate( Millimeter2iu( 10 ) );
m_boardSize = bbbox.GetSize();
m_boardPos = bbbox.Centre();
wxASSERT( (m_boardSize.x > 0) && (m_boardSize.y > 0) );
m_boardPos.y = -m_boardPos.y; // The y coord is inverted in 3D viewer
m_copperLayersCount = m_board->GetCopperLayerCount();
// Ensure the board has 2 sides for 3D views, because it is hard to find
// a *really* single side board in the true life...
if( m_copperLayersCount < 2 )
m_copperLayersCount = 2;
// Calculate the convertion to apply to all positions.
m_biuTo3Dunits = RANGE_SCALE_3D / std::max( m_boardSize.x, m_boardSize.y );
// Calculate factors for cicle segment approximation
m_calc_seg_min_factor3DU = (float)( SEG_MIN_FACTOR_BIU * m_biuTo3Dunits );
m_calc_seg_max_factor3DU = (float)( SEG_MAX_FACTOR_BIU * m_biuTo3Dunits );
m_epoxyThickness3DU = m_board->GetDesignSettings().GetBoardThickness() *
m_biuTo3Dunits;
// !TODO: use value defined by user (currently use default values by ctor
m_copperThickness3DU = COPPER_THICKNESS * m_biuTo3Dunits;
m_nonCopperLayerThickness3DU = TECH_LAYER_THICKNESS * m_biuTo3Dunits;
// Init Z position of each layer
// calculate z position for each copper layer
// Zstart = -m_epoxyThickness / 2.0 is the z position of the back (bottom layer) (layer id = 31)
// Zstart = +m_epoxyThickness / 2.0 is the z position of the front (top layer) (layer id = 0)
// all unused copper layer z position are set to 0
// ____==__________==________==______ <- Bottom = +m_epoxyThickness / 2.0,
// | | Top = Bottom + m_copperThickness
// |__________________________________|
// == == == == <- Bottom = -m_epoxyThickness / 2.0,
// Top = Bottom - m_copperThickness
unsigned int layer;
for( layer = 0; layer < m_copperLayersCount; ++layer )
{
m_layerZcoordBottom[layer] = m_epoxyThickness3DU / 2.0f -
(m_epoxyThickness3DU * layer / (m_copperLayersCount - 1) );
if( layer < (m_copperLayersCount / 2) )
m_layerZcoordTop[layer] = m_layerZcoordBottom[layer] + m_copperThickness3DU;
else
m_layerZcoordTop[layer] = m_layerZcoordBottom[layer] - m_copperThickness3DU;
}
#define layerThicknessMargin 1.1
const float zpos_offset = m_nonCopperLayerThickness3DU * layerThicknessMargin;
// Fill remaining unused copper layers and back layer zpos
// with -m_epoxyThickness / 2.0
for( ; layer < MAX_CU_LAYERS; layer++ )
{
m_layerZcoordBottom[layer] = -(m_epoxyThickness3DU / 2.0f);
m_layerZcoordTop[layer] = -(m_epoxyThickness3DU / 2.0f) - m_copperThickness3DU;
}
// This is the top of the copper layer thickness.
const float zpos_copperTop_back = m_layerZcoordTop[B_Cu];
const float zpos_copperTop_front = m_layerZcoordTop[F_Cu];
// calculate z position for each non copper layer
// Solder mask and Solder paste have the same Z position
for( int layer_id = MAX_CU_LAYERS; layer_id < LAYER_ID_COUNT; ++layer_id )
{
float zposTop;
float zposBottom;
switch( layer_id )
{
case B_Adhes:
zposBottom = zpos_copperTop_back - 2.0f * zpos_offset;
zposTop = zposBottom - m_nonCopperLayerThickness3DU;
break;
case F_Adhes:
zposBottom = zpos_copperTop_front + 2.0f * zpos_offset;
zposTop = zposBottom + m_nonCopperLayerThickness3DU;
break;
case B_Mask:
case B_Paste:
zposBottom = zpos_copperTop_back;
zposTop = zpos_copperTop_back - m_nonCopperLayerThickness3DU;
break;
case F_Mask:
case F_Paste:
zposTop = zpos_copperTop_front + m_nonCopperLayerThickness3DU;
zposBottom = zpos_copperTop_front;
break;
case B_SilkS:
zposBottom = zpos_copperTop_back - 1.0f * zpos_offset;
zposTop = zposBottom - m_nonCopperLayerThickness3DU;
break;
case F_SilkS:
zposBottom = zpos_copperTop_front + 1.0f * zpos_offset;
zposTop = zposBottom + m_nonCopperLayerThickness3DU;
break;
// !TODO: review
default:
zposTop = zpos_copperTop_front + (layer_id - MAX_CU_LAYERS + 3.0f) * zpos_offset;
zposBottom = zposTop - m_nonCopperLayerThickness3DU;
break;
}
m_layerZcoordTop[layer_id] = zposTop;
m_layerZcoordBottom[layer_id] = zposBottom;
}
m_boardCenter = SFVEC3F( m_boardPos.x * m_biuTo3Dunits,
m_boardPos.y * m_biuTo3Dunits,
0.0f );
SFVEC3F boardSize = SFVEC3F( m_boardSize.x * m_biuTo3Dunits,
m_boardSize.y * m_biuTo3Dunits,
0.0f );
boardSize /= 2.0f;
SFVEC3F boardMin = (m_boardCenter - boardSize);
SFVEC3F boardMax = (m_boardCenter + boardSize);
boardMin.z = m_layerZcoordTop[B_Adhes];
boardMax.z = m_layerZcoordTop[F_Adhes];
m_boardBoudingBox = CBBOX( boardMin, boardMax );
#ifdef PRINT_STATISTICS_3D_VIEWER
unsigned stats_startCreateBoardPolyTime = GetRunningMicroSecs();
#endif
if( aStatusTextReporter )
aStatusTextReporter->Report( _( "Build board body" ) );
createBoardPolygon();
#ifdef PRINT_STATISTICS_3D_VIEWER
unsigned stats_stopCreateBoardPolyTime = GetRunningMicroSecs();
unsigned stats_startCreateLayersTime = stats_stopCreateBoardPolyTime;
#endif
if( aStatusTextReporter )
aStatusTextReporter->Report( _( "Create layers" ) );
createLayers( aStatusTextReporter );
#ifdef PRINT_STATISTICS_3D_VIEWER
unsigned stats_stopCreateLayersTime = GetRunningMicroSecs();
printf( "CINFO3D_VISU::InitSettings times\n" );
printf( " CreateBoardPoly: %.3f ms\n",
(float)( stats_stopCreateBoardPolyTime - stats_startCreateBoardPolyTime ) / 1e3 );
printf( " CreateLayers and holes: %.3f ms\n",
(float)( stats_stopCreateLayersTime - stats_startCreateLayersTime ) / 1e3 );
printf( "\n" );
#endif
}
void CINFO3D_VISU::createBoardPolygon()
{
m_board_poly.RemoveAllContours();
// Create board outlines and board holes
SHAPE_POLY_SET allLayerHoles;
wxString errmsg;
if( !m_board->GetBoardPolygonOutlines( m_board_poly, allLayerHoles, &errmsg ) )
{
errmsg.append( wxT( "\n\n" ) );
errmsg.append( _( "Unable to calculate the board outlines." ) );
errmsg.append( wxT( "\n" ) );
errmsg.append( _( "Therefore use the board boundary box." ) );
wxLogMessage( "%s", errmsg.ToUTF8() );
}
m_board_poly.BooleanSubtract( allLayerHoles, SHAPE_POLY_SET::PM_FAST );
Polygon_Calc_BBox_3DU( m_board_poly, m_board2dBBox3DU, m_biuTo3Dunits );
}
float CINFO3D_VISU::GetModulesZcoord3DIU( bool aIsFlipped ) const
{
if( aIsFlipped )
{
if( GetFlag( FL_SOLDERPASTE ) )
return m_layerZcoordBottom[B_SilkS];
else
return m_layerZcoordBottom[B_Paste];
}
else
{
if( GetFlag( FL_SOLDERPASTE ) )
return m_layerZcoordTop[F_SilkS];
else
return m_layerZcoordTop[F_Paste];
}
}
void CINFO3D_VISU::CameraSetType( CAMERA_TYPE aCameraType )
{
switch( aCameraType )
{
case CAMERA_TRACKBALL:
m_currentCamera = m_trackBallCamera;
break;
default:
wxLogMessage( wxT( "CINFO3D_VISU::CameraSetType() error: unknown camera type %d" ),
(int)aCameraType );
break;
}
}
SFVEC3F CINFO3D_VISU::GetLayerColor( LAYER_ID aLayerId ) const
{
wxASSERT( aLayerId < LAYER_ID_COUNT );
const EDA_COLOR_T color = g_ColorsSettings.GetLayerColor( aLayerId );
const StructColors &colordata = g_ColorRefs[ColorGetBase( color )];
static const float inv_255 = 1.0f / 255.0f;
const float red = colordata.m_Red * inv_255;
const float green = colordata.m_Green * inv_255;
const float blue = colordata.m_Blue * inv_255;
return SFVEC3F( red, green, blue );
}
SFVEC3F CINFO3D_VISU::GetItemColor( int aItemId ) const
{
return GetColor( g_ColorsSettings.GetItemColor( aItemId ) );
}
SFVEC3F CINFO3D_VISU::GetColor( EDA_COLOR_T aColor ) const
{
const StructColors &colordata = g_ColorRefs[ColorGetBase( aColor )];
static const float inv_255 = 1.0f / 255.0f;
const float red = colordata.m_Red * inv_255;
const float green = colordata.m_Green * inv_255;
const float blue = colordata.m_Blue * inv_255;
return SFVEC3F( red, green, blue );
}

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -36,63 +36,25 @@
#include "../3d_rendering/3d_render_raytracing/shapes3D/cbbox.h"
#include "../3d_rendering/ccamera.h"
#include "../3d_rendering/ctrack_ball.h"
#include "../3d_enums.h"
#include "../3d_cache/3d_cache.h"
#include <layers_id_colors_and_visibility.h>
#include <class_pad.h>
#include <class_track.h>
#include <wx/gdicmn.h>
#include <wxBasePcbFrame.h>
#include <clipper.hpp>
#include <class_pcb_text.h>
#include <class_drawsegment.h>
#include <class_zone.h>
/**
* Flags used in rendering options
*/
enum DISPLAY3D_FLG {
FL_AXIS=0, FL_MODULE, FL_ZONE,
FL_ADHESIVE, FL_SILKSCREEN, FL_SOLDERMASK, FL_SOLDERPASTE,
FL_COMMENTS, FL_ECO,
FL_USE_COPPER_THICKNESS,
FL_SHOW_BOARD_BODY,
FL_USE_REALISTIC_MODE,
FL_RENDER_SHADOWS,
FL_RENDER_SHOW_HOLES_IN_ZONES,
FL_RENDER_TEXTURES,
FL_RENDER_SMOOTH_NORMALS,
FL_RENDER_USE_MODEL_NORMALS,
FL_RENDER_MATERIAL,
FL_RENDER_SHOW_MODEL_BBOX,
FL_LAST
};
/**
* Camera types
*/
enum CAMERA_TYPE
{
CAMERA_TRACKBALL
};
/**
* Grid types
*/
enum GRID3D_TYPE
{
GRID3D_NONE,
GRID3D_1MM,
GRID3D_2P5MM,
GRID3D_5MM,
GRID3D_10MM
};
#include <class_module.h>
#include <reporter.h>
/// A type that stores a container of 2d objects for each layer id
typedef std::map< LAYER_ID, CBVHCONTAINER2D *> MAP_CONTAINER_2D;
/// A type that stores polysets for each layer id
typedef std::map< LAYER_ID, SHAPE_POLY_SET *> MAP_POLY;
/// This defines the range that all coord will have to be rendered.
/// It will use this value to convert to a normalized value between
@ -112,6 +74,18 @@ class CINFO3D_VISU
~CINFO3D_VISU();
/**
* @brief Set3DCacheManager - Update the Cache manager pointer
* @param aCachePointer: the pointer to the 3d cache manager
*/
void Set3DCacheManager( S3D_CACHE *aCachePointer ) { m_3d_model_manager = aCachePointer; }
/**
* @brief Get3DCacheManager - Return the 3d cache manager pointer
* @return
*/
S3D_CACHE *Get3DCacheManager( ) const { return m_3d_model_manager; }
/**
* @brief GetFlag - get a configuration status of a flag
* @param aFlag: the flag to get the status
@ -133,6 +107,13 @@ class CINFO3D_VISU
*/
bool Is3DLayerEnabled( LAYER_ID aLayer ) const;
/**
* @brief ShouldModuleBeDisplayed - Test if module should be displayed in
* relation to attributs and the flags
* @return true if module should be displayed, false if not
*/
bool ShouldModuleBeDisplayed( MODULE_ATTR_T aModuleAttributs ) const;
/**
* @brief SetBoard - Set current board to be rendered
* @param aBoard: board to process
@ -148,18 +129,19 @@ class CINFO3D_VISU
/**
* @brief InitSettings - Function to be called by the render when it need to
* reload the settings for the board.
* @param aStatusTextReporter: the pointer for the status reporter
*/
void InitSettings();
void InitSettings( REPORTER *aStatusTextReporter );
/**
* Function BiuTo3Dunits
* @brief BiuTo3Dunits - Board integer units To 3D units
* @return the conversion factor to transform a position from the board to 3d units
*/
double BiuTo3Dunits() const { return m_biuTo3Dunits; }
/**
* @brief GetBBox3DU - Get the bbox of the pcb board
* @return
* @return the board bbox in 3d units
*/
const CBBOX &GetBBox3DU() const { return m_boardBoudingBox; }
@ -167,19 +149,19 @@ class CINFO3D_VISU
* @brief GetEpoxyThickness3DU - Get the current epoxy thickness
* @return thickness in 3d unities
*/
float GetEpoxyThickness3DU() const { return m_epoxyThickness; }
float GetEpoxyThickness3DU() const { return m_epoxyThickness3DU; }
/**
* @brief GetNonCopperLayerThickness3DU - Get the current non copper layers thickness
* @return thickness in 3d unities of non copperlayers
*/
float GetNonCopperLayerThickness3DU() const { return m_nonCopperLayerThickness; }
float GetNonCopperLayerThickness3DU() const { return m_nonCopperLayerThickness3DU; }
/**
* @brief GetCopperThickness3DU - Get the current copper layer thickness
* @return thickness in 3d unities of copperlayers
*/
float GetCopperThickness3DU() const { return m_copperThickness; }
float GetCopperThickness3DU() const { return m_copperThickness3DU; }
/**
* @brief GetCopperThicknessBIU - Get the current copper layer thickness
@ -188,26 +170,35 @@ class CINFO3D_VISU
int GetCopperThicknessBIU() const;
/**
* @brief GetBoardSize3DU - Get the board size
* @return size in 3D unities
* @brief GetBoardSizeBIU - Get the board size
* @return size in BIU unities
*/
wxSize GetBoardSize3DU() const { return m_boardSize; }
wxSize GetBoardSizeBIU() const { return m_boardSize; }
/**
* Function GetBoardCenter
* @return board center in 3d units
* @brief GetBoardPosBIU - Get the board size
* @return size in BIU unities
*/
SFVEC3F &GetBoardCenter3DU() { return m_boardCenter; }
wxPoint GetBoardPosBIU() const { return m_boardPos; }
/**
* @param aIsFlipped: true for use in modules on Front (top) layer, false
* if module is on back (bottom) layer
* @return the Z position of 3D shapes, in 3D Units
* @brief GetBoardCenter - the board center position in 3d units
* @return board center vector position in 3d units
*/
const SFVEC3F &GetBoardCenter3DU() const { return m_boardCenter; }
/**
* @brief GetModulesZcoord3DIU - Get the position of the module in 3d integer units
* considering if it is flipped or not.
* @param aIsFlipped: true for use in modules on Front (top) layer, false
* if module is on back (bottom) layer
* @return the Z position of 3D shapes, in 3D integer units
*/
float GetModulesZcoord3DIU( bool aIsFlipped ) const ;
/**
* @param aCameraType: camera type to use in this canvas
* @brief CameraSetType - Set the camera type to use
* @param aCameraType: camera type to use in this canvas
*/
void CameraSetType( CAMERA_TYPE aCameraType );
@ -218,22 +209,46 @@ class CINFO3D_VISU
CCAMERA &CameraGet() const { return m_currentCamera; }
/**
* Function GridGet
* @return space type of the grid
* @brief GridGet - get the current grid
* @return space type of the grid
*/
GRID3D_TYPE GridGet() const { return m_3D_Grid_type; }
GRID3D_TYPE GridGet() const { return m_3D_grid_type; }
/**
* Function GridSet
* @param aGridType = the type space of the grid
* @brief GridSet - set the current grid
* @param aGridType = the type space of the grid
*/
void GridSet( GRID3D_TYPE aGridType ) { m_3D_Grid_type = aGridType; }
void GridSet( GRID3D_TYPE aGridType ) { m_3D_grid_type = aGridType; }
/**
* @brief RenderEngineSet
* @param aRenderEngine = the render engine mode selected
*/
void RenderEngineSet( RENDER_ENGINE aRenderEngine ) { m_render_engine = aRenderEngine; }
/**
* @brief RenderEngineGet
* @return render engine on use
*/
RENDER_ENGINE RenderEngineGet() const { return m_render_engine; }
/**
* @brief MaterialModeSet
* @param aMaterialMode = the render material mode
*/
void MaterialModeSet( MATERIAL_MODE aMaterialMode ) { m_material_mode = aMaterialMode; }
/**
* @brief MaterialModeGet
* @return material rendering mode
*/
MATERIAL_MODE MaterialModeGet() const { return m_material_mode; }
/**
* @brief GetBoardPoly - Get the current polygon of the epoxy board
* @return the shape polygon
*/
const SHAPE_POLY_SET &GetBoardPoly() const { return m_boardPoly; }
const SHAPE_POLY_SET &GetBoardPoly() const { return m_board_poly; }
/**
* @brief GetLayerColor - get the technical color of a layer
@ -249,6 +264,13 @@ class CINFO3D_VISU
*/
SFVEC3F GetItemColor( int aItemId ) const;
/**
* @brief GetColor
* @param aColor: the color mapped
* @return the color in SFVEC3F format
*/
SFVEC3F GetColor( EDA_COLOR_T aColor ) const;
/**
* @brief GetLayerTopZpos3DU - Get the top z position
* @param aLayerId: layer id
@ -276,90 +298,365 @@ class CINFO3D_VISU
const MAP_CONTAINER_2D &GetMapLayersHoles() const { return m_layers_holes2D; }
/**
* @brief GetThroughHole_Inflated - Get the inflated ThroughHole container
* @brief GetThroughHole_Outer - Get the inflated ThroughHole container
* @return a container with holes
*/
const CBVHCONTAINER2D &GetThroughHole_Inflated() const { return m_throughHoles_inflated; }
const CBVHCONTAINER2D &GetThroughHole_Outer() const { return m_through_holes_outer; }
/**
* @brief GetThroughHole - Get the ThroughHole container
* @brief GetThroughHole_Outer_poly -
* @return
*/
const SHAPE_POLY_SET &GetThroughHole_Outer_poly() const { return m_through_outer_holes_poly; }
/**
* @brief GetThroughHole_Outer_poly_NPTH -
* @return
*/
const SHAPE_POLY_SET &GetThroughHole_Outer_poly_NPTH() const {
return m_through_outer_holes_poly_NPTH; }
/**
* @brief GetThroughHole_Vias_Outer -
* @return a container with via THT holes only
*/
const CBVHCONTAINER2D &GetThroughHole_Vias_Outer() const { return m_through_holes_vias_outer; }
/**
* @brief GetThroughHole_Vias_Inner -
* @return a container with via THT holes only
*/
const CBVHCONTAINER2D &GetThroughHole_Vias_Inner() const { return m_through_holes_vias_inner; }
/**
* @brief GetThroughHole_Vias_Outer_poly -
* @return
*/
const SHAPE_POLY_SET &GetThroughHole_Vias_Outer_poly() const {
return m_through_outer_holes_vias_poly; }
/**
* @brief GetThroughHole_Vias_Inner_poly -
* @return
*/
const SHAPE_POLY_SET &GetThroughHole_Vias_Inner_poly() const {
return m_through_inner_holes_vias_poly; }
/**
* @brief GetThroughHole_Inner - Get the ThroughHole container
* @return a container with holes
*/
const CBVHCONTAINER2D &GetThroughHole() const { return m_throughHoles; }
const CBVHCONTAINER2D &GetThroughHole_Inner() const { return m_through_holes_inner; }
/**
* @brief GetThroughHole_Inner_poly -
* @return
*/
const SHAPE_POLY_SET &GetThroughHole_Inner_poly() const { return m_through_inner_holes_poly; }
/**
* @brief GetStats_Nr_Vias - Get statistics of the nr of vias
* @return number of vias
*/
unsigned int GetStats_Nr_Vias() const { return m_stats_nr_vias; }
/**
* @brief GetStats_Nr_Holes - Get statistics of the nr of holes
* @return number of holes
*/
unsigned int GetStats_Nr_Holes() const { return m_stats_nr_holes; }
/**
* @brief GetStats_Med_Via_Hole_Diameter3DU - Average diameter of the via holes
* @return dimension in 3D units
*/
float GetStats_Med_Via_Hole_Diameter3DU() const { return m_stats_via_med_hole_diameter; }
/**
* @brief GetStats_Med_Hole_Diameter3DU - Average diameter of holes
* @return dimension in 3D units
*/
float GetStats_Med_Hole_Diameter3DU() const { return m_stats_hole_med_diameter; }
/**
* @brief GetStats_Med_Track_Width - Average width of the tracks
* @return dimensions in 3D units
*/
float GetStats_Med_Track_Width() const { return m_stats_track_med_width; }
/**
* @brief GetNrSegmentsCircle
* @param aDiameter: diameter in 3DU
* @return number of sides that should be used in that circle
*/
unsigned int GetNrSegmentsCircle( float aDiameter3DU ) const;
/**
* @brief GetNrSegmentsCircle
* @param aDiameterBUI: diameter in board unities
* @return number of sides that should be used in that circle
*/
unsigned int GetNrSegmentsCircle( int aDiameterBUI ) const;
/**
* @brief GetCircleCorrectionFactor - computes a angle correction
* factor used when creating circles
* @param aNrSides: the number of segments sides of the circle
* @return a factor to apply to contour creation
*/
double GetCircleCorrectionFactor( int aNrSides ) const;
/**
* @brief GetPolyMap - Get maps of polygons's layers
* @return the map with polygons's layers
*/
const MAP_POLY &GetPolyMap() const { return m_layers_poly; }
const MAP_POLY &GetPolyMapHoles_Inner() const { return m_layers_inner_holes_poly; }
const MAP_POLY &GetPolyMapHoles_Outer() const { return m_layers_outer_holes_poly; }
private:
void createBoardPolygon();
void createLayers();
void createLayers( REPORTER *aStatusTextReporter );
void destroyLayers();
// Helper functions to create the board
COBJECT2D *createNewTrack( const TRACK* aTrack , int aClearanceValue ) const;
void createNewPad(const D_PAD* aPad, CGENERICCONTAINER2D *aDstContainer, const wxSize &aInflateValue ) const;
void createNewPadWithClearance( const D_PAD* aPad, CGENERICCONTAINER2D *aDstContainer, int aClearanceValue ) const;
COBJECT2D *createNewPadDrill(const D_PAD* aPad, int aInflateValue);
void AddPadsShapesWithClearanceToContainer( const MODULE* aModule, CGENERICCONTAINER2D *aDstContainer, LAYER_ID aLayerId, int aInflateValue, bool aSkipNPTHPadsWihNoCopper );
void AddGraphicsShapesWithClearanceToContainer( const MODULE* aModule, CGENERICCONTAINER2D *aDstContainer, LAYER_ID aLayerId, int aInflateValue );
void AddShapeWithClearanceToContainer( const TEXTE_PCB* aTextPCB, CGENERICCONTAINER2D *aDstContainer, LAYER_ID aLayerId, int aClearanceValue );
void AddShapeWithClearanceToContainer(const DRAWSEGMENT* aDrawSegment, CGENERICCONTAINER2D *aDstContainer, LAYER_ID aLayerId, int aClearanceValue );
void AddSolidAreasShapesToContainer( const ZONE_CONTAINER* aZoneContainer, CGENERICCONTAINER2D *aDstContainer, LAYER_ID aLayerId );
void TransformArcToSegments(const wxPoint &aCentre, const wxPoint &aStart, double aArcAngle, int aCircleToSegmentsCount, int aWidth, CGENERICCONTAINER2D *aDstContainer , const BOARD_ITEM &aBoardItem);
void buildPadShapeThickOutlineAsSegments( const D_PAD* aPad, CGENERICCONTAINER2D *aDstContainer, int aWidth);
void createNewPad( const D_PAD* aPad,
CGENERICCONTAINER2D *aDstContainer,
const wxSize &aInflateValue ) const;
void createNewPadWithClearance( const D_PAD *aPad,
CGENERICCONTAINER2D *aDstContainer,
int aClearanceValue ) const;
COBJECT2D *createNewPadDrill( const D_PAD* aPad, int aInflateValue );
void AddPadsShapesWithClearanceToContainer( const MODULE *aModule,
CGENERICCONTAINER2D *aDstContainer,
LAYER_ID aLayerId,
int aInflateValue,
bool aSkipNPTHPadsWihNoCopper );
void AddGraphicsShapesWithClearanceToContainer( const MODULE *aModule,
CGENERICCONTAINER2D *aDstContainer,
LAYER_ID aLayerId,
int aInflateValue );
void AddShapeWithClearanceToContainer( const TEXTE_PCB *aTextPCB,
CGENERICCONTAINER2D *aDstContainer,
LAYER_ID aLayerId,
int aClearanceValue );
void AddShapeWithClearanceToContainer( const DRAWSEGMENT *aDrawSegment,
CGENERICCONTAINER2D *aDstContainer,
LAYER_ID aLayerId,
int aClearanceValue );
void AddSolidAreasShapesToContainer( const ZONE_CONTAINER *aZoneContainer,
CGENERICCONTAINER2D *aDstContainer,
LAYER_ID aLayerId );
void TransformArcToSegments( const wxPoint &aCentre,
const wxPoint &aStart,
double aArcAngle,
int aCircleToSegmentsCount,
int aWidth,
CGENERICCONTAINER2D *aDstContainer,
const BOARD_ITEM &aBoardItem );
void buildPadShapeThickOutlineAsSegments( const D_PAD *aPad,
CGENERICCONTAINER2D *aDstContainer,
int aWidth );
// Helper functions to create poly contours
void buildPadShapeThickOutlineAsPolygon( const D_PAD *aPad,
SHAPE_POLY_SET &aCornerBuffer,
int aWidth) const;
void transformPadsShapesWithClearanceToPolygon( const DLIST<D_PAD> &aPads,
LAYER_ID aLayer,
SHAPE_POLY_SET &aCornerBuffer,
int aInflateValue,
bool aSkipNPTHPadsWihNoCopper) const;
void transformGraphicModuleEdgeToPolygonSet( const MODULE *aModule,
LAYER_ID aLayer,
SHAPE_POLY_SET& aCornerBuffer ) const;
void buildPadShapePolygon( const D_PAD *aPad,
SHAPE_POLY_SET &aCornerBuffer,
wxSize aInflateValue,
int aSegmentsPerCircle,
double aCorrectionFactor ) const;
public:
wxColour m_BgColor;
wxColour m_BgColor_Top;
SFVEC3D m_BgColorBot; ///< background bottom color
SFVEC3D m_BgColorTop; ///< background top color
SFVEC3D m_BoardBodyColor; ///< in realistic mode: FR4 board color
SFVEC3D m_SolderMaskColor; ///< in realistic mode: solder mask color
SFVEC3D m_SolderPasteColor; ///< in realistic mode: solder paste color
SFVEC3D m_SilkScreenColor; ///< in realistic mode: SilkScreen color
SFVEC3D m_CopperColor; ///< in realistic mode: copper color
private:
/// Current board
BOARD *m_board;
/// pointer to the 3d model manager
S3D_CACHE *m_3d_model_manager;
// Render options
std::vector< bool > m_drawFlags; ///< options flags to render the board
GRID3D_TYPE m_3D_Grid_type; ///< Stores the current grid type
/// options flags to render the board
std::vector< bool > m_drawFlags;
/// Stores the current grid type
GRID3D_TYPE m_3D_grid_type;
/// render engine currently on use
RENDER_ENGINE m_render_engine;
/// mode to render the 3d shape models material
MATERIAL_MODE m_material_mode;
// Pcb board position
wxPoint m_boardPos; ///< center board actual position in board units
wxSize m_boardSize; ///< board actual size in board units
SFVEC3F m_boardCenter; ///< 3d center position of the pcb board in 3d units
/// center board actual position in board units
wxPoint m_boardPos;
/// board actual size in board units
wxSize m_boardSize;
/// 3d center position of the pcb board in 3d units
SFVEC3F m_boardCenter;
// Pcb board bounding boxes
CBBOX m_boardBoudingBox; ///< 3d bouding box of the pcb board in 3d units
CBBOX2D m_board2dBBox3DU; ///< 2d bouding box of the pcb board in 3d units
SHAPE_POLY_SET m_boardPoly; ///< PCB board outline polygon
/// 3d bouding box of the pcb board in 3d units
CBBOX m_boardBoudingBox;
/// 2d bouding box of the pcb board in 3d units
CBBOX2D m_board2dBBox3DU;
/// It contains polygon contours for each layer
MAP_POLY m_layers_poly;
/// It contains polygon contours for holes of each layer (outer holes)
MAP_POLY m_layers_outer_holes_poly;
/// It contains polygon contours for holes of each layer (inner holes)
MAP_POLY m_layers_inner_holes_poly;
/// It contains polygon contours for (just) non plated through holes (outer cylinder)
SHAPE_POLY_SET m_through_outer_holes_poly_NPTH;
/// It contains polygon contours for through holes (outer cylinder)
SHAPE_POLY_SET m_through_outer_holes_poly;
/// It contains polygon contours for through holes (inner cylinder)
SHAPE_POLY_SET m_through_inner_holes_poly;
/// It contains polygon contours for through holes vias (outer cylinder)
SHAPE_POLY_SET m_through_outer_holes_vias_poly;
/// It contains polygon contours for through holes vias (inner cylinder)
SHAPE_POLY_SET m_through_inner_holes_vias_poly;
/// PCB board outline polygon
SHAPE_POLY_SET m_board_poly;
// 2D element containers
MAP_CONTAINER_2D m_layers_container2D; ///< It contains the 2d elements of each layer
MAP_CONTAINER_2D m_layers_holes2D; ///< It contains the holes per each layer
CBVHCONTAINER2D m_throughHoles_inflated; ///< It contains the list of throughHoles of the board, the radius of the hole is inflated with the copper tickness
CBVHCONTAINER2D m_throughHoles; ///< It contains the list of throughHoles of the board, the radius of the hole is inflated with the copper tickness
/// It contains the 2d elements of each layer
MAP_CONTAINER_2D m_layers_container2D;
/// It contains the holes per each layer
MAP_CONTAINER_2D m_layers_holes2D;
/// It contains the list of throughHoles of the board,
/// the radius of the hole is inflated with the copper tickness
CBVHCONTAINER2D m_through_holes_outer;
/// It contains the list of throughHoles of the board,
/// the radius is the inner hole
CBVHCONTAINER2D m_through_holes_inner;
/// It contains the list of throughHoles vias of the board,
/// the radius of the hole is inflated with the copper tickness
CBVHCONTAINER2D m_through_holes_vias_outer;
/// It contains the list of throughHoles vias of the board,
/// the radius of the hole
CBVHCONTAINER2D m_through_holes_vias_inner;
// Layers information
unsigned int m_copperLayersCount; ///< Number of copper layers actually used by the board
double m_biuTo3Dunits; ///< Normalization scale to convert board internal units to 3D units to normalize 3D units between -1.0 and +1.0
float m_layerZcoordTop[LAYER_ID_COUNT]; ///< Top (End) Z position of each layer (normalized)
float m_layerZcoordBottom[LAYER_ID_COUNT]; ///< Bottom (Start) Z position of each layer (normalized)
float m_copperThickness; ///< Copper thickness (normalized)
float m_epoxyThickness; ///< Epoxy thickness (normalized)
float m_nonCopperLayerThickness; ///< Non copper layers thickness
/// Number of copper layers actually used by the board
unsigned int m_copperLayersCount;
/// Normalization scale to convert board internal units to 3D units to
/// normalize 3D units between -1.0 and +1.0
double m_biuTo3Dunits;
/// Top (End) Z position of each layer (normalized)
float m_layerZcoordTop[LAYER_ID_COUNT];
/// Bottom (Start) Z position of each layer (normalized)
float m_layerZcoordBottom[LAYER_ID_COUNT];
/// Copper thickness (normalized)
float m_copperThickness3DU;
/// Epoxy thickness (normalized)
float m_epoxyThickness3DU;
/// Non copper layers thickness
float m_nonCopperLayerThickness3DU;
// Cameras
CCAMERA &m_currentCamera; ///< Holds a pointer to current camera in use.
/// Holds a pointer to current camera in use.
CCAMERA &m_currentCamera;
CTRACK_BALL m_trackBallCamera;
/// min factor used for cicle segment approximation calculation
float m_calc_seg_min_factor3DU;
/// max factor used for cicle segment approximation calculation
float m_calc_seg_max_factor3DU;
// Statistics
/// Number of tracks in the board
unsigned int m_stats_nr_tracks;
/// Track average width
float m_stats_track_med_width;
unsigned int m_stats_nr_vias; ///< Nr of vias
float m_stats_via_med_hole_diameter; ///< Computed medium diameter of the via holes in 3dunits
/// Nr of vias
unsigned int m_stats_nr_vias;
/// Computed medium diameter of the via holes in 3D units
float m_stats_via_med_hole_diameter;
/// number of holes in the board
unsigned int m_stats_nr_holes;
float m_stats_hole_med_diameter; ///< Computed medium diameter of the holes in 3dunits
/// Computed medium diameter of the holes in 3D units
float m_stats_hole_med_diameter;
/**
* Trace mask used to enable or disable the trace output of this class.
@ -371,6 +668,7 @@ class CINFO3D_VISU
};
/// This is a dummy visualization configuration
extern CINFO3D_VISU G_null_CINFO3D_VISU;
#endif // CINFO3D_VISU_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,226 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file create_layer_poly.cpp
* @brief This file implements the creation of the pcb board items in the poly
* contours format. It is based on the function found in the files:
* board_items_to_polygon_shape_transform.cpp
* board_items_to_polygon_shape_transform.cpp
*/
#include "cinfo3d_visu.h"
#include <convert_basic_shapes_to_polygon.h>
#include <class_edge_mod.h>
#include <class_module.h>
// This is the same function as in board_items_to_polygon_shape_transform.cpp
// but it adds the rect/trapezoid shapes with a different winding
void CINFO3D_VISU::buildPadShapePolygon( const D_PAD* aPad,
SHAPE_POLY_SET& aCornerBuffer,
wxSize aInflateValue,
int aSegmentsPerCircle,
double aCorrectionFactor ) const
{
wxPoint corners[4];
wxPoint PadShapePos = aPad->ShapePos(); /* Note: for pad having a shape offset,
* the pad position is NOT the shape position */
switch( aPad->GetShape() )
{
case PAD_SHAPE_CIRCLE:
case PAD_SHAPE_OVAL:
case PAD_SHAPE_ROUNDRECT:
aPad->TransformShapeWithClearanceToPolygon( aCornerBuffer, aInflateValue.x,
aSegmentsPerCircle, aCorrectionFactor );
break;
case PAD_SHAPE_TRAPEZOID:
case PAD_SHAPE_RECT:
{
SHAPE_LINE_CHAIN aLineChain;
aPad->BuildPadPolygon( corners, aInflateValue, aPad->GetOrientation() );
for( int ii = 0; ii < 4; ++ii )
{
corners[3-ii] += PadShapePos; // Shift origin to position
aLineChain.Append( corners[3-ii].x, corners[3-ii].y );
}
aLineChain.SetClosed( true );
aCornerBuffer.AddOutline( aLineChain );
}
break;
default:
wxFAIL_MSG( wxT( "CINFO3D_VISU::buildPadShapePolygon: found a not implemented pad shape (new shape?)" ) );
break;
}
}
void CINFO3D_VISU::buildPadShapeThickOutlineAsPolygon( const D_PAD* aPad,
SHAPE_POLY_SET& aCornerBuffer,
int aWidth ) const
{
if( aPad->GetShape() == PAD_SHAPE_CIRCLE ) // Draw a ring
{
unsigned int nr_sides_per_circle = GetNrSegmentsCircle( ( aPad->GetSize().x / 2 +
aWidth / 2 ) * 2 );
TransformRingToPolygon( aCornerBuffer, aPad->ShapePos(),
aPad->GetSize().x / 2, nr_sides_per_circle, aWidth );
return;
}
// For other shapes, draw polygon outlines
SHAPE_POLY_SET corners;
unsigned int nr_sides_per_circle = GetNrSegmentsCircle( glm::min( aPad->GetSize().x,
aPad->GetSize().y) );
buildPadShapePolygon( aPad, corners, wxSize( 0, 0 ),
nr_sides_per_circle, GetCircleCorrectionFactor( nr_sides_per_circle ) );
// Add outlines as thick segments in polygon buffer
const SHAPE_LINE_CHAIN& path = corners.COutline( 0 );
for( int ii = 0; ii < path.PointCount(); ++ii )
{
const VECTOR2I& a = path.CPoint( ii );
const VECTOR2I& b = path.CPoint( ii + 1 );
TransformRoundedEndsSegmentToPolygon( aCornerBuffer,
wxPoint( a.x, a.y ),
wxPoint( b.x, b.y ),
nr_sides_per_circle,
aWidth );
}
}
// Based on the same function name in board_items_to_polyshape_transform.cpp
// It was implemented here to allow dynamic segments count per pad shape
void CINFO3D_VISU::transformPadsShapesWithClearanceToPolygon( const DLIST<D_PAD>& aPads, LAYER_ID aLayer,
SHAPE_POLY_SET& aCornerBuffer,
int aInflateValue,
bool aSkipNPTHPadsWihNoCopper ) const
{
const D_PAD* pad = aPads;
wxSize margin;
for( ; pad != NULL; pad = pad->Next() )
{
if( !pad->IsOnLayer(aLayer) )
continue;
// NPTH pads are not drawn on layers if the shape size and pos is the same
// as their hole:
if( aSkipNPTHPadsWihNoCopper && (pad->GetAttribute() == PAD_ATTRIB_HOLE_NOT_PLATED) )
{
if( (pad->GetDrillSize() == pad->GetSize()) &&
(pad->GetOffset() == wxPoint( 0, 0 )) )
{
switch( pad->GetShape() )
{
case PAD_SHAPE_CIRCLE:
if( pad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE )
continue;
break;
case PAD_SHAPE_OVAL:
if( pad->GetDrillShape() != PAD_DRILL_SHAPE_CIRCLE )
continue;
break;
default:
break;
}
}
}
switch( aLayer )
{
case F_Mask:
case B_Mask:
margin.x = margin.y = pad->GetSolderMaskMargin() + aInflateValue;
break;
case F_Paste:
case B_Paste:
margin = pad->GetSolderPasteMargin();
margin.x += aInflateValue;
margin.y += aInflateValue;
break;
default:
margin.x = margin.y = aInflateValue;
break;
}
unsigned int aCircleToSegmentsCount = GetNrSegmentsCircle( pad->GetSize().x );
double aCorrectionFactor = GetCircleCorrectionFactor( aCircleToSegmentsCount );
buildPadShapePolygon( pad, aCornerBuffer, margin,
aCircleToSegmentsCount, aCorrectionFactor );
}
}
void CINFO3D_VISU::transformGraphicModuleEdgeToPolygonSet( const MODULE *aModule,
LAYER_ID aLayer,
SHAPE_POLY_SET& aCornerBuffer ) const
{
for( const EDA_ITEM* item = aModule->GraphicalItems();
item != NULL;
item = item->Next() )
{
switch( item->Type() )
{
case PCB_MODULE_EDGE_T:
{
EDGE_MODULE*outline = (EDGE_MODULE*) item;
if( outline->GetLayer() != aLayer )
break;
unsigned int aCircleToSegmentsCount =
GetNrSegmentsCircle( outline->GetBoundingBox().GetSizeMax() );
double aCorrectionFactor = GetCircleCorrectionFactor( aCircleToSegmentsCount );
outline->TransformShapeWithClearanceToPolygon( aCornerBuffer,
0,
aCircleToSegmentsCount,
aCorrectionFactor );
}
break;
default:
break;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,279 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file eda_3d_canvas.h
* @brief
*/
#ifndef EDA_3D_CANVAS_H
#define EDA_3D_CANVAS_H
#include "cinfo3d_visu.h"
#include "3d_rendering/c3d_render_base.h"
#include "3d_rendering/3d_render_ogl_legacy/c3d_render_ogl_legacy.h"
#include "3d_rendering/3d_render_raytracing/c3d_render_raytracing.h"
#include "3d_cache/3d_cache.h"
#include <wx/clipbrd.h>
#include <wx/dataobj.h>
#include <wx/glcanvas.h>
#include <wx/image.h>
#include <wx/wupdlock.h>
#include <wx/timer.h>
#include <wx/statusbr.h>
#include <wxBasePcbFrame.h>
/**
* Class EDA_3D_CANVAS
* Implement a canvas based on a wxGLCanvas
*/
class EDA_3D_CANVAS : public wxGLCanvas
{
public:
/**
* @brief EDA_3D_CANVAS - Creates a new 3D Canvas with a attribute list
* @param aParent: the parent creator of this canvas
* @param aAttribList: a list of openGL options created by GetOpenGL_AttributesList
* @param aBoard: The board
* @param aSettings: the settings options to be used by this canvas
*/
EDA_3D_CANVAS( wxWindow *aParent,
const int *aAttribList = 0,
BOARD *aBoard = NULL,
CINFO3D_VISU &aSettings = G_null_CINFO3D_VISU,
S3D_CACHE *a3DCachePointer = NULL );
~EDA_3D_CANVAS();
void SetStatusBar( wxStatusBar *aStatusBar ) { m_parentStatusBar = aStatusBar; }
void ReloadRequest( BOARD *aBoard = NULL, S3D_CACHE *aCachePointer = NULL );
/**
* @brief IsReloadRequestPending - Query if there is a pending reload request
* @return true if it wants to reload, false if there is no reload pending
*/
bool IsReloadRequestPending() const
{
if( m_3d_render )
return m_3d_render->IsReloadRequestPending();
else
return false;
}
/**
* @brief RenderRaytracingRequest - Request to render the current view in Raytracing mode
*/
void RenderRaytracingRequest();
/**
* Request a screenshot and output it to the aDstImage
* @param aDstImage - Screenshot destination image
*/
void GetScreenshot( wxImage &aDstImage );
/**
* @brief SetView3D - Helper function to call view commands
* @param keycode: ascii key commands
*/
void SetView3D( int keycode );
/**
* @brief RenderEngineChanged - Notify that the render engine was changed
*/
void RenderEngineChanged();
/**
* @brief DisplayStatus - Update the status bar with the position information
*/
void DisplayStatus();
/**
* @brief Request_refresh - Schedule a refresh update of the canvas
* @param aRedrawImmediately - true will request a redraw, false will
* schedule a redraw, after a short timeout.
*/
void Request_refresh( bool aRedrawImmediately = true );
private:
void OnPaint( wxPaintEvent &event );
void OnEraseBackground( wxEraseEvent &event );
void OnMouseWheel( wxMouseEvent &event );
#if wxCHECK_VERSION( 3, 1, 0 ) || defined( USE_OSX_MAGNIFY_EVENT )
void OnMagnify( wxMouseEvent& event );
#endif
void OnMouseMove( wxMouseEvent &event );
void OnLeftDown( wxMouseEvent &event );
void OnLeftUp( wxMouseEvent &event );
void OnMiddleUp( wxMouseEvent &event );
void OnMiddleDown( wxMouseEvent &event );
void OnRightClick( wxMouseEvent &event );
void OnPopUpMenu( wxCommandEvent &event );
void OnCharHook( wxKeyEvent& event );
void OnKeyEvent( wxKeyEvent& event );
void OnTimerTimeout_Editing( wxTimerEvent& event );
/**
* @brief OnCloseWindow - called when the frame is closed
* @param event
*/
void OnCloseWindow( wxCloseEvent &event );
void OnTimerTimeout_Redraw( wxTimerEvent& event );
DECLARE_EVENT_TABLE();
private:
/**
* @brief stop_editingTimeOut_Timer - stop the editing time, so it will not timeout
*/
void stop_editingTimeOut_Timer();
/**
* @brief restart_editingTimeOut_Timer - reset the editing timer
*/
void restart_editingTimeOut_Timer();
/**
* @brief request_start_moving_camera - start a camera movement
* @param aMovingSpeed: the time speed
* @param aRenderPivot: if it should display pivot cursor while move
*/
void request_start_moving_camera( float aMovingSpeed = 2.0f,
bool aRenderPivot = true );
/**
* @brief move_pivot_based_on_cur_mouse_position -
* This function hits a ray to the board and start a moviment
*/
void move_pivot_based_on_cur_mouse_position();
/**
* @brief render_pivot - render the pivot cursor
* @param t: time between 0.0 and 1.0
* @param aScale: scale to apply on the cursor
*/
void render_pivot( float t, float aScale );
/**
* @brief initializeOpenGL
* @return if OpenGL initialization succeed
*/
bool initializeOpenGL();
/**
* @brief releaseOpenGL - free created targets and openGL context
*/
void releaseOpenGL();
private:
/// current OpenGL context
wxGLContext *m_glRC;
/// Parent statusbar to report progress
wxStatusBar *m_parentStatusBar;
/// Time timeout will expires after some time sinalizing that the mouse /
/// keyboard movements are over.
wxTimer m_editing_timeout_timer;
/// This timer will be used to schedule a redraw event
wxTimer m_redraw_trigger_timer;
/// true if mouse activity is on progress
bool m_mouse_is_moving;
/// true if there was some type of activity, it will be used to render in
/// preview mode
bool m_mouse_was_moved;
/// true if camera animation is ongoing
bool m_camera_is_moving;
/// activated the render of pivot while camera moving
bool m_render_pivot;
/// 1.0f will be 1:1
float m_camera_moving_speed;
/// Stores the ticktime when the camera star its movement
unsigned m_strtime_camera_movement;
/// Stores all pre-computed 3D information and visualization settings to render the board
CINFO3D_VISU &m_settings;
/// The current render in used for this canvas
C3D_RENDER_BASE *m_3d_render;
/// Raytracing render class
C3D_RENDER_RAYTRACING *m_3d_render_raytracing;
/// OpenGL legacy render class
C3D_RENDER_OGL_LEGACY *m_3d_render_ogl_legacy;
/// Flag to store if opengl was initialized already
bool m_is_opengl_initialized;
/// Step factor to used with cursor on relation to the current zoom
static const float m_delta_move_step_factor;
/// Flags that the user requested the current view to be render with raytracing
bool m_render_raytracing_was_requested;
/**
* Trace mask used to enable or disable the trace output of this class.
* The debug output can be turned on by setting the WXTRACE environment variable to
* "KI_TRACE_EDA_3D_CANVAS". See the wxWidgets documentation on wxLogTrace for
* more information.
*/
static const wxChar *m_logTrace;
};
#endif // EDA_3D_CANVAS_H

View File

@ -0,0 +1,122 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file eda_3d_canvas_pivot.cpp
* @brief Implementation of a 3d cursor
*/
#include "../common_ogl/openGL_includes.h"
#include "../common_ogl/ogl_utils.h"
#include "eda_3d_canvas.h"
static void pivot_render_triangles( float t )
{
wxASSERT( t >= 0.0f );
SFVEC3F vertexPointer[12];
const float u = 1.0f / 6.0f;
vertexPointer[0] = SFVEC3F( (-3.0f + t) * u, -2.0f * u, 0.0f );
vertexPointer[1] = SFVEC3F( (-3.0f + t) * u, 2.0f * u, 0.0f );
vertexPointer[2] = SFVEC3F( (-1.0f + t) * u, 0.0f * u, 0.0f );
vertexPointer[3] = SFVEC3F( -2.0f * u, (-3.0f + t) * u, 0.0f );
vertexPointer[4] = SFVEC3F( 2.0f * u, (-3.0f + t) * u, 0.0f );
vertexPointer[5] = SFVEC3F( 0.0f * u, (-1.0f + t) * u, 0.0f );
vertexPointer[6] = SFVEC3F( (3.0f - t) * u, -2.0f * u, 0.0f );
vertexPointer[7] = SFVEC3F( (3.0f - t) * u, 2.0f * u, 0.0f );
vertexPointer[8] = SFVEC3F( (1.0f - t) * u, 0.0f * u, 0.0f );
vertexPointer[9] = SFVEC3F( 2.0f * u, (3.0f - t) * u, 0.0f );
vertexPointer[10] = SFVEC3F( -2.0f * u, (3.0f - t) * u, 0.0f );
vertexPointer[11] = SFVEC3F( 0.0f * u, (1.0f - t) * u, 0.0f );
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
glDisableClientState( GL_COLOR_ARRAY );
glDisableClientState( GL_NORMAL_ARRAY );
glEnableClientState( GL_VERTEX_ARRAY );
glVertexPointer( 3, GL_FLOAT, 0, vertexPointer );
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glDrawArrays( GL_TRIANGLES, 0, 4 * 3 );
glDisable( GL_BLEND );
glDisableClientState( GL_VERTEX_ARRAY );
}
void EDA_3D_CANVAS::render_pivot( float t , float aScale )
{
wxASSERT( aScale >= 0.0f );
wxASSERT( t >= 0.0f );
if( t > 1.0f )
t = 1.0f;
const SFVEC3F &lookAtPos = m_settings.CameraGet().GetLookAtPos_T1();
glDisable( GL_LIGHTING );
glDisable( GL_DEPTH_TEST );
glDisable( GL_CULL_FACE );
// Set projection and modelview matrixes
// /////////////////////////////////////////////////////////////////////////
glMatrixMode( GL_PROJECTION );
glLoadMatrixf( glm::value_ptr( m_settings.CameraGet().GetProjectionMatrix() ) );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glLoadMatrixf( glm::value_ptr( m_settings.CameraGet().GetViewMatrix() ) );
glEnable( GL_COLOR_MATERIAL );
glColor4f( 0.0f, 1.0f, 0.0f, 0.75f - t * 0.75f );
// Translate to the look at position
glTranslatef( lookAtPos.x, lookAtPos.y, lookAtPos.z );
glScalef( aScale, aScale, aScale );
pivot_render_triangles( t * 0.5f );
t = t * 0.80f;
glScalef( 1.0f - t, 1.0f - t, 1.0f - t );
glColor4f( 0.0f, 1.0f, 0.0f, 0.8f - t );
glPushMatrix();
glRotatef( t * 90.0f, 0.0f, 0.0f, 1.0f );
pivot_render_triangles( t * 0.5f );
glPopMatrix();
glPushMatrix();
glRotatef( -t * 90.0f, 0.0f, 0.0f, 1.0f );
pivot_render_triangles( t * 0.5f );
glPopMatrix();
}

View File

@ -0,0 +1,68 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file status_text_reporter.h
* @brief
*/
#ifndef STATUS_TEXT_REPORTER_H_
#define STATUS_TEXT_REPORTER_H_
#include <reporter.h>
/**
* Class STATUS_TEXT_REPORTER
* is a wrapper for reporting to a wxString in a wxFrame status text.
*/
class STATUS_TEXT_REPORTER : public REPORTER
{
private:
wxStatusBar *m_parentStatusBar;
int m_position;
bool m_hasMessage;
public:
STATUS_TEXT_REPORTER( wxStatusBar* aParentStatusBar, int aPosition = 0 ) :
REPORTER(),
m_parentStatusBar( aParentStatusBar ), m_position( aPosition )
{
m_hasMessage = false;
}
REPORTER& Report( const wxString& aText, SEVERITY aSeverity = RPT_UNDEFINED )
{
if( !aText.IsEmpty() )
m_hasMessage = true;
if( m_parentStatusBar )
m_parentStatusBar->SetStatusText( aText, m_position );
return *this;
}
bool HasMessage() const { return m_hasMessage; }
};
#endif // STATUS_TEXT_REPORTER_H_

View File

@ -1,181 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file 3d_class.cpp
*/
#include <fctsys.h>
#include "3d_viewer.h"
#include "3d_struct.h"
#include "common.h"
#include "modelparsers.h"
#include <kiway.h>
#include <3d_cache.h>
#include <3d_filename_resolver.h>
extern KIWAY* TheKiway;
void S3D_MASTER::Insert( S3D_MATERIAL* aMaterial )
{
aMaterial->SetNext( m_Materials );
m_Materials = aMaterial;
}
void S3D_MASTER::Copy( S3D_MASTER* pattern )
{
SetShape3DName( pattern->GetShape3DName() );
m_MatScale = pattern->m_MatScale;
m_MatRotation = pattern->m_MatRotation;
m_MatPosition = pattern->m_MatPosition;
m_3D_Drawings = NULL;
m_Materials = NULL;
}
S3D_MASTER::S3D_MASTER( EDA_ITEM* aParent ) :
EDA_ITEM( aParent, NOT_USED )
{
m_MatScale.x = m_MatScale.y = m_MatScale.z = 1.0;
m_3D_Drawings = NULL;
m_Materials = NULL;
m_parser = NULL;
m_ShapeType = FILE3D_NONE;
m_use_modelfile_diffuseColor = true;
m_use_modelfile_emissiveColor = true;
m_use_modelfile_specularColor = true;
m_use_modelfile_ambientIntensity = true;
m_use_modelfile_transparency = true;
m_use_modelfile_shininess = true;
}
S3D_MASTER:: ~S3D_MASTER()
{
STRUCT_3D_SHAPE* next;
S3D_MATERIAL* nextmat;
for( ; m_3D_Drawings != NULL; m_3D_Drawings = next )
{
next = m_3D_Drawings->Next();
delete m_3D_Drawings;
m_3D_Drawings = 0;
}
for( ; m_Materials != NULL; m_Materials = nextmat )
{
nextmat = m_Materials->Next();
delete m_Materials;
m_Materials = NULL;
}
}
bool S3D_MASTER::Is3DType( enum FILE3D_TYPE aShapeType )
{
// type 'none' is not valid and will always return false
if( aShapeType == FILE3D_NONE )
return false;
// no one is interested if we have no file
if( m_Shape3DName.empty() )
return false;
if( aShapeType == m_ShapeType )
return true;
return false;
}
void S3D_MASTER::SetShape3DName( const wxString& aShapeName )
{
m_ShapeType = FILE3D_NONE;
m_Shape3DName = aShapeName;
if( m_Shape3DName.empty() )
return;
wxFileName fn = m_Shape3DName;
m_Shape3DNameExtension = fn.GetExt();
if( m_Shape3DNameExtension == wxT( "wrl" ) ||
m_Shape3DNameExtension == wxT( "x3d" ) )
m_ShapeType = FILE3D_VRML;
else if( m_Shape3DNameExtension == wxT( "idf" ) )
m_ShapeType = FILE3D_IDF;
else
m_ShapeType = FILE3D_UNKNOWN;
// Expand any environment variables embedded in footprint's m_Shape3DName field.
// To ensure compatibility with most of footprint's m_Shape3DName field,
// if the m_Shape3DName is not an absolute path the default path
// given by the environment variable KISYS3DMOD will be used
if( m_Shape3DName.StartsWith( wxT("${") ) ||
m_Shape3DName.StartsWith( wxT("$(") ) )
m_Shape3DFullFilename = ExpandEnvVarSubstitutions( m_Shape3DName );
else
m_Shape3DFullFilename = m_Shape3DName;
if( NULL != TheKiway )
{
m_Shape3DFullFilename = TheKiway->Prj().Get3DCacheManager()->GetResolver()
->ResolvePath( m_Shape3DFullFilename );
}
return;
}
const wxString S3D_MASTER::GetShape3DFullFilename()
{
return m_Shape3DFullFilename;
}
const wxString S3D_MASTER::GetShape3DExtension()
{
return m_Shape3DNameExtension;
}
STRUCT_3D_SHAPE::STRUCT_3D_SHAPE( EDA_ITEM* aParent ) :
EDA_ITEM( aParent, NOT_USED )
{
m_3D_Coord = NULL;
m_3D_CoordIndex = NULL;
m_3D_Points = 0;
}
STRUCT_3D_SHAPE:: ~STRUCT_3D_SHAPE()
{
delete m_3D_Coord;
delete m_3D_CoordIndex;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,426 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2012 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file 3d_draw_basic_functions.cpp
*/
#include <fctsys.h>
#include <trigo.h>
#include <convert_basic_shapes_to_polygon.h>
#include <3d_viewer.h>
#include <info3d_visu.h>
#include <3d_draw_basic_functions.h>
#include <modelparsers.h>
// Number of segments to approximate a circle by segments
#define SEGM_PER_CIRCLE 24
#ifndef CALLBACK
#define CALLBACK
#endif
// Variables used to pass a value to call back openGL functions
static float s_textureScale;
static double s_currentZpos;
static double s_biuTo3Dunits;
bool s_useTextures;
// CALLBACK functions for GLU_TESS
static void CALLBACK tessBeginCB( GLenum which );
static void CALLBACK tessEndCB();
static void CALLBACK tessErrorCB( GLenum errorCode );
static void CALLBACK tessCPolyPt2Vertex( const GLvoid* data );
void TransfertToGLlist( std::vector< S3D_VERTEX >& aVertices, double aBiuTo3DUnits );
/* Draw3D_VerticalPolygonalCylinder is a helper function.
*
* draws a "vertical cylinder" having a polygon shape
* from Z position = aZpos to aZpos + aHeight
* Used to create the vertical sides of 3D horizontal shapes with thickness.
*/
static void Draw3D_VerticalPolygonalCylinder( const SHAPE_POLY_SET& aPolysList,
int aHeight, int aZpos,
bool aInside, double aBiuTo3DUnits )
{
if( aHeight == 0 )
return;
std::vector<S3D_VERTEX> coords;
coords.resize( 4 );
// Init Z position of the 4 points of a GL_QUAD
if( aInside )
{
coords[0].z = aZpos;
coords[1].z = aZpos + aHeight;
}
else
{
coords[0].z = aZpos + aHeight;
coords[1].z = aZpos;
}
coords[2].z = coords[1].z;
coords[3].z = coords[0].z;
// Draw the vertical polygonal side
for( int idx = 0; idx < aPolysList.OutlineCount(); idx++ )
{
// Each polygon in aPolysList is a polygon with holes
const SHAPE_POLY_SET::POLYGON& curr_polywithholes = aPolysList.CPolygon( idx );
// Draw the outline of each simple polygon inside the polygon with holes:
for( unsigned ipoly = 0; ipoly < curr_polywithholes.size(); ipoly++ )
{
const SHAPE_LINE_CHAIN& path = curr_polywithholes[ipoly]; // a simple polygon
for( int jj = 0; jj < path.PointCount(); jj++ )
{
const VECTOR2I& a = path.CPoint( jj );
const VECTOR2I& b = path.CPoint( jj + 1 );
// Build the 4 vertices of each GL_QUAD
coords[0].x = a.x;
coords[0].y = -a.y;
coords[1].x = coords[0].x;
coords[1].y = coords[0].y; // only z change
coords[2].x = b.x;
coords[2].y = -b.y;
coords[3].x = coords[2].x;
coords[3].y = coords[2].y; // only z change
// Creates the GL_QUAD
TransfertToGLlist( coords, aBiuTo3DUnits );
}
}
}
}
void SetGLColor( EDA_COLOR_T color, double alpha )
{
const StructColors &colordata = g_ColorRefs[ColorGetBase( color )];
float red = colordata.m_Red / 255.0;
float blue = colordata.m_Blue / 255.0;
float green = colordata.m_Green / 255.0;
glColor4f( red, green, blue, (float)alpha );
}
void SetGLColor( S3D_COLOR& aColor, float aTransparency )
{
glColor4f( aColor.m_Red, aColor.m_Green, aColor.m_Blue, aTransparency );
}
void SetGLTexture( GLuint text_id, float scale )
{
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, text_id );
s_textureScale = scale; // for Tess callback functions
}
/* draw all solid polygons found in aPolysList
* aZpos = z position in board internal units
* aThickness = thickness in board internal units
* If aThickness = 0, a polygon area is drawn in a XY plane at Z position = aZpos.
* If aThickness > 0, a solid object is drawn.
* The top side is located at aZpos + aThickness / 2
* The bottom side is located at aZpos - aThickness / 2
*/
void Draw3D_SolidHorizontalPolyPolygons( const SHAPE_POLY_SET& aPolysList,
int aZpos, int aThickness, double aBiuTo3DUnits,
bool aUseTextures,
float aNormal_Z_Orientation )
{
// for Tess callback functions:
s_biuTo3Dunits = aBiuTo3DUnits;
s_useTextures = aUseTextures;
GLUtesselator* tess = gluNewTess();
gluTessCallback( tess, GLU_TESS_BEGIN, ( void (CALLBACK*) () )tessBeginCB );
gluTessCallback( tess, GLU_TESS_END, ( void (CALLBACK*) () )tessEndCB );
gluTessCallback( tess, GLU_TESS_ERROR, ( void (CALLBACK*) () )tessErrorCB );
gluTessCallback( tess, GLU_TESS_VERTEX, ( void (CALLBACK*) () )tessCPolyPt2Vertex );
GLdouble v_data[3];
double zpos = ( aZpos + (aThickness / 2.0) ) * aBiuTo3DUnits;
s_currentZpos = zpos; // for Tess callback functions
v_data[2] = zpos;
// Set normal toward positive Z axis, for a solid object on the top side
//gluTessProperty( tess, GLU_TESS_BOUNDARY_ONLY, GL_FALSE );
gluTessProperty( tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD );
glNormal3f( 0.0, 0.0, aNormal_Z_Orientation );
// Draw solid areas contained in this list
SHAPE_POLY_SET polylist = aPolysList; // temporary copy for gluTessVertex
for( int side = 0; side < 2; side++ )
{
for ( int idx = 0; idx < polylist.OutlineCount(); ++idx )
{
gluTessBeginPolygon( tess, NULL );
SHAPE_POLY_SET::POLYGON& curr_polywithholes = polylist.Polygon( idx ); // a polygon with holes
for( unsigned ipoly = 0; ipoly < curr_polywithholes.size(); ipoly++ )
{
SHAPE_LINE_CHAIN& curr_poly = curr_polywithholes[ipoly]; // a simple polygon
gluTessBeginContour( tess );
for( int ipt = 0; ipt < curr_poly.PointCount(); ipt++ )
{
v_data[0] = curr_poly.Point( ipt ).x * aBiuTo3DUnits;
v_data[1] = -curr_poly.Point( ipt ).y * aBiuTo3DUnits;
// gluTessVertex store pointers on data, not data, so do not store
// different corners values in a temporary variable
// but send pointer on each CPolyPt value in polylist
// before calling gluDeleteTess
gluTessVertex( tess, v_data, &curr_poly.Point( ipt ) );
}
gluTessEndContour( tess );
}
gluTessEndPolygon( tess );
}
if( aThickness == 0 )
break;
// Prepare the bottom side of solid areas
zpos = ( aZpos - (aThickness / 2.0) ) * aBiuTo3DUnits;
s_currentZpos = zpos; // for Tess callback functions
v_data[2] = zpos;
glNormal3f( 0.0, 0.0, -aNormal_Z_Orientation );
}
gluDeleteTess( tess );
if( aThickness == 0 )
return;
// Build the 3D data : vertical side
Draw3D_VerticalPolygonalCylinder( polylist, aThickness, aZpos - (aThickness / 2.0),
true, aBiuTo3DUnits );
}
/* draw a cylinder (a tube) using 3D primitives.
* the cylinder axis is parallel to the Z axis
* If aHeight = height of the cylinder is 0, only one ring will be drawn
* If aThickness = 0, only one cylinder will be drawn
*/
void Draw3D_ZaxisCylinder( wxPoint aCenterPos, int aRadius,
int aHeight, int aThickness,
int aZpos, double aBiuTo3DUnits )
{
const int slice = SEGM_PER_CIRCLE;
SHAPE_POLY_SET outer_cornerBuffer;
TransformCircleToPolygon( outer_cornerBuffer, aCenterPos,
aRadius + (aThickness / 2), slice );
std::vector<S3D_VERTEX> coords;
coords.resize( 4 );
SHAPE_POLY_SET inner_cornerBuffer;
if( aThickness ) // build the the vertical inner polygon (hole)
TransformCircleToPolygon( inner_cornerBuffer, aCenterPos,
aRadius - (aThickness / 2), slice );
if( aHeight )
{
// Draw the vertical outer side
Draw3D_VerticalPolygonalCylinder( outer_cornerBuffer,
aHeight, aZpos, false, aBiuTo3DUnits );
if( aThickness )
// Draws the vertical inner side (hole)
Draw3D_VerticalPolygonalCylinder( inner_cornerBuffer,
aHeight, aZpos, true, aBiuTo3DUnits );
}
if( aThickness )
{
// draw top (front) and bottom (back) horizontal sides (rings)
outer_cornerBuffer.AddHole( inner_cornerBuffer.COutline( 0 ) );
// draw top (front) horizontal ring
Draw3D_SolidHorizontalPolyPolygons( outer_cornerBuffer, aZpos + aHeight,
0, aBiuTo3DUnits, false, 1.0f );
if( aHeight )
{
// draw bottom (back) horizontal ring
Draw3D_SolidHorizontalPolyPolygons( outer_cornerBuffer, aZpos,
0, aBiuTo3DUnits, false, -1.0f );
}
}
}
/*
* Function Draw3D_ZaxisOblongCylinder:
* draw a segment with an oblong hole.
* Used to draw oblong holes
* If aHeight = height of the cylinder is 0, only one ring will be drawn
* If aThickness = 0, only one cylinder will be drawn
*/
void Draw3D_ZaxisOblongCylinder( wxPoint aAxis1Pos, wxPoint aAxis2Pos,
int aRadius, int aHeight, int aThickness,
int aZpos, double aBiuTo3DUnits )
{
const int slice = SEGM_PER_CIRCLE;
// Build the points to approximate oblong cylinder by segments
SHAPE_POLY_SET cornerBuffer;
int segm_width = (aRadius * 2) + aThickness;
TransformRoundedEndsSegmentToPolygon( cornerBuffer, aAxis1Pos,
aAxis2Pos, slice, segm_width );
// Draw the oblong outer cylinder
if( aHeight )
Draw3D_VerticalPolygonalCylinder( cornerBuffer, aHeight, aZpos,
false, aBiuTo3DUnits );
if( aThickness )
{
SHAPE_POLY_SET inner_cornerBuffer;
segm_width = aRadius * 2;
TransformRoundedEndsSegmentToPolygon( inner_cornerBuffer, aAxis1Pos,
aAxis2Pos, slice, segm_width );
// Draw the oblong inner cylinder
if( aHeight )
Draw3D_VerticalPolygonalCylinder( inner_cornerBuffer, aHeight,
aZpos, true, aBiuTo3DUnits );
// Build the horizontal full polygon shape
// (outer polygon shape - inner polygon shape)
cornerBuffer.AddHole( inner_cornerBuffer.COutline( 0 ) );
// draw top (front) horizontal side (ring)
Draw3D_SolidHorizontalPolyPolygons( cornerBuffer, aZpos + aHeight, 0, aBiuTo3DUnits, false,
1.0f );
if( aHeight )
{
// draw bottom (back) horizontal side (ring)
Draw3D_SolidHorizontalPolyPolygons( cornerBuffer, aZpos, 0, aBiuTo3DUnits, false,
-1.0f );
}
}
}
/* draw a thick segment using 3D primitives, in a XY plane
* wxPoint aStart, wxPoint aEnd = YX position of end in board units
* aWidth = width of segment in board units
* aThickness = thickness of segment in board units
* aZpos = z position of segment in board units
*/
void Draw3D_SolidSegment( const wxPoint& aStart, const wxPoint& aEnd,
int aWidth, int aThickness, int aZpos, double aBiuTo3DUnits )
{
SHAPE_POLY_SET cornerBuffer;
const int slice = SEGM_PER_CIRCLE;
TransformRoundedEndsSegmentToPolygon( cornerBuffer, aStart, aEnd, slice, aWidth );
Draw3D_SolidHorizontalPolyPolygons( cornerBuffer, aZpos, aThickness, aBiuTo3DUnits, false, 1.0f );
}
void Draw3D_ArcSegment( const wxPoint& aCenterPos, const wxPoint& aStartPoint,
double aArcAngle, int aWidth, int aThickness,
int aZpos, double aBiuTo3DUnits )
{
const int slice = SEGM_PER_CIRCLE;
SHAPE_POLY_SET cornerBuffer;
TransformArcToPolygon( cornerBuffer, aCenterPos, aStartPoint, aArcAngle,
slice, aWidth );
Draw3D_SolidHorizontalPolyPolygons( cornerBuffer, aZpos, aThickness, aBiuTo3DUnits, false, 1.0f );
}
// /////////////////////////////////////////////////////////////////////////////
// GLU_TESS CALLBACKS
// /////////////////////////////////////////////////////////////////////////////
void CALLBACK tessBeginCB( GLenum which )
{
glBegin( which );
}
void CALLBACK tessEndCB()
{
glEnd();
}
void CALLBACK tessCPolyPt2Vertex( const GLvoid* data )
{
// cast back to double type
const VECTOR2I* ptr = (const VECTOR2I*) data;
if( s_useTextures )
{
glTexCoord2f( ptr->x * s_biuTo3Dunits * s_textureScale,
-ptr->y * s_biuTo3Dunits * s_textureScale);
}
glVertex3d( ptr->x * s_biuTo3Dunits, -ptr->y * s_biuTo3Dunits, s_currentZpos );
}
void CALLBACK tessErrorCB( GLenum errorCode )
{
#if defined(DEBUG)
const GLubyte* errorStr;
errorStr = gluErrorString( errorCode );
// DEBUG //
DBG( printf( "Tess ERROR: %s\n", errorStr ); )
#endif
}

View File

@ -1,134 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2012 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file 3d_draw_basic_functions.h
*/
#ifndef _3D_DRAW_BASIC_FUNCTIONS_H_
#define _3D_DRAW_BASIC_FUNCTIONS_H_
// angle increment to draw a circle, approximated by segments
#define ANGLE_INC( x ) ( 3600 / (x) )
/** draw all solid polygons found in aPolysList
* @param aPolysList = the poligon list to draw
* @param aZpos = z position in board internal units
* @param aThickness = thickness in board internal units
* @param aBiuTo3DUnits = board internal units to 3D units scaling value
* @param aUseTextures = true to use textxures for the polygons
* @param aNormal_Z_Orientation = the normal Z orientation to apply
* If aThickness = 0, a polygon area is drawn in a XY plane at Z position = aZpos.
* If aThickness > 0, a solid object is drawn.
* The top side is located at aZpos + aThickness / 2
* The bottom side is located at aZpos - aThickness / 2
*/
void Draw3D_SolidHorizontalPolyPolygons( const SHAPE_POLY_SET& aPolysList,
int aZpos, int aThickness, double aBiuTo3DUnits,
bool aUseTextures,
float aNormal_Z_Orientation );
/** draw a thick segment using 3D primitives, in a XY plane
* @param aStart = YX position of start point in board units
* @param aEnd = YX position of end point in board units
* @param aWidth = width of segment in board units
* @param aThickness = thickness of segment in board units
* @param aZpos = z position of segment in board units
* @param aBiuTo3DUnits = board internal units to 3D units scaling value
* If aThickness = 0, a polygon area is drawn in a XY plane at Z position = aZpos.
* If aThickness > 0, a solid object is drawn.
* The top side is located at aZpos + aThickness / 2
* The bottom side is located at aZpos - aThickness / 2
*/
void Draw3D_SolidSegment( const wxPoint& aStart, const wxPoint& aEnd,
int aWidth, int aThickness, int aZpos,
double aBiuTo3DUnits );
/** draw an arc using 3D primitives, in a XY plane
* @param aCenterPos = XY position of the center in board units
* @param aStartPoint = start point coordinate of arc in board units
* @param aWidth = width of the circle in board units
* @param aArcAngle = arc angle in 1/10 degrees
* @param aWidth = thickness of arc
* @param aThickness = thickness of segment in board units
* @param aZpos = z position of segment in board units
* @param aBiuTo3DUnits = board internal units to 3D units scaling value
*/
void Draw3D_ArcSegment( const wxPoint& aCenterPos, const wxPoint& aStartPoint,
double aArcAngle, int aWidth, int aThickness,
int aZpos, double aBiuTo3DUnits );
/** draw a thick cylinder (a tube) using 3D primitives.
* the cylinder axis is parallel to the Z axis
* @param aCenterPos = XY position of the axis cylinder ( board internal units)
* @param aRadius = radius of the cylinder ( board internal units)
* @param aHeight = height of the cylinder ( boardinternal units)
* @param aThickness = tichkness of tube ( boardinternal units)
* @param aZpos = Z position of the bottom side of the cylinder ( board internal units)
* @param aBiuTo3DUnits = board internal units to 3D units scaling value
*
* If aHeight = height of the cylinder is 0, only one ring will be drawn
* If aThickness = 0, only one cylinder (not a tube) will be drawn
*/
void Draw3D_ZaxisCylinder( wxPoint aCenterPos, int aRadius,
int aHeight, int aThickness,
int aZpos, double aBiuTo3DUnits );
/** draw an oblong cylinder (oblong tube) using 3D primitives.
* the cylinder axis are parallel to the Z axis
* @param aAxis1Pos = position of the first axis cylinder
* @param aAxis2Pos = position of the second axis cylinder
* @param aRadius = radius of the cylinder ( board internal units )
* @param aHeight = height of the cylinder ( board internal units )
* @param aThickness = tichkness of tube ( board internal units )
* @param aZpos = Z position of the bottom side of the cylinder ( board internal units )
* @param aBiuTo3DUnits = board internal units to 3D units scaling value
*/
void Draw3D_ZaxisOblongCylinder( wxPoint aAxis1Pos, wxPoint aAxis2Pos,
int aRadius, int aHeight, int aThickness,
int aZpos, double aBiuTo3DUnits );
/**
* Set the current 3D color from a Kicad color, with optional transparency
* @param aColor = a EDA_COLOR_T kicad color index
* @param aTransparency = the color transparency (default = 1.0 = no transparency)
*/
void SetGLColor( EDA_COLOR_T aColor, double aTransparency = 1.0 );
/**
* Set the current 3D color from a S3D_COLOR color, with optional transparency
* @param aColor = a S3D_COLOR RGB color index
* @param aTransparency = the color transparency (default = 1.0 = no transparency)
*/
void SetGLColor( S3D_COLOR& aColor, float aTransparency );
/**
* Set a texture id and a scale to apply when rendering the polygons
* @param text_id = texture ID created by glGenTextures
* @param scale = scale to apply to texture coords
*/
void SetGLTexture( GLuint text_id, float scale );
#endif // _3D_DRAW_BASIC_FUNCTIONS_H_

View File

@ -1,640 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014-2015 Mario Luzeiro <mrluzeiro@gmail.com>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file 3d_draw_board_body.cpp
*
*/
#include <fctsys.h>
#include <common.h>
#include <trigo.h>
#include <pcbstruct.h>
#include <drawtxt.h>
#include <layers_id_colors_and_visibility.h>
#include <wxBasePcbFrame.h>
#include <class_board.h>
#include <class_module.h>
#include <class_track.h>
#include <class_edge_mod.h>
#include <class_zone.h>
#include <class_drawsegment.h>
#include <class_pcb_text.h>
#include <colors_selection.h>
#include <convert_basic_shapes_to_polygon.h>
#define GLM_FORCE_RADIANS
#include <glm/gtc/matrix_transform.hpp>
#include <gal/opengl/opengl_compositor.h>
#ifdef __WINDOWS__
#include <GL/glew.h> // must be included before gl.h
#endif
#include <3d_viewer.h>
#include <3d_canvas.h>
#include <info3d_visu.h>
#include <trackball.h>
#include <3d_draw_basic_functions.h>
#include <geometry/shape_poly_set.h>
#include <geometry/shape_file_io.h>
#include <cimage.h>
#include <reporter.h>
// An option for all operations on polygons:
// when polygonsCalcMode = true, calculations can be *a lot* faster.
// but created polygons can be not stricty simple (can share edges)
// Although stricty simple are better for glu tesselation functions, I do not see
// any issue when allowing not stricty simple polygons.
// But I see *very* long calculations when setting useFastMode to false.
// So, be careful if changing thie option
SHAPE_POLY_SET::POLYGON_MODE polygonsCalcMode = SHAPE_POLY_SET::PM_FAST;
/* returns the Z orientation parameter 1.0 or -1.0 for aLayer
* Z orientation is 1.0 for all layers but "back" layers:
* B_Cu , B_Adhes, B_Paste ), B_SilkS
* used to calculate the Z orientation parameter for glNormal3f
*/
GLfloat Get3DLayer_Z_Orientation( LAYER_NUM aLayer );
void EDA_3D_CANVAS::buildBoardThroughHolesPolygonList( SHAPE_POLY_SET& allBoardHoles,
int aSegCountPerCircle, bool aOptimizeLargeCircles )
{
// hole diameter value to change seg count by circle:
int small_hole_limit = Millimeter2iu( 1.0 );
int copper_thickness = GetPrm3DVisu().GetCopperThicknessBIU();
BOARD* pcb = GetBoard();
// Build holes of through vias:
for( TRACK* track = pcb->m_Track; track; track = track->Next() )
{
if( track->Type() != PCB_VIA_T )
continue;
VIA *via = static_cast<VIA*>( track );
if( via->GetViaType() != VIA_THROUGH )
continue;
int holediameter = via->GetDrillValue();
int hole_outer_radius = (holediameter + copper_thickness) / 2;
TransformCircleToPolygon( allBoardHoles,
via->GetStart(), hole_outer_radius,
aSegCountPerCircle );
}
// Build holes of through pads:
for( MODULE* footprint = pcb->m_Modules; footprint; footprint = footprint->Next() )
{
for( D_PAD* pad = footprint->Pads(); pad; pad = pad->Next() )
{
// Calculate a factor to apply to segcount for large holes ( > 1 mm)
// (bigger pad drill size -> more segments) because holes in pads can have
// very different sizes and optimizing this segcount gives a better look
// Mainly mounting holes have a size bigger than small_hole_limit
wxSize padHole = pad->GetDrillSize();
if( ! padHole.x ) // Not drilled pad like SMD pad
continue;
// we use the hole diameter to calculate the seg count.
// for round holes, padHole.x == padHole.y
// for oblong holes, the diameter is the smaller of (padHole.x, padHole.y)
int diam = std::min( padHole.x, padHole.y );
int segcount = aSegCountPerCircle;
if( diam > small_hole_limit )
{
double segFactor = (double)diam / small_hole_limit;
segcount = (int)(aSegCountPerCircle * segFactor);
// limit segcount to 48. For a circle this is a very good approx.
if( segcount > 48 )
segcount = 48;
}
// The hole in the body is inflated by copper thickness.
int inflate = copper_thickness;
// If not plated, no copper.
if( pad->GetAttribute () == PAD_ATTRIB_HOLE_NOT_PLATED )
inflate = 0;
pad->BuildPadDrillShapePolygon( allBoardHoles, inflate, segcount );
}
}
allBoardHoles.Simplify( polygonsCalcMode );
}
void EDA_3D_CANVAS::buildBoard3DView( GLuint aBoardList, GLuint aBodyOnlyList,
REPORTER* aErrorMessages, REPORTER* aActivity )
{
BOARD* pcb = GetBoard();
// If FL_RENDER_SHOW_HOLES_IN_ZONES is true, holes are correctly removed from copper zones areas.
// If FL_RENDER_SHOW_HOLES_IN_ZONES is false, holes are not removed from copper zones areas,
// but the calculation time is twice shorter.
bool remove_Holes = isEnabled( FL_RENDER_SHOW_HOLES_IN_ZONES );
bool realistic_mode = isRealisticMode();
bool useTextures = isRealisticMode() && isEnabled( FL_RENDER_TEXTURES );
// Number of segments to convert a circle to polygon
// We use 2 values: the first gives a good shape (for instanes rond pads)
// the second is used to speed up calculations, when a poor approximation is acceptable (holes)
const int segcountforcircle = 18;
double correctionFactor = 1.0 / cos( M_PI / (segcountforcircle * 2.0) );
const int segcountLowQuality = 12; // segments to draw a circle with low quality
// to reduce time calculations
// for holes and items which do not need
// a fine representation
double correctionFactorLQ = 1.0 / cos( M_PI / (segcountLowQuality * 2.0) );
SHAPE_POLY_SET bufferPolys; // copper areas: tracks, pads and filled zones areas
// when holes are removed from zones
SHAPE_POLY_SET bufferPcbOutlines; // stores the board main outlines
SHAPE_POLY_SET bufferZonesPolys; // copper filled zones areas
// when holes are not removed from zones
SHAPE_POLY_SET currLayerHoles; // Contains holes for the current layer
SHAPE_POLY_SET allLayerHoles; // Contains holes for all layers
// Build a polygon from edge cut items
wxString msg;
if( !pcb->GetBoardPolygonOutlines( bufferPcbOutlines, allLayerHoles, &msg ) )
{
if( aErrorMessages )
{
msg << wxT("\n") << _("Unable to calculate the board outlines.\n"
"Therefore use the board boundary box.") << wxT("\n\n");
aErrorMessages->Report( msg, REPORTER::RPT_WARNING );
}
}
// Build board holes, with optimization of large holes shape.
buildBoardThroughHolesPolygonList( allLayerHoles, segcountLowQuality, true );
LSET cu_set = LSET::AllCuMask( GetPrm3DVisu().m_CopperLayersCount );
glNewList( aBoardList, GL_COMPILE );
for( LSEQ cu = cu_set.CuStack(); cu; ++cu )
{
LAYER_ID layer = *cu;
// Skip non enabled layers in normal mode,
// and internal layers in realistic mode
if( !is3DLayerEnabled( layer ) )
continue;
if( aActivity )
aActivity->Report( wxString::Format( _( "Build layer %s" ), LSET::Name( layer ) ) );
bufferPolys.RemoveAllContours();
bufferZonesPolys.RemoveAllContours();
currLayerHoles.RemoveAllContours();
// Draw track shapes:
for( TRACK* track = pcb->m_Track; track; track = track->Next() )
{
if( !track->IsOnLayer( layer ) )
continue;
track->TransformShapeWithClearanceToPolygon( bufferPolys,
0, segcountforcircle,
correctionFactor );
// Add blind/buried via holes
if( track->Type() == PCB_VIA_T )
{
VIA *via = static_cast<VIA*>( track );
if( via->GetViaType() == VIA_THROUGH )
continue; // already done
int holediameter = via->GetDrillValue();
int thickness = GetPrm3DVisu().GetCopperThicknessBIU();
int hole_outer_radius = (holediameter + thickness) / 2;
TransformCircleToPolygon( currLayerHoles,
via->GetStart(), hole_outer_radius,
segcountLowQuality );
}
}
// draw pad shapes
for( MODULE* module = pcb->m_Modules; module; module = module->Next() )
{
// Note: NPTH pads are not drawn on copper layers when the pad
// has same shape as its hole
module->TransformPadsShapesWithClearanceToPolygon( layer,
bufferPolys,
0,
segcountforcircle,
correctionFactor, true );
// Micro-wave modules may have items on copper layers
module->TransformGraphicShapesWithClearanceToPolygonSet( layer,
bufferPolys,
0,
segcountforcircle,
correctionFactor );
// pad holes are already in list.
}
// Draw copper zones. Note:
// * if the holes are removed from copper zones
// the polygons are stored in bufferPolys (which contains all other polygons)
// * if the holes are NOT removed from copper zones
// the polygons are stored in bufferZonesPolys
if( isEnabled( FL_ZONE ) )
{
for( int ii = 0; ii < pcb->GetAreaCount(); ii++ )
{
ZONE_CONTAINER* zone = pcb->GetArea( ii );
LAYER_NUM zonelayer = zone->GetLayer();
if( zonelayer == layer )
{
zone->TransformSolidAreasShapesToPolygonSet(
remove_Holes ? bufferPolys : bufferZonesPolys,
segcountLowQuality, correctionFactorLQ );
}
}
}
// draw graphic items on copper layers (texts)
for( BOARD_ITEM* item = pcb->m_Drawings; item; item = item->Next() )
{
if( !item->IsOnLayer( layer ) )
continue;
switch( item->Type() )
{
case PCB_LINE_T: // should not exist on copper layers
( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon(
bufferPolys, 0, segcountforcircle, correctionFactor );
break;
case PCB_TEXT_T:
( (TEXTE_PCB*) item )->TransformShapeWithClearanceToPolygonSet(
bufferPolys, 0, segcountLowQuality, correctionFactor );
break;
default:
break;
}
}
// bufferPolys contains polygons to merge. Many overlaps .
// Calculate merged polygons
if( bufferPolys.IsEmpty() )
continue;
// Use Clipper lib to subtract holes to copper areas
if( currLayerHoles.OutlineCount() )
{
currLayerHoles.Append(allLayerHoles);
currLayerHoles.Simplify( polygonsCalcMode );
bufferPolys.BooleanSubtract( currLayerHoles, polygonsCalcMode );
}
else
bufferPolys.BooleanSubtract( allLayerHoles, polygonsCalcMode );
int thickness = GetPrm3DVisu().GetLayerObjectThicknessBIU( layer );
int zpos = GetPrm3DVisu().GetLayerZcoordBIU( layer );
float zNormal = 1.0f; // When using thickness it will draw first the top and then botton (with z inverted)
// If we are not using thickness, then the z-normal has to match the layer direction
// because just one plane will be drawn
if( !thickness )
zNormal = Get3DLayer_Z_Orientation( layer );
if( realistic_mode )
{
setGLCopperColor();
}
else
{
EDA_COLOR_T color = g_ColorsSettings.GetLayerColor( layer );
SetGLColor( color );
}
// If holes are removed from copper zones, bufferPolys contains all polygons
// to draw (tracks+zones+texts).
Draw3D_SolidHorizontalPolyPolygons( bufferPolys, zpos, thickness,
GetPrm3DVisu().m_BiuTo3Dunits, useTextures,
zNormal );
// If holes are not removed from copper zones (for calculation time reasons,
// the zone polygons are stored in bufferZonesPolys and have to be drawn now:
if( !bufferZonesPolys.IsEmpty() )
{
Draw3D_SolidHorizontalPolyPolygons( bufferZonesPolys, zpos, thickness,
GetPrm3DVisu().m_BiuTo3Dunits, useTextures,
zNormal );
}
}
if( aActivity )
aActivity->Report( _( "Build board body" ) );
// Draw plated vertical holes inside the board, but not always. They are drawn:
// - if the board body is not shown, to show the holes.
// - or if the copper thickness is shown
if( !isEnabled( FL_SHOW_BOARD_BODY ) || isEnabled( FL_USE_COPPER_THICKNESS ) )
{
// Draw vias holes (vertical cylinders)
for( const TRACK* track = pcb->m_Track; track; track = track->Next() )
{
if( track->Type() == PCB_VIA_T )
{
const VIA *via = static_cast<const VIA*>(track);
draw3DViaHole( via );
}
}
// Draw pads holes (vertical cylinders)
for( const MODULE* module = pcb->m_Modules; module; module = module->Next() )
{
for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() )
if( pad->GetAttribute () != PAD_ATTRIB_HOLE_NOT_PLATED )
draw3DPadHole( pad );
}
}
glEndList();
// Build the body board:
glNewList( aBodyOnlyList, GL_COMPILE );
if( isRealisticMode() )
{
setGLEpoxyColor( 1.00 );
}
else
{
EDA_COLOR_T color = g_ColorsSettings.GetLayerColor( Edge_Cuts );
SetGLColor( color, 0.7 );
}
float copper_thickness = GetPrm3DVisu().GetCopperThicknessBIU();
// a small offset between substrate and external copper layer to avoid artifacts
// when drawing copper items on board
float epsilon = Millimeter2iu( 0.01 );
float zpos = GetPrm3DVisu().GetLayerZcoordBIU( B_Cu );
float board_thickness = GetPrm3DVisu().GetLayerZcoordBIU( F_Cu )
- GetPrm3DVisu().GetLayerZcoordBIU( B_Cu );
// items on copper layers and having a thickness = copper_thickness
// are drawn from zpos - copper_thickness/2 to zpos + copper_thickness
// therefore substrate position is copper_thickness/2 to
// substrate_height - copper_thickness/2
zpos += (copper_thickness + epsilon) / 2.0f;
board_thickness -= copper_thickness + epsilon;
bufferPcbOutlines.BooleanSubtract( allLayerHoles, polygonsCalcMode );
if( !bufferPcbOutlines.IsEmpty() )
{
Draw3D_SolidHorizontalPolyPolygons( bufferPcbOutlines, zpos + board_thickness / 2.0,
board_thickness, GetPrm3DVisu().m_BiuTo3Dunits, useTextures,
1.0f );
}
glEndList();
}
void EDA_3D_CANVAS::buildTechLayers3DView( REPORTER* aErrorMessages, REPORTER* aActivity )
{
BOARD* pcb = GetBoard();
bool useTextures = isRealisticMode() && isEnabled( FL_RENDER_TEXTURES );
// Number of segments to draw a circle using segments
const int segcountforcircle = 18;
double correctionFactor = 1.0 / cos( M_PI / (segcountforcircle * 2) );
const int segcountLowQuality = 12; // segments to draw a circle with low quality
// to reduce time calculations
// for holes and items which do not need
// a fine representation
double correctionFactorLQ = 1.0 / cos( M_PI / (segcountLowQuality * 2) );
// segments to draw a circle to build texts. Is is used only to build
// the shape of each segment of the stroke font, therefore no need to have
// many segments per circle.
const int segcountInStrokeFont = 8;
SHAPE_POLY_SET bufferPolys;
SHAPE_POLY_SET allLayerHoles; // Contains through holes, calculated only once
SHAPE_POLY_SET bufferPcbOutlines; // stores the board main outlines
// Build a polygon from edge cut items
wxString msg;
if( !pcb->GetBoardPolygonOutlines( bufferPcbOutlines, allLayerHoles, &msg ) )
{
if( aErrorMessages )
{
msg << wxT("\n") <<
_("Unable to calculate the board outlines.\n"
"Therefore use the board boundary box.") << wxT("\n\n");
aErrorMessages->Report( msg, REPORTER::RPT_WARNING );
}
}
// Build board holes, with no optimization of large holes shape.
buildBoardThroughHolesPolygonList( allLayerHoles, segcountLowQuality, false );
// draw graphic items, on technical layers
static const LAYER_ID teckLayerList[] = {
B_Adhes,
F_Adhes,
B_Paste,
F_Paste,
B_SilkS,
F_SilkS,
B_Mask,
F_Mask,
};
// User layers are not drawn here, only technical layers
for( LSEQ seq = LSET::AllTechMask().Seq( teckLayerList, DIM( teckLayerList ) ); seq; ++seq )
{
LAYER_ID layer = *seq;
if( !is3DLayerEnabled( layer ) )
continue;
if( layer == Edge_Cuts && isEnabled( FL_SHOW_BOARD_BODY ) )
continue;
if( aActivity )
aActivity->Report( wxString::Format( _( "Build layer %s" ), LSET::Name( layer ) ) );
bufferPolys.RemoveAllContours();
for( BOARD_ITEM* item = pcb->m_Drawings; item; item = item->Next() )
{
if( !item->IsOnLayer( layer ) )
continue;
switch( item->Type() )
{
case PCB_LINE_T:
( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon(
bufferPolys, 0, segcountforcircle, correctionFactor );
break;
case PCB_TEXT_T:
( (TEXTE_PCB*) item )->TransformShapeWithClearanceToPolygonSet(
bufferPolys, 0, segcountLowQuality, 1.0 );
break;
default:
break;
}
}
for( MODULE* module = pcb->m_Modules; module; module = module->Next() )
{
if( layer == F_SilkS || layer == B_SilkS )
{
// On silk screen layers, the pad shape is only the pad outline
// never a filled shape
D_PAD* pad = module->Pads();
int linewidth = g_DrawDefaultLineThickness;
for( ; pad; pad = pad->Next() )
{
if( !pad->IsOnLayer( layer ) )
continue;
buildPadShapeThickOutlineAsPolygon( pad, bufferPolys,
linewidth, segcountforcircle, correctionFactor );
}
}
else
module->TransformPadsShapesWithClearanceToPolygon( layer,
bufferPolys, 0, segcountforcircle, correctionFactor );
// On tech layers, use a poor circle approximation, only for texts (stroke font)
module->TransformGraphicShapesWithClearanceToPolygonSet( layer,
bufferPolys, 0, segcountforcircle, correctionFactor, segcountInStrokeFont );
}
// Draw non copper zones
if( isEnabled( FL_ZONE ) )
{
for( int ii = 0; ii < pcb->GetAreaCount(); ii++ )
{
ZONE_CONTAINER* zone = pcb->GetArea( ii );
if( !zone->IsOnLayer( layer ) )
continue;
zone->TransformSolidAreasShapesToPolygonSet(
bufferPolys, segcountLowQuality, correctionFactorLQ );
}
}
// bufferPolys contains polygons to merge. Many overlaps .
// Calculate merged polygons and remove pads and vias holes
if( layer != B_Mask && layer != F_Mask && bufferPolys.IsEmpty() )
// if a layer has no item to draw, skip it
// However solder mask layers are negative layers, so no item
// means only a full layer mask
continue;
// Solder mask layers are "negative" layers.
// Shapes should be removed from the full board area.
if( layer == B_Mask || layer == F_Mask )
{
SHAPE_POLY_SET cuts = bufferPolys;
bufferPolys = bufferPcbOutlines;
cuts.Append(allLayerHoles);
cuts.Simplify( polygonsCalcMode );
bufferPolys.BooleanSubtract( cuts, polygonsCalcMode );
}
// Remove holes from Solder paste layers and silkscreen
else if( layer == B_Paste || layer == F_Paste
|| layer == B_SilkS || layer == F_SilkS )
{
bufferPolys.BooleanSubtract( allLayerHoles, polygonsCalcMode );
}
int thickness = 0;
if( layer != B_Mask && layer != F_Mask )
thickness = GetPrm3DVisu().GetLayerObjectThicknessBIU( layer );
int zpos = GetPrm3DVisu().GetLayerZcoordBIU( layer );
if( layer == Edge_Cuts )
{
thickness = GetPrm3DVisu().GetLayerZcoordBIU( F_Cu )
- GetPrm3DVisu().GetLayerZcoordBIU( B_Cu );
zpos = GetPrm3DVisu().GetLayerZcoordBIU( B_Cu )
+ (thickness / 2);
}
else
{
// for Draw3D_SolidHorizontalPolyPolygons, zpos it the middle between bottom and top
// sides.
// However for top layers, zpos should be the bottom layer pos,
// and for bottom layers, zpos should be the top layer pos.
if( Get3DLayer_Z_Orientation( layer ) > 0 )
zpos += thickness/2;
else
zpos -= thickness/2 ;
}
float zNormal = 1.0f; // When using thickness it will draw first the top and then botton (with z inverted)
// If we are not using thickness, then the znormal must face the layer direction
// because it will draw just one plane
if( !thickness )
zNormal = Get3DLayer_Z_Orientation( layer );
setGLTechLayersColor( layer );
Draw3D_SolidHorizontalPolyPolygons( bufferPolys, zpos,
thickness, GetPrm3DVisu().m_BiuTo3Dunits, useTextures,
zNormal );
}
}

View File

@ -1,493 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 1992-2014 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file 3d_draw_helper_functions.cpp
*/
#include <fctsys.h>
#include <PolyLine.h>
#include <colors.h>
#include <colors_selection.h>
#include <class_pad.h>
#include <class_track.h>
#include <convert_basic_shapes_to_polygon.h>
#include <3d_viewer.h>
#include <3d_canvas.h>
#include <info3d_visu.h>
#include <3d_draw_basic_functions.h>
#define TEXTURE_PCB_SCALE 5.0
// -----------------
// helper function (from wxWidgets, opengl/cube.cpp sample
// -----------------
void CheckGLError(const char *aFileName, int aLineNumber)
{
GLenum errLast = GL_NO_ERROR;
for ( ; ; )
{
GLenum err = glGetError();
if ( err == GL_NO_ERROR )
return;
// normally the error is reset by the call to glGetError() but if
// glGetError() itself returns an error, we risk looping forever here
// so check that we get a different error than the last time
if ( err == errLast )
{
wxLogError(wxT("OpenGL error state couldn't be reset."));
return;
}
errLast = err;
wxLogError( wxT( "OpenGL error %d At: %s, line: %d" ), err,
GetChars( FROM_UTF8( aFileName ) ), aLineNumber );
}
}
INFO3D_VISU& EDA_3D_CANVAS::GetPrm3DVisu() const
{
return Parent()->GetPrm3DVisu();
}
wxSize EDA_3D_CANVAS::getBoardSize() const
{
// return the size of the board in pcb units
return GetPrm3DVisu().m_BoardSize;
}
wxPoint EDA_3D_CANVAS::getBoardCenter() const
{
// return the position of the board center in pcb units
return GetPrm3DVisu().m_BoardPos;
}
// return true if we are in realistic mode render
bool EDA_3D_CANVAS::isRealisticMode() const
{
return GetPrm3DVisu().IsRealisticMode();
}
// return true if aItem should be displayed
bool EDA_3D_CANVAS::isEnabled( DISPLAY3D_FLG aItem ) const
{
return GetPrm3DVisu().GetFlag( aItem );
}
// Helper function: initialize the copper color to draw the board
// in realistic mode.
void EDA_3D_CANVAS::setGLCopperColor()
{
glDisable( GL_TEXTURE_2D );
SetGLColor( GetPrm3DVisu().m_CopperColor, 1.0 );
}
// Helper function: initialize the color to draw the epoxy
// body board in realistic mode.
void EDA_3D_CANVAS::setGLEpoxyColor( float aTransparency )
{
// Generates an epoxy color, near board color
SetGLColor( GetPrm3DVisu().m_BoardBodyColor, aTransparency );
if( isEnabled( FL_RENDER_TEXTURES ) )
{
SetGLTexture( m_text_pcb, TEXTURE_PCB_SCALE );
}
}
// Helper function: initialize the color to draw the
// solder mask layers in realistic mode.
void EDA_3D_CANVAS::setGLSolderMaskColor( float aTransparency )
{
// Generates a solder mask color
SetGLColor( GetPrm3DVisu().m_SolderMaskColor, aTransparency );
if( isEnabled( FL_RENDER_TEXTURES ) )
{
SetGLTexture( m_text_pcb, TEXTURE_PCB_SCALE );
}
}
// Helper function: initialize the color to draw the non copper layers
// in realistic mode and normal mode.
void EDA_3D_CANVAS::setGLTechLayersColor( LAYER_NUM aLayer )
{
EDA_COLOR_T color;
if( isRealisticMode() )
{
switch( aLayer )
{
case B_Paste:
case F_Paste:
SetGLColor( GetPrm3DVisu().m_SolderPasteColor, 1 );
break;
case B_SilkS:
case F_SilkS:
SetGLColor( GetPrm3DVisu().m_SilkScreenColor, 0.96 );
if( isEnabled( FL_RENDER_TEXTURES ) )
{
SetGLTexture( m_text_silk, 10.0f );
}
break;
case B_Mask:
case F_Mask:
setGLSolderMaskColor( 0.90 );
break;
default:
color = g_ColorsSettings.GetLayerColor( aLayer );
SetGLColor( color, 0.7 );
break;
}
}
else
{
color = g_ColorsSettings.GetLayerColor( aLayer );
SetGLColor( color, 0.7 );
}
}
void EDA_3D_CANVAS::draw3DAxis()
{
if( ! m_glLists[GL_ID_AXIS] )
{
m_glLists[GL_ID_AXIS] = glGenLists( 1 );
glNewList( m_glLists[GL_ID_AXIS], GL_COMPILE );
glEnable( GL_COLOR_MATERIAL );
glBegin( GL_LINES );
SetGLColor( RED );
glNormal3f( 0.0f, 0.0f, 1.0f ); // Normal is Z axis
glVertex3f( 0.0f, 0.0f, 0.0f );
glVertex3f( -10.0f, 0.0f, 0.0f );
glVertex3f( 0.0f, 0.0f, 0.0f );
glVertex3f( 10.0f, 0.0f, 0.0f ); // X axis
SetGLColor( GREEN );
glVertex3f( 0.0f, 0.0f, 0.0f );
glVertex3f( 0.0f, -10.0f, 0.0f ); // Y axis
glVertex3f( 0.0f, 0.0f, 0.0f );
glVertex3f( 0.0f, 10.0f, 0.0f );
SetGLColor( BLUE );
glNormal3f( 1.0f, 0.0f, 0.0f ); // Normal is Y axis
glVertex3f( 0.0f, 0.0f, 0.0f );
glVertex3f( 0.0f, 0.0f, -10.0f );
glVertex3f( 0.0f, 0.0f, 0.0f );
glVertex3f( 0.0f, 0.0f, 10.0f ); // Z axis
glEnd();
glEndList();
}
}
// draw a 3D grid: an horizontal grid (XY plane and Z = 0,
// and a vertical grid (XZ plane and Y = 0)
void EDA_3D_CANVAS::draw3DGrid( double aGriSizeMM )
{
double zpos = 0.0;
EDA_COLOR_T gridcolor = DARKGRAY; // Color of grid lines
EDA_COLOR_T gridcolor_marker = LIGHTGRAY; // Color of grid lines every 5 lines
const double scale = GetPrm3DVisu().m_BiuTo3Dunits;
const double transparency = 0.3;
glNormal3f( 0.0, 0.0, 1.0 );
wxSize brd_size = getBoardSize();
wxPoint brd_center_pos = getBoardCenter();
brd_center_pos.y = -brd_center_pos.y;
int xsize = std::max( brd_size.x, Millimeter2iu( 100 ) ) * 1.2;
int ysize = std::max( brd_size.y, Millimeter2iu( 100 ) ) * 1.2;
// Grid limits, in 3D units
double xmin = (brd_center_pos.x - xsize / 2) * scale;
double xmax = (brd_center_pos.x + xsize / 2) * scale;
double ymin = (brd_center_pos.y - ysize / 2) * scale;
double ymax = (brd_center_pos.y + ysize / 2) * scale;
double zmin = Millimeter2iu( -50 ) * scale;
double zmax = Millimeter2iu( 100 ) * scale;
// Draw horizontal grid centered on 3D origin (center of the board)
for( int ii = 0; ; ii++ )
{
if( (ii % 5) )
SetGLColor( gridcolor, transparency );
else
SetGLColor( gridcolor_marker, transparency );
int delta = KiROUND( ii * aGriSizeMM * IU_PER_MM );
if( delta <= xsize / 2 ) // Draw grid lines parallel to X axis
{
glBegin( GL_LINES );
glVertex3f( (brd_center_pos.x + delta) * scale, -ymin, zpos );
glVertex3f( (brd_center_pos.x + delta) * scale, -ymax, zpos );
glEnd();
if( ii != 0 )
{
glBegin( GL_LINES );
glVertex3f( (brd_center_pos.x - delta) * scale, -ymin, zpos );
glVertex3f( (brd_center_pos.x - delta) * scale, -ymax, zpos );
glEnd();
}
}
if( delta <= ysize / 2 ) // Draw grid lines parallel to Y axis
{
glBegin( GL_LINES );
glVertex3f( xmin, -(brd_center_pos.y + delta) * scale, zpos );
glVertex3f( xmax, -(brd_center_pos.y + delta) * scale, zpos );
glEnd();
if( ii != 0 )
{
glBegin( GL_LINES );
glVertex3f( xmin, -(brd_center_pos.y - delta) * scale, zpos );
glVertex3f( xmax, -(brd_center_pos.y - delta) * scale, zpos );
glEnd();
}
}
if( ( delta > ysize / 2 ) && ( delta > xsize / 2 ) )
break;
}
// Draw vertical grid on Z axis
glNormal3f( 0.0, -1.0, 0.0 );
// Draw vertical grid lines (parallel to Z axis)
double posy = -brd_center_pos.y * scale;
for( int ii = 0; ; ii++ )
{
if( (ii % 5) )
SetGLColor( gridcolor, transparency );
else
SetGLColor( gridcolor_marker, transparency );
double delta = ii * aGriSizeMM * IU_PER_MM;
glBegin( GL_LINES );
xmax = (brd_center_pos.x + delta) * scale;
glVertex3f( xmax, posy, zmin );
glVertex3f( xmax, posy, zmax );
glEnd();
if( ii != 0 )
{
glBegin( GL_LINES );
xmin = (brd_center_pos.x - delta) * scale;
glVertex3f( xmin, posy, zmin );
glVertex3f( xmin, posy, zmax );
glEnd();
}
if( delta > xsize / 2.0f )
break;
}
// Draw horizontal grid lines on Z axis (parallel to X axis)
for( int ii = 0; ; ii++ )
{
if( (ii % 5) )
SetGLColor( gridcolor, transparency);
else
SetGLColor( gridcolor_marker, transparency );
double delta = ii * aGriSizeMM * IU_PER_MM * scale;
if( delta <= zmax )
{
// Draw grid lines on Z axis (positive Z axis coordinates)
glBegin( GL_LINES );
glVertex3f( xmin, posy, delta );
glVertex3f( xmax, posy, delta );
glEnd();
}
if( delta <= -zmin && ( ii != 0 ) )
{
// Draw grid lines on Z axis (negative Z axis coordinates)
glBegin( GL_LINES );
glVertex3f( xmin, posy, -delta );
glVertex3f( xmax, posy, -delta );
glEnd();
}
if( ( delta > zmax ) && ( delta > -zmin ) )
break;
}
}
// Draw 3D pads.
void EDA_3D_CANVAS::draw3DPadHole( const D_PAD* aPad )
{
// Draw the pad hole
wxSize drillsize = aPad->GetDrillSize();
bool hasHole = drillsize.x && drillsize.y;
if( !hasHole )
return;
// Store here the points to approximate hole by segments
SHAPE_POLY_SET holecornersBuffer;
int thickness = GetPrm3DVisu().GetCopperThicknessBIU();
int height = GetPrm3DVisu().GetLayerZcoordBIU( F_Cu ) -
GetPrm3DVisu().GetLayerZcoordBIU( B_Cu );
if( isRealisticMode() )
setGLCopperColor();
else
SetGLColor( DARKGRAY );
int holeZpoz = GetPrm3DVisu().GetLayerZcoordBIU( B_Cu ) - thickness / 2;
int holeHeight = height + thickness;
if( drillsize.x == drillsize.y ) // usual round hole
{
int hole_radius = ( drillsize.x + thickness ) / 2;
Draw3D_ZaxisCylinder( aPad->GetPosition(),
hole_radius, holeHeight,
thickness, holeZpoz, GetPrm3DVisu().m_BiuTo3Dunits );
}
else // Oblong hole
{
wxPoint ends_offset;
int width;
if( drillsize.x > drillsize.y ) // Horizontal oval
{
ends_offset.x = ( drillsize.x - drillsize.y ) / 2;
width = drillsize.y;
}
else // Vertical oval
{
ends_offset.y = ( drillsize.y - drillsize.x ) / 2;
width = drillsize.x;
}
RotatePoint( &ends_offset, aPad->GetOrientation() );
wxPoint start = aPad->GetPosition() + ends_offset;
wxPoint end = aPad->GetPosition() - ends_offset;
int hole_radius = ( width + thickness ) / 2;
// Draw the hole
Draw3D_ZaxisOblongCylinder( start, end, hole_radius, holeHeight,
thickness, holeZpoz, GetPrm3DVisu().m_BiuTo3Dunits );
}
}
void EDA_3D_CANVAS::draw3DViaHole( const VIA* aVia )
{
LAYER_ID top_layer, bottom_layer;
int thickness = GetPrm3DVisu().GetCopperThicknessBIU();
int inner_radius = (int)((float)aVia->GetDrillValue() * 1.01f) / 2.0f; // This add a bit more in order to correct a draw artifact while using thickness
aVia->LayerPair( &top_layer, &bottom_layer );
// Drawing via hole:
if( isRealisticMode() )
setGLCopperColor();
else
{
EDA_COLOR_T color = g_ColorsSettings.GetItemColor( VIAS_VISIBLE + aVia->GetViaType() );
SetGLColor( color );
}
int height = GetPrm3DVisu().GetLayerZcoordBIU( top_layer ) -
GetPrm3DVisu().GetLayerZcoordBIU( bottom_layer ) + thickness;
int zpos = GetPrm3DVisu().GetLayerZcoordBIU( bottom_layer ) - thickness / 2;
Draw3D_ZaxisCylinder( aVia->GetStart(), inner_radius, height,
thickness, zpos, GetPrm3DVisu().m_BiuTo3Dunits );
}
/* Build a pad outline as non filled polygon, to draw pads on silkscreen layer
* Used only to draw pads outlines on silkscreen layers.
*/
void EDA_3D_CANVAS::buildPadShapeThickOutlineAsPolygon( const D_PAD* aPad,
SHAPE_POLY_SET& aCornerBuffer,
int aWidth,
int aCircleToSegmentsCount,
double aCorrectionFactor )
{
if( aPad->GetShape() == PAD_SHAPE_CIRCLE ) // Draw a ring
{
TransformRingToPolygon( aCornerBuffer, aPad->ShapePos(),
aPad->GetSize().x / 2, aCircleToSegmentsCount, aWidth );
return;
}
// For other shapes, draw polygon outlines
SHAPE_POLY_SET corners;
aPad->BuildPadShapePolygon( corners, wxSize( 0, 0 ),
aCircleToSegmentsCount, aCorrectionFactor );
// Add outlines as thick segments in polygon buffer
const SHAPE_LINE_CHAIN& path = corners.COutline( 0 );
for( int ii = 0; ii < path.PointCount(); ii++ )
{
const VECTOR2I& a = path.CPoint( ii );
const VECTOR2I& b = path.CPoint( ii + 1 );
TransformRoundedEndsSegmentToPolygon( aCornerBuffer,
wxPoint( a.x, a.y ),
wxPoint( b.x, b.y ),
aCircleToSegmentsCount, aWidth );
}
}
GLfloat Get3DLayer_Z_Orientation( LAYER_NUM aLayer )
{
double nZ = 1.0;
if( ( aLayer == B_Cu )
|| ( aLayer == B_Adhes )
|| ( aLayer == B_Paste )
|| ( aLayer == B_SilkS )
|| ( aLayer == B_Mask ) )
nZ = -1.0;
return nZ;
}

97
3d-viewer/3d_enums.h Normal file
View File

@ -0,0 +1,97 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file 3d_enums.h
* @brief declared enumerations and flags
*/
#ifndef _3D_ENUMS_H_
#define _3D_ENUMS_H_
/// Flags used in rendering options
enum DISPLAY3D_FLG {
FL_AXIS=0, FL_ZONE,
FL_ADHESIVE, FL_SILKSCREEN, FL_SOLDERMASK, FL_SOLDERPASTE,
FL_COMMENTS, FL_ECO,
FL_MODULE_ATTRIBUTES_NORMAL,
FL_MODULE_ATTRIBUTES_NORMAL_INSERT,
FL_MODULE_ATTRIBUTES_VIRTUAL,
FL_SHOW_BOARD_BODY,
FL_MOUSEWHEEL_PANNING,
FL_USE_REALISTIC_MODE,
FL_RENDER_SHOW_HOLES_IN_ZONES,
// OpenGL options
FL_RENDER_OPENGL_SHOW_MODEL_BBOX,
FL_RENDER_OPENGL_COPPER_THICKNESS,
// Raytracing options
FL_RENDER_RAYTRACING_SHADOWS,
FL_RENDER_RAYTRACING_BACKFLOOR,
FL_RENDER_RAYTRACING_REFRACTIONS,
FL_RENDER_RAYTRACING_REFLECTIONS,
FL_RENDER_RAYTRACING_POST_PROCESSING,
FL_RENDER_RAYTRACING_ANTI_ALIASING,
FL_LAST
};
/// Camera types
enum CAMERA_TYPE
{
CAMERA_TRACKBALL
};
/// Grid types
enum GRID3D_TYPE
{
GRID3D_NONE,
GRID3D_1MM,
GRID3D_2P5MM,
GRID3D_5MM,
GRID3D_10MM
};
/// Render engine mode
enum RENDER_ENGINE
{
RENDER_ENGINE_OPENGL_LEGACY,
RENDER_ENGINE_RAYTRACING,
};
/// Render 3d model shape materials mode
enum MATERIAL_MODE
{
MATERIAL_MODE_NORMAL, ///< Use all material properties from model file
MATERIAL_MODE_DIFFUSE_ONLY, ///< Use only diffuse material properties
MATERIAL_MODE_CAD_MODE ///< Use a gray shading based on diffuse material
};
#endif // _3D_ENUMS_H_

68
3d-viewer/3d_fastmath.cpp Normal file
View File

@ -0,0 +1,68 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file 3d_fastmath.cpp
* @brief
*/
#include "3d_fastmath.h"
// Fast Float Random Numbers
// a small and fast implementation for random float numbers in the range [-1,1]
// References : Posted by dominik.ries[AT]gmail[DOT]com
// http://www.musicdsp.org/showone.php?id=273
// set the initial seed to whatever you like
static int s_randSeed = 1;
// fast rand float, using full 32bit precision
// returns in the range [-1, 1] (not confirmed)
float Fast_RandFloat()
{
s_randSeed *= 16807;
return (float)s_randSeed * 4.6566129e-010f;
}
// Fast rand, as described here:
// http://wiki.osdev.org/Random_Number_Generator
static unsigned long int s_nextRandSeed = 1;
int Fast_rand( void ) // RAND_MAX assumed to be 32767
{
s_nextRandSeed = s_nextRandSeed * 1103515245 + 12345;
return (unsigned int)(s_nextRandSeed >> 16) & 0x7FFF;
}
void Fast_srand( unsigned int seed )
{
s_nextRandSeed = seed;
}

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -47,6 +47,14 @@
#endif
// Fast Float Random Numbers
// a small and fast implementation for random float numbers in the range [-1,1]
// This is not thread safe
float Fast_RandFloat();
int Fast_rand( void );
void Fast_srand( unsigned int seed );
/**
* This part contains some functions from the PBRT 3 source code.
* https://github.com/mmp/pbrt-v3/blob/master/src/core/pbrt.h
@ -85,54 +93,84 @@
// Global Inline Functions
inline uint32_t FloatToBits(float f) {
inline uint32_t FloatToBits( float f )
{
uint32_t ui;
memcpy(&ui, &f, sizeof(float));
memcpy( &ui, &f, sizeof( float ) );
return ui;
}
inline float BitsToFloat(uint32_t ui) {
inline float BitsToFloat( uint32_t ui )
{
float f;
memcpy(&f, &ui, sizeof(uint32_t));
memcpy( &f, &ui, sizeof (uint32_t ) );
return f;
}
inline uint64_t FloatToBits(double f) {
inline uint64_t FloatToBits( double f )
{
uint64_t ui;
memcpy(&ui, &f, sizeof(double));
memcpy( &ui, &f, sizeof( double ) );
return ui;
}
inline double BitsToFloat(uint64_t ui) {
inline double BitsToFloat( uint64_t ui )
{
double f;
memcpy(&f, &ui, sizeof(uint64_t));
memcpy( &f, &ui, sizeof( uint64_t ) );
return f;
}
inline float NextFloatUp(float v) {
inline float NextFloatUp( float v )
{
// Handle infinity and negative zero for _NextFloatUp()_
if (std::isinf(v) && v > 0.) return v;
if (v == -0.f) v = 0.f;
if( std::isinf( v ) && (v > 0.) )
return v;
if( v == -0.f )
v = 0.f;
// Advance _v_ to next higher float
uint32_t ui = FloatToBits(v);
if (v >= 0.)
uint32_t ui = FloatToBits( v );
if( v >= 0. )
++ui;
else
--ui;
return BitsToFloat(ui);
return BitsToFloat( ui );
}
inline float NextFloatDown(float v) {
inline float NextFloatDown( float v )
{
// Handle infinity and positive zero for _NextFloatDown()_
if (std::isinf(v) && v < 0.) return v;
if (v == 0.f) v = -0.f;
uint32_t ui = FloatToBits(v);
if (v > 0.)
if( std::isinf( v ) && (v < 0.) )
return v;
if( v == 0.f )
v = -0.f;
uint32_t ui = FloatToBits( v );
if( v > 0. )
--ui;
else
++ui;
return BitsToFloat(ui);
return BitsToFloat( ui );
}
#endif // 3D_FASTMATH_H

View File

@ -1,913 +0,0 @@
/**
* @file 3d_frame.cpp
*/
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <fctsys.h>
#include <kiface_i.h>
#include <pgm_base.h>
#include <macros.h>
#include <3d_viewer.h>
#include <3d_canvas.h>
#include <info3d_visu.h>
#include <trackball.h>
#include <wx/colordlg.h>
#include <3d_viewer_id.h>
#include <wxBasePcbFrame.h>
INFO3D_VISU g_Parm_3D_Visu;
// Key to store 3D Viewer config:
static const wxChar keyBgColor_Red[] = wxT( "BgColor_Red" );
static const wxChar keyBgColor_Green[] = wxT( "BgColor_Green" );
static const wxChar keyBgColor_Blue[] = wxT( "BgColor_Blue" );
static const wxChar keyBgColor_Red_Top[] = wxT( "BgColor_Red_Top" );
static const wxChar keyBgColor_Green_Top[] = wxT( "BgColor_Green_Top" );
static const wxChar keyBgColor_Blue_Top[] = wxT( "BgColor_Blue_Top" );
static const wxChar keySMaskColor_Red[] = wxT( "SMaskColor_Red" );
static const wxChar keySMaskColor_Green[] = wxT( "SMaskColor_Green" );
static const wxChar keySMaskColor_Blue[] = wxT( "SMaskColor_Blue" );
static const wxChar keySPasteColor_Red[] = wxT( "SPasteColor_Red" );
static const wxChar keySPasteColor_Green[] = wxT( "SPasteColor_Green" );
static const wxChar keySPasteColor_Blue[] = wxT( "SPasteColor_Blue" );
static const wxChar keySilkColor_Red[] = wxT( "SilkColor_Red" );
static const wxChar keySilkColor_Green[] = wxT( "SilkColor_Green" );
static const wxChar keySilkColor_Blue[] = wxT( "SilkColor_Blue" );
static const wxChar keyCopperColor_Red[] = wxT( "CopperColor_Red" );
static const wxChar keyCopperColor_Green[] = wxT( "CopperColor_Green" );
static const wxChar keyCopperColor_Blue[] = wxT( "CopperColor_Blue" );
static const wxChar keyBoardBodyColor_Red[] = wxT( "BoardBodyColor_Red" );
static const wxChar keyBoardBodyColor_Green[] = wxT( "BoardBodyColor_Green" );
static const wxChar keyBoardBodyColor_Blue[]= wxT( "BoardBodyColor_Blue" );
static const wxChar keyMousewheelPanning[] = wxT( "MousewheelPAN3D" );
static const wxChar keyShowRealisticMode[] = wxT( "ShowRealisticMode" );
static const wxChar keyRenderShadows[] = wxT( "Render_Shadows" );
static const wxChar keyRenderRemoveHoles[] = wxT( "Render_RemoveHoles" );
static const wxChar keyRenderTextures[] = wxT( "Render_Textures" );
static const wxChar keyRenderSmoothNormals[] = wxT( "Render_Smooth_Normals" );
static const wxChar keyRenderUseModelNormals[] =wxT( "Render_Use_Model_Normals" );
static const wxChar keyRenderMaterial[] = wxT( "Render_Material" );
static const wxChar keyRenderShowModelBBox[] = wxT( "Render_ShowModelBoudingBoxes" );
static const wxChar keyShowAxis[] = wxT( "ShowAxis" );
static const wxChar keyShowGrid[] = wxT( "ShowGrid3D" );
static const wxChar keyShowGridSize[] = wxT( "Grid3DSize" );
static const wxChar keyShowZones[] = wxT( "ShowZones" );
static const wxChar keyShowFootprints[] = wxT( "ShowFootprints" );
static const wxChar keyShowCopperThickness[] = wxT( "ShowCopperThickness" );
static const wxChar keyShowAdhesiveLayers[] = wxT( "ShowAdhesiveLayers" );
static const wxChar keyShowSilkScreenLayers[] = wxT( "ShowSilkScreenLayers" );
static const wxChar keyShowSolderMaskLayers[] = wxT( "ShowSolderMasLayers" );
static const wxChar keyShowSolderPasteLayers[] =wxT( "ShowSolderPasteLayers" );
static const wxChar keyShowCommentsLayer[] = wxT( "ShowCommentsLayers" );
static const wxChar keyShowBoardBody[] = wxT( "ShowBoardBody" );
static const wxChar keyShowEcoLayers[] = wxT( "ShowEcoLayers" );
BEGIN_EVENT_TABLE( EDA_3D_FRAME, EDA_BASE_FRAME )
EVT_ACTIVATE( EDA_3D_FRAME::OnActivate )
EVT_TOOL_RANGE( ID_ZOOM_IN, ID_ZOOM_PAGE, EDA_3D_FRAME::Process_Zoom )
EVT_TOOL_RANGE( ID_START_COMMAND_3D, ID_END_COMMAND_3D,
EDA_3D_FRAME::Process_Special_Functions )
EVT_TOOL( ID_TOOL_SET_VISIBLE_ITEMS, EDA_3D_FRAME::Process_Special_Functions )
EVT_MENU( wxID_EXIT, EDA_3D_FRAME::Exit3DFrame )
EVT_MENU( ID_MENU_SCREENCOPY_PNG, EDA_3D_FRAME::Process_Special_Functions )
EVT_MENU( ID_MENU_SCREENCOPY_JPEG, EDA_3D_FRAME::Process_Special_Functions )
EVT_MENU_RANGE( ID_MENU3D_GRID, ID_MENU3D_GRID_END,
EDA_3D_FRAME::On3DGridSelection )
EVT_CLOSE( EDA_3D_FRAME::OnCloseWindow )
END_EVENT_TABLE()
EDA_3D_FRAME::EDA_3D_FRAME( KIWAY* aKiway, PCB_BASE_FRAME* aParent,
const wxString& aTitle, long style ) :
KIWAY_PLAYER( aKiway, aParent, FRAME_PCB_DISPLAY3D, aTitle,
wxDefaultPosition, wxDefaultSize, style, VIEWER3D_FRAMENAME )
{
m_canvas = NULL;
m_reloadRequest = false;
m_ortho = false;
// Give it an icon
wxIcon icon;
icon.CopyFromBitmap( KiBitmap( icon_3d_xpm ) );
SetIcon( icon );
LoadSettings( config() );
SetSize( m_FramePos.x, m_FramePos.y, m_FrameSize.x, m_FrameSize.y );
// Create the status line
static const int status_dims[4] = { -1, 130, 130, 170 };
CreateStatusBar( DIM( status_dims ) );
SetStatusWidths( DIM( status_dims ), status_dims );
CreateMenuBar();
ReCreateMainToolbar();
// Make a EDA_3D_CANVAS
// Note: We try to use anti aliasing if the graphic card allows that,
// but only on wxWidgets >= 3.0.0 (this option does not exist on wxWidgets 2.8)
int attrs[] = { // This array should be 2*n+1
// Sadly wxwidgets / glx < 13 allowed
// a thing named "boolean attributes" that don't take a value.
// (See src/unix/glx11.cpp -> wxGLCanvasX11::ConvertWXAttrsToGL() ).
// To avoid problems due to this, just specify those attributes twice.
// Only WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_STEREO are such boolean
// attributes.
// Boolean attributes (using itself at padding):
WX_GL_RGBA, WX_GL_RGBA,
WX_GL_DOUBLEBUFFER, WX_GL_DOUBLEBUFFER,
// Normal attributes with values:
WX_GL_DEPTH_SIZE, 16,
WX_GL_STENCIL_SIZE, 1,
WX_GL_SAMPLE_BUFFERS, 1, // Enable multisampling support (antialiasing).
WX_GL_SAMPLES, 0, // Disable AA for the start.
0 }; // NULL termination
// Check if the canvas supports multisampling.
if( EDA_3D_CANVAS::IsDisplaySupported( attrs ) )
{
// Check for possible sample sizes, start form the top.
int maxSamples = 8; // Any higher doesn't change anything.
int samplesOffset = 0;
for( unsigned int ii = 0; ii < DIM( attrs ); ii += 2 )
{
if( attrs[ii] == WX_GL_SAMPLES )
{
samplesOffset = ii+1;
break;
}
}
attrs[samplesOffset] = maxSamples;
for( ; maxSamples > 0 && !EDA_3D_CANVAS::IsDisplaySupported( attrs );
maxSamples = maxSamples>>1 )
{
attrs[samplesOffset] = maxSamples;
}
}
else
{
// Disable multisampling
for( unsigned int ii = 0; ii < DIM( attrs ); ii += 2 )
{
if( attrs[ii] == WX_GL_SAMPLE_BUFFERS )
{
attrs[ii+1] = 0;
break;
}
}
}
m_canvas = new EDA_3D_CANVAS( this, attrs );
m_auimgr.SetManagedWindow( this );
EDA_PANEINFO horiztb;
horiztb.HorizontalToolbarPane();
m_auimgr.AddPane( m_mainToolBar,
wxAuiPaneInfo( horiztb ).Name( wxT( "m_mainToolBar" ) ).Top() );
m_auimgr.AddPane( m_canvas,
wxAuiPaneInfo().Name( wxT( "DrawFrame" ) ).CentrePane() );
m_auimgr.Update();
// Fixes bug in Windows (XP and possibly others) where the canvas requires the focus
// in order to receive mouse events. Otherwise, the user has to click somewhere on
// the canvas before it will respond to mouse wheel events.
m_canvas->SetFocus();
}
EDA_3D_FRAME::~EDA_3D_FRAME()
{
m_auimgr.UnInit();
}
void EDA_3D_FRAME::Exit3DFrame( wxCommandEvent& event )
{
Close( true );
}
void EDA_3D_FRAME::OnCloseWindow( wxCloseEvent& Event )
{
Destroy();
}
void EDA_3D_FRAME::LoadSettings( wxConfigBase* aCfg )
{
EDA_BASE_FRAME::LoadSettings( aCfg );
INFO3D_VISU& prms = GetPrm3DVisu();
aCfg->Read( keyBgColor_Red, &GetPrm3DVisu().m_BgColor.m_Red, 0.4 );
aCfg->Read( keyBgColor_Green, &GetPrm3DVisu().m_BgColor.m_Green, 0.4 );
aCfg->Read( keyBgColor_Blue, &GetPrm3DVisu().m_BgColor.m_Blue, 0.5 );
aCfg->Read( keyBgColor_Red_Top, &GetPrm3DVisu().m_BgColor_Top.m_Red, 0.8 );
aCfg->Read( keyBgColor_Green_Top, &GetPrm3DVisu().m_BgColor_Top.m_Green, 0.8 );
aCfg->Read( keyBgColor_Blue_Top, &GetPrm3DVisu().m_BgColor_Top.m_Blue, 0.9 );
// m_SolderMaskColor default value = dark grey-green
aCfg->Read( keySMaskColor_Red, &GetPrm3DVisu().m_SolderMaskColor.m_Red, 100.0 * 0.2 / 255.0 );
aCfg->Read( keySMaskColor_Green, &GetPrm3DVisu().m_SolderMaskColor.m_Green, 255.0 * 0.2 / 255.0 );
aCfg->Read( keySMaskColor_Blue, &GetPrm3DVisu().m_SolderMaskColor.m_Blue, 180.0 * 0.2 / 255.0 );
// m_SolderPasteColor default value = light grey
aCfg->Read( keySPasteColor_Red, &GetPrm3DVisu().m_SolderPasteColor.m_Red, 128.0 /255.0 );
aCfg->Read( keySPasteColor_Green, &GetPrm3DVisu().m_SolderPasteColor.m_Green, 128.0 /255.0 );
aCfg->Read( keySPasteColor_Blue, &GetPrm3DVisu().m_SolderPasteColor.m_Blue, 128.0 /255.0 );
// m_SilkScreenColor default value = white
aCfg->Read( keySilkColor_Red, &GetPrm3DVisu().m_SilkScreenColor.m_Red, 0.9 );
aCfg->Read( keySilkColor_Green, &GetPrm3DVisu().m_SilkScreenColor.m_Green, 0.9 );
aCfg->Read( keySilkColor_Blue, &GetPrm3DVisu().m_SilkScreenColor.m_Blue, 0.9 );
// m_CopperColor default value = gold
aCfg->Read( keyCopperColor_Red, &GetPrm3DVisu().m_CopperColor.m_Red, 255.0 * 0.7 / 255.0 );
aCfg->Read( keyCopperColor_Green, &GetPrm3DVisu().m_CopperColor.m_Green, 223.0 * 0.7 / 255.0 );
aCfg->Read( keyCopperColor_Blue, &GetPrm3DVisu().m_CopperColor.m_Blue, 0.0 /255.0 );
// m_BoardBodyColor default value = FR4, in realistic mode
aCfg->Read( keyBoardBodyColor_Red, &GetPrm3DVisu().m_BoardBodyColor.m_Red, 51.0 / 255.0 );
aCfg->Read( keyBoardBodyColor_Green, &GetPrm3DVisu().m_BoardBodyColor.m_Green, 43.0 / 255.0 );
aCfg->Read( keyBoardBodyColor_Blue, &GetPrm3DVisu().m_BoardBodyColor.m_Blue, 22.0 /255.0 );
bool tmp;
aCfg->Read( keyMousewheelPanning, &tmp, false );
prms.SetFlag( FL_MOUSEWHEEL_PANNING, tmp );
aCfg->Read( keyShowRealisticMode, &tmp, false );
prms.SetFlag( FL_USE_REALISTIC_MODE, tmp );
aCfg->Read( keyRenderShadows, &tmp, false );
prms.SetFlag( FL_RENDER_SHADOWS, tmp );
aCfg->Read( keyRenderRemoveHoles, &tmp, false );
prms.SetFlag( FL_RENDER_SHOW_HOLES_IN_ZONES, tmp );
aCfg->Read( keyRenderTextures, &tmp, false );
prms.SetFlag( FL_RENDER_TEXTURES, tmp );
aCfg->Read( keyRenderSmoothNormals, &tmp, false );
prms.SetFlag( FL_RENDER_SMOOTH_NORMALS, tmp );
aCfg->Read( keyRenderUseModelNormals, &tmp, false );
prms.SetFlag( FL_RENDER_USE_MODEL_NORMALS, tmp );
aCfg->Read( keyRenderMaterial, &tmp, false );
prms.SetFlag( FL_RENDER_MATERIAL, tmp );
aCfg->Read( keyRenderShowModelBBox, &tmp, false );
prms.SetFlag( FL_RENDER_SHOW_MODEL_BBOX, tmp );
aCfg->Read( keyShowAxis, &tmp, true );
prms.SetFlag( FL_AXIS, tmp );
aCfg->Read( keyShowGrid, &tmp, true );
prms.SetFlag( FL_GRID, tmp );
aCfg->Read( keyShowGridSize, &prms.m_3D_Grid, 10.0 );
aCfg->Read( keyShowFootprints, &tmp, true );
prms.SetFlag( FL_MODULE, tmp );
aCfg->Read( keyShowCopperThickness, &tmp, false );
prms.SetFlag( FL_USE_COPPER_THICKNESS, tmp );
aCfg->Read( keyShowZones, &tmp, true );
prms.SetFlag( FL_ZONE, tmp );
aCfg->Read( keyShowAdhesiveLayers, &tmp, true );
prms.SetFlag( FL_ADHESIVE, tmp );
aCfg->Read( keyShowSilkScreenLayers, &tmp, true );
prms.SetFlag( FL_SILKSCREEN, tmp );
aCfg->Read( keyShowSolderMaskLayers, &tmp, true );
prms.SetFlag( FL_SOLDERMASK, tmp );
aCfg->Read( keyShowSolderPasteLayers, &tmp, true );
prms.SetFlag( FL_SOLDERPASTE, tmp );
aCfg->Read( keyShowCommentsLayer, &tmp, true );
prms.SetFlag( FL_COMMENTS, tmp );
aCfg->Read( keyShowEcoLayers, &tmp, true );
prms.SetFlag( FL_ECO, tmp );
aCfg->Read( keyShowBoardBody, &tmp, true );
prms.SetFlag( FL_SHOW_BOARD_BODY, tmp );
}
void EDA_3D_FRAME::SaveSettings( wxConfigBase* aCfg )
{
EDA_BASE_FRAME::SaveSettings( aCfg );
INFO3D_VISU& prms = GetPrm3DVisu();
aCfg->Write( keyBgColor_Red, GetPrm3DVisu().m_BgColor.m_Red );
aCfg->Write( keyBgColor_Green, GetPrm3DVisu().m_BgColor.m_Green );
aCfg->Write( keyBgColor_Blue, GetPrm3DVisu().m_BgColor.m_Blue );
aCfg->Write( keyBgColor_Red_Top, GetPrm3DVisu().m_BgColor_Top.m_Red );
aCfg->Write( keyBgColor_Green_Top, GetPrm3DVisu().m_BgColor_Top.m_Green );
aCfg->Write( keyBgColor_Blue_Top, GetPrm3DVisu().m_BgColor_Top.m_Blue );
aCfg->Write( keySMaskColor_Red, GetPrm3DVisu().m_SolderMaskColor.m_Red );
aCfg->Write( keySMaskColor_Green, GetPrm3DVisu().m_SolderMaskColor.m_Green );
aCfg->Write( keySMaskColor_Blue, GetPrm3DVisu().m_SolderMaskColor.m_Blue );
aCfg->Write( keySPasteColor_Red, GetPrm3DVisu().m_SolderPasteColor.m_Red );
aCfg->Write( keySPasteColor_Green, GetPrm3DVisu().m_SolderPasteColor.m_Green );
aCfg->Write( keySPasteColor_Blue, GetPrm3DVisu().m_SolderPasteColor.m_Blue );
aCfg->Write( keySilkColor_Red, GetPrm3DVisu().m_SilkScreenColor.m_Red );
aCfg->Write( keySilkColor_Green, GetPrm3DVisu().m_SilkScreenColor.m_Green );
aCfg->Write( keySilkColor_Blue, GetPrm3DVisu().m_SilkScreenColor.m_Blue );
aCfg->Write( keyCopperColor_Red, GetPrm3DVisu().m_CopperColor.m_Red );
aCfg->Write( keyCopperColor_Green, GetPrm3DVisu().m_CopperColor.m_Green );
aCfg->Write( keyCopperColor_Blue, GetPrm3DVisu().m_CopperColor.m_Blue );
aCfg->Write( keyBoardBodyColor_Red, GetPrm3DVisu().m_BoardBodyColor.m_Red );
aCfg->Write( keyBoardBodyColor_Green, GetPrm3DVisu().m_BoardBodyColor.m_Green );
aCfg->Write( keyBoardBodyColor_Blue, GetPrm3DVisu().m_BoardBodyColor.m_Blue );
aCfg->Write( keyMousewheelPanning, prms.GetFlag( FL_MOUSEWHEEL_PANNING ) );
aCfg->Write( keyShowRealisticMode, prms.GetFlag( FL_USE_REALISTIC_MODE ) );
aCfg->Write( keyRenderShadows, prms.GetFlag( FL_RENDER_SHADOWS ) );
aCfg->Write( keyRenderRemoveHoles, prms.GetFlag( FL_RENDER_SHOW_HOLES_IN_ZONES ) );
aCfg->Write( keyRenderTextures, prms.GetFlag( FL_RENDER_TEXTURES ) );
aCfg->Write( keyRenderSmoothNormals, prms.GetFlag( FL_RENDER_SMOOTH_NORMALS ) );
aCfg->Write( keyRenderUseModelNormals, prms.GetFlag( FL_RENDER_USE_MODEL_NORMALS ) );
aCfg->Write( keyRenderMaterial, prms.GetFlag( FL_RENDER_MATERIAL ) );
aCfg->Write( keyRenderShowModelBBox, prms.GetFlag( FL_RENDER_SHOW_MODEL_BBOX ) );
aCfg->Write( keyShowAxis, prms.GetFlag( FL_AXIS ) );
aCfg->Write( keyShowGrid, prms.GetFlag( FL_GRID ) );
aCfg->Write( keyShowGridSize, prms.m_3D_Grid );
aCfg->Write( keyShowFootprints, prms.GetFlag( FL_MODULE ) );
aCfg->Write( keyShowCopperThickness, prms.GetFlag( FL_USE_COPPER_THICKNESS ) );
aCfg->Write( keyShowZones, prms.GetFlag( FL_ZONE ) );
aCfg->Write( keyShowAdhesiveLayers, prms.GetFlag( FL_ADHESIVE ) );
aCfg->Write( keyShowSilkScreenLayers, prms.GetFlag( FL_SILKSCREEN ) );
aCfg->Write( keyShowSolderMaskLayers, prms.GetFlag( FL_SOLDERMASK ) );
aCfg->Write( keyShowSolderPasteLayers, prms.GetFlag( FL_SOLDERPASTE ) );
aCfg->Write( keyShowCommentsLayer, prms.GetFlag( FL_COMMENTS ) );
aCfg->Write( keyShowEcoLayers, prms.GetFlag( FL_ECO ) );
aCfg->Write( keyShowBoardBody, prms.GetFlag( FL_SHOW_BOARD_BODY ) );
}
void EDA_3D_FRAME::Process_Zoom( wxCommandEvent& event )
{
int ii;
switch( event.GetId() )
{
case ID_ZOOM_PAGE:
for( ii = 0; ii < 4; ii++ )
GetPrm3DVisu().m_Rot[ii] = 0.0;
GetPrm3DVisu().m_Zoom = 1.0;
m_canvas->SetOffset( 0.0, 0.0 );
trackball( GetPrm3DVisu().m_Quat, 0.0, 0.0, 0.0, 0.0 );
break;
case ID_ZOOM_IN:
GetPrm3DVisu().m_Zoom /= 1.2;
if( GetPrm3DVisu().m_Zoom <= 0.01 )
GetPrm3DVisu().m_Zoom = 0.01;
break;
case ID_ZOOM_OUT:
GetPrm3DVisu().m_Zoom *= 1.2;
break;
case ID_ZOOM_REDRAW:
break;
default:
return;
}
m_canvas->Refresh( false );
m_canvas->DisplayStatus();
}
void EDA_3D_FRAME::OnLeftClick( wxDC* DC, const wxPoint& MousePos )
{
}
void EDA_3D_FRAME::OnRightClick( const wxPoint& MousePos, wxMenu* PopMenu )
{
}
double EDA_3D_FRAME::BestZoom()
{
return 1.0;
}
void EDA_3D_FRAME::RedrawActiveWindow( wxDC* DC, bool EraseBg )
{
}
void EDA_3D_FRAME::Process_Special_Functions( wxCommandEvent& event )
{
#define ROT_ANGLE 10.0
int id = event.GetId();
bool isChecked = event.IsChecked();
switch( id )
{
case ID_TOOL_SET_VISIBLE_ITEMS:
Install_3D_ViewOptionDialog( event );
break;
case ID_RELOAD3D_BOARD:
m_reloadRequest = true;
NewDisplay();
return;
break;
case ID_ROTATE3D_X_POS:
GetPrm3DVisu().m_ROTX += ROT_ANGLE;
break;
case ID_ROTATE3D_X_NEG:
GetPrm3DVisu().m_ROTX -= ROT_ANGLE;
break;
case ID_ROTATE3D_Y_POS:
GetPrm3DVisu().m_ROTY += ROT_ANGLE;
break;
case ID_ROTATE3D_Y_NEG:
GetPrm3DVisu().m_ROTY -= ROT_ANGLE;
break;
case ID_ROTATE3D_Z_POS:
GetPrm3DVisu().m_ROTZ += ROT_ANGLE;
break;
case ID_ROTATE3D_Z_NEG:
GetPrm3DVisu().m_ROTZ -= ROT_ANGLE;
break;
case ID_MOVE3D_LEFT:
m_canvas->SetView3D( WXK_LEFT );
return;
case ID_MOVE3D_RIGHT:
m_canvas->SetView3D( WXK_RIGHT );
return;
case ID_MOVE3D_UP:
m_canvas->SetView3D( WXK_UP );
return;
case ID_MOVE3D_DOWN:
m_canvas->SetView3D( WXK_DOWN );
return;
case ID_ORTHO:
ToggleOrtho();
return;
case ID_TOOL_SCREENCOPY_TOCLIBBOARD:
case ID_MENU_SCREENCOPY_PNG:
case ID_MENU_SCREENCOPY_JPEG:
m_canvas->TakeScreenshot( event );
break;
case ID_MENU3D_BGCOLOR_BOTTOM_SELECTION:
if( Set3DColorFromUser( GetPrm3DVisu().m_BgColor, _( "Background Color, Bottom" ) ) )
m_canvas->Refresh( true );
return;
case ID_MENU3D_BGCOLOR_TOP_SELECTION:
if( Set3DColorFromUser( GetPrm3DVisu().m_BgColor_Top, _( "Background Color, Top" ) ) )
m_canvas->Refresh( true );
return;
case ID_MENU3D_SILKSCREEN_COLOR_SELECTION:
Set3DSilkScreenColorFromUser();
return;
case ID_MENU3D_SOLDERMASK_COLOR_SELECTION:
Set3DSolderMaskColorFromUser();
return;
case ID_MENU3D_SOLDERPASTE_COLOR_SELECTION:
Set3DSolderPasteColorFromUser();
return;
case ID_MENU3D_COPPER_COLOR_SELECTION:
Set3DCopperColorFromUser();
break;
case ID_MENU3D_PCB_BODY_COLOR_SELECTION:
Set3DBoardBodyColorFromUser();
break;
case ID_MENU3D_MOUSEWHEEL_PANNING:
GetPrm3DVisu().SetFlag( FL_MOUSEWHEEL_PANNING, isChecked );
return;
case ID_MENU3D_REALISTIC_MODE:
GetPrm3DVisu().SetFlag( FL_USE_REALISTIC_MODE, isChecked );
GetMenuBar()->FindItem( ID_MENU3D_COMMENTS_ONOFF )->Enable( !isChecked );
GetMenuBar()->FindItem( ID_MENU3D_ECO_ONOFF )->Enable( !isChecked );
NewDisplay();
return;
case ID_MENU3D_FL_RENDER_SHADOWS:
GetPrm3DVisu().SetFlag( FL_RENDER_SHADOWS, isChecked );
NewDisplay();
return;
case ID_MENU3D_FL_RENDER_SHOW_HOLES_IN_ZONES:
GetPrm3DVisu().SetFlag( FL_RENDER_SHOW_HOLES_IN_ZONES, isChecked );
NewDisplay();
return;
case ID_MENU3D_FL_RENDER_TEXTURES:
GetPrm3DVisu().SetFlag( FL_RENDER_TEXTURES, isChecked );
NewDisplay(GL_ID_BOARD);
NewDisplay(GL_ID_TECH_LAYERS);
return;
case ID_MENU3D_FL_RENDER_SMOOTH_NORMALS:
GetPrm3DVisu().SetFlag( FL_RENDER_SMOOTH_NORMALS, isChecked );
NewDisplay();
return;
case ID_MENU3D_FL_RENDER_USE_MODEL_NORMALS:
GetPrm3DVisu().SetFlag( FL_RENDER_USE_MODEL_NORMALS, isChecked );
NewDisplay();
return;
case ID_MENU3D_FL_RENDER_MATERIAL:
GetPrm3DVisu().SetFlag( FL_RENDER_MATERIAL, isChecked );
NewDisplay();
return;
case ID_MENU3D_FL_RENDER_SHOW_MODEL_BBOX:
GetPrm3DVisu().SetFlag( FL_RENDER_SHOW_MODEL_BBOX, isChecked );
NewDisplay();
return;
case ID_MENU3D_SHOW_BOARD_BODY:
GetPrm3DVisu().SetFlag( FL_SHOW_BOARD_BODY, isChecked );
NewDisplay();
return;
case ID_MENU3D_AXIS_ONOFF:
GetPrm3DVisu().SetFlag( FL_AXIS, isChecked );
m_canvas->Refresh();
return;
case ID_MENU3D_MODULE_ONOFF:
GetPrm3DVisu().SetFlag( FL_MODULE, isChecked );
m_canvas->Refresh();
return;
case ID_MENU3D_USE_COPPER_THICKNESS:
GetPrm3DVisu().SetFlag( FL_USE_COPPER_THICKNESS, isChecked );
NewDisplay( GL_ID_BOARD );
NewDisplay( GL_ID_TECH_LAYERS );
return;
case ID_MENU3D_ZONE_ONOFF:
GetPrm3DVisu().SetFlag( FL_ZONE, isChecked );
NewDisplay( GL_ID_BOARD );
return;
case ID_MENU3D_ADHESIVE_ONOFF:
GetPrm3DVisu().SetFlag( FL_ADHESIVE, isChecked );
NewDisplay( GL_ID_TECH_LAYERS );
return;
case ID_MENU3D_SILKSCREEN_ONOFF:
GetPrm3DVisu().SetFlag( FL_SILKSCREEN, isChecked );
NewDisplay( GL_ID_TECH_LAYERS );
return;
case ID_MENU3D_SOLDER_MASK_ONOFF:
GetPrm3DVisu().SetFlag( FL_SOLDERMASK, isChecked );
NewDisplay( GL_ID_TECH_LAYERS );
return;
case ID_MENU3D_SOLDER_PASTE_ONOFF:
GetPrm3DVisu().SetFlag( FL_SOLDERPASTE, isChecked );
NewDisplay( GL_ID_TECH_LAYERS );
return;
case ID_MENU3D_COMMENTS_ONOFF:
GetPrm3DVisu().SetFlag( FL_COMMENTS, isChecked );
NewDisplay( GL_ID_AUX_LAYERS );
return;
case ID_MENU3D_ECO_ONOFF:
GetPrm3DVisu().SetFlag( FL_ECO, isChecked );
NewDisplay( GL_ID_AUX_LAYERS );
return;
default:
wxLogMessage( wxT( "EDA_3D_FRAME::Process_Special_Functions() error: unknown command" ) );
return;
}
m_canvas->Refresh( true );
m_canvas->DisplayStatus();
}
void EDA_3D_FRAME::On3DGridSelection( wxCommandEvent& event )
{
int id = event.GetId();
for( int ii = ID_MENU3D_GRID_NOGRID; ii < ID_MENU3D_GRID_END; ii++ )
{
if( event.GetId() == ii )
continue;
GetMenuBar()->Check( ii, false );
}
switch( id )
{
case ID_MENU3D_GRID_NOGRID:
GetPrm3DVisu().SetFlag( FL_GRID, false );
break;
case ID_MENU3D_GRID_10_MM:
GetPrm3DVisu().SetFlag( FL_GRID, true );
GetPrm3DVisu().m_3D_Grid = 10.0;
break;
case ID_MENU3D_GRID_5_MM:
GetPrm3DVisu().SetFlag( FL_GRID, true );
GetPrm3DVisu().m_3D_Grid = 5.0;
break;
case ID_MENU3D_GRID_2P5_MM:
GetPrm3DVisu().SetFlag( FL_GRID, true );
GetPrm3DVisu().m_3D_Grid = 2.5;
break;
case ID_MENU3D_GRID_1_MM:
GetPrm3DVisu().SetFlag( FL_GRID, true );
GetPrm3DVisu().m_3D_Grid = 1.0;
break;
default:
wxLogMessage( wxT( "EDA_3D_FRAME::On3DGridSelection() error: unknown command" ) );
return;
}
NewDisplay( GL_ID_GRID );
}
void EDA_3D_FRAME::NewDisplay( int aGlList )
{
m_canvas->ClearLists( aGlList );
// Rebuild the 3D board and refresh the view on reload request:
if( m_reloadRequest )
m_canvas->ReportWarnings( true );
m_canvas->Refresh( true );
m_canvas->DisplayStatus();
m_reloadRequest = false;
}
void EDA_3D_FRAME::OnActivate( wxActivateEvent& event )
{
// Reload data if 3D frame shows a board,
// because it can be changed since last frame activation
if( m_reloadRequest )
NewDisplay();
event.Skip(); // required under wxMAC
}
bool EDA_3D_FRAME::Set3DColorFromUser( S3D_COLOR &aColor, const wxString& aTitle,
wxColourData* aPredefinedColors )
{
wxColour newcolor, oldcolor;
oldcolor.Set( KiROUND( aColor.m_Red * 255 ),
KiROUND( aColor.m_Green * 255 ),
KiROUND( aColor.m_Blue * 255 ) );
wxColourData emptyColorSet; // Provides a empty predefined set of colors
// if no color set available to avoid use of an
// old color set
if( aPredefinedColors == NULL )
aPredefinedColors = &emptyColorSet;
newcolor = wxGetColourFromUser( this, oldcolor, aTitle, aPredefinedColors );
if( !newcolor.IsOk() ) // Cancel command
return false;
if( newcolor != oldcolor )
{
aColor.m_Red = (double) newcolor.Red() / 255.0;
aColor.m_Green = (double) newcolor.Green() / 255.0;
aColor.m_Blue = (double) newcolor.Blue() / 255.0;
}
return true;
}
bool EDA_3D_FRAME::Set3DSilkScreenColorFromUser()
{
wxColourData definedColors;
definedColors.SetCustomColour(0, wxColour( 241, 241, 241 ) ); // White
definedColors.SetCustomColour(1, wxColour( 180, 180, 180 ) ); // Gray
bool change = Set3DColorFromUser( GetPrm3DVisu().m_SilkScreenColor,
_( "Silk Screen Color" ),
&definedColors );
if( change )
NewDisplay( GL_ID_TECH_LAYERS );
return change;
}
bool EDA_3D_FRAME::Set3DSolderMaskColorFromUser()
{
wxColourData definedColors;
definedColors.SetCustomColour(0, wxColour( 20, 51, 36 ) ); // Green
definedColors.SetCustomColour(1, wxColour( 43, 10, 65 ) ); // Purple
definedColors.SetCustomColour(2, wxColour( 117, 19, 21 ) ); // Red
definedColors.SetCustomColour(3, wxColour( 54, 79, 116) ); // Light blue
definedColors.SetCustomColour(4, wxColour( 11, 11, 11 ) ); // Black
definedColors.SetCustomColour(5, wxColour( 241, 241,241) ); // White
bool change = Set3DColorFromUser( GetPrm3DVisu().m_SolderMaskColor,
_( "Solder Mask Color" ),
&definedColors );
if( change )
NewDisplay( GL_ID_TECH_LAYERS );
return change;
}
bool EDA_3D_FRAME::Set3DCopperColorFromUser()
{
wxColourData definedColors;
definedColors.SetCustomColour( 0, wxColour( 184, 115, 50 ) ); // Copper
definedColors.SetCustomColour( 1, wxColour( 233, 221, 82 ) ); // Gold
definedColors.SetCustomColour( 2, wxColour( 213, 213, 213) ); // Silver
definedColors.SetCustomColour( 3, wxColour( 160, 160, 160) ); // tin
bool change = Set3DColorFromUser( GetPrm3DVisu().m_CopperColor,
_( "Copper Color" ),
&definedColors );
if( change )
NewDisplay( GL_ID_BOARD );
return change;
}
bool EDA_3D_FRAME::Set3DBoardBodyColorFromUser()
{
wxColourData definedColors;
definedColors.SetCustomColour( 0, wxColour( 51, 43, 22 ) ); // FR4 natural, dark
definedColors.SetCustomColour( 1, wxColour( 109, 116, 75 ) ); // FR4 natural
definedColors.SetCustomColour( 2, wxColour( 78, 14, 5 ) ); // brown/red
definedColors.SetCustomColour( 3, wxColour( 146, 99, 47 ) ); // brown 1
definedColors.SetCustomColour( 4, wxColour( 160, 123, 54 ) ); // brown 2
definedColors.SetCustomColour( 5, wxColour( 146, 99, 47 ) ); // brown 3
definedColors.SetCustomColour( 6, wxColour( 63, 126, 71 ) ); // green 1
definedColors.SetCustomColour( 7, wxColour( 117, 122, 90 ) ); // green 2
bool change = Set3DColorFromUser( GetPrm3DVisu().m_BoardBodyColor,
_( "Board Body Color" ),
&definedColors );
if( change )
NewDisplay( GL_ID_BOARD );
return change;
}
bool EDA_3D_FRAME::Set3DSolderPasteColorFromUser()
{
wxColourData definedColors;
definedColors.SetCustomColour(0, wxColour( 128, 128, 128 ) ); // grey
definedColors.SetCustomColour(1, wxColour( 213, 213, 213 ) ); // Silver
definedColors.SetCustomColour(2, wxColour( 90, 90, 90 ) ); // grey 2
bool change = Set3DColorFromUser( GetPrm3DVisu().m_SolderPasteColor,
_( "Solder Paste Color" ),
&definedColors );
if( change )
NewDisplay( GL_ID_TECH_LAYERS );
return change;
}
BOARD* EDA_3D_FRAME::GetBoard()
{
return Parent()->GetBoard();
}
INFO3D_VISU& EDA_3D_FRAME::GetPrm3DVisu() const
{
// return the INFO3D_VISU which contains the current parameters
// to draw the 3D view of the board
return g_Parm_3D_Visu;
}
bool EDA_3D_FRAME::IsEnabled( DISPLAY3D_FLG aItem ) const
{
// return true if aItem must be displayed
return GetPrm3DVisu().GetFlag( aItem );
}

View File

@ -1,156 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014-2015 Mario Luzeiro <mrluzeiro@gmail.com>
* Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file 3d_class.cpp
*/
#include <fctsys.h>
#include <3d_struct.h>
#include <3d_material.h>
#include <info3d_visu.h>
#ifdef __WXMAC__
# ifdef __DARWIN__
# include <OpenGL/glu.h>
# else
# include <glu.h>
# endif
#else
# include <GL/glu.h>
#endif
S3D_MATERIAL::S3D_MATERIAL( S3D_MASTER* father, const wxString& name ) :
EDA_ITEM( father, NOT_USED )
{
m_Name = name;
m_AmbientColor.clear();
m_DiffuseColor.clear();
m_EmissiveColor.clear();
m_SpecularColor.clear();
m_Shininess.clear();
m_Transparency.clear();
m_ColorPerVertex = false;
}
void SetOpenGlDefaultMaterial()
{
glm::vec4 ambient( 0.2f, 0.2f, 0.2f, 1.0f );
glm::vec4 specular( 0.0f, 0.0f, 0.0f, 1.0f );
glm::vec4 emissive( 0.0f, 0.0f, 0.0f, 1.0f );
glm::vec4 diffuse( 0.0f, 0.0f, 0.0f, 1.0f );
GLint shininess_value = 0;
glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
glMateriali ( GL_FRONT_AND_BACK, GL_SHININESS, shininess_value );
glMaterialfv( GL_FRONT_AND_BACK, GL_EMISSION, &emissive.x );
glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, &specular.x );
glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, &ambient.x );
glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, &diffuse.x );
}
bool S3D_MATERIAL::SetOpenGLMaterial( unsigned int aMaterialIndex, bool aUseMaterial )
{
if( aUseMaterial )
{
float transparency_value = 0.0f;
if( m_Transparency.size() > aMaterialIndex )
{
transparency_value = m_Transparency[aMaterialIndex];
}
else
{
if( m_Transparency.size() > 0 )
transparency_value = m_Transparency[0];
}
if( m_DiffuseColor.size() > aMaterialIndex )
{
glm::vec3 color = m_DiffuseColor[aMaterialIndex];
glColor4f( color.x, color.y, color.z, 1.0f - transparency_value );
}
else
{
if( m_DiffuseColor.size() == 0 )
{
glColor4f( 0.8f, 0.8f, 0.8f, 1.0f );
}
}
if( m_Shininess.size() > 0 )
{
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, m_Shininess[0] );
}
// emissive
if( m_EmissiveColor.size() > aMaterialIndex )
{
glm::vec4 emissive;
emissive[0] = m_EmissiveColor[aMaterialIndex].x;
emissive[1] = m_EmissiveColor[aMaterialIndex].y;
emissive[2] = m_EmissiveColor[aMaterialIndex].z;
emissive[3] = 1.0f;
glMaterialfv( GL_FRONT_AND_BACK, GL_EMISSION, &emissive.x );
}
// specular
if( m_SpecularColor.size() > aMaterialIndex )
{
glm::vec4 specular;
specular[0] = m_SpecularColor[aMaterialIndex].x;
specular[1] = m_SpecularColor[aMaterialIndex].y;
specular[2] = m_SpecularColor[aMaterialIndex].z;
specular[3] = 1.0f;
glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, &specular.x );
}
// ambient
if( m_AmbientColor.size() > aMaterialIndex )
{
glm::vec4 ambient;
ambient[0] = m_AmbientColor[aMaterialIndex].x;
ambient[1] = m_AmbientColor[aMaterialIndex].y;
ambient[2] = m_AmbientColor[aMaterialIndex].z;
ambient[3] = 1.0f;
glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, &ambient.x );
}
return (transparency_value != 0.0f);
}
else
{
if( m_DiffuseColor.size() > aMaterialIndex )
{
glm::vec3 color = m_DiffuseColor[aMaterialIndex];
glColor4f( color.x, color.y, color.z, 1.0 );
}
}
return false;
}

View File

@ -1,83 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014-2015 Mario Luzeiro <mrluzeiro@gmail.com>
* Copyright (C) 1992-2014 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file 3d_material.h
*/
#ifndef STRUCT_3D_MATERIAL_H
#define STRUCT_3D_MATERIAL_H
#include <common.h>
#include <base_struct.h>
#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
class S3D_MASTER;
class S3D_MATERIAL : public EDA_ITEM // openGL "material" data
{
public:
wxString m_Name;
// Material list
std::vector< glm::vec3 > m_AmbientColor;
std::vector< glm::vec3 > m_DiffuseColor;
std::vector< glm::vec3 > m_EmissiveColor;
std::vector< glm::vec3 > m_SpecularColor;
std::vector< float > m_Shininess;
std::vector< float > m_Transparency;
bool m_ColorPerVertex;
public:
S3D_MATERIAL( S3D_MASTER* father, const wxString& name );
S3D_MATERIAL* Next() const { return (S3D_MATERIAL*) Pnext; }
S3D_MATERIAL* Back() const { return (S3D_MATERIAL*) Pback; }
/**
* Initialize the material prms.
* @param aMaterialIndex = the index in list of available materials
* @param aUseMaterial = true to use the values found in the available material
* = false to use only the color, and other prms are fixed
* @return true if the material is transparency
*/
bool SetOpenGLMaterial(unsigned int aMaterialIndex, bool aUseMaterial);
#if defined(DEBUG)
void Show( int nestLevel, std::ostream& os ) const { ShowDummy( os ); } // override
#endif
/** Get class name
* @return string "S3D_MATERIAL"
*/
virtual wxString GetClass() const
{
return wxT( "S3D_MATERIAL" );
}
};
void SetOpenGlDefaultMaterial();
#endif

31
3d-viewer/3d_math.cpp Normal file
View File

@ -0,0 +1,31 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file 3d_math.cpp
* @brief
*/
#include "3d_math.h"

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -30,8 +30,8 @@
#ifndef _3D_MATH_H
#define _3D_MATH_H
#include "plugins/3dapi/xv3d_types.h"
#include <plugins/3dapi/xv3d_types.h>
#include "3d_fastmath.h"
// https://en.wikipedia.org/wiki/Spherical_coordinate_system
/**
@ -53,13 +53,21 @@ inline SFVEC3F SphericalToCartesian( float aInclination, float aAzimuth )
// !TODO: this is not correct because it is not a gaussian random
inline SFVEC3F UniformRandomHemisphereDirection( )
{
SFVEC3F b( (rand()/(float)RAND_MAX) - 0.5f, (rand()/(float)RAND_MAX) - 0.5f, (rand()/(float)RAND_MAX) - 0.5f);
// It was experienced that this function is slow! do not use it :/
// SFVEC3F b( (rand()/(float)RAND_MAX) - 0.5f,
// (rand()/(float)RAND_MAX) - 0.5f,
// (rand()/(float)RAND_MAX) - 0.5f );
SFVEC3F b( Fast_RandFloat() * 0.5f,
Fast_RandFloat() * 0.5f,
Fast_RandFloat() * 0.5f );
return b;
}
// https://pathtracing.wordpress.com/2011/03/03/cosine-weighted-hemisphere/
inline SFVEC3F CosWeightedRandomHemisphereDirection( SFVEC3F n )
inline SFVEC3F CosWeightedRandomHemisphereDirection( const SFVEC3F &n )
{
const float Xi1 = (float)rand() / (float)RAND_MAX;
const float Xi2 = (float)rand() / (float)RAND_MAX;
@ -74,9 +82,9 @@ inline SFVEC3F CosWeightedRandomHemisphereDirection( SFVEC3F n )
const SFVEC3F y( n.x, n.y, n.z );
SFVEC3F h = y;
if (fabs( h.x ) <= fabs( h.y ) && fabs( h.x ) <= fabs( h.z ) )
if( fabs( h.x ) <= fabs( h.y ) && fabs( h.x ) <= fabs( h.z ) )
h.x= 1.0f;
else if (fabs(h.y)<=fabs(h.x) && fabs(h.y)<=fabs(h.z))
else if( fabs( h.y ) <= fabs( h.x ) && fabs( h.y ) <= fabs( h.z ) )
h.y= 1.0f;
else
h.z= 1.0f;
@ -92,15 +100,20 @@ inline SFVEC3F CosWeightedRandomHemisphereDirection( SFVEC3F n )
/**
* @brief Refract
* Based on: https://github.com/mmp/pbrt-v3/blob/master/src/core/reflection.h
* See also: http://www.flipcode.com/archives/Raytracing_Topics_Techniques-Part_3_Refractions_and_Beers_Law.shtml
* Based on:
* https://github.com/mmp/pbrt-v3/blob/master/src/core/reflection.h
* See also:
* http://www.flipcode.com/archives/Raytracing_Topics_Techniques-Part_3_Refractions_and_Beers_Law.shtml
* @param aInVector incoming vector
* @param aNormal normal in the intersection point
* @param aRin_over_Rout incoming refraction index / out refraction index
* @param aOutVector the refracted vector
* @return true
*/
inline bool Refract( const SFVEC3F &aInVector, const SFVEC3F &aNormal, float aRin_over_Rout, SFVEC3F &aOutVector )
inline bool Refract( const SFVEC3F &aInVector,
const SFVEC3F &aNormal,
float aRin_over_Rout,
SFVEC3F &aOutVector )
{
float cosThetaI = -glm::dot( aNormal, aInVector );
float sin2ThetaI = glm::max( 0.0f, 1.0f - cosThetaI * cosThetaI );
@ -111,15 +124,66 @@ inline bool Refract( const SFVEC3F &aInVector, const SFVEC3F &aNormal, float aRi
return false;
float cosThetaT = sqrtf( 1.0f - sin2ThetaT );
aOutVector = glm::normalize( aRin_over_Rout * aInVector + ( aRin_over_Rout * cosThetaI - cosThetaT ) * aNormal );
aOutVector = glm::normalize( aRin_over_Rout * aInVector +
( aRin_over_Rout * cosThetaI - cosThetaT ) *
aNormal );
return true;
}
inline float mapf( float x, float in_min, float in_max, float out_min, float out_max)
inline float mapf( float x,
float in_min,
float in_max,
float out_min,
float out_max)
{
x = glm::clamp( x, in_min, in_max );
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
inline SFVEC3F MaterialDiffuseToColorCAD( const SFVEC3F &aDiffuseColor )
{
// convert to a discret scale of grays
const float luminance = glm::min( (((float)((unsigned int) ( 4.0f *
(aDiffuseColor.r * 0.2126f +
aDiffuseColor.g * 0.7152f +
aDiffuseColor.b * 0.0722f))) + 0.5f) /
4.0f) * 1.0f,
1.0f );
const float maxValue = glm::max( glm::max( glm::max( aDiffuseColor.r,
aDiffuseColor.g),
aDiffuseColor.b ),
FLT_EPSILON );
return (aDiffuseColor / SFVEC3F(maxValue) ) * 0.125f + luminance* 0.875f;
}
// http://fooplot.com/#W3sidHlwZSI6MCwiZXEiOiJ4KngqMiIsImNvbG9yIjoiIzAwMDAwMCJ9LHsidHlwZSI6MCwiZXEiOiItKCh4LTEpXjIpKjIrMSIsImNvbG9yIjoiIzAwMDAwMCJ9LHsidHlwZSI6MTAwMCwid2luZG93IjpbIi0xLjM4NzUwMDAwMDAwMDAwMDIiLCIxLjg2MjQ5OTk5OTk5OTk5OTgiLCItMC43IiwiMS4zIl19XQ--
inline float QuadricEasingInOut( float t )
{
if( t <= 0.5f )
{
return t * t * 2.0f;
}
else
{
t = t - 1.0f;
return -2.0f * (t * t) + 1.0f;
}
}
// http://www.wolframalpha.com/input/?i=t%5E2(3-2t)
inline float BezierBlend( float t )
{
return t * t * ( 3.0f - 2.0f * t );
}
#endif // 3D_MATH_H

File diff suppressed because it is too large Load Diff

View File

@ -1,107 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014-2015 Mario Luzeiro <mrluzeiro@gmail.com>
* Copyright (C) 1992-2014 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file 3d_mesh_model.h
* @brief
*/
#ifndef __3D_MESH_MODEL_H__
#define __3D_MESH_MODEL_H__
#include <memory>
#include <vector>
#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include "3d_struct.h"
#include "3d_material.h"
#include "3d_rendering/3d_render_raytracing/shapes3D/cbbox.h"
class S3D_MESH;
/** A smart pointer to an S3D_MESH object */
typedef std::shared_ptr<S3D_MESH> S3D_MESH_PTR;
/** A container of smar S3D_MESH object pointers */
typedef std::vector<S3D_MESH_PTR> S3D_MESH_PTRS;
class S3D_MESH
{
public:
S3D_MESH();
~S3D_MESH();
void openGL_RenderAllChilds( bool aIsRenderingJustNonTransparentObjects,
bool aIsRenderingJustTransparentObjects );
S3D_MATERIAL *m_Materials;
// Point and index list
std::vector< S3D_VERTEX > m_Point;
std::vector< std::vector<int> > m_CoordIndex;
std::vector< std::vector<int> > m_NormalIndex;
std::vector< S3D_VERTEX > m_PerFaceColor;
std::vector< S3D_VERTEX > m_PerFaceNormalsNormalized;
std::vector< S3D_VERTEX > m_PerVertexNormalsNormalized;
std::vector< int > m_MaterialIndexPerFace;
std::vector< std::vector<int> > m_MaterialIndexPerVertex;
S3D_MESH_PTRS childs;
S3D_VERTEX m_translation;
glm::vec4 m_rotation;
S3D_VERTEX m_scale;
CBBOX &getBBox();
private:
std::vector< S3D_VERTEX > m_PerFaceNormalsRaw_X_PerFaceSquaredArea;
std::vector< std::vector< S3D_VERTEX > > m_PerFaceVertexNormals;
std::vector< S3D_VERTEX > m_PointNormalized;
std::vector< std::vector<int> > m_InvalidCoordIndexes; //!TODO: check for invalid CoordIndex in file and remove the index and the same material index
bool isPerFaceNormalsComputed;
void calcPerFaceNormals ();
bool isPointNormalizedComputed;
void calcPointNormalized();
bool isPerPointNormalsComputed;
void calcPerPointNormals();
bool isPerVertexNormalsVerified;
void perVertexNormalsVerify_and_Repair();
void calcBBox();
void calcBBoxAllChilds();
CBBOX m_BBox;
void openGL_Render( bool aIsRenderingJustNonTransparentObjects,
bool aIsRenderingJustTransparentObjects );
};
#endif

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -30,13 +30,18 @@
*/
#include <iostream>
#include "3d_rendering/3d_render_ogl_legacy/c_ogl_3dmodel.h"
#include "c3d_model_viewer.h"
#include "3d_rendering/3d_render_ogl_legacy/ogl_legacy_utils.h"
#include "../3d_rendering/3d_render_ogl_legacy/ogl_legacy_utils.h"
#include "../3d_cache/3d_cache.h"
#include "common_ogl/ogl_utils.h"
#include <wx/dcclient.h>
#include "convert_to_biu.h"
#include <base_units.h>
#include <gl_context_mgr.h>
/**
* Scale convertion from 3d model units to pcb units
*/
#define UNITS3D_TO_UNITSPCB (IU_PER_MM)
/**
@ -69,14 +74,14 @@ BEGIN_EVENT_TABLE( C3D_MODEL_VIEWER, wxGLCanvas )
END_EVENT_TABLE()
/// This defines the range that all coord will have to be rendered.
/// It will use this value to convert to a normalized value between
/// -(RANGE_SCALE_3D/2) .. +(RANGE_SCALE_3D/2)
// This defines the range that all coord will have to be rendered.
// It will use this value to convert to a normalized value between
// -(RANGE_SCALE_3D/2) .. +(RANGE_SCALE_3D/2)
#define RANGE_SCALE_3D 8.0f
C3D_MODEL_VIEWER::C3D_MODEL_VIEWER( wxWindow *aParent,
const int *aAttribList ) :
C3D_MODEL_VIEWER::C3D_MODEL_VIEWER(wxWindow *aParent,
const int *aAttribList , S3D_CACHE *aCacheManager) :
wxGLCanvas( aParent,
wxID_ANY,
@ -84,7 +89,8 @@ C3D_MODEL_VIEWER::C3D_MODEL_VIEWER( wxWindow *aParent,
wxDefaultPosition,
wxDefaultSize,
wxFULL_REPAINT_ON_RESIZE ),
m_trackBallCamera( RANGE_SCALE_3D * 2.0f )
m_trackBallCamera( RANGE_SCALE_3D * 2.0f ),
m_cacheManager(aCacheManager)
{
wxLogTrace( m_logTrace, wxT( "C3D_MODEL_VIEWER::C3D_MODEL_VIEWER" ) );
@ -94,28 +100,30 @@ C3D_MODEL_VIEWER::C3D_MODEL_VIEWER( wxWindow *aParent,
m_3d_model = NULL;
m_BiuTo3Dunits = 1.0;
// Explicitly create a new rendering context instance for this canvas.
m_glRC = GL_CONTEXT_MANAGER::Get().CreateCtx( this );
m_glRC = NULL;
}
C3D_MODEL_VIEWER::~C3D_MODEL_VIEWER()
{
GL_CONTEXT_MANAGER::Get().LockCtx( m_glRC, this );
wxLogTrace( m_logTrace, wxT( "C3D_MODEL_VIEWER::~C3D_MODEL_VIEWER" ) );
delete m_ogl_3dmodel;
m_ogl_3dmodel = NULL;
if( m_glRC )
{
GL_CONTEXT_MANAGER::Get().LockCtx( m_glRC, this );
GL_CONTEXT_MANAGER::Get().UnlockCtx( m_glRC );
GL_CONTEXT_MANAGER::Get().DestroyCtx( m_glRC );
delete m_ogl_3dmodel;
m_ogl_3dmodel = NULL;
GL_CONTEXT_MANAGER::Get().UnlockCtx( m_glRC );
GL_CONTEXT_MANAGER::Get().DestroyCtx( m_glRC );
}
}
void C3D_MODEL_VIEWER::Set3DModel( const S3DMODEL &a3DModel )
{
wxLogTrace( m_logTrace, wxT( "C3D_MODEL_VIEWER::Set3DModel" ) );
wxLogTrace( m_logTrace, wxT( "C3D_MODEL_VIEWER::Set3DModel with a S3DMODEL" ) );
// Validate a3DModel pointers
wxASSERT( a3DModel.m_Materials != NULL );
@ -135,16 +143,38 @@ void C3D_MODEL_VIEWER::Set3DModel( const S3DMODEL &a3DModel )
m_3d_model = &a3DModel;
m_reload_is_needed = true;
}
Refresh();
}
void C3D_MODEL_VIEWER::Set3DModel(const wxString &aModelPathName)
{
wxLogTrace( m_logTrace, wxT( "C3D_MODEL_VIEWER::Set3DModel with a wxString" ) );
if( m_cacheManager )
{
const S3DMODEL* model = m_cacheManager->GetModel( aModelPathName );
if( model )
Set3DModel( (const S3DMODEL &)*model );
else
Clear3DModel();
}
}
void C3D_MODEL_VIEWER::Clear3DModel()
{
// Delete the old model
m_reload_is_needed = false;
delete m_ogl_3dmodel;
m_ogl_3dmodel = NULL;
m_3d_model = NULL;
Refresh();
}
@ -168,7 +198,10 @@ void C3D_MODEL_VIEWER::ogl_initialize()
const GLfloat ambient[] = { 0.01f, 0.01f, 0.01f, 1.0f };
const GLfloat diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
const GLfloat specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
const GLfloat position[] = { 0.0f, 0.0f, 2.0f * RANGE_SCALE_3D, 0.0f }; // defines a directional light that points along the negative z-axis
// defines a directional light that points along the negative z-axis
const GLfloat position[] = { 0.0f, 0.0f, 2.0f * RANGE_SCALE_3D, 0.0f };
const GLfloat lmodel_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f };
glLightfv( GL_LIGHT0, GL_AMBIENT, ambient );
@ -195,6 +228,8 @@ void C3D_MODEL_VIEWER::OnPaint( wxPaintEvent &event )
{
wxPaintDC( this );
event.Skip( false );
// SwapBuffer requires the window to be shown before calling
if( !IsShownOnScreen() )
{
@ -205,6 +240,9 @@ void C3D_MODEL_VIEWER::OnPaint( wxPaintEvent &event )
// "Makes the OpenGL state that is represented by the OpenGL rendering
// context context current, i.e. it will be used by all subsequent OpenGL calls.
// This function may only be called when the window is shown on screen"
if( m_glRC == NULL )
m_glRC = GL_CONTEXT_MANAGER::Get().CreateCtx( this );
GL_CONTEXT_MANAGER::Get().LockCtx( m_glRC, this );
// Set the OpenGL viewport according to the client size of this canvas.
@ -226,11 +264,13 @@ void C3D_MODEL_VIEWER::OnPaint( wxPaintEvent &event )
wxLogTrace( m_logTrace, wxT( "C3D_MODEL_VIEWER::OnPaint m_reload_is_needed" ) );
m_reload_is_needed = false;
m_ogl_3dmodel = new C_OGL_3DMODEL( *m_3d_model );
m_ogl_3dmodel = new C_OGL_3DMODEL( *m_3d_model, MATERIAL_MODE_NORMAL );
// It convert a model as it was a board, so get the max size dimension of the board
// and compute the conversion scale
m_BiuTo3Dunits = (double)RANGE_SCALE_3D / ((double)m_ogl_3dmodel->GetBBox().GetMaxDimension() * UNITS3D_TO_UNITSPCB);
m_BiuTo3Dunits = (double)RANGE_SCALE_3D /
( (double)m_ogl_3dmodel->GetBBox().GetMaxDimension() *
UNITS3D_TO_UNITSPCB );
}
glViewport( 0, 0, clientSize.x, clientSize.y );
@ -253,8 +293,8 @@ void C3D_MODEL_VIEWER::OnPaint( wxPaintEvent &event )
glMatrixMode( GL_MODELVIEW );
glLoadMatrixf( glm::value_ptr( m_trackBallCamera.GetViewMatrix() ) );
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable( GL_LIGHTING );
glEnable( GL_LIGHT0 );
// Render Model
if( m_ogl_3dmodel )
@ -263,22 +303,24 @@ void C3D_MODEL_VIEWER::OnPaint( wxPaintEvent &event )
double modelunit_to_3d_units_factor = m_BiuTo3Dunits * UNITS3D_TO_UNITSPCB;
glScaled( modelunit_to_3d_units_factor, modelunit_to_3d_units_factor, modelunit_to_3d_units_factor);
glScaled( modelunit_to_3d_units_factor,
modelunit_to_3d_units_factor,
modelunit_to_3d_units_factor );
// Center model in the render viewport
const SFVEC3F model_center = m_ogl_3dmodel->GetBBox().GetCenter();
glTranslatef( -model_center.x, -model_center.y, -model_center.z );
// !TODO: draw transparent models
m_ogl_3dmodel->Draw_opaque();
m_ogl_3dmodel->Draw_transparent();
//m_ogl_3dmodel->Draw_bboxes();
glPopMatrix();
}
glViewport( 0, 0, clientSize.y / 8 , clientSize.y / 8 ); // YxY squared view port
// YxY squared view port
glViewport( 0, 0, clientSize.y / 8 , clientSize.y / 8 );
glClear( GL_DEPTH_BUFFER_BIT );
glMatrixMode( GL_PROJECTION );
@ -288,7 +330,9 @@ void C3D_MODEL_VIEWER::OnPaint( wxPaintEvent &event )
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
const glm::mat4 TranslationMatrix = glm::translate( glm::mat4(1.0f), SFVEC3F( 0.0f, 0.0f, -RANGE_SCALE_3D ) );
const glm::mat4 TranslationMatrix = glm::translate( glm::mat4(1.0f),
SFVEC3F( 0.0f, 0.0f, -RANGE_SCALE_3D ) );
const glm::mat4 ViewMatrix = TranslationMatrix * m_trackBallCamera.GetRotationMatrix();
glLoadMatrixf( glm::value_ptr( ViewMatrix ) );
@ -314,9 +358,8 @@ void C3D_MODEL_VIEWER::OnPaint( wxPaintEvent &event )
// front-buffer and vice versa, so that the output of the previous OpenGL
// commands is displayed on the window."
SwapBuffers();
GL_CONTEXT_MANAGER::Get().UnlockCtx( m_glRC );
event.Skip();
GL_CONTEXT_MANAGER::Get().UnlockCtx( m_glRC );
}
@ -432,3 +475,4 @@ void C3D_MODEL_VIEWER::OnRightClick( wxMouseEvent &event )
{
event.Skip();
}

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -32,10 +32,11 @@
#ifndef _C3D_MODEL_VIEWER_H_
#define _C3D_MODEL_VIEWER_H_
#include "3d_rendering/3d_render_ogl_legacy/c_ogl_3dmodel.h"
#include "3d_rendering/ctrack_ball.h"
#include <wx/glcanvas.h>
class S3D_CACHE;
class C_OGL_3DMODEL;
/**
* Class C3D_MODEL_VIEWER
@ -50,10 +51,12 @@ public:
/**
* Creates a new 3D Canvas with a attribute list
* @param aParent = the parent creator of this canvas
* @param aAttribList = a list of openGL options created by COGL_ATT_LIST::GetAttributesList
* @param aAttribList = a list of openGL options created by
* COGL_ATT_LIST::GetAttributesList
*/
C3D_MODEL_VIEWER( wxWindow *aParent,
const int *aAttribList = 0 );
const int *aAttribList = 0,
S3D_CACHE *aCacheManager = NULL );
~C3D_MODEL_VIEWER();
@ -63,6 +66,12 @@ public:
*/
void Set3DModel( const S3DMODEL &a3DModel );
/**
* @brief Set3DModel - Set this model to be displayed
* @param aModelPathName - 3d model path name
*/
void Set3DModel( wxString const& aModelPathName );
/**
* @brief Clear3DModel - Unloads the displayed 3d model
*/
@ -91,6 +100,7 @@ private:
void OnLeftUp( wxMouseEvent &event );
void OnMiddleUp( wxMouseEvent &event );
void OnMiddleDown( wxMouseEvent &event );
void OnRightClick( wxMouseEvent &event );
@ -117,10 +127,14 @@ private:
/// Flag if open gl was initialized
bool m_ogl_initialized;
/// factor to convert the model or any other items to keep it in relation to the +/-RANGE_SCALE_3D
/// factor to convert the model or any other items to keep it in relation to
/// the +/-RANGE_SCALE_3D
/// (it is named same as the board render for better understanding proposes)
double m_BiuTo3Dunits;
/// Optional cache manager
S3D_CACHE* m_cacheManager;
/**
* Trace mask used to enable or disable the trace output of this class.
* The debug output can be turned on by setting the WXTRACE environment variable to

View File

@ -1,173 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@gmail.com>
* Copyright (C) 2015 Jean-Pierre Charras, jp.charras@wanadoo.fr
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file 3d_read_mesh.cpp
*/
#include <fctsys.h>
#include <common.h>
#include <macros.h>
#include <kicad_string.h>
#include <pgm_base.h>
#define GLM_FORCE_RADIANS
#include <glm/gtc/matrix_transform.hpp>
#include <3d_viewer.h>
#include <info3d_visu.h>
#include "3d_struct.h"
#include "modelparsers.h"
S3D_MODEL_PARSER *S3D_MODEL_PARSER::Create( S3D_MASTER* aMaster,
const wxString aExtension )
{
if ( aExtension == wxT( "x3d" ) )
return new X3D_MODEL_PARSER( aMaster );
else if ( aExtension == wxT( "wrl" ) )
return new VRML_MODEL_PARSER( aMaster );
return NULL;
}
int S3D_MASTER::ReadData( S3D_MODEL_PARSER* aParser )
{
if( m_Shape3DFullFilename.IsEmpty() || aParser == NULL )
return -1;
wxString filename = m_Shape3DFullFilename;
#ifdef __WINDOWS__
filename.Replace( wxT( "/" ), wxT( "\\" ) );
#else
filename.Replace( wxT( "\\" ), wxT( "/" ) );
#endif
if( wxFileName::FileExists( filename ) )
{
wxFileName fn( filename );
if( aParser->Load( filename ) )
{
// Invalidate bounding boxes
m_fastAABBox.Reset();
m_BBox.Reset();
m_parser = aParser;
return 0;
}
}
wxLogDebug( wxT( "3D shape '%s' not found, even tried '%s' after env var substitution." ),
GetChars( m_Shape3DName ),
GetChars( filename ) );
return -1;
}
void S3D_MASTER::Render( bool aIsRenderingJustNonTransparentObjects,
bool aIsRenderingJustTransparentObjects )
{
if( m_parser == NULL )
return;
double aVrmlunits_to_3Dunits = g_Parm_3D_Visu.m_BiuTo3Dunits * UNITS3D_TO_UNITSPCB;
glScalef( aVrmlunits_to_3Dunits, aVrmlunits_to_3Dunits, aVrmlunits_to_3Dunits );
glTranslatef( m_MatPosition.x * SCALE_3D_CONV,
m_MatPosition.y * SCALE_3D_CONV,
m_MatPosition.z * SCALE_3D_CONV );
glRotatef( -m_MatRotation.z, 0.0f, 0.0f, 1.0f );
glRotatef( -m_MatRotation.y, 0.0f, 1.0f, 0.0f );
glRotatef( -m_MatRotation.x, 1.0f, 0.0f, 0.0f );
glScalef( m_MatScale.x, m_MatScale.y, m_MatScale.z );
for( unsigned int idx = 0; idx < m_parser->childs.size(); idx++ )
m_parser->childs[idx]->openGL_RenderAllChilds( aIsRenderingJustNonTransparentObjects,
aIsRenderingJustTransparentObjects );
}
CBBOX &S3D_MASTER::getBBox( )
{
if( !m_BBox.IsInitialized() )
calcBBox();
return m_BBox;
}
CBBOX &S3D_MASTER::getFastAABBox( )
{
if( !m_fastAABBox.IsInitialized() )
calcBBox();
return m_fastAABBox;
}
void S3D_MASTER::calcBBox()
{
if( m_parser == NULL )
return;
m_BBox.Reset();
for( unsigned int idx = 0; idx < m_parser->childs.size(); idx++ )
m_BBox.Union( m_parser->childs[idx]->getBBox() );
// Calc transformation matrix to apply in AABBox
float aVrmlunits_to_3Dunits = g_Parm_3D_Visu.m_BiuTo3Dunits * UNITS3D_TO_UNITSPCB;
glm::mat4 fullTransformMatrix;
fullTransformMatrix = glm::scale( glm::mat4(), S3D_VERTEX( aVrmlunits_to_3Dunits,
aVrmlunits_to_3Dunits,
aVrmlunits_to_3Dunits ) );
fullTransformMatrix = glm::translate( fullTransformMatrix, S3D_VERTEX( m_MatPosition.x * SCALE_3D_CONV,
m_MatPosition.y * SCALE_3D_CONV,
m_MatPosition.z * SCALE_3D_CONV) );
if( m_MatRotation.z != 0.0 )
fullTransformMatrix = glm::rotate( fullTransformMatrix, glm::radians(-(float)m_MatRotation.z), S3D_VERTEX( 0.0f, 0.0f, 1.0f ) );
if( m_MatRotation.y != 0.0 )
fullTransformMatrix = glm::rotate( fullTransformMatrix, glm::radians(-(float)m_MatRotation.y), S3D_VERTEX( 0.0f, 1.0f, 0.0f ) );
if( m_MatRotation.x != 0.0 )
fullTransformMatrix = glm::rotate( fullTransformMatrix, glm::radians(-(float)m_MatRotation.x), S3D_VERTEX( 1.0f, 0.0f, 0.0f ) );
fullTransformMatrix = glm::scale( fullTransformMatrix, S3D_VERTEX( m_MatScale.x, m_MatScale.y, m_MatScale.z ) );
// Apply transformation
m_fastAABBox = m_BBox;
m_fastAABBox.ApplyTransformationAA( fullTransformMatrix );
}

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -32,13 +32,26 @@
#include "../c3d_render_base.h"
#include "clayer_triangles.h"
#include "../3d_render_raytracing/shapes2D/cpolygon2d.h"
#include "../3d_render_raytracing/shapes2D/ctriangle2d.h"
#include "../3d_render_raytracing/shapes2D/cpolygon4pts2d.h"
#include "../3d_render_raytracing/shapes2D/cfilledcircle2d.h"
#include "../3d_render_raytracing/shapes2D/cring2d.h"
#include "../3d_render_raytracing/shapes2D/croundsegment2d.h"
#include "c_ogl_3dmodel.h"
#include "3d_cache/3d_info.h"
#include <map>
typedef std::map< LAYER_ID, CLAYERS_OGL_DISP_LISTS* > MAP_OGL_DISP_LISTS;
typedef std::map< LAYER_ID, CLAYER_TRIANGLES * > MAP_TRIANGLES;
typedef std::map< wxString, C_OGL_3DMODEL * > MAP_3DMODEL;
#define SIZE_OF_CIRCLE_TEXTURE 512
#define SIZE_OF_CIRCLE_TEXTURE 1024
/**
* @brief The C3D_RENDER_OGL_LEGACY class render the board using openGL legacy mode
@ -46,30 +59,157 @@ typedef std::map< LAYER_ID, CLAYER_TRIANGLES * > MAP_TRIANGLES;
class C3D_RENDER_OGL_LEGACY : public C3D_RENDER_BASE
{
public:
C3D_RENDER_OGL_LEGACY( CINFO3D_VISU &aSettings,
S3D_CACHE *a3DModelManager );
explicit C3D_RENDER_OGL_LEGACY( CINFO3D_VISU &aSettings );
~C3D_RENDER_OGL_LEGACY();
// Imported from C3D_RENDER_BASE
void SetCurWindowSize( const wxSize &aSize );
void Redraw( bool aIsMoving );
bool Redraw( bool aIsMoving, REPORTER *aStatusTextReporter );
int GetWaitForEditingTimeOut();
private:
bool initializeOpenGL();
void reload();
void reload( REPORTER *aStatusTextReporter );
void ogl_set_arrow_material();
void ogl_free_all_display_lists();
MAP_OGL_DISP_LISTS m_ogl_disp_lists_layers;
MAP_OGL_DISP_LISTS m_ogl_disp_lists_layers_holes_outer;
MAP_OGL_DISP_LISTS m_ogl_disp_lists_layers_holes_inner;
CLAYERS_OGL_DISP_LISTS* m_ogl_disp_list_board;
CLAYERS_OGL_DISP_LISTS* m_ogl_disp_list_through_holes_outer;
CLAYERS_OGL_DISP_LISTS* m_ogl_disp_list_through_holes_inner;
// User for body render
CLAYERS_OGL_DISP_LISTS* m_ogl_disp_list_through_holes_outer_with_npth;
CLAYERS_OGL_DISP_LISTS* m_ogl_disp_list_through_holes_vias_outer;
//CLAYERS_OGL_DISP_LISTS* m_ogl_disp_list_through_holes_vias_inner; // Not in use
// This is for pads holes of the modules
//CLAYERS_OGL_DISP_LISTS* m_ogl_disp_list_vias_and_pad_holes_inner_contourn_and_caps;
CLAYERS_OGL_DISP_LISTS* m_ogl_disp_list_vias_and_pad_holes_outer_contourn_and_caps;
MAP_TRIANGLES m_triangles;
GLuint m_ogl_circle_texture;
GLuint m_ogl_disp_list_grid; ///< oGL list that stores current grid
GRID3D_TYPE m_last_grid_type; ///< Stores the last grid computed
CLAYERS_OGL_DISP_LISTS* m_ogl_disp_list_via;
CLAYERS_OGL_DISP_LISTS* m_ogl_disp_list_pads_holes;
MAP_3DMODEL m_3dmodel_map;
private:
void add_triangle_top_bot( CLAYER_TRIANGLES *aDst, const SFVEC2F &v0, const SFVEC2F &v1, const SFVEC2F &v2, float top, float bot );
void generate_through_outer_holes();
void generate_through_inner_holes();
CLAYERS_OGL_DISP_LISTS *generate_holes_display_list( const LIST_OBJECT2D &aListHolesObject2d,
const SHAPE_POLY_SET &aPoly,
float aZtop,
float aZbot,
bool aInvertFaces );
void add_triangle_top_bot( CLAYER_TRIANGLES *aDst,
const SFVEC2F &v0,
const SFVEC2F &v1,
const SFVEC2F &v2,
float top,
float bot );
void add_object_to_triangle_layer( const CRING2D *aRing,
CLAYER_TRIANGLES *aDstLayer,
float aZtop,
float aZbot );
void add_object_to_triangle_layer( const CPOLYGON4PTS2D *aPoly,
CLAYER_TRIANGLES *aDstLayer,
float aZtop,
float aZbot );
void add_object_to_triangle_layer( const CFILLEDCIRCLE2D *aFilledCircle,
CLAYER_TRIANGLES *aDstLayer,
float aZtop,
float aZbot );
void add_object_to_triangle_layer( const CTRIANGLE2D *aTri,
CLAYER_TRIANGLES *aDstLayer,
float aZtop,
float aZbot );
void add_object_to_triangle_layer( const CROUNDSEGMENT2D *aSeg,
CLAYER_TRIANGLES *aDstLayer,
float aZtop,
float aZbot );
void render_solder_mask_layer( LAYER_ID aLayerID,
float aZPosition,
bool aIsRenderingOnPreviewMode );
void get_layer_z_pos( LAYER_ID aLayerID,
float &aOutZtop,
float &aOutZbot ) const;
void generate_ring_contour( const SFVEC2F &aCenter,
float aInnerRadius,
float aOuterRadius,
unsigned int aNr_sides_per_circle,
std::vector< SFVEC2F > &aInnerContourResult,
std::vector< SFVEC2F > &aOuterContourResult,
bool aInvertOrder );
void generate_cylinder( const SFVEC2F &aCenter,
float aInnerRadius,
float aOuterRadius,
float aZtop,
float aZbot,
unsigned int aNr_sides_per_circle,
CLAYER_TRIANGLES *aDstLayer );
void generate_3D_Vias_and_Pads();
void load_3D_models();
/**
* @brief render_3D_models
* @param aRenderTopOrBot - true will render Top, false will render bottom
* @param aRenderTransparentOnly - true will render only the transparent
* objects, false will render opaque
*/
void render_3D_models( bool aRenderTopOrBot, bool aRenderTransparentOnly );
void render_3D_module( const MODULE* module, bool aRenderTransparentOnly );
void setLight_Front( bool enabled );
void setLight_Top( bool enabled );
void setLight_Bottom( bool enabled );
void render_3D_arrows();
void generate_new_3DGrid( GRID3D_TYPE aGridType );
// Materials
void setupMaterials();
struct
{
SMATERIAL m_Paste;
SMATERIAL m_SilkS;
SMATERIAL m_SolderMask;
SMATERIAL m_EpoxyBoard;
SMATERIAL m_Copper;
SMATERIAL m_Plastic;
SMATERIAL m_GrayMaterial;
}m_materials;
void set_layer_material( LAYER_ID aLayerID );
SFVEC3F get_layer_color( LAYER_ID aLayerID );
public:
const MAP_OGL_DISP_LISTS &GetLayerDispListMap() const { return m_ogl_disp_lists_layers; }
@ -78,3 +218,4 @@ public:
};
#endif // C3D_RENDER_OGL_LEGACY_H_

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -30,14 +30,15 @@
#include "c_ogl_3dmodel.h"
#include "ogl_legacy_utils.h"
#include "../common_ogl/ogl_utils.h"
#include "../3d_math.h"
#include <wx/debug.h>
C_OGL_3DMODEL::C_OGL_3DMODEL( const S3DMODEL &a3DModel )
C_OGL_3DMODEL::C_OGL_3DMODEL( const S3DMODEL &a3DModel,
MATERIAL_MODE aMaterialMode )
{
m_ogl_idx_list_opaque = 0;
m_ogl_idx_list_transparent = 0;
m_ogl_idx_list_meshes = 0;
m_nr_meshes = 0;
m_meshs_bbox = NULL;
@ -55,7 +56,7 @@ C_OGL_3DMODEL::C_OGL_3DMODEL( const S3DMODEL &a3DModel )
m_meshs_bbox = new CBBOX[a3DModel.m_MeshesSize];
// Generate m_MeshesSize auxiliar lists to render the meshes
GLuint m_ogl_idx_list_meshes = glGenLists( a3DModel.m_MeshesSize );
m_ogl_idx_list_meshes = glGenLists( a3DModel.m_MeshesSize );
// Render each mesh of the model
// /////////////////////////////////////////////////////////////////////
@ -75,14 +76,18 @@ C_OGL_3DMODEL::C_OGL_3DMODEL( const S3DMODEL &a3DModel )
(mesh.m_FaceIdx != NULL) &&
(mesh.m_FaceIdxSize > 0) && (mesh.m_VertexSize > 0) )
{
SFVEC4F *pColorRGBA = NULL;
SFVEC4F *pColorRGBA = NULL;
// Create the bbox for this mesh
// /////////////////////////////////////////////////////////
m_meshs_bbox[mesh_i].Reset();
for( unsigned int vertex_i = 0; vertex_i < mesh.m_VertexSize; ++vertex_i )
for( unsigned int vertex_i = 0;
vertex_i < mesh.m_VertexSize;
++vertex_i )
{
m_meshs_bbox[mesh_i].Union( mesh.m_Positions[vertex_i] );
}
// Make sure we start with client state disabled
// /////////////////////////////////////////////////////////
@ -107,22 +112,47 @@ C_OGL_3DMODEL::C_OGL_3DMODEL( const S3DMODEL &a3DModel )
if( mesh.m_MaterialIdx < a3DModel.m_MaterialsSize )
transparency = a3DModel.m_Materials[mesh.m_MaterialIdx].m_Transparency;
if( transparency > FLT_EPSILON )
if( (transparency > FLT_EPSILON) &&
(aMaterialMode == MATERIAL_MODE_NORMAL) )
{
// Create a new array of RGBA colors
pColorRGBA = new SFVEC4F[mesh.m_VertexSize];
// Copy RGB array and add the Alpha value
for( unsigned int i = 0; i < mesh.m_VertexSize; ++i )
pColorRGBA[i] = SFVEC4F( mesh.m_Color[i], 1.0f - transparency );
pColorRGBA[i] = SFVEC4F( mesh.m_Color[i],
1.0f - transparency );
// Load an RGBA array
glColorPointer( 4, GL_FLOAT, 0, pColorRGBA );
}
else
{
// Else load the original RGB color array
glColorPointer( 3, GL_FLOAT, 0, mesh.m_Color );
switch( aMaterialMode )
{
case MATERIAL_MODE_NORMAL:
case MATERIAL_MODE_DIFFUSE_ONLY:
// load the original RGB color array
glColorPointer( 3, GL_FLOAT, 0, mesh.m_Color );
break;
case MATERIAL_MODE_CAD_MODE:
// Create a new array of RGBA colors
pColorRGBA = new SFVEC4F[mesh.m_VertexSize];
// Copy RGB array and add the Alpha value
for( unsigned int i = 0; i < mesh.m_VertexSize; ++i )
{
pColorRGBA[i] =
SFVEC4F( MaterialDiffuseToColorCAD( mesh.m_Color[i] ),
1.0f );
}
// Load an RGBA array
glColorPointer( 4, GL_FLOAT, 0, pColorRGBA );
break;
default:
break;
}
}
}
@ -152,12 +182,29 @@ C_OGL_3DMODEL::C_OGL_3DMODEL( const S3DMODEL &a3DModel )
if( mesh.m_MaterialIdx < a3DModel.m_MaterialsSize )
{
OGL_SetMaterial( a3DModel.m_Materials[mesh.m_MaterialIdx] );
switch( aMaterialMode )
{
case MATERIAL_MODE_NORMAL:
OGL_SetMaterial( a3DModel.m_Materials[mesh.m_MaterialIdx] );
break;
case MATERIAL_MODE_DIFFUSE_ONLY:
OGL_SetDiffuseOnlyMaterial(
a3DModel.m_Materials[mesh.m_MaterialIdx].m_Diffuse );
break;
case MATERIAL_MODE_CAD_MODE:
OGL_SetDiffuseOnlyMaterial(
MaterialDiffuseToColorCAD(
a3DModel.m_Materials[mesh.m_MaterialIdx].m_Diffuse ) );
break;
default:
break;
}
}
// Draw mesh
// /////////////////////////////////////////////////////////
glDrawElements( GL_TRIANGLES, mesh.m_FaceIdxSize, GL_UNSIGNED_INT, mesh.m_FaceIdx );
glDrawElements( GL_TRIANGLES, mesh.m_FaceIdxSize,
GL_UNSIGNED_INT, mesh.m_FaceIdx );
glDisable( GL_COLOR_MATERIAL );
@ -170,19 +217,22 @@ C_OGL_3DMODEL::C_OGL_3DMODEL( const S3DMODEL &a3DModel )
glDisableClientState( GL_NORMAL_ARRAY );
glDisableClientState( GL_VERTEX_ARRAY );
glFinish();
delete [] pColorRGBA;
}
}
}// for each mesh
bool have_opaque_meshes = false;
bool have_transparent_meshes = false;
m_ogl_idx_list_opaque = glGenLists( 1 );
// Check if the generated list is valid
if( glIsList( m_ogl_idx_list_opaque ) )
{
bool have_opaque_meshes = false;
bool have_transparent_meshes = false;
// Compile the model display list
glNewList( m_ogl_idx_list_opaque, GL_COMPILE );
@ -198,12 +248,12 @@ C_OGL_3DMODEL::C_OGL_3DMODEL( const S3DMODEL &a3DModel )
if( material.m_Transparency == 0.0f )
{
have_opaque_meshes = true; // Flag that we have at least one opaque mesh
have_opaque_meshes = true; // Flag that we have at least one opaque mesh
glCallList( m_ogl_idx_list_meshes + mesh_i );
}
else
{
have_transparent_meshes = true; // Flag that we found a transparent mesh
have_transparent_meshes = true; // Flag that we found a transparent mesh
}
}
}
@ -212,7 +262,8 @@ C_OGL_3DMODEL::C_OGL_3DMODEL( const S3DMODEL &a3DModel )
if( !have_opaque_meshes )
{
glDeleteLists( m_ogl_idx_list_opaque, 1 ); // If we dont have opaque meshes, we can free the list
// If we dont have opaque meshes, we can free the list
glDeleteLists( m_ogl_idx_list_opaque, 1 );
m_ogl_idx_list_opaque = 0;
}
@ -239,8 +290,9 @@ C_OGL_3DMODEL::C_OGL_3DMODEL( const S3DMODEL &a3DModel )
{
const SMATERIAL &material = a3DModel.m_Materials[mesh.m_MaterialIdx];
// Render the transparent mesh if it have a transparency value
if( material.m_Transparency != 0.0f )
glCallList( m_ogl_idx_list_meshes + mesh_i ); // Render the transparent mesh
glCallList( m_ogl_idx_list_meshes + mesh_i );
}
}
@ -265,6 +317,8 @@ C_OGL_3DMODEL::C_OGL_3DMODEL( const S3DMODEL &a3DModel )
for( unsigned int mesh_i = 0; mesh_i < a3DModel.m_MeshesSize; ++mesh_i )
m_model_bbox.Union( m_meshs_bbox[mesh_i] );
glFinish();
}
}

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -30,19 +30,21 @@
#ifndef _C_OGL_3DMODEL_H_
#define _C_OGL_3DMODEL_H_
#include "plugins/3dapi/c3dmodel.h"
#include "common_ogl/openGL_includes.h"
#include "3d_rendering/3d_render_raytracing/shapes3D/cbbox.h"
#include <plugins/3dapi/c3dmodel.h>
#include "../../common_ogl/openGL_includes.h"
#include "../3d_render_raytracing/shapes3D/cbbox.h"
#include "../../3d_enums.h"
///
class GLM_ALIGN(CLASS_ALIGNMENT) C_OGL_3DMODEL
///
class C_OGL_3DMODEL
{
public:
/**
* @brief C_OGL_3DMODEL - Load a 3d model. This must be called inside a gl context
* @param a3DModel: a 3d model data to load.
* @param aMaterialMode: a mode to render the materials of the model
*/
C_OGL_3DMODEL( const S3DMODEL &a3DModel );
C_OGL_3DMODEL( const S3DMODEL &a3DModel, MATERIAL_MODE aMaterialMode );
~C_OGL_3DMODEL();
@ -56,16 +58,6 @@ public:
*/
void Draw_transparent() const;
/**
* @brief Draw_bbox - draw main bounding box of the model
*/
void Draw_bbox() const;
/**
* @brief Draw_bboxes - draw individual bounding boxes of each mesh
*/
void Draw_bboxes() const;
/**
* @brief Have_opaque - return true if have opaque meshs to render
*/
@ -76,6 +68,16 @@ public:
*/
bool Have_transparent() const;
/**
* @brief Draw_bbox - draw main bounding box of the model
*/
void Draw_bbox() const;
/**
* @brief Draw_bboxes - draw individual bounding boxes of each mesh
*/
void Draw_bboxes() const;
/**
* @brief GetBBox - Get main bbox
* @return the main model bbox
@ -83,13 +85,13 @@ public:
const CBBOX &GetBBox() const { return m_model_bbox; }
private:
GLuint m_ogl_idx_list_opaque; ///< display list for rendering opaque meshes
GLuint m_ogl_idx_list_transparent; ///< display list for rendering transparent meshes
GLuint m_ogl_idx_list_meshes; ///< display lists for all meshes.
unsigned int m_nr_meshes; ///< number of meshes of this model
GLuint m_ogl_idx_list_opaque; ///< display list for rendering opaque meshes
GLuint m_ogl_idx_list_transparent; ///< display list for rendering transparent meshes
GLuint m_ogl_idx_list_meshes; ///< display lists for all meshes.
unsigned int m_nr_meshes; ///< number of meshes of this model
CBBOX m_model_bbox; ///< global bounding box for this model
CBBOX *m_meshs_bbox; ///< individual bbox for each mesh
CBBOX m_model_bbox; ///< global bounding box for this model
CBBOX *m_meshs_bbox; ///< individual bbox for each mesh
};
#endif // _C_OGL_3DMODEL_H_

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -29,10 +29,11 @@
#include "clayer_triangles.h"
#include <wx/debug.h> // For the wxASSERT
#include <wx/debug.h> // For the wxASSERT
CLAYER_TRIANGLE_CONTAINER::CLAYER_TRIANGLE_CONTAINER(unsigned int aNrReservedTriangles, bool aReserveNormals)
CLAYER_TRIANGLE_CONTAINER::CLAYER_TRIANGLE_CONTAINER( unsigned int aNrReservedTriangles,
bool aReserveNormals )
{
wxASSERT( aNrReservedTriangles > 0 );
@ -46,7 +47,20 @@ CLAYER_TRIANGLE_CONTAINER::CLAYER_TRIANGLE_CONTAINER(unsigned int aNrReservedTri
}
void CLAYER_TRIANGLE_CONTAINER::AddQuad( const SFVEC3F &aV1, const SFVEC3F &aV2, const SFVEC3F &aV3, const SFVEC3F &aV4 )
void CLAYER_TRIANGLE_CONTAINER::Reserve_More( unsigned int aNrReservedTriangles,
bool aReserveNormals )
{
m_vertexs.reserve( m_vertexs.size() + aNrReservedTriangles * 3 );
if( aReserveNormals )
m_normals.reserve( m_normals.size() + aNrReservedTriangles * 3 );
}
void CLAYER_TRIANGLE_CONTAINER::AddQuad( const SFVEC3F &aV1,
const SFVEC3F &aV2,
const SFVEC3F &aV3,
const SFVEC3F &aV4 )
{
m_vertexs.push_back( aV1 );
m_vertexs.push_back( aV2 );
@ -58,7 +72,9 @@ void CLAYER_TRIANGLE_CONTAINER::AddQuad( const SFVEC3F &aV1, const SFVEC3F &aV2,
}
void CLAYER_TRIANGLE_CONTAINER::AddTriangle( const SFVEC3F &aV1, const SFVEC3F &aV2, const SFVEC3F &aV3 )
void CLAYER_TRIANGLE_CONTAINER::AddTriangle( const SFVEC3F &aV1,
const SFVEC3F &aV2,
const SFVEC3F &aV3 )
{
m_vertexs.push_back( aV1 );
m_vertexs.push_back( aV2 );
@ -66,14 +82,19 @@ void CLAYER_TRIANGLE_CONTAINER::AddTriangle( const SFVEC3F &aV1, const SFVEC3F &
}
void CLAYER_TRIANGLE_CONTAINER::AddNormal( const SFVEC3F &aN1, const SFVEC3F &aN2, const SFVEC3F &aN3 )
void CLAYER_TRIANGLE_CONTAINER::AddNormal( const SFVEC3F &aN1,
const SFVEC3F &aN2,
const SFVEC3F &aN3 )
{
m_normals.push_back( aN1 );
m_normals.push_back( aN2 );
m_normals.push_back( aN3 );
}
void CLAYER_TRIANGLE_CONTAINER::AddNormal( const SFVEC3F &aN1, const SFVEC3F &aN2, const SFVEC3F &aN3, const SFVEC3F &aN4 )
void CLAYER_TRIANGLE_CONTAINER::AddNormal( const SFVEC3F &aN1,
const SFVEC3F &aN2,
const SFVEC3F &aN3,
const SFVEC3F &aN4 )
{
m_normals.push_back( aN1 );
m_normals.push_back( aN2 );
@ -89,11 +110,16 @@ CLAYER_TRIANGLES::CLAYER_TRIANGLES( unsigned int aNrReservedTriangles )
{
wxASSERT( aNrReservedTriangles > 0 );
m_layer_top_segment_ends = new CLAYER_TRIANGLE_CONTAINER( aNrReservedTriangles, false );
m_layer_top_triangles = new CLAYER_TRIANGLE_CONTAINER( aNrReservedTriangles, false );
m_layer_middle_contourns_quads = new CLAYER_TRIANGLE_CONTAINER( aNrReservedTriangles, true );
m_layer_bot_triangles = new CLAYER_TRIANGLE_CONTAINER( aNrReservedTriangles, false );
m_layer_bot_segment_ends = new CLAYER_TRIANGLE_CONTAINER( aNrReservedTriangles, false );
m_layer_top_segment_ends = new CLAYER_TRIANGLE_CONTAINER( aNrReservedTriangles,
false );
m_layer_top_triangles = new CLAYER_TRIANGLE_CONTAINER( aNrReservedTriangles,
false );
m_layer_middle_contourns_quads = new CLAYER_TRIANGLE_CONTAINER( aNrReservedTriangles,
true );
m_layer_bot_triangles = new CLAYER_TRIANGLE_CONTAINER( aNrReservedTriangles,
false );
m_layer_bot_segment_ends = new CLAYER_TRIANGLE_CONTAINER( aNrReservedTriangles,
false );
}
@ -116,11 +142,194 @@ CLAYER_TRIANGLES::~CLAYER_TRIANGLES()
}
CLAYERS_OGL_DISP_LISTS::CLAYERS_OGL_DISP_LISTS(const CLAYER_TRIANGLES &aLayerTriangles,
GLuint aTextureIndexForSegEnds,
const SFVEC3F& aLayerColor )
void CLAYER_TRIANGLES::AddToMiddleContourns( const std::vector< SFVEC2F > &aContournPoints,
float zBot,
float zTop,
bool aInvertFaceDirection )
{
wxASSERT( glIsTexture( aTextureIndexForSegEnds ) );
if( aContournPoints.size() > 4 )
{
// Calculate normals of each segment of the contourn
std::vector< SFVEC2F > contournNormals;
contournNormals.clear();
contournNormals.resize( aContournPoints.size() - 1 );
if( aInvertFaceDirection )
{
for( unsigned int i = 0; i < ( aContournPoints.size() - 1 ); ++i )
{
const SFVEC2F &v0 = aContournPoints[i + 0];
const SFVEC2F &v1 = aContournPoints[i + 1];
const SFVEC2F n = glm::normalize( v1 - v0 );
contournNormals[i] = SFVEC2F( n.y,-n.x );
}
}
else
{
for( unsigned int i = 0; i < ( aContournPoints.size() - 1 ); ++i )
{
const SFVEC2F &v0 = aContournPoints[i + 0];
const SFVEC2F &v1 = aContournPoints[i + 1];
const SFVEC2F n = glm::normalize( v1 - v0 );
contournNormals[i] = SFVEC2F( -n.y, n.x );
}
}
if( aInvertFaceDirection )
std::swap( zBot, zTop );
const unsigned int nContournsToProcess = ( aContournPoints.size() - 1 );
for( unsigned int i = 0; i < nContournsToProcess; ++i )
{
SFVEC2F lastNormal;
if( i > 0 )
lastNormal = contournNormals[i - 1];
else
lastNormal = contournNormals[nContournsToProcess - 1];
SFVEC2F n0 = contournNormals[i];
// Only interpolate the normal if the angle is closer
if( glm::dot( n0, lastNormal ) > 0.5f )
n0 = glm::normalize( n0 + lastNormal );
SFVEC2F nextNormal;
if( i < (nContournsToProcess - 1) )
nextNormal = contournNormals[i + 1];
else
nextNormal = contournNormals[0];
SFVEC2F n1 = contournNormals[i];
if( glm::dot( n1, nextNormal ) > 0.5f )
n1 = glm::normalize( n1 + nextNormal );
const SFVEC3F n3d0 = SFVEC3F( n0.x, n0.y, 0.0f );
const SFVEC3F n3d1 = SFVEC3F( n1.x, n1.y, 0.0f );
const SFVEC2F &v0 = aContournPoints[i + 0];
const SFVEC2F &v1 = aContournPoints[i + 1];
#pragma omp critical
{
m_layer_middle_contourns_quads->AddQuad( SFVEC3F( v0.x, v0.y, zTop ),
SFVEC3F( v1.x, v1.y, zTop ),
SFVEC3F( v1.x, v1.y, zBot ),
SFVEC3F( v0.x, v0.y, zBot ) );
m_layer_middle_contourns_quads->AddNormal( n3d0, n3d1, n3d1, n3d0 );
}
}
}
}
void CLAYER_TRIANGLES::AddToMiddleContourns( const SHAPE_LINE_CHAIN &outlinePath,
float zBot,
float zTop,
double aBiuTo3Du,
bool aInvertFaceDirection )
{
std::vector< SFVEC2F >contournPoints;
contournPoints.clear();
contournPoints.reserve( outlinePath.PointCount() + 2 );
const VECTOR2I &firstV = outlinePath.CPoint( 0 );
SFVEC2F lastV = SFVEC2F( firstV.x * aBiuTo3Du,
-firstV.y * aBiuTo3Du );
contournPoints.push_back( lastV );
for( unsigned int i = 1; i < (unsigned int)outlinePath.PointCount(); ++i )
{
const VECTOR2I & v = outlinePath.CPoint( i );
const SFVEC2F vf = SFVEC2F( v.x * aBiuTo3Du,
-v.y * aBiuTo3Du );
if( vf != lastV ) // Do not add repeated points
{
lastV = vf;
contournPoints.push_back( vf );
}
}
// Add first position fo the list to close the path
if( lastV != contournPoints[0] )
contournPoints.push_back( contournPoints[0] );
AddToMiddleContourns( contournPoints, zBot, zTop, aInvertFaceDirection );
}
void CLAYER_TRIANGLES::AddToMiddleContourns( const SHAPE_POLY_SET &aPolySet,
float zBot,
float zTop,
double aBiuTo3Du,
bool aInvertFaceDirection )
{
wxASSERT( aPolySet.OutlineCount() > 0 );
if( aPolySet.OutlineCount() == 0 )
return;
// Calculate an estimation of points to reserve
unsigned int nrContournPointsToReserve = 0;
for( int i = 0; i < aPolySet.OutlineCount(); ++i )
{
const SHAPE_LINE_CHAIN& pathOutline = aPolySet.COutline( i );
nrContournPointsToReserve += pathOutline.PointCount();
for( int h = 0; h < aPolySet.HoleCount( i ); ++h )
{
const SHAPE_LINE_CHAIN &hole = aPolySet.CHole( i, h );
nrContournPointsToReserve += hole.PointCount();
}
}
// Request to reserve more space
m_layer_middle_contourns_quads->Reserve_More( nrContournPointsToReserve * 2,
true );
#pragma omp parallel for
for( signed int i = 0; i < aPolySet.OutlineCount(); ++i )
{
// Add outline
const SHAPE_LINE_CHAIN& pathOutline = aPolySet.COutline( i );
AddToMiddleContourns( pathOutline, zBot, zTop, aBiuTo3Du, aInvertFaceDirection );
// 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 );
}
}
}
CLAYERS_OGL_DISP_LISTS::CLAYERS_OGL_DISP_LISTS( const CLAYER_TRIANGLES &aLayerTriangles,
GLuint aTextureIndexForSegEnds,
float aZBot,
float aZTop )
{
m_zBot = aZBot;
m_zTop = aZTop;
m_layer_top_segment_ends = 0;
m_layer_top_triangles = 0;
@ -128,12 +337,41 @@ CLAYERS_OGL_DISP_LISTS::CLAYERS_OGL_DISP_LISTS(const CLAYER_TRIANGLES &aLayerTri
m_layer_bot_triangles = 0;
m_layer_bot_segment_ends = 0;
m_layer_top_segment_ends = generate_top_or_bot_seg_ends( aLayerTriangles.m_layer_top_segment_ends, aLayerColor, true, aTextureIndexForSegEnds );
m_layer_top_triangles = generate_top_or_bot_triangles( aLayerTriangles.m_layer_top_triangles, aLayerColor, true );
m_layer_bot_triangles = generate_top_or_bot_triangles( aLayerTriangles.m_layer_bot_triangles, aLayerColor, false );
m_layer_bot_segment_ends = generate_top_or_bot_seg_ends( aLayerTriangles.m_layer_bot_segment_ends, aLayerColor, false, aTextureIndexForSegEnds );
if( aTextureIndexForSegEnds )
{
wxASSERT( glIsTexture( aTextureIndexForSegEnds ) );
m_layer_middle_contourns_quads = generate_middle_triangles( aLayerTriangles.m_layer_middle_contourns_quads, aLayerColor );
if( glIsTexture( aTextureIndexForSegEnds ) )
{
m_layer_top_segment_ends =
generate_top_or_bot_seg_ends( aLayerTriangles.m_layer_top_segment_ends,
true,
aTextureIndexForSegEnds );
m_layer_bot_segment_ends =
generate_top_or_bot_seg_ends( aLayerTriangles.m_layer_bot_segment_ends,
false,
aTextureIndexForSegEnds );
}
}
m_layer_top_triangles = generate_top_or_bot_triangles( aLayerTriangles.m_layer_top_triangles,
true );
m_layer_bot_triangles = generate_top_or_bot_triangles( aLayerTriangles.m_layer_bot_triangles,
false );
if( aLayerTriangles.m_layer_middle_contourns_quads->GetVertexSize() > 0 )
{
m_layer_middle_contourns_quads =
generate_middle_triangles( aLayerTriangles.m_layer_middle_contourns_quads );
}
m_draw_it_transparent = false;
m_haveTransformation = false;
m_zPositionTransformation = 0.0f;
m_zScaleTransformation = 0.0f;
}
@ -153,73 +391,99 @@ CLAYERS_OGL_DISP_LISTS::~CLAYERS_OGL_DISP_LISTS()
if( glIsList( m_layer_bot_segment_ends ) )
glDeleteLists( m_layer_bot_segment_ends, 1 );
m_layer_top_segment_ends = 0;
m_layer_top_triangles = 0;
m_layer_middle_contourns_quads = 0;
m_layer_bot_triangles = 0;
m_layer_bot_segment_ends = 0;
}
void CLAYERS_OGL_DISP_LISTS::DrawTopAndMiddle() const
{
if( glIsList( m_layer_top_triangles ) )
glCallList( m_layer_top_triangles );
beginTransformation();
if( glIsList( m_layer_middle_contourns_quads ) )
glCallList( m_layer_middle_contourns_quads );
if( glIsList( m_layer_top_triangles ) )
glCallList( m_layer_top_triangles );
if( glIsList( m_layer_top_segment_ends ) )
glCallList( m_layer_top_segment_ends );
endTransformation();
}
void CLAYERS_OGL_DISP_LISTS::DrawBotAndMiddle() const
{
if( glIsList( m_layer_bot_triangles ) )
glCallList( m_layer_bot_triangles );
beginTransformation();
if( glIsList( m_layer_middle_contourns_quads ) )
glCallList( m_layer_middle_contourns_quads );
if( glIsList( m_layer_bot_triangles ) )
glCallList( m_layer_bot_triangles );
if( glIsList( m_layer_bot_segment_ends ) )
glCallList( m_layer_bot_segment_ends );
endTransformation();
}
void CLAYERS_OGL_DISP_LISTS::DrawTop() const
{
beginTransformation();
if( glIsList( m_layer_top_triangles ) )
glCallList( m_layer_top_triangles );
if( glIsList( m_layer_top_segment_ends ) )
glCallList( m_layer_top_segment_ends );
endTransformation();
}
void CLAYERS_OGL_DISP_LISTS::DrawBot() const
{
beginTransformation();
if( glIsList( m_layer_bot_triangles ) )
glCallList( m_layer_bot_triangles );
if( glIsList( m_layer_bot_segment_ends ) )
glCallList( m_layer_bot_segment_ends );
endTransformation();
}
void CLAYERS_OGL_DISP_LISTS::DrawMiddle() const
{
beginTransformation();
if( glIsList( m_layer_middle_contourns_quads ) )
glCallList( m_layer_middle_contourns_quads );
endTransformation();
}
void CLAYERS_OGL_DISP_LISTS::DrawAll() const
void CLAYERS_OGL_DISP_LISTS::DrawAll( bool aDrawMiddle ) const
{
beginTransformation();
if( aDrawMiddle )
if( glIsList( m_layer_middle_contourns_quads ) )
glCallList( m_layer_middle_contourns_quads );
if( glIsList( m_layer_top_triangles ) )
glCallList( m_layer_top_triangles );
if( glIsList( m_layer_middle_contourns_quads ) )
glCallList( m_layer_middle_contourns_quads );
if( glIsList( m_layer_bot_triangles ) )
glCallList( m_layer_bot_triangles );
@ -229,15 +493,162 @@ void CLAYERS_OGL_DISP_LISTS::DrawAll() const
if( glIsList( m_layer_bot_segment_ends ) )
glCallList( m_layer_bot_segment_ends );
endTransformation();
}
GLuint CLAYERS_OGL_DISP_LISTS::generate_top_or_bot_seg_ends(const CLAYER_TRIANGLE_CONTAINER *aTriangleContainer, const SFVEC3F &aLayerColor, bool aIsNormalUp, GLuint aTextureId ) const
void CLAYERS_OGL_DISP_LISTS::DrawAllCameraCulled(float zCameraPos, bool aDrawMiddle ) const
{
zCameraPos = m_haveTransformation?( (zCameraPos - m_zPositionTransformation ) /
m_zScaleTransformation ):zCameraPos;
if( aDrawMiddle )
DrawMiddle();
if( zCameraPos > m_zTop )
{
DrawTop();
}
else
{
if( zCameraPos < m_zBot )
{
DrawBot();
}
else
{
// If camera is in the middle dont draw it
}
}
}
void CLAYERS_OGL_DISP_LISTS::DrawAllCameraCulledSubtractLayer(
const CLAYERS_OGL_DISP_LISTS *aLayerToSubtractA,
const CLAYERS_OGL_DISP_LISTS *aLayerToSubtractB,
bool aDrawMiddle ) const
{
if( aDrawMiddle )
DrawMiddle();
glClearStencil( 0x00 );
glClear( GL_STENCIL_BUFFER_BIT );
glEnable( GL_CULL_FACE );
glCullFace( GL_BACK );
glDisable( GL_DEPTH_TEST );
glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
glDepthMask( GL_FALSE );
glEnable( GL_STENCIL_TEST );
glStencilFunc( GL_ALWAYS, 1, 0 );
glStencilOp( GL_KEEP, GL_KEEP, GL_REPLACE );
if( aLayerToSubtractA )
aLayerToSubtractA->DrawBot();
if( aLayerToSubtractB )
aLayerToSubtractB->DrawBot();
//if( !m_draw_it_transparent )
{
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
}
glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
glStencilFunc( GL_EQUAL, 0, 1 );
glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
DrawBot();
glDisable( GL_DEPTH_TEST );
glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
glDepthMask( GL_FALSE );
glEnable( GL_STENCIL_TEST );
glStencilFunc( GL_ALWAYS, 2, 0 );
glStencilOp( GL_KEEP, GL_KEEP, GL_REPLACE );
if( aLayerToSubtractA )
aLayerToSubtractA->DrawTop();
if( aLayerToSubtractB )
aLayerToSubtractB->DrawTop();
//if( !m_draw_it_transparent )
{
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
}
glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
glStencilFunc( GL_NOTEQUAL, 2, 0x03 );
glStencilOp( GL_KEEP, GL_KEEP, GL_INCR );
DrawTop();
glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE );
glCullFace( GL_FRONT );
glStencilFunc( GL_GEQUAL, 3, 0x03 );
glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
if( aDrawMiddle )
{
if( aLayerToSubtractA )
aLayerToSubtractA->DrawMiddle();
// It will not render the middle contours of the layer.
// It is used with vias and holes (copper vias and to subtract solder
// mask holes). But since in the vias, it will draw a cylinder
// and in soldermask it doesn't need to draw the contour.
// so it is not used the middle part of B
// if( aLayerToSubtractB )
// aLayerToSubtractB->DrawMiddle();
}
glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE );
glCullFace( GL_BACK );
glDisable( GL_STENCIL_TEST );
/*
if( m_draw_it_transparent )
{
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
}*/
}
void CLAYERS_OGL_DISP_LISTS::ApplyScalePosition( float aZposition,
float aZscale )
{
wxASSERT( aZscale > FLT_EPSILON );
m_zPositionTransformation = aZposition;
m_zScaleTransformation = aZscale;
m_haveTransformation = true;
}
void CLAYERS_OGL_DISP_LISTS::SetItIsTransparent( bool aSetTransparent )
{
m_draw_it_transparent = aSetTransparent;
}
GLuint CLAYERS_OGL_DISP_LISTS::generate_top_or_bot_seg_ends(
const CLAYER_TRIANGLE_CONTAINER *aTriangleContainer,
bool aIsNormalUp,
GLuint aTextureId ) const
{
wxASSERT( aTriangleContainer != NULL );
wxASSERT( (aTriangleContainer->GetVertexSize() % 3) == 0 );
// Top and Bot dont have normals array stored in container
wxASSERT( aTriangleContainer->GetNormalsSize() == 0 );
if( (aTriangleContainer->GetVertexSize() > 0) &&
@ -250,7 +661,9 @@ GLuint CLAYERS_OGL_DISP_LISTS::generate_top_or_bot_seg_ends(const CLAYER_TRIANGL
// Prepare an array of UV text coordinates
SFVEC2F *uvArray = new SFVEC2F[aTriangleContainer->GetVertexSize()];
for( unsigned int i = 0; i < aTriangleContainer->GetVertexSize(); i += 3 )
for( unsigned int i = 0;
i < aTriangleContainer->GetVertexSize();
i += 3 )
{
uvArray[i + 0] = SFVEC2F( 1.0f, 0.0f );
uvArray[i + 1] = SFVEC2F( 0.0f, 1.0f );
@ -266,22 +679,16 @@ GLuint CLAYERS_OGL_DISP_LISTS::generate_top_or_bot_seg_ends(const CLAYER_TRIANGL
glNewList( listIdx, GL_COMPILE );
glDisable( GL_COLOR_MATERIAL );
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, aTextureId );
glAlphaFunc( GL_GREATER, 0.60f );
setBlendfunction();
glAlphaFunc( GL_GREATER, 0.2f );
glEnable( GL_ALPHA_TEST );
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
//SFVEC4F layerColor4 = SFVEC4F( aLayerColor.x, aLayerColor.y, aLayerColor.z, 1.0f );
//glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, &layerColor4.x );
//glDisable( GL_COLOR_MATERIAL );
glEnable( GL_COLOR_MATERIAL );
glColor4f( aLayerColor.x, aLayerColor.y, aLayerColor.z, 1.0f );
// OGL_SetMaterial()
glNormal3f( 0.0f, 0.0f, aIsNormalUp?1.0f:-1.0f );
glDrawArrays( GL_TRIANGLES, 0, aTriangleContainer->GetVertexSize() );
@ -289,7 +696,6 @@ GLuint CLAYERS_OGL_DISP_LISTS::generate_top_or_bot_seg_ends(const CLAYER_TRIANGL
glDisable( GL_TEXTURE_2D );
glDisable( GL_ALPHA_TEST );
glDisable( GL_BLEND );
glDisable( GL_COLOR_MATERIAL );
glEndList();
@ -305,18 +711,21 @@ GLuint CLAYERS_OGL_DISP_LISTS::generate_top_or_bot_seg_ends(const CLAYER_TRIANGL
}
GLuint CLAYERS_OGL_DISP_LISTS::generate_top_or_bot_triangles(const CLAYER_TRIANGLE_CONTAINER *aTriangleContainer, const SFVEC3F &aLayerColor , bool aIsNormalUp) const
GLuint CLAYERS_OGL_DISP_LISTS::generate_top_or_bot_triangles(
const CLAYER_TRIANGLE_CONTAINER *aTriangleContainer,
bool aIsNormalUp ) const
{
wxASSERT( aTriangleContainer != NULL );
wxASSERT( (aTriangleContainer->GetVertexSize() % 3) == 0 );
// Top and Bot dont have normals array stored in container
wxASSERT( aTriangleContainer->GetNormalsSize() == 0 );
if( (aTriangleContainer->GetVertexSize() > 0) &&
((aTriangleContainer->GetVertexSize() % 3) == 0) )
( (aTriangleContainer->GetVertexSize() % 3) == 0) )
{
GLuint listIdx = glGenLists( 1 );
const GLuint listIdx = glGenLists( 1 );
if( glIsList( listIdx ) )
{
@ -328,35 +737,13 @@ GLuint CLAYERS_OGL_DISP_LISTS::generate_top_or_bot_triangles(const CLAYER_TRIANG
glNewList( listIdx, GL_COMPILE );
//SFVEC4F layerColor4 = SFVEC4F( aLayerColor.x, aLayerColor.y, aLayerColor.z, 1.0f );
//glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, &layerColor4.x );
glEnable( GL_COLOR_MATERIAL );
glColor4f( aLayerColor.x, aLayerColor.y, aLayerColor.z, 1.0f );
setBlendfunction();
// OGL_SetMaterial()
glNormal3f( 0.0f, 0.0f, aIsNormalUp?1.0f:-1.0f );
glDrawArrays( GL_TRIANGLES, 0, aTriangleContainer->GetVertexSize() );
/*
glEnable( GL_COLOR_MATERIAL );
glColor3f( 0.0,1.0,1.0);
for( unsigned int i=0; i < aTriangleContainer->GetVertexSize(); ++i )
{
const SFVEC3F &v1 = aTriangleContainer->GetVertexPointer()[ i * 3];
glBegin(GL_LINES);
glVertex3f( v1.x, v1.y, v1.z );
if( aIsNormalUp )
{
glVertex3f( v1.x, v1.y, v1.z+1.0f*.0051f );
}
else
{
glVertex3f( v1.x, v1.y, v1.z-1.0f*.0051f );
}
glEnd();
}
*/
glDisable( GL_BLEND );
glEndList();
glDisableClientState( GL_VERTEX_ARRAY );
@ -368,7 +755,9 @@ GLuint CLAYERS_OGL_DISP_LISTS::generate_top_or_bot_triangles(const CLAYER_TRIANG
return 0;
}
GLuint CLAYERS_OGL_DISP_LISTS::generate_middle_triangles( const CLAYER_TRIANGLE_CONTAINER *aTriangleContainer, const SFVEC3F &aLayerColor ) const
GLuint CLAYERS_OGL_DISP_LISTS::generate_middle_triangles(
const CLAYER_TRIANGLE_CONTAINER *aTriangleContainer ) const
{
wxASSERT( aTriangleContainer != NULL );
@ -387,7 +776,7 @@ GLuint CLAYERS_OGL_DISP_LISTS::generate_middle_triangles( const CLAYER_TRIANGLE_
( (aTriangleContainer->GetVertexSize() % 6) == 0 ) &&
( aTriangleContainer->GetNormalsSize() == aTriangleContainer->GetVertexSize() ) )
{
GLuint listIdx = glGenLists( 1 );
const GLuint listIdx = glGenLists( 1 );
if( glIsList( listIdx ) )
{
@ -399,34 +788,12 @@ GLuint CLAYERS_OGL_DISP_LISTS::generate_middle_triangles( const CLAYER_TRIANGLE_
glNormalPointer( GL_FLOAT, 0, aTriangleContainer->GetNormalsPointer() );
glNewList( listIdx, GL_COMPILE );
/*
const SFVEC4F specular = SFVEC4F( 0.5f, 0.5f, 0.5f, 1.0f );
glMaterialfv( GL_FRONT, GL_SPECULAR, &specular.r );
glMaterialf( GL_FRONT, GL_SHININESS, 10.0f );*/
//SFVEC4F layerColor4 = SFVEC4F( aLayerColor.x, aLayerColor.y, aLayerColor.z, 1.0f );
//glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, &layerColor4.x );
//glDisable( GL_COLOR_MATERIAL );
glEnable( GL_COLOR_MATERIAL );
glColor4f( aLayerColor.x, aLayerColor.y, aLayerColor.z, 1.0f );
// OGL_SetMaterial()
setBlendfunction();
glDrawArrays( GL_TRIANGLES, 0, aTriangleContainer->GetVertexSize() );
/*
glEnable( GL_COLOR_MATERIAL );
glColor3f( 1.0,0.0,1.0);
for( unsigned int i=0; i < aTriangleContainer->GetVertexSize() / 3 ; ++i )
{
const SFVEC3F &v1 = ((const SFVEC3F*)aTriangleContainer->GetVertexPointer())[i * 3];
const SFVEC3F &n1 = ((const SFVEC3F*)aTriangleContainer->GetNormalsPointer())[i * 3];
glBegin(GL_LINES);
glVertex3f( v1.x, v1.y, v1.z );
glVertex3f( v1.x+n1.x*.01f, v1.y+n1.y*.01f, v1.z+n1.z*.01f );
glEnd();
}
*/
glDisable( GL_BLEND );
glEndList();
glDisableClientState( GL_VERTEX_ARRAY );
@ -439,3 +806,29 @@ GLuint CLAYERS_OGL_DISP_LISTS::generate_middle_triangles( const CLAYER_TRIANGLE_
return 0;
}
void CLAYERS_OGL_DISP_LISTS::endTransformation() const
{
if( m_haveTransformation )
{
glPopMatrix();
}
}
void CLAYERS_OGL_DISP_LISTS::setBlendfunction() const
{
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
}
void CLAYERS_OGL_DISP_LISTS::beginTransformation() const
{
if( m_haveTransformation )
{
glPushMatrix();
glTranslatef( 0.0f, 0.0f, m_zPositionTransformation );
glScalef( 1.0f, 1.0f, m_zScaleTransformation );
}
}

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -30,8 +30,10 @@
#ifndef CLAYER_TRIANGLES_H_
#define CLAYER_TRIANGLES_H_
#include "common_ogl/openGL_includes.h"
#include "plugins/3dapi/xv3d_types.h"
#include "../../common_ogl/openGL_includes.h"
#include <plugins/3dapi/xv3d_types.h>
#include <geometry/shape_line_chain.h>
#include <geometry/shape_poly_set.h>
#include <vector>
@ -49,10 +51,17 @@ public:
/**
* @brief CLAYER_TRIANGLE_CONTAINER
* @param aNrReservedTriangles: number of triangles expected to be used
* @param aReserveNormals: if you will use normals, set it to bool to pre reserve space
* @param aReserveNormals: if you will use normals, set it to bool to pre
* reserve space
*/
CLAYER_TRIANGLE_CONTAINER( unsigned int aNrReservedTriangles, bool aReserveNormals );
/**
* @brief Reserve_More - reserve more triangles
*
*/
void Reserve_More( unsigned int aNrReservedTriangles, bool aReserveNormals );
/**
* @brief AddTriangle
* @param aV1
@ -68,7 +77,10 @@ public:
* @param aV3
* @param aV4
*/
void AddQuad( const SFVEC3F &aV1, const SFVEC3F &aV2, const SFVEC3F &aV3, const SFVEC3F &aV4 );
void AddQuad( const SFVEC3F &aV1,
const SFVEC3F &aV2,
const SFVEC3F &aV3,
const SFVEC3F &aV4 );
/**
* @brief AddNormal
@ -84,7 +96,10 @@ public:
* @param aN2
* @param aN3
*/
void AddNormal( const SFVEC3F &aN1, const SFVEC3F &aN2, const SFVEC3F &aN3, const SFVEC3F &aN4 );
void AddNormal( const SFVEC3F &aN1,
const SFVEC3F &aN2,
const SFVEC3F &aN3,
const SFVEC3F &aN4 );
/**
* @brief GetVertexPointer - Get the array of vertexes
@ -102,17 +117,17 @@ public:
* @brief GetVertexSize
* @return
*/
unsigned int GetVertexSize() const { return m_vertexs.size(); }
unsigned int GetVertexSize() const { return (unsigned int)m_vertexs.size(); }
/**
* @brief GetNormalsSize
* @return
*/
unsigned int GetNormalsSize() const { return m_normals.size(); }
unsigned int GetNormalsSize() const { return (unsigned int)m_normals.size(); }
private:
SFVEC3F_VECTOR m_vertexs; ///< vertex array
SFVEC3F_VECTOR m_normals; ///< normals array
SFVEC3F_VECTOR m_vertexs; ///< vertex array
SFVEC3F_VECTOR m_normals; ///< normals array
};
@ -127,7 +142,7 @@ public:
* @brief CLAYER_TRIANGLES - initialize arrays with reserved triangles
* @param aNrReservedTriangles: number of pre alloc triangles to reserve
*/
CLAYER_TRIANGLES( unsigned int aNrReservedTriangles );
explicit CLAYER_TRIANGLES( unsigned int aNrReservedTriangles );
/**
* @brief ~CLAYER_TRIANGLES - Free containers
@ -135,11 +150,30 @@ public:
~CLAYER_TRIANGLES();
/**
* @brief IsLayersSizeValid - check if the vertex arrays of the layers are as expected
* @brief IsLayersSizeValid - check if the vertex arrays of the layers are
* as expected
* @return TRUE if layers are correctly setup
*/
bool IsLayersSizeValid();
void AddToMiddleContourns( const SHAPE_LINE_CHAIN &outlinePath,
float zBot,
float zTop,
double aBiuTo3Du,
bool aInvertFaceDirection );
void AddToMiddleContourns( const SHAPE_POLY_SET &aPolySet,
float zBot,
float zTop,
double aBiuTo3Du,
bool aInvertFaceDirection );
void AddToMiddleContourns( const std::vector< SFVEC2F > &aContournPoints,
float zBot,
float zTop,
bool aInvertFaceDirection );
CLAYER_TRIANGLE_CONTAINER *m_layer_top_segment_ends;
CLAYER_TRIANGLE_CONTAINER *m_layer_top_triangles;
CLAYER_TRIANGLE_CONTAINER *m_layer_middle_contourns_quads;
@ -157,25 +191,33 @@ class CLAYERS_OGL_DISP_LISTS
public:
/**
* @brief CLAYERS_OGL_DISP_LISTS - Creates the display lists for a layer
* @param aLayerTriangles: contains the layers array of vertex to render to display lists
* @param aTextureIndexForSegEnds: texture index to be used by segment ends. It is a black and white squared texture with a center circle diameter of the size of the texture.
* @param aLayerTriangles: contains the layers array of vertex to render to
* display lists
* @param aTextureIndexForSegEnds: texture index to be used by segment ends.
* It is a black and white squared texture
* with a center circle diameter of the size
* of the texture.
*/
CLAYERS_OGL_DISP_LISTS( const CLAYER_TRIANGLES &aLayerTriangles,
GLuint aTextureIndexForSegEnds,
const SFVEC3F& aLayerColor );
float aZBot,
float aZTop );
/**
* @brief ~CLAYERS_OGL_DISP_LISTS - Destroy this class while free the display lists from GPU mem
* @brief ~CLAYERS_OGL_DISP_LISTS - Destroy this class while free the display
* lists from GPU mem
*/
~CLAYERS_OGL_DISP_LISTS();
/**
* @brief DrawTopAndMiddle - This function calls the display lists for the top elements and middle contourns
* @brief DrawTopAndMiddle - This function calls the display lists for the
* top elements and middle contourns
*/
void DrawTopAndMiddle() const;
/**
* @brief DrawBotAndMiddle - This function calls the display lists for the botton elements and middle contourns
* @brief DrawBotAndMiddle - This function calls the display lists for the
* botton elements and middle contourns
*/
void DrawBotAndMiddle() const;
@ -190,26 +232,66 @@ public:
void DrawBot() const;
/**
* @brief DrawMiddle - This function calls the display lists for the middle elements
* @brief DrawMiddle - This function calls the display lists for the middle
* elements
*/
void DrawMiddle() const;
/**
* @brief DrawAll - This function calls all the display lists
*/
void DrawAll() const;
void DrawAll( bool aDrawMiddle = true ) const;
/**
* @brief DrawAllCameraCulled - Draw all layers if they are visible by the camera.
* i.e.: if camera position is above the layer. This only works because the
* board is centered and the planes are always perpendicular to the Z axis.
* @param zCameraPos: camera z position
*/
void DrawAllCameraCulled( float zCameraPos, bool aDrawMiddle = true ) const;
void DrawAllCameraCulledSubtractLayer( const CLAYERS_OGL_DISP_LISTS *aLayerToSubtractA,
const CLAYERS_OGL_DISP_LISTS *aLayerToSubtractB,
bool aDrawMiddle = true ) const;
void ApplyScalePosition( float aZposition, float aZscale );
void ClearScalePosition() { m_haveTransformation = false; }
void SetItIsTransparent( bool aSetTransparent );
float GetZBot() const { return m_zBot; }
float GetZTop() const { return m_zTop; }
private:
GLuint generate_top_or_bot_seg_ends(const CLAYER_TRIANGLE_CONTAINER * aTriangleContainer, const SFVEC3F& aLayerColor, bool aIsNormalUp , GLuint aTextureId ) const;
GLuint generate_top_or_bot_triangles( const CLAYER_TRIANGLE_CONTAINER * aTriangleContainer, const SFVEC3F& aLayerColor, bool aIsNormalUp ) const;
GLuint generate_middle_triangles( const CLAYER_TRIANGLE_CONTAINER * aTriangleContainer, const SFVEC3F& aLayerColor ) const;
GLuint generate_top_or_bot_seg_ends( const CLAYER_TRIANGLE_CONTAINER * aTriangleContainer,
bool aIsNormalUp,
GLuint aTextureId ) const;
GLuint generate_top_or_bot_triangles( const CLAYER_TRIANGLE_CONTAINER * aTriangleContainer,
bool aIsNormalUp ) const;
GLuint generate_middle_triangles( const CLAYER_TRIANGLE_CONTAINER * aTriangleContainer ) const;
void beginTransformation() const;
void endTransformation() const;
void setBlendfunction() const;
private:
GLuint m_layer_top_segment_ends;
GLuint m_layer_top_triangles;
GLuint m_layer_middle_contourns_quads;
GLuint m_layer_bot_triangles;
GLuint m_layer_bot_segment_ends;
float m_zBot;
float m_zTop;
GLuint m_layer_top_segment_ends;
GLuint m_layer_top_triangles;
GLuint m_layer_middle_contourns_quads;
GLuint m_layer_bot_triangles;
GLuint m_layer_bot_segment_ends;
bool m_haveTransformation;
float m_zPositionTransformation;
float m_zScaleTransformation;
bool m_draw_it_transparent;
};
#endif // CLAYER_TRIANGLES_H_

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -28,10 +28,10 @@
*/
#include "common_ogl/openGL_includes.h"
#include "../../common_ogl/openGL_includes.h"
#include "ogl_legacy_utils.h"
#include <trigo.h>
#include <wx/debug.h> // For the wxASSERT
#include <wx/debug.h> // For the wxASSERT
#define RADPERDEG 0.0174533
@ -50,8 +50,12 @@ void OGL_draw_arrow( SFVEC3F aPosition, SFVEC3F aTargetPos, float aSize )
if( ( vec.x != 0.0f ) || ( vec.y != 0.0f ) )
{
glRotatef( atan2(vec.y, vec.x) / RADPERDEG, 0.0f, 0.0f, 1.0f );
glRotatef( atan2(sqrt(vec.x * vec.x + vec.y * vec.y), vec.z) / RADPERDEG, 0.0f, 1.0f, 0.0f );
glRotatef( atan2( vec.y, vec.x ) / RADPERDEG, 0.0f, 0.0f, 1.0f );
glRotatef( atan2( sqrt( vec.x * vec.x + vec.y * vec.y ), vec.z ) / RADPERDEG,
0.0f,
1.0f,
0.0f );
} else if( vec.z < 0.0f )
{
glRotatef( 180.0f, 1.0f, 0.0f, 0.0f );
@ -87,8 +91,8 @@ void OGL_draw_arrow( SFVEC3F aPosition, SFVEC3F aTargetPos, float aSize )
glTranslatef( 0.0f , 0.0f ,-length + 4.0f * aSize );
quadObj = gluNewQuadric();
gluQuadricDrawStyle(quadObj, GLU_FILL );
gluQuadricNormals(quadObj, GLU_SMOOTH );
gluQuadricDrawStyle( quadObj, GLU_FILL );
gluQuadricNormals( quadObj, GLU_SMOOTH );
gluCylinder( quadObj, aSize, aSize, length - 4.0 * aSize, 12, 1 );
gluDeleteQuadric( quadObj );
/*
@ -154,45 +158,53 @@ void OGL_draw_half_open_cylinder( unsigned int aNrSidesPerCircle )
{
if( aNrSidesPerCircle > 1 )
{
float radius = 0.5f;
int delta = 3600 / aNrSidesPerCircle;
const float radius = 0.5f;
const int delta = 3600 / aNrSidesPerCircle;
// Generate bottom
glNormal3f( 0.0f, 0.0f,-1.0f );
glBegin( GL_TRIANGLE_FAN );
glVertex3f( 0.0, 0.0, 0.0 ); // This is the V0 of the FAN
glVertex3f( 0.0, 0.0, 0.0 ); // This is the V0 of the FAN
for( int ii = 0; ii < 1800; ii += delta )
{
SFVEC2D corner = SFVEC2D( 0.0, radius );
RotatePoint( &corner.x, &corner.y, ii );
glVertex3f( corner.x, corner.y, 0.0 );
}
glVertex3d( 0.0, -radius, 0.0 );
glEnd();
// Generate top
glNormal3f( 0.0f, 0.0f, 1.0f );
glBegin( GL_TRIANGLE_FAN );
glVertex3f( 0.0, 0.0, 1.0 ); // This is the V0 of the FAN
glVertex3f( 0.0, 0.0, 1.0 ); // This is the V0 of the FAN
for( int ii = 1800; ii > 0; ii -= delta )
{
SFVEC2D corner = SFVEC2D( 0.0, radius );
RotatePoint( &corner.x, &corner.y, ii );
glVertex3f( corner.x, corner.y, 1.0 );
}
glVertex3f( 0.0, radius, 1.0 );
glEnd();
// Generate contours
glBegin( GL_QUAD_STRIP );
for( int ii = 1800; ii > 0; ii -= delta )
{
SFVEC2D corner = SFVEC2D( 0.0, radius );
RotatePoint( &corner.x, &corner.y, ii );
glNormal3f( corner.x * 2.0f, corner.y * 2.0f, 0.0f );
glVertex3f( corner.x, corner.y, 1.0 );
glVertex3f( corner.x, corner.y, 0.0 );
}
glNormal3f( 0.0, 1.0f, 0.0f );
glVertex3d( 0.0, radius, 1.0 );
glVertex3d( 0.0, radius, 0.0 );
@ -201,7 +213,8 @@ void OGL_draw_half_open_cylinder( unsigned int aNrSidesPerCircle )
}
void OGL_Draw_segment( const CROUNDSEGMENT2D &aSegment, unsigned int aNrSidesPerCircle )
void OGL_Draw_segment( const CROUNDSEGMENT2D &aSegment,
unsigned int aNrSidesPerCircle )
{
glPushMatrix();
@ -215,14 +228,17 @@ void OGL_Draw_segment( const CROUNDSEGMENT2D &aSegment, unsigned int aNrSidesPer
if( ( end_minus_start.x != 0.0f ) || ( end_minus_start.y != 0.0f ) )
{
glRotatef( atan2(end_minus_start.y, end_minus_start.x) / RADPERDEG, 0.0f, 0.0f, 1.0f );
glRotatef( atan2( end_minus_start.y, end_minus_start.x ) / RADPERDEG,
0.0f,
0.0f,
1.0f );
}
glPushMatrix();
glTranslatef( length, 0.0, 0.0f );
glScalef( width, width, 1.0f );
OGL_draw_half_open_cylinder( aNrSidesPerCircle );
glPopMatrix ();
glPopMatrix();
glBegin( GL_QUADS );
glNormal3f( 0.0,-1.0, 0.0 );

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -30,9 +30,8 @@
#ifndef OGL_LEGACY_UTILS_H_
#define OGL_LEGACY_UTILS_H_
#include "plugins/3dapi/xv3d_types.h"
#include "3d_render_raytracing/shapes3D/cbbox.h"
#include "3d_render_raytracing/shapes2D/croundsegment2d.h"
#include "../3d_render_raytracing/shapes3D/cbbox.h"
#include "../3d_render_raytracing/shapes2D/croundsegment2d.h"
/**
* @brief OGL_draw_arrow - draw a round arrow
@ -62,6 +61,7 @@ void OGL_draw_half_open_cylinder( unsigned int aNrSidesPerCircle );
* @brief OGL_Draw_segment
* @param aSegment
*/
void OGL_Draw_segment( const CROUNDSEGMENT2D &aSegment, unsigned int aNrSidesPerCircle );
void OGL_Draw_segment( const CROUNDSEGMENT2D &aSegment,
unsigned int aNrSidesPerCircle );
#endif // OGL_LEGACY_UTILS_H_

View File

@ -0,0 +1,40 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file caccelerator.cpp
* @brief
*/
#include "caccelerator.h"
CGENERICACCELERATOR::CGENERICACCELERATOR( )
{
m_bbox.Reset();
}
CGENERICACCELERATOR::~CGENERICACCELERATOR()
{
}

View File

@ -0,0 +1,58 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file caccelerator.h
* @brief
*/
#ifndef _CACCELERATOR_H_
#define _CACCELERATOR_H_
#include "ccontainer.h"
#include "../raypacket.h"
class CGENERICACCELERATOR
{
protected:
CBBOX m_bbox;
public:
CGENERICACCELERATOR( );
virtual ~CGENERICACCELERATOR();
virtual bool Intersect( const RAY &aRay, HITINFO &aHitInfo ) const = 0;
virtual bool Intersect( const RAY &aRay,
HITINFO &aHitInfo,
unsigned int aAccNodeInfo ) const = 0;
virtual bool Intersect( const RAYPACKET &aRayPacket,
HITINFO_PACKET *aHitInfoPacket ) const = 0;
virtual bool IntersectP( const RAY &aRay, float aMaxDistance ) const = 0;
};
#endif // _CACCELERATOR_H_

View File

@ -0,0 +1,295 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file cbvh_packet_traversal.cpp
* @brief This file implementes packet traversal over the BVH PBRT implementation
*/
#include "cbvh_pbrt.h"
#include <wx/debug.h>
#define BVH_RANGED_TRAVERSAL
//#define BVH_PARTITION_TRAVERSAL
#define MAX_TODOS 64
struct StackNode
{
int cell;
unsigned int ia; // Index to the first alive ray
};
static inline unsigned int getFirstHit( const RAYPACKET &aRayPacket,
const CBBOX &aBBox,
unsigned int ia,
HITINFO_PACKET *aHitInfoPacket )
{
float hitT;
if( aBBox.Intersect( aRayPacket.m_ray[ia], &hitT ) )
if( hitT < aHitInfoPacket[ia].m_HitInfo.m_tHit )
return ia;
if( !aRayPacket.m_Frustum.Intersect( aBBox ) )
return RAYPACKET_RAYS_PER_PACKET;
for( unsigned int i = ia + 1; i < RAYPACKET_RAYS_PER_PACKET; ++i )
{
if( aBBox.Intersect( aRayPacket.m_ray[i], &hitT ) )
if( hitT < aHitInfoPacket[i].m_HitInfo.m_tHit )
return i;
}
return RAYPACKET_RAYS_PER_PACKET;
}
#ifdef BVH_RANGED_TRAVERSAL
static inline unsigned int getLastHit( const RAYPACKET &aRayPacket,
const CBBOX &aBBox,
unsigned int ia,
HITINFO_PACKET *aHitInfoPacket )
{
for( unsigned int ie = (RAYPACKET_RAYS_PER_PACKET - 1); ie > ia; --ie )
{
float hitT;
if( aBBox.Intersect( aRayPacket.m_ray[ie], &hitT ) )
if( hitT < aHitInfoPacket[ie].m_HitInfo.m_tHit )
return ie + 1;
}
return ia + 1;
}
// "Large Ray Packets for Real-time Whitted Ray Tracing"
// http://cseweb.ucsd.edu/~ravir/whitted.pdf
// Ranged Traversal
bool CBVH_PBRT::Intersect( const RAYPACKET &aRayPacket,
HITINFO_PACKET *aHitInfoPacket ) const
{
if( m_nodes == NULL )
return false;
if( (&m_nodes[0]) == NULL )
return false;
bool anyHitted = false;
int todoOffset = 0, nodeNum = 0;
StackNode todo[MAX_TODOS];
unsigned int ia = 0;
while( true )
{
const LinearBVHNode *curCell = &m_nodes[nodeNum];
ia = getFirstHit( aRayPacket, curCell->bounds, ia, aHitInfoPacket );
if( ia < RAYPACKET_RAYS_PER_PACKET )
{
if( curCell->nPrimitives == 0 )
{
StackNode &node = todo[todoOffset++];
node.cell = curCell->secondChildOffset;
node.ia = ia;
nodeNum = nodeNum + 1;
continue;
}
else
{
const unsigned int ie = getLastHit( aRayPacket,
curCell->bounds,
ia,
aHitInfoPacket );
for( int j = 0; j < curCell->nPrimitives; ++j )
{
const COBJECT *obj = m_primitives[curCell->primitivesOffset + j];
if( aRayPacket.m_Frustum.Intersect( obj->GetBBox() ) )
{
for( unsigned int i = ia; i < ie; ++i )
{
const bool hitted = obj->Intersect( aRayPacket.m_ray[i],
aHitInfoPacket[i].m_HitInfo );
if( hitted )
{
anyHitted |= hitted;
aHitInfoPacket[i].m_hitresult |= hitted;
aHitInfoPacket[i].m_HitInfo.m_acc_node_info = nodeNum;
}
}
}
}
}
}
if( todoOffset == 0 )
break;
const StackNode &node = todo[--todoOffset];
nodeNum = node.cell;
ia = node.ia;
}
return anyHitted;
}// Ranged Traversal
#endif
// "Ray Tracing Deformable Scenes Using Dynamic Bounding Volume Hierarchies"
// http://www.cs.cmu.edu/afs/cs/academic/class/15869-f11/www/readings/wald07_packetbvh.pdf
#ifdef BVH_PARTITION_TRAVERSAL
static inline unsigned int getLastHit( const RAYPACKET &aRayPacket,
const CBBOX &aBBox,
unsigned int ia,
const unsigned int *aRayIndex,
HITINFO_PACKET *aHitInfoPacket )
{
for( unsigned int ie = (RAYPACKET_RAYS_PER_PACKET - 1); ie > ia; --ie )
{
float hitT;
if( aBBox.Intersect( aRayPacket.m_ray[ aRayIndex[ie] ], &hitT ) )
if( hitT < aHitInfoPacket[ aRayIndex[ie] ].m_HitInfo.m_tHit )
return ie + 1;
}
return ia + 1;
}
static inline unsigned int partRays( const RAYPACKET &aRayPacket,
const CBBOX &aBBox,
unsigned int ia,
unsigned int *aRayIndex,
HITINFO_PACKET *aHitInfoPacket )
{
if( !aRayPacket.m_Frustum.Intersect( aBBox ) )
return RAYPACKET_RAYS_PER_PACKET;
unsigned int ie = 0;
for( unsigned int i = 0; i < ia; ++i )
{
float hitT;
if( aBBox.Intersect( aRayPacket.m_ray[ aRayIndex[i] ], &hitT ) )
if( hitT < aHitInfoPacket[ aRayIndex[i] ].m_HitInfo.m_tHit )
std::swap( aRayIndex[ie++], aRayIndex[i] );
}
return ie;
}
bool CBVH_PBRT::Intersect( const RAYPACKET &aRayPacket,
HITINFO_PACKET *aHitInfoPacket ) const
{
bool anyHitted = false;
int todoOffset = 0, nodeNum = 0;
StackNode todo[MAX_TODOS];
unsigned int I[RAYPACKET_RAYS_PER_PACKET];
memcpy( I, m_I, RAYPACKET_RAYS_PER_PACKET * sizeof( unsigned int ) );
unsigned int ia = 0;
while( true )
{
const LinearBVHNode *curCell = &m_nodes[nodeNum];
ia = partRays( aRayPacket, curCell->bounds, ia, I, aHitInfoPacket );
if( ia < RAYPACKET_RAYS_PER_PACKET )
{
if( curCell->nPrimitives == 0 )
{
StackNode &node = todo[todoOffset++];
node.cell = curCell->secondChildOffset;
node.ia = ia;
nodeNum = nodeNum + 1;
continue;
}
else
{
unsigned int ie = getLastHit( aRayPacket,
curCell->bounds,
ia,
I,
aHitInfoPacket );
for( int j = 0; j < curCell->nPrimitives; ++j )
{
const COBJECT *obj = m_primitives[curCell->primitivesOffset + j];
if( aRayPacket.m_Frustum.Intersect( obj->GetBBox() ) )
{
for( unsigned int i = 0; i < ie; ++i )
{
unsigned int idx = I[i];
bool hitted = obj->Intersect(
aRayPacket.m_ray[idx],
aHitInfoPacket[idx].m_HitInfo );
if( hitted )
{
anyHitted |= hitted;
aHitInfoPacket[idx].m_hitresult |= hitted;
aHitInfoPacket[idx].m_HitInfo.m_acc_node_info = nodeNum;
}
}
}
}
}
}
if( todoOffset == 0 )
break;
const StackNode &node = todo[--todoOffset];
nodeNum = node.cell;
ia = node.ia;
}
return anyHitted;
}// Partition Traversal
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,168 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file cbvh_pbrt.h
* @brief This BVH implementation is based on the source code implementation
* from the book "Physically Based Rendering" (v2 and v3)
*
* Adaptions performed:
* - Types and class types adapted to KiCad project
* - Convert some source to build in the C++ specification of KiCad
* - Code style to match KiCad
* - Asserts converted
* - Use compare functions/structures for std::partition and std::nth_element
*
* The original source code have the following licence:
*
* "pbrt source code is Copyright(c) 1998-2015
* Matt Pharr, Greg Humphreys, and Wenzel Jakob.
*
* This file is part of pbrt.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
*
*/
#ifndef _CBVH_PBRT_H_
#define _CBVH_PBRT_H_
#include "caccelerator.h"
#include <list>
#include <stdint.h>
// Forward Declarations
struct BVHBuildNode;
struct BVHPrimitiveInfo;
struct MortonPrimitive;
struct LinearBVHNode
{
// 24 bytes
CBBOX bounds;
// 4 bytes
union
{
int primitivesOffset; ///< leaf
int secondChildOffset; ///< interior
};
// 4 bytes
uint16_t nPrimitives; ///< 0 -> interior node
uint8_t axis; ///< interior node: xyz
uint8_t pad[1]; ///< ensure 32 byte total size
};
enum SPLITMETHOD
{
SPLIT_MIDDLE,
SPLIT_EQUALCOUNTS,
SPLIT_SAH,
SPLIT_HLBVH
};
class CBVH_PBRT : public CGENERICACCELERATOR
{
public:
CBVH_PBRT( const CGENERICCONTAINER &aObjectContainer,
int aMaxPrimsInNode = 4,
SPLITMETHOD aSplitMethod = SPLIT_SAH );
~CBVH_PBRT();
// Imported from CGENERICACCELERATOR
bool Intersect( const RAY &aRay, HITINFO &aHitInfo ) const;
bool Intersect( const RAY &aRay, HITINFO &aHitInfo, unsigned int aAccNodeInfo ) const;
bool Intersect(const RAYPACKET &aRayPacket, HITINFO_PACKET *aHitInfoPacket ) const;
bool IntersectP( const RAY &aRay, float aMaxDistance ) const;
private:
BVHBuildNode *recursiveBuild( std::vector<BVHPrimitiveInfo> &primitiveInfo,
int start,
int end,
int *totalNodes,
CONST_VECTOR_OBJECT &orderedPrims );
BVHBuildNode *HLBVHBuild( const std::vector<BVHPrimitiveInfo> &primitiveInfo,
int *totalNodes,
CONST_VECTOR_OBJECT &orderedPrims );
//!TODO: after implement memory arena, put const back to this functions
BVHBuildNode *emitLBVH( BVHBuildNode *&buildNodes,
const std::vector<BVHPrimitiveInfo> &primitiveInfo,
MortonPrimitive *mortonPrims,
int nPrimitives,
int *totalNodes,
CONST_VECTOR_OBJECT &orderedPrims,
int *orderedPrimsOffset,
int bit );
BVHBuildNode *buildUpperSAH( std::vector<BVHBuildNode *> &treeletRoots,
int start,
int end,
int *totalNodes );
int flattenBVHTree( BVHBuildNode *node,
uint32_t *offset );
// BVH Private Data
const int m_maxPrimsInNode;
SPLITMETHOD m_splitMethod;
CONST_VECTOR_OBJECT m_primitives;
LinearBVHNode *m_nodes;
std::list<void *> m_addresses_pointer_to_mm_free;
// Partition traversal
unsigned int m_I[RAYPACKET_RAYS_PER_PACKET];
};
#endif // _CBVH_PBRT_H_

View File

@ -0,0 +1,124 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file ccontainer.cpp
* @brief
*/
#include "ccontainer.h"
#include <stdio.h>
CGENERICCONTAINER::CGENERICCONTAINER()
{
m_objects.clear();
m_bbox.Reset();
}
void CGENERICCONTAINER::Clear()
{
if( !m_objects.empty() )
{
for( LIST_OBJECT::iterator ii = m_objects.begin();
ii != m_objects.end();
++ii )
{
delete *ii;
*ii = NULL;
}
m_objects.clear();
}
m_bbox.Reset();
}
CGENERICCONTAINER::~CGENERICCONTAINER()
{
Clear();
}
void CGENERICCONTAINER::ConvertTo( CONST_VECTOR_OBJECT &aOutVector ) const
{
aOutVector.resize( m_objects.size() );
if( !m_objects.empty() )
{
unsigned int i = 0;
for( LIST_OBJECT::const_iterator ii = m_objects.begin();
ii != m_objects.end();
++ii )
{
wxASSERT( (*ii) != NULL );
aOutVector[i++] = static_cast<const COBJECT *>(*ii);
}
}
}
bool CCONTAINER::Intersect( const RAY &aRay, HITINFO &aHitInfo ) const
{
if( !m_bbox.Intersect( aRay ) )
return false;
bool hitted = false;
for( LIST_OBJECT::const_iterator ii = m_objects.begin();
ii != m_objects.end();
++ii )
{
const COBJECT *object = static_cast<const COBJECT *>(*ii);
if( object->Intersect( aRay, aHitInfo) )
hitted = true;
}
return hitted;
}
bool CCONTAINER::IntersectP( const RAY &aRay, float aMaxDistance ) const
{
/*
if( !m_bbox.Inside( aRay.m_Origin ) )
if( !m_bbox.Intersect( aRay ) )
return false;
*/
for( LIST_OBJECT::const_iterator ii = m_objects.begin();
ii != m_objects.end();
++ii )
{
const COBJECT *object = static_cast<const COBJECT *>(*ii);
if( object->IntersectP( aRay, aMaxDistance ) )
return true;
}
return false;
}

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -38,7 +38,7 @@ typedef std::list<COBJECT *> LIST_OBJECT;
typedef std::vector<COBJECT *> VECTOR_OBJECT;
typedef std::vector<const COBJECT *> CONST_VECTOR_OBJECT;
class GLM_ALIGN(CLASS_ALIGNMENT) CGENERICCONTAINER
class CGENERICCONTAINER
{
protected:
CBBOX m_bbox;
@ -62,7 +62,7 @@ public:
const LIST_OBJECT &GetList() const { return m_objects; }
const void ConvertTo( CONST_VECTOR_OBJECT &aOutVector ) const;
void ConvertTo( CONST_VECTOR_OBJECT &aOutVector ) const;
const CBBOX &GetBBox() const { return m_bbox; }
@ -73,7 +73,7 @@ private:
};
class GLM_ALIGN(CLASS_ALIGNMENT) CCONTAINER : public CGENERICCONTAINER
class CCONTAINER : public CGENERICCONTAINER
{
public:
bool Intersect( const RAY &aRay, HITINFO &aHitInfo ) const;

View File

@ -0,0 +1,437 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file ccontainer2d.cpp
* @brief
*/
#include "ccontainer2d.h"
#include <vector>
#include <boost/range/algorithm/partition.hpp>
#include <boost/range/algorithm/nth_element.hpp>
#include <wx/debug.h>
// /////////////////////////////////////////////////////////////////////////////
// CGENERICCONTAINER2
// /////////////////////////////////////////////////////////////////////////////
CGENERICCONTAINER2D::CGENERICCONTAINER2D( OBJECT2D_TYPE aObjType )
{
m_bbox.Reset();
}
void CGENERICCONTAINER2D::Clear()
{
m_bbox.Reset();
for( LIST_OBJECT2D::iterator ii = m_objects.begin();
ii != m_objects.end();
++ii )
{
delete *ii;
*ii = NULL;
}
m_objects.clear();
}
CGENERICCONTAINER2D::~CGENERICCONTAINER2D()
{
Clear();
}
// /////////////////////////////////////////////////////////////////////////////
// CCONTAINER2D
// /////////////////////////////////////////////////////////////////////////////
CCONTAINER2D::CCONTAINER2D() : CGENERICCONTAINER2D( OBJ2D_CONTAINER )
{
}
/*
bool CCONTAINER2D::Intersects( const CBBOX2D &aBBox ) const
{
return false;
}
bool CCONTAINER2D::Overlaps( const CBBOX2D &aBBox ) const
{
// NOT IMPLEMENTED
return false;
}
bool CCONTAINER2D::Intersect( const RAYSEG2D &aSegRay, float *aOutT, SFVEC2F *aNormalOut ) const
{
if( !m_bbox.Intersect( aSegRay ) )
return false;
bool hitted = false;
for( LIST_OBJECT2D::const_iterator ii = m_objects.begin();
ii != m_objects.end();
ii++ )
{
const COBJECT2D *object = static_cast<const COBJECT2D *>(*ii);
float t;
SFVEC2F hitNormal;
if( object->Intersect( aSegRay, &t, &hitNormal ) )
if( (hitted == false) || (t < *aOutT ) )
{
hitted = true;
*aOutT = t;
*aNormalOut = hitNormal;
}
}
return hitted;
}
INTERSECTION_RESULT CCONTAINER2D::IsBBoxInside( const CBBOX2D &aBBox ) const
{
return INTR_MISSES;
}
bool CCONTAINER2D::IsPointInside( const SFVEC2F &aPoint ) const
{
if( !m_bbox.Inside( aPoint ) )
return false;
for( LIST_OBJECT2D::const_iterator ii = m_objects.begin();
ii != m_objects.end();
ii++ )
{
const COBJECT2D *object = static_cast<const COBJECT2D *>(*ii);
if( object->IsPointInside( aPoint ) )
return true;
}
return false;
}
*/
void CCONTAINER2D::GetListObjectsIntersects( const CBBOX2D & aBBox,
CONST_LIST_OBJECT2D &aOutList ) const
{
// !TODO:
}
// /////////////////////////////////////////////////////////////////////////////
// CBVHCONTAINER2D
// /////////////////////////////////////////////////////////////////////////////
CBVHCONTAINER2D::CBVHCONTAINER2D() : CGENERICCONTAINER2D( OBJ2D_BVHCONTAINER )
{
m_isInitialized = false;
m_bbox.Reset();
m_elements_to_delete.clear();
m_Tree = NULL;
}
/*
bool CBVHCONTAINER2D::Intersects( const CBBOX2D &aBBox ) const
{
// !TODO: implement the BVH
return m_bbox.Intersects( aBBox );
}
bool CBVHCONTAINER2D::Overlaps( const CBBOX2D &aBBox ) const
{
// NOT IMPLEMENTED
return false;
}
bool CBVHCONTAINER2D::Intersect( const RAYSEG2D &aSegRay,
float *aOutT, SFVEC2F *aNormalOut ) const
{
// !TODO: implement the BVH
if( !m_bbox.Intersect( aSegRay ) )
return false;
bool hitted = false;
for( LIST_OBJECT2D::const_iterator ii = m_objects.begin();
ii != m_objects.end();
ii++ )
{
const COBJECT2D *object = static_cast<const COBJECT2D *>(*ii);
float t;
SFVEC2F hitNormal;
if( object->Intersect( aSegRay, &t, &hitNormal ) )
if( (hitted == false) || (t < *aOutT ) )
{
hitted = true;
*aOutT = t;
*aNormalOut = hitNormal;
}
}
return hitted;
}
INTERSECTION_RESULT CBVHCONTAINER2D::IsBBoxInside( const CBBOX2D &aBBox ) const
{
return INTR_MISSES;
}
bool CBVHCONTAINER2D::IsPointInside( const SFVEC2F &aPoint ) const
{
// !TODO: implement the BVH
if( !m_bbox.Inside( aPoint ) )
return false;
for( LIST_OBJECT2D::const_iterator ii = m_objects.begin();
ii != m_objects.end();
ii++ )
{
const COBJECT2D *object = static_cast<const COBJECT2D *>(*ii);
if( object->IsPointInside( aPoint ) )
return true;
}
return false;
}
*/
void CBVHCONTAINER2D::destroy()
{
for( std::list<BVH_CONTAINER_NODE_2D *>::iterator ii = m_elements_to_delete.begin();
ii != m_elements_to_delete.end();
++ii )
{
delete *ii;
*ii = NULL;
}
m_elements_to_delete.clear();
m_isInitialized = false;
}
CBVHCONTAINER2D::~CBVHCONTAINER2D()
{
destroy();
}
#define BVH_CONTAINER2D_MAX_OBJ_PER_LEAF 4
void CBVHCONTAINER2D::BuildBVH()
{
if( m_isInitialized )
destroy();
if( m_objects.empty() )
{
return;
}
m_isInitialized = true;
m_Tree = new BVH_CONTAINER_NODE_2D;
m_elements_to_delete.push_back( m_Tree );
m_Tree->m_BBox = m_bbox;
for( LIST_OBJECT2D::const_iterator ii = m_objects.begin();
ii != m_objects.end();
++ii )
{
m_Tree->m_LeafList.push_back( static_cast<const COBJECT2D *>(*ii) );
}
recursiveBuild_MIDDLE_SPLIT( m_Tree );
}
// Based on a blog post by VADIM KRAVCENKO
// http://www.vadimkravcenko.com/bvh-tree-building
// Implements:
// "Split in the middle of the longest Axis"
// "Creates a binary tree with Top-Down approach.
// Fastest BVH building, but least [speed] accuracy."
static bool sortByCentroid_X( const COBJECT2D *a, const COBJECT2D *b )
{
return a->GetCentroid()[0] < b->GetCentroid()[0];
}
static bool sortByCentroid_Y( const COBJECT2D *a, const COBJECT2D *b )
{
return a->GetCentroid()[0] < b->GetCentroid()[0];
}
static bool sortByCentroid_Z( const COBJECT2D *a, const COBJECT2D *b )
{
return a->GetCentroid()[0] < b->GetCentroid()[0];
}
void CBVHCONTAINER2D::recursiveBuild_MIDDLE_SPLIT( BVH_CONTAINER_NODE_2D *aNodeParent )
{
wxASSERT( aNodeParent != NULL );
wxASSERT( aNodeParent->m_BBox.IsInitialized() == true );
wxASSERT( aNodeParent->m_LeafList.size() > 0 );
if( aNodeParent->m_LeafList.size() > BVH_CONTAINER2D_MAX_OBJ_PER_LEAF )
{
// Create Leaf Nodes
BVH_CONTAINER_NODE_2D *leftNode = new BVH_CONTAINER_NODE_2D;
BVH_CONTAINER_NODE_2D *rightNode = new BVH_CONTAINER_NODE_2D;
m_elements_to_delete.push_back( leftNode );
m_elements_to_delete.push_back( rightNode );
leftNode->m_BBox.Reset();
rightNode->m_BBox.Reset();
leftNode->m_LeafList.clear();
rightNode->m_LeafList.clear();
// Decide wich axis to split
const unsigned int axis_to_split = aNodeParent->m_BBox.MaxDimension();
// Divide the objects
switch( axis_to_split )
{
case 0: aNodeParent->m_LeafList.sort( sortByCentroid_X );
case 1: aNodeParent->m_LeafList.sort( sortByCentroid_Y );
case 2: aNodeParent->m_LeafList.sort( sortByCentroid_Z );
}
unsigned int i = 0;
for( CONST_LIST_OBJECT2D::const_iterator ii = aNodeParent->m_LeafList.begin();
ii != aNodeParent->m_LeafList.end();
++ii )
{
const COBJECT2D *object = static_cast<const COBJECT2D *>(*ii);
if( i < (aNodeParent->m_LeafList.size() / 2 ) )
{
leftNode->m_BBox.Union( object->GetBBox() );
leftNode->m_LeafList.push_back( object );
}
else
{
rightNode->m_BBox.Union( object->GetBBox() );
rightNode->m_LeafList.push_back( object );
}
i++;
}
wxASSERT( leftNode->m_LeafList.size() > 0 );
wxASSERT( rightNode->m_LeafList.size() > 0 );
wxASSERT( ( leftNode->m_LeafList.size() + rightNode->m_LeafList.size() ) ==
aNodeParent->m_LeafList.size() );
aNodeParent->m_Children[0] = leftNode;
aNodeParent->m_Children[1] = rightNode;
aNodeParent->m_LeafList.clear();
recursiveBuild_MIDDLE_SPLIT( leftNode );
recursiveBuild_MIDDLE_SPLIT( rightNode );
}
else
{
// It is a Leaf
aNodeParent->m_Children[0] = NULL;
aNodeParent->m_Children[1] = NULL;
}
}
void CBVHCONTAINER2D::GetListObjectsIntersects( const CBBOX2D &aBBox,
CONST_LIST_OBJECT2D &aOutList ) const
{
wxASSERT( aBBox.IsInitialized() == true );
wxASSERT( m_isInitialized == true );
aOutList.clear();
if( m_Tree )
recursiveGetListObjectsIntersects( m_Tree, aBBox, aOutList );
}
void CBVHCONTAINER2D::recursiveGetListObjectsIntersects( const BVH_CONTAINER_NODE_2D *aNode,
const CBBOX2D & aBBox,
CONST_LIST_OBJECT2D &aOutList ) const
{
wxASSERT( aNode != NULL );
wxASSERT( aBBox.IsInitialized() == true );
if( aNode->m_BBox.Intersects( aBBox ) )
{
if( !aNode->m_LeafList.empty() )
{
wxASSERT( aNode->m_Children[0] == NULL );
wxASSERT( aNode->m_Children[1] == NULL );
// Leaf
for( CONST_LIST_OBJECT2D::const_iterator ii = aNode->m_LeafList.begin();
ii != aNode->m_LeafList.end();
++ii )
{
const COBJECT2D *obj = static_cast<const COBJECT2D *>(*ii);
if( obj->Intersects( aBBox ) )
aOutList.push_back( obj );
}
}
else
{
wxASSERT( aNode->m_Children[0] != NULL );
wxASSERT( aNode->m_Children[1] != NULL );
// Node
recursiveGetListObjectsIntersects( aNode->m_Children[0], aBBox, aOutList );
recursiveGetListObjectsIntersects( aNode->m_Children[1], aBBox, aOutList );
}
}
}

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -37,14 +37,14 @@ typedef std::list<COBJECT2D *> LIST_OBJECT2D;
typedef std::list<const COBJECT2D *> CONST_LIST_OBJECT2D;
class GLM_ALIGN(CLASS_ALIGNMENT) CGENERICCONTAINER2D
class CGENERICCONTAINER2D
{
protected:
CBBOX2D m_bbox;
LIST_OBJECT2D m_objects;
public:
CGENERICCONTAINER2D( OBJECT2D_TYPE aObjType );
explicit CGENERICCONTAINER2D( OBJECT2D_TYPE aObjType );
virtual ~CGENERICCONTAINER2D();
@ -55,7 +55,7 @@ public:
m_objects.push_back( aObject );
m_bbox.Union( aObject->GetBBox() );
}
}// automatically releases the lock when lck goes out of scope.
}
void Clear();
@ -66,19 +66,21 @@ public:
* @param aBBox - a bbox to make the query
* @param aOutList - A list of objects that intersects the bbox
*/
virtual void GetListObjectsIntersects( const CBBOX2D & aBBox, CONST_LIST_OBJECT2D &aOutList ) const = 0;
virtual void GetListObjectsIntersects( const CBBOX2D & aBBox,
CONST_LIST_OBJECT2D &aOutList ) const = 0;
private:
};
class GLM_ALIGN(CLASS_ALIGNMENT) CCONTAINER2D : public CGENERICCONTAINER2D
class CCONTAINER2D : public CGENERICCONTAINER2D
{
public:
CCONTAINER2D();
// Imported from CGENERICCONTAINER2D
void GetListObjectsIntersects( const CBBOX2D & aBBox, CONST_LIST_OBJECT2D &aOutList ) const;
void GetListObjectsIntersects( const CBBOX2D & aBBox,
CONST_LIST_OBJECT2D &aOutList ) const;
};
@ -86,11 +88,13 @@ struct BVH_CONTAINER_NODE_2D
{
CBBOX2D m_BBox;
BVH_CONTAINER_NODE_2D *m_Children[2];
CONST_LIST_OBJECT2D m_LeafList; ///< Store the list of objects if that node is a Leaf
/// Store the list of objects if that node is a Leaf
CONST_LIST_OBJECT2D m_LeafList;
};
class GLM_ALIGN(CLASS_ALIGNMENT) CBVHCONTAINER2D : public CGENERICCONTAINER2D
class CBVHCONTAINER2D : public CGENERICCONTAINER2D
{
public:
CBVHCONTAINER2D();
@ -105,12 +109,15 @@ private:
void destroy();
void recursiveBuild_MIDDLE_SPLIT( BVH_CONTAINER_NODE_2D *aNodeParent );
void recursiveGetListObjectsIntersects( const BVH_CONTAINER_NODE_2D *aNode, const CBBOX2D & aBBox, CONST_LIST_OBJECT2D &aOutList ) const;
void recursiveGetListObjectsIntersects( const BVH_CONTAINER_NODE_2D *aNode,
const CBBOX2D & aBBox,
CONST_LIST_OBJECT2D &aOutList ) const;
public:
// Imported from CGENERICCONTAINER2D
void GetListObjectsIntersects( const CBBOX2D & aBBox, CONST_LIST_OBJECT2D &aOutList ) const;
void GetListObjectsIntersects( const CBBOX2D & aBBox,
CONST_LIST_OBJECT2D &aOutList ) const;
};
#endif // _CCONTAINER2D_H_

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,187 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file c3d_render_raytracing.h
* @brief
*/
#ifndef C3D_RENDER_RAYTRACING_H
#define C3D_RENDER_RAYTRACING_H
#include "../../common_ogl/openGL_includes.h"
#include "accelerators/ccontainer.h"
#include "accelerators/caccelerator.h"
#include "../c3d_render_base.h"
#include "clight.h"
#include "../cpostshader_ssao.h"
#include "cmaterial.h"
#include <plugins/3dapi/c3dmodel.h>
#include <map>
/// Vector of materials
typedef std::vector< CBLINN_PHONG_MATERIAL > MODEL_MATERIALS;
/// Maps a S3DMODEL pointer with a created CBLINN_PHONG_MATERIAL vector
typedef std::map< const S3DMODEL * , MODEL_MATERIALS > MAP_MODEL_MATERIALS;
typedef enum
{
RT_RENDER_STATE_TRACING = 0,
RT_RENDER_STATE_POST_PROCESS_SHADE,
RT_RENDER_STATE_POST_PROCESS_BLUR_AND_FINISH,
RT_RENDER_STATE_FINISH,
RT_RENDER_STATE_MAX
}RT_RENDER_STATE;
class C3D_RENDER_RAYTRACING : public C3D_RENDER_BASE
{
public:
explicit C3D_RENDER_RAYTRACING( CINFO3D_VISU &aSettings );
~C3D_RENDER_RAYTRACING();
// Imported from C3D_RENDER_BASE
void SetCurWindowSize( const wxSize &aSize );
bool Redraw(bool aIsMoving, REPORTER *aStatusTextReporter );
int GetWaitForEditingTimeOut();
private:
bool initializeOpenGL();
void initializeNewWindowSize();
void opengl_init_pbo();
void opengl_delete_pbo();
void reload( REPORTER *aStatusTextReporter );
void restart_render_state();
void rt_render_tracing( GLubyte *ptrPBO , REPORTER *aStatusTextReporter );
void rt_render_post_process_shade( GLubyte *ptrPBO , REPORTER *aStatusTextReporter );
void rt_render_post_process_blur_finish( GLubyte *ptrPBO , REPORTER *aStatusTextReporter );
void rt_render_trace_block( GLubyte *ptrPBO , signed int iBlock );
// Materials
void setupMaterials();
struct
{
CBLINN_PHONG_MATERIAL m_Paste;
CBLINN_PHONG_MATERIAL m_SilkS;
CBLINN_PHONG_MATERIAL m_SolderMask;
CBLINN_PHONG_MATERIAL m_EpoxyBoard;
CBLINN_PHONG_MATERIAL m_Copper;
CBLINN_PHONG_MATERIAL m_Floor;
}m_materials;
bool m_isPreview;
SFVEC3F shadeHit( const SFVEC3F &aBgColor,
const RAY &aRay,
HITINFO &aHitInfo,
bool aIsInsideObject,
unsigned int aRecursiveLevel ) const;
/// State used on quality render
RT_RENDER_STATE m_rt_render_state;
/// Time that the render starts
unsigned long int m_stats_start_rendering_time;
/// Save the number of blocks progress of the render
unsigned int m_nrBlocksRenderProgress;
CPOSTSHADER_SSAO m_postshader_ssao;
CLIGHTCONTAINER m_lights;
CDIRECTIONALLIGHT *m_camera_light;
bool m_opengl_support_vertex_buffer_object;
GLuint m_pboId;
GLuint m_pboDataSize;
CCONTAINER m_object_container;
/// This will store the list of created objects special for RT,
/// that will be clear in the end
CCONTAINER2D m_containerWithObjectsToDelete;
CCONTAINER2D *m_outlineBoard2dObjects;
CGENERICACCELERATOR *m_accelerator;
// Morton codes
/// used to see if the windows size changed
wxSize m_oldWindowsSize;
/// this encodes the Morton code positions
std::vector< SFVEC2UI > m_blockPositions;
/// this flags if a position was already processed (cleared each new render)
std::vector< bool > m_blockPositionsWasProcessed;
/// this encodes the Morton code positions (on fast preview mode)
std::vector< SFVEC2UI > m_blockPositionsFast;
SFVEC2UI m_realBufferSize;
SFVEC2UI m_fastPreviewModeSize;
HITINFO_PACKET *m_firstHitinfo;
SFVEC3F *m_shaderBuffer;
// Display Offset
unsigned int m_xoffset;
unsigned int m_yoffset;
// Statistics
unsigned int m_stats_converted_dummy_to_plane;
unsigned int m_stats_converted_roundsegment2d_to_roundsegment;
void create_3d_object_from( CCONTAINER &aDstContainer,
const COBJECT2D *aObject2D,
float aZMin, float aZMax,
const CMATERIAL *aMaterial,
const SFVEC3F &aObjColor );
void add_3D_vias_and_pads_to_container();
void insert3DViaHole( const VIA* aVia );
void insert3DPadHole( const D_PAD* aPad );
void load_3D_models();
void add_3D_models( const S3DMODEL *a3DModel,
const glm::mat4 &aModelMatrix );
/// Stores materials of the 3D models
MAP_MODEL_MATERIALS m_model_materials;
void initialize_block_positions();
void render( GLubyte *ptrPBO, REPORTER *aStatusTextReporter );
void render_preview( GLubyte *ptrPBO );
};
#endif // C3D_RENDER_RAYTRACING_H

View File

@ -0,0 +1,115 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file cfrustum.cpp
* @brief
*/
#include "cfrustum.h"
// !TODO: optimize wih SSE
//#if(GLM_ARCH != GLM_ARCH_PURE)
#if 0
#error not implemented
#else
#endif
void CFRUSTUM::GenerateFrustum( const RAY &topLeft,
const RAY &topRight,
const RAY &bottomLeft,
const RAY &bottomRight )
{
m_point[0] = topLeft.m_Origin;
m_point[1] = topRight.m_Origin;
m_point[2] = bottomLeft.m_Origin;
m_point[3] = topLeft.m_Origin;
if( topRight.m_Dir == topLeft.m_Dir )
{
// This will be the case if the camera is Ortho projection
m_normals[0] = glm::normalize( bottomLeft.m_Origin - topLeft.m_Origin ); // TOP
m_normals[1] = glm::normalize( topLeft.m_Origin - topRight.m_Origin ); // RIGHT
m_normals[2] = -m_normals[0]; // BOTTOM
m_normals[3] = -m_normals[1]; // LEFT
}
else
{
m_normals[0] = glm::cross( topRight.m_Dir, topLeft.m_Dir ); // TOP
m_normals[1] = glm::cross( bottomRight.m_Dir, topRight.m_Dir ); // RIGHT
m_normals[2] = glm::cross( bottomLeft.m_Dir, bottomRight.m_Dir ); // BOTTOM
m_normals[3] = glm::cross( topLeft.m_Dir, bottomLeft.m_Dir ); // LEFT
}
}
// There are multiple implementation of this algorithm on the web,
// this one was based on the one find in:
// https://github.com/nslo/raytracer/blob/2c2e0ff4bbb6082e07804ec7cf0b92673b98dcb1/src/raytracer/geom_utils.cpp#L66
// by Nathan Slobody and Adam Wright
// The frustum test is not exllude all the boxes,
// when a box is behind and if it is intersecting the planes it will not be discardly but should.
bool CFRUSTUM::Intersect( const CBBOX &aBBox ) const
{
const SFVEC3F box[8] = { aBBox.Min(),
aBBox.Max(),
SFVEC3F(aBBox.Min().x, aBBox.Min().y, aBBox.Max().z),
SFVEC3F(aBBox.Min().x, aBBox.Max().y, aBBox.Min().z),
SFVEC3F(aBBox.Min().x, aBBox.Max().y, aBBox.Max().z),
SFVEC3F(aBBox.Max().x, aBBox.Min().y, aBBox.Min().z),
SFVEC3F(aBBox.Max().x, aBBox.Min().y, aBBox.Max().z),
SFVEC3F(aBBox.Max().x, aBBox.Max().y, aBBox.Min().z) };
// test each plane of frustum individually; if the point is on the wrong
// side of the plane, the box is outside the frustum and we can exit
int out_side = 0;
for( unsigned int i = 0; i < 4; ++i )
{
const SFVEC3F &pointPlane = m_point[i];
const SFVEC3F &normalPlane = m_normals[i];
for( unsigned int j = 0; j < 8; ++j )
{
const SFVEC3F OP = pointPlane - box[j];
const float dot = glm::dot( OP, normalPlane );
if( dot < 0.0f )
{
out_side++;
break;
}
}
}
if( out_side == 4 )
return true;
return false;
}

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -24,13 +24,12 @@
/**
* @file cfrustum.h
* @brief
* @brief implements a frustum that is used to test ray pack tests
*/
#ifndef _CFRUSTUM_H_
#define _CFRUSTUM_H_
#include "plugins/3dapi/xv3d_types.h"
#include "shapes3D/cbbox.h"
#include "ray.h"
@ -39,13 +38,32 @@
#if 0
#error not implemented
#else
GLM_ALIGNED_STRUCT(CLASS_ALIGNMENT) CFRUSTUM
struct CFRUSTUM
{
SFVEC3F m_normals[4];
SFVEC3F m_point[4];
void GenerateFrustum( const RAY &topLeft, const RAY &topRight, const RAY &bottomLeft, const RAY &bottomRight );
public:
/**
* @brief GenerateFrustum
* @param topLeft
* @param topRight
* @param bottomLeft
* @param bottomRight
*/
void GenerateFrustum( const RAY &topLeft,
const RAY &topRight,
const RAY &bottomLeft,
const RAY &bottomRight );
/**
* @brief Intersect - Intersects a bbox with this frustum
* @param aBBox: a bbox to test
* @return true if the bbox intersects this frustum
*/
bool Intersect( const CBBOX &aBBox ) const;
private:
SFVEC3F m_normals[4];
SFVEC3F m_point[4];
};
#endif

View File

@ -0,0 +1,203 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file clight.h
* @brief declare and implement light types classes
*/
#ifndef _CLIGHT_H_
#define _CLIGHT_H_
#include "ray.h"
#include "hitinfo.h"
/// A base light class to derive to implement other light classes
class CLIGHT
{
public:
CLIGHT() { m_castShadow = true; }
virtual ~CLIGHT() {}
/**
* @brief GetLightParameters - Get parameters from this light
* @param aHitPoint: input hit position
* @param aOutVectorToLight: a vector that points from the hit
* position in direction to the light
* @param aOutLightColor: the color of this light
* @param aOutDistance: the distance from the point to the light
*/
virtual void GetLightParameters( const SFVEC3F &aHitPoint,
SFVEC3F &aOutVectorToLight,
SFVEC3F &aOutLightColor,
float &aOutDistance ) const = 0;
void SetCastShadows( bool aCastShadow ) { m_castShadow = aCastShadow; }
bool GetCastShadows() const { return m_castShadow; }
protected:
bool m_castShadow;
};
/// Point light based on:
/// http://ogldev.atspace.co.uk/www/tutorial20/tutorial20.html
class CPOINTLIGHT : public CLIGHT
{
public:
CPOINTLIGHT( const SFVEC3F &aPos, const SFVEC3F &aColor )
{
m_position = aPos;
m_color = aColor;
m_att_constant = 1.0f;
m_att_linear = 0.5f;
m_att_exp = 0.25f;
m_castShadow = true;
}
// Imported functions from CLIGHT
void GetLightParameters( const SFVEC3F &aHitPoint,
SFVEC3F &aOutVectorToLight,
SFVEC3F &aOutLightColor,
float &aOutDistance ) const
{
const SFVEC3F vectorLight = m_position - aHitPoint;
aOutDistance = glm::length( vectorLight );
aOutVectorToLight = vectorLight / aOutDistance; // normalize
float att = 1.0f / ( m_att_constant +
m_att_linear * aOutDistance +
m_att_exp * aOutDistance * aOutDistance );
if( att <= 0.0f )
aOutLightColor = SFVEC3F( 0.0f, 0.0f, 0.0f );
else
aOutLightColor = m_color * att;
}
private:
SFVEC3F m_position;
SFVEC3F m_color;
float m_att_constant;
float m_att_linear;
float m_att_exp;
};
/// Directional light - a light based only on a direction vector
class CDIRECTIONALLIGHT : public CLIGHT
{
public:
CDIRECTIONALLIGHT( const SFVEC3F &aDir, const SFVEC3F &aColor )
{
// Invert light direction and make sure it is normalized
m_inv_direction = glm::normalize( -aDir );
m_color = aColor;
m_castShadow = true; // Set as default to cast shadows
}
/**
* @brief SetDirection - Set directional light orientation
* @param aDir: vector from the light
*/
void SetDirection( const SFVEC3F &aDir ) { m_inv_direction = -aDir; }
// Imported functions from CLIGHT
void GetLightParameters( const SFVEC3F &aHitPoint,
SFVEC3F &aOutVectorToLight,
SFVEC3F &aOutLightColor,
float &aOutDistance ) const
{
(void)aHitPoint; // unused
aOutVectorToLight = m_inv_direction;
aOutDistance = std::numeric_limits<float>::infinity();
aOutLightColor = m_color;
}
private:
SFVEC3F m_inv_direction; ///< oposite direction of the light
SFVEC3F m_color; ///< light color
};
typedef std::list< CLIGHT * > LIST_LIGHT;
/// A light contariner. It will add lights and remove it in the end
class CLIGHTCONTAINER
{
public:
CLIGHTCONTAINER() {}
~CLIGHTCONTAINER() { Clear(); }
/**
* @brief Clear - Remove all lights from the container
*/
void Clear()
{
if( !m_lights.empty() )
{
for( LIST_LIGHT::iterator ii = m_lights.begin();
ii != m_lights.end();
--ii )
{
delete *ii;
*ii = NULL;
}
m_lights.clear();
}
}
/**
* @brief Add - Add a light to the container
* @param aLight
*/
void Add( CLIGHT *aLight )
{
if( aLight )
m_lights.push_back( aLight );
}
/**
* @brief GetList - get light list of this container
* @return a list of lights
*/
const LIST_LIGHT &GetList() const { return m_lights; }
private:
LIST_LIGHT m_lights; ///< list of lights
};
#endif // _CLIGHT_H_

View File

@ -0,0 +1,119 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file cmaterial.cpp
* @brief
*/
#include "cmaterial.h"
#include <wx/debug.h>
CMATERIAL::CMATERIAL()
{
m_ambientColor = SFVEC3F( 0.2f, 0.2f, 0.2f );
m_emissiveColor = SFVEC3F( 0.0f, 0.0f, 0.0f );
m_specularColor = SFVEC3F( 1.0f, 1.0f, 1.0f );
m_shinness = 50.2f;
m_transparency = 0.0f; // completely opaque
m_cast_shadows = true;
m_reflection = 0.0f;
}
CMATERIAL::CMATERIAL( const SFVEC3F &aAmbient,
const SFVEC3F &aEmissive,
const SFVEC3F &aSpecular,
float aShinness,
float aTransparency,
float aReflection )
{
wxASSERT( aReflection >= 0.0f );
wxASSERT( aReflection <= 1.0f );
wxASSERT( aTransparency >= 0.0f );
wxASSERT( aTransparency <= 1.0f );
wxASSERT( aShinness >= 0.0f );
wxASSERT( aShinness <= 180.0f );
m_ambientColor = aAmbient;
m_emissiveColor = aEmissive;
m_specularColor = aSpecular;
m_shinness = aShinness;
m_transparency = aTransparency;
m_reflection = aReflection;
m_cast_shadows = true;
}
// This may be a good value if based on nr of lights
// that contribute to the illumination of that point
#define AMBIENT_FACTOR 0.160f
#define SPECULAR_FACTOR 1.000f
// https://en.wikipedia.org/wiki/Blinn%E2%80%93Phong_shading_model
SFVEC3F CBLINN_PHONG_MATERIAL::Shade( const RAY &aRay,
const HITINFO &aHitInfo,
float NdotL,
const SFVEC3F &aDiffuseObjColor,
const SFVEC3F &aDirToLight,
const SFVEC3F &aLightColor,
float aShadowAttenuationFactor ) const
{
wxASSERT( NdotL >= FLT_EPSILON );
//const float ambientFactor = AMBIENT_FACTOR;
// This is a hack to get some kind of fake ambient illumination
// There is no logic behind this, just pure artistic experimentation
const float ambientFactor = glm::max( ( (1.0f - NdotL) /** (1.0f - NdotL)*/ ) *
( AMBIENT_FACTOR + AMBIENT_FACTOR ),
AMBIENT_FACTOR );
if( aShadowAttenuationFactor > FLT_EPSILON )
{
// Calculate the diffuse light factoring in light color,
// power and the attenuation
const SFVEC3F diffuse = NdotL * aLightColor;
// Calculate the half vector between the light vector and the view vector.
const SFVEC3F H = glm::normalize( aDirToLight - aRay.m_Dir );
//Intensity of the specular light
const float NdotH = glm::dot( H, aHitInfo.m_HitNormal );
const float intensitySpecular = glm::pow( glm::max( NdotH, 0.0f ),
m_shinness );
return m_ambientColor * ambientFactor +
aShadowAttenuationFactor * ( diffuse * aDiffuseObjColor +
SPECULAR_FACTOR *
aLightColor *
intensitySpecular *
m_specularColor );
}
return m_ambientColor * ambientFactor;
}

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -33,37 +33,57 @@
#include "ray.h"
#include "hitinfo.h"
///
class GLM_ALIGN(CLASS_ALIGNMENT) CMATERIAL
/// A base material class that can be used to derive a material implementation
class CMATERIAL
{
public:
CMATERIAL();
CMATERIAL( const SFVEC3F &aAmbient, const SFVEC3F &aEmissive, const SFVEC3F &aSpecular, float aShinness, float aTransparency );
CMATERIAL( const SFVEC3F &aAmbient,
const SFVEC3F &aEmissive,
const SFVEC3F &aSpecular,
float aShinness,
float aTransparency,
float aReflection );
const SFVEC3F &GetAmbientColor() const { return m_ambientColor; }
const SFVEC3F &GetAmbientColor() const { return m_ambientColor; }
const SFVEC3F &GetEmissiveColor() const { return m_emissiveColor; }
const SFVEC3F &GetSpecularColor() const { return m_specularColor; }
float GetShinness() const { return m_shinness; }
float GetShinness() const { return m_shinness; }
float GetTransparency() const { return m_transparency; }
float GetReflection() const { return m_reflection; }
/**
* @brief SetCastShadows - Set if the material can receive shadows
* @param aCastShadows - true yes it can, false not it cannot
*/
void SetCastShadows( bool aCastShadows ) { m_cast_shadows = aCastShadows; }
void SetCastShadows( bool aCastShadows ) { m_cast_shadows = aCastShadows; }
bool GetCastShadows() const { return m_cast_shadows; }
virtual SFVEC3F Shade( const RAY &aRay, const HITINFO &aHitInfo, float NdotL, const SFVEC3F &aDiffuseObjColor, const SFVEC3F &aDirToLight, const SFVEC3F &aLightColor, bool aIsInShadow ) const = 0;
/**
* @brief Shade - Shades an intersection point
* @param aRay: the camera ray that hits the object
* @param aHitInfo: the hit information
* @param NdotL: the dot product between Normal and Light
* @param aDiffuseObjColor: diffuse object color
* @param aDirToLight: a vector of the incident light direction
* @param aLightColor: the light color
* @param aShadowAttenuationFactor 0.0f total in shadow, 1.0f completely not in shadow
* @return the resultant color
*/
virtual SFVEC3F Shade( const RAY &aRay,
const HITINFO &aHitInfo,
float NdotL,
const SFVEC3F &aDiffuseObjColor,
const SFVEC3F &aDirToLight,
const SFVEC3F &aLightColor,
float aShadowAttenuationFactor ) const = 0;
/*
virtual SFVEC3F GetReflect(Vec3f point){ return reflectiveColor;}
virtual Vec3f GetTrans(Vec3f point){ return transparentColor;}
virtual float getIndexOfRefrac(Vec3f point){ return indexOfRefraction;}
virtual bool isReflect(Vec3f point){return ((reflectiveColor.x()>0)||(reflectiveColor.y()>0)||(reflectiveColor.z()>0));}
virtual bool isTransparent(Vec3f point){return ((transparentColor.x()>0)||(transparentColor.y()>0)||(transparentColor.z()>0));}
*/
protected:
SFVEC3F m_ambientColor;
// NOTE: we will not use diffuse color material here,
// because it will be stored in object, since there are objects (i.e: triangles)
// that can have per vertex color
@ -72,12 +92,14 @@ protected:
SFVEC3F m_specularColor;
float m_shinness;
float m_transparency; ///< 1.0 is completely transparent, 0.0 completely opaque
float m_reflection; ///< 1.0 completely reflective, 0.0 no reflective
bool m_cast_shadows; ///< true if this object will block the light
};
/// Blinn Phong based material
/// https://en.wikipedia.org/wiki/Blinn%E2%80%93Phong_shading_model
class GLM_ALIGN(CLASS_ALIGNMENT) CBLINN_PHONG_MATERIAL : public CMATERIAL
class CBLINN_PHONG_MATERIAL : public CMATERIAL
{
public:
CBLINN_PHONG_MATERIAL() : CMATERIAL() {}
@ -86,10 +108,22 @@ public:
const SFVEC3F &aEmissive,
const SFVEC3F &aSpecular,
float aShinness,
float aTransparency ) :
CMATERIAL( aAmbient, aEmissive, aSpecular, aShinness, aTransparency ) {}
float aTransparency,
float aReflection ) : CMATERIAL( aAmbient,
aEmissive,
aSpecular,
aShinness,
aTransparency,
aReflection ) {}
SFVEC3F Shade( const RAY &aRay, const HITINFO &aHitInfo, float NdotL, const SFVEC3F &aDiffuseObjColor, const SFVEC3F &aDirToLight, const SFVEC3F &aLightColor, bool aIsInShadow ) const;
// Imported from CMATERIAL
SFVEC3F Shade( const RAY &aRay,
const HITINFO &aHitInfo,
float NdotL,
const SFVEC3F &aDiffuseObjColor,
const SFVEC3F &aDirToLight,
const SFVEC3F &aLightColor,
float aShadowAttenuationFactor ) const;
};
#endif // _CMATERIAL_H_

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -30,7 +30,6 @@
#ifndef _HITINFO_H_
#define _HITINFO_H_
#include "plugins/3dapi/xv3d_types.h"
#include "raypacket.h"
//#define RAYTRACING_RAY_STATISTICS
@ -38,15 +37,16 @@
class COBJECT;
/// Stores the hit information of a ray with a point on the surface of a object
GLM_ALIGNED_STRUCT(CLASS_ALIGNMENT) HITINFO
struct HITINFO
{
SFVEC3F m_HitNormal; ///< (12) normal at the hit point
float m_tHit; ///< ( 4) distance
const COBJECT *pHitObject; ///< ( 4) Object that was hitted
SFVEC2F m_UV; ///< ( 8) 2-D texture coordinates
unsigned int m_acc_node_info; ///< ( 4) The acc stores here the node that it hits
unsigned int m_acc_node_info; ///< ( 4) The acc should store here information (Ex: the node that it hits)
float m_ShadowFactor; ///< ( 4) Shadow attenuation (1.0 no shadow, 0.0f darkness)
#ifdef RAYTRACING_RAY_STATISTICS
// Statistics
@ -55,11 +55,11 @@ GLM_ALIGNED_STRUCT(CLASS_ALIGNMENT) HITINFO
#endif
};
GLM_ALIGNED_STRUCT(CLASS_ALIGNMENT) HITINFO_PACKET
struct HITINFO_PACKET
{
bool m_hitresult;
HITINFO m_HitInfo;
};
#endif // _HITINFO_H_

View File

@ -0,0 +1,125 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file mortoncodes.cpp
* @brief Implementes Morton Codes base on the implementation of Fabian ryg Giesen
* https://fgiesen.wordpress.com/2009/12/13/decoding-morton-codes/
*/
#include "mortoncodes.h"
// "Insert" a 0 bit after each of the 16 low bits of x
uint32_t Part1By1( uint32_t x )
{
x &= 0x0000ffff; // x = ---- ---- ---- ---- fedc ba98 7654 3210
x = (x ^ (x << 8)) & 0x00ff00ff; // x = ---- ---- fedc ba98 ---- ---- 7654 3210
x = (x ^ (x << 4)) & 0x0f0f0f0f; // x = ---- fedc ---- ba98 ---- 7654 ---- 3210
x = (x ^ (x << 2)) & 0x33333333; // x = --fe --dc --ba --98 --76 --54 --32 --10
x = (x ^ (x << 1)) & 0x55555555; // x = -f-e -d-c -b-a -9-8 -7-6 -5-4 -3-2 -1-0
return x;
}
// "Insert" two 0 bits after each of the 10 low bits of x
uint32_t Part1By2( uint32_t x )
{
x &= 0x000003ff; // x = ---- ---- ---- ---- ---- --98 7654 3210
x = (x ^ (x << 16)) & 0xff0000ff; // x = ---- --98 ---- ---- ---- ---- 7654 3210
x = (x ^ (x << 8)) & 0x0300f00f; // x = ---- --98 ---- ---- 7654 ---- ---- 3210
x = (x ^ (x << 4)) & 0x030c30c3; // x = ---- --98 ---- 76-- --54 ---- 32-- --10
x = (x ^ (x << 2)) & 0x09249249; // x = ---- 9--8 --7- -6-- 5--4 --3- -2-- 1--0
return x;
}
// Inverse of Part1By1 - "delete" all odd-indexed bits
uint32_t Compact1By1( uint32_t x )
{
x &= 0x55555555; // x = -f-e -d-c -b-a -9-8 -7-6 -5-4 -3-2 -1-0
x = (x ^ (x >> 1)) & 0x33333333; // x = --fe --dc --ba --98 --76 --54 --32 --10
x = (x ^ (x >> 2)) & 0x0f0f0f0f; // x = ---- fedc ---- ba98 ---- 7654 ---- 3210
x = (x ^ (x >> 4)) & 0x00ff00ff; // x = ---- ---- fedc ba98 ---- ---- 7654 3210
x = (x ^ (x >> 8)) & 0x0000ffff; // x = ---- ---- ---- ---- fedc ba98 7654 3210
return x;
}
// Inverse of Part1By2 - "delete" all bits not at positions divisible by 3
uint32_t Compact1By2( uint32_t x )
{
x &= 0x09249249; // x = ---- 9--8 --7- -6-- 5--4 --3- -2-- 1--0
x = (x ^ (x >> 2)) & 0x030c30c3; // x = ---- --98 ---- 76-- --54 ---- 32-- --10
x = (x ^ (x >> 4)) & 0x0300f00f; // x = ---- --98 ---- ---- 7654 ---- ---- 3210
x = (x ^ (x >> 8)) & 0xff0000ff; // x = ---- --98 ---- ---- ---- ---- 7654 3210
x = (x ^ (x >> 16)) & 0x000003ff; // x = ---- ---- ---- ---- ---- --98 7654 3210
return x;
}
uint32_t EncodeMorton2( uint32_t x, uint32_t y )
{
return ( Part1By1( y ) << 1 ) + Part1By1( x );
}
uint32_t EncodeMorton3( uint32_t x, uint32_t y, uint32_t z )
{
return ( Part1By2( z ) << 2 ) + ( Part1By2( y ) << 1 ) + Part1By2( x );
}
uint32_t DecodeMorton2X( uint32_t code )
{
return Compact1By1( code >> 0 );
}
uint32_t DecodeMorton2Y( uint32_t code )
{
return Compact1By1( code >> 1 );
}
uint32_t DecodeMorton3X( uint32_t code )
{
return Compact1By2( code >> 0 );
}
uint32_t DecodeMorton3Y( uint32_t code )
{
return Compact1By2( code >> 1 );
}
uint32_t DecodeMorton3Z( uint32_t code )
{
return Compact1By2( code >> 2 );
}

View File

@ -0,0 +1,47 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file mortoncodes.h
* @brief Implementes Morton Codes
* https://fgiesen.wordpress.com/2009/12/13/decoding-morton-codes/
* http://www.forceflow.be/2013/10/07/morton-encodingdecoding-through-bit-interleaving-implementations/
*/
#ifndef _MORTONCODES_H_
#define _MORTONCODES_H_
#include <stdint.h>
uint32_t EncodeMorton2( uint32_t x, uint32_t y );
uint32_t EncodeMorton3( uint32_t x, uint32_t y, uint32_t z );
uint32_t DecodeMorton2X( uint32_t code );
uint32_t DecodeMorton2Y( uint32_t code );
uint32_t DecodeMorton3X( uint32_t code );
uint32_t DecodeMorton3Y( uint32_t code );
uint32_t DecodeMorton3Z( uint32_t code );
#endif // _MORTONCODES_H_

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -29,7 +29,7 @@
#include "ray.h"
#include "3d_math/3d_fastmath.h"
#include "../../3d_fastmath.h"
#include <stdio.h>
#include <wx/debug.h>
@ -189,7 +189,9 @@ void RAY::Init( const SFVEC3F& o, const SFVEC3F& d )
bool IntersectSegment( const SFVEC2F &aStartA, const SFVEC2F &aEnd_minus_startA,
const SFVEC2F &aStartB, const SFVEC2F &aEnd_minus_startB )
{
float rxs = aEnd_minus_startA.x * aEnd_minus_startB.y - aEnd_minus_startA.y * aEnd_minus_startB.x;
float rxs = aEnd_minus_startA.x *
aEnd_minus_startB.y - aEnd_minus_startA.y *
aEnd_minus_startB.x;
if( fabs(rxs) > glm::epsilon<float>() )
{
@ -213,6 +215,7 @@ bool IntersectSegment( const SFVEC2F &aStartA, const SFVEC2F &aEnd_minus_startA,
return false;
}
// !TODO: not tested
bool RAY::IntersectSphere( const SFVEC3F &aCenter, float aRadius, float &aOutT0, float &aOutT1 ) const
{
@ -271,6 +274,7 @@ bool RAY::IntersectSphere( const SFVEC3F &aCenter, float aRadius, float &aOutT0,
return true;
}
RAYSEG2D::RAYSEG2D( const SFVEC2F& s, const SFVEC2F& e )
{
m_Start = s;
@ -290,17 +294,21 @@ RAYSEG2D::RAYSEG2D( const SFVEC2F& s, const SFVEC2F& e )
}
bool RAYSEG2D::IntersectSegment( const SFVEC2F &aStart, const SFVEC2F &aEnd_minus_start, float *aOutT ) const
bool RAYSEG2D::IntersectSegment( const SFVEC2F &aStart,
const SFVEC2F &aEnd_minus_start,
float *aOutT ) const
{
float rxs = m_End_minus_start.x * aEnd_minus_start.y - m_End_minus_start.y * aEnd_minus_start.x;
float rxs = m_End_minus_start.x *
aEnd_minus_start.y - m_End_minus_start.y *
aEnd_minus_start.x;
if( fabs(rxs) > glm::epsilon<float>() )
if( fabs( rxs ) > glm::epsilon<float>() )
{
float inv_rxs = 1.0f / rxs;
const float inv_rxs = 1.0f / rxs;
SFVEC2F pq = aStart - m_Start;
const SFVEC2F pq = aStart - m_Start;
float t = (pq.x * aEnd_minus_start.y - pq.y * aEnd_minus_start.x) * inv_rxs;
const float t = (pq.x * aEnd_minus_start.y - pq.y * aEnd_minus_start.x) * inv_rxs;
if( (t < 0.0f) || (t > 1.0f) )
return false;
@ -324,7 +332,7 @@ float RAYSEG2D::DistanceToPointSquared( const SFVEC2F &aPoint ) const
{
SFVEC2F p = aPoint - m_Start;
float c1 = glm::dot( p, m_End_minus_start );
const float c1 = glm::dot( p, m_End_minus_start );
if( c1 < FLT_EPSILON )
return glm::dot( p, p );
@ -333,8 +341,9 @@ float RAYSEG2D::DistanceToPointSquared( const SFVEC2F &aPoint ) const
p = aPoint - m_End;
else
{
float b = c1 / m_DOT_End_minus_start;
SFVEC2F pb = m_Start + m_End_minus_start * b;
const float b = c1 / m_DOT_End_minus_start;
const SFVEC2F pb = m_Start + m_End_minus_start * b;
p = aPoint - pb;
}
@ -342,21 +351,26 @@ float RAYSEG2D::DistanceToPointSquared( const SFVEC2F &aPoint ) const
}
bool RAYSEG2D::IntersectCircle( const SFVEC2F &aCenter, float aRadius, float *aOutT0, float *aOutT1, SFVEC2F *aOutNormalT0, SFVEC2F *aOutNormalT1 ) const
bool RAYSEG2D::IntersectCircle( const SFVEC2F &aCenter,
float aRadius,
float *aOutT0,
float *aOutT1,
SFVEC2F *aOutNormalT0,
SFVEC2F *aOutNormalT1 ) const
{
// This code used directly from Steve Marschner's CS667 framework
// http://cs665pd.googlecode.com/svn/trunk/photon/sphere.cpp
// Compute some factors used in computation
float qx = m_Start.x - aCenter.x;
float qy = m_Start.y - aCenter.y;
const float qx = m_Start.x - aCenter.x;
const float qy = m_Start.y - aCenter.y;
float qd = qx * m_Dir.x + qy * m_Dir.y;
float qq = qx * qx + qy * qy;
const float qd = qx * m_Dir.x + qy * m_Dir.y;
const float qq = qx * qx + qy * qy;
// solving the quadratic equation for t at the pts of intersection
// dd*t^2 + (2*qd)*t + (qq-r^2) = 0
float discriminantsqr = (qd * qd - (qq - aRadius * aRadius));
const float discriminantsqr = (qd * qd - (qq - aRadius * aRadius));
// If the discriminant is less than zero, there is no intersection
if( discriminantsqr < FLT_EPSILON )
@ -365,9 +379,9 @@ bool RAYSEG2D::IntersectCircle( const SFVEC2F &aCenter, float aRadius, float *aO
// Otherwise check and make sure that the intersections occur on the ray (t
// > 0) and return the closer one
float discriminant = sqrt(discriminantsqr);
float t1 = (-qd - discriminant);
float t2 = (-qd + discriminant);
const float discriminant = sqrt( discriminantsqr );
const float t1 = (-qd - discriminant);
const float t2 = (-qd + discriminant);
if( (( t1 < 0.0f ) || ( t1 > m_Length ) ) &&
(( t2 < 0.0f ) || ( t2 > m_Length ) ) )

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -30,7 +30,7 @@
#ifndef _RAY_H_
#define _RAY_H_
#include "plugins/3dapi/xv3d_types.h"
#include <plugins/3dapi/xv3d_types.h>
enum RAY_CLASSIFICATION
@ -40,7 +40,7 @@ enum RAY_CLASSIFICATION
};
GLM_ALIGNED_STRUCT(CLASS_ALIGNMENT) RAY
struct RAY
{
SFVEC3F m_Origin;
unsigned int rayID; ///< unique ray ID
@ -57,16 +57,21 @@ GLM_ALIGNED_STRUCT(CLASS_ALIGNMENT) RAY
void Init( const SFVEC3F& o, const SFVEC3F& d );
bool IntersectSphere( const SFVEC3F &aCenter, float aRadius, float &aOutT0, float &aOutT1 ) const;
bool IntersectSphere( const SFVEC3F &aCenter,
float aRadius,
float &aOutT0,
float &aOutT1 ) const;
SFVEC3F at( float t ) const { return m_Origin + m_Dir * t; }
SFVEC2F at2D( float t ) const { return SFVEC2F( m_Origin.x + m_Dir.x * t, m_Origin.y + m_Dir.y * t ); }
SFVEC2F at2D( float t ) const {
return SFVEC2F( m_Origin.x + m_Dir.x * t, m_Origin.y + m_Dir.y * t ); }
void debug() const;
};
GLM_ALIGNED_STRUCT(CLASS_ALIGNMENT) RAY2D
struct RAY2D
{
SFVEC2F m_Origin;
SFVEC2F m_Dir;
@ -78,7 +83,7 @@ GLM_ALIGNED_STRUCT(CLASS_ALIGNMENT) RAY2D
};
GLM_ALIGNED_STRUCT(CLASS_ALIGNMENT) RAYSEG2D
struct RAYSEG2D
{
SFVEC2F m_Start;
SFVEC2F m_End;
@ -90,10 +95,19 @@ GLM_ALIGNED_STRUCT(CLASS_ALIGNMENT) RAYSEG2D
RAYSEG2D( const SFVEC2F& s, const SFVEC2F& e );
bool IntersectSegment( const SFVEC2F &aStart, const SFVEC2F &aEnd_minus_start, float *aOutT ) const;
bool IntersectCircle( const SFVEC2F &aCenter, float aRadius, float *aOutT0, float *aOutT1, SFVEC2F *aOutNormalT0, SFVEC2F *aOutNormalT1 ) const;
bool IntersectSegment( const SFVEC2F &aStart,
const SFVEC2F &aEnd_minus_start,
float *aOutT ) const;
bool IntersectCircle( const SFVEC2F &aCenter,
float aRadius,
float *aOutT0,
float *aOutT1,
SFVEC2F *aOutNormalT0,
SFVEC2F *aOutNormalT1 ) const;
float DistanceToPointSquared( const SFVEC2F &aPoint ) const;
/**
* Function atNormalized - returns the position at t
* t - value 0.0 ... 1.0
@ -109,7 +123,7 @@ bool IntersectSegment( const SFVEC2F &aStartA, const SFVEC2F &aEnd_minus_startA,
#if(GLM_ARCH != GLM_ARCH_PURE)
/*
GLM_ALIGNED_STRUCT(CLASS_ALIGNMENT) RAY4
struct RAY4
{
glm::simdVec4 m_orgX; ///< x coordinate of ray origin
glm::simdVec4 m_orgy; ///< y coordinate of ray origin

View File

@ -0,0 +1,131 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file raypacket.cpp
* @brief
*/
#include "raypacket.h"
#include "../3d_fastmath.h"
#include <wx/debug.h>
RAYPACKET::RAYPACKET( const CCAMERA &aCamera, const SFVEC2I &aWindowsPosition )
{
unsigned int i = 0;
for( unsigned int y = 0; y < RAYPACKET_DIM; ++y )
{
for( unsigned int x = 0; x < RAYPACKET_DIM; ++x )
{
SFVEC3F rayOrigin;
SFVEC3F rayDir;
aCamera.MakeRay( SFVEC2I( aWindowsPosition.x + x,
aWindowsPosition.y + y ),
rayOrigin, rayDir );
m_ray[i].Init( rayOrigin, rayDir );
i++;
}
}
wxASSERT( i == RAYPACKET_RAYS_PER_PACKET );
m_Frustum.GenerateFrustum(
m_ray[ 0 * RAYPACKET_DIM + 0 ],
m_ray[ 0 * RAYPACKET_DIM + (RAYPACKET_DIM - 1) ],
m_ray[ (RAYPACKET_DIM - 1) * RAYPACKET_DIM + 0 ],
m_ray[ (RAYPACKET_DIM - 1) * RAYPACKET_DIM + (RAYPACKET_DIM - 1) ] );
}
RAYPACKET::RAYPACKET( const CCAMERA &aCamera,
const SFVEC2I &aWindowsPosition,
const SFVEC3F &aDirectionDisplacementFactor )
{
unsigned int i = 0;
for( unsigned int y = 0; y < RAYPACKET_DIM; ++y )
for( unsigned int x = 0; x < RAYPACKET_DIM; ++x )
{
SFVEC3F rayOrigin;
SFVEC3F rayDir;
aCamera.MakeRay( SFVEC2I( aWindowsPosition.x + x,
aWindowsPosition.y + y ),
rayOrigin, rayDir );
const SFVEC3F randVector = SFVEC3F( Fast_RandFloat() * aDirectionDisplacementFactor.x,
Fast_RandFloat() * aDirectionDisplacementFactor.y,
Fast_RandFloat() * aDirectionDisplacementFactor.z );
m_ray[i].Init( rayOrigin,
glm::normalize( rayDir + randVector ) );
i++;
}
wxASSERT( i == RAYPACKET_RAYS_PER_PACKET );
m_Frustum.GenerateFrustum( m_ray[ 0 * RAYPACKET_DIM + 0 ],
m_ray[ 0 * RAYPACKET_DIM + (RAYPACKET_DIM - 1) ],
m_ray[ (RAYPACKET_DIM - 1) * RAYPACKET_DIM + 0 ],
m_ray[ (RAYPACKET_DIM - 1) * RAYPACKET_DIM + (RAYPACKET_DIM - 1) ] );
}
RAYPACKET::RAYPACKET( const CCAMERA &aCamera,
const SFVEC2I &aWindowsPosition,
unsigned int aPixelMultiple )
{
unsigned int i = 0;
for( unsigned int y = 0; y < RAYPACKET_DIM; y++ )
{
for( unsigned int x = 0; x < RAYPACKET_DIM; x++ )
{
SFVEC3F rayOrigin;
SFVEC3F rayDir;
aCamera.MakeRay( SFVEC2I( aWindowsPosition.x + x * aPixelMultiple,
aWindowsPosition.y + y * aPixelMultiple),
rayOrigin, rayDir );
m_ray[i].Init( rayOrigin, rayDir );
i++;
}
}
wxASSERT( i == RAYPACKET_RAYS_PER_PACKET );
m_Frustum.GenerateFrustum( m_ray[ 0 * RAYPACKET_DIM + 0 ],
m_ray[ 0 * RAYPACKET_DIM + (RAYPACKET_DIM - 1) ],
m_ray[ (RAYPACKET_DIM - 1) * RAYPACKET_DIM + 0 ],
m_ray[ (RAYPACKET_DIM - 1) * RAYPACKET_DIM + (RAYPACKET_DIM - 1) ] );
}

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -40,13 +40,21 @@
#define RAYPACKET_RAYS_PER_PACKET (RAYPACKET_DIM * RAYPACKET_DIM)
GLM_ALIGNED_STRUCT(CLASS_ALIGNMENT) RAYPACKET
struct RAYPACKET
{
CFRUSTUM m_Frustum;
RAY m_ray[RAYPACKET_RAYS_PER_PACKET];
RAYPACKET( const CCAMERA &aCamera, const SFVEC2I &aWindowsPosition );
RAYPACKET( const CCAMERA &aCamera, const SFVEC2I &aWindowsPosition, unsigned int aPixelMultiple );
RAYPACKET( const CCAMERA &aCamera,
const SFVEC2I &aWindowsPosition );
RAYPACKET( const CCAMERA &aCamera,
const SFVEC2I &aWindowsPosition,
const SFVEC3F &aDirectionDisplacementFactor );
RAYPACKET( const CCAMERA &aCamera,
const SFVEC2I &aWindowsPosition,
unsigned int aPixelMultiple );
};

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@gmail.com>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -27,7 +27,7 @@
* @brief Bounding Box class implementation
*/
#include "3d_math/3d_fastmath.h"
#include "3d_fastmath.h"
#include "cbbox2d.h"
#include <fctsys.h>
@ -106,11 +106,13 @@ void CBBOX2D::Union( const SFVEC2F &aPoint )
void CBBOX2D::Union( const CBBOX2D &aBBox )
{
// get the minimun value between the added bounding box and the existent bounding box
// get the minimun value between the added bounding box and
// the existent bounding box
m_min.x = fminf( m_min.x, aBBox.m_min.x );
m_min.y = fminf( m_min.y, aBBox.m_min.y );
// get the maximun value between the added bounding box and the existent bounding box
// get the maximun value between the added bounding box and
// the existent bounding box
m_max.x = fmaxf( m_max.x, aBBox.m_max.x );
m_max.y = fmaxf( m_max.y, aBBox.m_max.y );
}
@ -131,7 +133,7 @@ SFVEC2F CBBOX2D::GetExtent() const
unsigned int CBBOX2D::MaxDimension() const
{
unsigned int result = 0;
SFVEC2F extent = GetExtent();
const SFVEC2F extent = GetExtent();
if( extent.y > extent.x ) result = 1;
@ -141,7 +143,8 @@ unsigned int CBBOX2D::MaxDimension() const
float CBBOX2D::Perimeter() const
{
SFVEC2F extent = GetExtent();
const SFVEC2F extent = GetExtent();
return 2.0f * ( extent.x + extent.y );
}
@ -150,8 +153,8 @@ void CBBOX2D::Scale( float aScale )
{
wxASSERT( IsInitialized() );
SFVEC2F scaleV( aScale, aScale );
SFVEC2F centerV = GetCenter();
const SFVEC2F scaleV( aScale, aScale );
const SFVEC2F centerV = GetCenter();
m_min = (m_min - centerV) * scaleV + centerV;
m_max = (m_max - centerV) * scaleV + centerV;
@ -184,18 +187,20 @@ bool CBBOX2D::Intersects( const SFVEC2F &aCenter, float aRadiusSquared ) const
{
float fDistSq = 0.0f;
for ( unsigned int i = 0; i < 2; i++ )
for( unsigned int i = 0; i < 2; i++ )
{
if( aCenter[i] < m_min[i] )
{
float fDist = aCenter[i] - m_min[i];
const float fDist = aCenter[i] - m_min[i];
fDistSq += fDist * fDist;
}
else
{
if( aCenter[i] > m_max[i] )
{
float fDist = aCenter[i] - m_max[i];
const float fDist = aCenter[i] - m_max[i];
fDistSq += fDist * fDist;
}
}
@ -210,8 +215,8 @@ bool CBBOX2D::Intersects( const CBBOX2D &aBBox ) const
wxASSERT( IsInitialized() );
wxASSERT( aBBox.IsInitialized() );
bool x = ( m_max.x >= aBBox.m_min.x ) && ( m_min.x <= aBBox.m_max.x );
bool y = ( m_max.y >= aBBox.m_min.y ) && ( m_min.y <= aBBox.m_max.y );
const bool x = ( m_max.x >= aBBox.m_min.x ) && ( m_min.x <= aBBox.m_max.x );
const bool y = ( m_max.y >= aBBox.m_min.y ) && ( m_min.y <= aBBox.m_max.y );
return ( x && y );
}
@ -238,14 +243,14 @@ bool CBBOX2D::Intersect( const RAY2D &aRay, float *t ) const
{
wxASSERT( t );
float tx1 = (m_min.x - aRay.m_Origin.x) * aRay.m_InvDir.x;
float tx2 = (m_max.x - aRay.m_Origin.x) * aRay.m_InvDir.x;
const float tx1 = (m_min.x - aRay.m_Origin.x) * aRay.m_InvDir.x;
const float tx2 = (m_max.x - aRay.m_Origin.x) * aRay.m_InvDir.x;
float tmin = glm::min( tx1, tx2 );
float tmax = glm::max( tx1, tx2 );
float ty1 = (m_min.y - aRay.m_Origin.y) * aRay.m_InvDir.y;
float ty2 = (m_max.y - aRay.m_Origin.y) * aRay.m_InvDir.y;
const float ty1 = (m_min.y - aRay.m_Origin.y) * aRay.m_InvDir.y;
const float ty2 = (m_max.y - aRay.m_Origin.y) * aRay.m_InvDir.y;
tmin = glm::max( tmin, glm::min( ty1, ty2 ) );
tmax = glm::min( tmax, glm::max( ty1, ty2 ) );
@ -261,21 +266,22 @@ bool CBBOX2D::Intersect( const RAY2D &aRay, float *t ) const
bool CBBOX2D::Intersect( const RAYSEG2D &aRaySeg ) const
{
float tx1 = (m_min.x - aRaySeg.m_Start.x) * aRaySeg.m_InvDir.x;
float tx2 = (m_max.x - aRaySeg.m_Start.x) * aRaySeg.m_InvDir.x;
const float tx1 = (m_min.x - aRaySeg.m_Start.x) * aRaySeg.m_InvDir.x;
const float tx2 = (m_max.x - aRaySeg.m_Start.x) * aRaySeg.m_InvDir.x;
float tmin = glm::min( tx1, tx2 );
float tmax = glm::max( tx1, tx2 );
float ty1 = (m_min.y - aRaySeg.m_Start.y) * aRaySeg.m_InvDir.y;
float ty2 = (m_max.y - aRaySeg.m_Start.y) * aRaySeg.m_InvDir.y;
const float ty1 = (m_min.y - aRaySeg.m_Start.y) * aRaySeg.m_InvDir.y;
const float ty2 = (m_max.y - aRaySeg.m_Start.y) * aRaySeg.m_InvDir.y;
tmin = glm::max( tmin, glm::min( ty1, ty2 ) );
tmax = glm::min( tmax, glm::max( ty1, ty2 ) );
if( (tmax >= 0.0f) && (tmax >= tmin) )
{
float t = (tmin > 0.0f)?tmin:tmax;
const float t = (tmin > 0.0f)?tmin:tmax;
return ( t < aRaySeg.m_Length );
}
@ -288,14 +294,14 @@ bool CBBOX2D::Intersect( const RAY2D &aRay, float *aOutHitT0, float *aOutHitT1 )
wxASSERT( aOutHitT0 );
wxASSERT( aOutHitT1 );
float tx1 = (m_min.x - aRay.m_Origin.x) * aRay.m_InvDir.x;
float tx2 = (m_max.x - aRay.m_Origin.x) * aRay.m_InvDir.x;
const float tx1 = (m_min.x - aRay.m_Origin.x) * aRay.m_InvDir.x;
const float tx2 = (m_max.x - aRay.m_Origin.x) * aRay.m_InvDir.x;
float tmin = glm::min( tx1, tx2 );
float tmax = glm::max( tx1, tx2 );
float ty1 = (m_min.y - aRay.m_Origin.y) * aRay.m_InvDir.y;
float ty2 = (m_max.y - aRay.m_Origin.y) * aRay.m_InvDir.y;
const float ty1 = (m_min.y - aRay.m_Origin.y) * aRay.m_InvDir.y;
const float ty2 = (m_max.y - aRay.m_Origin.y) * aRay.m_InvDir.y;
tmin = glm::max( tmin, glm::min( ty1, ty2 ) );
tmax = glm::min( tmax, glm::max( ty1, ty2 ) );

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@gmail.com>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -30,15 +30,14 @@
#ifndef _CBBOX2D_H_
#define _CBBOX2D_H_
#include "plugins/3dapi/xv3d_types.h"
#include "3d_rendering/3d_render_raytracing/ray.h"
#include "../ray.h"
/**
* Class CBBOX
* manages a bounding box defined by two SFVEC2F min max points.
*/
GLM_ALIGNED_STRUCT(CLASS_ALIGNMENT) CBBOX2D
struct CBBOX2D
{
public:
@ -54,7 +53,7 @@ public:
* Initialize a bounding box with a given point
* @param aPbInit a point for the bounding box initialization
*/
CBBOX2D( const SFVEC2F &aPbInit );
explicit CBBOX2D( const SFVEC2F &aPbInit );
/**
* Constructor CBBOX2D
@ -209,8 +208,8 @@ public:
bool Intersect( const RAYSEG2D &aRaySeg ) const;
private:
SFVEC2F m_min; ///< point of the lower position of the bounding box
SFVEC2F m_max; ///< point of the higher position of the bounding box
SFVEC2F m_min; ///< point of the lower position of the bounding box
SFVEC2F m_max; ///< point of the higher position of the bounding box
};
#endif // CBBox2d_h

View File

@ -0,0 +1,177 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file cfilledcircle2d.cpp
* @brief
*/
#include "cfilledcircle2d.h"
#include <wx/debug.h>
CFILLEDCIRCLE2D::CFILLEDCIRCLE2D( const SFVEC2F &aCenter,
float aRadius,
const BOARD_ITEM &aBoardItem ) :
COBJECT2D( OBJ2D_FILLED_CIRCLE, aBoardItem )
{
wxASSERT( aRadius > 0.0f ); // If that happens, it should be handled before create this circle
m_center = aCenter;
m_radius = aRadius;
m_radius_squared = aRadius * aRadius;
m_bbox.Reset();
m_bbox.Set( m_center - SFVEC2F( aRadius, aRadius ),
m_center + SFVEC2F( aRadius, aRadius ) );
m_bbox.ScaleNextUp();
m_centroid = m_bbox.GetCenter();
wxASSERT( m_bbox.IsInitialized() );
}
bool CFILLEDCIRCLE2D::Overlaps( const CBBOX2D &aBBox ) const
{
// NOT IMPLEMENTED
return false;
}
bool CFILLEDCIRCLE2D::Intersects( const CBBOX2D &aBBox ) const
{
return aBBox.Intersects( m_center, m_radius_squared );
}
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
// Compute some factors used in computation
const float qx = aSegRay.m_Start.x - m_center.x;
const float qy = aSegRay.m_Start.y - m_center.y;
const float qd = qx * aSegRay.m_Dir.x + qy * aSegRay.m_Dir.y;
const float qq = qx * qx + qy * qy;
// solving the quadratic equation for t at the pts of intersection
// dd*t^2 + (2*qd)*t + (qq-r^2) = 0
const float discriminantsqr = (qd * qd - (qq - m_radius_squared));
// If the discriminant is less than zero, there is no intersection
if( discriminantsqr < FLT_EPSILON )
return false;
// Otherwise check and make sure that the intersections occur on the ray (t
// > 0) and return the closer one
const float discriminant = sqrt(discriminantsqr);
const float t1 = (-qd - discriminant);
const float t2 = (-qd + discriminant);
float t;
if( (t1 > 0.0f) && (t1 < aSegRay.m_Length) )
t = t1;
else
{
if( (t2 > 0.0f) && (t2 < aSegRay.m_Length) )
t = t2;
else
return false; // Neither intersection was in the ray's half line.
}
wxASSERT( (t > 0.0f) && (t <= aSegRay.m_Length) );
// Convert the intersection to a normalized 0.0 .. 1.0
*aOutT = t / aSegRay.m_Length;
const SFVEC2F hitPoint = aSegRay.at( t );
*aNormalOut = (hitPoint - m_center) / m_radius;
return true;
}
INTERSECTION_RESULT CFILLEDCIRCLE2D::IsBBoxInside( const CBBOX2D &aBBox ) const
{
if( !m_bbox.Intersects( aBBox ) )
return INTR_MISSES;
SFVEC2F v[4];
v[0] = aBBox.Min() - m_center;
v[1] = aBBox.Max() - m_center;
v[2] = SFVEC2F( aBBox.Min().x, aBBox.Max().y ) - m_center;
v[3] = SFVEC2F( aBBox.Max().x, aBBox.Min().y ) - m_center;
float s[4];
s[0] = v[0].x * v[0].x + v[0].y * v[0].y;
s[1] = v[1].x * v[1].x + v[1].y * v[1].y;
s[2] = v[2].x * v[2].x + v[2].y * v[2].y;
s[3] = v[3].x * v[3].x + v[3].y * v[3].y;
bool isInside[4];
isInside[0] = s[0] <= m_radius_squared;
isInside[1] = s[1] <= m_radius_squared;
isInside[2] = s[2] <= m_radius_squared;
isInside[3] = s[3] <= m_radius_squared;
// Check if all points are inside the circle
if( isInside[0] &&
isInside[1] &&
isInside[2] &&
isInside[3] )
return INTR_FULL_INSIDE;
// Check if any point is inside the circle
if( isInside[0] ||
isInside[1] ||
isInside[2] ||
isInside[3] )
return INTR_INTERSECTS;
return INTR_MISSES;
}
bool CFILLEDCIRCLE2D::IsPointInside( const SFVEC2F &aPoint ) const
{
const SFVEC2F v = m_center - aPoint;
if( (v.x * v.x + v.y * v.y) <= m_radius_squared )
return true;
return false;
}

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -32,7 +32,7 @@
#include "cobject2d.h"
class GLM_ALIGN(CLASS_ALIGNMENT) CFILLEDCIRCLE2D : public COBJECT2D
class CFILLEDCIRCLE2D : public COBJECT2D
{
public:
float GetRadius() const { return m_radius; }

View File

@ -0,0 +1,217 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file citemlayercsg2d.cpp
* @brief
*/
#include "citemlayercsg2d.h"
#include "3d_fastmath.h"
#include <wx/debug.h>
CITEMLAYERCSG2D::CITEMLAYERCSG2D( const COBJECT2D *aObjectA,
std::vector<const COBJECT2D *> *aObjectB,
const COBJECT2D *aObjectC,
const BOARD_ITEM &aBoardItem ):
COBJECT2D( OBJ2D_CSG, aBoardItem ),
m_objectA(aObjectA),
m_objectB(aObjectB),
m_objectC(aObjectC)
{
wxASSERT( aObjectA );
m_bbox.Reset();
m_bbox.Set( aObjectA->GetBBox() );
m_bbox.ScaleNextUp();
m_centroid = m_bbox.GetCenter();
wxASSERT( m_bbox.IsInitialized() );
}
CITEMLAYERCSG2D::~CITEMLAYERCSG2D()
{
if( ((void*)m_objectB != CSGITEM_EMPTY) &&
((void*)m_objectB != CSGITEM_FULL) )
{
delete m_objectB;
m_objectB = NULL;
}
}
bool CITEMLAYERCSG2D::Intersects( const CBBOX2D &aBBox ) const
{
return m_bbox.Intersects( aBBox );
// !TODO: improove this implementation
//return false;
}
bool CITEMLAYERCSG2D::Overlaps( const CBBOX2D &aBBox ) const
{
// NOT IMPLEMENTED
return false;
}
// Based on ideas and implementation by Nick Chapman
// http://homepages.paradise.net.nz/nickamy/raytracer/raytracer.htm
bool CITEMLAYERCSG2D::Intersect( const RAYSEG2D &aSegRay,
float *aOutT,
SFVEC2F *aNormalOut ) const
{
wxASSERT( aOutT );
wxASSERT( aNormalOut );
if( m_objectA->GetObjectType() == OBJ2D_DUMMYBLOCK )
return false;
float currentRayDist;
SFVEC2F currentRayPos;
SFVEC2F currentNormal;
if( m_objectA->IsPointInside( aSegRay.m_Start ) )
{
// start ray point off where it is now (at the origin)
currentRayDist = 0.0f;
currentRayPos = aSegRay.m_Start;
}
else
{
//move ray point to start of main object
if( !m_objectA->Intersect( aSegRay, &currentRayDist, &currentNormal ) )
return false;
currentRayPos = aSegRay.atNormalized( NextFloatDown( currentRayDist ) );
}
//wxASSERT( (currentRayDist >= 0.0f) && (currentRayDist <= 1.0f) );
// move through the union of subtracted regions
bool hitSubRegion = false;
if( m_objectB )
{
while(1)
{
bool wasInsideSubVol = false;
//check against all subbed objects
for( unsigned int i = 0; i < m_objectB->size(); ++i )
{
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,
&hitDist,
&currentNormal ) )
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 ) )
//if(1)
{
wasInsideSubVol = true;
break;
}
}
}
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;
return true;
}
INTERSECTION_RESULT CITEMLAYERCSG2D::IsBBoxInside( const CBBOX2D &aBBox ) const
{
// !TODO:
return INTR_MISSES;
}
bool CITEMLAYERCSG2D::IsPointInside( const SFVEC2F &aPoint ) const
{
// Perform the operation (A - B) /\ C
if( m_objectA->IsPointInside( aPoint ) )
{
if( m_objectB != CSGITEM_EMPTY)
for( unsigned int i = 0; i< m_objectB->size(); i++ )
{
if( (*m_objectB)[i]->IsPointInside( aPoint ) )
return false;
}
// !TODO: not yet implemented
//if( m_objectC && m_objectC != CSGITEM_FULL )
// return m_objectC->IsPointInside( aPoint );
return true;
}
return false;
}

View File

@ -0,0 +1,102 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file citemlayercsg2d.h
* @brief
*/
#ifndef _CITEMLAYERCSG2D_H_
#define _CITEMLAYERCSG2D_H_
#include "cobject2d.h"
#include <vector>
/**
* This class is used to make constructive solig geometry for items
* objects on layers.
* The operation is in the form (A - B) /\ C
* For almost all of the layers it translate something like:
* A (a via, a track, pad, polygon), B (a via hole, a THT hole, .. ),
* C the board (epoxy)
* For layers like Solder mask that are negative:
* A ( epoxy ), B( pads, polygons, ..), C=1
*
* Some notes:
* BODY = PCB_outlines - PCB_holes - (Modules_THT_holes + VIA_THT_holes)
*
* Plated_vias_and_holes = Tracks.Vias + Modules.PlatedHoles
*
* Layer.cu = ( Tracks.cu + Modules_Pads.cu + Modules_Graphics.cu +
* Layer_zones.cu + PCB_drawings.cu - Layer_VIA_holes ) & BODY
*
* Layer.Mask = BODY -
* (PCB_drawing.Mask + Modules_Graphics.Mask +
* Modules_Pads.Mask + Layer_zones.Mask )
* Layer.Paste = (PCB_drawing.Paste + Modules_Graphics.Paste +
* Modules_Pads.Paste + Layer_zones.Paste) & BODY
* Layer.Silk = (PCB_drawing.Silk + Modules_Graphics.Silk +
* Modules_Pads.Silk + Layer_zones.Paste) & BODY
*
* BODY = A - B /\ 1
* Layer.cu = A - B /\ C
* Layer.mask = A - B /\ 1
* Layers.Paste = A - 0 /\ C
* Layers.Silk = A - 0 /\ C
*
* BODY = P - T /\ 1
* Layer.cu = T - H /\ BODY
* Layer.mask = BODY - M /\ 1
* Layers.Paste = P - 0 /\ BODY
* Layers.Silk = S - 0 /\ BODY
*/
#define CSGITEM_EMPTY 0
#define CSGITEM_FULL (COBJECT2D *)((size_t)(-1))
class CITEMLAYERCSG2D : public COBJECT2D
{
private:
const COBJECT2D *m_objectA;
std::vector<const COBJECT2D *> *m_objectB;
const COBJECT2D *m_objectC;
public:
CITEMLAYERCSG2D( const COBJECT2D *aObjectA,
std::vector<const COBJECT2D *> *aObjectB,
const COBJECT2D *aObjectC,
const BOARD_ITEM &aBoardItem );
~CITEMLAYERCSG2D();
// Imported from COBJECT2D
bool Overlaps( const CBBOX2D &aBBox ) const;
bool Intersects( const CBBOX2D &aBBox ) const;
bool Intersect( const RAYSEG2D &aSegRay, float *aOutT, SFVEC2F *aNormalOut ) const;
INTERSECTION_RESULT IsBBoxInside( const CBBOX2D &aBBox ) const;
bool IsPointInside( const SFVEC2F &aPoint ) const;
};
#endif // _CITEMLAYERCSG2D_H_

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -30,7 +30,6 @@
#ifndef _COBJECT2D_H_
#define _COBJECT2D_H_
#include "plugins/3dapi/xv3d_types.h"
#include "cbbox2d.h"
#include <string.h>
@ -60,7 +59,7 @@ enum OBJECT2D_TYPE
};
class GLM_ALIGN(CLASS_ALIGNMENT) COBJECT2D
class COBJECT2D
{
protected:
CBBOX2D m_bbox;
@ -78,12 +77,13 @@ public:
/** Function Overlaps
* @brief Test if the box overlaps the object
* Conformance
* The function overlaps implements function Overlaps from the OGC Simple Feature Specification.
* The function overlaps implements function Overlaps from the OGC
* Simple Feature Specification.
* http://www.opengeospatial.org/standards/sfa
* a.Overlaps(b) ( dim(I(a)) = dim(I(b)) = dim(I(a) I(b))) (a b a) (a b b)
* It means that the result dimension of an overlap is the same dimentions of the bounding box
* (so the overlap cannot be a point or a line) and one of the boxes cannot full contain the other
* box.
* It means that the result dimension of an overlap is the same dimentions
* of the bounding box (so the overlap cannot be a point or a line) and one
* of the boxes cannot full contain the other box.
* @param aBBox - The bounding box to test
* @return true if the BBox intersects the object or is inside it
*/
@ -100,11 +100,14 @@ public:
/** Function Intersect
* @brief Intersect
* @param aSegRay
* @param aOutT a value between 0.0 and 1.0 in relation to the time of the hit of the segment
* @param aOutT a value between 0.0 and 1.0 in relation to the time of the
* hit of the segment
* @param aNormalOut
* @return
*/
virtual bool Intersect( const RAYSEG2D &aSegRay, float *aOutT, SFVEC2F *aNormalOut ) const = 0;
virtual bool Intersect( const RAYSEG2D &aSegRay,
float *aOutT,
SFVEC2F *aNormalOut ) const = 0;
/** Function IsBBoxInside
* @brief Tests if the bouding is out, intersects or is complety inside
@ -119,7 +122,7 @@ public:
const SFVEC2F &GetCentroid() const { return m_centroid; }
const OBJECT2D_TYPE GetObjectType() const { return m_obj_type; }
OBJECT2D_TYPE GetObjectType() const { return m_obj_type; }
};
@ -129,9 +132,12 @@ public:
class COBJECT2D_STATS
{
public:
void ResetStats() { memset( m_counter, 0, sizeof(unsigned int) * OBJ2D_MAX ); }
void ResetStats() { memset( m_counter, 0, sizeof( unsigned int ) * OBJ2D_MAX ); }
unsigned int GetCountOf( OBJECT2D_TYPE aObjType ) const { return m_counter[aObjType]; }
unsigned int GetCountOf( OBJECT2D_TYPE aObjType ) const
{
return m_counter[aObjType];
}
void AddOne( OBJECT2D_TYPE aObjType ) { m_counter[aObjType]++; }

View File

@ -0,0 +1,831 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file cpolygon2d.cpp
* @brief
*/
#include "cpolygon2d.h"
#include <wx/debug.h>
#include <fctsys.h>
#ifdef PRINT_STATISTICS_3D_VIEWER
#include <stdio.h>
#endif
// CPOLYGONBLOCK2D
// /////////////////////////////////////////////////////////////////////////////
static bool polygon_IsPointInside( const SEGMENTS &aSegments, const SFVEC2F &aPoint )
{
wxASSERT( aSegments.size() >= 3 );
unsigned int i;
unsigned int j = aSegments.size() - 1;
bool oddNodes = false;
for( i = 0; i < aSegments.size(); j = i++ )
{
const float polyJY = aSegments[j].m_Start.y;
const float polyIY = aSegments[i].m_Start.y;
if( ((polyIY <= aPoint.y) && (polyJY >= aPoint.y)) ||
((polyJY <= aPoint.y) && (polyIY >= aPoint.y))
)
{
const float polyJX = aSegments[j].m_Start.x;
const float polyIX = aSegments[i].m_Start.x;
if( (polyIX <= aPoint.x) || (polyJX <= aPoint.x) )
oddNodes ^= ( ( polyIX +
( ( aPoint.y - polyIY ) *
aSegments[i].m_inv_JY_minus_IY ) *
aSegments[i].m_JX_minus_IX ) < aPoint.x );
}
}
return oddNodes;
}
CPOLYGONBLOCK2D::CPOLYGONBLOCK2D( const SEGMENTS_WIDTH_NORMALS &aOpenSegmentList,
const OUTERS_AND_HOLES &aOuter_and_holes,
const BOARD_ITEM &aBoardItem ) :
COBJECT2D( OBJ2D_POLYGON, aBoardItem )
{
m_open_segments.resize( aOpenSegmentList.size() );
// Copy vectors and structures
for( unsigned int i = 0; i < aOpenSegmentList.size(); i++ )
m_open_segments[i] = aOpenSegmentList[i];
m_outers_and_holes = aOuter_and_holes;
// Compute bounding box with the points of the polygon
m_bbox.Reset();
for( unsigned int i = 0; i < m_outers_and_holes.m_Outers.size(); i++ )
{
for( unsigned int j = 0; j < m_outers_and_holes.m_Outers[i].size(); j++ )
m_bbox.Union( ((SEGMENTS)m_outers_and_holes.m_Outers[i])[j].m_Start );
}
m_bbox.ScaleNextUp();
m_centroid = m_bbox.GetCenter();
// Some checks
wxASSERT( m_open_segments.size() == aOpenSegmentList.size() );
wxASSERT( m_open_segments.size() > 0 );
wxASSERT( m_outers_and_holes.m_Outers.size() > 0 );
wxASSERT( m_outers_and_holes.m_Outers.size() == aOuter_and_holes.m_Outers.size() );
wxASSERT( m_outers_and_holes.m_Holes.size() == aOuter_and_holes.m_Holes.size() );
wxASSERT( m_outers_and_holes.m_Outers[0].size() >= 3 );
wxASSERT( m_outers_and_holes.m_Outers[0].size() ==
aOuter_and_holes.m_Outers[0].size() );
wxASSERT( m_bbox.IsInitialized() );
}
bool CPOLYGONBLOCK2D::Intersects( const CBBOX2D &aBBox ) const
{
return m_bbox.Intersects( aBBox );
// !TODO: this is a quick not perfect implementation
// in order to make it perfect the box must be checked against all the
// polygons in the outers and not inside the holes
}
bool CPOLYGONBLOCK2D::Overlaps( const CBBOX2D &aBBox ) const
{
// NOT IMPLEMENTED
return false;
}
bool CPOLYGONBLOCK2D::Intersect( const RAYSEG2D &aSegRay,
float *aOutT,
SFVEC2F *aNormalOut ) const
{
int hitIndex = -1;
float hitU = 0.0f;
float tMin = 0.0f;
for( unsigned int i = 0; i < m_open_segments.size(); i++ )
{
const SFVEC2F &s = m_open_segments[i].m_Precalc_slope;
const SFVEC2F &q = m_open_segments[i].m_Start;
float rxs = aSegRay.m_End_minus_start.x * s.y -
aSegRay.m_End_minus_start.y * s.x;
if( fabs(rxs) > FLT_EPSILON )
{
const float inv_rxs = 1.0f / rxs;
const SFVEC2F pq = q - aSegRay.m_Start;
const float t = (pq.x * s.y - pq.y * s.x) * inv_rxs;
if( (t < 0.0f) || (t > 1.0f) )
continue;
const float u = ( pq.x * aSegRay.m_End_minus_start.y -
pq.y * aSegRay.m_End_minus_start.x ) * inv_rxs;
if( (u < 0.0f) || (u > 1.0f) )
continue;
if( ( hitIndex == -1 ) || ( t <= tMin ) )
{
tMin = t;
hitIndex = i;
hitU = u;
}
}
}
if( hitIndex >= 0 )
{
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) );
return true;
}
return false;
}
INTERSECTION_RESULT CPOLYGONBLOCK2D::IsBBoxInside( const CBBOX2D &aBBox ) const
{
return INTR_MISSES;
}
bool CPOLYGONBLOCK2D::IsPointInside( const SFVEC2F &aPoint ) const
{
// NOTE: we could add here a test for the bounding box, but because in the
// 3d object it already checked for a 3d bbox.
// First test if point is inside a hole.
// If true it can early exit
for( unsigned int i = 0; i < m_outers_and_holes.m_Holes.size(); i++ )
if( !m_outers_and_holes.m_Holes[i].empty() )
if( polygon_IsPointInside( m_outers_and_holes.m_Holes[i], aPoint ) )
return false;
// 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( polygon_IsPointInside( m_outers_and_holes.m_Outers[i], aPoint ) )
return true;
// Miss the polygon
return false;
}
// CDUMMYBLOCK2D
// /////////////////////////////////////////////////////////////////////////////
CDUMMYBLOCK2D::CDUMMYBLOCK2D( const SFVEC2F &aPbMin, const SFVEC2F &aPbMax,
const BOARD_ITEM &aBoardItem ) :
COBJECT2D( OBJ2D_DUMMYBLOCK, aBoardItem )
{
m_bbox.Set( aPbMin, aPbMax );
m_bbox.ScaleNextUp();
m_centroid = m_bbox.GetCenter();
}
CDUMMYBLOCK2D::CDUMMYBLOCK2D( const CBBOX2D &aBBox,
const BOARD_ITEM &aBoardItem ) :
COBJECT2D( OBJ2D_DUMMYBLOCK, aBoardItem )
{
m_bbox.Set( aBBox );
m_bbox.ScaleNextUp();
m_centroid = m_bbox.GetCenter();
}
bool CDUMMYBLOCK2D::Intersects( const CBBOX2D &aBBox ) const
{
return m_bbox.Intersects( aBBox );
}
bool CDUMMYBLOCK2D::Overlaps( const CBBOX2D &aBBox ) const
{
// Not implemented
return false;
}
bool CDUMMYBLOCK2D::Intersect( const RAYSEG2D &aSegRay,
float *aOutT,
SFVEC2F *aNormalOut ) const
{
// The dummy block will be never intersected because it have no edges,
// only it have a plan surface of the size of the bounding box
return false;
}
INTERSECTION_RESULT CDUMMYBLOCK2D::IsBBoxInside( const CBBOX2D &aBBox ) const
{
//!TODO:
return INTR_MISSES;
}
bool CDUMMYBLOCK2D::IsPointInside( const SFVEC2F &aPoint ) const
{
// The dummy is filled in all his bounding box, so if it hit the bbox
// it will hit this dummy
if( m_bbox.Inside( aPoint ) )
return true;
return false;
}
// Polygon process and conversion
// ////////////////////////////////////////////////////////////////////////////
typedef std::vector<SFVEC2F> KF_POINTS;
#define MAX_NR_DIVISIONS 96
static bool intersect( const SEGMENT_WITH_NORMALS &aSeg,
const SFVEC2F &aStart,
const SFVEC2F &aEnd )
{
const SFVEC2F r = aEnd - aStart;
const SFVEC2F s = aSeg.m_Precalc_slope;
const SFVEC2F q = aSeg.m_Start;
const float rxs = r.x * s.y - r.y * s.x;
if( fabs(rxs) > glm::epsilon<float>() )
{
const float inv_rxs = 1.0f / rxs;
const SFVEC2F pq = q - aStart;
const float t = (pq.x * s.y - pq.y * s.x) * inv_rxs;
if( (t < 0.0f) || (t > 1.0f) )
return false;
const float u = (pq.x * r.y - pq.y * r.x) * inv_rxs;
if( (u < 0.0f) || (u > 1.0f) )
return false;
return true;
}
return false;
}
static void extractPathsFrom( const SEGMENTS_WIDTH_NORMALS &aSegList,
const CBBOX2D &aBBox,
SEGMENTS_WIDTH_NORMALS &aOutSegThatIntersect )
{
wxASSERT( aSegList.size () >= 3 );
unsigned int i;
unsigned int j = aSegList.size() - 1;
const SFVEC2F p1( aBBox.Min().x, aBBox.Min().y );
const SFVEC2F p2( aBBox.Max().x, aBBox.Min().y );
const SFVEC2F p3( aBBox.Max().x, aBBox.Max().y );
const SFVEC2F p4( aBBox.Min().x, aBBox.Max().y );
aOutSegThatIntersect.clear();
for( i = 0; i < aSegList.size(); j = i++ )
{
if( aBBox.Inside( aSegList[i].m_Start ) ||
aBBox.Inside( aSegList[j].m_Start ) )
{
// if the segment points are inside the bounding box then this
// segment is touching the bbox.
aOutSegThatIntersect.push_back( aSegList[i] );
}
else
{
// Check if a segment intersects the bounding box
// Make a bounding box based on the segments start and end
CBBOX2D segmentBBox( aSegList[i].m_Start,
aSegList[j].m_Start );
if( aBBox.Intersects( segmentBBox ) )
{
const SEGMENT_WITH_NORMALS &seg = aSegList[i];
if( intersect( seg, p1, p2 ) ||
intersect( seg, p2, p3 ) ||
intersect( seg, p3, p4 ) ||
intersect( seg, p4, p1 ) )
{
aOutSegThatIntersect.push_back( seg );
}
}
}
}
}
static void polygon_Convert( const SHAPE_LINE_CHAIN &aPath,
SEGMENTS &aOutSegment,
float aBiuTo3DunitsScale )
{
aOutSegment.resize( aPath.PointCount() );
for( int j = 0; j < aPath.PointCount(); j++ )
{
const VECTOR2I &a = aPath.CPoint( j );
aOutSegment[j].m_Start = SFVEC2F( (float) a.x * aBiuTo3DunitsScale,
(float)-a.y * aBiuTo3DunitsScale );
}
unsigned int i;
unsigned int j = aOutSegment.size () - 1;
for( i = 0; i < aOutSegment.size (); j = i++ )
{
// Calculate constants for each segment
aOutSegment[i].m_inv_JY_minus_IY = 1.0f / ( aOutSegment[j].m_Start.y -
aOutSegment[i].m_Start.y );
aOutSegment[i].m_JX_minus_IX = (aOutSegment[j].m_Start.x -
aOutSegment[i].m_Start.x);
}
}
void Convert_path_polygon_to_polygon_blocks_and_dummy_blocks(
const SHAPE_POLY_SET &aMainPath,
CGENERICCONTAINER2D &aDstContainer,
float aBiuTo3DunitsScale,
float aDivFactor,
const BOARD_ITEM &aBoardItem )
{
BOX2I pathBounds = aMainPath.BBox();
// Get the path
wxASSERT( aMainPath.OutlineCount() == 1 );
const SHAPE_POLY_SET::POLYGON& curr_polywithholes = aMainPath.CPolygon( 0 );
wxASSERT( curr_polywithholes.size() == 1 );
const SHAPE_LINE_CHAIN& path = curr_polywithholes[0]; // a simple polygon
// Convert the points to segments class
CBBOX2D bbox;
bbox.Reset();
// Contains the main list of segments and each segment normal interpolated
SEGMENTS_WIDTH_NORMALS segments_and_normals;
// Contains a closed polygon used to calc if points are inside
SEGMENTS segments;
segments_and_normals.resize( path.PointCount() );
segments.resize( path.PointCount() );
for( int i = 0; i < path.PointCount(); i++ )
{
const VECTOR2I& a = path.CPoint( i );
const SFVEC2F point ( (float)( a.x) * aBiuTo3DunitsScale,
(float)(-a.y) * aBiuTo3DunitsScale );
bbox.Union( point );
segments_and_normals[i].m_Start = point;
segments[i].m_Start = point;
}
bbox.ScaleNextUp();
// Calc the slopes, normals and some statistics about this polygon
unsigned int i;
unsigned int j = segments_and_normals.size() - 1;
// Temporary normal to the segment, it will later be used for interpolation
std::vector< SFVEC2F > tmpSegmentNormals;
tmpSegmentNormals.resize( segments_and_normals.size() );
float medOfTheSquaresSegmentLength = 0.0f;
#ifdef PRINT_STATISTICS_3D_VIEWER
float minLength = FLT_MAX;
#endif
for( i = 0; i < segments_and_normals.size(); j = i++ )
{
const SFVEC2F slope = segments_and_normals[j].m_Start -
segments_and_normals[i].m_Start;
segments_and_normals[i].m_Precalc_slope = slope;
// Calculate constants for each segment
segments[i].m_inv_JY_minus_IY = 1.0f / ( segments_and_normals[j].m_Start.y -
segments_and_normals[i].m_Start.y );
segments[i].m_JX_minus_IX = ( segments_and_normals[j].m_Start.x -
segments_and_normals[i].m_Start.x );
// The normal orientation expect a fixed polygon orientation (!TODO: which one?)
//tmpSegmentNormals[i] = glm::normalize( SFVEC2F( -slope.y, +slope.x ) );
tmpSegmentNormals[i] = glm::normalize( SFVEC2F( slope.y, -slope.x ) );
const float length = slope.x * slope.x + slope.y * slope.y;
#ifdef PRINT_STATISTICS_3D_VIEWER
if( length < minLength )
minLength = length;
#endif
medOfTheSquaresSegmentLength += length;
}
#ifdef PRINT_STATISTICS_3D_VIEWER
float minSegmentLength = sqrt( minLength );
#endif
// This calc an approximation of medium lengths, that will be used to calc
// the size of the division.
medOfTheSquaresSegmentLength /= segments_and_normals.size();
medOfTheSquaresSegmentLength = sqrt( medOfTheSquaresSegmentLength );
// Compute the normal interpolation
// If calculate the dot between the segments, if they are above/below some
// threshould it will not interpolated it (ex: if you are in a edge corner
// or in a smooth transaction)
j = segments_and_normals.size() - 1;
for( i = 0; i < segments_and_normals.size(); j = i++ )
{
const SFVEC2F normalBeforeSeg = tmpSegmentNormals[j];
const SFVEC2F normalSeg = tmpSegmentNormals[i];
const SFVEC2F normalAfterSeg = tmpSegmentNormals[ (i + 1) %
segments_and_normals.size() ];
const float dotBefore = glm::dot( normalBeforeSeg, normalSeg );
const float dotAfter = glm::dot( normalAfterSeg, normalSeg );
if( dotBefore < 0.7f )
segments_and_normals[i].m_Normals.m_Start = normalSeg;
else
segments_and_normals[i].m_Normals.m_Start =
glm::normalize( (((normalBeforeSeg * dotBefore ) + normalSeg) * 0.5f) );
if( dotAfter < 0.7f )
segments_and_normals[i].m_Normals.m_End = normalSeg;
else
segments_and_normals[i].m_Normals.m_End =
glm::normalize( (((normalAfterSeg * dotAfter ) + normalSeg) * 0.5f) );
}
if( aDivFactor == 0.0f )
aDivFactor = medOfTheSquaresSegmentLength;
SFVEC2UI grid_divisions;
grid_divisions.x = (unsigned int)( (bbox.GetExtent().x / aDivFactor) );
grid_divisions.y = (unsigned int)( (bbox.GetExtent().y / aDivFactor) );
grid_divisions = glm::clamp( grid_divisions ,
SFVEC2UI( 1, 1 ),
SFVEC2UI( MAX_NR_DIVISIONS, MAX_NR_DIVISIONS ) );
// Calculate the steps advance of the grid
SFVEC2F blockAdvance;
blockAdvance.x = bbox.GetExtent().x / (float)grid_divisions.x;
blockAdvance.y = bbox.GetExtent().y / (float)grid_divisions.y;
wxASSERT( blockAdvance.x > 0.0f );
wxASSERT( blockAdvance.y > 0.0f );
const int leftToRight_inc = (pathBounds.GetRight() - pathBounds.GetLeft()) /
grid_divisions.x;
const int topToBottom_inc = (pathBounds.GetBottom() - pathBounds.GetTop()) /
grid_divisions.y;
// Statistics
unsigned int stats_n_empty_blocks = 0;
unsigned int stats_n_dummy_blocks = 0;
unsigned int stats_n_poly_blocks = 0;
unsigned int stats_sum_size_of_polygons = 0;
// Step by each block of a grid trying to extract segments and create
// polygon blocks
int topToBottom = pathBounds.GetTop();
float blockY = bbox.Max().y;
for( unsigned int iy = 0; iy < grid_divisions.y; iy++ )
{
int leftToRight = pathBounds.GetLeft();
float blockX = bbox.Min().x;
for( unsigned int ix = 0; ix < grid_divisions.x; ix++ )
{
CBBOX2D blockBox( SFVEC2F( blockX,
blockY - blockAdvance.y ),
SFVEC2F( blockX + blockAdvance.x,
blockY ) );
// Make the box large to it will catch (intersect) the edges
blockBox.ScaleNextUp();
blockBox.ScaleNextUp();
blockBox.ScaleNextUp();
SEGMENTS_WIDTH_NORMALS extractedSegments;
extractPathsFrom( segments_and_normals, blockBox, extractedSegments );
if( extractedSegments.empty() )
{
SFVEC2F p1( blockBox.Min().x, blockBox.Min().y );
SFVEC2F p2( blockBox.Max().x, blockBox.Min().y );
SFVEC2F p3( blockBox.Max().x, blockBox.Max().y );
SFVEC2F p4( blockBox.Min().x, blockBox.Max().y );
if( polygon_IsPointInside( segments, p1 ) ||
polygon_IsPointInside( segments, p2 ) ||
polygon_IsPointInside( segments, p3 ) ||
polygon_IsPointInside( segments, p4 ) )
{
// In this case, the segments are not intersecting the
// polygon, so it means that if any point is inside it,
// then all other are inside the polygon.
// This is a full bbox inside, so add a dummy box
aDstContainer.Add( new CDUMMYBLOCK2D( blockBox, aBoardItem ) );
stats_n_dummy_blocks++;
}
else
{
// Points are outside, so this block complety missed the polygon
// In this case, no objects need to be added
stats_n_empty_blocks++;
}
}
else
{
// At this point, the borders of polygon were intersected by the
// bounding box, so we must calculate a new polygon that will
// close that small block.
// This block will be used to calculate if points are inside
// the (sub block) polygon.
SHAPE_POLY_SET subBlockPoly;
SHAPE_LINE_CHAIN sb = SHAPE_LINE_CHAIN(
VECTOR2I( leftToRight,
topToBottom ),
VECTOR2I( leftToRight + leftToRight_inc,
topToBottom ),
VECTOR2I( leftToRight + leftToRight_inc,
topToBottom + topToBottom_inc ),
VECTOR2I( leftToRight,
topToBottom + topToBottom_inc ) );
//sb.Append( leftToRight, topToBottom );
sb.SetClosed( true );
subBlockPoly.AddOutline( sb );
// We need here a strictly simple polygon with outlines and holes
SHAPE_POLY_SET solution;
solution.BooleanIntersection( aMainPath,
subBlockPoly,
SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
OUTERS_AND_HOLES outersAndHoles;
outersAndHoles.m_Holes.clear();
outersAndHoles.m_Outers.clear();
for( int idx = 0; idx < solution.OutlineCount(); idx++ )
{
const SHAPE_LINE_CHAIN & outline = solution.Outline( idx );
SEGMENTS solutionSegment;
polygon_Convert( outline, solutionSegment, aBiuTo3DunitsScale );
outersAndHoles.m_Outers.push_back( solutionSegment );
stats_sum_size_of_polygons += solutionSegment.size();
for( int holeIdx = 0;
holeIdx < solution.HoleCount( idx );
holeIdx++ )
{
const SHAPE_LINE_CHAIN & hole = solution.Hole( idx, holeIdx );
polygon_Convert( hole, solutionSegment, aBiuTo3DunitsScale );
outersAndHoles.m_Holes.push_back( solutionSegment );
stats_sum_size_of_polygons += solutionSegment.size();
}
}
if( !outersAndHoles.m_Outers.empty() )
{
aDstContainer.Add( new CPOLYGONBLOCK2D( extractedSegments,
outersAndHoles,
aBoardItem ) );
stats_n_poly_blocks++;
}
}
blockX += blockAdvance.x;
leftToRight += leftToRight_inc;
}
blockY -= blockAdvance.y;
topToBottom += topToBottom_inc;
}
#ifdef PRINT_STATISTICS_3D_VIEWER
printf( "////////////////////////////////////////////////////////////////////////////////\n" );
printf( "Convert_path_polygon_to_polygon_blocks_and_dummy_blocks\n" );
printf( " grid_divisions (%u, %u)\n", grid_divisions.x, grid_divisions.y );
printf( " N Total Blocks %u\n", grid_divisions.x * grid_divisions.y );
printf( " N Empty Blocks %u\n", stats_n_empty_blocks );
printf( " N Dummy Blocks %u\n", stats_n_dummy_blocks );
printf( " N Polyg Blocks %u\n", stats_n_poly_blocks );
printf( " Med N Seg Poly %u\n", stats_sum_size_of_polygons / stats_n_poly_blocks );
printf( " medOfTheSquaresSegmentLength %f\n", medOfTheSquaresSegmentLength );
printf( " minSegmentLength %f\n", minSegmentLength );
printf( " aDivFactor %f\n", aDivFactor );
printf( "////////////////////////////////////////////////////////////////////////////////\n" );
#endif
}
void Polygon_Calc_BBox_3DU( const SHAPE_POLY_SET &aPolysList,
CBBOX2D &aOutBBox ,
float aBiuTo3DunitsScale )
{
aOutBBox.Reset();
for( int idx = 0; idx < aPolysList.OutlineCount(); ++idx )
{
// Each polygon in aPolysList is a polygon with holes
const SHAPE_POLY_SET::POLYGON& curr_polywithholes = aPolysList.CPolygon( idx );
for( unsigned ipoly = 0; ipoly < curr_polywithholes.size(); ++ipoly )
{
const SHAPE_LINE_CHAIN& path = curr_polywithholes[ipoly]; // a simple polygon
for( int jj = 0; jj < path.PointCount(); jj++ )
{
const VECTOR2I& a = path.CPoint( jj );
aOutBBox.Union( SFVEC2F( (float) a.x * aBiuTo3DunitsScale,
(float)-a.y * aBiuTo3DunitsScale ) );
}
}
}
aOutBBox.ScaleNextUp();
}
void Polygon_Convert( const KI_POLYGON &aPolygon,
ClipperLib::Path &aOutPath,
CBBOX2D &aOutBBox,
float aBiuTo3DunitsScale )
{
aOutPath.resize( aPolygon.size() );
aOutBBox.Reset();
for( unsigned i = 0; i < aPolygon.size(); i++ )
{
const KI_POLY_POINT point = *(aPolygon.begin() + i);
aOutPath[i] = ClipperLib::IntPoint( (ClipperLib::cInt)point.x(),
(ClipperLib::cInt)point.y() );
aOutBBox.Union( SFVEC2F( (float) point.x() * aBiuTo3DunitsScale,
(float)-point.y() * aBiuTo3DunitsScale ) );
}
aOutBBox.ScaleNextUp();
ClipperLib::CleanPolygon( aOutPath );
}
#ifdef DEBUG
static void polygon_Convert( const ClipperLib::Path &aPath,
SEGMENTS &aOutSegment,
float aBiuTo3DunitsScale )
{
aOutSegment.resize( aPath.size() );
for( unsigned i = 0; i < aPath.size(); i++ )
{
aOutSegment[i].m_Start = SFVEC2F( (float) aPath[i].X * aBiuTo3DunitsScale,
(float)-aPath[i].Y * aBiuTo3DunitsScale );
}
unsigned int i;
unsigned int j = aOutSegment.size () - 1;
for( i = 0; i < aOutSegment.size (); j = i++ )
{
// Calculate constants for each segment
aOutSegment[i].m_inv_JY_minus_IY = 1.0f / ( aOutSegment[j].m_Start.y -
aOutSegment[i].m_Start.y );
aOutSegment[i].m_JX_minus_IX = (aOutSegment[j].m_Start.x - aOutSegment[i].m_Start.x);
}
}
void Polygon2d_TestModule()
{
// "This structure contains a sequence of IntPoint vertices defining a
// single contour"
ClipperLib::Path aPath;
SEGMENTS aSegments;
aPath.resize( 4 );
aPath[0] = ClipperLib::IntPoint( -2, -2 );
aPath[1] = ClipperLib::IntPoint( 2, -2 );
aPath[2] = ClipperLib::IntPoint( 2, 2 );
aPath[3] = ClipperLib::IntPoint( -2, 2 );
// It must be an outter polygon
wxASSERT( ClipperLib::Orientation( aPath ) );
polygon_Convert( aPath, aSegments, 1.0f );
wxASSERT( aPath.size() == aSegments.size() );
wxASSERT( aSegments[0].m_Start == SFVEC2F( -2.0f, 2.0f ) );
wxASSERT( aSegments[1].m_Start == SFVEC2F( 2.0f, 2.0f ) );
wxASSERT( aSegments[2].m_Start == SFVEC2F( 2.0f, -2.0f ) );
wxASSERT( aSegments[3].m_Start == SFVEC2F( -2.0f, -2.0f ) );
wxASSERT( polygon_IsPointInside( aSegments, SFVEC2F( 0.0f, 0.0f ) ) );
wxASSERT( polygon_IsPointInside( aSegments, SFVEC2F( -1.9f, -1.9f ) ) );
wxASSERT( polygon_IsPointInside( aSegments, SFVEC2F( -1.9f, 1.9f ) ) );
wxASSERT( polygon_IsPointInside( aSegments, SFVEC2F( 1.9f, 1.9f ) ) );
wxASSERT( polygon_IsPointInside( aSegments, SFVEC2F( 1.9f, -1.9f ) ) );
wxASSERT( polygon_IsPointInside( aSegments, SFVEC2F( -2.1f, -2.0f ) ) == false );
wxASSERT( polygon_IsPointInside( aSegments, SFVEC2F( -2.1f, 2.0f ) ) == false );
wxASSERT( polygon_IsPointInside( aSegments, SFVEC2F( 2.1f, 2.0f ) ) == false );
wxASSERT( polygon_IsPointInside( aSegments, SFVEC2F( 2.1f, -2.0f ) ) == false );
}
#endif

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -84,7 +84,7 @@ typedef struct
/// polygons. This polygon class represent a sub part of that main polygon.
/// There is information for the contours (used to test the ray2d intersection)
/// and a close definition of the block polygon to test if a point is inside.
class GLM_ALIGN(CLASS_ALIGNMENT) CPOLYGONBLOCK2D : public COBJECT2D
class CPOLYGONBLOCK2D : public COBJECT2D
{
private:
/// This is the outter part of the polygon. This list is used to test a ray
@ -115,11 +115,14 @@ public:
/// a ray will return allways false.
/// This is used as a sub block extrated from polygon (pcb polygon areas) and
/// represents an area that is full filled.
class GLM_ALIGN(CLASS_ALIGNMENT) CDUMMYBLOCK2D : public COBJECT2D
class CDUMMYBLOCK2D : public COBJECT2D
{
public:
CDUMMYBLOCK2D(const SFVEC2F &aPbMin, const SFVEC2F &aPbMax , const BOARD_ITEM &aBoardItem );
CDUMMYBLOCK2D( const SFVEC2F &aPbMin,
const SFVEC2F &aPbMax,
const BOARD_ITEM &aBoardItem );
CDUMMYBLOCK2D( const CBBOX2D &aBBox, const BOARD_ITEM &aBoardItem );
// Imported from COBJECT2D
@ -138,16 +141,24 @@ public:
* @param aMainPath - the polygon are that was converted from the pcb board
* @param aDstContainer - the destination container to put the created sub blocks
* @param aBiuTo3DunitsScale - the rendering target 3d scale
* @param aDivFactor - a division factor (in 3Dunits) to divide the polygon plane, 0.0f will use the internal polygon segm statistics
* @param aDivFactor - a division factor (in 3Dunits) to divide the polygon plane,
* 0.0f will use the internal polygon segm statistics
*/
void Convert_path_polygon_to_polygon_blocks_and_dummy_blocks(const SHAPE_POLY_SET &aMainPath,
void Convert_path_polygon_to_polygon_blocks_and_dummy_blocks(
const SHAPE_POLY_SET &aMainPath,
CGENERICCONTAINER2D &aDstContainer,
float aBiuTo3DunitsScale,
float aDivFactor,
const BOARD_ITEM &aBoardItem );
void Polygon_Calc_BBox_3DU(const SHAPE_POLY_SET &aPolysList, CBBOX2D &aOutBBox , float aBiuTo3DunitsScale );
void Polygon_Convert( const KI_POLYGON &aPolygon, ClipperLib::Path &aOutPath, CBBOX2D &aOutBBox, float aBiuTo3DunitsScale );
void Polygon_Calc_BBox_3DU( const SHAPE_POLY_SET &aPolysList,
CBBOX2D &aOutBBox,
float aBiuTo3DunitsScale );
void Polygon_Convert( const KI_POLYGON &aPolygon,
ClipperLib::Path &aOutPath,
CBBOX2D &aOutBBox,
float aBiuTo3DunitsScale );
void Polygon2d_TestModule();

View File

@ -0,0 +1,212 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file cpolygon4pts2d.cpp
* @brief
*/
#include "cpolygon4pts2d.h"
#include <wx/debug.h>
CPOLYGON4PTS2D::CPOLYGON4PTS2D( const SFVEC2F &v1,
const SFVEC2F &v2,
const SFVEC2F &v3,
const SFVEC2F &v4,
const BOARD_ITEM &aBoardItem ) :
COBJECT2D( OBJ2D_POLYGON4PT, aBoardItem )
{/*
if( (v1.x > v2.x) || (v1.y < v2.y) )
{
m_segments[0] = v4;
m_segments[1] = v3;
m_segments[2] = v2;
m_segments[3] = v1;
}
else
{*/
m_segments[0] = v1;
m_segments[1] = v4;
m_segments[2] = v3;
m_segments[3] = v2;
// }
unsigned int i;
unsigned int j = 4 - 1;
for( i = 0; i < 4; j = i++ )
{
SFVEC2F slope = m_segments[j] - m_segments[i];
m_precalc_slope[i] = slope;
m_seg_normal[i] = glm::normalize( SFVEC2F( -slope.y, +slope.x ) );
}
m_bbox.Reset();
m_bbox.Union( v1 );
m_bbox.Union( v2 );
m_bbox.Union( v3 );
m_bbox.Union( v4 );
m_bbox.ScaleNextUp();
m_bbox.ScaleNextUp();
m_bbox.ScaleNextUp();
m_bbox.ScaleNextUp();
m_bbox.ScaleNextUp();
m_centroid = m_bbox.GetCenter();
wxASSERT( m_bbox.IsInitialized() );
}
bool CPOLYGON4PTS2D::Intersects( const CBBOX2D &aBBox ) const
{
return m_bbox.Intersects( aBBox );
// This source code is not working OK.
/*
if( !m_bbox.Intersects( aBBox ) )
return false;
// Check if the bouding box complety have inside the small bouding box
if( (aBBox.Max().x > m_bbox.Max().x) &&
(aBBox.Max().y > m_bbox.Max().x) &&
(aBBox.Min().x < m_bbox.Min().x) &&
(aBBox.Min().y < m_bbox.Min().y)
)
return true;
SFVEC2F v[4];
v[0] = aBBox.Min();
v[1] = SFVEC2F( aBBox.Min().x, aBBox.Max().y );
v[2] = aBBox.Max();
v[3] = SFVEC2F( aBBox.Max().x, aBBox.Min().y );
for( unsigned int i = 0; i < 4; i++ )
{
if( IntersectSegment( m_segments[i], m_precalc_slope[i], v[0], v[1] - v[0] ) )
return true;
if( IntersectSegment( m_segments[i], m_precalc_slope[i], v[1], v[2] - v[1] ) )
return true;
if( IntersectSegment( m_segments[i], m_precalc_slope[i], v[2], v[3] - v[2] ) )
return true;
if( IntersectSegment( m_segments[i], m_precalc_slope[i], v[3], v[0] - v[3] ) )
return true;
}
if( IsPointInside( v[0] ) )
return true;
if( IsPointInside( v[1] ) )
return true;
if( IsPointInside( v[2] ) )
return true;
if( IsPointInside( v[3] ) )
return true;
return false;*/
}
bool CPOLYGON4PTS2D::Overlaps( const CBBOX2D &aBBox ) const
{
// NOT IMPLEMENTED
return true;
}
bool CPOLYGON4PTS2D::Intersect( const RAYSEG2D &aSegRay,
float *aOutT,
SFVEC2F *aNormalOut ) const
{
wxASSERT( aOutT );
wxASSERT( aNormalOut );
bool hited = false;
unsigned int hitIndex;
float bestHitT;
for( unsigned int i = 0; i < 4; i++ )
{
float t;
if( aSegRay.IntersectSegment( m_segments[i], m_precalc_slope[i], &t ) )
if( (hited == false) || ( t < bestHitT) )
{
hited = true;
hitIndex = i;
bestHitT = t;
}
}
if( hited )
{
wxASSERT( (bestHitT >= 0.0f) && (bestHitT <= 1.0f) );
*aOutT = bestHitT;
*aNormalOut = m_seg_normal[hitIndex];
return true;
}
return false;
}
INTERSECTION_RESULT CPOLYGON4PTS2D::IsBBoxInside( const CBBOX2D &aBBox ) const
{
// !TODO:
return INTR_MISSES;
}
bool CPOLYGON4PTS2D::IsPointInside( const SFVEC2F &aPoint ) const
{
unsigned int i;
unsigned int j = 4 - 1;
bool oddNodes = false;
for( i = 0; i < 4; j = i++ )
{
const float polyJY = m_segments[j].y;
const float polyIY = m_segments[i].y;
if( ((polyIY <= aPoint.y) && (polyJY >= aPoint.y)) ||
((polyJY <= aPoint.y) && (polyIY >= aPoint.y))
)
{
const float polyJX = m_segments[j].x;
const float polyIX = m_segments[i].x;
if( (polyIX <= aPoint.x) || (polyJX <= aPoint.x) )
{
oddNodes ^= ( ( polyIX +
( ( aPoint.y - polyIY ) / ( polyJY - polyIY ) ) *
( polyJX - polyIX ) ) < aPoint.x );
}
}
}
return oddNodes;
}

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -37,7 +37,7 @@
* (rectangles, trapezoids, with rotation.etc)
* This is a simplified version of the cpolygon2d class
*/
class GLM_ALIGN(CLASS_ALIGNMENT) CPOLYGON4PTS2D : public COBJECT2D
class CPOLYGON4PTS2D : public COBJECT2D
{
private:
SFVEC2F m_segments[4];

View File

@ -0,0 +1,196 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file cring2d.cpp
* @brief
*/
#include "cring2d.h"
#include "../../../3d_fastmath.h"
#include <wx/debug.h>
CRING2D::CRING2D( const SFVEC2F &aCenter, float aInnerRadius, float aOuterRadius,
const BOARD_ITEM &aBoardItem ) : COBJECT2D( OBJ2D_RING, aBoardItem )
{
wxASSERT( aInnerRadius < aOuterRadius );
m_center = aCenter;
m_inner_radius = aInnerRadius;
m_outer_radius = aOuterRadius;
m_inner_radius_squared = aInnerRadius * aInnerRadius;
m_outer_radius_squared = aOuterRadius * aOuterRadius;
m_bbox.Reset();
m_bbox.Set( m_center - SFVEC2F( aOuterRadius, aOuterRadius ),
m_center + SFVEC2F( aOuterRadius, aOuterRadius ) );
m_bbox.ScaleNextUp();
m_centroid = m_bbox.GetCenter();
wxASSERT( m_bbox.IsInitialized() );
}
bool CRING2D::Overlaps( const CBBOX2D &aBBox ) const
{
// NOT IMPLEMENTED
return false;
}
bool CRING2D::Intersects( const CBBOX2D &aBBox ) const
{
// !TODO: check the inside for a great improovment
return aBBox.Intersects( m_center, m_outer_radius_squared );
}
bool CRING2D::Intersect( const RAYSEG2D &aSegRay,
float *aOutT,
SFVEC2F *aNormalOut ) const
{
// This code used directly from Steve Marschner's CS667 framework
// http://cs665pd.googlecode.com/svn/trunk/photon/sphere.cpp
// Compute some factors used in computation
const float qx = (aSegRay.m_Start.x - m_center.x);
const float qy = (aSegRay.m_Start.y - m_center.y);
const float qd = qx * aSegRay.m_Dir.x + qy * aSegRay.m_Dir.y;
const float qq = qx * qx + qy * qy;
// solving the quadratic equation for t at the pts of intersection
// dd*t^2 + (2*qd)*t + (qq-r^2) = 0
const float discriminantsqr = qd * qd - qq;
const float discriminantsqr_outter = discriminantsqr + m_outer_radius_squared;
// If the discriminant is less than zero, there is no intersection
if( discriminantsqr_outter < FLT_EPSILON )
return false;
// Otherwise check and make sure that the intersections occur on the ray (t
// > 0) and return the closer one
const float discriminant = sqrt( discriminantsqr_outter );
float t = (-qd - discriminant);
if( (t > FLT_EPSILON) && (t < aSegRay.m_Length) )
{
SFVEC2F hitPoint = aSegRay.at( t );
*aNormalOut = (hitPoint - m_center) / m_outer_radius;
}
else
{
const float discriminantsqr_inter = discriminantsqr + m_inner_radius_squared;
if( discriminantsqr_inter > FLT_EPSILON )
{
const float discriminant_inner = sqrt( discriminantsqr_inter );
const float t2_inner = (-qd + discriminant_inner);
if( (t2_inner > FLT_EPSILON) && (t2_inner < aSegRay.m_Length) )
{
t = t2_inner;
const SFVEC2F hitPoint = aSegRay.at( t2_inner );
*aNormalOut = (m_center - hitPoint) / m_inner_radius;
}
else
return false;
}
else
return false;
}
wxASSERT( (t > 0.0f) && (t <= aSegRay.m_Length) );
// Convert the intersection to a normalized 0.0 .. 1.0
*aOutT = t / aSegRay.m_Length;
return true;
}
INTERSECTION_RESULT CRING2D::IsBBoxInside( const CBBOX2D &aBBox ) const
{
/*
if( !m_bbox.Overlaps( aBBox ) )
return INTR_MISSES;
SFVEC2F v[4];
v[0] = aBBox.Min() - m_center;
v[1] = aBBox.Max() - m_center;
v[2] = SFVEC2F( aBBox.Min().x, aBBox.Max().y ) - m_center;
v[3] = SFVEC2F( aBBox.Max().x, aBBox.Min().y ) - m_center;
float s[4];
s[0] = v[0].x * v[0].x + v[0].y * v[0].y;
s[1] = v[1].x * v[1].x + v[1].y * v[1].y;
s[2] = v[2].x * v[2].x + v[2].y * v[2].y;
s[3] = v[3].x * v[3].x + v[3].y * v[3].y;
bool isInside[4];
isInside[0] = s[0] <= m_radius_squared;
isInside[1] = s[1] <= m_radius_squared;
isInside[2] = s[2] <= m_radius_squared;
isInside[3] = s[3] <= m_radius_squared;
// Check if all points are inside the circle
if( isInside[0] &&
isInside[1] &&
isInside[2] &&
isInside[3] )
return INTR_FULL_INSIDE;
// Check if any point is inside the circle
if( isInside[0] ||
isInside[1] ||
isInside[2] ||
isInside[3] )
return INTR_INTERSECTS;
*/
return INTR_MISSES;
}
bool CRING2D::IsPointInside( const SFVEC2F &aPoint ) const
{
const SFVEC2F v = m_center - aPoint;
const float dot = glm::dot( v, v );
if( (dot <= m_outer_radius_squared) &&
(dot >= m_inner_radius_squared) )
return true;
return false;
}

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -32,7 +32,7 @@
#include "cobject2d.h"
class GLM_ALIGN(CLASS_ALIGNMENT) CRING2D : public COBJECT2D
class CRING2D : public COBJECT2D
{
public:
const SFVEC2F &GetCenter() const { return m_center; }

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -31,30 +31,38 @@
#include <wx/debug.h>
CROUNDSEGMENT2D::CROUNDSEGMENT2D( const SFVEC2F &aStart, const SFVEC2F &aEnd, float aWidth,
CROUNDSEGMENT2D::CROUNDSEGMENT2D( const SFVEC2F &aStart,
const SFVEC2F &aEnd,
float aWidth,
const BOARD_ITEM &aBoardItem ) :
COBJECT2D( OBJ2D_ROUNDSEG, aBoardItem ),
m_segment( aStart, aEnd )
{
wxASSERT( aStart != aEnd );
m_radius = (aWidth / 2.0f);
m_radius_squared = m_radius * m_radius;
m_width = aWidth;
SFVEC2F leftRadiusOffset( -m_segment.m_Dir.y * m_radius, m_segment.m_Dir.x * m_radius);
SFVEC2F leftRadiusOffset( -m_segment.m_Dir.y * m_radius,
m_segment.m_Dir.x * m_radius );
m_leftStart = aStart + leftRadiusOffset;
m_leftEnd = aEnd + leftRadiusOffset;
m_leftEnd_minus_start = m_leftEnd - m_leftStart;
m_leftDir = glm::normalize( m_leftEnd_minus_start );
m_leftEndMinusStart = m_leftEnd - m_leftStart;
m_leftDir = glm::normalize( m_leftEndMinusStart );
SFVEC2F rightRadiusOffset( -leftRadiusOffset.x, -leftRadiusOffset.y );
SFVEC2F rightRadiusOffset( -leftRadiusOffset.x,
-leftRadiusOffset.y );
m_rightStart = aEnd + rightRadiusOffset;
m_rightEnd = aStart + rightRadiusOffset;
m_rightEnd_minus_start = m_rightEnd - m_rightStart;
m_rightDir = glm::normalize( m_rightEnd_minus_start );
m_rightEndMinusStart = m_rightEnd - m_rightStart;
m_rightDir = glm::normalize( m_rightEndMinusStart );
m_bbox.Reset();
m_bbox.Set( aStart, aEnd );
m_bbox.Set( m_bbox.Min() - SFVEC2F( m_radius, m_radius ), m_bbox.Max() + SFVEC2F( m_radius, m_radius ) );
m_bbox.Set( m_bbox.Min() - SFVEC2F( m_radius, m_radius ),
m_bbox.Max() + SFVEC2F( m_radius, m_radius ) );
m_bbox.ScaleNextUp();
m_centroid = m_bbox.GetCenter();
@ -82,19 +90,37 @@ bool CROUNDSEGMENT2D::Intersects( const CBBOX2D &aBBox ) const
v[3] = SFVEC2F( aBBox.Max().x, aBBox.Min().y );
// Test against the main rectangle segment
if( IntersectSegment( m_leftStart, m_leftEnd_minus_start, v[0], v[1] - v[0] ) ) return true;
if( IntersectSegment( m_leftStart, m_leftEnd_minus_start, v[1], v[2] - v[1] ) ) return true;
if( IntersectSegment( m_leftStart, m_leftEnd_minus_start, v[2], v[3] - v[2] ) ) return true;
if( IntersectSegment( m_leftStart, m_leftEnd_minus_start, v[3], v[0] - v[3] ) ) return true;
if( IntersectSegment( m_leftStart, m_leftEndMinusStart, v[0], v[1] - v[0] ) )
return true;
if( IntersectSegment( m_rightStart, m_rightEnd_minus_start, v[0], v[1] - v[0] ) ) return true;
if( IntersectSegment( m_rightStart, m_rightEnd_minus_start, v[1], v[2] - v[1] ) ) return true;
if( IntersectSegment( m_rightStart, m_rightEnd_minus_start, v[2], v[3] - v[2] ) ) return true;
if( IntersectSegment( m_rightStart, m_rightEnd_minus_start, v[3], v[0] - v[3] ) ) return true;
if( IntersectSegment( m_leftStart, m_leftEndMinusStart, v[1], v[2] - v[1] ) )
return true;
if( IntersectSegment( m_leftStart, m_leftEndMinusStart, v[2], v[3] - v[2] ) )
return true;
if( IntersectSegment( m_leftStart, m_leftEndMinusStart, v[3], v[0] - v[3] ) )
return true;
if( IntersectSegment( m_rightStart, m_rightEndMinusStart, v[0], v[1] - v[0] ) )
return true;
if( IntersectSegment( m_rightStart, m_rightEndMinusStart, v[1], v[2] - v[1] ) )
return true;
if( IntersectSegment( m_rightStart, m_rightEndMinusStart, v[2], v[3] - v[2] ) )
return true;
if( IntersectSegment( m_rightStart, m_rightEndMinusStart, v[3], v[0] - v[3] ) )
return true;
// Test the two circles
if( aBBox.Intersects( m_segment.m_Start, m_radius_squared ) ) return true;
if( aBBox.Intersects( m_segment.m_End, m_radius_squared ) ) return true;
if( aBBox.Intersects( m_segment.m_Start, m_radius_squared ) )
return true;
if( aBBox.Intersects( m_segment.m_End, m_radius_squared ) )
return true;
return false;
}
@ -107,13 +133,15 @@ bool CROUNDSEGMENT2D::Overlaps( const CBBOX2D &aBBox ) const
}
bool CROUNDSEGMENT2D::Intersect( const RAYSEG2D &aSegRay, float *aOutT, SFVEC2F *aNormalOut ) const
bool CROUNDSEGMENT2D::Intersect( const RAYSEG2D &aSegRay,
float *aOutT,
SFVEC2F *aNormalOut ) const
{
wxASSERT( aOutT );
wxASSERT( aNormalOut );
bool start_is_inside = IsPointInside( aSegRay.m_Start );
bool end_is_inside = IsPointInside( aSegRay.m_End );
const bool start_is_inside = IsPointInside( aSegRay.m_Start );
const bool end_is_inside = IsPointInside( aSegRay.m_End );
// If segment if inside there are no hits
if( start_is_inside && end_is_inside )
@ -128,7 +156,9 @@ bool CROUNDSEGMENT2D::Intersect( const RAYSEG2D &aSegRay, float *aOutT, SFVEC2F
SFVEC2F farHitNormal;
float leftSegT;
bool leftSegmentHit = aSegRay.IntersectSegment( m_leftStart, m_leftEnd_minus_start, &leftSegT );
const bool leftSegmentHit = aSegRay.IntersectSegment( m_leftStart,
m_leftEndMinusStart,
&leftSegT );
if( leftSegmentHit )
{
@ -141,7 +171,9 @@ bool CROUNDSEGMENT2D::Intersect( const RAYSEG2D &aSegRay, float *aOutT, SFVEC2F
}
float rightSegT;
bool rightSegmentHit = aSegRay.IntersectSegment( m_rightStart, m_rightEnd_minus_start, &rightSegT );
const bool rightSegmentHit = aSegRay.IntersectSegment( m_rightStart,
m_rightEndMinusStart,
&rightSegT );
if( rightSegmentHit )
{
@ -167,9 +199,9 @@ bool CROUNDSEGMENT2D::Intersect( const RAYSEG2D &aSegRay, float *aOutT, SFVEC2F
SFVEC2F circleStart_N0;
SFVEC2F circleStart_N1;
bool startCircleHit = aSegRay.IntersectCircle( m_segment.m_Start, m_radius,
&circleStart_T0, &circleStart_T1,
&circleStart_N0, &circleStart_N1 );
const bool startCircleHit = aSegRay.IntersectCircle( m_segment.m_Start, m_radius,
&circleStart_T0, &circleStart_T1,
&circleStart_N0, &circleStart_N1 );
if( startCircleHit )
{
@ -207,9 +239,9 @@ bool CROUNDSEGMENT2D::Intersect( const RAYSEG2D &aSegRay, float *aOutT, SFVEC2F
SFVEC2F circleEnd_N0;
SFVEC2F circleEnd_N1;
bool rightCircleHit = aSegRay.IntersectCircle( m_segment.m_End, m_radius,
&circleEnd_T0, &circleEnd_T1,
&circleEnd_N0, &circleEnd_N1 );
const bool rightCircleHit = aSegRay.IntersectCircle( m_segment.m_End, m_radius,
&circleEnd_T0, &circleEnd_T1,
&circleEnd_N0, &circleEnd_N1 );
if( rightCircleHit )
{
if( circleEnd_T0 > 0.0f )
@ -251,9 +283,10 @@ bool CROUNDSEGMENT2D::Intersect( const RAYSEG2D &aSegRay, float *aOutT, SFVEC2F
}
else
{
wxASSERT( (farHitT > 0.0f) && (farHitT <= 1.0f) );
wxASSERT( (farHitT >= 0.0f) && (farHitT <= 1.0f) );
*aOutT = farHitT;
*aNormalOut = farHitNormal;
*aNormalOut = -farHitNormal; // the normal started inside, so invert it
}
}

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -32,7 +32,7 @@
#include "cobject2d.h"
class GLM_ALIGN(CLASS_ALIGNMENT) CROUNDSEGMENT2D : public COBJECT2D
class CROUNDSEGMENT2D : public COBJECT2D
{
friend class CROUNDSEG;
@ -42,12 +42,12 @@ private:
SFVEC2F m_leftStart;
SFVEC2F m_leftEnd;
SFVEC2F m_leftEnd_minus_start;
SFVEC2F m_leftEndMinusStart;
SFVEC2F m_leftDir;
SFVEC2F m_rightStart;
SFVEC2F m_rightEnd;
SFVEC2F m_rightEnd_minus_start;
SFVEC2F m_rightEndMinusStart;
SFVEC2F m_rightDir;
float m_radius;
@ -69,12 +69,12 @@ public:
const SFVEC2F &GetLeftStar() const { return m_leftStart; }
const SFVEC2F &GetLeftEnd() const { return m_leftEnd; }
const SFVEC2F &GetLeftEnd_minus_Start() const { return m_leftEnd_minus_start; }
const SFVEC2F &GetLeftEnd_minus_Start() const { return m_leftEndMinusStart; }
const SFVEC2F &GetLeftDir() const { return m_leftDir; }
const SFVEC2F &GetRightStar() const { return m_rightStart; }
const SFVEC2F &GetRightEnd() const { return m_rightEnd; }
const SFVEC2F &GetRightEnd_minus_Start() const { return m_rightEnd_minus_start; }
const SFVEC2F &GetRightEnd_minus_Start() const { return m_rightEndMinusStart; }
const SFVEC2F &GetRightDir() const { return m_rightDir; }
// Imported from COBJECT2D
@ -85,5 +85,23 @@ public:
bool IsPointInside( const SFVEC2F &aPoint ) const;
};
static const float s_min_dot = (FLT_EPSILON * 4.0f) ;
/**
* @brief Segment_is_a_circle - check if segment start and end is very close to each other
* should used to check if the segment should be converted to a circle instead
* @param aStart
* @param aEnd
* @return true is it is better to convert the segment to circle
*/
inline bool Is_segment_a_circle( const SFVEC2F &aStart, const SFVEC2F &aEnd )
{
const SFVEC2F vec = aEnd - aStart;
return (aStart == aEnd) ||
// This is the same as calc the lenght squared (without the sqrt)
// and compare with a small value
( glm::dot( vec, vec ) <= s_min_dot );
}
#endif // _CROUNDSEGMENT2D_H_

View File

@ -0,0 +1,316 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file ctriangle2d.cpp
* @brief
*/
#include "ctriangle2d.h"
#include <map>
#include <boost/smart_ptr/shared_ptr.hpp>
#include <boost/smart_ptr/shared_array.hpp>
#include <wx/debug.h>
#include <wx/glcanvas.h> // CALLBACK definition, needed on Windows
// alse needed on OSX to define __DARWIN__
#include "../../../3d_fastmath.h"
#include <poly2tri/poly2tri.h>
CTRIANGLE2D::CTRIANGLE2D ( const SFVEC2F &aV1,
const SFVEC2F &aV2,
const SFVEC2F &aV3,
const BOARD_ITEM &aBoardItem ) : COBJECT2D( OBJ2D_TRIANGLE,
aBoardItem )
{
p1 = aV1;
p2 = aV2;
p3 = aV3;
// Pre-Calc values
m_inv_denominator = 1.0f / ( (p2.y - p3.y) * (p1.x - p3.x) +
(p3.x - p2.x) * (p1.y - p3.y));
m_p2y_minus_p3y = (p2.y - p3.y);
m_p3x_minus_p2x = (p3.x - p2.x);
m_p3y_minus_p1y = (p3.y - p1.y);
m_p1x_minus_p3x = (p1.x - p3.x);
m_bbox.Reset();
m_bbox.Union( aV1 );
m_bbox.Union( aV2 );
m_bbox.Union( aV3 );
m_bbox.ScaleNextUp();
m_centroid = m_bbox.GetCenter();
wxASSERT( m_bbox.IsInitialized() );
}
bool CTRIANGLE2D::Intersects( const CBBOX2D &aBBox ) const
{
if( !m_bbox.Intersects( aBBox ) )
return false;
//!TODO: Optimize
return true;
}
bool CTRIANGLE2D::Overlaps( const CBBOX2D &aBBox ) const
{
// NOT IMPLEMENTED
return false;
}
bool CTRIANGLE2D::Intersect( const RAYSEG2D &aSegRay,
float *aOutT,
SFVEC2F *aNormalOut ) const
{
wxASSERT( aOutT );
wxASSERT( aNormalOut );
return false;
}
INTERSECTION_RESULT CTRIANGLE2D::IsBBoxInside( const CBBOX2D &aBBox ) const
{
if( !m_bbox.Intersects( aBBox ) )
return INTR_MISSES;
// !TODO:
return INTR_MISSES;
}
bool CTRIANGLE2D::IsPointInside( const SFVEC2F &aPoint ) const
{
// http://totologic.blogspot.co.uk/2014/01/accurate-point-in-triangle-test.html
SFVEC2F point_minus_p3 = aPoint - p3;
// barycentric coordinate system
const float a = ( m_p2y_minus_p3y * point_minus_p3.x +
m_p3x_minus_p2x * point_minus_p3.y ) * m_inv_denominator;
if( 0.0f > a || a > 1.0f )
return false;
const float b = ( m_p3y_minus_p1y * point_minus_p3.x +
m_p1x_minus_p3x * point_minus_p3.y ) * m_inv_denominator;
if( 0.0f > b || b > 1.0f )
return false;
const float c = 1.0f - a - b;
return 0.0f <= c && c <= 1.0f;
/*
return 0.0f <= a && a <= 1.0f &&
0.0f <= b && b <= 1.0f &&
0.0f <= c && c <= 1.0f;*/
}
template <class C> void FreeClear( C & cntr )
{
for( typename C::iterator it = cntr.begin();
it != cntr.end();
++it )
{
delete * it;
}
cntr.clear();
}
// Note: Please check edgeshrink.cpp in order to learn the EdgeShrink propose
#define APPLY_EDGE_SHRINK
#ifdef APPLY_EDGE_SHRINK
extern void EdgeShrink( std::vector<SFVEC2I64> &aPath );
#define POLY_SCALE_FACT 256
#define POLY_SCALE_FACT_INVERSE (1.0 / (double)(POLY_SCALE_FACT))
#endif
void Convert_shape_line_polygon_to_triangles( const SHAPE_POLY_SET &aPolyList,
CGENERICCONTAINER2D &aDstContainer,
float aBiuTo3DunitsScale ,
const BOARD_ITEM &aBoardItem )
{
unsigned int nOutlines = aPolyList.OutlineCount();
for( unsigned int idx = 0; idx < nOutlines; ++idx )
{
const SHAPE_LINE_CHAIN &outlinePath = aPolyList.COutline( idx );
wxASSERT( outlinePath.PointCount() >= 3 );
std::vector<SFVEC2I64> scaledOutline;
scaledOutline.resize( outlinePath.PointCount() );
// printf("\nidx: %u\n", idx);
// Apply a scale to the points
for( unsigned int i = 0;
i < (unsigned int)outlinePath.PointCount();
++i )
{
const VECTOR2I& a = outlinePath.CPoint( i );
#ifdef APPLY_EDGE_SHRINK
scaledOutline[i] = SFVEC2I64( (glm::int64)a.x * POLY_SCALE_FACT,
(glm::int64)a.y * POLY_SCALE_FACT );
#else
scaledOutline[i] = SFVEC2I64( (glm::int64)a.x,
(glm::int64)a.y );
#endif
}
#ifdef APPLY_EDGE_SHRINK
// Apply a modification to the points
EdgeShrink( scaledOutline );
#endif
// Copy to a array of pointers
std::vector<p2t::Point*> polyline;
polyline.resize( outlinePath.PointCount() );
for( unsigned int i = 0;
i < (unsigned int)scaledOutline.size();
++i )
{
const SFVEC2I64 &a = scaledOutline[i];
//printf("%lu %lu\n", a.x, a.y);
polyline[i] = new p2t::Point( (double)a.x,
(double)a.y );
}
// Start creating the structured to be triangulated
p2t::CDT* cdt = new p2t::CDT( polyline );
// Add holes for this outline
unsigned int nHoles = aPolyList.HoleCount( idx );
std::vector< std::vector<p2t::Point*> > polylineHoles;
polylineHoles.resize( nHoles );
for( unsigned int idxHole = 0; idxHole < nHoles; ++idxHole )
{
const SHAPE_LINE_CHAIN &outlineHoles = aPolyList.CHole( idx,
idxHole );
wxASSERT( outlineHoles.PointCount() >= 3 );
std::vector<SFVEC2I64> scaledHole;
scaledHole.resize( outlineHoles.PointCount() );
// Apply a scale to the points
for( unsigned int i = 0;
i < (unsigned int)outlineHoles.PointCount();
++i )
{
const VECTOR2I &h = outlineHoles.CPoint( i );
#ifdef APPLY_EDGE_SHRINK
scaledHole[i] = SFVEC2I64( (glm::int64)h.x * POLY_SCALE_FACT,
(glm::int64)h.y * POLY_SCALE_FACT );
#else
scaledHole[i] = SFVEC2I64( (glm::int64)h.x,
(glm::int64)h.y );
#endif
}
#ifdef APPLY_EDGE_SHRINK
// Apply a modification to the points
EdgeShrink( scaledHole );
#endif
// Resize and reserve space
polylineHoles[idxHole].resize( outlineHoles.PointCount() );
for( unsigned int i = 0;
i < (unsigned int)outlineHoles.PointCount();
++i )
{
const SFVEC2I64 &h = scaledHole[i];
polylineHoles[idxHole][i] = new p2t::Point( h.x, h.y );
}
cdt->AddHole( polylineHoles[idxHole] );
}
// Triangulate
cdt->Triangulate();
// Hint: if you find any crashes on the triangulation poly2tri library,
// you can use the following site to debug the points and it will mark
// the errors in the polygon:
// http://r3mi.github.io/poly2tri.js/
// Get and add triangles
std::vector<p2t::Triangle*> triangles;
triangles = cdt->GetTriangles();
#ifdef APPLY_EDGE_SHRINK
const double conver_d = (double)aBiuTo3DunitsScale *
POLY_SCALE_FACT_INVERSE;
#else
const double conver_d = (double)aBiuTo3DunitsScale;
#endif
for( unsigned int i = 0; i < triangles.size(); ++i )
{
p2t::Triangle& t = *triangles[i];
p2t::Point& a = *t.GetPoint( 0 );
p2t::Point& b = *t.GetPoint( 1 );
p2t::Point& c = *t.GetPoint( 2 );
aDstContainer.Add( new CTRIANGLE2D( SFVEC2F( a.x * conver_d,
-a.y * conver_d ),
SFVEC2F( b.x * conver_d,
-b.y * conver_d ),
SFVEC2F( c.x * conver_d,
-c.y * conver_d ),
aBoardItem ) );
}
// Delete created data
delete cdt;
// Free points
FreeClear(polyline);
for( unsigned int idxHole = 0; idxHole < nHoles; ++idxHole )
{
FreeClear( polylineHoles[idxHole] );
}
}
}

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -36,7 +36,7 @@
#include <geometry/shape_poly_set.h>
#include <clipper.hpp>
class GLM_ALIGN(CLASS_ALIGNMENT) CTRIANGLE2D : public COBJECT2D
class CTRIANGLE2D : public COBJECT2D
{
private:
SFVEC2F p1;

View File

@ -0,0 +1,89 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file edgeshrink.cpp
* @brief The edgeShrink function was found in the project clip2tri by the:
* Bitfighter project (http://bitfighter.org)
* https://github.com/raptor/clip2tri
* https://github.com/raptor/clip2tri/blob/f62a734d22733814b8a970ed8a68a4d94c24fa5f/clip2tri/clip2tri.cpp#L150
*/
#include <plugins/3dapi/xv3d_types.h>
#include <vector>
// clip2tri is Licenced under:
// The MIT License (MIT)
// Copyright (c) 2014 Bitfighter developers
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// Shrink large polygons by reducing each coordinate by 1 in the
// general direction of the last point as we wind around
//
// This normally wouldn't work in every case, but our upscaled-by-1000 polygons
// have little chance to create new duplicate points with this method.
//
// For information on why this was needed, see:
//
// https://github.com/greenm01/poly2tri/issues/90
//
#define S_INC 1
void EdgeShrink( std::vector<SFVEC2I64> &aPath )
{
unsigned int prev = aPath.size() - 1;
for( unsigned int i = 0; i < aPath.size(); i++ )
{
// Adjust coordinate by 1 depending on the direction
(aPath[i].x - aPath[prev].x) > 0 ? aPath[i].x -= S_INC :
aPath[i].x += S_INC;
(aPath[i].y - aPath[prev].y) > 0 ? aPath[i].y -= S_INC :
aPath[i].y += S_INC;
prev = i;
}
}

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@gmail.com>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -26,11 +26,11 @@
* @file cbbox.cpp
* @brief Bounding Box class implementation
*/
#include "3d_math/3d_fastmath.h"
#include "3d_fastmath.h"
#include "cbbox.h"
#include <stdio.h>
#include <wx/debug.h> // For the wxASSERT
#include <wx/debug.h> // For the wxASSERT
CBBOX::CBBOX()
@ -57,6 +57,13 @@ CBBOX::~CBBOX()
}
void CBBOX::Set( const SFVEC3F &aPoint )
{
m_min = aPoint;
m_max = aPoint;
}
void CBBOX::Set( const SFVEC3F &aPbMin, const SFVEC3F &aPbMax )
{
m_min.x = fminf( aPbMin.x, aPbMax.x );
@ -111,8 +118,7 @@ void CBBOX::Union( const SFVEC3F &aPoint )
void CBBOX::Union( const CBBOX &aBBox )
{
if( !aBBox.IsInitialized() )
return;
wxASSERT( aBBox.IsInitialized() );
// get the minimun value between the added bounding box and the existent bounding box
m_min.x = fmin( m_min.x, aBBox.m_min.x );
@ -151,8 +157,10 @@ unsigned int CBBOX::MaxDimension() const
SFVEC3F extent = GetExtent();
if( extent.y > extent.x ) result = 1;
if( extent.z > extent.y ) result = 2;
if( extent.y > extent.x )
result = 1;
if( extent.z > extent.y )
result = 2;
return result;
}
@ -164,8 +172,10 @@ float CBBOX::GetMaxDimension() const
SFVEC3F extent = GetExtent();
if( extent.y > extent.x ) max_dimensions_idx = 1;
if( extent.z > extent.y ) max_dimensions_idx = 2;
if( extent.y > extent.x )
max_dimensions_idx = 1;
if( extent.z > extent.y )
max_dimensions_idx = 2;
return extent[max_dimensions_idx];
}
@ -288,14 +298,18 @@ bool CBBOX::Intersect( const RAY &aRay, float *aOutHitt0, float *aOutHitt1 )
return false;
}
if( aOutHitt0 ) *aOutHitt0 = t0;
if( aOutHitt1 ) *aOutHitt1 = t1;
if( aOutHitt0 )
*aOutHitt0 = t0;
if( aOutHitt1 )
*aOutHitt1 = t1;
return true;
}
#else
// https://github.com/mmp/pbrt-v2/blob/master/src/accelerators/bvh.cpp#L126
bool CBBOX::Intersect( const RAY &aRay, float *aOutHitt0, float *aOutHitt1 ) const
bool CBBOX::Intersect( const RAY &aRay,
float *aOutHitt0,
float *aOutHitt1 ) const
{
wxASSERT( aOutHitt0 );
wxASSERT( aOutHitt1 );
@ -303,8 +317,8 @@ bool CBBOX::Intersect( const RAY &aRay, float *aOutHitt0, float *aOutHitt1 ) con
const SFVEC3F bounds[2] = {m_min, m_max};
// Check for ray intersection against x and y slabs
float tmin = (bounds[ aRay.m_dirIsNeg[0]].x - aRay.m_Origin.x) * aRay.m_InvDir.x;
float tmax = (bounds[1 - aRay.m_dirIsNeg[0]].x - aRay.m_Origin.x) * aRay.m_InvDir.x;
float tmin = (bounds[ aRay.m_dirIsNeg[0]].x - aRay.m_Origin.x) * aRay.m_InvDir.x;
float tmax = (bounds[1 - aRay.m_dirIsNeg[0]].x - aRay.m_Origin.x) * aRay.m_InvDir.x;
float tymin = (bounds[ aRay.m_dirIsNeg[1]].y - aRay.m_Origin.y) * aRay.m_InvDir.y;
float tymax = (bounds[1 - aRay.m_dirIsNeg[1]].y - aRay.m_Origin.y) * aRay.m_InvDir.y;
@ -315,8 +329,8 @@ bool CBBOX::Intersect( const RAY &aRay, float *aOutHitt0, float *aOutHitt1 ) con
tmax = (tymax < tmax)? tymax : tmax;
// Check for ray intersection against z slab
float tzmin = (bounds[ aRay.m_dirIsNeg[2]].z - aRay.m_Origin.z) * aRay.m_InvDir.z;
float tzmax = (bounds[1 - aRay.m_dirIsNeg[2]].z - aRay.m_Origin.z) * aRay.m_InvDir.z;
const float tzmin = (bounds[ aRay.m_dirIsNeg[2]].z - aRay.m_Origin.z) * aRay.m_InvDir.z;
const float tzmax = (bounds[1 - aRay.m_dirIsNeg[2]].z - aRay.m_Origin.z) * aRay.m_InvDir.z;
if( (tmin > tzmax) || (tzmin > tmax) )
return false;
@ -338,8 +352,11 @@ void CBBOX::ApplyTransformation( glm::mat4 aTransformMatrix )
{
wxASSERT( IsInitialized() );
SFVEC3F v1 = SFVEC3F( aTransformMatrix * glm::vec4( m_min.x, m_min.y, m_min.z, 1.0f ) );
SFVEC3F v2 = SFVEC3F( aTransformMatrix * glm::vec4( m_max.x, m_max.y, m_max.z, 1.0f ) );
const SFVEC3F v1 = SFVEC3F( aTransformMatrix *
glm::vec4( m_min.x, m_min.y, m_min.z, 1.0f ) );
const SFVEC3F v2 = SFVEC3F( aTransformMatrix *
glm::vec4( m_max.x, m_max.y, m_max.z, 1.0f ) );
Reset();
Union( v1 );
@ -349,19 +366,27 @@ void CBBOX::ApplyTransformation( glm::mat4 aTransformMatrix )
void CBBOX::ApplyTransformationAA( glm::mat4 aTransformMatrix )
{
// XXX - CB - commented out because it spams the legacy renderer
// wxASSERT( IsInitialized() );
wxASSERT( IsInitialized() );
// apply the transformation matrix for each of vertices of the bounding box
// and make a union with all vertices
CBBOX tmpBBox = CBBOX( SFVEC3F( aTransformMatrix * glm::vec4( m_min.x, m_min.y, m_min.z, 1.0f ) ) );
tmpBBox.Union( SFVEC3F( aTransformMatrix * glm::vec4( m_max.x, m_min.y, m_min.z, 1.0f ) ) );
tmpBBox.Union( SFVEC3F( aTransformMatrix * glm::vec4( m_min.x, m_max.y, m_min.z, 1.0f ) ) );
tmpBBox.Union( SFVEC3F( aTransformMatrix * glm::vec4( m_min.x, m_min.y, m_max.z, 1.0f ) ) );
tmpBBox.Union( SFVEC3F( aTransformMatrix * glm::vec4( m_min.x, m_max.y, m_max.z, 1.0f ) ) );
tmpBBox.Union( SFVEC3F( aTransformMatrix * glm::vec4( m_max.x, m_max.y, m_min.z, 1.0f ) ) );
tmpBBox.Union( SFVEC3F( aTransformMatrix * glm::vec4( m_max.x, m_min.y, m_max.z, 1.0f ) ) );
tmpBBox.Union( SFVEC3F( aTransformMatrix * glm::vec4( m_max.x, m_max.y, m_max.z, 1.0f ) ) );
CBBOX tmpBBox = CBBOX(
SFVEC3F( aTransformMatrix *
glm::vec4( m_min.x, m_min.y, m_min.z, 1.0f ) ) );
tmpBBox.Union( SFVEC3F( aTransformMatrix *
glm::vec4( m_max.x, m_min.y, m_min.z, 1.0f ) ) );
tmpBBox.Union( SFVEC3F( aTransformMatrix *
glm::vec4( m_min.x, m_max.y, m_min.z, 1.0f ) ) );
tmpBBox.Union( SFVEC3F( aTransformMatrix *
glm::vec4( m_min.x, m_min.y, m_max.z, 1.0f ) ) );
tmpBBox.Union( SFVEC3F( aTransformMatrix *
glm::vec4( m_min.x, m_max.y, m_max.z, 1.0f ) ) );
tmpBBox.Union( SFVEC3F( aTransformMatrix *
glm::vec4( m_max.x, m_max.y, m_min.z, 1.0f ) ) );
tmpBBox.Union( SFVEC3F( aTransformMatrix *
glm::vec4( m_max.x, m_min.y, m_max.z, 1.0f ) ) );
tmpBBox.Union( SFVEC3F( aTransformMatrix *
glm::vec4( m_max.x, m_max.y, m_max.z, 1.0f ) ) );
m_min = tmpBBox.m_min;
m_max = tmpBBox.m_max;

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@gmail.com>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -30,15 +30,14 @@
#ifndef _CBBOX_H_
#define _CBBOX_H_
#include "plugins/3dapi/xv3d_types.h"
#include "3d_rendering/3d_render_raytracing/ray.h"
#include <fctsys.h> // For the DBG(
#include "../ray.h"
#include <fctsys.h> // For the DBG(
/**
* Class CBBOX
* manages a bounding box defined by two SFVEC3F min max points.
*/
GLM_ALIGNED_STRUCT(CLASS_ALIGNMENT) CBBOX
struct CBBOX
{
public:
@ -54,7 +53,7 @@ public:
* Initialize a bounding box with a given point
* @param aPbInit a point for the bounding box initialization
*/
CBBOX( const SFVEC3F &aPbInit );
explicit CBBOX( const SFVEC3F &aPbInit );
/**
* Constructor CBBOX
@ -77,6 +76,13 @@ public:
void Set( const CBBOX &aBBox );
/**
* @brief Set
* @param aPbMin
* @param aPbMax
*/
void Set( const SFVEC3F &aPoint );
/**
* Function Union
* recalculate the bounding box adding a point
@ -246,8 +252,8 @@ public:
private:
SFVEC3F m_min; ///< (12) point of the lower position of the bounding box
SFVEC3F m_max; ///< (12) point of the higher position of the bounding box
SFVEC3F m_min; ///< (12) point of the lower position of the bounding box
SFVEC3F m_max; ///< (12) point of the higher position of the bounding box
};
#endif // CBBox_h

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@gmail.com>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -45,19 +45,21 @@
bool CBBOX::Intersect( const RAY &aRay, float *t ) const
{
switch ( aRay.m_Classification )
switch( aRay.m_Classification )
{
case MMM:
{
if (( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.z < m_min.z)
|| ( aRay.jbyi * m_min.x - m_max.y + aRay.c_xy > 0)
|| ( aRay.ibyj * m_min.y - m_max.x + aRay.c_yx > 0)
|| ( aRay.jbyk * m_min.z - m_max.y + aRay.c_zy > 0)
|| ( aRay.kbyj * m_min.y - m_max.z + aRay.c_yz > 0)
|| ( aRay.kbyi * m_min.x - m_max.z + aRay.c_xz > 0)
|| ( aRay.ibyk * m_min.z - m_max.x + aRay.c_zx > 0)
)
return false;
if( ( aRay.m_Origin.x < m_min.x ) ||
( aRay.m_Origin.y < m_min.y ) ||
( aRay.m_Origin.z < m_min.z )
|| ( aRay.jbyi * m_min.x - m_max.y + aRay.c_xy > 0)
|| ( aRay.ibyj * m_min.y - m_max.x + aRay.c_yx > 0)
|| ( aRay.jbyk * m_min.z - m_max.y + aRay.c_zy > 0)
|| ( aRay.kbyj * m_min.y - m_max.z + aRay.c_yz > 0)
|| ( aRay.kbyi * m_min.x - m_max.z + aRay.c_xz > 0)
|| ( aRay.ibyk * m_min.z - m_max.x + aRay.c_zx > 0)
)
return false;
// compute the intersection distance
@ -79,15 +81,17 @@ bool CBBOX::Intersect( const RAY &aRay, float *t ) const
case MMP:
{
if (( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.z > m_max.z)
|| ( aRay.jbyi * m_min.x - m_max.y + aRay.c_xy > 0)
|| ( aRay.ibyj * m_min.y - m_max.x + aRay.c_yx > 0)
|| ( aRay.jbyk * m_max.z - m_max.y + aRay.c_zy > 0)
|| ( aRay.kbyj * m_min.y - m_min.z + aRay.c_yz < 0)
|| ( aRay.kbyi * m_min.x - m_min.z + aRay.c_xz < 0)
|| ( aRay.ibyk * m_max.z - m_max.x + aRay.c_zx > 0)
)
return false;
if( ( aRay.m_Origin.x < m_min.x ) ||
( aRay.m_Origin.y < m_min.y ) ||
( aRay.m_Origin.z > m_max.z )
|| ( aRay.jbyi * m_min.x - m_max.y + aRay.c_xy > 0)
|| ( aRay.ibyj * m_min.y - m_max.x + aRay.c_yx > 0)
|| ( aRay.jbyk * m_max.z - m_max.y + aRay.c_zy > 0)
|| ( aRay.kbyj * m_min.y - m_min.z + aRay.c_yz < 0)
|| ( aRay.kbyi * m_min.x - m_min.z + aRay.c_xz < 0)
|| ( aRay.ibyk * m_max.z - m_max.x + aRay.c_zx > 0)
)
return false;
*t = (m_max.x - aRay.m_Origin.x) * aRay.m_InvDir.x;
@ -106,15 +110,17 @@ bool CBBOX::Intersect( const RAY &aRay, float *t ) const
case MPM:
{
if (( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.y > m_max.y) || ( aRay.m_Origin.z < m_min.z)
|| ( aRay.jbyi * m_min.x - m_min.y + aRay.c_xy < 0)
|| ( aRay.ibyj * m_max.y - m_max.x + aRay.c_yx > 0)
|| ( aRay.jbyk * m_min.z - m_min.y + aRay.c_zy < 0)
|| ( aRay.kbyj * m_max.y - m_max.z + aRay.c_yz > 0)
|| ( aRay.kbyi * m_min.x - m_max.z + aRay.c_xz > 0)
|| ( aRay.ibyk * m_min.z - m_max.x + aRay.c_zx > 0)
)
return false;
if( ( aRay.m_Origin.x < m_min.x ) ||
( aRay.m_Origin.y > m_max.y ) ||
( aRay.m_Origin.z < m_min.z )
|| ( aRay.jbyi * m_min.x - m_min.y + aRay.c_xy < 0)
|| ( aRay.ibyj * m_max.y - m_max.x + aRay.c_yx > 0)
|| ( aRay.jbyk * m_min.z - m_min.y + aRay.c_zy < 0)
|| ( aRay.kbyj * m_max.y - m_max.z + aRay.c_yz > 0)
|| ( aRay.kbyi * m_min.x - m_max.z + aRay.c_xz > 0)
|| ( aRay.ibyk * m_min.z - m_max.x + aRay.c_zx > 0)
)
return false;
*t = (m_max.x - aRay.m_Origin.x) * aRay.m_InvDir.x;
@ -133,15 +139,17 @@ bool CBBOX::Intersect( const RAY &aRay, float *t ) const
case MPP:
{
if (( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.y > m_max.y) || ( aRay.m_Origin.z > m_max.z)
|| ( aRay.jbyi * m_min.x - m_min.y + aRay.c_xy < 0)
|| ( aRay.ibyj * m_max.y - m_max.x + aRay.c_yx > 0)
|| ( aRay.jbyk * m_max.z - m_min.y + aRay.c_zy < 0)
|| ( aRay.kbyj * m_max.y - m_min.z + aRay.c_yz < 0)
|| ( aRay.kbyi * m_min.x - m_min.z + aRay.c_xz < 0)
|| ( aRay.ibyk * m_max.z - m_max.x + aRay.c_zx > 0)
)
return false;
if( ( aRay.m_Origin.x < m_min.x ) ||
( aRay.m_Origin.y > m_max.y ) ||
( aRay.m_Origin.z > m_max.z )
|| ( aRay.jbyi * m_min.x - m_min.y + aRay.c_xy < 0)
|| ( aRay.ibyj * m_max.y - m_max.x + aRay.c_yx > 0)
|| ( aRay.jbyk * m_max.z - m_min.y + aRay.c_zy < 0)
|| ( aRay.kbyj * m_max.y - m_min.z + aRay.c_yz < 0)
|| ( aRay.kbyi * m_min.x - m_min.z + aRay.c_xz < 0)
|| ( aRay.ibyk * m_max.z - m_max.x + aRay.c_zx > 0)
)
return false;
*t = (m_max.x - aRay.m_Origin.x) * aRay.m_InvDir.x;
@ -160,15 +168,17 @@ bool CBBOX::Intersect( const RAY &aRay, float *t ) const
case PMM:
{
if (( aRay.m_Origin.x > m_max.x) || ( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.z < m_min.z)
|| ( aRay.jbyi * m_max.x - m_max.y + aRay.c_xy > 0)
|| ( aRay.ibyj * m_min.y - m_min.x + aRay.c_yx < 0)
|| ( aRay.jbyk * m_min.z - m_max.y + aRay.c_zy > 0)
|| ( aRay.kbyj * m_min.y - m_max.z + aRay.c_yz > 0)
|| ( aRay.kbyi * m_max.x - m_max.z + aRay.c_xz > 0)
|| ( aRay.ibyk * m_min.z - m_min.x + aRay.c_zx < 0)
)
return false;
if( ( aRay.m_Origin.x > m_max.x ) ||
( aRay.m_Origin.y < m_min.y ) ||
( aRay.m_Origin.z < m_min.z )
|| ( aRay.jbyi * m_max.x - m_max.y + aRay.c_xy > 0)
|| ( aRay.ibyj * m_min.y - m_min.x + aRay.c_yx < 0)
|| ( aRay.jbyk * m_min.z - m_max.y + aRay.c_zy > 0)
|| ( aRay.kbyj * m_min.y - m_max.z + aRay.c_yz > 0)
|| ( aRay.kbyi * m_max.x - m_max.z + aRay.c_xz > 0)
|| ( aRay.ibyk * m_min.z - m_min.x + aRay.c_zx < 0)
)
return false;
*t = (m_min.x - aRay.m_Origin.x) * aRay.m_InvDir.x;
@ -188,15 +198,17 @@ bool CBBOX::Intersect( const RAY &aRay, float *t ) const
case PMP:
{
if (( aRay.m_Origin.x > m_max.x) || ( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.z > m_max.z)
|| ( aRay.jbyi * m_max.x - m_max.y + aRay.c_xy > 0)
|| ( aRay.ibyj * m_min.y - m_min.x + aRay.c_yx < 0)
|| ( aRay.jbyk * m_max.z - m_max.y + aRay.c_zy > 0)
|| ( aRay.kbyj * m_min.y - m_min.z + aRay.c_yz < 0)
|| ( aRay.kbyi * m_max.x - m_min.z + aRay.c_xz < 0)
|| ( aRay.ibyk * m_max.z - m_min.x + aRay.c_zx < 0)
)
return false;
if( ( aRay.m_Origin.x > m_max.x ) ||
( aRay.m_Origin.y < m_min.y ) ||
( aRay.m_Origin.z > m_max.z )
|| ( aRay.jbyi * m_max.x - m_max.y + aRay.c_xy > 0)
|| ( aRay.ibyj * m_min.y - m_min.x + aRay.c_yx < 0)
|| ( aRay.jbyk * m_max.z - m_max.y + aRay.c_zy > 0)
|| ( aRay.kbyj * m_min.y - m_min.z + aRay.c_yz < 0)
|| ( aRay.kbyi * m_max.x - m_min.z + aRay.c_xz < 0)
|| ( aRay.ibyk * m_max.z - m_min.x + aRay.c_zx < 0)
)
return false;
*t = (m_min.x - aRay.m_Origin.x) * aRay.m_InvDir.x;
@ -215,15 +227,17 @@ bool CBBOX::Intersect( const RAY &aRay, float *t ) const
case PPM:
{
if (( aRay.m_Origin.x > m_max.x) || ( aRay.m_Origin.y > m_max.y) || ( aRay.m_Origin.z < m_min.z)
|| ( aRay.jbyi * m_max.x - m_min.y + aRay.c_xy < 0)
|| ( aRay.ibyj * m_max.y - m_min.x + aRay.c_yx < 0)
|| ( aRay.jbyk * m_min.z - m_min.y + aRay.c_zy < 0)
|| ( aRay.kbyj * m_max.y - m_max.z + aRay.c_yz > 0)
|| ( aRay.kbyi * m_max.x - m_max.z + aRay.c_xz > 0)
|| ( aRay.ibyk * m_min.z - m_min.x + aRay.c_zx < 0)
)
return false;
if( ( aRay.m_Origin.x > m_max.x ) ||
( aRay.m_Origin.y > m_max.y ) ||
( aRay.m_Origin.z < m_min.z )
|| ( aRay.jbyi * m_max.x - m_min.y + aRay.c_xy < 0)
|| ( aRay.ibyj * m_max.y - m_min.x + aRay.c_yx < 0)
|| ( aRay.jbyk * m_min.z - m_min.y + aRay.c_zy < 0)
|| ( aRay.kbyj * m_max.y - m_max.z + aRay.c_yz > 0)
|| ( aRay.kbyi * m_max.x - m_max.z + aRay.c_xz > 0)
|| ( aRay.ibyk * m_min.z - m_min.x + aRay.c_zx < 0)
)
return false;
*t = (m_min.x - aRay.m_Origin.x) * aRay.m_InvDir.x;
@ -242,15 +256,17 @@ bool CBBOX::Intersect( const RAY &aRay, float *t ) const
case PPP:
{
if (( aRay.m_Origin.x > m_max.x) || ( aRay.m_Origin.y > m_max.y) || ( aRay.m_Origin.z > m_max.z)
|| ( aRay.jbyi * m_max.x - m_min.y + aRay.c_xy < 0)
|| ( aRay.ibyj * m_max.y - m_min.x + aRay.c_yx < 0)
|| ( aRay.jbyk * m_max.z - m_min.y + aRay.c_zy < 0)
|| ( aRay.kbyj * m_max.y - m_min.z + aRay.c_yz < 0)
|| ( aRay.kbyi * m_max.x - m_min.z + aRay.c_xz < 0)
|| ( aRay.ibyk * m_max.z - m_min.x + aRay.c_zx < 0)
)
return false;
if( ( aRay.m_Origin.x > m_max.x ) ||
( aRay.m_Origin.y > m_max.y ) ||
( aRay.m_Origin.z > m_max.z )
|| ( aRay.jbyi * m_max.x - m_min.y + aRay.c_xy < 0)
|| ( aRay.ibyj * m_max.y - m_min.x + aRay.c_yx < 0)
|| ( aRay.jbyk * m_max.z - m_min.y + aRay.c_zy < 0)
|| ( aRay.kbyj * m_max.y - m_min.z + aRay.c_yz < 0)
|| ( aRay.kbyi * m_max.x - m_min.z + aRay.c_xz < 0)
|| ( aRay.ibyk * m_max.z - m_min.x + aRay.c_zx < 0)
)
return false;
*t = (m_min.x - aRay.m_Origin.x) * aRay.m_InvDir.x;
@ -269,12 +285,13 @@ bool CBBOX::Intersect( const RAY &aRay, float *t ) const
case OMM:
{
if(( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.x > m_max.x)
|| ( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.z < m_min.z)
|| ( aRay.jbyk * m_min.z - m_max.y + aRay.c_zy > 0)
|| ( aRay.kbyj * m_min.y - m_max.z + aRay.c_yz > 0)
)
return false;
if(( aRay.m_Origin.x < m_min.x ) ||
( aRay.m_Origin.x > m_max.x )
|| ( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.z < m_min.z)
|| ( aRay.jbyk * m_min.z - m_max.y + aRay.c_zy > 0)
|| ( aRay.kbyj * m_min.y - m_max.z + aRay.c_yz > 0)
)
return false;
*t = (m_max.y - aRay.m_Origin.y) * aRay.m_InvDir.y;
@ -288,12 +305,13 @@ bool CBBOX::Intersect( const RAY &aRay, float *t ) const
case OMP:
{
if(( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.x > m_max.x)
|| ( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.z > m_max.z)
|| ( aRay.jbyk * m_max.z - m_max.y + aRay.c_zy > 0)
|| ( aRay.kbyj * m_min.y - m_min.z + aRay.c_yz < 0)
)
return false;
if(( aRay.m_Origin.x < m_min.x ) ||
( aRay.m_Origin.x > m_max.x )
|| ( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.z > m_max.z)
|| ( aRay.jbyk * m_max.z - m_max.y + aRay.c_zy > 0)
|| ( aRay.kbyj * m_min.y - m_min.z + aRay.c_yz < 0)
)
return false;
*t = (m_max.y - aRay.m_Origin.y) * aRay.m_InvDir.y;
@ -307,12 +325,12 @@ bool CBBOX::Intersect( const RAY &aRay, float *t ) const
case OPM:
{
if(( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.x > m_max.x)
|| ( aRay.m_Origin.y > m_max.y) || ( aRay.m_Origin.z < m_min.z)
|| ( aRay.jbyk * m_min.z - m_min.y + aRay.c_zy < 0)
|| ( aRay.kbyj * m_max.y - m_max.z + aRay.c_yz > 0)
)
return false;
if(( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.x > m_max.x)
|| ( aRay.m_Origin.y > m_max.y) || ( aRay.m_Origin.z < m_min.z)
|| ( aRay.jbyk * m_min.z - m_min.y + aRay.c_zy < 0)
|| ( aRay.kbyj * m_max.y - m_max.z + aRay.c_yz > 0)
)
return false;
*t = (m_min.y - aRay.m_Origin.y) * aRay.m_InvDir.y;
@ -326,12 +344,12 @@ bool CBBOX::Intersect( const RAY &aRay, float *t ) const
case OPP:
{
if(( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.x > m_max.x)
|| ( aRay.m_Origin.y > m_max.y) || ( aRay.m_Origin.z > m_max.z)
|| ( aRay.jbyk * m_max.z - m_min.y + aRay.c_zy < 0)
|| ( aRay.kbyj * m_max.y - m_min.z + aRay.c_yz < 0)
)
return false;
if(( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.x > m_max.x)
|| ( aRay.m_Origin.y > m_max.y) || ( aRay.m_Origin.z > m_max.z)
|| ( aRay.jbyk * m_max.z - m_min.y + aRay.c_zy < 0)
|| ( aRay.kbyj * m_max.y - m_min.z + aRay.c_yz < 0)
)
return false;
*t = (m_min.y - aRay.m_Origin.y) * aRay.m_InvDir.y;
@ -346,12 +364,12 @@ bool CBBOX::Intersect( const RAY &aRay, float *t ) const
case MOM:
{
if(( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.y > m_max.y)
|| ( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.z < m_min.z)
|| ( aRay.kbyi * m_min.x - m_max.z + aRay.c_xz > 0)
|| ( aRay.ibyk * m_min.z - m_max.x + aRay.c_zx > 0)
)
return false;
if(( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.y > m_max.y)
|| ( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.z < m_min.z)
|| ( aRay.kbyi * m_min.x - m_max.z + aRay.c_xz > 0)
|| ( aRay.ibyk * m_min.z - m_max.x + aRay.c_zx > 0)
)
return false;
*t = (m_max.x - aRay.m_Origin.x) * aRay.m_InvDir.x;
@ -366,12 +384,12 @@ bool CBBOX::Intersect( const RAY &aRay, float *t ) const
case MOP:
{
if(( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.y > m_max.y)
|| ( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.z > m_max.z)
|| ( aRay.kbyi * m_min.x - m_min.z + aRay.c_xz < 0)
|| ( aRay.ibyk * m_max.z - m_max.x + aRay.c_zx > 0)
)
return false;
if(( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.y > m_max.y)
|| ( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.z > m_max.z)
|| ( aRay.kbyi * m_min.x - m_min.z + aRay.c_xz < 0)
|| ( aRay.ibyk * m_max.z - m_max.x + aRay.c_zx > 0)
)
return false;
*t = (m_max.x - aRay.m_Origin.x) * aRay.m_InvDir.x;
@ -385,12 +403,12 @@ bool CBBOX::Intersect( const RAY &aRay, float *t ) const
case POM:
{
if(( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.y > m_max.y)
|| ( aRay.m_Origin.x > m_max.x) || ( aRay.m_Origin.z < m_min.z)
|| ( aRay.kbyi * m_max.x - m_max.z + aRay.c_xz > 0)
|| ( aRay.ibyk * m_min.z - m_min.x + aRay.c_zx < 0)
)
return false;
if(( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.y > m_max.y)
|| ( aRay.m_Origin.x > m_max.x) || ( aRay.m_Origin.z < m_min.z)
|| ( aRay.kbyi * m_max.x - m_max.z + aRay.c_xz > 0)
|| ( aRay.ibyk * m_min.z - m_min.x + aRay.c_zx < 0)
)
return false;
*t = (m_min.x - aRay.m_Origin.x) * aRay.m_InvDir.x;
@ -405,12 +423,12 @@ bool CBBOX::Intersect( const RAY &aRay, float *t ) const
case POP:
{
if(( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.y > m_max.y)
|| ( aRay.m_Origin.x > m_max.x) || ( aRay.m_Origin.z > m_max.z)
|| ( aRay.kbyi * m_max.x - m_min.z + aRay.c_xz < 0)
|| ( aRay.ibyk * m_max.z - m_min.x + aRay.c_zx < 0)
)
return false;
if(( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.y > m_max.y)
|| ( aRay.m_Origin.x > m_max.x) || ( aRay.m_Origin.z > m_max.z)
|| ( aRay.kbyi * m_max.x - m_min.z + aRay.c_xz < 0)
|| ( aRay.ibyk * m_max.z - m_min.x + aRay.c_zx < 0)
)
return false;
*t = (m_min.x - aRay.m_Origin.x) * aRay.m_InvDir.x;
@ -424,12 +442,12 @@ bool CBBOX::Intersect( const RAY &aRay, float *t ) const
case MMO:
{
if(( aRay.m_Origin.z < m_min.z) || ( aRay.m_Origin.z > m_max.z)
|| ( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.y < m_min.y)
|| ( aRay.jbyi * m_min.x - m_max.y + aRay.c_xy > 0)
|| ( aRay.ibyj * m_min.y - m_max.x + aRay.c_yx > 0)
)
return false;
if(( aRay.m_Origin.z < m_min.z) || ( aRay.m_Origin.z > m_max.z)
|| ( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.y < m_min.y)
|| ( aRay.jbyi * m_min.x - m_max.y + aRay.c_xy > 0)
|| ( aRay.ibyj * m_min.y - m_max.x + aRay.c_yx > 0)
)
return false;
*t = (m_max.x - aRay.m_Origin.x) * aRay.m_InvDir.x;
@ -443,12 +461,12 @@ bool CBBOX::Intersect( const RAY &aRay, float *t ) const
case MPO:
{
if(( aRay.m_Origin.z < m_min.z) || ( aRay.m_Origin.z > m_max.z)
|| ( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.y > m_max.y)
|| ( aRay.jbyi * m_min.x - m_min.y + aRay.c_xy < 0)
|| ( aRay.ibyj * m_max.y - m_max.x + aRay.c_yx > 0)
)
return false;
if(( aRay.m_Origin.z < m_min.z) || ( aRay.m_Origin.z > m_max.z)
|| ( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.y > m_max.y)
|| ( aRay.jbyi * m_min.x - m_min.y + aRay.c_xy < 0)
|| ( aRay.ibyj * m_max.y - m_max.x + aRay.c_yx > 0)
)
return false;
*t = (m_max.x - aRay.m_Origin.x) * aRay.m_InvDir.x;
@ -463,12 +481,12 @@ bool CBBOX::Intersect( const RAY &aRay, float *t ) const
case PMO:
{
if(( aRay.m_Origin.z < m_min.z) || ( aRay.m_Origin.z > m_max.z)
|| ( aRay.m_Origin.x > m_max.x) || ( aRay.m_Origin.y < m_min.y)
|| ( aRay.jbyi * m_max.x - m_max.y + aRay.c_xy > 0)
|| ( aRay.ibyj * m_min.y - m_min.x + aRay.c_yx < 0)
)
return false;
if(( aRay.m_Origin.z < m_min.z) || ( aRay.m_Origin.z > m_max.z)
|| ( aRay.m_Origin.x > m_max.x) || ( aRay.m_Origin.y < m_min.y)
|| ( aRay.jbyi * m_max.x - m_max.y + aRay.c_xy > 0)
|| ( aRay.ibyj * m_min.y - m_min.x + aRay.c_yx < 0)
)
return false;
*t = (m_min.x - aRay.m_Origin.x) * aRay.m_InvDir.x;
@ -482,12 +500,12 @@ bool CBBOX::Intersect( const RAY &aRay, float *t ) const
case PPO:
{
if(( aRay.m_Origin.z < m_min.z) || ( aRay.m_Origin.z > m_max.z)
|| ( aRay.m_Origin.x > m_max.x) || ( aRay.m_Origin.y > m_max.y)
|| ( aRay.jbyi * m_max.x - m_min.y + aRay.c_xy < 0)
|| ( aRay.ibyj * m_max.y - m_min.x + aRay.c_yx < 0)
)
return false;
if(( aRay.m_Origin.z < m_min.z) || ( aRay.m_Origin.z > m_max.z)
|| ( aRay.m_Origin.x > m_max.x) || ( aRay.m_Origin.y > m_max.y)
|| ( aRay.jbyi * m_max.x - m_min.y + aRay.c_xy < 0)
|| ( aRay.ibyj * m_max.y - m_min.x + aRay.c_yx < 0)
)
return false;
*t = (m_min.x - aRay.m_Origin.x) * aRay.m_InvDir.x;
@ -502,11 +520,11 @@ bool CBBOX::Intersect( const RAY &aRay, float *t ) const
case MOO:
{
if(( aRay.m_Origin.x < m_min.x)
|| ( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.y > m_max.y)
|| ( aRay.m_Origin.z < m_min.z) || ( aRay.m_Origin.z > m_max.z)
)
return false;
if(( aRay.m_Origin.x < m_min.x)
|| ( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.y > m_max.y)
|| ( aRay.m_Origin.z < m_min.z) || ( aRay.m_Origin.z > m_max.z)
)
return false;
*t = (m_max.x - aRay.m_Origin.x) * aRay.m_InvDir.x;
@ -515,11 +533,11 @@ bool CBBOX::Intersect( const RAY &aRay, float *t ) const
case POO:
{
if(( aRay.m_Origin.x > m_max.x)
|| ( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.y > m_max.y)
|| ( aRay.m_Origin.z < m_min.z) || ( aRay.m_Origin.z > m_max.z)
)
return false;
if(( aRay.m_Origin.x > m_max.x)
|| ( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.y > m_max.y)
|| ( aRay.m_Origin.z < m_min.z) || ( aRay.m_Origin.z > m_max.z)
)
return false;
*t = (m_min.x - aRay.m_Origin.x) * aRay.m_InvDir.x;
@ -528,11 +546,11 @@ bool CBBOX::Intersect( const RAY &aRay, float *t ) const
case OMO:
{
if(( aRay.m_Origin.y < m_min.y)
|| ( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.x > m_max.x)
|| ( aRay.m_Origin.z < m_min.z) || ( aRay.m_Origin.z > m_max.z)
)
return false;
if(( aRay.m_Origin.y < m_min.y)
|| ( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.x > m_max.x)
|| ( aRay.m_Origin.z < m_min.z) || ( aRay.m_Origin.z > m_max.z)
)
return false;
*t = (m_max.y - aRay.m_Origin.y) * aRay.m_InvDir.y;
@ -541,11 +559,11 @@ bool CBBOX::Intersect( const RAY &aRay, float *t ) const
case OPO:
{
if(( aRay.m_Origin.y > m_max.y)
|| ( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.x > m_max.x)
|| ( aRay.m_Origin.z < m_min.z) || ( aRay.m_Origin.z > m_max.z)
)
return false;
if(( aRay.m_Origin.y > m_max.y)
|| ( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.x > m_max.x)
|| ( aRay.m_Origin.z < m_min.z) || ( aRay.m_Origin.z > m_max.z)
)
return false;
*t = (m_min.y - aRay.m_Origin.y) * aRay.m_InvDir.y;
@ -555,11 +573,11 @@ bool CBBOX::Intersect( const RAY &aRay, float *t ) const
case OOM:
{
if(( aRay.m_Origin.z < m_min.z)
|| ( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.x > m_max.x)
|| ( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.y > m_max.y)
)
return false;
if(( aRay.m_Origin.z < m_min.z)
|| ( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.x > m_max.x)
|| ( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.y > m_max.y)
)
return false;
*t = (m_max.z - aRay.m_Origin.z) * aRay.m_InvDir.z;
@ -568,11 +586,11 @@ bool CBBOX::Intersect( const RAY &aRay, float *t ) const
case OOP:
{
if(( aRay.m_Origin.z > m_max.z)
|| ( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.x > m_max.x)
|| ( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.y > m_max.y)
)
return false;
if(( aRay.m_Origin.z > m_max.z)
|| ( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.x > m_max.x)
|| ( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.y > m_max.y)
)
return false;
*t = (m_min.z - aRay.m_Origin.z) * aRay.m_InvDir.z;
@ -586,11 +604,13 @@ bool CBBOX::Intersect( const RAY &aRay, float *t ) const
bool CBBOX::Intersect( const RAY &aRay ) const
{
switch ( aRay.m_Classification )
switch( aRay.m_Classification )
{
case MMM:
{
if (( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.z < m_min.z)
{
if( ( aRay.m_Origin.x < m_min.x ) ||
( aRay.m_Origin.y < m_min.y ) ||
( aRay.m_Origin.z < m_min.z )
|| ( aRay.jbyi * m_min.x - m_max.y + aRay.c_xy > 0)
|| ( aRay.ibyj * m_min.y - m_max.x + aRay.c_yx > 0)
|| ( aRay.jbyk * m_min.z - m_max.y + aRay.c_zy > 0)
@ -599,14 +619,15 @@ bool CBBOX::Intersect( const RAY &aRay ) const
|| ( aRay.ibyk * m_min.z - m_max.x + aRay.c_zx > 0)
)
return false;
return true;
}
return true;
}
case MMP:
{
if (( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.z > m_max.z)
{
if( ( aRay.m_Origin.x < m_min.x ) ||
( aRay.m_Origin.y < m_min.y ) ||
( aRay.m_Origin.z > m_max.z )
|| ( aRay.jbyi * m_min.x - m_max.y + aRay.c_xy > 0)
|| ( aRay.ibyj * m_min.y - m_max.x + aRay.c_yx > 0)
|| ( aRay.jbyk * m_max.z - m_max.y + aRay.c_zy > 0)
@ -615,13 +636,14 @@ bool CBBOX::Intersect( const RAY &aRay ) const
|| ( aRay.ibyk * m_max.z - m_max.x + aRay.c_zx > 0)
)
return false;
return true;
}
return true;
}
case MPM:
{
if (( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.y > m_max.y) || ( aRay.m_Origin.z < m_min.z)
{
if( ( aRay.m_Origin.x < m_min.x ) ||
( aRay.m_Origin.y > m_max.y ) ||
( aRay.m_Origin.z < m_min.z )
|| ( aRay.jbyi * m_min.x - m_min.y + aRay.c_xy < 0)
|| ( aRay.ibyj * m_max.y - m_max.x + aRay.c_yx > 0)
|| ( aRay.jbyk * m_min.z - m_min.y + aRay.c_zy < 0)
@ -630,13 +652,14 @@ bool CBBOX::Intersect( const RAY &aRay ) const
|| ( aRay.ibyk * m_min.z - m_max.x + aRay.c_zx > 0)
)
return false;
return true;
}
return true;
}
case MPP:
{
if (( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.y > m_max.y) || ( aRay.m_Origin.z > m_max.z)
{
if( ( aRay.m_Origin.x < m_min.x ) ||
( aRay.m_Origin.y > m_max.y ) ||
( aRay.m_Origin.z > m_max.z )
|| ( aRay.jbyi * m_min.x - m_min.y + aRay.c_xy < 0)
|| ( aRay.ibyj * m_max.y - m_max.x + aRay.c_yx > 0)
|| ( aRay.jbyk * m_max.z - m_min.y + aRay.c_zy < 0)
@ -645,13 +668,14 @@ bool CBBOX::Intersect( const RAY &aRay ) const
|| ( aRay.ibyk * m_max.z - m_max.x + aRay.c_zx > 0)
)
return false;
return true;
}
return true;
}
case PMM:
{
if (( aRay.m_Origin.x > m_max.x) || ( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.z < m_min.z)
{
if( ( aRay.m_Origin.x > m_max.x ) ||
( aRay.m_Origin.y < m_min.y ) ||
( aRay.m_Origin.z < m_min.z )
|| ( aRay.jbyi * m_max.x - m_max.y + aRay.c_xy > 0)
|| ( aRay.ibyj * m_min.y - m_min.x + aRay.c_yx < 0)
|| ( aRay.jbyk * m_min.z - m_max.y + aRay.c_zy > 0)
@ -660,14 +684,15 @@ bool CBBOX::Intersect( const RAY &aRay ) const
|| ( aRay.ibyk * m_min.z - m_min.x + aRay.c_zx < 0)
)
return false;
return true;
}
return true;
}
case PMP:
{
if (( aRay.m_Origin.x > m_max.x) || ( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.z > m_max.z)
{
if( ( aRay.m_Origin.x > m_max.x ) ||
( aRay.m_Origin.y < m_min.y ) ||
( aRay.m_Origin.z > m_max.z )
|| ( aRay.jbyi * m_max.x - m_max.y + aRay.c_xy > 0)
|| ( aRay.ibyj * m_min.y - m_min.x + aRay.c_yx < 0)
|| ( aRay.jbyk * m_max.z - m_max.y + aRay.c_zy > 0)
@ -676,13 +701,14 @@ bool CBBOX::Intersect( const RAY &aRay ) const
|| ( aRay.ibyk * m_max.z - m_min.x + aRay.c_zx < 0)
)
return false;
return true;
}
return true;
}
case PPM:
{
if (( aRay.m_Origin.x > m_max.x) || ( aRay.m_Origin.y > m_max.y) || ( aRay.m_Origin.z < m_min.z)
{
if( ( aRay.m_Origin.x > m_max.x ) ||
( aRay.m_Origin.y > m_max.y ) ||
( aRay.m_Origin.z < m_min.z )
|| ( aRay.jbyi * m_max.x - m_min.y + aRay.c_xy < 0)
|| ( aRay.ibyj * m_max.y - m_min.x + aRay.c_yx < 0)
|| ( aRay.jbyk * m_min.z - m_min.y + aRay.c_zy < 0)
@ -691,13 +717,14 @@ bool CBBOX::Intersect( const RAY &aRay ) const
|| ( aRay.ibyk * m_min.z - m_min.x + aRay.c_zx < 0)
)
return false;
return true;
}
return true;
}
case PPP:
{
if (( aRay.m_Origin.x > m_max.x) || ( aRay.m_Origin.y > m_max.y) || ( aRay.m_Origin.z > m_max.z)
{
if( ( aRay.m_Origin.x > m_max.x ) ||
( aRay.m_Origin.y > m_max.y ) ||
( aRay.m_Origin.z > m_max.z )
|| ( aRay.jbyi * m_max.x - m_min.y + aRay.c_xy < 0)
|| ( aRay.ibyj * m_max.y - m_min.x + aRay.c_yx < 0)
|| ( aRay.jbyk * m_max.z - m_min.y + aRay.c_zy < 0)
@ -706,225 +733,209 @@ bool CBBOX::Intersect( const RAY &aRay ) const
|| ( aRay.ibyk * m_max.z - m_min.x + aRay.c_zx < 0)
)
return false;
return true;
}
return true;
}
case OMM:
{
if(( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.x > m_max.x)
|| ( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.z < m_min.z)
|| ( aRay.jbyk * m_min.z - m_max.y + aRay.c_zy > 0)
|| ( aRay.kbyj * m_min.y - m_max.z + aRay.c_yz > 0)
)
{
if( ( aRay.m_Origin.x < m_min.x ) ||
( aRay.m_Origin.x > m_max.x )
|| ( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.z < m_min.z)
|| ( aRay.jbyk * m_min.z - m_max.y + aRay.c_zy > 0)
|| ( aRay.kbyj * m_min.y - m_max.z + aRay.c_yz > 0) )
return false;
return true;
}
return true;
}
case OMP:
{
if(( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.x > m_max.x)
{
if(( aRay.m_Origin.x < m_min.x ) ||
( aRay.m_Origin.x > m_max.x )
|| ( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.z > m_max.z)
|| ( aRay.jbyk * m_max.z - m_max.y + aRay.c_zy > 0)
|| ( aRay.kbyj * m_min.y - m_min.z + aRay.c_yz < 0)
)
return false;
return true;
}
return true;
}
case OPM:
{
if(( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.x > m_max.x)
{
if(( aRay.m_Origin.x < m_min.x ) ||
( aRay.m_Origin.x > m_max.x )
|| ( aRay.m_Origin.y > m_max.y) || ( aRay.m_Origin.z < m_min.z)
|| ( aRay.jbyk * m_min.z - m_min.y + aRay.c_zy < 0)
|| ( aRay.kbyj * m_max.y - m_max.z + aRay.c_yz > 0)
)
return false;
return true;
}
return true;
}
case OPP:
{
if(( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.x > m_max.x)
{
if(( aRay.m_Origin.x < m_min.x ) ||
( aRay.m_Origin.x > m_max.x )
|| ( aRay.m_Origin.y > m_max.y) || ( aRay.m_Origin.z > m_max.z)
|| ( aRay.jbyk * m_max.z - m_min.y + aRay.c_zy < 0)
|| ( aRay.kbyj * m_max.y - m_min.z + aRay.c_yz < 0)
)
return false;
return true;
}
return true;
}
case MOM:
{
{
if(( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.y > m_max.y)
|| ( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.z < m_min.z)
|| ( aRay.kbyi * m_min.x - m_max.z + aRay.c_xz > 0)
|| ( aRay.ibyk * m_min.z - m_max.x + aRay.c_zx > 0)
)
return false;
return true;
}
return true;
}
case MOP:
{
{
if(( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.y > m_max.y)
|| ( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.z > m_max.z)
|| ( aRay.kbyi * m_min.x - m_min.z + aRay.c_xz < 0)
|| ( aRay.ibyk * m_max.z - m_max.x + aRay.c_zx > 0)
)
return false;
return true;
}
return true;
}
case POM:
{
{
if(( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.y > m_max.y)
|| ( aRay.m_Origin.x > m_max.x) || ( aRay.m_Origin.z < m_min.z)
|| ( aRay.kbyi * m_max.x - m_max.z + aRay.c_xz > 0)
|| ( aRay.ibyk * m_min.z - m_min.x + aRay.c_zx < 0)
)
return false;
return true;
}
return true;
}
case POP:
{
{
if(( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.y > m_max.y)
|| ( aRay.m_Origin.x > m_max.x) || ( aRay.m_Origin.z > m_max.z)
|| ( aRay.kbyi * m_max.x - m_min.z + aRay.c_xz < 0)
|| ( aRay.ibyk * m_max.z - m_min.x + aRay.c_zx < 0)
)
return false;
return true;
}
return true;
}
case MMO:
{
{
if(( aRay.m_Origin.z < m_min.z) || ( aRay.m_Origin.z > m_max.z)
|| ( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.y < m_min.y)
|| ( aRay.jbyi * m_min.x - m_max.y + aRay.c_xy > 0)
|| ( aRay.ibyj * m_min.y - m_max.x + aRay.c_yx > 0)
)
return false;
return true;
}
return true;
}
case MPO:
{
{
if(( aRay.m_Origin.z < m_min.z) || ( aRay.m_Origin.z > m_max.z)
|| ( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.y > m_max.y)
|| ( aRay.jbyi * m_min.x - m_min.y + aRay.c_xy < 0)
|| ( aRay.ibyj * m_max.y - m_max.x + aRay.c_yx > 0)
)
return false;
return true;
}
return true;
}
case PMO:
{
{
if(( aRay.m_Origin.z < m_min.z) || ( aRay.m_Origin.z > m_max.z)
|| ( aRay.m_Origin.x > m_max.x) || ( aRay.m_Origin.y < m_min.y)
|| ( aRay.jbyi * m_max.x - m_max.y + aRay.c_xy > 0)
|| ( aRay.ibyj * m_min.y - m_min.x + aRay.c_yx < 0)
)
return false;
return true;
}
return true;
}
case PPO:
{
{
if(( aRay.m_Origin.z < m_min.z) || ( aRay.m_Origin.z > m_max.z)
|| ( aRay.m_Origin.x > m_max.x) || ( aRay.m_Origin.y > m_max.y)
|| ( aRay.jbyi * m_max.x - m_min.y + aRay.c_xy < 0)
|| ( aRay.ibyj * m_max.y - m_min.x + aRay.c_yx < 0)
)
return false;
return true;
}
return true;
}
case MOO:
{
{
if(( aRay.m_Origin.x < m_min.x)
|| ( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.y > m_max.y)
|| ( aRay.m_Origin.z < m_min.z) || ( aRay.m_Origin.z > m_max.z)
)
return false;
return true;
}
return true;
}
case POO:
{
{
if(( aRay.m_Origin.x > m_max.x)
|| ( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.y > m_max.y)
|| ( aRay.m_Origin.z < m_min.z) || ( aRay.m_Origin.z > m_max.z)
)
return false;
return true;
}
return true;
}
case OMO:
{
{
if(( aRay.m_Origin.y < m_min.y)
|| ( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.x > m_max.x)
|| ( aRay.m_Origin.z < m_min.z) || ( aRay.m_Origin.z > m_max.z)
)
return false;
return true;
}
return true;
}
case OPO:
{
{
if(( aRay.m_Origin.y > m_max.y)
|| ( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.x > m_max.x)
|| ( aRay.m_Origin.z < m_min.z) || ( aRay.m_Origin.z > m_max.z)
)
return false;
return true;
}
return true;
}
case OOM:
{
{
if(( aRay.m_Origin.z < m_min.z)
|| ( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.x > m_max.x)
|| ( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.y > m_max.y)
)
return false;
return true;
}
return true;
}
case OOP:
{
{
if(( aRay.m_Origin.z > m_max.z)
|| ( aRay.m_Origin.x < m_min.x) || ( aRay.m_Origin.x > m_max.x)
|| ( aRay.m_Origin.y < m_min.y) || ( aRay.m_Origin.y > m_max.y)
)
return false;
return true;
}
return true;
}
}
return false;

View File

@ -0,0 +1,184 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file ccylinder.cpp
* @brief
*/
#include "3d_fastmath.h"
#include "ccylinder.h"
CVCYLINDER::CVCYLINDER( SFVEC2F aCenterPoint,
float aZmin,
float aZmax,
float aRadius ) : COBJECT( OBJ3D_CYLINDER )
{
m_center = aCenterPoint;
m_radius_squared = aRadius * aRadius;
m_inv_radius = 1.0f / aRadius;
m_bbox.Set( SFVEC3F( aCenterPoint.x - aRadius,
aCenterPoint.y - aRadius,
aZmin ),
SFVEC3F( aCenterPoint.x + aRadius,
aCenterPoint.y + aRadius,
aZmax ) );
m_bbox.ScaleNextUp();
m_centroid = m_bbox.GetCenter();
}
bool CVCYLINDER::Intersect( const RAY &aRay, HITINFO &aHitInfo ) const
{
// Based on:
// http://www.cs.utah.edu/~lha/Code%206620%20/Ray4/Cylinder.cpp
// Ray-sphere intersection: geometric
// /////////////////////////////////////////////////////////////////////////
const double OCx_Start = aRay.m_Origin.x - m_center.x;
const double OCy_Start = aRay.m_Origin.y - m_center.y;
const double p_dot_p = OCx_Start * OCx_Start + OCy_Start * OCy_Start;
const double a = (double)aRay.m_Dir.x * (double)aRay.m_Dir.x +
(double)aRay.m_Dir.y * (double)aRay.m_Dir.y;
const double b = (double)aRay.m_Dir.x * (double)OCx_Start +
(double)aRay.m_Dir.y * (double)OCy_Start;
const double c = p_dot_p - m_radius_squared;
const float delta = (float)(b * b - a * c);
bool hitResult = false;
if( delta > FLT_EPSILON )
{
const float inv_a = 1.0 / a;
const float sdelta = sqrtf( delta );
const float t = (-b - sdelta) * inv_a;
const float z = aRay.m_Origin.z + t * aRay.m_Dir.z;
if( (z >= m_bbox.Min().z) &&
(z <= m_bbox.Max().z) )
{
if( t < aHitInfo.m_tHit )
{
hitResult = true;
aHitInfo.m_tHit = t;
}
}
if( !hitResult )
{
const float t1 = (-b + sdelta) * inv_a;
const float z1 = aRay.m_Origin.z + t1 * aRay.m_Dir.z;
if( (z1 > m_bbox.Min().z ) &&
(z1 < m_bbox.Max().z ) )
{
if( t1 < aHitInfo.m_tHit )
{
hitResult = true;
aHitInfo.m_tHit = t1;
}
}
}
}
if( hitResult )
{
const SFVEC2F hitPoint2D = aRay.at2D( aHitInfo.m_tHit );
//aHitInfo.m_HitPoint =
aHitInfo.m_HitNormal = SFVEC3F( -(hitPoint2D.x - m_center.x) * m_inv_radius,
-(hitPoint2D.y - m_center.y) * m_inv_radius,
0.0f );
aHitInfo.pHitObject = this;
}
return hitResult;
}
bool CVCYLINDER::IntersectP(const RAY &aRay , float aMaxDistance ) const
{
// Based on:
// http://www.cs.utah.edu/~lha/Code%206620%20/Ray4/Cylinder.cpp
// Ray-sphere intersection: geometric
// /////////////////////////////////////////////////////////////////////////
const double OCx_Start = aRay.m_Origin.x - m_center.x;
const double OCy_Start = aRay.m_Origin.y - m_center.y;
const double p_dot_p = OCx_Start * OCx_Start + OCy_Start * OCy_Start;
const double a = (double)aRay.m_Dir.x * (double)aRay.m_Dir.x +
(double)aRay.m_Dir.y * (double)aRay.m_Dir.y;
const double b = (double)aRay.m_Dir.x * (double)OCx_Start +
(double)aRay.m_Dir.y * (double)OCy_Start;
const double c = p_dot_p - m_radius_squared;
const float delta = (float)(b * b - a * c);
if( delta > FLT_EPSILON )
{
const float inv_a = 1.0 / a;
const float sdelta = sqrtf( delta );
const float t = (-b - sdelta) * inv_a;
const float z = aRay.m_Origin.z + t * aRay.m_Dir.z;
if( (z >= m_bbox.Min().z) &&
(z <= m_bbox.Max().z) )
{
if( t < aMaxDistance )
return true;
}
const float t1 = (-b + sdelta) * inv_a;
const float z1 = aRay.m_Origin.z + t1 * aRay.m_Dir.z;
if( (z1 > m_bbox.Min().z ) &&
(z1 < m_bbox.Max().z ) )
{
if( t1 < aMaxDistance )
return true;
}
}
return false;
}
bool CVCYLINDER::Intersects( const CBBOX &aBBox ) const
{
// !TODO: improove
return m_bbox.Intersects( aBBox );
}
SFVEC3F CVCYLINDER::GetDiffuseColor( const HITINFO &aHitInfo ) const
{
(void)aHitInfo; // unused
return m_diffusecolor;
}

View File

@ -0,0 +1,66 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file ccylinder.h
* @brief
*/
#ifndef _CCYLINDER_H_
#define _CCYLINDER_H_
#include "cobject.h"
/**
* A vertical cylinder
*/
class CVCYLINDER : public COBJECT
{
public:
/**
* Constructor CVCYLINDER
* @param aCenterPoint = position of the center of the plane
* @param aXSize = size by X axis
* @param aYSize = size by Y axis
*/
CVCYLINDER( SFVEC2F aCenterPoint, float aZmin, float aZmax, float aRadius );
void SetColor( SFVEC3F aObjColor ) { m_diffusecolor = aObjColor; }
// Imported from COBJECT
bool Intersect( const RAY &aRay, HITINFO &aHitInfo ) const;
bool IntersectP(const RAY &aRay , float aMaxDistance ) const;
bool Intersects( const CBBOX &aBBox ) const;
SFVEC3F GetDiffuseColor( const HITINFO &aHitInfo ) const;
private:
SFVEC2F m_center;
float m_radius_squared;
float m_inv_radius;
SFVEC3F m_diffusecolor;
};
#endif // _CCYLINDER_H_

View File

@ -0,0 +1,90 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file cdummyblock.cpp
* @brief
*/
#include "cdummyblock.h"
CDUMMYBLOCK::CDUMMYBLOCK( const CBBOX &aBBox ) : COBJECT( OBJ3D_DUMMYBLOCK )
{
m_centroid = aBBox.GetCenter();
m_bbox.Reset();
m_bbox.Set( aBBox );
}
bool CDUMMYBLOCK::Intersect( const RAY &aRay, HITINFO &aHitInfo ) const
{
float t;
if( !m_bbox.Intersect( aRay, &t ) )
return false;
if( t < aHitInfo.m_tHit )
{
aHitInfo.m_tHit = t;
//aHitInfo.m_HitPoint = aRay.at( t );
if( aRay.m_dirIsNeg[2] )
aHitInfo.m_HitNormal = SFVEC3F( 0.0f, 0.0f, 1.0f );
else
aHitInfo.m_HitNormal = SFVEC3F( 0.0f, 0.0f,-1.0f );
aHitInfo.pHitObject = this;
return true;
}
return false;
}
bool CDUMMYBLOCK::IntersectP(const RAY &aRay , float aMaxDistance ) const
{
float t;
if( !m_bbox.Intersect( aRay, &t ) )
return false;
if( t < aMaxDistance )
return true;
return false;
}
bool CDUMMYBLOCK::Intersects( const CBBOX &aBBox ) const
{
return m_bbox.Intersects( aBBox );
}
SFVEC3F CDUMMYBLOCK::GetDiffuseColor( const HITINFO &aHitInfo ) const
{
(void)aHitInfo; // unused
return m_diffusecolor;
}

View File

@ -0,0 +1,57 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file cdummyblock.h
* @brief
*/
#ifndef _CDUMMYBLOCK_H_
#define _CDUMMYBLOCK_H_
#include "cobject.h"
/**
* A dummy block is used to fill the polygons. It will only will be intersepted
* from top or from bottom
*/
class CDUMMYBLOCK : public COBJECT
{
public:
explicit CDUMMYBLOCK( const CBBOX &aBBox );
void SetColor( SFVEC3F aObjColor ) { m_diffusecolor = aObjColor; }
// Imported from COBJECT
bool Intersect( const RAY &aRay, HITINFO &aHitInfo ) const;
bool IntersectP(const RAY &aRay , float aMaxDistance ) const;
bool Intersects( const CBBOX &aBBox ) const;
SFVEC3F GetDiffuseColor( const HITINFO &aHitInfo ) const;
private:
SFVEC3F m_diffusecolor;
};
#endif // _CDUMMYBLOCK_H_

View File

@ -0,0 +1,463 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file clayeritem.cpp
* @brief
*/
#include "clayeritem.h"
#include "3d_fastmath.h"
#include <wx/debug.h>
CLAYERITEM::CLAYERITEM( const COBJECT2D *aObject2D, float aZMin, float aZMax ) :
COBJECT( OBJ3D_LAYERITEM ),
m_object2d(aObject2D)
{
wxASSERT( aObject2D );
CBBOX2D bbox2d = m_object2d->GetBBox();
bbox2d.ScaleNextUp();
bbox2d.ScaleNextUp();
m_bbox.Reset();
m_bbox.Set( SFVEC3F( bbox2d.Min().x, bbox2d.Min().y, aZMin ),
SFVEC3F( bbox2d.Max().x, bbox2d.Max().y, aZMax ) );
m_bbox.ScaleNextUp();
m_centroid = SFVEC3F( aObject2D->GetCentroid().x,
aObject2D->GetCentroid().y,
(aZMax + aZMin) * 0.5f );
}
bool CLAYERITEM::Intersect( const RAY &aRay, HITINFO &aHitInfo ) const
{
float tBBoxStart;
float tBBoxEnd;
if( !m_bbox.Intersect( aRay, &tBBoxStart, &tBBoxEnd ) )
return false;
if( tBBoxStart >= aHitInfo.m_tHit )
return false;
if( fabs(tBBoxStart - tBBoxEnd) < FLT_EPSILON )
return false;
bool startedInside = m_bbox.Inside( aRay.m_Origin );
if( !startedInside )
{
float tTop = FLT_MAX;
float tBot = FLT_MAX;
bool hit_top = false;
bool hit_bot = false;
if( (float)fabs(aRay.m_Dir.z) > FLT_EPSILON )
{
tBot = (m_bbox.Min().z - aRay.m_Origin.z) * aRay.m_InvDir.z;
tTop = (m_bbox.Max().z - aRay.m_Origin.z) * aRay.m_InvDir.z;
float tBBoxStartAdjusted = NextFloatUp( tBBoxStart );
if( tBot > FLT_EPSILON )
{
hit_bot = tBot <= tBBoxStartAdjusted;
tBot = NextFloatDown( tBot );
}
if( tTop > FLT_EPSILON )
{
hit_top = tTop <= tBBoxStartAdjusted;
tTop = NextFloatDown( tTop );
}
}
tBBoxStart = NextFloatDown( tBBoxStart );
tBBoxEnd = NextFloatUp( tBBoxEnd );
SFVEC2F topHitPoint2d;
SFVEC2F botHitPoint2d;
if( hit_top )
topHitPoint2d = SFVEC2F( aRay.m_Origin.x + aRay.m_Dir.x * tTop,
aRay.m_Origin.y + aRay.m_Dir.y * tTop );
if( hit_bot )
botHitPoint2d = SFVEC2F( aRay.m_Origin.x + aRay.m_Dir.x * tBot,
aRay.m_Origin.y + aRay.m_Dir.y * tBot );
if( hit_top && hit_bot )
{
if( tBot < tTop )
{
if( m_object2d->IsPointInside( botHitPoint2d ) )
{
if( tBot < aHitInfo.m_tHit )
{
aHitInfo.m_tHit = tBot;
//aHitInfo.m_HitPoint = aRay.at( tBot );
aHitInfo.m_HitNormal = SFVEC3F( 0.0f, 0.0f, -1.0f );
aHitInfo.pHitObject = this;
return true;
}
return false;
}
}
else
{
if( m_object2d->IsPointInside( topHitPoint2d ) )
{
if( tTop < aHitInfo.m_tHit )
{
aHitInfo.m_tHit = tTop;
//aHitInfo.m_HitPoint = aRay.at( tTop );
aHitInfo.m_HitNormal = SFVEC3F( 0.0f, 0.0f, 1.0f );
aHitInfo.pHitObject = this;
return true;
}
return false;
}
}
}
else
{
if( hit_top )
{
if( tTop < tBot )
{
if( m_object2d->IsPointInside( topHitPoint2d ) )
{
if( tTop < aHitInfo.m_tHit )
{
aHitInfo.m_tHit = tTop;
//aHitInfo.m_HitPoint = aRay.at( tTop );
aHitInfo.m_HitNormal = SFVEC3F( 0.0f, 0.0f, 1.0f );
aHitInfo.pHitObject = this;
return true;
}
return false;
}
}
}
else
{
if( hit_bot )
{
if( tBot < tTop )
{
if( m_object2d->IsPointInside( botHitPoint2d ) )
{
if( tBot < aHitInfo.m_tHit )
{
aHitInfo.m_tHit = tBot;
//aHitInfo.m_HitPoint = aRay.at( tBot );
aHitInfo.m_HitNormal = SFVEC3F( 0.0f, 0.0f, -1.0f );
aHitInfo.pHitObject = this;
return true;
}
return false;
}
}
}
else
{
// At this point, the ray miss the two planes but it still
// hits the box. It means that the rays are "(almost)paralell"
// to the planes, so must calc the intersection
}
}
}
SFVEC3F boxHitPointStart = aRay.at( tBBoxStart );
SFVEC3F boxHitPointEnd = aRay.at( tBBoxEnd );
SFVEC2F boxHitPointStart2D( boxHitPointStart.x, boxHitPointStart.y );
//SFVEC2F boxHitPointStart2D( m_bbox.GetCenter().x, m_bbox.GetCenter().y );
SFVEC2F boxHitPointEnd2D( boxHitPointEnd.x, boxHitPointEnd.y );
float tOut;
SFVEC2F outNormal;
RAYSEG2D raySeg( boxHitPointStart2D, boxHitPointEnd2D );
if( m_object2d->Intersect( raySeg, &tOut, &outNormal ) )
{
// The hitT is a hit value for the segment length 'start' - 'end',
// so it ranges from 0.0 - 1.0. We now convert it to a 3D hit position
// and calculate the real hitT of the ray.
SFVEC3F hitPoint = boxHitPointStart +
(boxHitPointEnd - boxHitPointStart) * tOut;
const float t = glm::length( hitPoint - aRay.m_Origin );
if( t < aHitInfo.m_tHit )
{
aHitInfo.m_tHit = t;
//aHitInfo.m_HitPoint = hitPoint;
aHitInfo.m_HitNormal = SFVEC3F( outNormal.x, outNormal.y, 0.0f );
aHitInfo.pHitObject = this;
return true;
}
}
return false;
}
else
{
// Started inside
const SFVEC3F boxHitPointStart = aRay.at( tBBoxStart );
const SFVEC3F boxHitPointEnd = aRay.at( tBBoxEnd );
const SFVEC2F boxHitPointStart2D( boxHitPointStart.x, boxHitPointStart.y );
const SFVEC2F boxHitPointEnd2D( boxHitPointEnd.x, boxHitPointEnd.y );
if(!(m_object2d->IsPointInside( boxHitPointStart2D ) &&
m_object2d->IsPointInside( boxHitPointEnd2D ) ) )
return false;
float tOut;
SFVEC2F outNormal;
RAYSEG2D raySeg( boxHitPointStart2D, boxHitPointEnd2D );
if( (m_object2d->IsPointInside( boxHitPointStart2D ) &&
m_object2d->IsPointInside( boxHitPointEnd2D ) ) )
{
if( tBBoxEnd < aHitInfo.m_tHit )
{
aHitInfo.m_tHit = tBBoxEnd;
if( aRay.m_Dir.z > 0.0f )
aHitInfo.m_HitNormal = SFVEC3F( 0.0f, 0.0f, -1.0f );
else
aHitInfo.m_HitNormal = SFVEC3F( 0.0f, 0.0f, 1.0f );
aHitInfo.pHitObject = this;
return true;
}
}
else
{
if( m_object2d->Intersect( raySeg, &tOut, &outNormal ) )
{
// The hitT is a hit value for the segment length 'start' - 'end',
// so it ranges from 0.0 - 1.0. We now convert it to a 3D hit position
// and calculate the real hitT of the ray.
const SFVEC3F hitPoint = boxHitPointStart +
(boxHitPointEnd - boxHitPointStart) * tOut;
const float t = glm::length( hitPoint - aRay.m_Origin );
if( t < aHitInfo.m_tHit )
{
aHitInfo.m_tHit = t;
//aHitInfo.m_HitPoint = hitPoint;
aHitInfo.m_HitNormal = SFVEC3F( outNormal.x, outNormal.y, 0.0f );
aHitInfo.pHitObject = this;
return true;
}
}
}
}
return false;
}
bool CLAYERITEM::IntersectP(const RAY &aRay , float aMaxDistance ) const
{
float tBBoxStart;
float tBBoxEnd;
if( !m_bbox.Intersect( aRay, &tBBoxStart, &tBBoxEnd ) )
return false;
if( ( tBBoxStart > aMaxDistance ) ||
//( tBBoxEnd < FLT_EPSILON )
( fabs(tBBoxStart - tBBoxEnd) < FLT_EPSILON ) )
return false;
float tTop = FLT_MAX;
float tBot = FLT_MAX;
bool hit_top = false;
bool hit_bot = false;
if( (float)fabs(aRay.m_Dir.z) > FLT_EPSILON )
{
tBot = (m_bbox.Min().z - aRay.m_Origin.z) * aRay.m_InvDir.z;
tTop = (m_bbox.Max().z - aRay.m_Origin.z) * aRay.m_InvDir.z;
const float tBBoxStartAdjusted = NextFloatUp( tBBoxStart );
if( tBot > FLT_EPSILON )
{
hit_bot = tBot <= tBBoxStartAdjusted;
tBot = NextFloatDown( tBot );
}
if( tTop > FLT_EPSILON )
{
hit_top = tTop <= tBBoxStartAdjusted;
tTop = NextFloatDown( tTop );
}
}
tBBoxStart = NextFloatDown( tBBoxStart );
tBBoxEnd = NextFloatUp( tBBoxEnd );
SFVEC2F topHitPoint2d;
SFVEC2F botHitPoint2d;
if( hit_top )
topHitPoint2d = SFVEC2F( aRay.m_Origin.x + aRay.m_Dir.x * tTop,
aRay.m_Origin.y + aRay.m_Dir.y * tTop );
if( hit_bot )
botHitPoint2d = SFVEC2F( aRay.m_Origin.x + aRay.m_Dir.x * tBot,
aRay.m_Origin.y + aRay.m_Dir.y * tBot );
if( hit_top && hit_bot )
{
if( tBot < tTop )
{
if( m_object2d->IsPointInside( botHitPoint2d ) )
{
if( tBot < aMaxDistance )
return true;
return false;
}
}
else
{
if( m_object2d->IsPointInside( topHitPoint2d ) )
{
if( tTop < aMaxDistance )
return true;
return false;
}
}
}
else
{
if( hit_top )
{
if( tTop < tBot )
{
if( m_object2d->IsPointInside( topHitPoint2d ) )
{
if( tTop < aMaxDistance )
return true;
return false;
}
}
}
else
{
if( hit_bot )
{
if( tBot < tTop )
{
if( m_object2d->IsPointInside( botHitPoint2d ) )
{
if( tBot < aMaxDistance )
return true;
return false;
}
}
}
else
{
// At this point, the ray miss the two planes but it still
// hits the box. It means that the rays are "(almost)paralell"
// to the planes, so must calc the intersection
}
}
}
SFVEC3F boxHitPointStart = aRay.at( tBBoxStart );
SFVEC3F boxHitPointEnd = aRay.at( tBBoxEnd );
SFVEC2F boxHitPointStart2D( boxHitPointStart.x, boxHitPointStart.y );
SFVEC2F boxHitPointEnd2D( boxHitPointEnd.x, boxHitPointEnd.y );
float tOut;
SFVEC2F outNormal;
RAYSEG2D raySeg( boxHitPointStart2D, boxHitPointEnd2D );
if( m_object2d->Intersect( raySeg, &tOut, &outNormal ) )
{
//if( (tOut > FLT_EPSILON) && (tOut < 1.0f) )
{
// The hitT is a hit value for the segment length 'start' - 'end',
// so it ranges from 0.0 - 1.0. We now convert it to a 3D hit position
// and calculate the real hitT of the ray.
const SFVEC3F hitPoint = boxHitPointStart +
(boxHitPointEnd - boxHitPointStart) * tOut;
const float t = glm::length( hitPoint - aRay.m_Origin );
if( (t < 1.0f) && ( t > FLT_EPSILON ) )
return true;
}
}
return false;
}
bool CLAYERITEM::Intersects( const CBBOX &aBBox ) const
{
if( !m_bbox.Intersects( aBBox ) )
return false;
const CBBOX2D bbox2D( SFVEC2F( aBBox.Min().x, aBBox.Min().y),
SFVEC2F( aBBox.Max().x, aBBox.Max().y) );
return m_object2d->Intersects( bbox2D );
}
SFVEC3F CLAYERITEM::GetDiffuseColor( const HITINFO &aHitInfo ) const
{
(void)aHitInfo; // unused
return m_diffusecolor;
}

View File

@ -0,0 +1,58 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file clayeritem.h
* @brief
*/
#ifndef _CLAYERITEM_H_
#define _CLAYERITEM_H_
#include "cobject.h"
#include "../shapes2D/cobject2d.h"
class CLAYERITEM : public COBJECT
{
protected:
const COBJECT2D *m_object2d;
public:
CLAYERITEM( const COBJECT2D *aObject2D, float aZMin, float aZMax );
void SetColor( SFVEC3F aObjColor ) { m_diffusecolor = aObjColor; }
// Imported from COBJECT
bool Intersect( const RAY &aRay, HITINFO &aHitInfo ) const;
bool IntersectP(const RAY &aRay , float aMaxDistance ) const;
bool Intersects( const CBBOX &aBBox ) const;
SFVEC3F GetDiffuseColor( const HITINFO &aHitInfo ) const;
private:
SFVEC3F m_diffusecolor;
};
#endif // _CLAYERITEM_H_

View File

@ -0,0 +1,65 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file cobject.cpp
* @brief
*/
#include "cobject.h"
#include <stdio.h>
COBJECT3D_STATS *COBJECT3D_STATS::s_instance = 0;
static const CBLINN_PHONG_MATERIAL s_defaultMaterial = CBLINN_PHONG_MATERIAL();
COBJECT::COBJECT( OBJECT3D_TYPE aObjType )
{
m_obj_type = aObjType;
COBJECT3D_STATS::Instance().AddOne( aObjType );
m_material = &s_defaultMaterial;
}
static const char *OBJECT3D_STR[OBJ3D_MAX] =
{
"OBJ3D_CYLINDER",
"OBJ3D_DUMMYBLOCK",
"OBJ3D_LAYERITEM",
"OBJ3D_XYPLANE",
"OBJ3D_ROUNDSEG",
"OBJ3D_TRIANGLE"
};
void COBJECT3D_STATS::PrintStats()
{
printf( "OBJ3D Statistics:\n" );
for( unsigned int i = 0; i < OBJ3D_MAX; ++i )
{
printf( " %20s %u\n", OBJECT3D_STR[i], m_counter[i] );
}
}

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -30,7 +30,6 @@
#ifndef _COBJECT_H_
#define _COBJECT_H_
#include "plugins/3dapi/xv3d_types.h"
#include "cbbox.h"
#include "../hitinfo.h"
#include "../cmaterial.h"
@ -47,7 +46,7 @@ enum OBJECT3D_TYPE
OBJ3D_MAX
};
class GLM_ALIGN(CLASS_ALIGNMENT) COBJECT
class COBJECT
{
protected:
CBBOX m_bbox;
@ -57,7 +56,7 @@ protected:
public:
COBJECT( OBJECT3D_TYPE aObjType );
explicit COBJECT( OBJECT3D_TYPE aObjType );
void SetMaterial( const CMATERIAL *aMaterial ) { m_material = aMaterial; }
const CMATERIAL *GetMaterial() const { return m_material; }
@ -103,7 +102,9 @@ class COBJECT3D_STATS
{
public:
void ResetStats() { memset( m_counter, 0, sizeof(unsigned int) * OBJ3D_MAX ); }
void ResetStats() { memset( m_counter,
0,
sizeof( unsigned int ) * OBJ3D_MAX ); }
unsigned int GetCountOf( OBJECT3D_TYPE aObjType ) const { return m_counter[aObjType]; }

View File

@ -0,0 +1,130 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file cplane.cpp
* @brief
*/
#include "cplane.h"
CXYPLANE::CXYPLANE( const CBBOX &aBBox ) : COBJECT( OBJ3D_XYPLANE )
{
m_centerPoint = aBBox.GetCenter();
m_centroid = m_centerPoint;
m_bbox.Reset();
m_bbox.Set( aBBox );
m_xsize = aBBox.GetExtent().x;
m_ysize = aBBox.GetExtent().y;
m_xsize_inv2 = 1.0f / (2.0f * m_xsize);
m_ysize_inv2 = 1.0f / (2.0f * m_ysize);
}
CXYPLANE::CXYPLANE( SFVEC3F aCenterPoint,
float aXSize,
float aYSize ) : COBJECT( OBJ3D_XYPLANE )
{
m_centerPoint = aCenterPoint;
m_xsize = aXSize;
m_ysize = aYSize;
m_xsize_inv2 = 1.0f / (2.0f * aXSize);
m_ysize_inv2 = 1.0f / (2.0f * aYSize);
m_bbox.Set( SFVEC3F( aCenterPoint.x - aXSize / 2.0f,
aCenterPoint.y - aYSize / 2.0f,
aCenterPoint.z ),
SFVEC3F( aCenterPoint.x + aXSize / 2.0f,
aCenterPoint.y + aYSize / 2.0f,
aCenterPoint.z ) );
m_centroid = aCenterPoint;
}
bool CXYPLANE::Intersect( const RAY &aRay, HITINFO &aHitInfo ) const
{
const float t = (m_centerPoint.z - aRay.m_Origin.z) * aRay.m_InvDir.z;
if( ( t < FLT_EPSILON ) ||
( t >= aHitInfo.m_tHit ) )
return false;
const float vSU = t * aRay.m_Dir.x + aRay.m_Origin.x - m_centerPoint.x;
if( (vSU < -m_xsize) || (vSU > m_xsize) )
return false;
const float vSV = t * aRay.m_Dir.y + aRay.m_Origin.y - m_centerPoint.y;
if( (vSV < -m_ysize) || (vSV > m_ysize) )
return false;
aHitInfo.m_tHit = t;
//aHitInfo.m_HitPoint = aRay.at( t );
aHitInfo.pHitObject = this;
if( aRay.m_dirIsNeg[2] )
aHitInfo.m_HitNormal = SFVEC3F( 0.0f, 0.0f, 1.0f );
else
aHitInfo.m_HitNormal = SFVEC3F( 0.0f, 0.0f,-1.0f );
return true;
}
bool CXYPLANE::IntersectP(const RAY &aRay , float aMaxDistance ) const
{
const float t = (m_centerPoint.z - aRay.m_Origin.z) * aRay.m_InvDir.z;
if( ( t < FLT_EPSILON ) ||
( t >= aMaxDistance ) )
return false;
const float vSU = t * aRay.m_Dir.x + aRay.m_Origin.x - m_centerPoint.x;
if( (vSU < -m_xsize) || (vSU > m_xsize) )
return false;
const float vSV = t * aRay.m_Dir.y + aRay.m_Origin.y - m_centerPoint.y;
if( (vSV < -m_ysize) || (vSV > m_ysize) )
return false;
return true;
}
bool CXYPLANE::Intersects( const CBBOX &aBBox ) const
{
return m_bbox.Intersects( aBBox );
}
SFVEC3F CXYPLANE::GetDiffuseColor( const HITINFO &aHitInfo ) const
{
(void)aHitInfo; // unused
return m_diffusecolor;
}

Some files were not shown because too many files have changed in this diff Show More