int DRAWING_TOOL::DrawLine( const TOOL_EVENT& aEvent ) { boost::optional<VECTOR2D> startingPoint; if( m_editModules ) { m_frame->SetToolID( ID_MODEDIT_LINE_TOOL, wxCURSOR_PENCIL, _( "Add graphic line" ) ); EDGE_MODULE* line = new EDGE_MODULE( m_board->m_Modules ); while( drawSegment( S_SEGMENT, reinterpret_cast<DRAWSEGMENT*&>( line ), startingPoint ) ) { if( line ) { m_frame->OnModify(); m_frame->SaveCopyInUndoList( m_board->m_Modules, UR_MODEDIT ); line->SetParent( m_board->m_Modules ); line->SetLocalCoord(); m_board->m_Modules->GraphicalItems().PushFront( line ); startingPoint = line->GetEnd(); } else { startingPoint = boost::none; } line = new EDGE_MODULE( m_board->m_Modules ); } } else // !m_editModules case { m_frame->SetToolID( ID_PCB_ADD_LINE_BUTT, wxCURSOR_PENCIL, _( "Add graphic line" ) ); DRAWSEGMENT* line = new DRAWSEGMENT; while( drawSegment( S_SEGMENT, line, startingPoint ) ) { if( line ) { m_board->Add( line ); m_frame->OnModify(); m_frame->SaveCopyInUndoList( line, UR_NEW ); startingPoint = line->GetEnd(); } else { startingPoint = boost::none; } line = new DRAWSEGMENT; } } m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString ); return 0; }
int DRAWING_TOOL::DrawArc( const TOOL_EVENT& aEvent ) { if( m_editModules ) { m_frame->SetToolID( ID_MODEDIT_ARC_TOOL, wxCURSOR_PENCIL, _( "Add graphic arc" ) ); EDGE_MODULE* arc = new EDGE_MODULE( m_board->m_Modules ); while( drawArc( reinterpret_cast<DRAWSEGMENT*&>( arc ) ) ) { if( arc ) { m_frame->OnModify(); m_frame->SaveCopyInUndoList( m_board->m_Modules, UR_MODEDIT ); arc->SetParent( m_board->m_Modules ); arc->SetLocalCoord(); m_board->m_Modules->GraphicalItems().PushFront( arc ); } arc = new EDGE_MODULE( m_board->m_Modules ); } } else // !m_editModules case { m_frame->SetToolID( ID_PCB_ARC_BUTT, wxCURSOR_PENCIL, _( "Add graphic arc" ) ); DRAWSEGMENT* arc = new DRAWSEGMENT; while( drawArc( arc ) ) { if( arc ) { m_board->Add( arc ); m_frame->OnModify(); m_frame->SaveCopyInUndoList( arc, UR_NEW ); } arc = new DRAWSEGMENT; } } m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString ); return 0; }
int DRAWING_TOOL::DrawCircle( const TOOL_EVENT& aEvent ) { if( m_editModules ) { m_frame->SetToolID( ID_MODEDIT_CIRCLE_TOOL, wxCURSOR_PENCIL, _( "Add graphic circle" ) ); EDGE_MODULE* circle = new EDGE_MODULE( m_board->m_Modules ); while( drawSegment( S_CIRCLE, reinterpret_cast<DRAWSEGMENT*&>( circle ) ) ) { if( circle ) { m_frame->OnModify(); m_frame->SaveCopyInUndoList( m_board->m_Modules, UR_MODEDIT ); circle->SetParent( m_board->m_Modules ); circle->SetLocalCoord(); m_board->m_Modules->GraphicalItems().PushFront( circle ); } circle = new EDGE_MODULE( m_board->m_Modules ); } } else // !m_editModules case { m_frame->SetToolID( ID_PCB_CIRCLE_BUTT, wxCURSOR_PENCIL, _( "Add graphic circle" ) ); DRAWSEGMENT* circle = new DRAWSEGMENT; while( drawSegment( S_CIRCLE, circle ) ) { if( circle ) { m_board->Add( circle ); m_frame->OnModify(); m_frame->SaveCopyInUndoList( circle, UR_NEW ); } circle = new DRAWSEGMENT; } } m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString ); return 0; }
void POINT_EDITOR::addCorner( const VECTOR2I& aBreakPoint ) { EDA_ITEM* item = m_editPoints->GetParent(); const SELECTION& selection = m_selectionTool->GetSelection(); if( item->Type() == PCB_ZONE_AREA_T ) { getEditFrame<PCB_BASE_FRAME>()->OnModify(); getEditFrame<PCB_BASE_FRAME>()->SaveCopyInUndoList( selection.items, UR_CHANGED ); ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( item ); CPolyLine* outline = zone->Outline(); // Handle the last segment, so other segments can be easily handled in a loop unsigned int nearestIdx = outline->GetCornersCount() - 1, nextNearestIdx = 0; SEG side( VECTOR2I( outline->GetPos( nearestIdx ) ), VECTOR2I( outline->GetPos( nextNearestIdx ) ) ); unsigned int nearestDist = side.Distance( aBreakPoint ); for( int i = 0; i < outline->GetCornersCount() - 1; ++i ) { side = SEG( VECTOR2I( outline->GetPos( i ) ), VECTOR2I( outline->GetPos( i + 1 ) ) ); unsigned int distance = side.Distance( aBreakPoint ); if( distance < nearestDist ) { nearestDist = distance; nearestIdx = i; nextNearestIdx = i + 1; } } // Find the point on the closest segment VECTOR2I sideOrigin( outline->GetPos( nearestIdx ) ); VECTOR2I sideEnd( outline->GetPos( nextNearestIdx ) ); SEG nearestSide( sideOrigin, sideEnd ); VECTOR2I nearestPoint = nearestSide.NearestPoint( aBreakPoint ); // Do not add points that have the same coordinates as ones that already belong to polygon // instead, add a point in the middle of the side if( nearestPoint == sideOrigin || nearestPoint == sideEnd ) nearestPoint = ( sideOrigin + sideEnd ) / 2; outline->InsertCorner( nearestIdx, nearestPoint.x, nearestPoint.y ); } else if( item->Type() == PCB_LINE_T || item->Type() == PCB_MODULE_EDGE_T ) { bool moduleEdge = item->Type() == PCB_MODULE_EDGE_T; PCB_BASE_FRAME* frame = getEditFrame<PCB_BASE_FRAME>(); frame->OnModify(); if( moduleEdge ) frame->SaveCopyInUndoList( getModel<BOARD>()->m_Modules, UR_MODEDIT ); else frame->SaveCopyInUndoList( selection.items, UR_CHANGED ); DRAWSEGMENT* segment = static_cast<DRAWSEGMENT*>( item ); if( segment->GetShape() == S_SEGMENT ) { SEG seg( segment->GetStart(), segment->GetEnd() ); VECTOR2I nearestPoint = seg.NearestPoint( aBreakPoint ); // Move the end of the line to the break point.. segment->SetEnd( wxPoint( nearestPoint.x, nearestPoint.y ) ); // and add another one starting from the break point DRAWSEGMENT* newSegment; if( moduleEdge ) { EDGE_MODULE* edge = static_cast<EDGE_MODULE*>( segment ); assert( segment->GetParent()->Type() == PCB_MODULE_T ); newSegment = new EDGE_MODULE( *edge ); edge->SetLocalCoord(); } else { newSegment = new DRAWSEGMENT( *segment ); } newSegment->ClearSelected(); newSegment->SetStart( wxPoint( nearestPoint.x, nearestPoint.y ) ); newSegment->SetEnd( wxPoint( seg.B.x, seg.B.y ) ); if( moduleEdge ) { static_cast<EDGE_MODULE*>( newSegment )->SetLocalCoord(); getModel<BOARD>()->m_Modules->Add( newSegment ); } else { getModel<BOARD>()->Add( newSegment ); } getView()->Add( newSegment ); } } }
bool DRAWING_TOOL::drawSegment( int aShape, DRAWSEGMENT*& aGraphic, boost::optional<VECTOR2D> aStartingPoint ) { // Only two shapes are currently supported assert( aShape == S_SEGMENT || aShape == S_CIRCLE ); DRAWSEGMENT line45; // Add a VIEW_GROUP that serves as a preview for the new item KIGFX::VIEW_GROUP preview( m_view ); m_view->Add( &preview ); m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); m_controls->ShowCursor( true ); m_controls->SetSnapping( true ); Activate(); bool direction45 = false; // 45 degrees only mode bool started = false; VECTOR2I cursorPos = m_controls->GetCursorPosition(); if( aStartingPoint ) { LAYER_ID layer = m_frame->GetScreen()->m_Active_Layer; // Init the new item attributes aGraphic->SetShape( (STROKE_T) aShape ); aGraphic->SetWidth( m_lineWidth ); aGraphic->SetStart( wxPoint( aStartingPoint->x, aStartingPoint->y ) ); aGraphic->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) ); aGraphic->SetLayer( layer ); if( aShape == S_SEGMENT ) line45 = *aGraphic; // used only for direction 45 mode with lines preview.Add( aGraphic ); m_controls->SetAutoPan( true ); m_controls->CaptureCursor( true ); started = true; } // Main loop: keep receiving events while( OPT_TOOL_EVENT evt = Wait() ) { bool updatePreview = false; // should preview be updated cursorPos = m_controls->GetCursorPosition(); // Enable 45 degrees lines only mode by holding control if( direction45 != evt->Modifier( MD_CTRL ) && started && aShape == S_SEGMENT ) { direction45 = evt->Modifier( MD_CTRL ); if( direction45 ) { preview.Add( &line45 ); make45DegLine( aGraphic, &line45 ); } else { preview.Remove( &line45 ); aGraphic->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) ); } updatePreview = true; } if( evt->IsCancel() || evt->IsActivate() || evt->IsAction( &COMMON_ACTIONS::layerChanged ) ) { preview.Clear(); updatePreview = true; delete aGraphic; aGraphic = NULL; break; } else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) ) { if( !started ) { LAYER_ID layer = m_frame->GetScreen()->m_Active_Layer; if( IsCopperLayer( layer ) ) { DisplayInfoMessage( NULL, _( "Graphic not allowed on Copper layers" ) ); } else { // Init the new item attributes aGraphic->SetShape( (STROKE_T) aShape ); m_lineWidth = getSegmentWidth( layer ); aGraphic->SetWidth( m_lineWidth ); aGraphic->SetStart( wxPoint( cursorPos.x, cursorPos.y ) ); aGraphic->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) ); aGraphic->SetLayer( layer ); if( aShape == S_SEGMENT ) line45 = *aGraphic; // used only for direction 45 mode with lines preview.Add( aGraphic ); m_controls->SetAutoPan( true ); m_controls->CaptureCursor( true ); started = true; } } else { if( aGraphic->GetEnd() == aGraphic->GetStart() || ( evt->IsDblClick( BUT_LEFT ) && aShape == S_SEGMENT ) ) // User has clicked twice in the same spot { // a clear sign that the current drawing is finished if( direction45 ) { // Now we have to add the helper line as well if( m_editModules ) { EDGE_MODULE* l = new EDGE_MODULE( m_board->m_Modules ); // Copy coordinates, layer, etc. *static_cast<DRAWSEGMENT*>( l ) = line45; l->SetEnd( aGraphic->GetStart() ); l->SetLocalCoord(); m_frame->SaveCopyInUndoList( m_board->m_Modules, UR_MODEDIT ); m_board->m_Modules->SetLastEditTime(); m_board->m_Modules->GraphicalItems().PushFront( l ); m_view->Add( l ); l->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } else { DRAWSEGMENT* l = static_cast<DRAWSEGMENT*>( line45.Clone() ); l->SetEnd( aGraphic->GetStart() ); m_frame->SaveCopyInUndoList( l, UR_NEW ); m_board->Add( l ); m_view->Add( l ); l->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } m_frame->OnModify(); } delete aGraphic; aGraphic = NULL; } else { assert( aGraphic->GetLength() > 0 ); assert( aGraphic->GetWidth() > 0 ); m_view->Add( aGraphic ); aGraphic->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } preview.Clear(); break; } } else if( evt->IsMotion() ) { // 45 degree lines if( direction45 && aShape == S_SEGMENT ) make45DegLine( aGraphic, &line45 ); else aGraphic->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) ); updatePreview = true; } else if( evt->IsAction( &COMMON_ACTIONS::incWidth ) ) { m_lineWidth += WIDTH_STEP; aGraphic->SetWidth( m_lineWidth ); updatePreview = true; } else if( evt->IsAction( &COMMON_ACTIONS::decWidth ) ) { if( m_lineWidth > (unsigned) WIDTH_STEP ) { m_lineWidth -= WIDTH_STEP; aGraphic->SetWidth( m_lineWidth ); updatePreview = true; } } if( updatePreview ) preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } m_controls->ShowCursor( false ); m_controls->SetSnapping( false ); m_controls->SetAutoPan( false ); m_controls->CaptureCursor( false ); m_view->Remove( &preview ); return started; }