bool D_PAD::HitTest( const wxPoint& aPosition ) { int dx, dy; double dist; wxPoint shape_pos = ReturnShapePos(); wxPoint delta = aPosition - shape_pos; // first test: a test point must be inside a minimum sized bounding circle. int radius = GetBoundingRadius(); if( ( abs( delta.x ) > radius ) || ( abs( delta.y ) > radius ) ) return false; dx = m_Size.x >> 1; // dx also is the radius for rounded pads dy = m_Size.y >> 1; switch( m_PadShape & 0x7F ) { case PAD_CIRCLE: dist = hypot( delta.x, delta.y ); if( KiROUND( dist ) <= dx ) return true; break; case PAD_TRAPEZOID: { wxPoint poly[4]; BuildPadPolygon( poly, wxSize(0,0), 0 ); RotatePoint( &delta, -m_Orient ); return TestPointInsidePolygon( poly, 4, delta ); } default: RotatePoint( &delta, -m_Orient ); if( (abs( delta.x ) <= dx ) && (abs( delta.y ) <= dy) ) return true; break; } return false; }
void D_PAD::DrawShape( EDA_RECT* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo ) { wxPoint coord[4]; int delta_cx, delta_cy; int angle = m_Orient; int seg_width; GRSetDrawMode( aDC, aDrawInfo.m_DrawMode ); // calculate pad shape position : wxPoint shape_pos = ReturnShapePos() - aDrawInfo.m_Offset; wxSize halfsize = m_Size; halfsize.x >>= 1; halfsize.y >>= 1; switch( GetShape() ) { case PAD_CIRCLE: if( aDrawInfo.m_ShowPadFilled ) GRFilledCircle( aClipBox, aDC, shape_pos.x, shape_pos.y, halfsize.x + aDrawInfo.m_Mask_margin.x, 0, aDrawInfo.m_Color, aDrawInfo.m_Color ); else GRCircle( aClipBox, aDC, shape_pos.x, shape_pos.y, halfsize.x + aDrawInfo.m_Mask_margin.x, m_PadSketchModePenSize, aDrawInfo.m_Color ); if( aDrawInfo.m_PadClearance ) { GRCircle( aClipBox, aDC, shape_pos.x, shape_pos.y, halfsize.x + aDrawInfo.m_PadClearance, 0, aDrawInfo.m_Color ); } break; case PAD_OVAL: { wxPoint segStart, segEnd; seg_width = BuildSegmentFromOvalShape(segStart, segEnd, angle); segStart += shape_pos; segEnd += shape_pos; if( aDrawInfo.m_ShowPadFilled ) { GRFillCSegm( aClipBox, aDC, segStart.x, segStart.y, segEnd.x, segEnd.y, seg_width, aDrawInfo.m_Color ); } else { GRCSegm( aClipBox, aDC, segStart.x, segStart.y, segEnd.x, segEnd.y, seg_width, m_PadSketchModePenSize, aDrawInfo.m_Color ); } /* Draw the isolation line. */ if( aDrawInfo.m_PadClearance ) { seg_width += 2 * aDrawInfo.m_PadClearance; GRCSegm( aClipBox, aDC, segStart.x, segStart.y, segEnd.x, segEnd.y, seg_width, aDrawInfo.m_Color ); } } break; case PAD_RECT: case PAD_TRAPEZOID: BuildPadPolygon( coord, aDrawInfo.m_Mask_margin, angle ); for( int ii = 0; ii < 4; ii++ ) coord[ii] += shape_pos; GRClosedPoly( aClipBox, aDC, 4, coord, aDrawInfo.m_ShowPadFilled, aDrawInfo.m_ShowPadFilled ? 0 : m_PadSketchModePenSize, aDrawInfo.m_Color, aDrawInfo.m_Color ); if( aDrawInfo.m_PadClearance ) { BuildPadPolygon( coord, wxSize( aDrawInfo.m_PadClearance, aDrawInfo.m_PadClearance ), angle ); for( int ii = 0; ii < 4; ii++ ) coord[ii] += shape_pos; GRClosedPoly( aClipBox, aDC, 4, coord, 0, aDrawInfo.m_Color, aDrawInfo.m_Color ); } break; default: break; } /* Draw the pad hole */ wxPoint holepos = m_Pos - aDrawInfo.m_Offset; int hole = m_Drill.x >> 1; bool drawhole = hole > 0; if( !aDrawInfo.m_ShowPadFilled && !aDrawInfo. m_ShowNotPlatedHole ) drawhole = false; if( drawhole ) { bool blackpenstate = false; if( aDrawInfo.m_IsPrinting ) { blackpenstate = GetGRForceBlackPenState(); GRForceBlackPen( false ); aDrawInfo.m_HoleColor = g_DrawBgColor; } if( aDrawInfo.m_DrawMode != GR_XOR ) GRSetDrawMode( aDC, GR_COPY ); else GRSetDrawMode( aDC, GR_XOR ); int hole_color = aDrawInfo.m_HoleColor; if( aDrawInfo. m_ShowNotPlatedHole ) // Draw a specific hole color hole_color = aDrawInfo.m_NPHoleColor; switch( m_DrillShape ) { case PAD_CIRCLE: if( aDC->LogicalToDeviceXRel( hole ) > 1 ) GRFilledCircle( aClipBox, aDC, holepos.x, holepos.y, hole, 0, aDrawInfo.m_Color, hole_color ); break; case PAD_OVAL: halfsize.x = m_Drill.x >> 1; halfsize.y = m_Drill.y >> 1; if( m_Drill.x > m_Drill.y ) /* horizontal */ { delta_cx = halfsize.x - halfsize.y; delta_cy = 0; seg_width = m_Drill.y; } else /* vertical */ { delta_cx = 0; delta_cy = halfsize.y - halfsize.x; seg_width = m_Drill.x; } RotatePoint( &delta_cx, &delta_cy, angle ); GRFillCSegm( aClipBox, aDC, holepos.x + delta_cx, holepos.y + delta_cy, holepos.x - delta_cx, holepos.y - delta_cy, seg_width, hole_color ); break; default: break; } if( aDrawInfo.m_IsPrinting ) GRForceBlackPen( blackpenstate ); } GRSetDrawMode( aDC, aDrawInfo.m_DrawMode ); /* Draw "No connect" ( / or \ or cross X ) if necessary. : */ if( m_Netname.IsEmpty() && aDrawInfo.m_ShowNCMark ) { int dx0 = MIN( halfsize.x, halfsize.y ); int nc_color = BLUE; if( m_layerMask & LAYER_FRONT ) /* Draw \ */ GRLine( aClipBox, aDC, holepos.x - dx0, holepos.y - dx0, holepos.x + dx0, holepos.y + dx0, 0, nc_color ); if( m_layerMask & LAYER_BACK ) /* Draw / */ GRLine( aClipBox, aDC, holepos.x + dx0, holepos.y - dx0, holepos.x - dx0, holepos.y + dx0, 0, nc_color ); } /* Draw the pad number */ if( !aDrawInfo.m_Display_padnum && !aDrawInfo.m_Display_netname ) return; wxPoint tpos0 = shape_pos; // Position of the centre of text wxPoint tpos = tpos0; wxSize AreaSize; // size of text area, normalized to AreaSize.y < AreaSize.x int shortname_len = m_ShortNetname.Len(); if( !aDrawInfo.m_Display_netname ) shortname_len = 0; if( GetShape() == PAD_CIRCLE ) angle = 0; AreaSize = m_Size; if( m_Size.y > m_Size.x ) { angle += 900; AreaSize.x = m_Size.y; AreaSize.y = m_Size.x; } if( shortname_len > 0 ) // if there is a netname, provides room to display this netname { AreaSize.y /= 2; // Text used only the upper area of the // pad. The lower area displays the net name tpos.y -= AreaSize.y / 2; } // Calculate the position of text, that is the middle point of the upper // area of the pad RotatePoint( &tpos, shape_pos, angle ); /* Draw text with an angle between -90 deg and + 90 deg */ int t_angle = angle; NORMALIZE_ANGLE_90( t_angle ); /* Note: in next calculations, texte size is calculated for 3 or more * chars. Of course, pads numbers and nets names can have less than 3 * chars. but after some tries, i found this is gives the best look */ #define MIN_CHAR_COUNT 3 wxString buffer; int tsize; if( aDrawInfo.m_Display_padnum ) { ReturnStringPadName( buffer ); int numpad_len = buffer.Len(); numpad_len = MAX( numpad_len, MIN_CHAR_COUNT ); tsize = min( AreaSize.y, AreaSize.x / numpad_len ); #define CHAR_SIZE_MIN 5 if( aDC->LogicalToDeviceXRel( tsize ) >= CHAR_SIZE_MIN ) // Not drawable when size too small. { // tsize reserve room for marges and segments thickness tsize = (int) ( tsize * 0.8 ); DrawGraphicText( aDrawInfo.m_DrawPanel, aDC, tpos, WHITE, buffer, t_angle, wxSize( tsize, tsize ), GR_TEXT_HJUSTIFY_CENTER, GR_TEXT_VJUSTIFY_CENTER, tsize / 7, false, false ); } } // display the short netname, if exists if( shortname_len == 0 ) return; shortname_len = MAX( shortname_len, MIN_CHAR_COUNT ); tsize = min( AreaSize.y, AreaSize.x / shortname_len ); if( aDC->LogicalToDeviceXRel( tsize ) >= CHAR_SIZE_MIN ) // Not drawable in size too small. { tpos = tpos0; if( aDrawInfo.m_Display_padnum ) tpos.y += AreaSize.y / 2; RotatePoint( &tpos, shape_pos, angle ); // tsize reserve room for marges and segments thickness tsize = (int) ( tsize * 0.8 ); DrawGraphicText( aDrawInfo.m_DrawPanel, aDC, tpos, WHITE, m_ShortNetname, t_angle, wxSize( tsize, tsize ), GR_TEXT_HJUSTIFY_CENTER, GR_TEXT_VJUSTIFY_CENTER, tsize / 7, false, false ); } }
void D_PAD::Draw3D(Pcb3D_GLCanvas * glcanvas) /***********************************************/ /* Dessin 3D des pads avec leur trou de percage */ { int ii, ll, layer, nlmax; int ux0,uy0, dx,dx0,dy,dy0, delta_cx, delta_cy, xc, yc; int angle, delta_angle; int coord[4][2]; double fcoord[8][2], f_hole_coord[8][2]; float scale; double zpos; wxPoint shape_pos; double x, y, r, w, hole; double drillx, drilly; bool Oncu, Oncmp, Both; int color; scale = g_Parm_3D_Visu.m_BoardScale; hole = (double)m_Drill * scale / 2; /* calcul du centre des formes des pads : */ shape_pos = ReturnShapePos(); ux0 = shape_pos.x; uy0 = shape_pos.y; xc = ux0; yc = uy0; /* le trace depend de la rotation de l'empreinte */ dx = dx0 = m_Size.x >> 1 ; dy = dy0 = m_Size.y >> 1 ; /* demi dim dx et dy */ angle = m_Orient; drillx = m_Pos.x * scale; drilly = m_Pos.y * scale; /* trace du trou de percage */ if ( m_Drill ) { SetGLColor(DARKGRAY); Draw3D_FilledCylinder(drillx, -drilly, hole, g_Parm_3D_Visu.m_LayerZcoord[CMP_N], 0.0); } glNormal3f( 0.0, 0.0, 1.0); // Normal is Z axis nlmax = g_Parm_3D_Visu.m_Layers-1; Oncu = (m_Masque_Layer & CUIVRE_LAYER) ? TRUE : FALSE; Oncmp = (m_Masque_Layer & CMP_LAYER) ? TRUE : FALSE; Both = Oncu && Oncmp; switch (m_PadShape & 0x7F) { case CIRCLE : x = xc * scale; y = yc * scale; r = (double)dx * scale; for ( layer = CUIVRE_N; layer <= CMP_N; layer ++) { if (layer && (layer == nlmax) ) layer = CMP_N; if ( (layer == CMP_N) && ! Oncmp ) continue; if ( (layer == CUIVRE_N) && ! Oncu ) continue; if ( (layer > CUIVRE_N) && (layer < CMP_N) && !Both) continue; color = g_Parm_3D_Visu.m_BoardSettings->m_LayerColor[layer]; if ( color & ITEM_NOT_SHOW ) continue; SetGLColor(color); glNormal3f( 0.0, 0.0, (layer == CUIVRE_N) ? -1.0 : 1.0); zpos = g_Parm_3D_Visu.m_LayerZcoord[layer]; Draw3D_FilledCircle(x, -y, r, hole, zpos); } break; case OVALE : /* calcul de l'entraxe de l'ellipse */ if( dx > dy ) /* ellipse horizontale */ { delta_cx = dx - dy; delta_cy = 0; w = m_Size.y * scale; delta_angle = angle+900; } else /* ellipse verticale */ { delta_cx = 0; delta_cy = dy - dx; w = m_Size.x * scale; delta_angle = angle; } 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 = CUIVRE_N; layer <= CMP_N; layer ++) { if (layer && (layer == nlmax) ) layer = CMP_N; if ( (layer == CMP_N) && ! Oncmp ) continue; if ( (layer == CUIVRE_N) && ! Oncu ) continue; if ( (layer > CUIVRE_N) && (layer < CMP_N) && !Both) continue; color = g_Parm_3D_Visu.m_BoardSettings->m_LayerColor[layer]; glNormal3f( 0.0, 0.0, (layer == CUIVRE_N) ? -1.0 : 1.0); if ( color & ITEM_NOT_SHOW ) continue; SetGLColor(color); zpos = g_Parm_3D_Visu.m_LayerZcoord[layer]; Draw3D_FilledSegmentWithHole(ox, -oy, fx, -fy, w, drillx, -drilly, hole, zpos); } } break; case RECT : case SPECIAL_PAD: case TRAPEZE: { int ddx, ddy ; ddx = m_DeltaSize.x >> 1 ; ddy = m_DeltaSize.y >> 1 ; /* demi dim dx et dy */ coord[0][0] = - dx - ddy; coord[0][1] = + dy + ddx; coord[1][0] = - dx + ddy; coord[1][1] = - dy - ddx; coord[2][0] = + dx - ddy; coord[2][1] = - dy + ddx; coord[3][0] = + dx + ddy; coord[3][1] = + dy - ddx; for (ii = 0; ii < 4; ii++) { RotatePoint(&coord[ii][0],&coord[ii][1], angle); coord[ii][0] += ux0; coord[ii][1] += uy0; ll = ii*2; fcoord[ll][0] = coord[ii][0] * scale; fcoord[ll][1] = coord[ii][1] * scale; } for (ii = 0; ii < 7; ii+=2) { ll = ii+2; if (ll > 7) ll -= 8; fcoord[ii+1][0] = (fcoord[ii][0] + fcoord[ll][0])/2; fcoord[ii+1][1] = (fcoord[ii][1] + fcoord[ll][1])/2; } for (ii = 0; ii < 8; ii++) { f_hole_coord[ii][0] = -hole*0.707; f_hole_coord[ii][1] = hole*0.707; RotatePoint(&f_hole_coord[ii][0], &f_hole_coord[ii][1], angle -(ii * 450) ); f_hole_coord[ii][0] += drillx; f_hole_coord[ii][1] += drilly; } for ( layer = CUIVRE_N; layer <= CMP_N; layer ++) { if (layer && (layer == nlmax) ) layer = CMP_N; if ( (layer == CMP_N) && ! Oncmp ) continue; if ( (layer == CUIVRE_N) && ! Oncu ) continue; if ( (layer > CUIVRE_N) && (layer < CMP_N) && !Both) continue; color = g_Parm_3D_Visu.m_BoardSettings->m_LayerColor[layer]; glNormal3f( 0.0, 0.0, (layer == CUIVRE_N) ? -1.0 : 1.0); if ( color & ITEM_NOT_SHOW ) continue; SetGLColor(color); zpos = g_Parm_3D_Visu.m_LayerZcoord[layer]; glBegin(GL_QUAD_STRIP); for ( ii = 0; ii < 8; ii++ ) { glVertex3f( f_hole_coord[ii][0], -f_hole_coord[ii][1] , zpos); glVertex3f( fcoord[ii][0], -fcoord[ii][1] , zpos); } glVertex3f( f_hole_coord[0][0], -f_hole_coord[0][1] , zpos); glVertex3f( fcoord[0][0], -fcoord[0][1] , zpos); glEnd(); } break; default: break; } } }