/** * Function IsSame * test is 2 zones are equivalent: * 2 zones are equivalent if they have same parameters and same outlines * info relative to filling is not take in account * @param aZoneToCompare = zone to compare with "this" */ bool ZONE_CONTAINER::IsSame( const ZONE_CONTAINER& aZoneToCompare ) { // compare basic parameters: if( GetLayer() != aZoneToCompare.GetLayer() ) return false; if( GetNetCode() != aZoneToCompare.GetNetCode() ) return false; if( GetPriority() != aZoneToCompare.GetPriority() ) return false; // Compare zone specific parameters if( GetIsKeepout() != aZoneToCompare.GetIsKeepout() ) return false; if( GetIsKeepout() ) { if( GetDoNotAllowCopperPour() != aZoneToCompare.GetDoNotAllowCopperPour() ) return false; if( GetDoNotAllowVias() != aZoneToCompare.GetDoNotAllowVias() ) return false; if( GetDoNotAllowTracks() != aZoneToCompare.GetDoNotAllowTracks() ) return false; } if( m_ArcToSegmentsCount != aZoneToCompare.GetArcSegmentCount() ) return false; if( m_ZoneClearance != aZoneToCompare.m_ZoneClearance ) return false; if( m_ZoneMinThickness != aZoneToCompare.GetMinThickness() ) return false; if( m_FillMode != aZoneToCompare.GetFillMode() ) return false; if( m_PadConnection != aZoneToCompare.m_PadConnection ) return false; if( m_ThermalReliefGap != aZoneToCompare.m_ThermalReliefGap ) return false; if( m_ThermalReliefCopperBridge != aZoneToCompare.m_ThermalReliefCopperBridge ) return false; // Compare outlines wxASSERT( m_Poly ); // m_Poly == NULL Should never happen wxASSERT( aZoneToCompare.Outline() ); if( Outline()->m_CornersList.GetList() != aZoneToCompare.Outline()->m_CornersList.GetList() ) // Compare vector return false; return true; }
void ZONE_SETTINGS::ExportSetting( ZONE_CONTAINER& aTarget, bool aFullExport ) const { aTarget.SetFillMode( m_FillMode ); aTarget.SetZoneClearance( m_ZoneClearance ); aTarget.SetMinThickness( m_ZoneMinThickness ); aTarget.SetArcSegmentCount( m_ArcToSegmentsCount ); aTarget.SetThermalReliefGap( m_ThermalReliefGap ); aTarget.SetThermalReliefCopperBridge( m_ThermalReliefCopperBridge ); aTarget.SetPadConnection( m_PadConnection ); aTarget.SetCornerSmoothingType( m_cornerSmoothingType ); aTarget.SetCornerRadius( m_cornerRadius ); aTarget.SetIsKeepout( GetIsKeepout() ); aTarget.SetDoNotAllowCopperPour( GetDoNotAllowCopperPour() ); aTarget.SetDoNotAllowVias( GetDoNotAllowVias() ); aTarget.SetDoNotAllowTracks( GetDoNotAllowTracks() ); if( aFullExport ) { aTarget.SetPriority( m_ZonePriority ); aTarget.SetNet( m_NetcodeSelection ); aTarget.SetLayer( m_CurrentZone_Layer ); aTarget.Outline()->SetLayer( m_CurrentZone_Layer ); } // call SetHatch last, because hatch lines will be rebuilt, // using new parameters values aTarget.Outline()->SetHatch( m_Zone_HatchingStyle, Mils2iu( 20 ), true ); }
void DRC::testKeepoutAreas() { // Test keepout areas for vias, tracks and pads inside keepout areas for( int ii = 0; ii < m_pcb->GetAreaCount(); ii++ ) { ZONE_CONTAINER* area = m_pcb->GetArea( ii ); if( !area->GetIsKeepout() ) continue; for( TRACK* segm = m_pcb->m_Track; segm != NULL; segm = segm->Next() ) { if( segm->Type() == PCB_TRACE_T ) { if( ! area->GetDoNotAllowTracks() ) continue; if( segm->GetLayer() != area->GetLayer() ) continue; if( area->Outline()->Distance( segm->GetStart(), segm->GetEnd(), segm->GetWidth() ) == 0 ) { m_currentMarker = fillMarker( segm, NULL, DRCE_TRACK_INSIDE_KEEPOUT, m_currentMarker ); m_pcb->Add( m_currentMarker ); m_mainWindow->GetGalCanvas()->GetView()->Add( m_currentMarker ); m_currentMarker = 0; } } else if( segm->Type() == PCB_VIA_T ) { if( ! area->GetDoNotAllowVias() ) continue; if( ! ((VIA*)segm)->IsOnLayer( area->GetLayer() ) ) continue; if( area->Outline()->Distance( segm->GetPosition() ) < segm->GetWidth()/2 ) { m_currentMarker = fillMarker( segm, NULL, DRCE_VIA_INSIDE_KEEPOUT, m_currentMarker ); m_pcb->Add( m_currentMarker ); m_mainWindow->GetGalCanvas()->GetView()->Add( m_currentMarker ); m_currentMarker = 0; } } } // Test pads: TODO } }
void POINT_EDITOR::removeCorner( EDIT_POINT* aPoint ) { EDA_ITEM* item = m_editPoints->GetParent(); if( item->Type() == PCB_ZONE_AREA_T ) { const SELECTION& selection = m_selectionTool->GetSelection(); PCB_BASE_FRAME* frame = getEditFrame<PCB_BASE_FRAME>(); ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( item ); CPolyLine* outline = zone->Outline(); for( int i = 0; i < outline->GetCornersCount(); ++i ) { if( VECTOR2I( outline->GetPos( i ) ) == aPoint->GetPosition() ) { frame->OnModify(); frame->SaveCopyInUndoList( selection.items, UR_CHANGED ); outline->DeleteCorner( i ); setEditedPoint( NULL ); break; } } } }
/// Redraws the zone outline when moving a corner according to the cursor position void Show_Zone_Corner_Or_Outline_While_Move_Mouse( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, bool aErase ) { PCB_EDIT_FRAME* pcbframe = (PCB_EDIT_FRAME*) aPanel->GetParent(); ZONE_CONTAINER* zone = (ZONE_CONTAINER*) pcbframe->GetCurItem(); if( aErase ) // Undraw edge in old position { zone->Draw( aPanel, aDC, GR_XOR ); } wxPoint pos = pcbframe->GetCrossHairPosition(); if( zone->IsMoving() ) { wxPoint offset; offset = pos - s_CursorLastPosition; zone->Move( offset ); s_CursorLastPosition = pos; } else if( zone->IsDragging() ) { wxPoint offset; offset = pos - s_CursorLastPosition; zone->MoveEdge( offset ); s_CursorLastPosition = pos; } else { zone->Outline()->MoveCorner( zone->GetSelectedCorner(), pos.x, pos.y ); } zone->Draw( aPanel, aDC, GR_XOR ); }
int PCB_EDIT_FRAME::Delete_LastCreatedCorner( wxDC* DC ) { ZONE_CONTAINER* zone = GetBoard()->m_CurrentZoneContour; if( !zone ) return 0; if( !zone->GetNumCorners() ) return 0; zone->DrawWhileCreateOutline( m_canvas, DC, GR_XOR ); if( zone->GetNumCorners() > 2 ) { zone->Outline()->DeleteCorner( zone->GetNumCorners() - 1 ); if( m_canvas->IsMouseCaptured() ) m_canvas->CallMouseCapture( DC, wxDefaultPosition, false ); } else { m_canvas->SetMouseCapture( NULL, NULL ); SetCurItem( NULL ); zone->RemoveAllContours(); zone->ClearFlags(); } return zone->GetNumCorners(); }
bool DRC::doTrackKeepoutDrc( TRACK* aRefSeg ) { // Test keepout areas for vias, tracks and pads inside keepout areas for( int ii = 0; ii < m_pcb->GetAreaCount(); ii++ ) { ZONE_CONTAINER* area = m_pcb->GetArea( ii ); if( !area->GetIsKeepout() ) continue; if( aRefSeg->Type() == PCB_TRACE_T ) { if( ! area->GetDoNotAllowTracks() ) continue; if( aRefSeg->GetLayer() != area->GetLayer() ) continue; if( area->Outline()->Distance( aRefSeg->GetStart(), aRefSeg->GetEnd(), aRefSeg->GetWidth() ) == 0 ) { m_currentMarker = fillMarker( aRefSeg, NULL, DRCE_TRACK_INSIDE_KEEPOUT, m_currentMarker ); return false; } } else if( aRefSeg->Type() == PCB_VIA_T ) { if( ! area->GetDoNotAllowVias() ) continue; if( ! ((VIA*)aRefSeg)->IsOnLayer( area->GetLayer() ) ) continue; if( area->Outline()->Distance( aRefSeg->GetPosition() ) < aRefSeg->GetWidth()/2 ) { m_currentMarker = fillMarker( aRefSeg, NULL, DRCE_VIA_INSIDE_KEEPOUT, m_currentMarker ); return false; } } } return true; }
void PCB_EDIT_FRAME::duplicateZone( wxDC* aDC, ZONE_CONTAINER* aZone ) { ZONE_CONTAINER* newZone = new ZONE_CONTAINER( GetBoard() ); newZone->Copy( aZone ); newZone->UnFill(); ZONE_SETTINGS zoneSettings; zoneSettings << *aZone; bool success; if( aZone->GetIsKeepout() ) success = InvokeKeepoutAreaEditor( this, &zoneSettings ); else if( aZone->IsOnCopperLayer() ) success = InvokeCopperZonesEditor( this, &zoneSettings ); else success = InvokeNonCopperZonesEditor( this, aZone, &zoneSettings ); if( success ) { zoneSettings.ExportSetting( *newZone ); newZone->Outline()->Hatch(); s_AuxiliaryList.ClearListAndDeleteItems(); s_PickedList.ClearListAndDeleteItems(); SaveCopyOfZones( s_PickedList, GetBoard(), newZone->GetNet(), newZone->GetLayer() ); GetBoard()->Add( newZone ); ITEM_PICKER picker( newZone, UR_NEW ); s_PickedList.PushItem( picker ); GetScreen()->SetCurItem( NULL ); // This outline may be deleted when merging outlines // Combine zones if possible GetBoard()->OnAreaPolygonModified( &s_AuxiliaryList, newZone ); // Redraw zones GetBoard()->RedrawAreasOutlines( m_canvas, aDC, GR_OR, newZone->GetLayer() ); GetBoard()->RedrawFilledAreas( m_canvas, aDC, GR_OR, newZone->GetLayer() ); if( GetBoard()->GetAreaIndex( newZone ) >= 0 && GetBoard()->Test_Drc_Areas_Outlines_To_Areas_Outlines( newZone, true ) ) { DisplayError( this, _( "Duplicate Zone: The outline of the duplicated zone fails DRC check!" ) ); } UpdateCopyOfZonesList( s_PickedList, s_AuxiliaryList, GetBoard() ); SaveCopyInUndoList( s_PickedList, UR_UNSPECIFIED ); s_PickedList.ClearItemsList(); OnModify(); } else delete newZone; }
/** * Function Abort_Zone_Move_Corner_Or_Outlines * cancels the Begin_Zone state if at least one EDGE_ZONE has been created. */ void Abort_Zone_Move_Corner_Or_Outlines( EDA_DRAW_PANEL* Panel, wxDC* DC ) { PCB_EDIT_FRAME* pcbframe = (PCB_EDIT_FRAME*) Panel->GetParent(); ZONE_CONTAINER* zone = (ZONE_CONTAINER*) pcbframe->GetCurItem(); if( zone->IsMoving() ) { wxPoint offset; offset = s_CornerInitialPosition - s_CursorLastPosition; zone->Move( offset ); } else if( zone->IsDragging() ) { wxPoint offset; offset = s_CornerInitialPosition - s_CursorLastPosition; zone->MoveEdge( offset ); } else { if( s_CornerIsNew ) { zone->Outline()->DeleteCorner( zone->GetSelectedCorner() ); } else { wxPoint pos = s_CornerInitialPosition; zone->Outline()->MoveCorner( zone->GetSelectedCorner(), pos.x, pos.y ); } } Panel->SetMouseCapture( NULL, NULL ); s_AuxiliaryList.ClearListAndDeleteItems(); s_PickedList. ClearListAndDeleteItems(); Panel->Refresh(); pcbframe->SetCurItem( NULL ); zone->ClearFlags(); s_AddCutoutToCurrentZone = false; s_CurrentZone = NULL; }
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 ); } } }
void POINT_EDITOR::updateItem() const { EDA_ITEM* item = m_editPoints->GetParent(); switch( item->Type() ) { case PCB_LINE_T: case PCB_MODULE_EDGE_T: { DRAWSEGMENT* segment = static_cast<DRAWSEGMENT*>( item ); switch( segment->GetShape() ) { case S_SEGMENT: if( isModified( m_editPoints->Point( SEG_START ) ) ) segment->SetStart( wxPoint( m_editPoints->Point( SEG_START ).GetPosition().x, m_editPoints->Point( SEG_START ).GetPosition().y ) ); else if( isModified( m_editPoints->Point( SEG_END ) ) ) segment->SetEnd( wxPoint( m_editPoints->Point( SEG_END ).GetPosition().x, m_editPoints->Point( SEG_END ).GetPosition().y ) ); break; case S_ARC: { const VECTOR2I& center = m_editPoints->Point( ARC_CENTER ).GetPosition(); const VECTOR2I& start = m_editPoints->Point( ARC_START ).GetPosition(); const VECTOR2I& end = m_editPoints->Point( ARC_END ).GetPosition(); if( center != segment->GetCenter() ) { wxPoint moveVector = wxPoint( center.x, center.y ) - segment->GetCenter(); segment->Move( moveVector ); m_editPoints->Point( ARC_START ).SetPosition( segment->GetArcStart() ); m_editPoints->Point( ARC_END ).SetPosition( segment->GetArcEnd() ); } else { segment->SetArcStart( wxPoint( start.x, start.y ) ); VECTOR2D startLine = start - center; VECTOR2I endLine = end - center; double newAngle = RAD2DECIDEG( endLine.Angle() - startLine.Angle() ); // Adjust the new angle to (counter)clockwise setting bool clockwise = ( segment->GetAngle() > 0 ); if( clockwise && newAngle < 0.0 ) newAngle += 3600.0; else if( !clockwise && newAngle > 0.0 ) newAngle -= 3600.0; segment->SetAngle( newAngle ); } break; } case S_CIRCLE: { const VECTOR2I& center = m_editPoints->Point( CIRC_CENTER ).GetPosition(); const VECTOR2I& end = m_editPoints->Point( CIRC_END ).GetPosition(); if( isModified( m_editPoints->Point( CIRC_CENTER ) ) ) { wxPoint moveVector = wxPoint( center.x, center.y ) - segment->GetCenter(); segment->Move( moveVector ); } else { segment->SetEnd( wxPoint( end.x, end.y ) ); } break; } default: // suppress warnings break; } // Update relative coordinates for module edges if( EDGE_MODULE* edge = dyn_cast<EDGE_MODULE*>( item ) ) edge->SetLocalCoord(); break; } case PCB_ZONE_AREA_T: { ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( item ); zone->ClearFilledPolysList(); CPolyLine* outline = zone->Outline(); for( int i = 0; i < outline->GetCornersCount(); ++i ) { VECTOR2I point = m_editPoints->Point( i ).GetPosition(); outline->SetX( i, point.x ); outline->SetY( i, point.y ); } break; } case PCB_DIMENSION_T: { DIMENSION* dimension = static_cast<DIMENSION*>( item ); // Check which point is currently modified and updated dimension's points respectively if( isModified( m_editPoints->Point( DIM_CROSSBARO ) ) ) { VECTOR2D featureLine( m_editedPoint->GetPosition() - dimension->GetOrigin() ); VECTOR2D crossBar( dimension->GetEnd() - dimension->GetOrigin() ); if( featureLine.Cross( crossBar ) > 0 ) dimension->SetHeight( -featureLine.EuclideanNorm() ); else dimension->SetHeight( featureLine.EuclideanNorm() ); } else if( isModified( m_editPoints->Point( DIM_CROSSBARF ) ) ) { VECTOR2D featureLine( m_editedPoint->GetPosition() - dimension->GetEnd() ); VECTOR2D crossBar( dimension->GetEnd() - dimension->GetOrigin() ); if( featureLine.Cross( crossBar ) > 0 ) dimension->SetHeight( -featureLine.EuclideanNorm() ); else dimension->SetHeight( featureLine.EuclideanNorm() ); } else if( isModified( m_editPoints->Point( DIM_FEATUREGO ) ) ) { dimension->SetOrigin( wxPoint( m_editedPoint->GetPosition().x, m_editedPoint->GetPosition().y ) ); m_editPoints->Point( DIM_CROSSBARO ).SetConstraint( new EC_LINE( m_editPoints->Point( DIM_CROSSBARO ), m_editPoints->Point( DIM_FEATUREGO ) ) ); m_editPoints->Point( DIM_CROSSBARF ).SetConstraint( new EC_LINE( m_editPoints->Point( DIM_CROSSBARF ), m_editPoints->Point( DIM_FEATUREDO ) ) ); } else if( isModified( m_editPoints->Point( DIM_FEATUREDO ) ) ) { dimension->SetEnd( wxPoint( m_editedPoint->GetPosition().x, m_editedPoint->GetPosition().y ) ); m_editPoints->Point( DIM_CROSSBARO ).SetConstraint( new EC_LINE( m_editPoints->Point( DIM_CROSSBARO ), m_editPoints->Point( DIM_FEATUREGO ) ) ); m_editPoints->Point( DIM_CROSSBARF ).SetConstraint( new EC_LINE( m_editPoints->Point( DIM_CROSSBARF ), m_editPoints->Point( DIM_FEATUREDO ) ) ); } break; } default: break; } }
int DRAWING_TOOL::drawZone( bool aKeepout ) { ZONE_CONTAINER* zone = NULL; DRAWSEGMENT line45; DRAWSEGMENT* helperLine = NULL; // we will need more than one helper line // if one day it is possible to draw zones in the footprint editor, // then hereby I'm letting you know that this tool does not handle UR_MODEDIT undo yet assert( !m_editModules ); // 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(); VECTOR2I origin; int numPoints = 0; bool direction45 = false; // 45 degrees only mode // Main loop: keep receiving events while( OPT_TOOL_EVENT evt = Wait() ) { bool updatePreview = false; // should preview be updated VECTOR2I cursorPos = m_controls->GetCursorPosition(); // Enable 45 degrees lines only mode by holding control if( direction45 != ( evt->Modifier( MD_CTRL ) && numPoints > 0 ) ) { direction45 = evt->Modifier( MD_CTRL ); if( direction45 ) { preview.Add( &line45 ); make45DegLine( helperLine, &line45 ); } else { preview.Remove( &line45 ); helperLine->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) ); } updatePreview = true; } if( evt->IsCancel() || evt->IsActivate() ) { if( numPoints > 0 ) // cancel the current zone { delete zone; zone = NULL; m_controls->SetAutoPan( false ); m_controls->CaptureCursor( false ); if( direction45 ) { preview.Remove( &line45 ); direction45 = false; } preview.FreeItems(); updatePreview = true; numPoints = 0; } else // there is no zone currently drawn - just stop the tool break; if( evt->IsActivate() ) // now finish unconditionally break; } else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) ) { // Check if it is double click / closing line (so we have to finish the zone) if( evt->IsDblClick( BUT_LEFT ) || ( numPoints > 0 && cursorPos == origin ) ) { if( numPoints > 2 ) // valid zone consists of more than 2 points { assert( zone->GetNumCorners() > 2 ); // Finish the zone if( direction45 ) zone->AppendCorner( cursorPos == origin ? line45.GetStart() : line45.GetEnd() ); zone->Outline()->CloseLastContour(); zone->Outline()->RemoveNullSegments(); m_board->Add( zone ); m_view->Add( zone ); if( !aKeepout ) static_cast<PCB_EDIT_FRAME*>( m_frame )->Fill_Zone( zone ); zone->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); m_board->GetRatsnest()->Update( zone ); m_frame->OnModify(); m_frame->SaveCopyInUndoList( zone, UR_NEW ); zone = NULL; } else { delete zone; zone = NULL; } numPoints = 0; m_controls->SetAutoPan( false ); m_controls->CaptureCursor( false ); if( direction45 ) { preview.Remove( &line45 ); direction45 = false; } preview.FreeItems(); updatePreview = true; } else { if( numPoints == 0 ) // it's the first click { // Get the current default settings for zones ZONE_SETTINGS zoneInfo = m_frame->GetZoneSettings(); zoneInfo.m_CurrentZone_Layer = m_frame->GetScreen()->m_Active_Layer; m_controls->SetAutoPan( true ); m_controls->CaptureCursor( true ); // Show options dialog ZONE_EDIT_T dialogResult; if( aKeepout ) dialogResult = InvokeKeepoutAreaEditor( m_frame, &zoneInfo ); else { if( IsCopperLayer( zoneInfo.m_CurrentZone_Layer ) ) dialogResult = InvokeCopperZonesEditor( m_frame, &zoneInfo ); else dialogResult = InvokeNonCopperZonesEditor( m_frame, NULL, &zoneInfo ); } if( dialogResult == ZONE_ABORT ) { m_controls->SetAutoPan( false ); m_controls->CaptureCursor( false ); continue; } // Apply the selected settings zone = new ZONE_CONTAINER( m_board ); zoneInfo.ExportSetting( *zone ); m_frame->GetGalCanvas()->SetTopLayer( zoneInfo.m_CurrentZone_Layer ); // Add the first point zone->Outline()->Start( zoneInfo.m_CurrentZone_Layer, cursorPos.x, cursorPos.y, zone->GetHatchStyle() ); origin = cursorPos; // Helper line represents the currently drawn line of the zone polygon helperLine = new DRAWSEGMENT; helperLine->SetShape( S_SEGMENT ); helperLine->SetWidth( 1 ); helperLine->SetLayer( zoneInfo.m_CurrentZone_Layer ); helperLine->SetStart( wxPoint( cursorPos.x, cursorPos.y ) ); helperLine->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) ); line45 = *helperLine; preview.Add( helperLine ); } else { zone->AppendCorner( helperLine->GetEnd() ); helperLine = new DRAWSEGMENT( *helperLine ); helperLine->SetStart( helperLine->GetEnd() ); preview.Add( helperLine ); } ++numPoints; updatePreview = true; } } else if( evt->IsMotion() && numPoints > 0 ) { // 45 degree lines if( direction45 ) make45DegLine( helperLine, &line45 ); else helperLine->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) ); // Show a preview of the item 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 ); m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString ); return 0; }
bool PCB_EDIT_FRAME::End_Zone( wxDC* DC ) { ZONE_CONTAINER* zone = GetBoard()->m_CurrentZoneContour; if( !zone ) return true; // Validate the current outline: if( zone->GetNumCorners() <= 2 ) // An outline must have 3 corners or more { Abort_Zone_Create_Outline( m_canvas, DC ); return true; } // Remove the last corner if is is at the same location as the prevoius corner zone->Outline()->RemoveNullSegments(); // Validate the current edge: int icorner = zone->GetNumCorners() - 1; if( zone->IsOnCopperLayer() ) { if( g_Drc_On && m_drc->Drc( zone, icorner - 1 ) == BAD_DRC ) // we can't validate last edge return false; if( g_Drc_On && m_drc->Drc( zone, icorner ) == BAD_DRC ) // we can't validate the closing edge { DisplayError( this, _( "DRC error: closing this area creates a drc error with an other area" ) ); m_canvas->MoveCursorToCrossHair(); return false; } } zone->ClearFlags(); zone->DrawWhileCreateOutline( m_canvas, DC, GR_XOR ); m_canvas->SetMouseCapture( NULL, NULL ); // Undraw old drawings, because they can have important changes LAYER_NUM layer = zone->GetLayer(); GetBoard()->RedrawAreasOutlines( m_canvas, DC, GR_XOR, layer ); GetBoard()->RedrawFilledAreas( m_canvas, DC, GR_XOR, layer ); // Save initial zones configuration, for undo/redo, before adding new zone s_AuxiliaryList.ClearListAndDeleteItems(); s_PickedList.ClearListAndDeleteItems(); SaveCopyOfZones(s_PickedList, GetBoard(), zone->GetNet(), zone->GetLayer() ); // Put new zone in list if( !s_CurrentZone ) { zone->Outline()->CloseLastContour(); // Close the current corner list GetBoard()->Add( zone ); GetBoard()->m_CurrentZoneContour = NULL; // Add this zone in picked list, as new item ITEM_PICKER picker( zone, UR_NEW ); s_PickedList.PushItem( picker ); } else // Append this outline as a cutout to an existing zone { for( int ii = 0; ii < zone->GetNumCorners(); ii++ ) { s_CurrentZone->AppendCorner( zone->GetCornerPosition( ii ) ); } s_CurrentZone->Outline()->CloseLastContour(); // Close the current corner list zone->RemoveAllContours(); // All corners are copied in s_CurrentZone. Free corner list. zone = s_CurrentZone; } s_AddCutoutToCurrentZone = false; s_CurrentZone = NULL; GetScreen()->SetCurItem( NULL ); // This outline can be deleted when merging outlines // Combine zones if possible : GetBoard()->OnAreaPolygonModified( &s_AuxiliaryList, zone ); // Redraw the real edge zone : GetBoard()->RedrawAreasOutlines( m_canvas, DC, GR_OR, layer ); GetBoard()->RedrawFilledAreas( m_canvas, DC, GR_OR, layer ); int ii = GetBoard()->GetAreaIndex( zone ); // test if zone exists if( ii < 0 ) zone = NULL; // was removed by combining zones int error_count = GetBoard()->Test_Drc_Areas_Outlines_To_Areas_Outlines( zone, true ); if( error_count ) { DisplayError( this, _( "Area: DRC outline error" ) ); } UpdateCopyOfZonesList( s_PickedList, s_AuxiliaryList, GetBoard() ); SaveCopyInUndoList(s_PickedList, UR_UNSPECIFIED); s_PickedList.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items OnModify(); return true; }
int PCB_EDIT_FRAME::Begin_Zone( wxDC* DC ) { ZONE_SETTINGS zoneInfo = GetZoneSettings(); // verify if s_CurrentZone exists (could be deleted since last selection) : int ii; for( ii = 0; ii < GetBoard()->GetAreaCount(); ii++ ) { if( s_CurrentZone == GetBoard()->GetArea( ii ) ) break; } if( ii >= GetBoard()->GetAreaCount() ) // Not found: could be deleted since last selection { s_AddCutoutToCurrentZone = false; s_CurrentZone = NULL; } // If no zone contour in progress, a new zone is being created: if( !GetBoard()->m_CurrentZoneContour ) { if( GetToolId() == ID_PCB_KEEPOUT_AREA_BUTT && getActiveLayer() >= FIRST_NON_COPPER_LAYER ) { DisplayError( this, _( "Error: a keepout area is allowed only on copper layers" ) ); return 0; } else GetBoard()->m_CurrentZoneContour = new ZONE_CONTAINER( GetBoard() ); } ZONE_CONTAINER* zone = GetBoard()->m_CurrentZoneContour; if( zone->GetNumCorners() == 0 ) // Start a new contour: init zone params (net, layer ...) { if( !s_CurrentZone ) // A new outline is created, from scratch { ZONE_EDIT_T edited; // Init zone params to reasonable values zone->SetLayer( getActiveLayer() ); // Prompt user for parameters: m_canvas->SetIgnoreMouseEvents( true ); if( zone->IsOnCopperLayer() ) { // Put a zone on a copper layer if( GetBoard()->GetHighLightNetCode() > 0 ) { zoneInfo.m_NetcodeSelection = GetBoard()->GetHighLightNetCode(); zone->SetNet( zoneInfo.m_NetcodeSelection ); zone->SetNetNameFromNetCode( ); } double tmp = ZONE_THERMAL_RELIEF_GAP_MIL; wxGetApp().GetSettings()->Read( ZONE_THERMAL_RELIEF_GAP_STRING_KEY, &tmp ); zoneInfo.m_ThermalReliefGap = KiROUND( tmp * IU_PER_MILS); tmp = ZONE_THERMAL_RELIEF_COPPER_WIDTH_MIL; wxGetApp().GetSettings()->Read( ZONE_THERMAL_RELIEF_COPPER_WIDTH_STRING_KEY, &tmp ); zoneInfo.m_ThermalReliefCopperBridge = KiROUND( tmp * IU_PER_MILS ); tmp = ZONE_CLEARANCE_MIL; wxGetApp().GetSettings()->Read( ZONE_CLEARANCE_WIDTH_STRING_KEY, &tmp ); zoneInfo.m_ZoneClearance = KiROUND( tmp * IU_PER_MILS ); tmp = ZONE_THICKNESS_MIL; wxGetApp().GetSettings()->Read( ZONE_MIN_THICKNESS_WIDTH_STRING_KEY, &tmp ); zoneInfo.m_ZoneMinThickness = KiROUND( tmp * IU_PER_MILS ); zoneInfo.m_CurrentZone_Layer = zone->GetLayer(); if( GetToolId() == ID_PCB_KEEPOUT_AREA_BUTT ) { zoneInfo.SetIsKeepout( true ); // Netcode and netname are irrelevant, // so ensure they are cleared zone->SetNet( 0 ); zone->SetNetName( wxEmptyString ); edited = InvokeKeepoutAreaEditor( this, &zoneInfo ); } else { zoneInfo.SetIsKeepout( false ); edited = InvokeCopperZonesEditor( this, &zoneInfo ); } } else // Put a zone on a non copper layer (technical layer) { zoneInfo.SetIsKeepout( false ); zoneInfo.m_NetcodeSelection = 0; // No net for non copper zones edited = InvokeNonCopperZonesEditor( this, zone, &zoneInfo ); } m_canvas->MoveCursorToCrossHair(); m_canvas->SetIgnoreMouseEvents( false ); if( edited == ZONE_ABORT ) return 0; // Switch active layer to the selected zone layer setActiveLayer( zoneInfo.m_CurrentZone_Layer ); SetZoneSettings( zoneInfo ); } else { // Start a new contour: init zone params (net and layer) from an existing // zone (add cutout or similar zone) zoneInfo.m_CurrentZone_Layer = s_CurrentZone->GetLayer(); setActiveLayer( s_CurrentZone->GetLayer() ); zoneInfo << *s_CurrentZone; SetZoneSettings( zoneInfo ); } // Show the Net for zones on copper layers if( zoneInfo.m_CurrentZone_Layer < FIRST_NON_COPPER_LAYER && ! zoneInfo.GetIsKeepout() ) { if( s_CurrentZone ) { zoneInfo.m_NetcodeSelection = s_CurrentZone->GetNet(); GetBoard()->SetZoneSettings( zoneInfo ); } if( GetBoard()->IsHighLightNetON() ) { HighLight( DC ); // Remove old highlight selection } GetBoard()->SetHighLightNet( zoneInfo.m_NetcodeSelection ); HighLight( DC ); } if( !s_AddCutoutToCurrentZone ) s_CurrentZone = NULL; // the zone is used only once ("add similar zone" command) } // if first segment if( zone->GetNumCorners() == 0 ) { zone->SetFlags( IS_NEW ); zone->SetTimeStamp( GetNewTimeStamp() ); zoneInfo.ExportSetting( *zone ); zone->Outline()->Start( zoneInfo.m_CurrentZone_Layer, GetCrossHairPosition().x, GetCrossHairPosition().y, zone->GetHatchStyle() ); zone->AppendCorner( GetCrossHairPosition() ); if( g_Drc_On && (m_drc->Drc( zone, 0 ) == BAD_DRC) && zone->IsOnCopperLayer() ) { zone->ClearFlags(); zone->RemoveAllContours(); // use the form of SetCurItem() which does not write to the msg panel, // SCREEN::SetCurItem(), so the DRC error remains on screen. // PCB_EDIT_FRAME::SetCurItem() calls DisplayInfo(). GetScreen()->SetCurItem( NULL ); DisplayError( this, _( "DRC error: this start point is inside or too close an other area" ) ); return 0; } SetCurItem( zone ); m_canvas->SetMouseCapture( Show_New_Edge_While_Move_Mouse, Abort_Zone_Create_Outline ); } else // edge in progress: { ii = zone->GetNumCorners() - 1; // edge in progress : the current corner coordinate was set // by Show_New_Edge_While_Move_Mouse if( zone->GetCornerPosition( ii - 1 ) != zone->GetCornerPosition( ii ) ) { if( !g_Drc_On || !zone->IsOnCopperLayer() || ( m_drc->Drc( zone, ii - 1 ) == OK_DRC ) ) { // Ok, we can add a new corner if( m_canvas->IsMouseCaptured() ) m_canvas->CallMouseCapture( DC, wxPoint(0,0), false ); zone->AppendCorner( GetCrossHairPosition() ); SetCurItem( zone ); // calls DisplayInfo(). if( m_canvas->IsMouseCaptured() ) m_canvas->CallMouseCapture( DC, wxPoint(0,0), false ); } } } return zone->GetNumCorners(); }