Commit 31ff1bac authored by jean-pierre charras's avatar jean-pierre charras

3D viewer:

  *  serious code cleanup (remove duplicate code)
  *  shows (option in 3D preference menu) the copper items (tracks, zones...)  in 3D, using 35 microns copper thickness.
      However, because there are a lot more3D data to show (roughly 4 times more), this is slower.
parent 0c4c65d7
......@@ -44,6 +44,9 @@
#include <info3d_visu.h>
#include <trackball.h>
// Exported function:
void Set_Object_Data( std::vector< S3D_VERTEX >& aVertices, double aBiuTo3DUnits );
void S3D_MASTER::Set_Object_Coords( std::vector< S3D_VERTEX >& aVertices )
{
......@@ -75,7 +78,7 @@ void S3D_MASTER::Set_Object_Coords( std::vector< S3D_VERTEX >& aVertices )
}
void Set_Object_Data( std::vector< S3D_VERTEX >& aVertices )
void Set_Object_Data( std::vector< S3D_VERTEX >& aVertices, double aBiuTo3DUnits )
{
unsigned ii;
GLfloat ax, ay, az, bx, by, bz, nx, ny, nz, r;
......@@ -126,9 +129,9 @@ void Set_Object_Data( std::vector< S3D_VERTEX >& aVertices )
/* draw polygon/triangle/quad */
for( ii = 0; ii < aVertices.size(); ii++ )
{
glVertex3f( aVertices[ii].x * DataScale3D,
aVertices[ii].y * DataScale3D,
aVertices[ii].z * DataScale3D );
glVertex3f( aVertices[ii].x * aBiuTo3DUnits,
aVertices[ii].y * aBiuTo3DUnits,
aVertices[ii].z * aBiuTo3DUnits );
}
glEnd();
......@@ -172,35 +175,6 @@ GLuint EDA_3D_CANVAS::DisplayCubeforTest()
return gllist;
}
INFO3D_VISU::INFO3D_VISU()
{
int ii;
m_Beginx = m_Beginy = 0.0; // position of mouse
m_Zoom = 1.0;
m_3D_Grid = 10.0; // Grid value in mm
trackball( m_Quat, 0.0, 0.0, 0.0, 0.0 );
for( ii = 0; ii < 4; ii++ )
m_Rot[ii] = 0.0;
m_CopperLayersCount = 2;
m_BoardSettings = NULL;
// default all special item layers Visible
for( ii = 0; ii < FL_LAST; ii++)
m_DrawFlags[ii] = true;
m_DrawFlags[FL_GRID] = false;
}
INFO3D_VISU::~INFO3D_VISU()
{
}
VERTEX_VALUE_CTRL::VERTEX_VALUE_CTRL( wxWindow* parent, const wxString& title,
wxBoxSizer* BoxSizer )
{
......
......@@ -45,59 +45,13 @@
#include <3d_viewer.h>
#include <info3d_visu.h>
#include <trackball.h>
#include <3d_draw_basic_functions.h>
// angle increment to draw a circle, approximated by segments
#define ANGLE_INC(x) (3600/(x))
// Thickness of copper
// TODO: use the actual copper thickness to draw copper items with thickness
#define COPPER_THICKNESS (int)(0.035 * IU_PER_MM)
// Imported function:
extern void SetGLColor( int color );
extern void Set_Object_Data( std::vector< S3D_VERTEX >& aVertices, double aBiuTo3DUnits );
extern void CheckGLError();
/* draw a thick segment using 3D primitives, in a XY plane
* wxPoint aStart, wxPoint aEnd = YX position of ends 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
*/
static void Draw3D_SolidSegment( const wxPoint& aStart, const wxPoint& aEnd,
int aWidth, int aThickness, int aZpos,
double aBiuTo3DUnits );
static void Draw3D_SegmentWithHole( double startx, double starty,
double endx, double endy,
double width, double holex,
double holey, double holeradius,
double zpos );
/* draw an arc using 3D primitives, in a plane parallel to the XY plane
* aCenterPos = 3D position of the center
* aStartPointX, aStartPointY = start point coordinate of arc (3D units)
* aWidth = width of the circle (3D units)
* aArcAngle = arc angle in 1/10 degrees
* aWidth = thickness of arc
*/
static void Draw3D_ArcSegment( const S3D_VERTEX& aCenterPos,
double aStartPointX, double aStartPointY,
double aArcAngle, double aWidth );
/* draw a circle with hole using 3D primitives, in a XY plane
* aCenterPos = 3D position of the center
* aRadius = radius of the circle (3D units)
* aHoleRadius = radius of the hole (3D units)
* Used to draw vias and round pads with round hole
*/
static void Draw3D_FilledCircleWithHole( const S3D_VERTEX& aPos, double aRadius, double aHoleRadius );
/* draw a circle using 3D primitives, in a plane parallel to the XY plane
* aCenterPos = 3D position of the center
* aRadius = radius of the circle (3D units)
* aWidth = width of the circle (3D units)
* Does the same think as Draw3D_FilledCircleWithHole, just does not use the same parmeters
* Used to draw circular segments
*/
static void Draw3D_ThickCircle( const S3D_VERTEX& aCenterPos, double aRadius, double aWidth );
/* returns true if aLayer should be displayed, false otherwise
*/
......@@ -110,38 +64,6 @@ static bool Is3DLayerEnabled( int aLayer );
*/
static GLfloat Get3DLayer_Z_Orientation( int aLayer );
/* draw a cylinder using 3D primitives.
* the cylinder axis is parallel to the Z axis
* aCenterPos = 3D position of the axis cylinder
* aRadius = radius of the cylinder (3D units)
* aHeight = height of the cylinder (3D units)
*/
static void Draw3D_ZaxisCylinder( const S3D_VERTEX& aPos, double aRadius, double aHeight );
/* draw an oblong cylinder (oblong hole) using 3D primitives.
* the cylinder axis are parallel to the Z axis
* aStartPos = 3D position of the first axis cylinder
* aEndx, aEndy = 3D position of the second axis cylinder
* aRadius = radius of the cylinder (3D units)
* aHeight = height of the cylinder (3D units)
*/
static void Draw3D_ZaxisOblongCylinder( const S3D_VERTEX& aStartPos,
double aEndx, double aEndy,
double aRadius, double aHeight );
#ifndef CALLBACK
#define CALLBACK
#endif
// 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 );
static void CALLBACK tesswxPoint2Vertex( const GLvoid* data );
void EDA_3D_CANVAS::Redraw( bool finish )
{
// SwapBuffer requires the window to be shown before calling
......@@ -203,104 +125,8 @@ GLuint EDA_3D_CANVAS::CreateDrawGL_List()
m_gllist = glGenLists( 1 );
EDA_RECT bbbox = pcbframe->GetBoardBoundingBox();
g_Parm_3D_Visu.m_BoardSettings = &pcb->GetDesignSettings();
g_Parm_3D_Visu.m_BoardSize = bbbox.GetSize();
g_Parm_3D_Visu.m_BoardPos = bbbox.Centre();
g_Parm_3D_Visu.m_BoardPos.y = -g_Parm_3D_Visu.m_BoardPos.y;
g_Parm_3D_Visu.m_CopperLayersCount = pcb->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( g_Parm_3D_Visu.m_CopperLayersCount < 2 )
g_Parm_3D_Visu.m_CopperLayersCount = 2;
g_Parm_3D_Visu.m_BoardScale = 2.0 / std::max( g_Parm_3D_Visu.m_BoardSize.x,
g_Parm_3D_Visu.m_BoardSize.y );
g_Parm_3D_Visu.m_EpoxyThickness = pcb->GetDesignSettings().GetBoardThickness()
* g_Parm_3D_Visu.m_BoardScale;
// Arbitrary choose a thickness for non copper layers:
g_Parm_3D_Visu.m_NonCopperLayerThickness = g_Parm_3D_Visu.m_EpoxyThickness / 20;
// Init Z position of each layer
// calculate z position for each copper layer
int layer;
int copper_layers_cnt = g_Parm_3D_Visu.m_CopperLayersCount;
for( layer = 0; layer < copper_layers_cnt; layer++ )
{
g_Parm_3D_Visu.m_LayerZcoord[layer] =
g_Parm_3D_Visu.m_EpoxyThickness * layer / (copper_layers_cnt - 1);
}
double zpos_copper_back = g_Parm_3D_Visu.m_LayerZcoord[0];
double zpos_copper_front = g_Parm_3D_Visu.m_EpoxyThickness;
// Fill remaining unused copper layers and front layer zpos
// with g_Parm_3D_Visu.m_EpoxyThickness
for( ; layer <= LAST_COPPER_LAYER; layer++ )
{
g_Parm_3D_Visu.m_LayerZcoord[layer] = g_Parm_3D_Visu.m_EpoxyThickness;
}
// calculate z position for each non copper layer
for( int layer_id = FIRST_NO_COPPER_LAYER; layer_id < NB_LAYERS; layer_id++ )
{
double zpos;
switch( layer_id )
{
case ADHESIVE_N_BACK:
zpos = zpos_copper_back -
4 * g_Parm_3D_Visu.m_NonCopperLayerThickness;
break;
case ADHESIVE_N_FRONT:
zpos = zpos_copper_front +
4 * g_Parm_3D_Visu.m_NonCopperLayerThickness;
break;
case SOLDERPASTE_N_BACK:
zpos = zpos_copper_back -
3 * g_Parm_3D_Visu.m_NonCopperLayerThickness;
break;
case SOLDERPASTE_N_FRONT:
zpos = zpos_copper_front +
3 * g_Parm_3D_Visu.m_NonCopperLayerThickness;
break;
case SOLDERMASK_N_BACK:
zpos = zpos_copper_back -
1 * g_Parm_3D_Visu.m_NonCopperLayerThickness;
break;
case SOLDERMASK_N_FRONT:
zpos = zpos_copper_front +
1 * g_Parm_3D_Visu.m_NonCopperLayerThickness;
break;
case SILKSCREEN_N_BACK:
zpos = zpos_copper_back -
2 * g_Parm_3D_Visu.m_NonCopperLayerThickness;
break;
case SILKSCREEN_N_FRONT:
zpos = zpos_copper_front +
2 * g_Parm_3D_Visu.m_NonCopperLayerThickness;
break;
default:
zpos = zpos_copper_front +
(layer_id - FIRST_NO_COPPER_LAYER + 5) *
g_Parm_3D_Visu.m_NonCopperLayerThickness;
break;
}
g_Parm_3D_Visu.m_LayerZcoord[layer_id] = zpos;
}
// Build 3D board parameters:
g_Parm_3D_Visu.InitSettings( pcb );
glNewList( m_gllist, GL_COMPILE_AND_EXECUTE );
......@@ -323,12 +149,9 @@ GLuint EDA_3D_CANVAS::CreateDrawGL_List()
glEnd();
}
// Draw epoxy limits (do not use, works and test in progress)
// TODO
// move the board in order to draw it with its center at 0,0 3D coordinates
glTranslatef( -g_Parm_3D_Visu.m_BoardPos.x * g_Parm_3D_Visu.m_BoardScale,
-g_Parm_3D_Visu.m_BoardPos.y * g_Parm_3D_Visu.m_BoardScale,
glTranslatef( -g_Parm_3D_Visu.m_BoardPos.x * g_Parm_3D_Visu.m_BiuTo3Dunits,
-g_Parm_3D_Visu.m_BoardPos.y * g_Parm_3D_Visu.m_BiuTo3Dunits,
0.0F );
glNormal3f( 0.0, 0.0, 1.0 ); // Normal is Z axis
......@@ -358,6 +181,9 @@ GLuint EDA_3D_CANVAS::CreateDrawGL_List()
}
}
// Draw epoxy limits: TODO
// draw graphic items
EDA_ITEM* PtStruct;
......@@ -410,11 +236,14 @@ void EDA_3D_CANVAS::Draw3D_Zone( ZONE_CONTAINER* aZone )
{
int layer = aZone->GetLayer();
int color = g_ColorsSettings.GetLayerColor( layer );
int thickness = layer >= FIRST_NO_COPPER_LAYER ?
g_Parm_3D_Visu.GetNonCopperLayerThicknessBIU() :
g_Parm_3D_Visu.GetCopperThicknessBIU();
if( layer == LAST_COPPER_LAYER )
layer = g_Parm_3D_Visu.m_CopperLayersCount - 1;
int zpos = KiROUND( g_Parm_3D_Visu.m_LayerZcoord[layer] / g_Parm_3D_Visu.m_BoardScale );
int zpos = KiROUND( g_Parm_3D_Visu.m_LayerZcoord[layer] / g_Parm_3D_Visu.m_BiuTo3Dunits );
SetGLColor( color );
glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( layer ) );
......@@ -424,7 +253,9 @@ void EDA_3D_CANVAS::Draw3D_Zone( ZONE_CONTAINER* aZone )
// solid polygons only are used to fill areas
if( aZone->GetFilledPolysList().size() > 3 )
{
Draw3D_SolidPolygonsInZones( aZone );
Draw3D_SolidHorizontalPolyPolygons( aZone->GetFilledPolysList(),
g_Parm_3D_Visu.GetLayerZcoordBIU( layer ),
thickness, g_Parm_3D_Visu.m_BiuTo3Dunits );
}
}
else
......@@ -433,8 +264,8 @@ void EDA_3D_CANVAS::Draw3D_Zone( ZONE_CONTAINER* aZone )
for( unsigned iseg = 0; iseg < aZone->m_FillSegmList.size(); iseg++ )
Draw3D_SolidSegment( aZone->m_FillSegmList[iseg].m_Start,
aZone->m_FillSegmList[iseg].m_End,
aZone->m_ZoneMinThickness, COPPER_THICKNESS, zpos,
g_Parm_3D_Visu.m_BoardScale );
aZone->m_ZoneMinThickness, thickness, zpos,
g_Parm_3D_Visu.m_BiuTo3Dunits );
}
// Draw copper area outlines
......@@ -460,8 +291,8 @@ void EDA_3D_CANVAS::Draw3D_Zone( ZONE_CONTAINER* aZone )
wxPoint start( begincorner->x, begincorner->y );
wxPoint end( endcorner->x, endcorner->y );
Draw3D_SolidSegment( start, end,
aZone->m_ZoneMinThickness, COPPER_THICKNESS, zpos,
g_Parm_3D_Visu.m_BoardScale );
aZone->m_ZoneMinThickness, thickness, zpos,
g_Parm_3D_Visu.m_BiuTo3Dunits );
}
if( (endcorner->end_contour) || (ic == imax) )
......@@ -473,8 +304,8 @@ void EDA_3D_CANVAS::Draw3D_Zone( ZONE_CONTAINER* aZone )
wxPoint start( endcorner->x, endcorner->y );
wxPoint end( firstcorner->x, firstcorner->y );
Draw3D_SolidSegment( start, end,
aZone->m_ZoneMinThickness, COPPER_THICKNESS, zpos,
g_Parm_3D_Visu.m_BoardScale );
aZone->m_ZoneMinThickness, thickness, zpos,
g_Parm_3D_Visu.m_BiuTo3Dunits );
}
ic++;
......@@ -490,13 +321,14 @@ void EDA_3D_CANVAS::Draw3D_Zone( ZONE_CONTAINER* aZone )
}
// draw mm grid..
// 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::DrawGrid( double aGriSizeMM )
{
double zpos = -g_Parm_3D_Visu.m_NonCopperLayerThickness/2;
double zpos = 0.0;
int gridcolor = DARKGRAY; // Color of grid lines
int gridcolor_marker = LIGHTGRAY; // Color of grid lines every 5 lines
double scale = g_Parm_3D_Visu.m_BoardScale;
double scale = g_Parm_3D_Visu.m_BiuTo3Dunits;
glNormal3f( 0.0, 0.0, 1.0 );
......@@ -625,96 +457,37 @@ void EDA_3D_CANVAS::Draw3D_Track( TRACK* aTrack )
{
int layer = aTrack->GetLayer();
int color = g_ColorsSettings.GetLayerColor( layer );
int thickness = g_Parm_3D_Visu.GetCopperThicknessBIU();
if( layer == LAST_COPPER_LAYER )
layer = g_Parm_3D_Visu.m_CopperLayersCount - 1;
int zpos = KiROUND( g_Parm_3D_Visu.m_LayerZcoord[layer] / g_Parm_3D_Visu.m_BoardScale );
int zpos = KiROUND( g_Parm_3D_Visu.m_LayerZcoord[layer] / g_Parm_3D_Visu.m_BiuTo3Dunits );
SetGLColor( color );
glNormal3f( 0.0, 0.0, (layer == LAYER_N_BACK) ? -1.0 : 1.0 );
Draw3D_SolidSegment( aTrack->m_Start, aTrack->m_End,
aTrack->m_Width, COPPER_THICKNESS, zpos,
g_Parm_3D_Visu.m_BoardScale );
}
void EDA_3D_CANVAS::Draw3D_SolidPolygonsInZones( ZONE_CONTAINER* aZone )
{
double zpos;
int layer = aZone->GetLayer();
int color = g_ColorsSettings.GetLayerColor( layer );
if( layer == LAST_COPPER_LAYER )
layer = g_Parm_3D_Visu.m_CopperLayersCount - 1;
zpos = g_Parm_3D_Visu.m_LayerZcoord[layer];
g_Parm_3D_Visu.m_ActZpos = zpos;
SetGLColor( color );
glNormal3f( 0.0, 0.0, (layer == LAYER_N_BACK) ? -1.0 : 1.0 );
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];
v_data[2] = zpos;
//gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);
// Draw solid areas contained in this zone
int StartContour = 1;
std::vector<CPolyPt> polysList = aZone->GetFilledPolysList();
for( unsigned ii = 0; ii < polysList.size(); ii++ )
{
if( StartContour == 1 )
{
gluTessBeginPolygon( tess, NULL );
gluTessBeginContour( tess );
StartContour = 0;
}
v_data[0] = polysList[ii].x * g_Parm_3D_Visu.m_BoardScale;
v_data[1] = -polysList[ii].y * g_Parm_3D_Visu.m_BoardScale;
gluTessVertex( tess, v_data, &polysList[ii] );
if( polysList[ii].end_contour == 1 )
{
gluTessEndContour( tess );
gluTessEndPolygon( tess );
StartContour = 1;
}
}
gluDeleteTess( tess );
aTrack->m_Width, thickness, zpos,
g_Parm_3D_Visu.m_BiuTo3Dunits );
}
void EDA_3D_CANVAS::Draw3D_Via( SEGVIA* via )
{
double x, y, r, hole;
int layer, top_layer, bottom_layer;
double zpos, height;
int color;
double biu_to_3Dunits = g_Parm_3D_Visu.m_BiuTo3Dunits ;
r = via->m_Width * g_Parm_3D_Visu.m_BoardScale / 2;
hole = via->GetDrillValue();
hole *= g_Parm_3D_Visu.m_BoardScale / 2;
x = via->m_Start.x * g_Parm_3D_Visu.m_BoardScale;
y = via->m_Start.y * g_Parm_3D_Visu.m_BoardScale;
int outer_radius = via->m_Width / 2;
int inner_radius = via->GetDrillValue() / 2;
int thickness = g_Parm_3D_Visu.GetCopperThicknessBIU();
via->ReturnLayerPair( &top_layer, &bottom_layer );
// Drawing filled circles:
// Drawing horizontal thick rings:
for( layer = bottom_layer; layer < g_Parm_3D_Visu.m_CopperLayersCount; layer++ )
{
zpos = g_Parm_3D_Visu.m_LayerZcoord[layer];
int zpos = KiROUND( g_Parm_3D_Visu.m_LayerZcoord[layer] / biu_to_3Dunits );
if( layer < g_Parm_3D_Visu.m_CopperLayersCount - 1 )
{
......@@ -733,26 +506,25 @@ void EDA_3D_CANVAS::Draw3D_Via( SEGVIA* via )
SetGLColor( color );
glNormal3f( 0.0, 0.0, (layer == LAYER_N_BACK) ? -1.0 : 1.0 );
if( layer == LAYER_N_BACK )
zpos = zpos - 5 * g_Parm_3D_Visu.m_BoardScale;
else
zpos = zpos + 5 * g_Parm_3D_Visu.m_BoardScale;
S3D_VERTEX pos( x, -y, zpos);
Draw3D_FilledCircleWithHole( pos, r, hole );
if( thickness == 0 )
glNormal3f( 0.0, 0.0, layer == LAYER_N_BACK ? -1.0 : 1.0 );
Draw3D_ZaxisCylinder( via->m_Start, (outer_radius + inner_radius)/2,
thickness, outer_radius - inner_radius,
zpos - (thickness/2), biu_to_3Dunits );
if( layer >= top_layer )
break;
}
// Drawing hole:
// Drawing via hole:
color = g_ColorsSettings.GetItemColor( VIAS_VISIBLE + via->m_Shape );
SetGLColor( color );
height = g_Parm_3D_Visu.m_LayerZcoord[top_layer] - g_Parm_3D_Visu.m_LayerZcoord[bottom_layer];
S3D_VERTEX position( x, -y, g_Parm_3D_Visu.m_LayerZcoord[bottom_layer] );
Draw3D_ZaxisCylinder( position, hole, height );
int height = g_Parm_3D_Visu.GetLayerZcoordBIU(top_layer) -
g_Parm_3D_Visu.m_LayerZcoord[bottom_layer] - thickness;
int zpos = g_Parm_3D_Visu.GetLayerZcoordBIU(bottom_layer) + thickness/2;
Draw3D_ZaxisCylinder( via->m_Start, inner_radius + thickness/2, height,
thickness, zpos, biu_to_3Dunits );
}
......@@ -760,14 +532,17 @@ void EDA_3D_CANVAS::Draw3D_DrawSegment( DRAWSEGMENT* segment )
{
int layer = segment->GetLayer();
int color = g_ColorsSettings.GetLayerColor( layer );
int thickness = layer >= FIRST_NO_COPPER_LAYER ?
g_Parm_3D_Visu.GetNonCopperLayerThicknessBIU() :
g_Parm_3D_Visu.GetCopperThicknessBIU();
SetGLColor( color );
double w = segment->GetWidth() * g_Parm_3D_Visu.m_BoardScale;
double x = segment->GetStart().x * g_Parm_3D_Visu.m_BoardScale;
double y = segment->GetStart().y * g_Parm_3D_Visu.m_BoardScale;
double xf = segment->GetEnd().x * g_Parm_3D_Visu.m_BoardScale;
double yf = segment->GetEnd().y * g_Parm_3D_Visu.m_BoardScale;
double w = segment->GetWidth() * g_Parm_3D_Visu.m_BiuTo3Dunits;
double x = segment->GetStart().x * g_Parm_3D_Visu.m_BiuTo3Dunits;
double y = segment->GetStart().y * g_Parm_3D_Visu.m_BiuTo3Dunits;
double xf = segment->GetEnd().x * g_Parm_3D_Visu.m_BiuTo3Dunits;
double yf = segment->GetEnd().y * g_Parm_3D_Visu.m_BiuTo3Dunits;
if( layer == EDGE_N )
{
......@@ -787,17 +562,21 @@ void EDA_3D_CANVAS::Draw3D_DrawSegment( DRAWSEGMENT* segment )
case S_CIRCLE:
{
S3D_VERTEX pos( x, -y, zpos );
Draw3D_ThickCircle( pos, hypot( x - xf, y - yf ), w );
int radius = KiROUND( hypot( double(segment->GetStart().x - segment->GetEnd().x),
double(segment->GetStart().y - segment->GetEnd().y) )
);
Draw3D_ZaxisCylinder( segment->GetStart(), radius,
thickness, segment->GetWidth(),
g_Parm_3D_Visu.GetLayerZcoordBIU(layer),
g_Parm_3D_Visu.m_BiuTo3Dunits );
}
break;
default:
Draw3D_SolidSegment( segment->GetStart(), segment->GetEnd(),
segment->GetWidth(), COPPER_THICKNESS,
KiROUND( g_Parm_3D_Visu.m_LayerZcoord[layer] /
g_Parm_3D_Visu.m_BoardScale ),
g_Parm_3D_Visu.m_BoardScale );
segment->GetWidth(), thickness,
g_Parm_3D_Visu.GetLayerZcoordBIU(layer),
g_Parm_3D_Visu.m_BiuTo3Dunits );
break;
}
}
......@@ -820,17 +599,21 @@ void EDA_3D_CANVAS::Draw3D_DrawSegment( DRAWSEGMENT* segment )
case S_CIRCLE:
{
S3D_VERTEX pos( x, -y, zpos );
Draw3D_ThickCircle( pos, hypot( x - xf, y - yf ), w );
int radius = KiROUND( hypot( double(segment->GetStart().x - segment->GetEnd().x),
double(segment->GetStart().y - segment->GetEnd().y) )
);
Draw3D_ZaxisCylinder( segment->GetStart(), radius,
thickness, segment->GetWidth(),
g_Parm_3D_Visu.GetLayerZcoordBIU(layer),
g_Parm_3D_Visu.m_BiuTo3Dunits );
}
break;
default:
Draw3D_SolidSegment( segment->GetStart(), segment->GetEnd(),
segment->GetWidth(), COPPER_THICKNESS,
KiROUND( g_Parm_3D_Visu.m_LayerZcoord[layer] /
g_Parm_3D_Visu.m_BoardScale ),
g_Parm_3D_Visu.m_BoardScale );
segment->GetWidth(), thickness,
g_Parm_3D_Visu.GetLayerZcoordBIU(layer),
g_Parm_3D_Visu.m_BiuTo3Dunits );
break;
}
}
......@@ -841,14 +624,14 @@ void EDA_3D_CANVAS::Draw3D_DrawSegment( DRAWSEGMENT* segment )
// These variables are used in Draw3dTextSegm.
// But Draw3dTextSegm is a call back function, so we cannot send them as arguments,
// so they are static.
int s_Text3DWidth, s_Text3DZPos;
int s_Text3DWidth, s_Text3DZPos, s_thickness;
// This is a call back function, used by DrawGraphicText to draw the 3D text shape:
static void Draw3dTextSegm( int x0, int y0, int xf, int yf )
{
Draw3D_SolidSegment( wxPoint( x0, y0), wxPoint( xf, yf ),
s_Text3DWidth, COPPER_THICKNESS, s_Text3DZPos,
g_Parm_3D_Visu.m_BoardScale );
s_Text3DWidth, s_thickness, s_Text3DZPos,
g_Parm_3D_Visu.m_BiuTo3Dunits );
}
......@@ -858,10 +641,13 @@ void EDA_3D_CANVAS::Draw3D_DrawText( TEXTE_PCB* text )
int color = g_ColorsSettings.GetLayerColor( layer );
SetGLColor( color );
s_Text3DZPos = KiROUND( g_Parm_3D_Visu.m_LayerZcoord[layer] / g_Parm_3D_Visu.m_BoardScale );
s_Text3DZPos = KiROUND( g_Parm_3D_Visu.m_LayerZcoord[layer] / g_Parm_3D_Visu.m_BiuTo3Dunits );
s_Text3DWidth = text->GetThickness();
glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( layer ) );
wxSize size = text->m_Size;
s_thickness = layer >= FIRST_NO_COPPER_LAYER ?
g_Parm_3D_Visu.GetNonCopperLayerThicknessBIU() :
g_Parm_3D_Visu.GetCopperThicknessBIU();
if( text->m_Mirror )
NEGATE( size.x );
......@@ -906,13 +692,8 @@ void MODULE::Draw3D( EDA_3D_CANVAS* glcanvas )
D_PAD* pad = m_Pads;
// Draw pads
glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
glNormal3f( 0.0, 0.0, 1.0 ); // Normal is Z axis
for( ; pad != NULL; pad = pad->Next() )
{
pad->Draw3D( glcanvas );
}
// Draw module shape: 3D shape if exists (or module outlines if not exists)
S3D_MASTER* Struct3D = m_3D_Drawings;
......@@ -922,8 +703,8 @@ void MODULE::Draw3D( EDA_3D_CANVAS* glcanvas )
{
glPushMatrix();
glTranslatef( m_Pos.x * g_Parm_3D_Visu.m_BoardScale,
-m_Pos.y * g_Parm_3D_Visu.m_BoardScale,
glTranslatef( m_Pos.x * g_Parm_3D_Visu.m_BiuTo3Dunits,
-m_Pos.y * g_Parm_3D_Visu.m_BiuTo3Dunits,
g_Parm_3D_Visu.m_LayerZcoord[m_Layer] );
if( m_Orient )
......@@ -937,8 +718,6 @@ void MODULE::Draw3D( EDA_3D_CANVAS* glcanvas )
glRotatef( 180.0, 0.0, 0.0, 1.0 );
}
DataScale3D = g_Parm_3D_Visu.m_BoardScale * UNITS3D_TO_UNITSPCB;
for( ; Struct3D != NULL; Struct3D = Struct3D->Next() )
{
if( !Struct3D->m_Shape3DName.IsEmpty() )
......@@ -952,8 +731,6 @@ void MODULE::Draw3D( EDA_3D_CANVAS* glcanvas )
}
EDA_ITEM* Struct = m_Drawings;
glNormal3f( 0.0, 0.0, 1.0 ); // Normal is Z axis
for( ; Struct != NULL; Struct = Struct->Next() )
{
switch( Struct->Type() )
......@@ -994,11 +771,11 @@ void EDGE_MODULE::Draw3D( EDA_3D_CANVAS* glcanvas )
dx = m_End.x;
dy = m_End.y;
w = m_Width * g_Parm_3D_Visu.m_BoardScale;
x = m_Start.x * g_Parm_3D_Visu.m_BoardScale;
y = m_Start.y * g_Parm_3D_Visu.m_BoardScale;
fx = dx * g_Parm_3D_Visu.m_BoardScale;
fy = dy * g_Parm_3D_Visu.m_BoardScale;
w = m_Width * g_Parm_3D_Visu.m_BiuTo3Dunits;
x = m_Start.x * g_Parm_3D_Visu.m_BiuTo3Dunits;
y = m_Start.y * g_Parm_3D_Visu.m_BiuTo3Dunits;
fx = dx * g_Parm_3D_Visu.m_BiuTo3Dunits;
fy = dy * g_Parm_3D_Visu.m_BiuTo3Dunits;
if( m_Layer == EDGE_N )
......@@ -1006,20 +783,28 @@ void EDGE_MODULE::Draw3D( EDA_3D_CANVAS* glcanvas )
for( int layer = 0; layer < g_Parm_3D_Visu.m_CopperLayersCount; layer++ )
{
glNormal3f( 0.0, 0.0, (layer == LAYER_N_BACK) ? -1.0 : 1.0 );
int izpos = KiROUND( g_Parm_3D_Visu.m_LayerZcoord[layer] / g_Parm_3D_Visu.m_BoardScale );
int izpos = g_Parm_3D_Visu.GetLayerZcoordBIU( layer );
int thickness = m_Layer >= FIRST_NO_COPPER_LAYER ?
g_Parm_3D_Visu.GetNonCopperLayerThicknessBIU() :
g_Parm_3D_Visu.GetCopperThicknessBIU();
switch( m_Shape )
{
case S_SEGMENT:
Draw3D_SolidSegment( m_Start, m_End, m_Width,
COPPER_THICKNESS, izpos,
g_Parm_3D_Visu.m_BoardScale );
thickness, izpos,
g_Parm_3D_Visu.m_BiuTo3Dunits );
break;
case S_CIRCLE:
{
S3D_VERTEX pos( x, -y, g_Parm_3D_Visu.m_LayerZcoord[layer] );
Draw3D_ThickCircle( pos, hypot( x - fx, y - fy ), w);
int radius = KiROUND( hypot( double(m_Start.x - m_End.x),
double(m_Start.y - m_End.y) )
);
Draw3D_ZaxisCylinder( m_Start, radius,
thickness, GetWidth(),
g_Parm_3D_Visu.GetLayerZcoordBIU(layer),
g_Parm_3D_Visu.m_BiuTo3Dunits );
}
break;
......@@ -1048,7 +833,7 @@ void EDGE_MODULE::Draw3D( EDA_3D_CANVAS* glcanvas )
pt += module->m_Pos;
}
glcanvas->Draw3D_Polygon( points, g_Parm_3D_Visu.m_LayerZcoord[layer] );
Draw3D_HorizontalPolygon( points, izpos, 0, g_Parm_3D_Visu.m_BiuTo3Dunits);
}
break;
......@@ -1061,21 +846,29 @@ void EDGE_MODULE::Draw3D( EDA_3D_CANVAS* glcanvas )
}
else
{
int thickness = m_Layer >= FIRST_NO_COPPER_LAYER ?
g_Parm_3D_Visu.GetNonCopperLayerThicknessBIU() :
g_Parm_3D_Visu.GetCopperThicknessBIU();
glNormal3f( 0.0, 0.0, (m_Layer == LAYER_N_BACK) ? -1.0 : 1.0 );
int izpos = KiROUND( g_Parm_3D_Visu.m_LayerZcoord[m_Layer] / g_Parm_3D_Visu.m_BoardScale );
int izpos = g_Parm_3D_Visu.GetLayerZcoordBIU(m_Layer);
switch( m_Shape )
{
case S_SEGMENT:
Draw3D_SolidSegment( m_Start, m_End, m_Width,
COPPER_THICKNESS, izpos,
g_Parm_3D_Visu.m_BoardScale );
thickness, izpos,
g_Parm_3D_Visu.m_BiuTo3Dunits );
break;
case S_CIRCLE:
{
S3D_VERTEX pos( x, -y, g_Parm_3D_Visu.m_LayerZcoord[m_Layer] );
Draw3D_ThickCircle( pos, hypot( x - fx, y - fy ), w );
int radius = KiROUND( hypot( double(m_Start.x - m_End.x),
double(m_Start.y - m_End.y) )
);
Draw3D_ZaxisCylinder( m_Start, radius,
thickness, GetWidth(),
g_Parm_3D_Visu.GetLayerZcoordBIU(m_Layer),
g_Parm_3D_Visu.m_BiuTo3Dunits );
}
break;
......@@ -1104,7 +897,7 @@ void EDGE_MODULE::Draw3D( EDA_3D_CANVAS* glcanvas )
pt += module->m_Pos;
}
glcanvas->Draw3D_Polygon( points, g_Parm_3D_Visu.m_LayerZcoord[m_Layer] );
Draw3D_HorizontalPolygon( points, izpos, 0, g_Parm_3D_Visu.m_BiuTo3Dunits );
}
break;
......@@ -1120,90 +913,82 @@ void EDGE_MODULE::Draw3D( EDA_3D_CANVAS* glcanvas )
// Draw 3D pads.
void D_PAD::Draw3D( EDA_3D_CANVAS* glcanvas )
{
int ii, ll, layer, nlmax;
int ux0, uy0,
dx, dx0, dy, dy0,
delta_cx, delta_cy,
xc, yc;
int angle;
double zpos;
double x, y, r, w;
int layer, nlmax;
bool Oncu, Oncmp, Both;
int color;
double scale = g_Parm_3D_Visu.m_BoardScale;
double holeX = (double) m_Drill.x * scale / 2;
double holeY = (double) m_Drill.y * scale / 2;
double hole = fmin( holeX, holeY );
double scale = g_Parm_3D_Visu.m_BiuTo3Dunits;
// Calculate the center of the pad.
// Calculate the center of the pad shape.
wxPoint shape_pos = ReturnShapePos();
ux0 = shape_pos.x;
uy0 = shape_pos.y;
xc = ux0;
yc = uy0;
dx = dx0 = m_Size.x >> 1;
dy = dy0 = m_Size.y >> 1;
int height = g_Parm_3D_Visu.GetLayerZcoordBIU(LAYER_N_FRONT) -
g_Parm_3D_Visu.GetLayerZcoordBIU(LAYER_N_BACK);
int thickness = g_Parm_3D_Visu.GetCopperThicknessBIU();
angle = m_Orient;
double drillx = m_Pos.x * scale;
double drilly = m_Pos.y * scale;
double height = g_Parm_3D_Visu.m_LayerZcoord[LAYER_N_FRONT] -
g_Parm_3D_Visu.m_LayerZcoord[LAYER_N_BACK];
// Store here the points to approximate hole by segments
std::vector <CPolyPt> holecornersBuffer;
const int slice = 12; // number of segments to approximate a circle
// Draw the pad hole
if( holeX && holeY )
bool hasHole = m_Drill.x && m_Drill.y;
if( hasHole )
{
SetGLColor( DARKGRAY );
S3D_VERTEX position( drillx, -drilly, g_Parm_3D_Visu.m_LayerZcoord[LAYER_N_BACK] );
int holeZpoz = g_Parm_3D_Visu.GetLayerZcoordBIU(LAYER_N_BACK) + thickness/2;
int holeHeight = height - thickness;
if( holeX == holeY ) // usual round hole
Draw3D_ZaxisCylinder( position, hole, height );
else // Oval hole
if( m_Drill.x == m_Drill.y ) // usual round hole
{
Draw3D_ZaxisCylinder( m_Pos, (m_Drill.x + thickness) / 2, holeHeight,
thickness, holeZpoz, scale );
TransformCircleToPolygon( holecornersBuffer, m_Pos, m_Drill.x/2, slice );
}
else // Oblong hole
{
double ldx, ldy;
wxPoint ends_offset;
int width;
if( holeX > holeY ) // Horizontal oval
if( m_Drill.x > m_Drill.y ) // Horizontal oval
{
ldx = holeX - holeY;
ldy = 0;
w = m_Size.y * scale;
ends_offset.x = ( m_Drill.x - m_Drill.y ) / 2;
width = m_Drill.y;
}
else // Vertical oval
{
ldx = 0;
ldy = holeY - holeX;
w = m_Size.x * scale;
ends_offset.y = ( m_Drill.y - m_Drill.x ) / 2;
width = m_Drill.x;
}
RotatePoint( &ldx, &ldy, angle );
RotatePoint( &ends_offset, m_Orient );
{
double ox = ux0 * scale + ldx;
double oy = uy0 * scale + ldy;
double fx = ux0 * scale - ldx;
double fy = uy0 * scale - ldy;
wxPoint start = m_Pos + ends_offset;
wxPoint end = m_Pos - ends_offset;
int hole_radius = ( width + thickness ) / 2;
S3D_VERTEX position( ox, -oy, g_Parm_3D_Visu.m_LayerZcoord[LAYER_N_BACK] );
Draw3D_ZaxisOblongCylinder( position, fx, -fy, hole, height );
}
// Prepare the shape creation
TransformRoundedEndsSegmentToPolygon( holecornersBuffer, start, end, slice, width );
// Draw the hole
Draw3D_ZaxisOblongCylinder( start, end, hole_radius, holeHeight,
thickness, holeZpoz, scale );
}
}
glNormal3f( 0.0, 0.0, 1.0 ); // Normal is Z axis
nlmax = g_Parm_3D_Visu.m_CopperLayersCount - 1;
Oncu = (m_layerMask & LAYER_BACK) ? true : false;
Oncmp = (m_layerMask & LAYER_FRONT) ? true : false;
Both = Oncu && Oncmp;
switch( m_PadShape & 0x7F )
// Store here the points to approximate pad shape by segments
std::vector<CPolyPt> polyPadShape;
switch( GetShape() )
{
case PAD_CIRCLE:
x = xc * scale;
y = yc * scale;
r = (double) dx * scale;
for( layer = FIRST_COPPER_LAYER; layer <= LAST_COPPER_LAYER; layer++ )
{
if( layer && (layer == nlmax) )
......@@ -1224,113 +1009,65 @@ void D_PAD::Draw3D( EDA_3D_CANVAS* glcanvas )
continue;
SetGLColor( color );
glNormal3f( 0.0, 0.0, (layer == LAYER_N_BACK) ? -1.0 : 1.0 );
zpos = g_Parm_3D_Visu.m_LayerZcoord[layer];
int zpos = g_Parm_3D_Visu.GetLayerZcoordBIU( layer );
int ring_radius = (m_Size.x + m_Drill.x) / 4;
if( thickness == 0 )
glNormal3f( 0.0, 0.0, layer == LAYER_N_BACK ? -1.0 : 1.0 );
if( layer == LAYER_N_BACK )
zpos = zpos - 5 * g_Parm_3D_Visu.m_BoardScale;
else
zpos = zpos + 5 * g_Parm_3D_Visu.m_BoardScale;
S3D_VERTEX position( x, -y, zpos );
Draw3D_FilledCircleWithHole( position, r, hole );
Draw3D_ZaxisCylinder(shape_pos, ring_radius,
thickness, ( m_Size.x - m_Drill.x) / 2,
zpos - (thickness/2), scale );
}
break;
case PAD_OVAL:
if( dx > dy ) // Horizontal ellipse
{
delta_cx = dx - dy;
delta_cy = 0;
w = m_Size.y * scale;
wxPoint ends_offset;
int width;
if( m_Size.x > m_Size.y ) // Horizontal ellipse
{
ends_offset.x = ( m_Size.x - m_Size.y ) / 2;
width = m_Size.y;
}
else // Vertical ellipse
{
delta_cx = 0;
delta_cy = dy - dx;
w = m_Size.x * scale;
ends_offset.y = ( m_Size.y - m_Size.x ) / 2;
width = m_Size.x;
}
RotatePoint( &delta_cx, &delta_cy, angle );
{
double ox, oy, fx, fy;
ox = (double) ( ux0 + delta_cx ) * scale;
oy = (double) ( uy0 + delta_cy ) * scale;
fx = (double) ( ux0 - delta_cx ) * scale;
fy = (double) ( uy0 - delta_cy ) * scale;
for( layer = FIRST_COPPER_LAYER; layer <= LAST_COPPER_LAYER; layer++ )
{
if( layer && (layer == nlmax) )
layer = LAYER_N_FRONT;
if( (layer == LAYER_N_FRONT) && !Oncmp )
continue;
if( (layer == LAYER_N_BACK) && !Oncu )
continue;
if( (layer > FIRST_COPPER_LAYER) && (layer < LAST_COPPER_LAYER) && !Both )
continue;
color = g_ColorsSettings.GetLayerColor( layer );
glNormal3f( 0.0, 0.0, (layer == LAYER_N_BACK) ? -1.0 : 1.0 );
if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) == false )
continue;
SetGLColor( color );
zpos = g_Parm_3D_Visu.m_LayerZcoord[layer];
if( layer == LAYER_N_BACK )
zpos = zpos - 5 * g_Parm_3D_Visu.m_BoardScale;
else
zpos = zpos + 5 * g_Parm_3D_Visu.m_BoardScale;
Draw3D_SegmentWithHole( ox, -oy, fx, -fy, w, drillx, -drilly, hole, zpos );
RotatePoint( &ends_offset, m_Orient );
wxPoint start = shape_pos + ends_offset;
wxPoint end = shape_pos - ends_offset;
TransformRoundedEndsSegmentToPolygon( polyPadShape, start, end, slice, width );
if( hasHole )
polyPadShape.insert( polyPadShape.end(), holecornersBuffer.begin(), holecornersBuffer.end() );
}
}
break;
case PAD_RECT:
case PAD_TRAPEZOID:
{
wxPoint coord[5];
wxRealPoint fcoord[8], f_hole_coord[8];
BuildPadPolygon( coord, wxSize(0,0), angle );
for( ii = 0; ii < 4; ii++ )
BuildPadPolygon( coord, wxSize(0,0), m_Orient );
for( int ii = 0; ii < 4; ii ++ )
{
coord[ii].x += ux0;
coord[ii].y += uy0;
ll = ii * 2;
fcoord[ll].x = coord[ii].x *scale;
fcoord[ll].y = coord[ii].y *scale;
CPolyPt pt( coord[ii].x + shape_pos.x, coord[ii].y+ shape_pos.y );
polyPadShape.push_back( pt );
}
polyPadShape.back().end_contour = true;
for( ii = 0; ii < 7; ii += 2 )
{
ll = ii + 2;
if( ll > 7 )
ll -= 8;
fcoord[ii + 1].x = (fcoord[ii].x + fcoord[ll].x) / 2;
fcoord[ii + 1].y = (fcoord[ii].y + fcoord[ll].y) / 2;
if( hasHole )
polyPadShape.insert( polyPadShape.end(), holecornersBuffer.begin(), holecornersBuffer.end() );
}
break;
for( ii = 0; ii < 8; ii++ )
{
f_hole_coord[ii].x = -hole * 0.707;
f_hole_coord[ii].y = hole * 0.707;
RotatePoint( &f_hole_coord[ii].x, &f_hole_coord[ii].y, angle - (ii * 450) );
f_hole_coord[ii].x += drillx;
f_hole_coord[ii].y += drilly;
default:
break;
}
if( polyPadShape.size() )
{
for( layer = FIRST_COPPER_LAYER; layer <= LAST_COPPER_LAYER; layer++ )
{
if( layer && (layer == nlmax) )
......@@ -1345,420 +1082,33 @@ void D_PAD::Draw3D( EDA_3D_CANVAS* glcanvas )
if( (layer > FIRST_COPPER_LAYER) && (layer < LAST_COPPER_LAYER) && !Both )
continue;
color = g_ColorsSettings.GetLayerColor( layer );
glNormal3f( 0.0, 0.0, (layer == LAYER_N_BACK) ? -1.0 : 1.0 );
if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) == false )
continue;
color = g_ColorsSettings.GetLayerColor( layer );
SetGLColor( color );
zpos = g_Parm_3D_Visu.m_LayerZcoord[layer];
if( layer == LAYER_N_BACK )
zpos = zpos - 5 * g_Parm_3D_Visu.m_BoardScale;
else
zpos = zpos + 5 * g_Parm_3D_Visu.m_BoardScale;
glBegin( GL_QUAD_STRIP );
for( ii = 0; ii < 8; ii++ )
{
glVertex3f( f_hole_coord[ii].x, -f_hole_coord[ii].y, zpos );
glVertex3f( fcoord[ii].x, -fcoord[ii].y, zpos );
}
glVertex3f( f_hole_coord[0].x, -f_hole_coord[0].y, zpos );
glVertex3f( fcoord[0].x, -fcoord[0].y, zpos );
glEnd();
}
}
break;
default:
break;
}
}
void SetGLColor( int color )
{
double red, green, blue;
StructColors colordata = ColorRefs[color & MASKCOLOR];
red = colordata.m_Red / 255.0;
blue = colordata.m_Blue / 255.0;
green = colordata.m_Green / 255.0;
glColor3f( red, green, blue );
}
void Draw3D_FilledCircleWithHole( const S3D_VERTEX& aPos, double radius, double hole_radius )
{
const int slice = 16;
const int rot_angle = ANGLE_INC(slice);
glBegin( GL_QUAD_STRIP );
for( int ii = 0; ii <= slice; ii++ )
{
double x = hole_radius;
double y = 0.0;
RotatePoint( &x, &y, ii * rot_angle );
glVertex3f( x + aPos.x, y + aPos.y, aPos.z );
x = radius;
y = 0.0;
RotatePoint( &x, &y, ii * rot_angle );
glVertex3f( x + aPos.x, y + aPos.y, aPos.z );
}
glEnd();
}
static void Draw3D_ZaxisCylinder( const S3D_VERTEX& aPos, double aRadius, double aHeight )
{
const int slice = 12;
std::vector< S3D_VERTEX > coords;
coords.resize( 4 );
double tmp = DataScale3D;
DataScale3D = 1.0; // Coordinate is already in range for Set_Object_Data();
coords[0].x = coords[1].x = aPos.x + aRadius;
coords[0].y = coords[1].y = aPos.y;
coords[0].z = coords[3].z = aPos.z;
coords[1].z = coords[2].z = aPos.z + aHeight;
for( int ii = 0; ii <= slice; ii++ )
{
double x = aRadius;
double y = 0.0;
RotatePoint( &x, &y, ii * ANGLE_INC(slice) );
coords[2].x = coords[3].x = aPos.x + x;
coords[2].y = coords[3].y = aPos.y + y;
Set_Object_Data( coords );
coords[0].x = coords[2].x;
coords[0].y = coords[2].y;
coords[1].x = coords[3].x;
coords[1].y = coords[3].y;
}
glNormal3f( 0.0, 0.0, 1.0 ); // Normal is Z axis
DataScale3D = tmp;
}
if( thickness == 0 )
glNormal3f( 0.0, 0.0, layer == LAYER_N_BACK ? -1.0 : 1.0 );
/* 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 )
{
std::vector <CPolyPt> cornerBuffer;
const int slice = 16;
TransformRoundedEndsSegmentToPolygon(cornerBuffer, aStart, aEnd, slice, aWidth );
//Build the 3D data : upper side then lower side
double zupperpos = ( aZpos + (aThickness/2) ) * aBiuTo3DUnits;
double zlowerpos = ( aZpos - (aThickness/2) ) * aBiuTo3DUnits;
if( aThickness )
glNormal3f( 0.0, 0.0, 1.0 ); // Normale is Z axis
double zpos = zupperpos; // start with upper side
for( int face = 0; face < 2; face ++ )
{
glBegin( GL_POLYGON );
for( unsigned ii = 0; ii < cornerBuffer.size(); ii++ )
glVertex3f( cornerBuffer[ii].x * aBiuTo3DUnits,
- cornerBuffer[ii].y * aBiuTo3DUnits, zpos );
// Close the polygon shape
glVertex3f( cornerBuffer[0].x * aBiuTo3DUnits,
- cornerBuffer[0].y * aBiuTo3DUnits, zpos );
glEnd();
if( aThickness == 0 )
return;
// Prepare the creation of lower side
glNormal3f( 0.0, 0.0, -1.0 ); // Normale now is -Z axis
zpos = zlowerpos;
}
//Build the 3D data : vertical sides
std::vector< S3D_VERTEX > vertices;
vertices.resize(4);
for( int ii = 0; ii < slice; ii++ )
// If not hole: draw a single polygon
int zpos = g_Parm_3D_Visu.GetLayerZcoordBIU( layer );
if( hasHole )
{
int jj = ii+1;
if( jj >=slice )
jj = 0;
vertices[0].x = cornerBuffer[ii].x;
vertices[0].y = -cornerBuffer[ii].y;
vertices[0].z = aZpos + (aThickness/2);
vertices[1].x = cornerBuffer[ii].x;
vertices[1].y = -cornerBuffer[ii].y;
vertices[1].z = aZpos - (aThickness/2);
vertices[2].x = cornerBuffer[jj].x;
vertices[2].y = -cornerBuffer[jj].y;
vertices[2].z = aZpos - (aThickness/2);
vertices[3].x = cornerBuffer[jj].x;
vertices[3].y = -cornerBuffer[jj].y;
vertices[3].z = aZpos + (aThickness/2);
Set_Object_Data( vertices );
Draw3D_SolidHorizontalPolygonWithHoles( polyPadShape, zpos,
thickness, g_Parm_3D_Visu.m_BiuTo3Dunits );
}
glNormal3f( 0.0, 0.0, 1.0 ); // Normal is Z axis
}
/* Draw a polygon similar to a segment ends with round hole
*/
static void Draw3D_SegmentWithHole( double startx, double starty,
double endx, double endy,
double width, double holex,
double holey, double holeradius,
double zpos )
{
double x, y, xin, yin;
double firstx = 0, firsty = 0, firstxin = 0, firstyin = 0;
int ii, angle, theta;
// Calculate the coordinates of the segment assumed horizontal
// Then turn the strips of the desired angle
// All calculations are done with startx, starty as local origin
endx -= startx;
endy -= starty;
holex -= startx;
holey -= starty;
angle = (int) ( ( atan2( endy, endx ) * 1800 / M_PI ) + 0.5 );
RotatePoint( &endx, &endy, angle );
RotatePoint( &holex, &holey, angle );
width /= 2;
glBegin( GL_QUAD_STRIP );
// Path of the flare to right (1st half polygon at the end of the segment)
// around the half-hole drilling
for( ii = 0; ii <= 8; ii++ )
{
x = 0.0;
y = -width;
xin = 0.0;
yin = -holeradius;
theta = -ii * 225;
RotatePoint( &x, &y, theta );
RotatePoint( &xin, &yin, theta );
x += endx;
RotatePoint( &x, &y, -angle );
xin += holex;
RotatePoint( &xin, &yin, -angle );
glVertex3f( startx + xin, starty + yin, zpos );
glVertex3f( startx + x, starty + y, zpos );
if( ii == 0 )
{
firstx = startx + x;
firsty = starty + y;
firstxin = startx + xin;
firstyin = starty + yin;
}
}
// Layout of the rounded left (2nd half polygon is the origin of the
// segment)
for( ii = 0; ii <= 8; ii++ )
{
theta = -ii * 225;
x = 0.0;
y = width;
RotatePoint( &x, &y, -angle + theta );
xin = 0.0;
yin = holeradius;
RotatePoint( &xin, &yin, theta );
xin += holex;
RotatePoint( &xin, &yin, -angle );
glVertex3f( startx + xin, starty + yin, zpos );
glVertex3f( startx + x, starty + y, zpos );
}
glVertex3f( firstxin, firstyin, zpos );
glVertex3f( firstx, firsty, zpos );
glEnd();
}
static void Draw3D_ArcSegment( const S3D_VERTEX& aCenterPos,
double aStartPointX, double aStartPointY,
double aArcAngle, double aWidth )
{
const int slice = 16; // Number of segments to approximate a circle by segments
double arcStart_Angle;
arcStart_Angle = (atan2( aStartPointX - aCenterPos.x, aStartPointY - aCenterPos.y ) * 1800 / M_PI );
double radius = hypot( aStartPointX - aCenterPos.x, aStartPointY - aCenterPos.y )
+ ( aWidth / 2);
double hole = radius - aWidth;
// Calculate the number of segments to approximate this arc
int imax = (int) ( (double) aArcAngle / ANGLE_INC(slice) );
if( imax < 0 )
imax = -imax;
if( imax == 0 )
imax = 1;
// Adjust delta_angle to have exactly imax segments in arc_angle
// i.e. arc_angle = imax delta_agnle.
double delta_angle = (double) aArcAngle / imax;
glBegin( GL_QUAD_STRIP );
for( int ii = 0; ii <= imax; ii++ )
else
{
double angle = (double) ii * delta_angle;
angle += arcStart_Angle + 900;
double dx = hole;
double dy = 0.0;
RotatePoint( &dx, &dy, (int) angle );
glVertex3f( dx + aStartPointX, dy + aStartPointY, aCenterPos.z );
dx = radius;
dy = 0.0;
RotatePoint( &dx, &dy, (int) angle );
glVertex3f( dx + aStartPointX, dy + aStartPointY, aCenterPos.z );
Draw3D_SolidHorizontalPolyPolygons( polyPadShape, zpos,
thickness, g_Parm_3D_Visu.m_BiuTo3Dunits );
}
glEnd();
}
static void Draw3D_ThickCircle( const S3D_VERTEX& aCenterPos, double aRadius, double aWidth )
{
double outer_radius = aRadius + ( aWidth / 2);
double inner_radius = outer_radius - aWidth;
Draw3D_FilledCircleWithHole( aCenterPos, outer_radius, inner_radius );
}
/*
* Function Draw3D_ZaxisOblongCylinder:
* draw a segment with an oblong hole.
* Used to draw oblong holes
*/
void Draw3D_ZaxisOblongCylinder( const S3D_VERTEX& aStartPos,
double aEndx, double aEndy,
double aRadius, double aHeight )
{
const int slice = 16;
std::vector<S3D_VERTEX> coords;
coords.resize( 4 );
double tmp = DataScale3D;
DataScale3D = 1.0; // Coordinate is already in range for Set_Object_Data();
double dx = aEndx - aStartPos.x;
double dy = aEndy - aStartPos.y;
double angle = atan2( dy, dx ) * 1800 / M_PI;
dx = 0;
dy = aRadius;
// draws the first rectangle between half cylinders
RotatePoint( &dx, &dy, angle );
coords[0].x = coords[1].x = aStartPos.x + dx;
coords[0].y = coords[1].y = aStartPos.y - dy;
coords[2].x = coords[3].x = aEndx + dx;
coords[2].y = coords[3].y = aEndy - dy;
coords[0].z = coords[3].z = aStartPos.z;
coords[1].z = coords[2].z = aStartPos.z + aHeight;
Set_Object_Data( coords );
// Draw the first half cylinder
for( int ii = 1; ii <= slice/2; ii++ )
{
double ddx = dx;
double ddy = -dy;
RotatePoint( &ddx, &ddy, -ii * ANGLE_INC(slice) );
coords[0].x = coords[2].x;
coords[0].y = coords[2].y;
coords[1].x = coords[3].x;
coords[1].y = coords[3].y;
coords[2].x = coords[3].x = aEndx + ddx;
coords[2].y = coords[3].y = aEndy + ddy;
Set_Object_Data( coords );
}
// draws the second rectangle between half cylinders
coords[0].x = coords[1].x = aEndx - dx;
coords[0].y = coords[1].y = aEndy + dy;
coords[2].x = coords[3].x = aStartPos.x - dx;
coords[2].y = coords[3].y = aStartPos.y + dy;
coords[0].z = coords[3].z = aStartPos.z;
coords[1].z = coords[2].z = aStartPos.z + aHeight;
Set_Object_Data( coords );
// Draw the second half cylinder
for( int ii = 1; ii <= slice/2; ii++ )
{
double ddx = -dx;
double ddy = dy;
RotatePoint( &ddx, &ddy, -ii * ANGLE_INC(slice) );
coords[0].x = coords[2].x;
coords[0].y = coords[2].y;
coords[1].x = coords[3].x;
coords[1].y = coords[3].y;
coords[2].x = coords[3].x = aStartPos.x + ddx;
coords[2].y = coords[3].y = aStartPos.y + ddy;
Set_Object_Data( coords );
}
glNormal3f( 0.0, 0.0, 1.0 ); // Normal is Z axis
DataScale3D = tmp;
}
void EDA_3D_CANVAS::Draw3D_Polygon( std::vector<wxPoint>& aCornersList, double aZpos )
{
g_Parm_3D_Visu.m_ActZpos = aZpos;
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*)() )tesswxPoint2Vertex );
GLdouble v_data[3];
v_data[2] = aZpos;
//gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);
// Draw solid polygon
gluTessBeginPolygon( tess, NULL );
gluTessBeginContour( tess );
for( unsigned ii = 0; ii < aCornersList.size(); ii++ )
{
v_data[0] = aCornersList[ii].x * g_Parm_3D_Visu.m_BoardScale;
v_data[1] = -aCornersList[ii].y * g_Parm_3D_Visu.m_BoardScale;
// gluTessVertex store pointers on data, not data, so do not store
// different corners values in a temporary variable
// but send pointer on each corner value in aCornersList
gluTessVertex( tess, v_data, &aCornersList[ii] );
}
gluTessEndContour( tess );
gluTessEndPolygon( tess );
gluDeleteTess( tess );
}
bool Is3DLayerEnabled( int aLayer )
{
int flg = -1;
......@@ -1806,52 +1156,3 @@ GLfloat Get3DLayer_Z_Orientation( int aLayer )
return nZ;
}
///////////////////////////////////////////////////////////////////////////////
// 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 CPolyPt* ptr = (const CPolyPt*) data;
glVertex3f( ptr->x * g_Parm_3D_Visu.m_BoardScale,
-ptr->y * g_Parm_3D_Visu.m_BoardScale,
g_Parm_3D_Visu.m_ActZpos );
}
void CALLBACK tesswxPoint2Vertex( const GLvoid* data )
{
const wxPoint* ptr = (const wxPoint*) data;
glVertex3f( ptr->x * g_Parm_3D_Visu.m_BoardScale,
-ptr->y * g_Parm_3D_Visu.m_BoardScale,
g_Parm_3D_Visu.m_ActZpos );
}
void CALLBACK tessErrorCB( GLenum errorCode )
{
#if defined(DEBUG)
const GLubyte* errorStr;
errorStr = gluErrorString( errorCode );
// DEBUG //
D( printf( "Tess ERROR: %s\n", errorStr ); )
#endif
}
/*
* 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>
// Imported function:
extern void Set_Object_Data( std::vector<S3D_VERTEX>& aVertices, double aBiuTo3DUnits );
extern void CheckGLError();
#ifndef CALLBACK
#define CALLBACK
#endif
// 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 );
static void CALLBACK tesswxPoint2Vertex( const GLvoid* data );
/** draw a ring using 3D primitives, in a plane parallel to the XY plane
* @param aCenterPos = position of the center (Board internal units)
* @param aOuterRadius = radius of the external circle (Board internal units)
* @param aInnerRadius = radius of the circle (Board internal units)
* @param aZpos = z position in board internal units
* @param aBiuTo3DUnits = board internal units to 3D units scaling value
*/
static void Draw3D_FlatRing( wxPoint aCenterPos, int aOuterRadius,
int aInnerRadius, int aZpos, double aBiuTo3DUnits );
void SetGLColor( int color )
{
double red, green, blue;
StructColors colordata = ColorRefs[color & MASKCOLOR];
red = colordata.m_Red / 255.0;
blue = colordata.m_Blue / 255.0;
green = colordata.m_Green / 255.0;
glColor3f( red, green, blue );
}
/* 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 1 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 std::vector<CPolyPt>& aPolysList,
int aZpos, int aThickness, double aBiuTo3DUnits )
{
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) ) * aBiuTo3DUnits;
g_Parm_3D_Visu.m_CurrentZpos = zpos;
v_data[2] = aZpos + (aThickness / 2);
// Set normal to toward positive Z axis, for a solid object only (to draw the top side)
if( aThickness )
glNormal3f( 0.0, 0.0, 1.0 );
// gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);
// Draw solid areas contained in this list
std::vector<CPolyPt> polylist = aPolysList; // temporary copy for gluTessVertex
for( int side = 0; side < 2; side++ )
{
int startContour = 1;
for( unsigned ii = 0; ii < polylist.size(); ii++ )
{
if( startContour == 1 )
{
gluTessBeginPolygon( tess, NULL );
gluTessBeginContour( tess );
startContour = 0;
}
v_data[0] = polylist[ii].x * aBiuTo3DUnits;
v_data[1] = -polylist[ii].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, &polylist[ii] );
if( polylist[ii].end_contour == 1 )
{
gluTessEndContour( tess );
gluTessEndPolygon( tess );
startContour = 1;
}
}
if( aThickness == 0 )
break;
// Prepare the bottom side of solid areas
zpos = ( aZpos - (aThickness / 2) ) * aBiuTo3DUnits;
g_Parm_3D_Visu.m_CurrentZpos = zpos;
v_data[2] = zpos;
// Now;, set normal to toward negative Z axis, for the solid object bottom side
glNormal3f( 0.0, 0.0, -1.0 );
}
gluDeleteTess( tess );
if( aThickness == 0 )
return;
// Build the 3D data : vertical sides
std::vector<S3D_VERTEX> vertices;
vertices.resize( 4 );
vertices[0].z = aZpos + (aThickness / 2);
vertices[1].z = aZpos - (aThickness / 2);
vertices[2].z = vertices[1].z;
vertices[3].z = vertices[0].z;
int startContour = 0;
for( unsigned ii = 0; ii < polylist.size(); ii++ )
{
int jj = ii + 1;
if( polylist[ii].end_contour == 1 )
{
jj = startContour;
startContour = ii + 1;
}
vertices[0].x = polylist[ii].x;
vertices[0].y = -polylist[ii].y;
vertices[1].x = vertices[0].x;
vertices[1].y = vertices[0].y; // Z only changes.
vertices[2].x = polylist[jj].x;
vertices[2].y = -polylist[jj].y;
vertices[3].x = vertices[2].x;
vertices[3].y = vertices[2].y; // Z only changes.
Set_Object_Data( vertices, aBiuTo3DUnits );
}
glNormal3f( 0.0, 0.0, 1.0 );
}
/* draw the solid polygon found in aPolysList
* The first polygonj is the main polygon, others are holes
* See Draw3D_SolidHorizontalPolyPolygons for more info
*/
void Draw3D_SolidHorizontalPolygonWithHoles( const std::vector<CPolyPt>& aPolysList,
int aZpos, int aThickness, double aBiuTo3DUnits )
{
std::vector<CPolyPt> polygon;
ConvertPolysListWithHolesToOnePolygon( aPolysList, polygon );
Draw3D_SolidHorizontalPolyPolygons( polygon, aZpos, aThickness, 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 = 12;
std::vector <CPolyPt> outer_cornerBuffer;
TransformCircleToPolygon( outer_cornerBuffer, aCenterPos,
aRadius + (aThickness / 2), slice );
std::vector<S3D_VERTEX> coords;
coords.resize( 4 );
if( aHeight )
{
// Draw the outer vertical side
// Init Z position of the 4 points of a GL_QUAD
coords[0].z = aZpos;
coords[1].z = aZpos + aHeight;
coords[2].z = coords[1].z;
coords[3].z = coords[0].z;
for( int ii = 0; ii < slice; ii++ )
{
int jj = ii + 1;
if( jj >= slice )
jj = 0;
// Build the 4 vertices of each GL_QUAD
coords[0].x = outer_cornerBuffer[jj].x;
coords[0].y = -outer_cornerBuffer[jj].y;
coords[1].x = coords[0].x;
coords[1].y = coords[0].y; // only z change
coords[2].x = outer_cornerBuffer[ii].x;
coords[2].y = -outer_cornerBuffer[ii].y;
coords[3].x = coords[2].x;
coords[3].y = coords[2].y; // only z change
// Creates the GL_QUAD
Set_Object_Data( coords, aBiuTo3DUnits );
}
glNormal3f( 0.0, 0.0, 1.0 ); // Normal is Z axis
}
if( aThickness == 0 )
return;
// draw top (front) and bottom (back) horizontal sides (rings)
S3D_VERTEX centerPos;
centerPos.x = aCenterPos.x * aBiuTo3DUnits;
centerPos.y = -aCenterPos.y * aBiuTo3DUnits;
Draw3D_FlatRing( aCenterPos, aRadius + aThickness / 2, aRadius - aThickness / 2,
aZpos + aHeight, aBiuTo3DUnits );
glNormal3f( 0.0, 0.0, -1.0 );
Draw3D_FlatRing( aCenterPos, aRadius + aThickness / 2, aRadius - aThickness / 2,
aZpos, aBiuTo3DUnits );
if( aHeight )
{
// Draws the vertical inner side (hole)
std::vector <CPolyPt> inner_cornerBuffer;
TransformCircleToPolygon( inner_cornerBuffer, aCenterPos,
aRadius - (aThickness / 2), slice );
for( int ii = 0; ii < slice; ii++ )
{
int jj = ii + 1;
if( jj >= slice )
jj = 0;
// Build the 4 vertices of each GL_QUAD
coords[0].x = inner_cornerBuffer[ii].x;
coords[0].y = -inner_cornerBuffer[ii].y;
coords[1].x = coords[0].x;
coords[1].y = coords[0].y; // only z change
coords[2].x = inner_cornerBuffer[jj].x;
coords[2].y = -inner_cornerBuffer[jj].y;
coords[3].x = coords[2].x;
coords[3].y = coords[2].y; // only z change
Set_Object_Data( coords, aBiuTo3DUnits );
}
}
glNormal3f( 0.0, 0.0, 1.0 ); // Normal is Z axis
}
/*
* Function Draw3D_ZaxisOblongCylinder:
* draw a segment with an oblong hole.
* Used to draw oblong holes
*/
void Draw3D_ZaxisOblongCylinder( wxPoint aAxis1Pos, wxPoint aAxis2Pos,
int aRadius, int aHeight, int aThickness,
int aZpos, double aBiuTo3DUnits )
{
const int slice = 12;
// Build the points to approximate oblong cylinder by segments
std::vector <CPolyPt> cornerBuffer;
TransformRoundedEndsSegmentToPolygon( cornerBuffer, aAxis1Pos,
aAxis2Pos, slice, aRadius * 2 );
// Draw the cylinder
std::vector<S3D_VERTEX> coords;
coords.resize( 4 );
// Init Z position of the 4 points of a GL_QUAD
coords[0].z = aZpos;
coords[1].z = aZpos + aHeight;
coords[2].z = coords[1].z;
coords[3].z = coords[0].z;
for( int ii = 0; ii < slice; ii++ )
{
int jj = ii + 1;
if( jj >= slice )
jj = 0;
// Build the 4 vertices of each GL_QUAD
coords[0].x = cornerBuffer[ii].x;
coords[0].y = -cornerBuffer[ii].y;
coords[1].x = coords[0].x;
coords[1].y = coords[0].y; // only z change
coords[2].x = cornerBuffer[jj].x;
coords[2].y = -cornerBuffer[jj].y;
coords[3].x = coords[2].x;
coords[3].y = coords[2].y; // only z change
Set_Object_Data( coords, aBiuTo3DUnits );
}
glNormal3f( 0.0, 0.0, 1.0 ); // Normal is Z axis
}
/* 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 )
{
std::vector <CPolyPt> cornerBuffer;
const int slice = 16;
TransformRoundedEndsSegmentToPolygon( cornerBuffer, aStart, aEnd, slice, aWidth );
Draw3D_SolidHorizontalPolyPolygons( cornerBuffer, aZpos, aThickness, aBiuTo3DUnits );
}
void Draw3D_ArcSegment( const S3D_VERTEX& aCenterPos,
double aStartPointX, double aStartPointY,
double aArcAngle, double aWidth )
{
const int slice = 16; // Number of segments to approximate a circle by segments
double arcStart_Angle;
arcStart_Angle =
(atan2( aStartPointX - aCenterPos.x, aStartPointY - aCenterPos.y ) * 1800 / M_PI );
double radius = hypot( aStartPointX - aCenterPos.x, aStartPointY - aCenterPos.y )
+ ( aWidth / 2);
double hole = radius - aWidth;
// Calculate the number of segments to approximate this arc
int imax = (int) ( (double) aArcAngle / ANGLE_INC( slice ) );
if( imax < 0 )
imax = -imax;
if( imax == 0 )
imax = 1;
// Adjust delta_angle to have exactly imax segments in arc_angle
// i.e. arc_angle = imax delta_agnle.
double delta_angle = (double) aArcAngle / imax;
glBegin( GL_QUAD_STRIP );
for( int ii = 0; ii <= imax; ii++ )
{
double angle = (double) ii * delta_angle;
angle += arcStart_Angle + 900;
double dx = hole;
double dy = 0.0;
RotatePoint( &dx, &dy, (int) angle );
glVertex3f( dx + aStartPointX, dy + aStartPointY, aCenterPos.z );
dx = radius;
dy = 0.0;
RotatePoint( &dx, &dy, (int) angle );
glVertex3f( dx + aStartPointX, dy + aStartPointY, aCenterPos.z );
}
glEnd();
}
/** draw a ring using 3D primitives, in a plane parallel to the XY plane
* @param aCenterPos = position of the center (Board internal units)
* @param aOuterRadius = radius of the external circle (Board internal units)
* @param aInnerRadius = radius of the circle (Board internal units)
* @param aZpos = z position in board internal units
* @param aBiuTo3DUnits = board internal units to 3D units scaling value
*/
void Draw3D_FlatRing( wxPoint aCenterPos, int aOuterRadius,
int aInnerRadius, int aZpos, double aBiuTo3DUnits )
{
const int slice = 16;
const int rot_angle = ANGLE_INC( slice );
double cposx = aCenterPos.x * aBiuTo3DUnits;
double cposy = - aCenterPos.y * aBiuTo3DUnits;
glBegin( GL_QUAD_STRIP );
double zpos = aZpos * aBiuTo3DUnits;
for( int ii = 0; ii <= slice; ii++ )
{
double x = aInnerRadius * aBiuTo3DUnits;
double y = 0.0;
RotatePoint( &x, &y, ii * rot_angle );
glVertex3f( x + cposx, y + cposy, zpos );
x = aOuterRadius * aBiuTo3DUnits;
y = 0.0;
RotatePoint( &x, &y, ii * rot_angle );
glVertex3f( x + cposx, y + cposy, zpos );
}
glEnd();
}
/* draw one solid polygon
* aCornersList = a std::vector<wxPoint> list of corners, in board internal units
* aZpos = z position in board internal units
* aThickness = thickness in board internal units
* aIu_to_3Dunits = board internal units to 3D units scaling value
*/
void Draw3D_HorizontalPolygon( std::vector<wxPoint>& aCornersList, int aZpos,
int aThickness, double aBiuTo3DUnits )
{
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*) () )tesswxPoint2Vertex );
GLdouble v_data[3];
v_data[2] = ( aZpos + (aThickness / 2) ) * aBiuTo3DUnits;
g_Parm_3D_Visu.m_CurrentZpos = v_data[2];
// gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);
// Draw solid polygon
if( aThickness )
glNormal3f( 0.0, 0.0, 1.0 );
for( int side = 0; side < 2; side++ )
{
gluTessBeginPolygon( tess, NULL );
gluTessBeginContour( tess );
for( unsigned ii = 0; ii < aCornersList.size(); ii++ )
{
v_data[0] = aCornersList[ii].x * g_Parm_3D_Visu.m_BiuTo3Dunits;
v_data[1] = -aCornersList[ii].y * g_Parm_3D_Visu.m_BiuTo3Dunits;
// gluTessVertex store pointers on data, not data, so do not store
// different corners values in a temporary variable
// but send pointer on each corner value in aCornersList
gluTessVertex( tess, v_data, &aCornersList[ii] );
}
gluTessEndContour( tess );
gluTessEndPolygon( tess );
if( aThickness == 0 )
break;
glNormal3f( 0.0, 0.0, -1.0 );
v_data[2] = ( aZpos - (aThickness / 2) ) * aBiuTo3DUnits;
g_Parm_3D_Visu.m_CurrentZpos = v_data[2];
}
gluDeleteTess( tess );
if( aThickness == 0 )
return;
// Build the 3D data : vertical sides
std::vector<S3D_VERTEX> vertices;
vertices.resize( 4 );
vertices[0].z = aZpos + (aThickness / 2);
vertices[1].z = aZpos - (aThickness / 2);
vertices[2].z = vertices[1].z;
vertices[3].z = vertices[0].z;
int slice = (int) aCornersList.size();
for( int ii = 0; ii < slice; ii++ )
{
int jj = ii + 1;
if( jj >=slice )
jj = 0;
vertices[0].x = aCornersList[ii].x;
vertices[0].y = -aCornersList[ii].y;
vertices[1].x = vertices[0].x;
vertices[1].y = vertices[0].y; // Z only changes.
vertices[2].x = aCornersList[jj].x;
vertices[2].y = -aCornersList[jj].y;
vertices[3].x = vertices[2].x;
vertices[3].y = vertices[2].y; // Z only changes.
Set_Object_Data( vertices, aBiuTo3DUnits );
}
}
// /////////////////////////////////////////////////////////////////////////////
// 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 CPolyPt* ptr = (const CPolyPt*) data;
glVertex3f( ptr->x * g_Parm_3D_Visu.m_BiuTo3Dunits,
-ptr->y * g_Parm_3D_Visu.m_BiuTo3Dunits,
g_Parm_3D_Visu.m_CurrentZpos );
}
void CALLBACK tesswxPoint2Vertex( const GLvoid* data )
{
const wxPoint* ptr = (const wxPoint*) data;
glVertex3f( ptr->x * g_Parm_3D_Visu.m_BiuTo3Dunits,
-ptr->y * g_Parm_3D_Visu.m_BiuTo3Dunits,
g_Parm_3D_Visu.m_CurrentZpos );
}
void CALLBACK tessErrorCB( GLenum errorCode )
{
#if defined(DEBUG)
const GLubyte* errorStr;
errorStr = gluErrorString( errorCode );
// DEBUG //
D( printf( "Tess ERROR: %s\n", errorStr ); )
#endif
}
/*
* 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) )
/**
* Function Draw3D_HorizontalPolygon
* draw one solid polygon
* @param aCornersList = a std::vector<wxPoint> list of corners, in board internal units
* @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
* If aThickness = 0, a polygon area is drawn in a XY plane at Z position = aZpos.
* If aThickness 1 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_HorizontalPolygon( std::vector<wxPoint>& aCornersList, int aZpos,
int aThickness, double aBiuTo3DUnits );
/** 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
* If aThickness = 0, a polygon area is drawn in a XY plane at Z position = aZpos.
* If aThickness 1 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 std::vector<CPolyPt>& aPolysList,
int aZpos, int aThickness, double aBiuTo3DUnits );
/** draw the solid polygon found in aPolysList
* The first polygonj is the main polygon, others are holes
* @param aPolysList = the polygon with holes 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
* If aThickness = 0, a polygon area is drawn in a XY plane at Z position = aZpos.
* If aThickness 1 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_SolidHorizontalPolygonWithHoles( const std::vector<CPolyPt>& aPolysList,
int aZpos, int aThickness, double aBiuTo3DUnits );
/** draw a thick segment using 3D primitives, in a XY plane
* @param wxPoint aStart = YX position of start point in board units
* @param wxPoint 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
* If aThickness = 0, a polygon area is drawn in a XY plane at Z position = aZpos.
* If aThickness 1 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 plane parallel to the XY plane
* @param aCenterPos = 3D position of the center
* @param aStartPointX, aStartPointY = start point coordinate of arc (3D units)
* @param aWidth = width of the circle (3D units)
* @param aArcAngle = arc angle in 1/10 degrees
* @param aWidth = thickness of arc
*/
void Draw3D_ArcSegment( const S3D_VERTEX& aCenterPos,
double aStartPointX, double aStartPointY,
double aArcAngle, double aWidth );
/** draw a thick cylinder (a tube) using 3D primitives.
* the cylinder axis is parallel to the Z axis
* @param aCentPos = 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 );
#endif // _3D_DRAW_BASIC_FUNCTIONS_H_
......@@ -37,8 +37,6 @@
#include <3d_viewer_id.h>
INFO3D_VISU g_Parm_3D_Visu;
double DataScale3D; // 3D conversion units.
BEGIN_EVENT_TABLE( EDA_3D_FRAME, wxFrame )
EVT_ACTIVATE( EDA_3D_FRAME::OnActivate )
......@@ -130,6 +128,13 @@ void EDA_3D_FRAME::OnCloseWindow( wxCloseEvent& Event )
Destroy();
}
static const wxString keyPosx( wxT( "Pos_x" ) );
static const wxString keyPosy( wxT( "Pos_y" ) );
static const wxString keySizex( wxT( "Size_x" ) );
static const wxString keySizey( wxT( "Size_y" ) );
static const wxString keyBgColor_Red( wxT( "BgColor_Red" ) );
static const wxString keyBgColor_Green( wxT( "BgColor_Green" ) );
static const wxString keyBgColor_Blue( wxT( "BgColor_Blue" ) );
void EDA_3D_FRAME::GetSettings()
{
......@@ -138,17 +143,17 @@ void EDA_3D_FRAME::GetSettings()
if( config )
{
text = m_FrameName + wxT( "Pos_x" );
text = m_FrameName + keyPosx;
config->Read( text, &m_FramePos.x );
text = m_FrameName + wxT( "Pos_y" );
text = m_FrameName + keyPosy;
config->Read( text, &m_FramePos.y );
text = m_FrameName + wxT( "Size_x" );
text = m_FrameName + keySizex;
config->Read( text, &m_FrameSize.x, 600 );
text = m_FrameName + wxT( "Size_y" );
text = m_FrameName + keySizey;
config->Read( text, &m_FrameSize.y, 400 );
config->Read( wxT( "BgColor_Red" ), &g_Parm_3D_Visu.m_BgColor.m_Red, 0.0 );
config->Read( wxT( "BgColor_Green" ), &g_Parm_3D_Visu.m_BgColor.m_Green, 0.0 );
config->Read( wxT( "BgColor_Blue" ), &g_Parm_3D_Visu.m_BgColor.m_Blue, 0.0 );
config->Read( keyBgColor_Red, &g_Parm_3D_Visu.m_BgColor.m_Red, 0.0 );
config->Read( keyBgColor_Green, &g_Parm_3D_Visu.m_BgColor.m_Green, 0.0 );
config->Read( keyBgColor_Blue, &g_Parm_3D_Visu.m_BgColor.m_Blue, 0.0 );
}
#if defined( __WXMAC__ )
// for macOSX, the window must be below system (macOSX) toolbar
......@@ -166,9 +171,9 @@ void EDA_3D_FRAME::SaveSettings()
if( !Config )
return;
Config->Write( wxT( "BgColor_Red" ), g_Parm_3D_Visu.m_BgColor.m_Red );
Config->Write( wxT( "BgColor_Green" ), g_Parm_3D_Visu.m_BgColor.m_Green );
Config->Write( wxT( "BgColor_Blue" ), g_Parm_3D_Visu.m_BgColor.m_Blue );
Config->Write( keyBgColor_Red, g_Parm_3D_Visu.m_BgColor.m_Red );
Config->Write( keyBgColor_Green, g_Parm_3D_Visu.m_BgColor.m_Green );
Config->Write( keyBgColor_Blue, g_Parm_3D_Visu.m_BgColor.m_Blue );
if( IsIconized() )
return;
......@@ -176,13 +181,13 @@ void EDA_3D_FRAME::SaveSettings()
m_FrameSize = GetSize();
m_FramePos = GetPosition();
text = m_FrameName + wxT( "Pos_x" );
text = m_FrameName + keyPosx;
Config->Write( text, (long) m_FramePos.x );
text = m_FrameName + wxT( "Pos_y" );
text = m_FrameName + keyPosy;
Config->Write( text, (long) m_FramePos.y );
text = m_FrameName + wxT( "Size_x" );
text = m_FrameName + keySizex;
Config->Write( text, (long) m_FrameSize.x );
text = m_FrameName + wxT( "Size_y" );
text = m_FrameName + keySizey;
Config->Write( text, (long) m_FrameSize.y );
}
......@@ -322,6 +327,11 @@ void EDA_3D_FRAME::Process_Special_Functions( wxCommandEvent& event )
NewDisplay();
return;
case ID_MENU3D_USE_COPPER_THICKNESS:
g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_USE_COPPER_THICKNESS] = isChecked;
NewDisplay();
return;
case ID_MENU3D_ZONE_ONOFF:
g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_ZONE] = isChecked;
NewDisplay();
......
......@@ -34,6 +34,10 @@
#include <appl_wxstruct.h>
#include <3d_viewer.h>
#include <info3d_visu.h>
// Imported function:
extern void Set_Object_Data( std::vector< S3D_VERTEX >& aVertices, double aBiuTo3DUnits );
// separator chars
static const char* sep_chars = " \t\n\r";
......@@ -400,6 +404,7 @@ int S3D_MASTER::ReadGeometry( FILE* file, int* LineNum )
int err = 1;
std::vector< double > points;
std::vector< double > list;
double vrmlunits_to_3Dunits = g_Parm_3D_Visu.m_BiuTo3Dunits * UNITS3D_TO_UNITSPCB;
while( GetLine( file, line, LineNum, 512 ) )
{
......@@ -545,7 +550,7 @@ int S3D_MASTER::ReadGeometry( FILE* file, int* LineNum )
}
Set_Object_Coords( vertices );
Set_Object_Data( vertices );
Set_Object_Data( vertices, vrmlunits_to_3Dunits );
vertices.clear();
coordIndex.clear();
}
......
......@@ -169,6 +169,10 @@ void EDA_3D_FRAME::ReCreateMenuBar()
if( full_options )
{
item = AddMenuItem( prefsMenu, ID_MENU3D_USE_COPPER_THICKNESS,
_( "Show Copper Thickness" ), KiBitmap( use_3D_copper_thickness_xpm ), wxITEM_CHECK );
item->Check(g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_USE_COPPER_THICKNESS]);
item = AddMenuItem( prefsMenu, ID_MENU3D_MODULE_ONOFF,
_( "Show 3D F&ootprints" ), KiBitmap( shape_3d_xpm ), wxITEM_CHECK );
item->Check(g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_MODULE]);
......
......@@ -30,8 +30,9 @@
#ifndef __3D_VIEWER_H__
#define __3D_VIEWER_H__
#include <wxBasePcbFrame.h> // m_auimanager member.
#include <wxBasePcbFrame.h> // for m_auimanager member.
#include <layers_id_colors_and_visibility.h> // Layers id definitions
#include <PolyLine.h> // fot CPolyPt
#if !wxUSE_GLCANVAS
#error Please set wxUSE_GLCANVAS to 1 in setup.h.
......@@ -149,24 +150,6 @@ public:
*/
void Draw3D_Zone( ZONE_CONTAINER* aZone );
/**
* Function Draw3D_SolidPolygonsInZones
* draw all solid polygons used as filled areas in a zone
* Function used by Draw3D_Zone
* Note: polygons are drawn, but not the thick polygon outlines
* Use Draw3D_Zone to draw aZone
* @param aZone = the zone to draw
*/
void Draw3D_SolidPolygonsInZones( ZONE_CONTAINER* aZone );
/**
* Function Draw3D_Polygon
* draw one solid polygon
* @param aCornersList = a std::vector<wxPoint> list of corners, in physical coordinates
* @param aZpos = the z position in 3D units
*/
void Draw3D_Polygon( std::vector<wxPoint>& aCornersList, double aZpos );
/**
* Function Draw3D_DrawText
* draws 3D segments to create text objects.
......@@ -258,7 +241,4 @@ private:
DECLARE_EVENT_TABLE()
};
void SetGLColor( int color );
void Set_Object_Data( std::vector< S3D_VERTEX >& aVertices );
#endif /* __3D_VIEWER_H__ */
......@@ -29,6 +29,7 @@ enum id_3dview_frm
ID_MOVE3D_DOWN,
ID_ORTHO,
ID_MENU3D_BGCOLOR_SELECTION,
ID_MENU3D_USE_COPPER_THICKNESS,
ID_MENU3D_AXIS_ONOFF,
ID_MENU3D_MODULE_ONOFF,
ID_MENU3D_ZONE_ONOFF,
......
......@@ -13,9 +13,11 @@ set(3D-VIEWER_SRCS
3d_canvas.cpp
3d_class.cpp
3d_draw.cpp
3d_draw_basic_functions.cpp
3d_frame.cpp
3d_read_mesh.cpp
3d_toolbar.cpp
info3d_visu.cpp
trackball.cpp
)
......
/*
* 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-2011 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 info3d_visu.cpp
*/
#include <fctsys.h>
#include <common.h>
#include <class_board_design_settings.h>
#include <class_board.h>
#include <3d_viewer.h>
#include <info3d_visu.h>
#include <trackball.h>
// Thickness of copper
// TODO: define the actual copper thickness by user
#define COPPER_THICKNESS (int)(0.035 * IU_PER_MM) // for 35 u
#define TECH_LAYER_THICKNESS (int)(0.04 * IU_PER_MM)
#define EPOXY_THICKNESS (int)(1.6 * IU_PER_MM) // for 1.6 mm
/* INFO3D_VISU in an helper class to store parameters like scaling factors,
* board size, Z coordinates of layers ...
* to create the 3D GLList
*/
INFO3D_VISU::INFO3D_VISU()
{
int ii;
m_Beginx = m_Beginy = 0.0; // position of mouse
m_Zoom = 1.0;
m_3D_Grid = 10.0; // Grid value in mm
trackball( m_Quat, 0.0, 0.0, 0.0, 0.0 );
for( ii = 0; ii < 4; ii++ )
m_Rot[ii] = 0.0;
m_CopperLayersCount = 2;
m_BoardSettings = NULL;
m_CopperThickness = 0;
m_EpoxyThickness = 0;
m_NonCopperLayerThickness = 0;
// default all special item layers Visible
for( ii = 0; ii < FL_LAST; ii++ )
m_DrawFlags[ii] = true;
m_DrawFlags[FL_GRID] = false;
m_DrawFlags[FL_USE_COPPER_THICKNESS] = false;
}
INFO3D_VISU::~INFO3D_VISU()
{
}
/* Initialize info 3D Parameters from aBoard
*/
void INFO3D_VISU::InitSettings( BOARD* aBoard )
{
EDA_RECT bbbox = aBoard->ComputeBoundingBox( false );
if( bbbox.GetWidth() == 0 && bbbox.GetHeight() == 0 )
{
bbbox.SetWidth( 100 * IU_PER_MM );
bbbox.SetHeight( 100 * IU_PER_MM );
}
m_BoardSettings = &aBoard->GetDesignSettings();
m_BoardSize = bbbox.GetSize();
m_BoardPos = bbbox.Centre();
m_BoardPos.y = -m_BoardPos.y;
m_CopperLayersCount = aBoard->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;
m_BiuTo3Dunits = 2.0 / std::max( m_BoardSize.x, m_BoardSize.y );
m_EpoxyThickness = aBoard->GetDesignSettings().GetBoardThickness() * m_BiuTo3Dunits;
// TODO use value defined by user (currently use default values by ctor
m_CopperThickness = COPPER_THICKNESS * m_BiuTo3Dunits;
m_NonCopperLayerThickness = TECH_LAYER_THICKNESS * m_BiuTo3Dunits;
// Init Z position of each layer
// calculate z position for each copper layer
int layer;
int copper_layers_cnt = m_CopperLayersCount;
for( layer = 0; layer < copper_layers_cnt; layer++ )
{
m_LayerZcoord[layer] =
m_EpoxyThickness * layer / (copper_layers_cnt - 1);
}
double zpos_copper_back = m_LayerZcoord[0];
double zpos_copper_front = m_EpoxyThickness;
// Fill remaining unused copper layers and front layer zpos
// with m_EpoxyThickness
for( ; layer <= LAST_COPPER_LAYER; layer++ )
{
m_LayerZcoord[layer] = m_EpoxyThickness;
}
// calculate z position for each non copper layer
for( int layer_id = FIRST_NO_COPPER_LAYER; layer_id < NB_LAYERS; layer_id++ )
{
double zpos;
#define NonCopperLayerThicknessMargin 1.1
switch( layer_id )
{
case ADHESIVE_N_BACK:
zpos = zpos_copper_back -
4 * m_NonCopperLayerThickness * NonCopperLayerThicknessMargin;
break;
case ADHESIVE_N_FRONT:
zpos = zpos_copper_front +
4 * m_NonCopperLayerThickness * NonCopperLayerThicknessMargin;
break;
case SOLDERPASTE_N_BACK:
zpos = zpos_copper_back -
3 * m_NonCopperLayerThickness * NonCopperLayerThicknessMargin;
break;
case SOLDERPASTE_N_FRONT:
zpos = zpos_copper_front +
3 * m_NonCopperLayerThickness * NonCopperLayerThicknessMargin;
break;
case SOLDERMASK_N_BACK:
zpos = zpos_copper_back -
1 * m_NonCopperLayerThickness * NonCopperLayerThicknessMargin;
break;
case SOLDERMASK_N_FRONT:
zpos = zpos_copper_front +
1 * m_NonCopperLayerThickness * NonCopperLayerThicknessMargin;
break;
case SILKSCREEN_N_BACK:
zpos = zpos_copper_back -
2 * m_NonCopperLayerThickness * NonCopperLayerThicknessMargin;
break;
case SILKSCREEN_N_FRONT:
zpos = zpos_copper_front +
2 * m_NonCopperLayerThickness * NonCopperLayerThicknessMargin;
break;
default:
zpos = zpos_copper_front +
(layer_id - FIRST_NO_COPPER_LAYER + 5) *
m_NonCopperLayerThickness * NonCopperLayerThicknessMargin;
break;
}
m_LayerZcoord[layer_id] = zpos;
}
}
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com
* Copyright (C) 2012 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 1992-2011 KiCad Developers, see AUTHORS.txt for contributors.
*
......@@ -24,7 +24,7 @@
*/
/**
* @file 3d_viewer.h
* @file info3d_visu.h
*/
#ifndef __INFO3D_VISU_H__
......@@ -33,10 +33,6 @@
#include <wxBasePcbFrame.h> // m_auimanager member.
#include <layers_id_colors_and_visibility.h> // Layers id definitions
#if !wxUSE_GLCANVAS
#error Please set wxUSE_GLCANVAS to 1 in setup.h.
#endif
#include <wx/glcanvas.h>
#ifdef __WXMAC__
......@@ -74,34 +70,74 @@ public:
FL_AXIS=0, FL_MODULE, FL_ZONE,
FL_COMMENTS, FL_DRAWINGS, FL_ECO1, FL_ECO2,
FL_GRID,
FL_USE_COPPER_THICKNESS,
FL_LAST
};
double m_Beginx, m_Beginy; // position of mouse
double m_Quat[4]; // orientation of object
double m_Rot[4]; // man rotation of object
double m_Zoom; // field of view in degrees
double m_Beginx, m_Beginy; // position of mouse (used in drag commands)
double m_Quat[4]; // orientation of 3D view
double m_Rot[4]; // rotation parameters of 3D view
double m_Zoom; // 3D zoom value
double m_3D_Grid; // 3D grid valmue, in mm
S3D_COLOR m_BgColor;
bool m_DrawFlags[FL_LAST]; // show these special items
wxPoint m_BoardPos;
wxSize m_BoardSize;
bool m_DrawFlags[FL_LAST]; // Enable/disable flags (see DISPLAY3D_FLG list)
wxPoint m_BoardPos; // center board actual position in board units
wxSize m_BoardSize; // board actual size in board units
int m_CopperLayersCount; // Number of copper layers actually used by the board
const BOARD_DESIGN_SETTINGS* m_BoardSettings; // Link to current board design settings
double m_BiuTo3Dunits; // Normalization scale to convert board
// internal units to 3D units
// to scale 3D units between -1.0 and +1.0
double m_LayerZcoord[LAYER_COUNT]; // Z position of each layer (normalized)
double m_CurrentZpos; // temporary storage of current value of Z position,
// used in some calculation
private:
double m_CopperThickness; // Copper thickness (normalized)
double m_EpoxyThickness; // Epoxy thickness (normalized)
double m_NonCopperLayerThickness; // Non copper layers thickness
double m_BoardScale; /* Normalization scale for coordinates:
* when scaled between -1.0 and +1.0 */
double m_LayerZcoord[LAYER_COUNT]; // Z position of each layer (normalized)
double m_ActZpos;
public: INFO3D_VISU();
~INFO3D_VISU();
/**
* Function InitSettings
* Initialize info 3D Parameters from aBoard
* @param aBoard: the board to display
*/
void InitSettings( BOARD* aBoard );
/**
* function m_BiuTo3Dunits
* @return the Z coordinate of the layer aLayer, in Board Internal Units
* @param aLayer: the layer number
*/
int GetLayerZcoordBIU( int aLayer )
{
return (int) (m_LayerZcoord[aLayer] / m_BiuTo3Dunits );
}
int GetCopperThicknessBIU() const
{
return m_DrawFlags[FL_USE_COPPER_THICKNESS] ?
(int) (m_CopperThickness / m_BiuTo3Dunits )
: 0;
}
int GetEpoxyThicknessBIU() const
{
return (int) (m_EpoxyThickness / m_BiuTo3Dunits );
}
int GetNonCopperLayerThicknessBIU() const
{
return m_DrawFlags[FL_USE_COPPER_THICKNESS] ?
(int) (m_NonCopperLayerThickness / m_BiuTo3Dunits )
: 0;
}
};
extern INFO3D_VISU g_Parm_3D_Visu;
extern double DataScale3D; // 3D scale units.
#endif /* __INFO3D_VISU_H__ */
......@@ -485,6 +485,7 @@ set( BMAPS_MID
unzip
update_module_board
up
use_3D_copper_thickness
via
via_sketch
warning
......
/* Do not modify this file, it was automatically generated by the
* PNG2cpp CMake script, using a *.png file as input.
*/
#include <bitmaps.h>
static const unsigned char png[] = {
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1a, 0x08, 0x06, 0x00, 0x00, 0x00, 0xa9, 0x4a, 0x4c,
0xce, 0x00, 0x00, 0x01, 0xa6, 0x49, 0x44, 0x41, 0x54, 0x48, 0xc7, 0xbd, 0xd5, 0xbf, 0x4b, 0xc3,
0x50, 0x10, 0x07, 0xf0, 0x4b, 0xfa, 0xde, 0x8b, 0x4e, 0x16, 0x71, 0x12, 0x2b, 0x0e, 0x2e, 0xa5,
0x43, 0x71, 0x12, 0x1c, 0xc4, 0xa5, 0xe8, 0x22, 0x76, 0x71, 0xd0, 0xa1, 0xa3, 0x4b, 0x41, 0x6c,
0x5a, 0x7f, 0x80, 0x08, 0x2e, 0x82, 0xe0, 0xa2, 0x83, 0xae, 0x2a, 0x45, 0x11, 0x9c, 0x15, 0x5c,
0x0a, 0x8a, 0xe0, 0xe0, 0xa0, 0x50, 0xf0, 0x0f, 0x28, 0x2a, 0x16, 0xc4, 0x22, 0x0e, 0x6a, 0xa1,
0x3d, 0xbf, 0x95, 0x0e, 0x6a, 0x92, 0xa9, 0x87, 0x90, 0x6f, 0x08, 0x21, 0xe4, 0x93, 0xbb, 0xe4,
0x5d, 0x88, 0x99, 0xe9, 0x3f, 0x42, 0xd8, 0x1c, 0xa4, 0x4d, 0x28, 0xa1, 0x60, 0xc8, 0x98, 0x3c,
0xc2, 0x22, 0x71, 0x9c, 0x0b, 0xdc, 0xd2, 0x0e, 0xaa, 0x28, 0x8c, 0x8b, 0xee, 0x05, 0x31, 0xd7,
0x17, 0xca, 0x11, 0xed, 0xec, 0xda, 0x76, 0x59, 0x0c, 0x32, 0xe6, 0x1d, 0x89, 0x7a, 0xa0, 0x05,
0xa2, 0x6e, 0x60, 0x2f, 0x57, 0x4a, 0xb1, 0x20, 0x76, 0x8d, 0x5b, 0xab, 0xdf, 0xad, 0xc3, 0x0e,
0xd0, 0xf4, 0x32, 0x0e, 0x9f, 0xb5, 0x96, 0xc4, 0x56, 0x3c, 0x50, 0x13, 0x3b, 0xde, 0xb6, 0x2c,
0xae, 0xcb, 0x41, 0x55, 0xd6, 0x7a, 0xc0, 0x03, 0x65, 0x89, 0xba, 0xe6, 0x89, 0x9e, 0xce, 0x43,
0x21, 0xc9, 0xaa, 0x8a, 0xdf, 0xcb, 0xe7, 0x27, 0xd4, 0xac, 0x6a, 0x62, 0x09, 0xa7, 0xca, 0xb2,
0x2d, 0x5c, 0xf7, 0x40, 0x4d, 0x6c, 0x6f, 0x0b, 0x2d, 0xac, 0xc9, 0x41, 0x35, 0x56, 0x6a, 0xc8,
0x03, 0x2d, 0x12, 0x75, 0x00, 0x2b, 0xed, 0xdb, 0x36, 0x9f, 0xa0, 0x8d, 0xad, 0xe6, 0x46, 0xa9,
0x53, 0x60, 0x93, 0xbe, 0xe3, 0x02, 0xef, 0x2b, 0x01, 0xac, 0x8e, 0xb0, 0x40, 0x3e, 0xf0, 0xf0,
0xb1, 0xc0, 0x21, 0x88, 0x0b, 0xdc, 0x46, 0x1b, 0x85, 0x32, 0x4b, 0x59, 0x56, 0xc3, 0x19, 0x76,
0xc6, 0x64, 0x62, 0x62, 0x81, 0x43, 0xd5, 0x65, 0x27, 0xed, 0xb2, 0x61, 0xa1, 0x54, 0x5c, 0x6e,
0x8f, 0xf8, 0x42, 0x3d, 0xe3, 0x14, 0x4d, 0xbf, 0xe9, 0x4b, 0x39, 0x4c, 0x17, 0x30, 0xa9, 0x2d,
0x3f, 0x28, 0xd7, 0x9f, 0xb2, 0x38, 0xfd, 0x2a, 0x56, 0x15, 0xe2, 0xe4, 0xfc, 0x20, 0x0b, 0x29,
0x0c, 0xae, 0xd9, 0x82, 0x90, 0xf9, 0x44, 0x65, 0x71, 0xcf, 0xac, 0x03, 0x14, 0x41, 0x2a, 0xc9,
0x33, 0x25, 0x89, 0x15, 0x57, 0x19, 0x7f, 0xdd, 0xbf, 0xb3, 0x0e, 0xd0, 0x54, 0x1f, 0x96, 0xd5,
0xcc, 0xa3, 0x16, 0xc3, 0x32, 0xac, 0x37, 0x3d, 0x50, 0x13, 0x3b, 0x88, 0xe7, 0x2c, 0xce, 0xd4,
0xc4, 0xaa, 0xaa, 0x67, 0xd9, 0x49, 0xf8, 0x41, 0x61, 0xa4, 0x34, 0x7a, 0x18, 0x92, 0x6c, 0xe1,
0x43, 0x86, 0xa9, 0xd3, 0xf3, 0xbd, 0x03, 0x1a, 0xe9, 0x4d, 0x52, 0x2d, 0x75, 0xa7, 0x79, 0xae,
0x6a, 0x5a, 0x8e, 0x5b, 0x37, 0x55, 0x60, 0x79, 0xdf, 0x55, 0x0c, 0x6c, 0x03, 0x61, 0xa1, 0x94,
0x1a, 0x9d, 0x0a, 0x82, 0x0c, 0x72, 0x2b, 0x88, 0x1d, 0x7d, 0x01, 0xbf, 0xeb, 0x9b, 0xb8, 0x05,
0x3e, 0x9f, 0x36, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
};
const BITMAP_OPAQUE use_3D_copper_thickness_xpm[1] = {{ png, sizeof( png ), "use_3D_copper_thickness_xpm" }};
//EOF
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
height="26"
width="26"
version="1.1"
id="svg2"
inkscape:version="0.48.1 "
sodipodi:docname="3d_use_copper_thickness.svg">
<metadata
id="metadata26">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1280"
inkscape:window-height="968"
id="namedview24"
showgrid="false"
inkscape:zoom="32.120513"
inkscape:cx="12.060967"
inkscape:cy="11.98812"
inkscape:window-x="-4"
inkscape:window-y="-4"
inkscape:window-maximized="1"
inkscape:current-layer="svg2"
showguides="true"
inkscape:guide-bbox="true"
showborder="true">
<sodipodi:guide
orientation="0,1"
position="45.626168,30.620228"
id="guide3799" />
</sodipodi:namedview>
<defs
id="defs4">
<filter
id="c"
height="1.212"
width="1.059"
color-interpolation-filters="sRGB"
y="-0.10598"
x="-0.029501">
<feGaussianBlur
stdDeviation="0.52522041"
id="feGaussianBlur7" />
</filter>
<filter
id="d"
height="1.212"
width="1.059"
color-interpolation-filters="sRGB"
y="-0.10598"
x="-0.029501">
<feGaussianBlur
stdDeviation="0.52522041"
id="feGaussianBlur10" />
</filter>
</defs>
<g
id="g3879"
transform="matrix(1.079734,0,0,0.8805836,0.04176086,4.8713303)">
<path
style="fill:#1c4d00;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none"
inkscape:connector-curvature="0"
id="path22-1-0"
d="M 0.00743077,13.573317 H 18.058057 l 6.017018,10.471372 H 6.0244485 L 0.00816177,13.573317 z" />
<path
style="fill:#72ff06;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none"
inkscape:connector-curvature="0"
id="path22-9"
d="M -0.01750581,11.199955 H 18.033121 l 6.017018,10.471372 H 5.999512 L -0.01677418,11.199955 z" />
</g>
<g
id="g3873"
transform="matrix(1.0749484,0,0,0.90644265,-0.0011,1.998042)">
<path
style="fill:#740000;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none"
inkscape:connector-curvature="0"
id="path22-1"
d="M 0.03961332,2.3524334 H 18.09024 L 24.107258,12.823805 H 6.056631 L 0.04034432,2.3524334 z" />
<path
style="fill:#ff0606;stroke:#000000;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none"
inkscape:connector-curvature="0"
id="path22"
d="M 0.01467674,-0.02092885 H 18.065304 L 24.082322,10.450443 H 6.0316946 L 0.01540837,-0.02092885 z" />
</g>
</svg>
......@@ -306,49 +306,6 @@ PARAM_CFG_ARRAY& SCH_EDIT_FRAME::GetProjectFileParameters()
&g_HPGL_Pen_Descr.m_Pen_Num,
1, 1, 8 ) );
/* these globals don't exist
m_projectFileParams.push_back( new PARAM_CFG_INT( wxT( "offX_A4" ),
&g_Sheet_A4.m_Offset.x ) );
m_projectFileParams.push_back( new PARAM_CFG_INT( wxT( "offY_A4" ),
&g_Sheet_A4.m_Offset.y ) );
m_projectFileParams.push_back( new PARAM_CFG_INT( wxT( "offX_A3" ),
&g_Sheet_A3.m_Offset.x ) );
m_projectFileParams.push_back( new PARAM_CFG_INT( wxT( "offY_A3" ),
&g_Sheet_A3.m_Offset.y ) );
m_projectFileParams.push_back( new PARAM_CFG_INT( wxT( "offX_A2" ),
&g_Sheet_A2.m_Offset.x ) );
m_projectFileParams.push_back( new PARAM_CFG_INT( wxT( "offY_A2" ),
&g_Sheet_A2.m_Offset.y ) );
m_projectFileParams.push_back( new PARAM_CFG_INT( wxT( "offX_A1" ),
&g_Sheet_A1.m_Offset.x ) );
m_projectFileParams.push_back( new PARAM_CFG_INT( wxT( "offY_A1" ),
&g_Sheet_A1.m_Offset.y ) );
m_projectFileParams.push_back( new PARAM_CFG_INT( wxT( "offX_A0" ),
&g_Sheet_A0.m_Offset.x ) );
m_projectFileParams.push_back( new PARAM_CFG_INT( wxT( "offY_A0" ),
&g_Sheet_A0.m_Offset.y ) );
m_projectFileParams.push_back( new PARAM_CFG_INT( wxT( "offX_A" ),
&g_Sheet_A.m_Offset.x ) );
m_projectFileParams.push_back( new PARAM_CFG_INT( wxT( "offY_A" ),
&g_Sheet_A.m_Offset.y ) );
m_projectFileParams.push_back( new PARAM_CFG_INT( wxT( "offX_B" ),
&g_Sheet_B.m_Offset.x ) );
m_projectFileParams.push_back( new PARAM_CFG_INT( wxT( "offY_B" ),
&g_Sheet_B.m_Offset.y ) );
m_projectFileParams.push_back( new PARAM_CFG_INT( wxT( "offX_C" ),
&g_Sheet_C.m_Offset.x ) );
m_projectFileParams.push_back( new PARAM_CFG_INT( wxT( "offY_C" ),
&g_Sheet_C.m_Offset.y ) );
m_projectFileParams.push_back( new PARAM_CFG_INT( wxT( "offX_D" ),
&g_Sheet_D.m_Offset.x ) );
m_projectFileParams.push_back( new PARAM_CFG_INT( wxT( "offY_D" ),
&g_Sheet_D.m_Offset.y ) );
m_projectFileParams.push_back( new PARAM_CFG_INT( wxT( "offX_E" ),
&g_Sheet_E.m_Offset.x ) );
m_projectFileParams.push_back( new PARAM_CFG_INT( wxT( "offY_E" ),
&g_Sheet_E.m_Offset.y ) );
*/
m_projectFileParams.push_back( new PARAM_CFG_INT( wxT( "RptD_X" ),
&g_RepeatStep.x,
0, -1000, +1000 ) );
......
......@@ -458,6 +458,7 @@ EXTERN_BITMAP( unlocked_xpm )
EXTERN_BITMAP( unzip_xpm )
EXTERN_BITMAP( update_module_board_xpm )
EXTERN_BITMAP( up_xpm )
EXTERN_BITMAP( use_3D_copper_thickness_xpm )
EXTERN_BITMAP( via_xpm )
EXTERN_BITMAP( via_sketch_xpm )
EXTERN_BITMAP( viewlibs_icon_xpm )
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment