diff --git a/CMakeLists.txt b/CMakeLists.txt index 092cae2587..161235edd6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -477,6 +477,8 @@ if( KICAD_SKIP_BOOST ) message( FATAL_ERROR "Boost 1.54+ libraries are required." ) endif() + add_custom_target( boost ) # it is required to meet some further dependencies + message( WARNING " WARNING: You decided to skip building boost library. KiCad developers strongly advise you to build the bundled boost library, as it is known to work with KiCad. diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 176bffeb7c..07da514a8e 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -29,7 +29,7 @@ add_custom_target( set( GAL_SRCS # Common part - drawpanel_gal.cpp + draw_panel_gal.cpp painter.cpp worksheet_viewitem.cpp gal/graphics_abstraction_layer.cpp diff --git a/common/base_screen.cpp b/common/base_screen.cpp index a441a418d5..01a798df4a 100644 --- a/common/base_screen.cpp +++ b/common/base_screen.cpp @@ -175,13 +175,6 @@ void BASE_SCREEN::SetGridList( GRIDS& gridlist ) } -void BASE_SCREEN::GetGrids( GRIDS& aList ) -{ - for( size_t i = 0; i < m_grids.size(); i++ ) - aList.push_back( m_grids[ i ] ); -} - - int BASE_SCREEN::SetGrid( const wxRealPoint& size ) { wxASSERT( !m_grids.empty() ); diff --git a/common/class_marker_base.cpp b/common/class_marker_base.cpp index b8aa30a058..6e54012fd4 100644 --- a/common/class_marker_base.cpp +++ b/common/class_marker_base.cpp @@ -19,8 +19,8 @@ // Default marquer shape: -#define M_SHAPE_SCALE 6 // default scaling factor for MarkerShapeCorners coordinates -#define CORNERS_COUNT 8 +const int M_SHAPE_SCALE = 6; // default scaling factor for MarkerShapeCorners coordinates +const int CORNERS_COUNT = 8; /* corners of the default shape * actual coordinates are these values * .m_ScalingFactor */ @@ -46,10 +46,10 @@ void MARKER_BASE::init() m_Color = RED; wxPoint start = MarkerShapeCorners[0]; wxPoint end = MarkerShapeCorners[0]; + for( unsigned ii = 0; ii < CORNERS_COUNT; ii++ ) { wxPoint corner = MarkerShapeCorners[ii]; - m_Corners.push_back( corner ); start.x = std::min( start.x, corner.x); start.y = std::min( start.y, corner.y); end.x = std::max( end.x, corner.x); @@ -64,7 +64,6 @@ void MARKER_BASE::init() MARKER_BASE::MARKER_BASE( const MARKER_BASE& aMarker ) { m_Pos = aMarker.m_Pos; - m_Corners = aMarker.m_Corners; m_MarkerType = aMarker.m_MarkerType; m_Color = aMarker.m_Color; m_ShapeBoundingBox = aMarker.m_ShapeBoundingBox; @@ -154,9 +153,9 @@ void MARKER_BASE::DrawMarker( EDA_DRAW_PANEL* aPanel, wxDC* aDC, GR_DRAWMODE aDr GRSetDrawMode( aDC, aDrawMode ); - for( unsigned ii = 0; ii < m_Corners.size(); ii++ ) + for( unsigned ii = 0; ii < CORNERS_COUNT; ii++ ) { - corners[ii] = m_Corners[ii]; + corners[ii] = MarkerShapeCorners[ii]; corners[ii].x *= m_ScalingFactor; corners[ii].y *= m_ScalingFactor; corners[ii] += m_Pos + aOffset; diff --git a/common/draw_frame.cpp b/common/draw_frame.cpp index a79503edd3..976aa1e60b 100644 --- a/common/draw_frame.cpp +++ b/common/draw_frame.cpp @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include #include @@ -48,6 +48,7 @@ #include #include +#include #include /** @@ -395,7 +396,7 @@ void EDA_DRAW_FRAME::OnSelectGrid( wxCommandEvent& event ) if( IsGalCanvasActive() ) { GetGalCanvas()->GetGAL()->SetGridSize( VECTOR2D( screen->GetGrid().m_Size.x, - screen->GetGrid().m_Size.y ) ); + screen->GetGrid().m_Size.y ) ); GetGalCanvas()->GetView()->MarkTargetDirty( KIGFX::TARGET_NONCACHED ); } @@ -532,6 +533,38 @@ wxPoint EDA_DRAW_FRAME::GetGridPosition( const wxPoint& aPosition ) const } +void EDA_DRAW_FRAME::SetNextGrid() +{ + if( m_gridSelectBox ) + { + m_gridSelectBox->SetSelection( ( m_gridSelectBox->GetSelection() + 1 ) % + m_gridSelectBox->GetCount() ); + + wxCommandEvent cmd( wxEVT_COMMAND_COMBOBOX_SELECTED ); + // cmd.SetEventObject( this ); + OnSelectGrid( cmd ); + } +} + + +void EDA_DRAW_FRAME::SetPrevGrid() +{ + if( m_gridSelectBox ) + { + int cnt = m_gridSelectBox->GetSelection(); + + if( --cnt < 0 ) + cnt = m_gridSelectBox->GetCount() - 1; + + m_gridSelectBox->SetSelection( cnt ); + + wxCommandEvent cmd( wxEVT_COMMAND_COMBOBOX_SELECTED ); + // cmd.SetEventObject( this ); + OnSelectGrid( cmd ); + } +} + + int EDA_DRAW_FRAME::BlockCommand( int key ) { return 0; @@ -1007,9 +1040,17 @@ void EDA_DRAW_FRAME::UseGalCanvas( bool aEnable ) wxPoint EDA_DRAW_FRAME::GetCrossHairPosition( bool aInvertY ) const { // subject to change, borrow from old BASE_SCREEN for now. + if( IsGalCanvasActive() ) + { + VECTOR2I cursor = GetGalCanvas()->GetViewControls()->GetCursorPosition(); - BASE_SCREEN* screen = GetScreen(); // virtual call - return screen->getCrossHairPosition( aInvertY ); + return wxPoint( cursor.x, cursor.y ); + } + else + { + BASE_SCREEN* screen = GetScreen(); // virtual call + return screen->getCrossHairPosition( aInvertY ); + } } diff --git a/common/draw_panel.cpp b/common/draw_panel.cpp index 9ac1875616..dedd4f6059 100644 --- a/common/draw_panel.cpp +++ b/common/draw_panel.cpp @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include diff --git a/common/drawpanel_gal.cpp b/common/draw_panel_gal.cpp similarity index 87% rename from common/drawpanel_gal.cpp rename to common/draw_panel_gal.cpp index e0d9dcdf89..0ec6a1130b 100644 --- a/common/drawpanel_gal.cpp +++ b/common/draw_panel_gal.cpp @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include #include @@ -45,8 +45,6 @@ #include #endif /* __WXDEBUG__ */ -#define METRIC_UNIT_LENGTH (1e9) - EDA_DRAW_PANEL_GAL::EDA_DRAW_PANEL_GAL( wxWindow* aParentWindow, wxWindowID aWindowId, const wxPoint& aPosition, const wxSize& aSize, GalType aGalType ) : @@ -61,11 +59,6 @@ EDA_DRAW_PANEL_GAL::EDA_DRAW_PANEL_GAL( wxWindow* aParentWindow, wxWindowID aWin SwitchBackend( aGalType ); SetBackgroundStyle( wxBG_STYLE_CUSTOM ); - // Initial display settings - m_gal->SetLookAtPoint( VECTOR2D( 0, 0 ) ); - m_gal->SetZoomFactor( 1.0 ); - m_gal->ComputeWorldScreenMatrix(); - m_painter = new KIGFX::PCB_PAINTER( m_gal ); m_view = new KIGFX::VIEW( true ); @@ -90,8 +83,7 @@ EDA_DRAW_PANEL_GAL::EDA_DRAW_PANEL_GAL( wxWindow* aParentWindow, wxWindowID aWin Connect( wxEVT_MIDDLE_DCLICK, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this ); Connect( wxEVT_MOUSEWHEEL, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this ); Connect( wxEVT_CHAR_HOOK, wxEventHandler( EDA_DRAW_PANEL_GAL::skipEvent ) ); - Connect( wxEVT_KEY_UP, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this ); - Connect( wxEVT_KEY_DOWN, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this ); + Connect( wxEVT_CHAR, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this ); Connect( wxEVT_ENTER_WINDOW, wxEventHandler( EDA_DRAW_PANEL_GAL::onEnter ), NULL, this ); Connect( KIGFX::WX_VIEW_CONTROLS::EVT_REFRESH_MOUSE, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this ); @@ -131,17 +123,22 @@ void EDA_DRAW_PANEL_GAL::onPaint( wxPaintEvent& WXUNUSED( aEvent ) ) { m_drawing = true; + m_view->UpdateItems(); m_gal->BeginDrawing(); - m_gal->SetBackgroundColor( KIGFX::COLOR4D( 0.0, 0.0, 0.0, 1.0 ) ); m_gal->ClearScreen(); - m_view->ClearTargets(); - // Grid has to be redrawn only when the NONCACHED target is redrawn - if( m_view->IsTargetDirty( KIGFX::TARGET_NONCACHED ) ) - m_gal->DrawGrid(); - m_view->Redraw(); - m_gal->DrawCursor( m_viewControls->GetCursorPosition() ); + if( m_view->IsDirty() ) + { + m_view->ClearTargets(); + // Grid has to be redrawn only when the NONCACHED target is redrawn + if( m_view->IsTargetDirty( KIGFX::TARGET_NONCACHED ) ) + m_gal->DrawGrid(); + + m_view->Redraw(); + } + + m_gal->DrawCursor( m_viewControls->GetCursorPosition() ); m_gal->EndDrawing(); m_drawing = false; @@ -196,14 +193,14 @@ void EDA_DRAW_PANEL_GAL::StopDrawing() void EDA_DRAW_PANEL_GAL::SwitchBackend( GalType aGalType ) { - // Protect from refreshing during backend switch - m_pendingRefresh = true; - m_refreshTimer.Stop(); - // Do not do anything if the currently used GAL is correct if( aGalType == m_currentGal && m_gal != NULL ) return; + // Prevent refreshing canvas during backend switch + m_pendingRefresh = true; + m_refreshTimer.Stop(); + delete m_gal; switch( aGalType ) @@ -220,21 +217,15 @@ void EDA_DRAW_PANEL_GAL::SwitchBackend( GalType aGalType ) return; } - m_gal->SetWorldUnitLength( 1.0 / METRIC_UNIT_LENGTH * 2.54 ); // 1 inch in nanometers - m_gal->SetScreenDPI( 106 ); // Display resolution setting - m_gal->ComputeWorldScreenMatrix(); - wxSize size = GetClientSize(); m_gal->ResizeScreen( size.GetX(), size.GetY() ); + m_gal->SetBackgroundColor( KIGFX::COLOR4D( 0.0, 0.0, 0.0, 1.0 ) ); if( m_painter ) m_painter->SetGAL( m_gal ); if( m_view ) - { m_view->SetGAL( m_gal ); - m_view->RecacheAllItems( true ); - } m_currentGal = aGalType; m_pendingRefresh = false; diff --git a/common/gal/cairo/cairo_gal.cpp b/common/gal/cairo/cairo_gal.cpp index 4b3d0bf6ff..13055c7aed 100644 --- a/common/gal/cairo/cairo_gal.cpp +++ b/common/gal/cairo/cairo_gal.cpp @@ -35,9 +35,6 @@ using namespace KIGFX; -///> Opacity of a single layer -const float LAYER_ALPHA = 0.8; - CAIRO_GAL::CAIRO_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener, wxEvtHandler* aPaintListener, const wxString& aName ) : wxWindow( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxEXPAND, aName ) @@ -73,14 +70,16 @@ CAIRO_GAL::CAIRO_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener, #endif SetSize( aParent->GetSize() ); - screenSize = VECTOR2D( aParent->GetSize() ); - initCursor( 20 ); + screenSize = VECTOR2I( aParent->GetSize() ); + initCursor(); // Grid color settings are different in Cairo and OpenGL SetGridColor( COLOR4D( 0.1, 0.1, 0.1, 0.8 ) ); // Allocate memory for pixel storage allocateBitmaps(); + + initSurface(); } @@ -139,7 +138,7 @@ void CAIRO_GAL::EndDrawing() *wxOutputPtr++ = value & 0xff; // Blue pixel } - wxImage img( (int) screenSize.x, (int) screenSize.y, (unsigned char*) wxOutput, true ); + wxImage img( screenSize.x, screenSize.y, (unsigned char*) wxOutput, true ); wxBitmap bmp( img ); wxClientDC client_dc( this ); wxBufferedDC dc; @@ -284,7 +283,7 @@ void CAIRO_GAL::DrawCurve( const VECTOR2D& aStartPoint, const VECTOR2D& aControl void CAIRO_GAL::ResizeScreen( int aWidth, int aHeight ) { - screenSize = VECTOR2D( aWidth, aHeight ); + screenSize = VECTOR2I( aWidth, aHeight ); // Recreate the bitmaps deleteBitmaps(); @@ -431,7 +430,7 @@ void CAIRO_GAL::SetLayerDepth( double aLayerDepth ) } -void CAIRO_GAL::Transform( MATRIX3x3D aTransformation ) +void CAIRO_GAL::Transform( const MATRIX3x3D& aTransformation ) { cairo_matrix_t cairoTransformation; @@ -885,11 +884,10 @@ void CAIRO_GAL::skipMouseEvent( wxMouseEvent& aEvent ) } -void CAIRO_GAL::initCursor( int aCursorSize ) +void CAIRO_GAL::initCursor() { - cursorPixels = new wxBitmap( aCursorSize, aCursorSize ); - cursorPixelsSaved = new wxBitmap( aCursorSize, aCursorSize ); - cursorSize = aCursorSize; + cursorPixels = new wxBitmap( cursorSize, cursorSize ); + cursorPixelsSaved = new wxBitmap( cursorSize, cursorSize ); wxMemoryDC cursorShape( *cursorPixels ); @@ -900,8 +898,8 @@ void CAIRO_GAL::initCursor( int aCursorSize ) cursorShape.SetPen( pen ); cursorShape.Clear(); - cursorShape.DrawLine( 0, aCursorSize / 2, aCursorSize, aCursorSize / 2 ); - cursorShape.DrawLine( aCursorSize / 2, 0, aCursorSize / 2, aCursorSize ); + cursorShape.DrawLine( 0, cursorSize / 2, cursorSize, cursorSize / 2 ); + cursorShape.DrawLine( cursorSize / 2, 0, cursorSize / 2, cursorSize ); } @@ -925,14 +923,15 @@ void CAIRO_GAL::blitCursor( wxBufferedDC& clientDC ) } // Store pixels that are going to be overpainted - cursorSave.Blit( 0, 0, cursorSize, cursorSize, &clientDC, cursorPosition.x, cursorPosition.y ); + VECTOR2D cursorScreen = ToScreen( cursorPosition ) - cursorSize / 2; + cursorSave.Blit( 0, 0, cursorSize, cursorSize, &clientDC, cursorScreen.x, cursorScreen.y ); // Draw the cursor - clientDC.Blit( cursorPosition.x, cursorPosition.y, cursorSize, cursorSize, + clientDC.Blit( cursorScreen.x, cursorScreen.y, cursorSize, cursorSize, &cursorShape, 0, 0, wxOR ); - savedCursorPosition.x = (wxCoord) cursorPosition.x; - savedCursorPosition.y = (wxCoord) cursorPosition.y; + savedCursorPosition.x = (wxCoord) cursorScreen.x; + savedCursorPosition.y = (wxCoord) cursorScreen.y; } @@ -958,7 +957,8 @@ void CAIRO_GAL::deleteBitmaps() void CAIRO_GAL::initSurface() { - wxASSERT( !isInitialized ); + if( isInitialized ) + return; // Create the Cairo surface surface = cairo_image_surface_create_for_data( (unsigned char*) bitmapBuffer, GAL_FORMAT, diff --git a/common/gal/graphics_abstraction_layer.cpp b/common/gal/graphics_abstraction_layer.cpp index 6fa929b062..724d14ac9e 100644 --- a/common/gal/graphics_abstraction_layer.cpp +++ b/common/gal/graphics_abstraction_layer.cpp @@ -39,7 +39,10 @@ GAL::GAL() : SetIsStroke( true ); SetFillColor( COLOR4D( 0.0, 0.0, 0.0, 0.0 ) ); SetStrokeColor( COLOR4D( 1.0, 1.0, 1.0, 1.0 ) ); + SetLookAtPoint( VECTOR2D( 0, 0 ) ); SetZoomFactor( 1.0 ); + SetWorldUnitLength( 1.0 / METRIC_UNIT_LENGTH * 2.54 ); // 1 inch in nanometers + SetScreenDPI( 106 ); // Display resolution setting SetDepthRange( VECTOR2D( GAL::MIN_DEPTH, GAL::MAX_DEPTH ) ); SetFlip( false, false ); SetLineWidth( 1.0 ); @@ -85,7 +88,7 @@ void GAL::ComputeWorldScreenMatrix() MATRIX3x3D translation; translation.SetIdentity(); - translation.SetTranslation( 0.5 * screenSize ); + translation.SetTranslation( 0.5 * VECTOR2D( screenSize ) ); MATRIX3x3D scale; scale.SetIdentity(); @@ -112,23 +115,23 @@ void GAL::DrawGrid() SetTarget( TARGET_NONCACHED ); // Draw the origin marker - double origSize = static_cast( gridOriginMarkerSize ) / worldScale; + double originSize = gridOriginMarkerSize / worldScale; SetLayerDepth( GAL::GRID_DEPTH ); SetIsFill( false ); SetIsStroke( true ); SetStrokeColor( COLOR4D( 1.0, 1.0, 1.0, 1.0 ) ); SetLineWidth( gridLineWidth / worldScale ); - DrawLine( gridOrigin + VECTOR2D( -origSize, -origSize ), - gridOrigin + VECTOR2D( origSize, origSize ) ); - DrawLine( gridOrigin + VECTOR2D( -origSize, origSize ), - gridOrigin + VECTOR2D( origSize, -origSize ) ); - DrawCircle( gridOrigin, origSize * 0.7 ); + DrawLine( gridOrigin + VECTOR2D( -originSize, -originSize ), + gridOrigin + VECTOR2D( originSize, originSize ) ); + DrawLine( gridOrigin + VECTOR2D( -originSize, originSize ), + gridOrigin + VECTOR2D( originSize, -originSize ) ); + DrawCircle( gridOrigin, originSize * 0.7 ); // Draw the grid // For the drawing the start points, end points and increments have // to be calculated in world coordinates VECTOR2D worldStartPoint = screenWorldMatrix * VECTOR2D( 0.0, 0.0 ); - VECTOR2D worldEndPoint = screenWorldMatrix * screenSize; + VECTOR2D worldEndPoint = screenWorldMatrix * VECTOR2D( screenSize ); int gridScreenSizeDense = round( gridSize.x * worldScale ); int gridScreenSizeCoarse = round( gridSize.x * static_cast( gridTick ) * worldScale ); @@ -232,12 +235,12 @@ void GAL::DrawGrid() } -VECTOR2D GAL::GetGridPoint( VECTOR2D aPoint ) const +VECTOR2D GAL::GetGridPoint( const VECTOR2D& aPoint ) const { - VECTOR2D pointWorld = ToWorld( aPoint ); + VECTOR2D gridPoint; - pointWorld.x = round( pointWorld.x / gridSize.x ) * gridSize.x; - pointWorld.y = round( pointWorld.y / gridSize.y ) * gridSize.y; + gridPoint.x = round( aPoint.x / gridSize.x ) * gridSize.x; + gridPoint.y = round( aPoint.y / gridSize.y ) * gridSize.y; - return ToScreen( pointWorld ); + return gridPoint; } diff --git a/common/gal/opengl/opengl_compositor.cpp b/common/gal/opengl/opengl_compositor.cpp index af7b52ba5b..3a6721e5c9 100644 --- a/common/gal/opengl/opengl_compositor.cpp +++ b/common/gal/opengl/opengl_compositor.cpp @@ -17,7 +17,7 @@ * 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:O//www.gnu.org website for the version 2 license, + * 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 */ diff --git a/common/gal/opengl/opengl_gal.cpp b/common/gal/opengl/opengl_gal.cpp index 8e603d27fb..5bd59303a2 100644 --- a/common/gal/opengl/opengl_gal.cpp +++ b/common/gal/opengl/opengl_gal.cpp @@ -86,8 +86,7 @@ OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener, #endif SetSize( aParent->GetSize() ); - screenSize = VECTOR2D( aParent->GetSize() ); - initCursor( 80 ); + screenSize = VECTOR2I( aParent->GetSize() ); // Grid color settings are different in Cairo and OpenGL SetGridColor( COLOR4D( 0.8, 0.8, 0.8, 0.1 ) ); @@ -103,6 +102,8 @@ OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener, } gluTessProperty( tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE ); + + currentManager = &nonCachedManager; } @@ -250,6 +251,8 @@ void OPENGL_GAL::DrawLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoin const VECTOR2D startEndVector = aEndPoint - aStartPoint; double lineAngle = startEndVector.Angle(); + currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); + drawLineQuad( aStartPoint, aEndPoint ); // Line caps @@ -467,10 +470,15 @@ void OPENGL_GAL::DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEn void OPENGL_GAL::DrawPolyline( std::deque& aPointList ) { + if( aPointList.empty() ) + return; + + currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); + std::deque::const_iterator it = aPointList.begin(); // Start from the second point - for( it++; it != aPointList.end(); it++ ) + for( ++it; it != aPointList.end(); ++it ) { const VECTOR2D startEndVector = ( *it - *( it - 1 ) ); double lineAngle = startEndVector.Angle(); @@ -554,7 +562,7 @@ void OPENGL_GAL::DrawCurve( const VECTOR2D& aStartPoint, const VECTOR2D& aContro void OPENGL_GAL::ResizeScreen( int aWidth, int aHeight ) { - screenSize = VECTOR2D( aWidth, aHeight ); + screenSize = VECTOR2I( aWidth, aHeight ); // Resize framebuffers compositor.Resize( aWidth, aHeight ); @@ -589,16 +597,7 @@ void OPENGL_GAL::ClearScreen() } -void OPENGL_GAL::SetStrokeColor( const COLOR4D& aColor ) -{ - strokeColor = aColor; - - // This is the default drawing color - currentManager->Color( aColor.r, aColor.g, aColor.b, aColor.a ); -} - - -void OPENGL_GAL::Transform( MATRIX3x3D aTransformation ) +void OPENGL_GAL::Transform( const MATRIX3x3D& aTransformation ) { GLdouble matrixData[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; @@ -767,8 +766,8 @@ void OPENGL_GAL::DrawCursor( const VECTOR2D& aCursorPosition ) { // Now we should only store the position of the mouse cursor // The real drawing routines are in blitCursor() - cursorPosition = VECTOR2D( aCursorPosition.x, - screenSize.y - aCursorPosition.y ); // invert Y axis + VECTOR2D screenCursor = worldScreenMatrix * aCursorPosition; + cursorPosition = screenWorldMatrix * VECTOR2D( screenCursor.x, screenSize.y - screenCursor.y ); } @@ -778,13 +777,9 @@ void OPENGL_GAL::drawGridLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEnd // We do not need a very precise comparison here (the lineWidth is set by GAL::DrawGrid()) if( fabs( lineWidth - 2.0 * gridLineWidth / worldScale ) < 0.1 ) - { glLineWidth( 1.0 ); - } else - { glLineWidth( 2.0 ); - } glColor4d( gridColor.r, gridColor.g, gridColor.b, gridColor.a ); @@ -798,8 +793,23 @@ void OPENGL_GAL::drawGridLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEnd } -inline void OPENGL_GAL::drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ) +void OPENGL_GAL::drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ) { + /* Helper drawing: ____--- v3 ^ + * ____---- ... \ \ + * ____---- ... \ end \ + * v1 ____---- ... ____---- \ width + * ---- ...___---- \ \ + * \ ___...-- \ v + * \ ____----... ____---- v2 + * ---- ... ____---- + * start \ ... ____---- + * \... ____---- + * ---- + * v0 + * dots mark triangles' hypotenuses + */ + VECTOR2D startEndVector = aEndPoint - aStartPoint; double lineLength = startEndVector.EuclideanNorm(); double scale = 0.5 * lineWidth / lineLength; @@ -857,8 +867,8 @@ void OPENGL_GAL::drawFilledSemiCircle( const VECTOR2D& aCenterPoint, double aRad /* Draw a triangle that contains the semicircle, then shade it to leave only * the semicircle. Parameters given to setShader are indices of the triangle's vertices - * (if you want to understand more, check the vertex shader source [shader.vert]). - * Shader uses this coordinates to determine if fragments are inside the semicircle or not. + * (if you want to understand more, check the vertex shader source [shader.vert]). + * Shader uses these coordinates to determine if fragments are inside the semicircle or not. * v2 * /\ * /__\ @@ -888,9 +898,9 @@ void OPENGL_GAL::drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRa /* Draw a triangle that contains the semicircle, then shade it to leave only * the semicircle. Parameters given to setShader are indices of the triangle's vertices - * (if you want to understand more, check the vertex shader source [shader.vert]), the - * radius and the line width. Shader uses this coordinates to determine if fragments are - * inside the semicircle or not. + * (if you want to understand more, check the vertex shader source [shader.vert]), the + * radius and the line width. Shader uses these coordinates to determine if fragments are + * inside the semicircle or not. * v2 * /\ * /__\ @@ -968,12 +978,6 @@ void OPENGL_GAL::initGlew() } -void OPENGL_GAL::initCursor( int aCursorSize ) -{ - cursorSize = aCursorSize; -} - - void OPENGL_GAL::blitCursor() { if( !isCursorEnabled ) @@ -981,11 +985,9 @@ void OPENGL_GAL::blitCursor() compositor.SetBuffer( OPENGL_COMPOSITOR::DIRECT_RENDERING ); - VECTOR2D cursorBegin = ToWorld( cursorPosition - - VECTOR2D( cursorSize / 2, cursorSize / 2 ) ); - VECTOR2D cursorEnd = ToWorld( cursorPosition + - VECTOR2D( cursorSize / 2, cursorSize / 2 ) ); - VECTOR2D cursorCenter = ( cursorBegin + cursorEnd ) / 2.0; + VECTOR2D cursorBegin = cursorPosition - cursorSize / ( 2 * worldScale ); + VECTOR2D cursorEnd = cursorPosition + cursorSize / ( 2 * worldScale ); + VECTOR2D cursorCenter = ( cursorBegin + cursorEnd ) / 2; glDisable( GL_TEXTURE_2D ); glLineWidth( 1.0 ); diff --git a/common/geometry/hetriang.cpp b/common/geometry/hetriang.cpp index eb5e59ecf7..2172413966 100644 --- a/common/geometry/hetriang.cpp +++ b/common/geometry/hetriang.cpp @@ -48,685 +48,681 @@ #include #include - using namespace hed; -using namespace std; - #ifdef TTL_USE_NODE_ID - int Node::id_count = 0; + int NODE::id_count = 0; #endif //#define DEBUG_HE #ifdef DEBUG_HE #include - static void errorAndExit(char* message) { - cout << "\n!!! ERROR: "<< message << " !!!\n" << endl; exit(-1); - } +static void errorAndExit( char* aMessage ) +{ + cout << "\n!!! ERROR: "<< aMessage << " !!!\n" << endl; + exit( -1 ); +} #endif -//-------------------------------------------------------------------------------------------------- -static EdgePtr getLeadingEdgeInTriangle(const EdgePtr& e) { - EdgePtr edge = e; - - // Code: 3EF (assumes triangle) - if (!edge->isLeadingEdge()) { - edge = edge->getNextEdgeInFace(); - if (!edge->isLeadingEdge()) - edge = edge->getNextEdgeInFace(); - } - - if (!edge->isLeadingEdge()) { - return EdgePtr(); - } - - return edge; -} +static EDGE_PTR getLeadingEdgeInTriangle( const EDGE_PTR& aEdge ) +{ + EDGE_PTR edge = aEdge; + // Code: 3EF (assumes triangle) + if( !edge->IsLeadingEdge() ) + { + edge = edge->GetNextEdgeInFace(); -//-------------------------------------------------------------------------------------------------- -static void getLimits(NodesContainer::iterator first, - NodesContainer::iterator last, - int& xmin, int& ymin, - int& xmax, int& ymax) { - - xmin = ymin = std::numeric_limits::min(); - xmax = ymax = std::numeric_limits::max(); - - NodesContainer::iterator it; - for (it = first; it != last; ++it) { - xmin = min(xmin, (*it)->GetX()); - ymin = min(ymin, (*it)->GetY()); - xmax = max(xmax, (*it)->GetX()); - ymax = max(ymax, (*it)->GetY()); - } -} - - -//-------------------------------------------------------------------------------------------------- -EdgePtr Triangulation::initTwoEnclosingTriangles(NodesContainer::iterator first, - NodesContainer::iterator last) { - - int xmin, ymin, xmax, ymax; - getLimits(first, last, xmin, ymin, xmax, ymax); - - // Add 10% of range: - double fac = 10.0; - double dx = (xmax-xmin)/fac; - double dy = (ymax-ymin)/fac; - - NodePtr n1 = boost::make_shared(xmin-dx, ymin-dy); - NodePtr n2 = boost::make_shared(xmax+dx, ymin-dy); - NodePtr n3 = boost::make_shared(xmax+dx, ymax+dy); - NodePtr n4 = boost::make_shared(xmin-dx, ymax+dy); - - // diagonal - EdgePtr e1d = boost::make_shared(); - EdgePtr e2d = boost::make_shared(); - - // lower triangle - EdgePtr e11 = boost::make_shared(); - EdgePtr e12 = boost::make_shared(); - - // upper triangle - EdgePtr e21 = boost::make_shared(); - EdgePtr e22 = boost::make_shared(); - - // lower triangle - e1d->setSourceNode(n3); - e1d->setNextEdgeInFace(e11); - e1d->setTwinEdge(e2d); - addLeadingEdge(e1d); - - e11->setSourceNode(n1); - e11->setNextEdgeInFace(e12); - - e12->setSourceNode(n2); - e12->setNextEdgeInFace(e1d); - - // upper triangle - e2d->setSourceNode(n1); - e2d->setNextEdgeInFace(e21); - e2d->setTwinEdge(e1d); - addLeadingEdge(e2d); - - e21->setSourceNode(n3); - e21->setNextEdgeInFace(e22); - - e22->setSourceNode(n4); - e22->setNextEdgeInFace(e2d); - - return e11; -} - - -//-------------------------------------------------------------------------------------------------- -Triangulation::Triangulation() { - helper = new ttl::TriangulationHelper( *this ); -} - - -//-------------------------------------------------------------------------------------------------- -Triangulation::Triangulation(const Triangulation& tr) { - std::cout << "Triangulation: Copy constructor not present - EXIT."; - exit(-1); -} - - -//-------------------------------------------------------------------------------------------------- -Triangulation::~Triangulation() { - cleanAll(); - delete helper; -} - - -//-------------------------------------------------------------------------------------------------- -void Triangulation::createDelaunay(NodesContainer::iterator first, - NodesContainer::iterator last) { - - cleanAll(); - - EdgePtr bedge = initTwoEnclosingTriangles(first, last); - Dart dc(bedge); - - Dart d_iter = dc; - - NodesContainer::iterator it; - for (it = first; it != last; ++it) { - helper->insertNode(d_iter, *it); - } - - // In general (e.g. for the triangle based data structure), the initial dart - // may have been changed. - // It is the users responsibility to get a valid boundary dart here. - // The half-edge data structure preserves the initial dart. - // (A dart at the boundary can also be found by trying to locate a - // triangle "outside" the triangulation.) - - // Assumes rectangular domain - helper->removeRectangularBoundary(dc); -} - - -//-------------------------------------------------------------------------------------------------- -void Triangulation::removeTriangle(EdgePtr& edge) { - - EdgePtr e1 = getLeadingEdgeInTriangle(edge); - -#ifdef DEBUG_HE - if (!e1) - errorAndExit("Triangulation::removeTriangle: could not find leading edge"); -#endif - - removeLeadingEdgeFromList(e1); - // cout << "No leading edges = " << leadingEdges_.size() << endl; - // Remove the triangle - EdgePtr e2(e1->getNextEdgeInFace()); - EdgePtr e3(e2->getNextEdgeInFace()); - - e1->clear(); - e2->clear(); - e3->clear(); -} - - -//-------------------------------------------------------------------------------------------------- -void Triangulation::reverse_splitTriangle(EdgePtr& edge) { - - // Reverse operation of splitTriangle - - EdgePtr e1(edge->getNextEdgeInFace()); - EdgePtr le(getLeadingEdgeInTriangle(e1)); -#ifdef DEBUG_HE - if (!le) - errorAndExit("Triangulation::removeTriangle: could not find leading edge"); -#endif - removeLeadingEdgeFromList(le); - - EdgePtr e2(e1->getNextEdgeInFace()->getTwinEdge()->getNextEdgeInFace()); - le = getLeadingEdgeInTriangle(e2); -#ifdef DEBUG_HE - if (!le) - errorAndExit("Triangulation::removeTriangle: could not find leading edge"); -#endif - removeLeadingEdgeFromList(le); - - EdgePtr e3(edge->getTwinEdge()->getNextEdgeInFace()->getNextEdgeInFace()); - le = getLeadingEdgeInTriangle(e3); -#ifdef DEBUG_HE - if (!le) - errorAndExit("Triangulation::removeTriangle: could not find leading edge"); -#endif - removeLeadingEdgeFromList(le); - - // The three triangles at the node have now been removed - // from the triangulation, but the arcs have not been deleted. - // Next delete the 6 half edges radiating from the node - // The node is maintained by handle and need not be deleted explicitly - EdgePtr estar = edge; - EdgePtr enext = estar->getTwinEdge()->getNextEdgeInFace(); - estar->getTwinEdge()->clear(); - estar->clear(); - - estar = enext; - enext = estar->getTwinEdge()->getNextEdgeInFace(); - estar->getTwinEdge()->clear(); - estar->clear(); - - enext->getTwinEdge()->clear(); - enext->clear(); - - - // Create the new triangle - e1->setNextEdgeInFace(e2); - e2->setNextEdgeInFace(e3); - e3->setNextEdgeInFace(e1); - addLeadingEdge(e1); -} - - -//-------------------------------------------------------------------------------------------------- -Dart Triangulation::createDart() { - - // Return an arbitrary CCW dart - return Dart(*leadingEdges_.begin()); -} - - -//-------------------------------------------------------------------------------------------------- -bool Triangulation::removeLeadingEdgeFromList(EdgePtr& leadingEdge) { - - // Remove the edge from the list of leading edges, - // but don't delete it. - // Also set flag for leading edge to false. - // Must search from start of list. Since edges are added to the - // start of the list during triangulation, this operation will - // normally be fast (when used in the triangulation algorithm) - list::iterator it; - for (it = leadingEdges_.begin(); it != leadingEdges_.end(); ++it) { - - EdgePtr edge = *it; - if (edge == leadingEdge) { - - edge->setAsLeadingEdge(false); - it = leadingEdges_.erase(it); - - return true; + if( !edge->IsLeadingEdge() ) + edge = edge->GetNextEdgeInFace(); } - } - - return false; + + if( !edge->IsLeadingEdge() ) + { + return EDGE_PTR(); + } + + return edge; } -//-------------------------------------------------------------------------------------------------- -void Triangulation::cleanAll() { - BOOST_FOREACH(EdgePtr& edge, leadingEdges_) - edge->setNextEdgeInFace(EdgePtr()); +static void getLimits( NODES_CONTAINER::iterator aFirst, NODES_CONTAINER::iterator aLast, + int& aXmin, int& aYmin, int& aXmax, int& aYmax) +{ + aXmin = aYmin = std::numeric_limits::min(); + aXmax = aYmax = std::numeric_limits::max(); + + NODES_CONTAINER::iterator it; + + for( it = aFirst; it != aLast; ++it ) + { + aXmin = std::min( aXmin, ( *it )->GetX() ); + aYmin = std::min( aYmin, ( *it )->GetY() ); + aXmax = std::max( aXmax, ( *it )->GetX() ); + aYmax = std::max( aYmax, ( *it )->GetY() ); + } } -//-------------------------------------------------------------------------------------------------- -void Triangulation::swapEdge(Dart& dart) { - swapEdge(dart.getEdge()); +EDGE_PTR TRIANGULATION::InitTwoEnclosingTriangles( NODES_CONTAINER::iterator aFirst, + NODES_CONTAINER::iterator aLast) +{ + int xmin, ymin, xmax, ymax; + getLimits( aFirst, aLast, xmin, ymin, xmax, ymax ); + + // Add 10% of range: + double fac = 10.0; + double dx = ( xmax - xmin ) / fac; + double dy = ( ymax - ymin ) / fac; + + NODE_PTR n1 = boost::make_shared( xmin - dx, ymin - dy ); + NODE_PTR n2 = boost::make_shared( xmax + dx, ymin - dy ); + NODE_PTR n3 = boost::make_shared( xmax + dx, ymax + dy ); + NODE_PTR n4 = boost::make_shared( xmin - dx, ymax + dy ); + + // diagonal + EDGE_PTR e1d = boost::make_shared(); + EDGE_PTR e2d = boost::make_shared(); + + // lower triangle + EDGE_PTR e11 = boost::make_shared(); + EDGE_PTR e12 = boost::make_shared(); + + // upper triangle + EDGE_PTR e21 = boost::make_shared(); + EDGE_PTR e22 = boost::make_shared(); + + // lower triangle + e1d->SetSourceNode( n3 ); + e1d->SetNextEdgeInFace( e11 ); + e1d->SetTwinEdge( e2d ); + addLeadingEdge( e1d ); + + e11->SetSourceNode( n1 ); + e11->SetNextEdgeInFace( e12 ); + + e12->SetSourceNode( n2 ); + e12->SetNextEdgeInFace( e1d ); + + // upper triangle + e2d->SetSourceNode( n1 ); + e2d->SetNextEdgeInFace( e21 ); + e2d->SetTwinEdge( e1d ); + addLeadingEdge( e2d ); + + e21->SetSourceNode( n3 ); + e21->SetNextEdgeInFace( e22 ); + + e22->SetSourceNode( n4 ); + e22->SetNextEdgeInFace( e2d ); + + return e11; } -//-------------------------------------------------------------------------------------------------- -void Triangulation::splitTriangle(Dart& dart, const NodePtr& point) { - EdgePtr edge = splitTriangle(dart.getEdge(), point); - dart.init(edge); +TRIANGULATION::TRIANGULATION() +{ + m_helper = new ttl::TRIANGULATION_HELPER( *this ); } -//-------------------------------------------------------------------------------------------------- -void Triangulation::reverse_splitTriangle(Dart& dart) { - reverse_splitTriangle(dart.getEdge()); +TRIANGULATION::TRIANGULATION( const TRIANGULATION& aTriangulation ) +{ + // Triangulation: Copy constructor not present + assert( false ); } -//-------------------------------------------------------------------------------------------------- -void Triangulation::removeBoundaryTriangle(Dart& d) { - removeTriangle(d.getEdge()); +TRIANGULATION::~TRIANGULATION() +{ + cleanAll(); + delete m_helper; +} + + +void TRIANGULATION::CreateDelaunay( NODES_CONTAINER::iterator aFirst, + NODES_CONTAINER::iterator aLast ) +{ + cleanAll(); + + EDGE_PTR bedge = InitTwoEnclosingTriangles( aFirst, aLast ); + DART dc( bedge ); + + DART d_iter = dc; + + NODES_CONTAINER::iterator it; + for( it = aFirst; it != aLast; ++it ) + { + m_helper->InsertNode( d_iter, *it ); + } + + // In general (e.g. for the triangle based data structure), the initial dart + // may have been changed. + // It is the users responsibility to get a valid boundary dart here. + // The half-edge data structure preserves the initial dart. + // (A dart at the boundary can also be found by trying to locate a + // triangle "outside" the triangulation.) + + // Assumes rectangular domain + m_helper->RemoveRectangularBoundary( dc ); +} + + +void TRIANGULATION::RemoveTriangle( EDGE_PTR& aEdge ) +{ + EDGE_PTR e1 = getLeadingEdgeInTriangle( aEdge ); + +#ifdef DEBUG_HE + if( !e1 ) + errorAndExit( "Triangulation::removeTriangle: could not find leading aEdge" ); +#endif + + removeLeadingEdgeFromList( e1 ); + // cout << "No leading edges = " << leadingEdges_.size() << endl; + // Remove the triangle + EDGE_PTR e2( e1->GetNextEdgeInFace() ); + EDGE_PTR e3( e2->GetNextEdgeInFace() ); + + e1->Clear(); + e2->Clear(); + e3->Clear(); +} + + +void TRIANGULATION::ReverseSplitTriangle( EDGE_PTR& aEdge ) +{ + // Reverse operation of splitTriangle + EDGE_PTR e1( aEdge->GetNextEdgeInFace() ); + EDGE_PTR le( getLeadingEdgeInTriangle( e1 ) ); +#ifdef DEBUG_HE + if (!le) + errorAndExit("Triangulation::removeTriangle: could not find leading edge"); +#endif + removeLeadingEdgeFromList( le ); + + EDGE_PTR e2( e1->GetNextEdgeInFace()->GetTwinEdge()->GetNextEdgeInFace() ); + le = getLeadingEdgeInTriangle( e2 ); +#ifdef DEBUG_HE + if (!le) + errorAndExit("Triangulation::removeTriangle: could not find leading edge"); +#endif + removeLeadingEdgeFromList( le ); + + EDGE_PTR e3( aEdge->GetTwinEdge()->GetNextEdgeInFace()->GetNextEdgeInFace() ); + le = getLeadingEdgeInTriangle( e3 ); +#ifdef DEBUG_HE + if (!le) + errorAndExit("Triangulation::removeTriangle: could not find leading edge"); +#endif + removeLeadingEdgeFromList( le ); + + // The three triangles at the node have now been removed + // from the triangulation, but the arcs have not been deleted. + // Next delete the 6 half edges radiating from the node + // The node is maintained by handle and need not be deleted explicitly + EDGE_PTR estar = aEdge; + EDGE_PTR enext = estar->GetTwinEdge()->GetNextEdgeInFace(); + estar->GetTwinEdge()->Clear(); + estar->Clear(); + + estar = enext; + enext = estar->GetTwinEdge()->GetNextEdgeInFace(); + estar->GetTwinEdge()->Clear(); + estar->Clear(); + + enext->GetTwinEdge()->Clear(); + enext->Clear(); + + // Create the new triangle + e1->SetNextEdgeInFace( e2 ); + e2->SetNextEdgeInFace( e3 ); + e3->SetNextEdgeInFace( e1 ); + addLeadingEdge( e1 ); +} + + +DART TRIANGULATION::CreateDart() +{ + // Return an arbitrary CCW dart + return DART( *m_leadingEdges.begin() ); +} + + +bool TRIANGULATION::removeLeadingEdgeFromList( EDGE_PTR& aLeadingEdge ) +{ + // Remove the edge from the list of leading edges, + // but don't delete it. + // Also set flag for leading edge to false. + // Must search from start of list. Since edges are added to the + // start of the list during triangulation, this operation will + // normally be fast (when used in the triangulation algorithm) + std::list::iterator it; + for( it = m_leadingEdges.begin(); it != m_leadingEdges.end(); ++it ) + { + EDGE_PTR edge = *it; + + if( edge == aLeadingEdge ) + { + edge->SetAsLeadingEdge( false ); + it = m_leadingEdges.erase( it ); + + return true; + } + } + + return false; +} + + +void TRIANGULATION::cleanAll() +{ + BOOST_FOREACH( EDGE_PTR& edge, m_leadingEdges ) + edge->SetNextEdgeInFace( EDGE_PTR() ); +} + + +void TRIANGULATION::swapEdge( DART& aDart ) +{ + SwapEdge( aDart.GetEdge() ); +} + + +void TRIANGULATION::splitTriangle( DART& aDart, const NODE_PTR& aPoint ) +{ + EDGE_PTR edge = SplitTriangle( aDart.GetEdge(), aPoint ); + aDart.Init( edge ); +} + + +void TRIANGULATION::reverseSplitTriangle( DART& aDart ) +{ + ReverseSplitTriangle( aDart.GetEdge() ); +} + + +void TRIANGULATION::removeBoundaryTriangle( DART& aDart ) +{ + RemoveTriangle( aDart.GetEdge() ); } #ifdef TTL_USE_NODE_FLAG -//-------------------------------------------------------------------------------------------------- -// This is a "template" for accessing all nodes (but multiple tests) -void Triangulation::flagNodes(bool flag) const { - - list::const_iterator it; - for (it = leadingEdges_.begin(); it != leadingEdges_.end(); ++it) { - EdgePtr edge = *it; - - for (int i = 0; i < 3; ++i) { - edge->getSourceNode()->SetFlag(flag); - edge = edge->getNextEdgeInFace(); - } - } -} +void TRIANGULATION::FlagNodes( bool aFlag ) const +{ + std::list::const_iterator it; + for( it = m_leadingEdges.begin(); it != m_leadingEdges.end(); ++it ) + { + EDGE_PTR edge = *it; - -//-------------------------------------------------------------------------------------------------- -list* Triangulation::getNodes() const { - - flagNodes(false); - list* nodeList = new list; - - list::const_iterator it; - for (it = leadingEdges_.begin(); it != leadingEdges_.end(); ++it) { - EdgePtr edge = *it; - - for (int i = 0; i < 3; ++i) { - const NodePtr& node = edge->getSourceNode(); - - if (node->GetFlag() == false) { - nodeList->push_back(node); - node->SetFlag(true); - } - edge = edge->getNextEdgeInFace(); - } - } - return nodeList; -} -#endif - - -//-------------------------------------------------------------------------------------------------- -list* Triangulation::getEdges(bool skip_boundary_edges) const { - - // collect all arcs (one half edge for each arc) - // (boundary edges are also collected). - - list::const_iterator it; - list* elist = new list; - for (it = leadingEdges_.begin(); it != leadingEdges_.end(); ++it) { - EdgePtr edge = *it; - for (int i = 0; i < 3; ++i) { - EdgePtr twinedge = edge->getTwinEdge(); - // only one of the half-edges - - if ( (!twinedge && !skip_boundary_edges) || - (twinedge && ((size_t)edge.get() > (size_t)twinedge.get())) ) - elist->push_front(edge); - - edge = edge->getNextEdgeInFace(); - } - } - return elist; -} - - -//-------------------------------------------------------------------------------------------------- -EdgePtr Triangulation::splitTriangle(EdgePtr& edge, const NodePtr& point) { - - // Add a node by just splitting a triangle into three triangles - // Assumes the half edge is located in the triangle - // Returns a half edge with source node as the new node - -// double x, y, z; -// x = point.x(); -// y = point.y(); -// z = point.z(); - - // e#_n are new edges - // e# are existing edges - // e#_n and e##_n are new twin edges - // e##_n are edges incident to the new node - - // Add the node to the structure - //NodePtr new_node(new Node(x,y,z)); - - NodePtr n1(edge->getSourceNode()); - EdgePtr e1(edge); - - EdgePtr e2(edge->getNextEdgeInFace()); - NodePtr n2(e2->getSourceNode()); - - EdgePtr e3(e2->getNextEdgeInFace()); - NodePtr n3(e3->getSourceNode()); - - EdgePtr e1_n = boost::make_shared(); - EdgePtr e11_n = boost::make_shared(); - EdgePtr e2_n = boost::make_shared(); - EdgePtr e22_n = boost::make_shared(); - EdgePtr e3_n = boost::make_shared(); - EdgePtr e33_n = boost::make_shared(); - - e1_n->setSourceNode(n1); - e11_n->setSourceNode(point); - e2_n->setSourceNode(n2); - e22_n->setSourceNode(point); - e3_n->setSourceNode(n3); - e33_n->setSourceNode(point); - - e1_n->setTwinEdge(e11_n); - e11_n->setTwinEdge(e1_n); - e2_n->setTwinEdge(e22_n); - e22_n->setTwinEdge(e2_n); - e3_n->setTwinEdge(e33_n); - e33_n->setTwinEdge(e3_n); - - e1_n->setNextEdgeInFace(e33_n); - e2_n->setNextEdgeInFace(e11_n); - e3_n->setNextEdgeInFace(e22_n); - - e11_n->setNextEdgeInFace(e1); - e22_n->setNextEdgeInFace(e2); - e33_n->setNextEdgeInFace(e3); - - // and update old's next edge - e1->setNextEdgeInFace(e2_n); - e2->setNextEdgeInFace(e3_n); - e3->setNextEdgeInFace(e1_n); - - // add the three new leading edges, - // Must remove the old leading edge from the list. - // Use the field telling if an edge is a leading edge - // NOTE: Must search in the list!!! - - if (e1->isLeadingEdge()) - removeLeadingEdgeFromList(e1); - else if (e2->isLeadingEdge()) - removeLeadingEdgeFromList(e2); - else if(e3->isLeadingEdge()) - removeLeadingEdgeFromList(e3); - else - assert( false ); // one of the edges should be leading - - addLeadingEdge(e1_n); - addLeadingEdge(e2_n); - addLeadingEdge(e3_n); - - // Return a half edge incident to the new node (with the new node as source node) - - return e11_n; -} - - -//-------------------------------------------------------------------------------------------------- -void Triangulation::swapEdge(EdgePtr& diagonal) { - - // Note that diagonal is both input and output and it is always - // kept in counterclockwise direction (this is not required by all - // functions in TriangulationHelper now) - - // Swap by rotating counterclockwise - // Use the same objects - no deletion or new objects - EdgePtr eL(diagonal); - EdgePtr eR(eL->getTwinEdge()); - EdgePtr eL_1(eL->getNextEdgeInFace()); - EdgePtr eL_2(eL_1->getNextEdgeInFace()); - EdgePtr eR_1(eR->getNextEdgeInFace()); - EdgePtr eR_2(eR_1->getNextEdgeInFace()); - - // avoid node to be dereferenced to zero and deleted - NodePtr nR(eR_2->getSourceNode()); - NodePtr nL(eL_2->getSourceNode()); - - eL->setSourceNode(nR); - eR->setSourceNode(nL); - - // and now 6 1-sewings - eL->setNextEdgeInFace(eL_2); - eL_2->setNextEdgeInFace(eR_1); - eR_1->setNextEdgeInFace(eL); - - eR->setNextEdgeInFace(eR_2); - eR_2->setNextEdgeInFace(eL_1); - eL_1->setNextEdgeInFace(eR); - - if (eL->isLeadingEdge()) - removeLeadingEdgeFromList(eL); - else if (eL_1->isLeadingEdge()) - removeLeadingEdgeFromList(eL_1); - else if (eL_2->isLeadingEdge()) - removeLeadingEdgeFromList(eL_2); - - if (eR->isLeadingEdge()) - removeLeadingEdgeFromList(eR); - else if (eR_1->isLeadingEdge()) - removeLeadingEdgeFromList(eR_1); - else if (eR_2->isLeadingEdge()) - removeLeadingEdgeFromList(eR_2); - - addLeadingEdge(eL); - addLeadingEdge(eR); -} - - -////-------------------------------------------------------------------------- -//static void printEdge(const Dart& dart, ostream& ofile) { -// -// Dart d0 = dart; -// d0.alpha0(); -// -// ofile << dart.x() << " " << dart.y() << endl; -// ofile << d0.x() << " " << d0.y() << endl; -//} - - -//-------------------------------------------------------------------------- -bool Triangulation::checkDelaunay() const { - - // ???? outputs !!!! - // ofstream os("qweND.dat"); - const list& leadingEdges = getLeadingEdges(); - - list::const_iterator it; - bool ok = true; - int noNotDelaunay = 0; - - for (it = leadingEdges.begin(); it != leadingEdges.end(); ++it) { - EdgePtr edge = *it; - - for (int i = 0; i < 3; ++i) { - EdgePtr twinedge = edge->getTwinEdge(); - - // only one of the half-edges - if (!twinedge || (size_t)edge.get() > (size_t)twinedge.get()) { - Dart dart(edge); - if (helper->swapTestDelaunay(dart)) { - noNotDelaunay++; - - //printEdge(dart,os); os << "\n"; - ok = false; - //cout << "............. not Delaunay .... " << endl; + for( int i = 0; i < 3; ++i ) + { + edge->GetSourceNode()->SetFlag( aFlag ); + edge = edge->GetNextEdgeInFace(); } - } - edge = edge->getNextEdgeInFace(); } - } - -#ifdef DEBUG_HE - cout << "!!! Triangulation is NOT Delaunay: " << noNotDelaunay << " edges\n" << endl; +} + + +std::list* TRIANGULATION::GetNodes() const +{ + FlagNodes( false ); + std::list* nodeList = new std::list; + std::list::const_iterator it; + + for( it = m_leadingEdges.begin(); it != m_leadingEdges.end(); ++it ) + { + EDGE_PTR edge = *it; + + for( int i = 0; i < 3; ++i ) + { + const NODE_PTR& node = edge->GetSourceNode(); + + if( node->GetFlag() == false ) + { + nodeList->push_back( node ); + node->SetFlag( true ); + } + edge = edge->GetNextEdgeInFace(); + } + } + return nodeList; +} #endif - - return ok; -} -//-------------------------------------------------------------------------------------------------- -void Triangulation::optimizeDelaunay() { +std::list* TRIANGULATION::GetEdges( bool aSkipBoundaryEdges ) const +{ + // collect all arcs (one half edge for each arc) + // (boundary edges are also collected). + std::list::const_iterator it; + std::list* elist = new std::list; - // This function is also present in ttl where it is implemented - // generically. - // The implementation below is tailored for the half-edge data structure, - // and is thus more efficient + for( it = m_leadingEdges.begin(); it != m_leadingEdges.end(); ++it ) + { + EDGE_PTR edge = *it; + for( int i = 0; i < 3; ++i ) + { + EDGE_PTR twinedge = edge->GetTwinEdge(); + // only one of the half-edges - // Collect all interior edges (one half edge for each arc) - bool skip_boundary_edges = true; - list* elist = getEdges(skip_boundary_edges); - - // Assumes that elist has only one half-edge for each arc. - bool cycling_check = true; - bool optimal = false; - list::const_iterator it; - while(!optimal) { - optimal = true; - for (it = elist->begin(); it != elist->end(); ++it) { - EdgePtr edge = *it; - - Dart dart(edge); - // Constrained edges should not be swapped - if (helper->swapTestDelaunay(dart, cycling_check)) { - optimal = false; - swapEdge(edge); - } + if( ( !twinedge && !aSkipBoundaryEdges ) + || ( twinedge && ( (size_t) edge.get() > (size_t) twinedge.get() ) ) ) + elist->push_front( edge ); + + edge = edge->GetNextEdgeInFace(); + } } - } - delete elist; + + return elist; } -//-------------------------------------------------------------------------------------------------- -EdgePtr Triangulation::getInteriorNode() const { - - const list& leadingEdges = getLeadingEdges(); - list::const_iterator it; - for (it = leadingEdges.begin(); it != leadingEdges.end(); ++it) { - EdgePtr edge = *it; - - // multiple checks, but only until found - for (int i = 0; i < 3; ++i) { - if (edge->getTwinEdge()) { - - if (!helper->isBoundaryNode(Dart(edge))) - return edge; - } - edge = edge->getNextEdgeInFace(); +EDGE_PTR TRIANGULATION::SplitTriangle( EDGE_PTR& aEdge, const NODE_PTR& aPoint ) +{ + // Add a node by just splitting a triangle into three triangles + // Assumes the half aEdge is located in the triangle + // Returns a half aEdge with source node as the new node + + // e#_n are new edges + // e# are existing edges + // e#_n and e##_n are new twin edges + // e##_n are edges incident to the new node + + // Add the node to the structure + //NODE_PTR new_node(new Node(x,y,z)); + + NODE_PTR n1( aEdge->GetSourceNode() ); + EDGE_PTR e1( aEdge ); + + EDGE_PTR e2( aEdge->GetNextEdgeInFace() ); + NODE_PTR n2( e2->GetSourceNode() ); + + EDGE_PTR e3( e2->GetNextEdgeInFace() ); + NODE_PTR n3( e3->GetSourceNode() ); + + EDGE_PTR e1_n = boost::make_shared(); + EDGE_PTR e11_n = boost::make_shared(); + EDGE_PTR e2_n = boost::make_shared(); + EDGE_PTR e22_n = boost::make_shared(); + EDGE_PTR e3_n = boost::make_shared(); + EDGE_PTR e33_n = boost::make_shared(); + + e1_n->SetSourceNode( n1 ); + e11_n->SetSourceNode( aPoint ); + e2_n->SetSourceNode( n2 ); + e22_n->SetSourceNode( aPoint ); + e3_n->SetSourceNode( n3 ); + e33_n->SetSourceNode( aPoint ); + + e1_n->SetTwinEdge( e11_n ); + e11_n->SetTwinEdge( e1_n ); + e2_n->SetTwinEdge( e22_n ); + e22_n->SetTwinEdge( e2_n ); + e3_n->SetTwinEdge( e33_n ); + e33_n->SetTwinEdge( e3_n ); + + e1_n->SetNextEdgeInFace( e33_n ); + e2_n->SetNextEdgeInFace( e11_n ); + e3_n->SetNextEdgeInFace( e22_n ); + + e11_n->SetNextEdgeInFace( e1 ); + e22_n->SetNextEdgeInFace( e2 ); + e33_n->SetNextEdgeInFace( e3 ); + + // and update old's next aEdge + e1->SetNextEdgeInFace( e2_n ); + e2->SetNextEdgeInFace( e3_n ); + e3->SetNextEdgeInFace( e1_n ); + + // add the three new leading edges, + // Must remove the old leading aEdge from the list. + // Use the field telling if an aEdge is a leading aEdge + // NOTE: Must search in the list!!! + + if( e1->IsLeadingEdge() ) + removeLeadingEdgeFromList( e1 ); + else if( e2->IsLeadingEdge() ) + removeLeadingEdgeFromList( e2 ); + else if( e3->IsLeadingEdge() ) + removeLeadingEdgeFromList( e3 ); + else + assert( false ); // one of the edges should be leading + + addLeadingEdge( e1_n ); + addLeadingEdge( e2_n ); + addLeadingEdge( e3_n ); + + // Return a half aEdge incident to the new node (with the new node as source node) + + return e11_n; +} + + +void TRIANGULATION::SwapEdge( EDGE_PTR& aDiagonal ) +{ + // Note that diagonal is both input and output and it is always + // kept in counterclockwise direction (this is not required by all + // functions in TriangulationHelper now) + + // Swap by rotating counterclockwise + // Use the same objects - no deletion or new objects + EDGE_PTR eL( aDiagonal ); + EDGE_PTR eR( eL->GetTwinEdge() ); + EDGE_PTR eL_1( eL->GetNextEdgeInFace() ); + EDGE_PTR eL_2( eL_1->GetNextEdgeInFace() ); + EDGE_PTR eR_1( eR->GetNextEdgeInFace() ); + EDGE_PTR eR_2( eR_1->GetNextEdgeInFace() ); + + // avoid node to be dereferenced to zero and deleted + NODE_PTR nR( eR_2->GetSourceNode() ); + NODE_PTR nL( eL_2->GetSourceNode() ); + + eL->SetSourceNode( nR ); + eR->SetSourceNode( nL ); + + // and now 6 1-sewings + eL->SetNextEdgeInFace( eL_2 ); + eL_2->SetNextEdgeInFace( eR_1 ); + eR_1->SetNextEdgeInFace( eL ); + + eR->SetNextEdgeInFace( eR_2 ); + eR_2->SetNextEdgeInFace( eL_1 ); + eL_1->SetNextEdgeInFace( eR ); + + if( eL->IsLeadingEdge() ) + removeLeadingEdgeFromList( eL ); + else if( eL_1->IsLeadingEdge() ) + removeLeadingEdgeFromList( eL_1 ); + else if( eL_2->IsLeadingEdge() ) + removeLeadingEdgeFromList( eL_2 ); + + if( eR->IsLeadingEdge() ) + removeLeadingEdgeFromList( eR ); + else if( eR_1->IsLeadingEdge() ) + removeLeadingEdgeFromList( eR_1 ); + else if( eR_2->IsLeadingEdge() ) + removeLeadingEdgeFromList( eR_2 ); + + addLeadingEdge( eL ); + addLeadingEdge( eR ); +} + + +bool TRIANGULATION::CheckDelaunay() const +{ + // ???? outputs !!!! + // ofstream os("qweND.dat"); + const std::list& leadingEdges = GetLeadingEdges(); + + std::list::const_iterator it; + bool ok = true; + int noNotDelaunay = 0; + + for( it = leadingEdges.begin(); it != leadingEdges.end(); ++it ) + { + EDGE_PTR edge = *it; + + for( int i = 0; i < 3; ++i ) + { + EDGE_PTR twinedge = edge->GetTwinEdge(); + + // only one of the half-edges + if( !twinedge || (size_t) edge.get() > (size_t) twinedge.get() ) + { + DART dart( edge ); + if( m_helper->SwapTestDelaunay( dart ) ) + { + noNotDelaunay++; + + //printEdge(dart,os); os << "\n"; + ok = false; + //cout << "............. not Delaunay .... " << endl; + } + } + + edge = edge->GetNextEdgeInFace(); + } } - } - return EdgePtr(); // no boundary nodes + +#ifdef DEBUG_HE + cout << "!!! Triangulation is NOT Delaunay: " << noNotDelaunay << " edges\n" << endl; +#endif + + return ok; } -//-------------------------------------------------------------------------------------------------- -EdgePtr Triangulation::getBoundaryEdgeInTriangle(const EdgePtr& e) const { - EdgePtr edge = e; - - if (helper->isBoundaryEdge(Dart(edge))) - return edge; +void TRIANGULATION::OptimizeDelaunay() +{ + // This function is also present in ttl where it is implemented + // generically. + // The implementation below is tailored for the half-edge data structure, + // and is thus more efficient - edge = edge->getNextEdgeInFace(); - if (helper->isBoundaryEdge(Dart(edge))) - return edge; + // Collect all interior edges (one half edge for each arc) + bool skip_boundary_edges = true; + std::list* elist = GetEdges( skip_boundary_edges ); - edge = edge->getNextEdgeInFace(); - if (helper->isBoundaryEdge(Dart(edge))) - return edge; - - return EdgePtr(); -} + // Assumes that elist has only one half-edge for each arc. + bool cycling_check = true; + bool optimal = false; + std::list::const_iterator it; + while( !optimal ) + { + optimal = true; -//-------------------------------------------------------------------------------------------------- -EdgePtr Triangulation::getBoundaryEdge() const { + for( it = elist->begin(); it != elist->end(); ++it ) + { + EDGE_PTR edge = *it; - // Get an arbitrary (CCW) boundary edge - // If the triangulation is closed, NULL is returned - - const list& leadingEdges = getLeadingEdges(); - list::const_iterator it; - EdgePtr edge; - - for (it = leadingEdges.begin(); it != leadingEdges.end(); ++it) { - edge = getBoundaryEdgeInTriangle(*it); - - if (edge) - return edge; - } - return EdgePtr(); -} - - -//-------------------------------------------------------------------------------------------------- -void Triangulation::printEdges(ofstream& os) const { - - // Print source node and target node for each edge face by face, - // but only one of the half-edges. - - const list& leadingEdges = getLeadingEdges(); - list::const_iterator it; - for (it = leadingEdges.begin(); it != leadingEdges.end(); ++it) { - EdgePtr edge = *it; - - for (int i = 0; i < 3; ++i) { - EdgePtr twinedge = edge->getTwinEdge(); - - // Print only one edge (the highest value of the pointer) - if (!twinedge || (size_t)edge.get() > (size_t)twinedge.get()) { - // Print source node and target node - NodePtr node = edge->getSourceNode(); - os << node->GetX() << " " << node->GetY() << endl; - node = edge->getTargetNode(); - os << node->GetX() << " " << node->GetY() << endl; - os << '\n'; // blank line - } - edge = edge->getNextEdgeInFace(); + DART dart( edge ); + // Constrained edges should not be swapped + if( m_helper->SwapTestDelaunay( dart, cycling_check ) ) + { + optimal = false; + SwapEdge( edge ); + } + } + } + + delete elist; +} + + +EDGE_PTR TRIANGULATION::GetInteriorNode() const +{ + const std::list& leadingEdges = GetLeadingEdges(); + std::list::const_iterator it; + + for( it = leadingEdges.begin(); it != leadingEdges.end(); ++it ) + { + EDGE_PTR edge = *it; + + // multiple checks, but only until found + for( int i = 0; i < 3; ++i ) + { + if( edge->GetTwinEdge() ) + { + if( !m_helper->IsBoundaryNode( DART( edge ) ) ) + return edge; + } + + edge = edge->GetNextEdgeInFace(); + } + } + + return EDGE_PTR(); // no boundary nodes +} + + +EDGE_PTR TRIANGULATION::GetBoundaryEdgeInTriangle( const EDGE_PTR& aEdge ) const +{ + EDGE_PTR edge = aEdge; + + if( m_helper->IsBoundaryEdge( DART( edge ) ) ) + return edge; + + edge = edge->GetNextEdgeInFace(); + if( m_helper->IsBoundaryEdge( DART( edge ) ) ) + return edge; + + edge = edge->GetNextEdgeInFace(); + if( m_helper->IsBoundaryEdge( DART( edge ) ) ) + return edge; + + return EDGE_PTR(); +} + + +EDGE_PTR TRIANGULATION::GetBoundaryEdge() const +{ + // Get an arbitrary (CCW) boundary edge + // If the triangulation is closed, NULL is returned + const std::list& leadingEdges = GetLeadingEdges(); + std::list::const_iterator it; + EDGE_PTR edge; + + for( it = leadingEdges.begin(); it != leadingEdges.end(); ++it ) + { + edge = GetBoundaryEdgeInTriangle( *it ); + + if( edge ) + return edge; + } + return EDGE_PTR(); +} + + +void TRIANGULATION::PrintEdges( std::ofstream& aOutput ) const +{ + // Print source node and target node for each edge face by face, + // but only one of the half-edges. + const std::list& leadingEdges = GetLeadingEdges(); + std::list::const_iterator it; + + for( it = leadingEdges.begin(); it != leadingEdges.end(); ++it ) + { + EDGE_PTR edge = *it; + + for( int i = 0; i < 3; ++i ) + { + EDGE_PTR twinedge = edge->GetTwinEdge(); + + // Print only one edge (the highest value of the pointer) + if( !twinedge || (size_t) edge.get() > (size_t) twinedge.get() ) + { + // Print source node and target node + NODE_PTR node = edge->GetSourceNode(); + aOutput << node->GetX() << " " << node->GetY() << std::endl; + node = edge->GetTargetNode(); + aOutput << node->GetX() << " " << node->GetY() << std::endl; + aOutput << '\n'; // blank line + } + + edge = edge->GetNextEdgeInFace(); + } } - } } diff --git a/common/painter.cpp b/common/painter.cpp index 7828623377..47efd47425 100644 --- a/common/painter.cpp +++ b/common/painter.cpp @@ -59,7 +59,7 @@ RENDER_SETTINGS::~RENDER_SETTINGS() void RENDER_SETTINGS::update() { - m_hiContrastColor = COLOR4D( m_hiContrastFactor, m_hiContrastFactor, m_highlightFactor, + m_hiContrastColor = COLOR4D( m_hiContrastFactor, m_hiContrastFactor, m_hiContrastFactor, m_layerOpacity ); } diff --git a/common/tool/action_manager.cpp b/common/tool/action_manager.cpp index a00d4d08cc..51c85aa273 100644 --- a/common/tool/action_manager.cpp +++ b/common/tool/action_manager.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include ACTION_MANAGER::ACTION_MANAGER( TOOL_MANAGER* aToolManager ) : @@ -43,7 +44,12 @@ ACTION_MANAGER::~ACTION_MANAGER() void ACTION_MANAGER::RegisterAction( TOOL_ACTION* aAction ) { - assert( aAction->GetId() == -1 ); // Check if the TOOL_ACTION was not registered before + // Check if the TOOL_ACTION was not registered before + assert( aAction->GetId() == -1 ); + // TOOL_ACTIONs are supposed to be named [appName.]toolName.actionName (with dots between) + // action name without specifying at least toolName is not valid + assert( aAction->GetName().find( '.', 0 ) != std::string::npos ); + assert( m_actionNameIndex.find( aAction->m_name ) == m_actionNameIndex.end() ); assert( m_actionIdIndex.find( aAction->m_id ) == m_actionIdIndex.end() ); @@ -53,15 +59,7 @@ void ACTION_MANAGER::RegisterAction( TOOL_ACTION* aAction ) m_actionIdIndex[aAction->m_id] = aAction; if( aAction->HasHotKey() ) - { - // Duplication of hot keys leads to unexpected behaviour - // The right way to change a hotkey is to use ACTION_MANAGER::ClearHotKey() first - assert( m_actionHotKeys.find( aAction->m_currentHotKey ) == m_actionHotKeys.end() ); - - m_actionHotKeys[aAction->m_currentHotKey] = aAction; - } - - aAction->setActionMgr( this ); + m_actionHotKeys[aAction->m_currentHotKey].push_back( aAction ); } @@ -71,11 +69,18 @@ void ACTION_MANAGER::UnregisterAction( TOOL_ACTION* aAction ) m_actionIdIndex.erase( aAction->m_id ); // Indicate that the ACTION_MANAGER no longer care about the object - aAction->setActionMgr( NULL ); aAction->setId( -1 ); if( aAction->HasHotKey() ) - m_actionHotKeys.erase( aAction->m_currentHotKey ); + { + std::list& actions = m_actionHotKeys[aAction->m_currentHotKey]; + std::list::iterator action = std::find( actions.begin(), actions.end(), aAction ); + + if( action != actions.end() ) + actions.erase( action ); + else + assert( false ); + } } @@ -94,34 +99,80 @@ bool ACTION_MANAGER::RunAction( const std::string& aActionName ) const if( it == m_actionNameIndex.end() ) return false; // no action with given name found - runAction( it->second ); + RunAction( it->second ); return true; } -bool ACTION_MANAGER::RunHotKey( int aHotKey ) const -{ - std::map::const_iterator it = m_actionHotKeys.find( aHotKey ); - - if( it == m_actionHotKeys.end() ) - return false; // no appropriate action found for the hotkey - - runAction( it->second ); - - return true; -} - - -void ACTION_MANAGER::ClearHotKey( int aHotKey ) -{ - m_actionHotKeys.erase( aHotKey ); -} - - -void ACTION_MANAGER::runAction( const TOOL_ACTION* aAction ) const +void ACTION_MANAGER::RunAction( const TOOL_ACTION* aAction ) const { TOOL_EVENT event = aAction->MakeEvent(); m_toolMgr->ProcessEvent( event ); } + + +bool ACTION_MANAGER::RunHotKey( int aHotKey ) const +{ + int key = std::toupper( aHotKey & ~MD_MODIFIER_MASK ); + int mod = aHotKey & MD_MODIFIER_MASK; + + HOTKEY_LIST::const_iterator it = m_actionHotKeys.find( key | mod ); + + // If no luck, try without modifier, to handle keys that require a modifier + // e.g. to get ? you need to press Shift+/ without US keyboard layout + // Hardcoding ? as Shift+/ is a bad idea, as on another layout you may need to press a + // different combination + if( it == m_actionHotKeys.end() ) + { + it = m_actionHotKeys.find( key ); + + if( it == m_actionHotKeys.end() ) + return false; // no appropriate action found for the hotkey + } + + const std::list& actions = it->second; + + // Choose the action that has the highest priority on the active tools stack + // If there is none, run the global action associated with the hot key + int highestPriority = -1, priority = -1; + const TOOL_ACTION* context = NULL; // pointer to context action of the highest priority tool + const TOOL_ACTION* global = NULL; // pointer to global action, if there is no context action + + BOOST_FOREACH( const TOOL_ACTION* action, actions ) + { + if( action->GetScope() == AS_GLOBAL ) + { + // Store the global action for the hot key in case there was no possible + // context actions to run + assert( global == NULL ); // there should be only one global action per hot key + global = action; + + continue; + } + + TOOL_BASE* tool = m_toolMgr->FindTool( action->GetToolName() ); + + if( tool ) + { + priority = m_toolMgr->GetPriority( tool->GetId() ); + + if( priority >= 0 && priority > highestPriority ) + { + highestPriority = priority; + context = action; + } + } + } + + if( !global && !context ) // currently there is no valid action to run + return false; + + if( context ) + RunAction( context ); + else if( global ) + RunAction( global ); + + return true; +} diff --git a/common/tool/tool_dispatcher.cpp b/common/tool/tool_dispatcher.cpp index f35689c97f..502dccfbdb 100644 --- a/common/tool/tool_dispatcher.cpp +++ b/common/tool/tool_dispatcher.cpp @@ -27,18 +27,16 @@ #include #include +#include #include #include -#include - +#include #include #include #include -using boost::optional; - ///> Stores information about a mouse button state struct TOOL_DISPATCHER::BUTTON_STATE { @@ -128,7 +126,7 @@ bool TOOL_DISPATCHER::handleMouseButton( wxEvent& aEvent, int aIndex, bool aMoti { BUTTON_STATE* st = m_buttons[aIndex]; wxEventType type = aEvent.GetEventType(); - optional evt; + boost::optional evt; bool isClick = false; bool up = type == st->upEvent; @@ -207,7 +205,7 @@ bool TOOL_DISPATCHER::handleMouseButton( wxEvent& aEvent, int aIndex, bool aMoti void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent ) { bool motion = false, buttonEvents = false; - optional evt; + boost::optional evt; int type = aEvent.GetEventType(); @@ -221,6 +219,9 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent ) // but changes in world coordinates (e.g. autopanning) type == KIGFX::WX_VIEW_CONTROLS::EVT_REFRESH_MOUSE ) { + wxMouseEvent* me = static_cast( &aEvent ); + int mods = decodeModifiers( me ); + VECTOR2D screenPos = m_toolMgr->GetViewControls()->GetMousePosition(); VECTOR2D pos = getView()->ToWorld( screenPos ); @@ -228,6 +229,7 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent ) { motion = true; m_lastMousePos = pos; + m_editFrame->UpdateStatusBar(); } for( unsigned int i = 0; i < m_buttons.size(); i++ ) @@ -235,29 +237,38 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent ) if( !buttonEvents && motion ) { - evt = TOOL_EVENT( TC_MOUSE, TA_MOUSE_MOTION ); + evt = TOOL_EVENT( TC_MOUSE, TA_MOUSE_MOTION, mods ); evt->SetMousePosition( pos ); } } // Keyboard handling - else if( type == wxEVT_KEY_UP || type == wxEVT_KEY_DOWN ) + else if( type == wxEVT_CHAR ) { wxKeyEvent* ke = static_cast( &aEvent ); int key = ke->GetKeyCode(); int mods = decodeModifiers( ke ); - if( type == wxEVT_KEY_UP ) + if( mods & MD_CTRL ) { - if( key == WXK_ESCAPE ) // ESC is the special key for cancelling tools - evt = TOOL_EVENT( TC_COMMAND, TA_CANCEL_TOOL ); - else - evt = TOOL_EVENT( TC_KEYBOARD, TA_KEY_UP, key | mods ); +#if !wxCHECK_VERSION( 2, 9, 0 ) + // I really look forward to the day when we will use only one version of wxWidgets.. + const int WXK_CONTROL_A = 1; + const int WXK_CONTROL_Z = 26; +#endif + + // wxWidgets have a quirk related to Ctrl+letter hot keys handled by CHAR_EVT + // http://docs.wxwidgets.org/trunk/classwx_key_event.html: + // "char events for ASCII letters in this case carry codes corresponding to the ASCII + // value of Ctrl-Latter, i.e. 1 for Ctrl-A, 2 for Ctrl-B and so on until 26 for Ctrl-Z." + if( key >= WXK_CONTROL_A && key <= WXK_CONTROL_Z ) + key += 'A' - 1; } + + if( key == WXK_ESCAPE ) // ESC is the special key for cancelling tools + evt = TOOL_EVENT( TC_COMMAND, TA_CANCEL_TOOL ); else - { - evt = TOOL_EVENT( TC_KEYBOARD, TA_KEY_DOWN, key | mods ); - } + evt = TOOL_EVENT( TC_KEYBOARD, TA_KEY_PRESSED, key | mods ); } if( evt ) @@ -268,21 +279,29 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent ) } -void TOOL_DISPATCHER::DispatchWxCommand( const wxCommandEvent& aEvent ) +void TOOL_DISPATCHER::DispatchWxCommand( wxCommandEvent& aEvent ) { - bool activateTool = false; - std::string toolName; + boost::optional evt; - // fixme: use TOOL_ACTIONs here switch( aEvent.GetId() ) { - case ID_PNS_ROUTER_TOOL: - toolName = "pcbnew.InteractiveRouter"; - activateTool = true; + case ID_ZOOM_IN: // toolbar button "Zoom In" + evt = COMMON_ACTIONS::zoomInCenter.MakeEvent(); + break; + + case ID_ZOOM_OUT: // toolbar button "Zoom In" + evt = COMMON_ACTIONS::zoomOutCenter.MakeEvent(); + break; + + case ID_ZOOM_PAGE: // toolbar button "Fit on Screen" + evt = COMMON_ACTIONS::zoomFitScreen.MakeEvent(); + break; + + default: + aEvent.Skip(); break; } - // do nothing if the legacy view is active - if( activateTool && m_editFrame->IsGalCanvasActive() ) - m_toolMgr->InvokeTool( toolName ); + if( evt ) + m_toolMgr->ProcessEvent( *evt ); } diff --git a/common/tool/tool_event.cpp b/common/tool/tool_event.cpp index 07460f3571..50739ba419 100644 --- a/common/tool/tool_event.cpp +++ b/common/tool/tool_event.cpp @@ -81,8 +81,7 @@ const std::string TOOL_EVENT::Format() const { TA_MOUSE_DRAG, "drag" }, { TA_MOUSE_MOTION, "motion" }, { TA_MOUSE_WHEEL, "wheel" }, - { TA_KEY_UP, "key-up" }, - { TA_KEY_DOWN, "key-down" }, + { TA_KEY_PRESSED, "key-pressed" }, { TA_VIEW_REFRESH, "view-refresh" }, { TA_VIEW_ZOOM, "view-zoom" }, { TA_VIEW_PAN, "view-pan" }, diff --git a/common/tool/tool_interactive.cpp b/common/tool/tool_interactive.cpp index 33756cf3d8..14ea61a86a 100644 --- a/common/tool/tool_interactive.cpp +++ b/common/tool/tool_interactive.cpp @@ -46,6 +46,12 @@ TOOL_INTERACTIVE::~TOOL_INTERACTIVE() } +void TOOL_INTERACTIVE::Activate() +{ + m_toolMgr->InvokeTool( m_toolId ); +} + + OPT_TOOL_EVENT TOOL_INTERACTIVE::Wait( const TOOL_EVENT_LIST& aEventList ) { return m_toolMgr->ScheduleWait( this, aEventList ); diff --git a/common/tool/tool_manager.cpp b/common/tool/tool_manager.cpp index f36d0cb343..e83b8fc6d2 100644 --- a/common/tool/tool_manager.cpp +++ b/common/tool/tool_manager.cpp @@ -44,7 +44,7 @@ #include #include -#include +#include using boost::optional; @@ -103,6 +103,14 @@ TOOL_MANAGER::TOOL_MANAGER() : TOOL_MANAGER::~TOOL_MANAGER() +{ + DeleteAll(); + + delete m_actionMgr; +} + + +void TOOL_MANAGER::DeleteAll() { std::map::iterator it, it_end; @@ -113,7 +121,7 @@ TOOL_MANAGER::~TOOL_MANAGER() delete it->first; // delete the tool itself } - delete m_actionMgr; + m_toolState.clear(); } @@ -196,6 +204,12 @@ bool TOOL_MANAGER::RunAction( const std::string& aActionName ) } +void TOOL_MANAGER::RunAction( const TOOL_ACTION& aAction ) +{ + m_actionMgr->RunAction( &aAction ); +} + + bool TOOL_MANAGER::invokeTool( TOOL_BASE* aTool ) { wxASSERT( aTool != NULL ); @@ -239,9 +253,15 @@ bool TOOL_MANAGER::runTool( TOOL_BASE* aTool ) return false; } - // If the tool is already active, do not invoke it again + // If the tool is already active, bring it to the top of the active tools stack if( isActive( aTool ) ) + { + m_activeTools.erase( std::find( m_activeTools.begin(), m_activeTools.end(), + aTool->GetId() ) ); + m_activeTools.push_front( aTool->GetId() ); + return false; + } aTool->Reset( TOOL_INTERACTIVE::RUN ); @@ -281,6 +301,25 @@ void TOOL_MANAGER::ResetTools( TOOL_BASE::RESET_REASON aReason ) } +int TOOL_MANAGER::GetPriority( int aToolId ) const +{ + int priority = 0; + + for( std::deque::const_iterator it = m_activeTools.begin(), + itEnd = m_activeTools.end(); it != itEnd; ++it ) + { + std::cout << FindTool( *it )->GetName() << std::endl; + + if( *it == aToolId ) + return priority; + + ++priority; + } + + return -1; +} + + void TOOL_MANAGER::ScheduleNextState( TOOL_BASE* aTool, TOOL_STATE_FUNC& aHandler, const TOOL_EVENT_LIST& aConditions ) { @@ -378,7 +417,7 @@ void TOOL_MANAGER::dispatchInternal( TOOL_EVENT& aEvent ) bool TOOL_MANAGER::dispatchStandardEvents( TOOL_EVENT& aEvent ) { - if( aEvent.Action() == TA_KEY_UP ) + if( aEvent.Action() == TA_KEY_PRESSED ) { // Check if there is a hotkey associated if( m_actionMgr->RunHotKey( aEvent.Modifier() | aEvent.KeyCode() ) ) diff --git a/common/view/view.cpp b/common/view/view.cpp index e27751bb76..4bf71ec638 100644 --- a/common/view/view.cpp +++ b/common/view/view.cpp @@ -45,32 +45,26 @@ VIEW::VIEW( bool aIsDynamic ) : m_scale( 1.0 ), m_painter( NULL ), m_gal( NULL ), - m_dynamic( aIsDynamic ), - m_scaleLimits( 15000.0, 1.0 ) + m_dynamic( aIsDynamic ) { - m_panBoundary.SetMaximum(); + m_needsUpdate.reserve( 32768 ); // Redraw everything at the beginning - for( int i = 0; i < TARGETS_NUMBER; ++i ) - MarkTargetDirty( i ); + MarkDirty(); // View uses layers to display EDA_ITEMs (item may be displayed on several layers, for example // pad may be shown on pad, pad hole and solder paste layers). There are usual copper layers // (eg. F.Cu, B.Cu, internal and so on) and layers for displaying objects such as texts, // silkscreen, pads, vias, etc. for( int i = 0; i < VIEW_MAX_LAYERS; i++ ) - { AddLayer( i ); - } } VIEW::~VIEW() { BOOST_FOREACH( LAYER_MAP::value_type& l, m_layers ) - { delete l.second.items; - } } @@ -82,7 +76,7 @@ void VIEW::AddLayer( int aLayer, bool aDisplayOnly ) m_layers[aLayer].id = aLayer; m_layers[aLayer].items = new VIEW_RTREE(); m_layers[aLayer].renderingOrder = aLayer; - m_layers[aLayer].enabled = true; + m_layers[aLayer].visible = true; m_layers[aLayer].displayOnly = aDisplayOnly; m_layers[aLayer].target = TARGET_CACHED; } @@ -98,7 +92,7 @@ void VIEW::Add( VIEW_ITEM* aItem ) aItem->ViewGetLayers( layers, layers_count ); aItem->saveLayers( layers, layers_count ); - for( int i = 0; i < layers_count; i++ ) + for( int i = 0; i < layers_count; ++i ) { VIEW_LAYER& l = m_layers[layers[i]]; l.items->Insert( aItem ); @@ -107,6 +101,9 @@ void VIEW::Add( VIEW_ITEM* aItem ) if( m_dynamic ) aItem->viewAssign( this ); + + if( aItem->viewRequiredUpdate() != VIEW_ITEM::NONE ) + MarkForUpdate( aItem ); } @@ -115,6 +112,15 @@ void VIEW::Remove( VIEW_ITEM* aItem ) if( m_dynamic ) aItem->m_view = NULL; + if( aItem->viewRequiredUpdate() != VIEW_ITEM::NONE ) // prevent from updating a removed item + { + std::vector::iterator item = std::find( m_needsUpdate.begin(), + m_needsUpdate.end(), aItem ); + + if( item != m_needsUpdate.end() ) + m_needsUpdate.erase( item ); + } + int layers[VIEW::VIEW_MAX_LAYERS], layers_count; aItem->getLayers( layers, layers_count ); @@ -126,9 +132,12 @@ void VIEW::Remove( VIEW_ITEM* aItem ) // Clear the GAL cache int prevGroup = aItem->getGroup( layers[i] ); + if( prevGroup >= 0 ) m_gal->DeleteGroup( prevGroup ); } + + aItem->deleteGroups(); } @@ -138,13 +147,9 @@ void VIEW::SetRequired( int aLayerId, int aRequiredId, bool aRequired ) wxASSERT( (unsigned) aRequiredId < m_layers.size() ); if( aRequired ) - { m_layers[aLayerId].requiredLayers.insert( aRequiredId ); - } else - { m_layers[aLayerId].requiredLayers.erase( aRequired ); - } } @@ -172,12 +177,12 @@ struct queryVisitor }; -int VIEW::Query( const BOX2I& aRect, std::vector& aResult ) +int VIEW::Query( const BOX2I& aRect, std::vector& aResult ) const { if( m_orderedLayers.empty() ) return 0; - std::vector::reverse_iterator i; + std::vector::const_reverse_iterator i; // execute queries in reverse direction, so that items that are on the top of // the rendering stack are returned first. @@ -197,31 +202,31 @@ int VIEW::Query( const BOX2I& aRect, std::vector& aResult ) VECTOR2D VIEW::ToWorld( const VECTOR2D& aCoord, bool aAbsolute ) const { - MATRIX3x3D matrix = m_gal->GetWorldScreenMatrix().Inverse(); + const MATRIX3x3D& matrix = m_gal->GetScreenWorldMatrix(); if( aAbsolute ) - { return VECTOR2D( matrix * aCoord ); - } else - { return VECTOR2D( matrix.GetScale().x * aCoord.x, matrix.GetScale().y * aCoord.y ); - } +} + + +double VIEW::ToWorld( double aSize ) const +{ + const MATRIX3x3D& matrix = m_gal->GetScreenWorldMatrix(); + + return matrix.GetScale().x * aSize; } VECTOR2D VIEW::ToScreen( const VECTOR2D& aCoord, bool aAbsolute ) const { - MATRIX3x3D matrix = m_gal->GetWorldScreenMatrix(); + const MATRIX3x3D& matrix = m_gal->GetWorldScreenMatrix(); if( aAbsolute ) - { return VECTOR2D( matrix * aCoord ); - } else - { return VECTOR2D( matrix.GetScale().x * aCoord.x, matrix.GetScale().y * aCoord.y ); - } } @@ -257,12 +262,6 @@ void VIEW::SetGAL( GAL* aGal ) } -void VIEW::SetPainter( PAINTER* aPainter ) -{ - m_painter = aPainter; -} - - BOX2D VIEW::GetViewport() const { BOX2D rect; @@ -293,19 +292,8 @@ void VIEW::SetMirror( bool aMirrorX, bool aMirrorY ) } -void VIEW::SetScale( double aScale ) -{ - SetScale( aScale, m_center ); -} - - void VIEW::SetScale( double aScale, const VECTOR2D& aAnchor ) { - if( aScale > m_scaleLimits.x ) - aScale = m_scaleLimits.x; - else if( aScale < m_scaleLimits.y ) - aScale = m_scaleLimits.y; - VECTOR2D a = ToScreen( aAnchor ); m_gal->SetZoomFactor( aScale ); @@ -325,19 +313,6 @@ void VIEW::SetCenter( const VECTOR2D& aCenter ) { m_center = aCenter; - if( !m_panBoundary.Contains( aCenter ) ) - { - if( aCenter.x < m_panBoundary.GetLeft() ) - m_center.x = m_panBoundary.GetLeft(); - else if( aCenter.x > m_panBoundary.GetRight() ) - m_center.x = m_panBoundary.GetRight(); - - if( aCenter.y < m_panBoundary.GetTop() ) - m_center.y = m_panBoundary.GetTop(); - else if( aCenter.y > m_panBoundary.GetBottom() ) - m_center.y = m_panBoundary.GetBottom(); - } - m_gal->SetLookAtPoint( m_center ); m_gal->ComputeWorldScreenMatrix(); @@ -425,6 +400,7 @@ void VIEW::UpdateLayerColor( int aLayer ) updateItemsColor visitor( aLayer, m_painter, m_gal ); m_layers[aLayer].items->Query( r, visitor ); + MarkTargetDirty( m_layers[aLayer].target ); } @@ -484,6 +460,7 @@ void VIEW::ChangeLayerDepth( int aLayer, int aDepth ) changeItemsDepth visitor( aLayer, aDepth, m_gal ); m_layers[aLayer].items->Query( r, visitor ); + MarkTargetDirty( m_layers[aLayer].target ); } @@ -578,8 +555,8 @@ void VIEW::UpdateAllLayersOrder() struct VIEW::drawItem { - drawItem( VIEW* aView, const VIEW_LAYER* aCurrentLayer ) : - currentLayer( aCurrentLayer ), view( aView ) + drawItem( VIEW* aView, int aLayer ) : + view( aView ), layer( aLayer ) { } @@ -587,18 +564,17 @@ struct VIEW::drawItem { // Conditions that have te be fulfilled for an item to be drawn bool drawCondition = aItem->ViewIsVisible() && - aItem->ViewGetLOD( currentLayer->id ) < view->m_scale; + aItem->ViewGetLOD( layer ) < view->m_scale; if( !drawCondition ) return true; - view->draw( aItem, currentLayer->id ); + view->draw( aItem, layer ); return true; } - const VIEW_LAYER* currentLayer; VIEW* view; - int layersCount, layers[VIEW_MAX_LAYERS]; + int layer, layersCount, layers[VIEW_MAX_LAYERS]; }; @@ -606,9 +582,9 @@ void VIEW::redrawRect( const BOX2I& aRect ) { BOOST_FOREACH( VIEW_LAYER* l, m_orderedLayers ) { - if( l->enabled && IsTargetDirty( l->target ) && areRequiredLayersEnabled( l->id ) ) + if( l->visible && IsTargetDirty( l->target ) && areRequiredLayersEnabled( l->id ) ) { - drawItem drawFunc( this, l ); + drawItem drawFunc( this, l->id ); m_gal->SetTarget( l->target ); m_gal->SetLayerDepth( l->renderingOrder ); @@ -618,7 +594,7 @@ void VIEW::redrawRect( const BOX2I& aRect ) } -void VIEW::draw( VIEW_ITEM* aItem, int aLayer, bool aImmediate ) const +void VIEW::draw( VIEW_ITEM* aItem, int aLayer, bool aImmediate ) { if( IsCached( aLayer ) && !aImmediate ) { @@ -649,11 +625,12 @@ void VIEW::draw( VIEW_ITEM* aItem, int aLayer, bool aImmediate ) const } -void VIEW::draw( VIEW_ITEM* aItem, bool aImmediate ) const +void VIEW::draw( VIEW_ITEM* aItem, bool aImmediate ) { int layers[VIEW_MAX_LAYERS], layers_count; aItem->ViewGetLayers( layers, layers_count ); + // Sorting is needed for drawing order dependent GALs (like Cairo) SortLayers( layers, layers_count ); @@ -665,26 +642,12 @@ void VIEW::draw( VIEW_ITEM* aItem, bool aImmediate ) const } -void VIEW::draw( VIEW_GROUP* aGroup, bool aImmediate ) const +void VIEW::draw( VIEW_GROUP* aGroup, bool aImmediate ) { std::set::const_iterator it; for( it = aGroup->Begin(); it != aGroup->End(); ++it ) - { draw( *it, aImmediate ); - } -} - - -bool VIEW::IsDirty() const -{ - for( int i = 0; i < TARGETS_NUMBER; ++i ) - { - if( IsTargetDirty( i ) ) - return true; - } - - return false; } @@ -709,14 +672,14 @@ struct VIEW::recacheItem bool operator()( VIEW_ITEM* aItem ) { // Remove previously cached group - int prevGroup = aItem->getGroup( layer ); + int group = aItem->getGroup( layer ); - if( prevGroup >= 0 ) - gal->DeleteGroup( prevGroup ); + if( group >= 0 ) + gal->DeleteGroup( group ); if( immediately ) { - int group = gal->BeginGroup(); + group = gal->BeginGroup(); aItem->setGroup( layer, group ); if( !view->m_painter->Draw( aItem, layer ) ) @@ -726,6 +689,7 @@ struct VIEW::recacheItem } else { + aItem->ViewUpdate( VIEW_ITEM::ALL ); aItem->setGroup( layer, -1 ); } @@ -757,6 +721,7 @@ void VIEW::Clear() } m_gal->ClearCache(); + m_needsUpdate.clear(); } @@ -783,6 +748,11 @@ void VIEW::ClearTargets() void VIEW::Redraw() { +#ifdef PROFILE + prof_counter totalRealTime; + prof_start( &totalRealTime ); +#endif /* PROFILE */ + VECTOR2D screenSize = m_gal->GetScreenPixelSize(); BOX2I rect( ToWorld( VECTOR2D( 0, 0 ) ), ToWorld( screenSize ) - ToWorld( VECTOR2D( 0, 0 ) ) ); @@ -791,13 +761,19 @@ void VIEW::Redraw() redrawRect( rect ); // All targets were redrawn, so nothing is dirty - clearTargetDirty( TARGET_CACHED ); - clearTargetDirty( TARGET_NONCACHED ); - clearTargetDirty( TARGET_OVERLAY ); + markTargetClean( TARGET_CACHED ); + markTargetClean( TARGET_NONCACHED ); + markTargetClean( TARGET_OVERLAY ); + +#ifdef PROFILE + prof_end( &totalRealTime ); + + wxLogDebug( wxT( "Redraw: %.1f ms" ), totalRealTime.msecs() ); +#endif /* PROFILE */ } -VECTOR2D VIEW::GetScreenPixelSize() const +const VECTOR2I& VIEW::GetScreenPixelSize() const { return m_gal->GetScreenPixelSize(); } @@ -812,10 +788,7 @@ struct VIEW::clearLayerCache bool operator()( VIEW_ITEM* aItem ) { - if( aItem->storesGroups() ) - { - aItem->deleteGroups(); - } + aItem->deleteGroups(); return true; } @@ -839,7 +812,7 @@ void VIEW::clearGroupCache() } -void VIEW::InvalidateItem( VIEW_ITEM* aItem, int aUpdateFlags ) +void VIEW::invalidateItem( VIEW_ITEM* aItem, int aUpdateFlags ) { // updateLayers updates geometry too, so we do not have to update both of them at the same time if( aUpdateFlags & VIEW_ITEM::LAYERS ) @@ -851,24 +824,23 @@ void VIEW::InvalidateItem( VIEW_ITEM* aItem, int aUpdateFlags ) aItem->ViewGetLayers( layers, layers_count ); // Iterate through layers used by the item and recache it immediately - for( int i = 0; i < layers_count; i++ ) + for( int i = 0; i < layers_count; ++i ) { int layerId = layers[i]; - if( aUpdateFlags & ( VIEW_ITEM::GEOMETRY | VIEW_ITEM::LAYERS ) ) + if( IsCached( layerId ) ) { - // Redraw - if( IsCached( layerId ) ) + if( aUpdateFlags & ( VIEW_ITEM::GEOMETRY | VIEW_ITEM::LAYERS ) ) updateItemGeometry( aItem, layerId ); - } - else if( aUpdateFlags & VIEW_ITEM::COLOR ) - { - updateItemColor( aItem, layerId ); + else if( aUpdateFlags & VIEW_ITEM::COLOR ) + updateItemColor( aItem, layerId ); } // Mark those layers as dirty, so the VIEW will be refreshed MarkTargetDirty( m_layers[layerId].target ); } + + aItem->clearUpdateFlags(); } @@ -890,6 +862,7 @@ void VIEW::sortLayers() void VIEW::updateItemColor( VIEW_ITEM* aItem, int aLayer ) { wxASSERT( (unsigned) aLayer < m_layers.size() ); + wxASSERT( IsCached( aLayer ) ); // Obtain the color that should be used for coloring the item on the specific layerId const COLOR4D color = m_painter->GetSettings()->GetColor( aItem, aLayer ); @@ -904,20 +877,25 @@ void VIEW::updateItemColor( VIEW_ITEM* aItem, int aLayer ) void VIEW::updateItemGeometry( VIEW_ITEM* aItem, int aLayer ) { wxASSERT( (unsigned) aLayer < m_layers.size() ); + wxASSERT( IsCached( aLayer ) ); + VIEW_LAYER& l = m_layers.at( aLayer ); m_gal->SetTarget( l.target ); m_gal->SetLayerDepth( l.renderingOrder ); // Redraw the item from scratch - int prevGroup = aItem->getGroup( aLayer ); + int group = aItem->getGroup( aLayer ); - if( prevGroup >= 0 ) - m_gal->DeleteGroup( prevGroup ); + if( group >= 0 ) + m_gal->DeleteGroup( group ); - int group = m_gal->BeginGroup(); + group = m_gal->BeginGroup(); aItem->setGroup( aLayer, group ); - m_painter->Draw( static_cast( aItem ), aLayer ); + + if( !m_painter->Draw( static_cast( aItem ), aLayer ) ); + aItem->ViewDraw( aLayer, m_gal ); // Alternative drawing method + m_gal->EndGroup(); } @@ -928,7 +906,7 @@ void VIEW::updateBbox( VIEW_ITEM* aItem ) aItem->ViewGetLayers( layers, layers_count ); - for( int i = 0; i < layers_count; i++ ) + for( int i = 0; i < layers_count; ++i ) { VIEW_LAYER& l = m_layers[layers[i]]; l.items->Remove( aItem ); @@ -945,17 +923,23 @@ void VIEW::updateLayers( VIEW_ITEM* aItem ) // Remove the item from previous layer set aItem->getLayers( layers, layers_count ); - for( int i = 0; i < layers_count; i++ ) + for( int i = 0; i < layers_count; ++i ) { VIEW_LAYER& l = m_layers[layers[i]]; l.items->Remove( aItem ); MarkTargetDirty( l.target ); - // Redraw the item from scratch - int prevGroup = aItem->getGroup( layers[i] ); + if( IsCached( l.id ) ) + { + // Redraw the item from scratch + int prevGroup = aItem->getGroup( layers[i] ); - if( prevGroup >= 0 ) - m_gal->DeleteGroup( prevGroup ); + if( prevGroup >= 0 ) + { + m_gal->DeleteGroup( prevGroup ); + aItem->setGroup( l.id, -1 ); + } + } } // Add the item to new layer set @@ -981,7 +965,7 @@ bool VIEW::areRequiredLayersEnabled( int aLayerId ) const it_end = m_layers.at( aLayerId ).requiredLayers.end(); it != it_end; ++it ) { // That is enough if just one layer is not enabled - if( !m_layers.at( *it ).enabled ) + if( !m_layers.at( *it ).visible || !areRequiredLayersEnabled( *it ) ) return false; } @@ -1023,13 +1007,15 @@ void VIEW::RecacheAllItems( bool aImmediately ) } -bool VIEW::IsTargetDirty( int aTarget ) const +void VIEW::UpdateItems() { - wxASSERT( aTarget < TARGETS_NUMBER ); + // Update items that need this + BOOST_FOREACH( VIEW_ITEM* item, m_needsUpdate ) + { + assert( item->viewRequiredUpdate() != VIEW_ITEM::NONE ); - // Check the target status - if( m_dirtyTargets[aTarget] ) - return true; + invalidateItem( item, item->viewRequiredUpdate() ); + } - return false; + m_needsUpdate.clear(); } diff --git a/common/view/view_item.cpp b/common/view/view_item.cpp index 305ab68579..900e030e61 100644 --- a/common/view/view_item.cpp +++ b/common/view/view_item.cpp @@ -31,25 +31,12 @@ using namespace KIGFX; void VIEW_ITEM::ViewSetVisible( bool aIsVisible ) { - bool update = false; - - if( m_visible != aIsVisible ) - update = true; - - m_visible = aIsVisible; - // update only if the visibility has really changed - if( update ) + if( m_visible != aIsVisible ) + { + m_visible = aIsVisible; ViewUpdate( APPEARANCE ); -} - - -void VIEW_ITEM::ViewUpdate( int aUpdateFlags ) -{ - if( !m_view ) - return; - - m_view->InvalidateItem( this, aUpdateFlags ); + } } diff --git a/common/view/wx_view_controls.cpp b/common/view/wx_view_controls.cpp index 48107911d2..22eb3ee47e 100644 --- a/common/view/wx_view_controls.cpp +++ b/common/view/wx_view_controls.cpp @@ -35,9 +35,7 @@ using namespace KIGFX; const wxEventType WX_VIEW_CONTROLS::EVT_REFRESH_MOUSE = wxNewEventType(); WX_VIEW_CONTROLS::WX_VIEW_CONTROLS( VIEW* aView, wxWindow* aParentPanel ) : - VIEW_CONTROLS( aView ), - m_state( IDLE ), - m_parentPanel( aParentPanel ) + VIEW_CONTROLS( aView ), m_state( IDLE ), m_parentPanel( aParentPanel ) { m_parentPanel->Connect( wxEVT_MOTION, wxMouseEventHandler( WX_VIEW_CONTROLS::onMotion ), NULL, this ); @@ -68,13 +66,44 @@ void VIEW_CONTROLS::ShowCursor( bool aEnabled ) } +void VIEW_CONTROLS::setCenter( const VECTOR2D& aCenter ) +{ + if( !m_panBoundary.Contains( aCenter ) ) + { + VECTOR2D newCenter( aCenter ); + + if( aCenter.x < m_panBoundary.GetLeft() ) + newCenter.x = m_panBoundary.GetLeft(); + else if( aCenter.x > m_panBoundary.GetRight() ) + newCenter.x = m_panBoundary.GetRight(); + + if( aCenter.y < m_panBoundary.GetTop() ) + newCenter.y = m_panBoundary.GetTop(); + else if( aCenter.y > m_panBoundary.GetBottom() ) + newCenter.y = m_panBoundary.GetBottom(); + + m_view->SetCenter( newCenter ); + } + else + { + m_view->SetCenter( aCenter ); + } +} + + +void VIEW_CONTROLS::setScale( double aScale, const VECTOR2D& aAnchor ) +{ + if( aScale < m_minScale ) + aScale = m_minScale; + else if( aScale > m_maxScale ) + aScale = m_maxScale; + + m_view->SetScale( aScale, aAnchor ); +} + + void WX_VIEW_CONTROLS::onMotion( wxMouseEvent& aEvent ) { - m_mousePosition.x = aEvent.GetX(); - m_mousePosition.y = aEvent.GetY(); - - updateCursor(); - bool isAutoPanning = false; if( m_autoPanEnabled ) @@ -84,10 +113,10 @@ void WX_VIEW_CONTROLS::onMotion( wxMouseEvent& aEvent ) { if( m_state == DRAG_PANNING ) { - VECTOR2D d = m_dragStartPoint - m_mousePosition; + VECTOR2D d = m_dragStartPoint - VECTOR2D( aEvent.GetX(), aEvent.GetY() ); VECTOR2D delta = m_view->ToWorld( d, false ); - m_view->SetCenter( m_lookStartPoint + delta ); + setCenter( m_lookStartPoint + delta ); aEvent.StopPropagation(); } else @@ -117,7 +146,7 @@ void WX_VIEW_CONTROLS::onWheel( wxMouseEvent& aEvent ) VECTOR2D delta( aEvent.ControlDown() ? -scrollSpeed : 0.0, aEvent.ShiftDown() ? -scrollSpeed : 0.0 ); - m_view->SetCenter( m_view->GetCenter() + delta ); + setCenter( m_view->GetCenter() + delta ); } else { @@ -140,7 +169,7 @@ void WX_VIEW_CONTROLS::onWheel( wxMouseEvent& aEvent ) } VECTOR2D anchor = m_view->ToWorld( VECTOR2D( aEvent.GetX(), aEvent.GetY() ) ); - m_view->SetScale( m_view->GetScale() * zoomScale, anchor ); + setScale( m_view->GetScale() * zoomScale, anchor ); } aEvent.Skip(); @@ -197,9 +226,7 @@ void WX_VIEW_CONTROLS::onTimer( wxTimerEvent& aEvent ) dir = dir.Resize( borderSize ); dir = m_view->ToWorld( dir, false ); - m_view->SetCenter( m_view->GetCenter() + dir * m_autoPanSpeed ); - - updateCursor(); + setCenter( m_view->GetCenter() + dir * m_autoPanSpeed ); // Notify tools that the cursor position has changed in the world coordinates wxMouseEvent moveEvent( EVT_REFRESH_MOUSE ); @@ -238,7 +265,7 @@ void WX_VIEW_CONTROLS::SetGrabMouse( bool aEnabled ) } -const VECTOR2D WX_VIEW_CONTROLS::GetMousePosition() const +VECTOR2D WX_VIEW_CONTROLS::GetMousePosition() const { wxPoint msp = wxGetMousePosition(); wxPoint winp = m_parentPanel->GetScreenPosition(); @@ -247,6 +274,22 @@ const VECTOR2D WX_VIEW_CONTROLS::GetMousePosition() const } +VECTOR2D WX_VIEW_CONTROLS::GetCursorPosition() const +{ + if( m_forceCursorPosition ) + return m_forcedPosition; + else + { + VECTOR2D mousePosition = GetMousePosition(); + + if( m_snappingEnabled ) + return m_view->GetGAL()->GetGridPoint( m_view->ToWorld( mousePosition ) ); + else + return m_view->ToWorld( mousePosition ); + } +} + + bool WX_VIEW_CONTROLS::handleAutoPanning( const wxMouseEvent& aEvent ) { VECTOR2D p( aEvent.GetX(), aEvent.GetY() ); @@ -257,17 +300,19 @@ bool WX_VIEW_CONTROLS::handleAutoPanning( const wxMouseEvent& aEvent ) double borderEndX = m_view->GetScreenPixelSize().x - borderStart; double borderEndY = m_view->GetScreenPixelSize().y - borderStart; - m_panDirection = VECTOR2D(); - if( p.x < borderStart ) m_panDirection.x = -( borderStart - p.x ); else if( p.x > borderEndX ) m_panDirection.x = ( p.x - borderEndX ); + else + m_panDirection.x = 0; if( p.y < borderStart ) m_panDirection.y = -( borderStart - p.y ); else if( p.y > borderEndY ) m_panDirection.y = ( p.y - borderEndY ); + else + m_panDirection.y = 0; bool borderHit = ( m_panDirection.x != 0 || m_panDirection.y != 0 ); @@ -304,14 +349,3 @@ bool WX_VIEW_CONTROLS::handleAutoPanning( const wxMouseEvent& aEvent ) wxASSERT_MSG( false, wxT( "This line should never be reached" ) ); return false; // Should not be reached, just avoid the compiler warnings.. } - - -void WX_VIEW_CONTROLS::updateCursor() -{ - if( m_forceCursorPosition ) - m_cursorPosition = m_view->ToScreen( m_forcedPosition ); - else if( m_snappingEnabled ) - m_cursorPosition = m_view->GetGAL()->GetGridPoint( m_mousePosition ); - else - m_cursorPosition = m_mousePosition; -} diff --git a/common/worksheet_viewitem.cpp b/common/worksheet_viewitem.cpp index ba4185f8af..e261b3eff9 100644 --- a/common/worksheet_viewitem.cpp +++ b/common/worksheet_viewitem.cpp @@ -189,7 +189,7 @@ void WORKSHEET_VIEWITEM::draw( const WS_DRAW_ITEM_TEXT* aItem, GAL* aGal ) const aGal->SetStrokeColor( COLOR4D( aItem->GetColor() ) ); aGal->SetLineWidth( aItem->GetThickness() ); aGal->SetTextAttributes( aItem ); - aGal->StrokeText( std::wstring( aItem->GetText().wc_str() ), position, 0.0 ); + aGal->StrokeText( aItem->GetText(), position, 0.0 ); } diff --git a/common/zoom.cpp b/common/zoom.cpp index b1652d9fa9..b7393cd54f 100644 --- a/common/zoom.cpp +++ b/common/zoom.cpp @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include #include @@ -194,24 +194,22 @@ void EDA_DRAW_FRAME::OnZoom( wxCommandEvent& event ) RedrawScreen( center, true ); } - if( IsGalCanvasActive() ) - { - // Apply computed view settings to GAL - KIGFX::VIEW* view = GetGalCanvas()->GetView(); - KIGFX::GAL* gal = GetGalCanvas()->GetGAL(); - - double zoomFactor = gal->GetWorldScale() / gal->GetZoomFactor(); - double zoom = 1.0 / ( zoomFactor * GetZoom() ); - - view->SetScale( zoom ); - view->SetCenter( VECTOR2D( center ) ); - GetGalCanvas()->Refresh(); - } - UpdateStatusBar(); } +void EDA_DRAW_FRAME::SetNextZoom() +{ + GetScreen()->SetNextZoom(); +} + + +void EDA_DRAW_FRAME::SetPrevZoom() +{ + GetScreen()->SetPreviousZoom(); +} + + /* add the zoom list menu the the MasterMenu. * used in OnRightClick(wxMouseEvent& event) */ diff --git a/cvpcb/class_DisplayFootprintsFrame.cpp b/cvpcb/class_DisplayFootprintsFrame.cpp index 241ecdd861..7b8b836f6f 100644 --- a/cvpcb/class_DisplayFootprintsFrame.cpp +++ b/cvpcb/class_DisplayFootprintsFrame.cpp @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/eeschema/eeschema_config.cpp b/eeschema/eeschema_config.cpp index aca02062da..ed548ef958 100644 --- a/eeschema/eeschema_config.cpp +++ b/eeschema/eeschema_config.cpp @@ -271,9 +271,7 @@ void SCH_EDIT_FRAME::Process_Config( wxCommandEvent& event ) void SCH_EDIT_FRAME::OnSetOptions( wxCommandEvent& event ) { wxArrayString units; - GRIDS grid_list; - - GetScreen()->GetGrids( grid_list ); + GRIDS grid_list = GetScreen()->GetGrids(); DIALOG_EESCHEMA_OPTIONS dlg( this ); diff --git a/include/class_base_screen.h b/include/class_base_screen.h index eed5987e39..502ab9a9e6 100644 --- a/include/class_base_screen.h +++ b/include/class_base_screen.h @@ -65,7 +65,7 @@ public: }; -typedef std::vector< GRID_TYPE > GRIDS; +typedef std::vector GRIDS; /** @@ -445,11 +445,12 @@ public: /** * Function GetGrids(). - * Copy the grid list to \a aList. - * - * @param aList - List to copy to. + * Returns the current list of grids. */ - void GetGrids( GRIDS& aList ); + const GRIDS& GetGrids() const + { + return m_grids; + } /** * Function GetClass diff --git a/include/class_board_item.h b/include/class_board_item.h index 91fd3ead0c..0527a33c91 100644 --- a/include/class_board_item.h +++ b/include/class_board_item.h @@ -33,8 +33,6 @@ #include #include -#include -#include #include /// Abbrevation for fomatting internal units to a string. diff --git a/include/class_drawpanel_gal.h b/include/class_draw_panel_gal.h similarity index 99% rename from include/class_drawpanel_gal.h rename to include/class_draw_panel_gal.h index b7f92c2209..4ec05ed65d 100644 --- a/include/class_drawpanel_gal.h +++ b/include/class_draw_panel_gal.h @@ -23,7 +23,7 @@ */ /** - * @file class_drawpanel_gal.h: + * @file class_draw_panel_gal.h: * @brief EDA_DRAW_PANEL_GAL class definition. */ diff --git a/include/class_marker_base.h b/include/class_marker_base.h index bcc1d66337..d76b114b03 100644 --- a/include/class_marker_base.h +++ b/include/class_marker_base.h @@ -13,7 +13,6 @@ class MARKER_BASE public: wxPoint m_Pos; ///< position of the marker protected: - std::vector m_Corners; ///< Corner list for shape definition (a polygon) int m_MarkerType; ///< Can be used as a flag EDA_COLOR_T m_Color; ///< color EDA_RECT m_ShapeBoundingBox; ///< Bounding box of the graphic symbol, relative diff --git a/include/draw_frame.h b/include/draw_frame.h index aaf999edec..a76e1f4cc6 100644 --- a/include/draw_frame.h +++ b/include/draw_frame.h @@ -353,6 +353,18 @@ public: */ wxPoint GetGridPosition( const wxPoint& aPosition ) const; + /** + * Function SetNextGrid() + * changes the grid size settings to the next one available. + */ + virtual void SetNextGrid(); + + /** + * Function SetPrevGrid() + * changes the grid size settings to the previous one available. + */ + virtual void SetPrevGrid(); + /** * Command event handler for selecting grid sizes. * @@ -410,6 +422,18 @@ public: virtual void OnZoom( wxCommandEvent& event ); + /** + * Function SetNextZoom() + * changes the zoom to the next one available. + */ + void SetNextZoom(); + + /** + * Function SetPrevZoom() + * changes the zoom to the previous one available. + */ + void SetPrevZoom(); + /** * Function RedrawScreen * redraws the entire screen area by updating the scroll bars and mouse pointer in diff --git a/include/gal/cairo/cairo_gal.h b/include/gal/cairo/cairo_gal.h index 20477db08a..352e262931 100644 --- a/include/gal/cairo/cairo_gal.h +++ b/include/gal/cairo/cairo_gal.h @@ -164,7 +164,7 @@ public: // -------------- /// @copydoc GAL::Transform() - virtual void Transform( MATRIX3x3D aTransformation ); + virtual void Transform( const MATRIX3x3D& aTransformation ); /// @copydoc GAL::Rotate() virtual void Rotate( double aAngle ); @@ -283,8 +283,6 @@ private: wxPoint savedCursorPosition; ///< The last cursor position wxBitmap* cursorPixels; ///< Cursor pixels wxBitmap* cursorPixelsSaved; ///< Saved cursor pixels - int cursorSize; ///< Cursor size - VECTOR2D cursorPosition; ///< Current cursor position /// Maximum number of arguments for one command static const int MAX_CAIRO_ARGUMENTS = 6; @@ -354,8 +352,10 @@ private: */ void skipMouseEvent( wxMouseEvent& aEvent ); - /// @copydoc GAL::initCursor() - virtual void initCursor( int aCursorSize ); + /** + * @brief Prepares cursor bitmap. + */ + virtual void initCursor(); /** * @brief Blits cursor into the current screen. @@ -386,6 +386,9 @@ private: /// Format used to store pixels static const cairo_format_t GAL_FORMAT = CAIRO_FORMAT_RGB24; + + ///> Opacity of a single layer + static const float LAYER_ALPHA = 0.8; }; } // namespace KIGFX diff --git a/include/gal/graphics_abstraction_layer.h b/include/gal/graphics_abstraction_layer.h index 7745dfa172..50b5c355c7 100644 --- a/include/gal/graphics_abstraction_layer.h +++ b/include/gal/graphics_abstraction_layer.h @@ -31,8 +31,6 @@ #include #include -#include - #include #include @@ -162,7 +160,7 @@ public: virtual bool Show( bool aShow ) = 0; /// @brief Returns GAL canvas size in pixels - VECTOR2D GetScreenPixelSize() const + const VECTOR2I& GetScreenPixelSize() const { return screenSize; } @@ -222,7 +220,7 @@ public: * * @return the color for stroking the outline. */ - inline COLOR4D GetStrokeColor() + inline const COLOR4D& GetStrokeColor() const { return strokeColor; } @@ -252,7 +250,7 @@ public: * * @return the actual line width. */ - inline double GetLineWidth() + inline double GetLineWidth() const { return lineWidth; } @@ -335,7 +333,7 @@ public: * * @param aTransformation is the ransformation matrix. */ - virtual void Transform( MATRIX3x3D aTransformation ) = 0; + virtual void Transform( const MATRIX3x3D& aTransformation ) = 0; /** * @brief Rotate the context. @@ -428,11 +426,21 @@ public: * * @return the transformation matrix. */ - MATRIX3x3D GetWorldScreenMatrix() + const MATRIX3x3D& GetWorldScreenMatrix() const { return worldScreenMatrix; } + /** + * @brief Get the screen <-> world transformation matrix. + * + * @return the transformation matrix. + */ + const MATRIX3x3D& GetScreenWorldMatrix() const + { + return screenWorldMatrix; + } + /** * @brief Set the world <-> screen transformation matrix. * @@ -487,7 +495,7 @@ public: * * @return the look at point. */ - inline VECTOR2D GetLookAtPoint() + inline const VECTOR2D& GetLookAtPoint() const { return lookAtPoint; } @@ -507,7 +515,7 @@ public: * * @return the zoom factor. */ - inline double GetZoomFactor() + inline double GetZoomFactor() const { return zoomFactor; } @@ -528,7 +536,7 @@ public: /** * @brief Returns the minimum depth in the currently used range (the top). */ - inline double GetMinDepth() + inline double GetMinDepth() const { return depthRange.x; } @@ -536,7 +544,7 @@ public: /** * @brief Returns the maximum depth in the currently used range (the bottom). */ - inline double GetMaxDepth() + inline double GetMaxDepth() const { return depthRange.y; } @@ -546,7 +554,7 @@ public: * * @return the actual world scale factor. */ - inline double GetWorldScale() + inline double GetWorldScale() const { return worldScale; } @@ -694,7 +702,7 @@ public: * * @return the grid line width */ - inline double GetGridLineWidth() + inline double GetGridLineWidth() const { return gridLineWidth; } @@ -709,19 +717,17 @@ public: gridLineWidth = aGridLineWidth; } - /// @brief Draw the grid + ///> @brief Draw the grid void DrawGrid(); - /** * Function GetGridPoint() - * For a given point it returns the nearest point belonging to the grid. + * For a given point it returns the nearest point belonging to the grid in world coordinates. * * @param aPoint is the point for which the grid point is searched. - * @return The nearest grid point. + * @return The nearest grid point in world coordinates. */ - VECTOR2D GetGridPoint( VECTOR2D aPoint ) const; - + VECTOR2D GetGridPoint( const VECTOR2D& aPoint ) const; /** * @brief Change the grid display style. @@ -739,7 +745,7 @@ public: * @param aPoint the pointposition in screen coordinates. * @return the point position in world coordinates. */ - inline virtual VECTOR2D ToWorld( const VECTOR2D& aPoint ) const + inline VECTOR2D ToWorld( const VECTOR2D& aPoint ) const { return VECTOR2D( screenWorldMatrix * aPoint ); } @@ -750,15 +756,15 @@ public: * @param aPoint the pointposition in world coordinates. * @return the point position in screen coordinates. */ - inline virtual VECTOR2D ToScreen( const VECTOR2D& aPoint ) const + inline VECTOR2D ToScreen( const VECTOR2D& aPoint ) const { return VECTOR2D( worldScreenMatrix * aPoint ); } /** - * @brief Enable/Disable cursor. + * @brief Enable/disable cursor. * - * @param aIsCursorEnabled is true if the cursor should be enabled, else false. + * @param aCursorEnabled is true if the cursor should be drawn, else false. */ inline void SetCursorEnabled( bool aCursorEnabled ) { @@ -778,7 +784,7 @@ public: /** * @brief Set the cursor size. * - * @param aCursorSize is the size of the cursor. + * @param aCursorSize is the size of the cursor expressed in pixels. */ inline void SetCursorSize( unsigned int aCursorSize ) { @@ -821,9 +827,11 @@ public: /// Depth level on which the grid is drawn static const int GRID_DEPTH = 1024; + static const double METRIC_UNIT_LENGTH = 1e9; + protected: std::stack depthStack; ///< Stored depth values - VECTOR2D screenSize; ///< Screen size in screen coordinates + VECTOR2I screenSize; ///< Screen size in screen coordinates double worldUnitLength; ///< The unit length of the world coordinates [inch] double screenDPI; ///< The dots per inch of the screen @@ -862,7 +870,8 @@ protected: bool isCursorEnabled; ///< Is the cursor enabled? COLOR4D cursorColor; ///< Cursor color - int cursorSize; ///< Size of the cursor in pixels + unsigned int cursorSize; ///< Size of the cursor in pixels + VECTOR2D cursorPosition; ///< Current cursor position (world coordinates) /// Instance of object that stores information about how to draw texts STROKE_FONT strokeFont; @@ -881,13 +890,6 @@ protected: */ virtual void drawGridLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ) = 0; - /** - * @brief Initialize the cursor. - * - * @param aCursorSize is the size of the cursor. - */ - virtual void initCursor( int aCursorSize ) = 0; - static const int MIN_DEPTH = -2048; static const int MAX_DEPTH = 2047; }; diff --git a/include/gal/opengl/opengl_gal.h b/include/gal/opengl/opengl_gal.h index 401f0a4411..d5c97aada9 100644 --- a/include/gal/opengl/opengl_gal.h +++ b/include/gal/opengl/opengl_gal.h @@ -145,19 +145,12 @@ public: /// @copydoc GAL::ClearScreen() virtual void ClearScreen(); - // ----------------- - // Attribute setting - // ----------------- - - /// @copydoc GAL::SetStrokeColor() - virtual void SetStrokeColor( const COLOR4D& aColor ); - // -------------- // Transformation // -------------- /// @copydoc GAL::Transform() - virtual void Transform( MATRIX3x3D aTransformation ); + virtual void Transform( const MATRIX3x3D& aTransformation ); /// @copydoc GAL::Rotate() virtual void Rotate( double aAngle ); @@ -299,8 +292,6 @@ private: bool isShaderInitialized; ///< Was the shader initialized? bool isGrouping; ///< Was a group started? - VECTOR2D cursorPosition; ///< Current cursor position - // Polygon tesselation /// The tessellator GLUtesselator* tesselator; @@ -313,7 +304,7 @@ private: * @param aStartPoint is the start point of the line. * @param aEndPoint is the end point of the line. */ - inline void drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ); + void drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ); /** * @brief Draw a semicircle. Depending on settings (isStrokeEnabled & isFilledEnabled) it runs @@ -364,9 +355,6 @@ private: /// Initialize GLEW void initGlew(); - /// @copydoc GAL::initCursor() - virtual void initCursor( int aCursorSize ); - /** * @brief Blits cursor into the current screen. */ diff --git a/include/geometry/seg.h b/include/geometry/seg.h index b400930ef2..cf5b8d50c9 100644 --- a/include/geometry/seg.h +++ b/include/geometry/seg.h @@ -46,7 +46,8 @@ public: * to an object the segment belongs to (e.g. a line chain) or references to locally stored * points (m_a, m_b). */ - VECTOR2I& A, B; + VECTOR2I& A; + VECTOR2I& B; /** Default constructor * Creates an empty (0, 0) segment, locally-referenced @@ -203,6 +204,8 @@ public: bool Collide( const SEG& aSeg, int aClearance ) const; + ecoord SquaredDistance( const SEG& aSeg ) const; + /** * Function Distance() * @@ -210,14 +213,16 @@ public: * @param aSeg other segment * @return minimum distance */ - - ecoord SquaredDistance( const SEG& aSeg ) const; - int Distance( const SEG& aSeg ) const { return sqrt( SquaredDistance( aSeg ) ); } + ecoord SquaredDistance( const VECTOR2I& aP ) const + { + return ( NearestPoint( aP ) - aP ).SquaredEuclideanNorm(); + } + /** * Function Distance() * @@ -225,11 +230,6 @@ public: * @param aP the point * @return minimum distance */ - ecoord SquaredDistance( const VECTOR2I& aP ) const - { - return ( NearestPoint( aP ) - aP ).SquaredEuclideanNorm(); - } - int Distance( const VECTOR2I& aP ) const { return sqrt( SquaredDistance( aP ) ); @@ -244,14 +244,14 @@ public: */ bool Collinear( const SEG& aSeg ) const { - ecoord qa1 = A.y - B.y; - ecoord qb1 = B.x - A.x; - ecoord qc1 = -qa1 * A.x - qb1 * A.y; - ecoord qa2 = aSeg.A.y - aSeg.B.y; - ecoord qb2 = aSeg.B.x - aSeg.A.x; - ecoord qc2 = -qa2 * aSeg.A.x - qb2 * aSeg.A.y; + ecoord qa = A.y - B.y; + ecoord qb = B.x - A.x; + ecoord qc = -qa * A.x - qb * A.y; - return ( qa1 == qa2 ) && ( qb1 == qb2 ) && ( qc1 == qc2 ); + ecoord d1 = std::abs( aSeg.A.x * qa + aSeg.A.y * qb + qc ); + ecoord d2 = std::abs( aSeg.B.x * qa + aSeg.B.y * qb + qc ); + + return ( d1 <= 1 && d2 <= 1 ); } /** diff --git a/include/geometry/shape_line_chain.h b/include/geometry/shape_line_chain.h index 5108191bb7..da6494e91a 100644 --- a/include/geometry/shape_line_chain.h +++ b/include/geometry/shape_line_chain.h @@ -415,7 +415,7 @@ public: * @param aP the point to be looked for * @return index of the correspoinding point in the line chain or negative when not found. */ - int Find ( const VECTOR2I& aP ) const; + int Find( const VECTOR2I& aP ) const; /** * Function Slice() diff --git a/include/layers_id_colors_and_visibility.h b/include/layers_id_colors_and_visibility.h index dd3943bcd0..5b73d4f266 100644 --- a/include/layers_id_colors_and_visibility.h +++ b/include/layers_id_colors_and_visibility.h @@ -246,6 +246,7 @@ enum PCB_VISIBLE PADS_HOLES_VISIBLE, VIAS_HOLES_VISIBLE, + DRC_VISIBLE, ///< drc markers WORKSHEET, ///< worksheet frame GP_OVERLAY, ///< general purpose overlay diff --git a/include/math/box2.h b/include/math/box2.h index 8ed1621935..467558e676 100644 --- a/include/math/box2.h +++ b/include/math/box2.h @@ -28,24 +28,9 @@ #define __BOX2_H #include +#include -template -class BOX2_TRAITS -{ -}; - -template <> -class BOX2_TRAITS -{ -public: - enum - { - c_max_size = INT_MAX - 1, - c_min_coord_value = INT_MIN / 2 + 1 - }; -}; - /** * Class BOX2 * handles a 2-D bounding box, built on top of an origin point @@ -59,8 +44,9 @@ private: Vec m_Size; // Rectangle Size public: - typedef typename Vec::coord_type coord_type; - typedef typename Vec::extended_type ecoord_type; + typedef typename Vec::coord_type coord_type; + typedef typename Vec::extended_type ecoord_type; + typedef typename std::numeric_limits coord_limits; BOX2() {}; @@ -73,8 +59,8 @@ public: void SetMaximum() { - m_Pos.x = m_Pos.y = BOX2_TRAITS().c_min_coord_value; - m_Size.x = m_Size.y = BOX2_TRAITS().c_max_size; + m_Pos.x = m_Pos.y = coord_limits::min() / 2 + coord_limits::epsilon(); + m_Size.x = m_Size.y = coord_limits::max() - coord_limits::epsilon(); } Vec Centre() const diff --git a/include/painter.h b/include/painter.h index 004c93e35e..34376d985d 100644 --- a/include/painter.h +++ b/include/painter.h @@ -109,6 +109,26 @@ public: return ( m_activeLayers.count( aLayerId ) > 0 ); } + /** + * Function GetHighlight + * Returns current highlight setting. + * @return True if highlight is enabled, false otherwise. + */ + bool GetHighlight() const + { + return m_highlightEnabled; + } + + /** + * Function GetHighlightNetCode + * Returns netcode of currently highlighted net. + * @return Netcode of currently highlighted net. + */ + int GetHighlightNetCode() const + { + return m_highlightNetcode; + } + /** * Function SetHighlight * Turns on/off highlighting - it may be done for the active layer or the specified net. @@ -119,9 +139,7 @@ public: inline void SetHighlight( bool aEnabled, int aNetcode = -1 ) { m_highlightEnabled = aEnabled; - - if( aNetcode > 0 ) - m_highlightNetcode = aNetcode; + m_highlightNetcode = aNetcode; } /** diff --git a/include/tool/action_manager.h b/include/tool/action_manager.h index fa66a23eba..626f795eff 100644 --- a/include/tool/action_manager.h +++ b/include/tool/action_manager.h @@ -25,6 +25,7 @@ #ifndef ACTION_MANAGER_H_ #define ACTION_MANAGER_H_ +#include #include #include @@ -81,6 +82,14 @@ public: */ bool RunAction( const std::string& aActionName ) const; + /** + * Function RunAction() + * Prepares an appropriate event and sends it to the destination specified in a TOOL_ACTION + * object. + * @param aAction is the action to be run. + */ + void RunAction( const TOOL_ACTION* aAction ) const; + /** * Function RunHotKey() * Runs an action associated with a hotkey (if there is one available). @@ -89,13 +98,6 @@ public: */ bool RunHotKey( int aHotKey ) const; - /** - * Function ClearHotKey() - * Removes an action associated with a hotkey. - * @param aHotKey is the hotkey to be cleared. - */ - void ClearHotKey( int aHotKey ); - private: ///> Tool manager needed to run actions TOOL_MANAGER* m_toolMgr; @@ -107,15 +109,8 @@ private: std::map m_actionNameIndex; ///> Map for indexing actions by their hotkeys - std::map m_actionHotKeys; - - /** - * Function runAction() - * Prepares an appropriate event and sends it to the destination specified in a TOOL_ACTION - * object. - * @param aAction is the action to be run. - */ - void runAction( const TOOL_ACTION* aAction ) const; + typedef std::map > HOTKEY_LIST; + HOTKEY_LIST m_actionHotKeys; }; #endif /* ACTION_MANAGER_H_ */ diff --git a/include/tool/tool_action.h b/include/tool/tool_action.h index 8a3e7c4111..8fb81e5d8d 100644 --- a/include/tool/tool_action.h +++ b/include/tool/tool_action.h @@ -30,7 +30,7 @@ #include #include -#include +#include /** * Class TOOL_ACTION @@ -50,14 +50,14 @@ public: const std::string& aMenuDesc = std::string( "" ) ) : m_name( aName ), m_scope( aScope ), m_defaultHotKey( aDefaultHotKey ), m_currentHotKey( aDefaultHotKey ), m_menuItem( aMenuItem ), - m_menuDescription( aMenuDesc ), m_id( -1 ), m_actionMgr( NULL ) + m_menuDescription( aMenuDesc ), m_id( -1 ) { + TOOL_MANAGER::Instance().RegisterAction( this ); } ~TOOL_ACTION() { - if( m_actionMgr ) - m_actionMgr->UnregisterAction( this ); + TOOL_MANAGER::Instance().UnregisterAction( this ); } bool operator==( const TOOL_ACTION& aRhs ) const @@ -171,6 +171,21 @@ public: m_menuDescription = aDescription; } + TOOL_ACTION_SCOPE GetScope() const + { + return m_scope; + } + + /** + * Returns name of the tool associated with the action. It is basically the action name + * stripped of the last part (e.g. for "pcbnew.InteractiveDrawing.drawCircle" it is + * "pcbnew.InteractiveDrawing"). + */ + std::string GetToolName() const + { + return m_name.substr( 0, m_name.rfind( '.' ) ); + } + private: friend class ACTION_MANAGER; @@ -180,12 +195,6 @@ private: m_id = aId; } - /// Assigns ACTION_MANAGER object that handles the TOOL_ACTION. - void setActionMgr( ACTION_MANAGER* aManager ) - { - m_actionMgr = aManager; - } - /// Name of the action (convention is: app.[tool.]action.name) std::string m_name; @@ -210,9 +219,6 @@ private: /// Unique ID for fast matching. Assigned by ACTION_MANAGER. int m_id; - /// Action manager that handles this TOOL_ACTION. - ACTION_MANAGER* m_actionMgr; - /// Origin of the action // const TOOL_BASE* m_origin; diff --git a/include/tool/tool_dispatcher.h b/include/tool/tool_dispatcher.h index 3a9be1ac64..8ecd893db1 100644 --- a/include/tool/tool_dispatcher.h +++ b/include/tool/tool_dispatcher.h @@ -79,7 +79,7 @@ public: * specified tool). * @param aEvent is the wxCommandEvent to be processed. */ - virtual void DispatchWxCommand( const wxCommandEvent& aEvent ); + virtual void DispatchWxCommand( wxCommandEvent& aEvent ); private: ///> Number of mouse buttons that is handled in events. diff --git a/include/tool/tool_event.h b/include/tool/tool_event.h index 46b06e1eed..bdfe8a8a10 100644 --- a/include/tool/tool_event.h +++ b/include/tool/tool_event.h @@ -64,36 +64,35 @@ enum TOOL_ACTIONS TA_MOUSE_WHEEL = 0x0040, TA_MOUSE = 0x007f, - TA_KEY_UP = 0x0080, - TA_KEY_DOWN = 0x0100, - TA_KEYBOARD = TA_KEY_UP | TA_KEY_DOWN, + TA_KEY_PRESSED = 0x0080, + TA_KEYBOARD = TA_KEY_PRESSED, // View related events - TA_VIEW_REFRESH = 0x0200, - TA_VIEW_ZOOM = 0x0400, - TA_VIEW_PAN = 0x0800, - TA_VIEW_DIRTY = 0x1000, - TA_VIEW = 0x1e00, + TA_VIEW_REFRESH = 0x0100, + TA_VIEW_ZOOM = 0x0200, + TA_VIEW_PAN = 0x0400, + TA_VIEW_DIRTY = 0x0800, + TA_VIEW = 0x0f00, - TA_CHANGE_LAYER = 0x2000, + TA_CHANGE_LAYER = 0x1000, // Tool cancel event. Issued automagically when the user hits escape or selects End Tool from // the context menu. - TA_CANCEL_TOOL = 0x4000, + TA_CANCEL_TOOL = 0x2000, // Context menu update. Issued whenever context menu is open and the user hovers the mouse // over one of choices. Used in dynamic highligting in disambiguation menu - TA_CONTEXT_MENU_UPDATE = 0x8000, + TA_CONTEXT_MENU_UPDATE = 0x4000, // Context menu choice. Sent if the user picked something from the context menu or // closed it without selecting anything. - TA_CONTEXT_MENU_CHOICE = 0x10000, + TA_CONTEXT_MENU_CHOICE = 0x8000, // This event is sent *before* undo/redo command is performed. - TA_UNDO_REDO = 0x20000, + TA_UNDO_REDO = 0x10000, // Tool action (allows to control tools) - TA_ACTION = 0x40000, + TA_ACTION = 0x20000, TA_ANY = 0xffffffff }; @@ -189,7 +188,7 @@ public: m_scope( aScope ), m_mouseButtons( 0 ) { - if( aCategory == TC_COMMAND ) + if( aCategory == TC_COMMAND || aCategory == TC_MESSAGE ) m_commandStr = aExtraParam; } @@ -207,7 +206,7 @@ public: ///> Returns information about difference between current mouse cursor position and the place ///> where dragging has started. - const VECTOR2D Delta() const + const VECTOR2D& Delta() const { assert( m_category == TC_MOUSE ); // this should be used only with mouse events return m_mouseDelta; @@ -277,14 +276,9 @@ public: return m_keyCode; } - bool IsKeyUp() const + bool IsKeyPressed() const { - return m_actions == TA_KEY_UP; - } - - bool IsKeyDown() const - { - return m_actions == TA_KEY_DOWN; + return m_actions == TA_KEY_PRESSED; } void SetMouseDragOrigin( const VECTOR2D& aP ) @@ -317,7 +311,7 @@ public: if( !( m_actions & aEvent.m_actions ) ) return false; - if( m_category == TC_COMMAND ) + if( m_category == TC_COMMAND || m_category == TC_MESSAGE ) { if( m_commandStr && aEvent.m_commandStr ) return *m_commandStr == *aEvent.m_commandStr; diff --git a/include/tool/tool_interactive.h b/include/tool/tool_interactive.h index 7e816bd3a4..1888011b5f 100644 --- a/include/tool/tool_interactive.h +++ b/include/tool/tool_interactive.h @@ -48,6 +48,12 @@ public: TOOL_INTERACTIVE( const std::string& aName ); virtual ~TOOL_INTERACTIVE(); + /** + * Function Activate() + * Runs the tool. After activation, the tool starts receiving events until it is finished. + */ + void Activate(); + /** * Function SetContextMenu() * diff --git a/include/tool/tool_manager.h b/include/tool/tool_manager.h index 6e9c18acb0..1e4563a7e0 100644 --- a/include/tool/tool_manager.h +++ b/include/tool/tool_manager.h @@ -48,9 +48,20 @@ class wxWindow; class TOOL_MANAGER { public: - TOOL_MANAGER(); + static TOOL_MANAGER& Instance() + { + static TOOL_MANAGER manager; + + return manager; + } + ~TOOL_MANAGER(); + /** + * Deletes all the tools that were registered in the TOOL_MANAGER. + */ + void DeleteAll(); + /** * Generates an unique ID from for a tool with given name. */ @@ -101,13 +112,21 @@ public: /** * Function RunAction() - * Runs the specified action. The common format is "application.ToolName.Action". + * Runs the specified action. The common format for action names is "application.ToolName.Action". * * @param aActionName is the name of action to be invoked. * @return True if the action finished successfully, false otherwise. */ bool RunAction( const std::string& aActionName ); + /** + * Function RunAction() + * Runs the specified action. + * + * @param aAction is the action to be invoked. + */ + void RunAction( const TOOL_ACTION& aAction ); + /** * Function FindTool() * Searches for a tool with given ID. @@ -167,6 +186,36 @@ public: return m_editFrame; } + /** + * Returns id of the tool that is on the top of the active tools stack + * (was invoked the most recently). + * @return Id of the currently used tool. + */ + int GetCurrentToolId() const + { + return m_activeTools.front(); + } + + /** + * Returns the tool that is on the top of the active tools stack + * (was invoked the most recently). + * @return Pointer to the currently used tool. + */ + TOOL_BASE* GetCurrentTool() const + { + return FindTool( GetCurrentToolId() ); + } + + /** + * Returns priority of a given tool. Higher number means that the tool is closer to the + * beginning of the active tools queue (i.e. receives events earlier, tools with lower + * priority receive events later). + * @param aToolId is the id of queried tool. + * @return The priority of a given tool. If returned number is negative, then it means that + * the tool id is invalid or the tool is not active. + */ + int GetPriority( int aToolId ) const; + /** * Defines a state transition - the events that cause a given handler method in the tool * to be called. Called by TOOL_INTERACTIVE::Go(). May be called from a coroutine context. @@ -203,6 +252,8 @@ public: } private: + TOOL_MANAGER(); + struct TOOL_STATE; typedef std::pair TRANSITION; diff --git a/include/ttl/halfedge/hedart.h b/include/ttl/halfedge/hedart.h index f85678963a..2749c5087c 100644 --- a/include/ttl/halfedge/hedart.h +++ b/include/ttl/halfedge/hedart.h @@ -40,111 +40,152 @@ #ifndef _HALF_EDGE_DART_ #define _HALF_EDGE_DART_ - #include +namespace hed +{ +/** + * \class Dart + * \brief \b %Dart class for the half-edge data structure. + * + * See \ref api for a detailed description of how the member functions + * should be implemented. + */ +class DART +{ + EDGE_PTR m_edge; -namespace hed { + /// Dart direction: true if dart is counterclockwise in face + bool m_dir; - - //------------------------------------------------------------------------------------------------ - // Dart class for the half-edge data structure - //------------------------------------------------------------------------------------------------ - - /** \class Dart - * \brief \b %Dart class for the half-edge data structure. - * - * See \ref api for a detailed description of how the member functions - * should be implemented. - */ - - class Dart { - - EdgePtr edge_; - bool dir_; // true if dart is counterclockwise in face - - public: +public: /// Default constructor - Dart() { dir_ = true; } + DART() + { + m_dir = true; + } /// Constructor - Dart(const EdgePtr& edge, bool dir = true) { edge_ = edge; dir_ = dir; } + DART( const EDGE_PTR& aEdge, bool aDir = true ) + { + m_edge = aEdge; + m_dir = aDir; + } /// Copy constructor - Dart(const Dart& dart) { edge_ = dart.edge_; dir_ = dart.dir_; } + DART( const DART& aDart ) + { + m_edge = aDart.m_edge; + m_dir = aDart.m_dir; + } /// Destructor - ~Dart() {} + ~DART() + { + } /// Assignment operator - Dart& operator = (const Dart& dart) { - if (this == &dart) + DART& operator=( const DART& aDart ) + { + if( this == &aDart ) + return *this; + + m_edge = aDart.m_edge; + m_dir = aDart.m_dir; + return *this; - edge_ = dart.edge_; - dir_ = dart.dir_; - return *this; } /// Comparing dart objects - bool operator==(const Dart& dart) const { - if (dart.edge_ == edge_ && dart.dir_ == dir_) - return true; - return false; + bool operator==( const DART& aDart ) const + { + return ( aDart.m_edge == m_edge && aDart.m_dir == m_dir ); } /// Comparing dart objects - bool operator!=(const Dart& dart) const { - return !(dart==*this); + bool operator!=( const DART& aDart ) const + { + return !( aDart == *this ); } /// Maps the dart to a different node - Dart& alpha0() { dir_ = !dir_; return *this; } + DART& Alpha0() + { + m_dir = !m_dir; + return *this; + } /// Maps the dart to a different edge - Dart& alpha1() { - if (dir_) { - edge_ = edge_->getNextEdgeInFace()->getNextEdgeInFace(); - dir_ = false; - } - else { - edge_ = edge_->getNextEdgeInFace(); - dir_ = true; - } - return *this; + DART& Alpha1() + { + if( m_dir ) + { + m_edge = m_edge->GetNextEdgeInFace()->GetNextEdgeInFace(); + m_dir = false; + } + else + { + m_edge = m_edge->GetNextEdgeInFace(); + m_dir = true; + } + + return *this; } /// Maps the dart to a different triangle. \b Note: the dart is not changed if it is at the boundary! - Dart& alpha2() { - if (edge_->getTwinEdge()) { - edge_ = edge_->getTwinEdge(); - dir_ = !dir_; - } - // else, the dart is at the boundary and should not be changed - return *this; + DART& Alpha2() + { + if( m_edge->GetTwinEdge() ) + { + m_edge = m_edge->GetTwinEdge(); + m_dir = !m_dir; + } + + // else, the dart is at the boundary and should not be changed + return *this; } - - // Utilities not required by TTL - // ----------------------------- - /** @name Utilities not required by TTL */ //@{ + void Init( const EDGE_PTR& aEdge, bool aDir = true ) + { + m_edge = aEdge; + m_dir = aDir; + } - void init(const EdgePtr& edge, bool dir = true) { edge_ = edge; dir_ = dir; } + double X() const + { + return GetNode()->GetX(); + } - double x() const { return getNode()->GetX(); } // x-coordinate of source node - double y() const { return getNode()->GetY(); } // y-coordinate of source node + double Y() const + { + return GetNode()->GetY(); + } - bool isCounterClockWise() const { return dir_; } + bool IsCCW() const + { + return m_dir; + } - const NodePtr& getNode() const { return dir_ ? edge_->getSourceNode() : edge_->getTargetNode(); } - const NodePtr& getOppositeNode() const { return dir_ ? edge_->getTargetNode() : edge_->getSourceNode(); } - EdgePtr& getEdge() { return edge_; } + const NODE_PTR& GetNode() const + { + return m_dir ? m_edge->GetSourceNode() : m_edge->GetTargetNode(); + } + + const NODE_PTR& GetOppositeNode() const + { + return m_dir ? m_edge->GetTargetNode() : m_edge->GetSourceNode(); + } + + EDGE_PTR& GetEdge() + { + return m_edge; + } //@} // End of Utilities not required by TTL +}; - }; - -}; // End of hed namespace +} // End of hed namespace #endif diff --git a/include/ttl/halfedge/hetraits.h b/include/ttl/halfedge/hetraits.h index e24cd0697d..04288a0ba5 100644 --- a/include/ttl/halfedge/hetraits.h +++ b/include/ttl/halfedge/hetraits.h @@ -40,136 +40,149 @@ #ifndef _HALF_EDGE_TRAITS_ #define _HALF_EDGE_TRAITS_ - #include #include - -namespace hed { - - - //------------------------------------------------------------------------------------------------ - // Traits class for the half-edge data structure - //------------------------------------------------------------------------------------------------ - - /** \struct TTLtraits - * \brief \b Traits class (static struct) for the half-edge data structure. - * - * The member functions are those required by different function templates - * in the TTL. Documentation is given here to explain what actions - * should be carried out on the actual data structure as required by the functions - * in the \ref ttl namespace. - * - * The source code of \c %HeTraits.h shows how the traits class is implemented for the - * half-edge data structure. - * - * \see \ref api - * - */ - - struct TTLtraits { +namespace hed +{ +/** + * \struct TTLtraits + * \brief \b Traits class (static struct) for the half-edge data structure. + * + * The member functions are those required by different function templates + * in the TTL. Documentation is given here to explain what actions + * should be carried out on the actual data structure as required by the functions + * in the \ref ttl namespace. + * + * The source code of \c %HeTraits.h shows how the traits class is implemented for the + * half-edge data structure. + * + * \see \ref api + */ +struct TTLtraits +{ + /** + * The floating point type used in calculations involving scalar products and cross products. + */ + typedef double REAL_TYPE; - /** The floating point type used in calculations - * involving scalar products and cross products. - */ - typedef double real_type; - - - //---------------------------------------------------------------------------------------------- - // ------------------------------- Geometric Predicates Group --------------------------------- - //---------------------------------------------------------------------------------------------- - /** @name Geometric Predicates */ //@{ + /** + * Scalar product between two 2D vectors represented as darts.\n + * + * ttl_util::scalarProduct2d can be used. + */ + static REAL_TYPE ScalarProduct2D( const DART& aV1, const DART& aV2 ) + { + DART v10 = aV1; + v10.Alpha0(); - //---------------------------------------------------------------------------------------------- - /** Scalar product between two 2D vectors represented as darts.\n - * - * ttl_util::scalarProduct2d can be used. - */ - static real_type scalarProduct2d(const Dart& v1, const Dart& v2) { - Dart v10 = v1; v10.alpha0(); - Dart v20 = v2; v20.alpha0(); - return ttl_util::scalarProduct2d(v10.x()-v1.x(), v10.y()-v1.y(), - v20.x()-v2.x(), v20.y()-v2.y()); + DART v20 = aV2; + v20.Alpha0(); + + return ttl_util::ScalarProduct2D( v10.X() - aV1.X(), v10.Y() - aV1.Y(), + v20.X() - aV2.X(), v20.Y() - aV2.Y() ); } + /** + * Scalar product between two 2D vectors. + * The first vector is represented by a dart \e v, and the second + * vector has direction from the source node of \e v to the point \e p.\n + * + * ttl_util::ScalarProduct2D can be used. + */ + static REAL_TYPE ScalarProduct2D( const DART& aV, const NODE_PTR& aP ) + { + DART d0 = aV; + d0.Alpha0(); - //---------------------------------------------------------------------------------------------- - /** Scalar product between two 2D vectors. - * The first vector is represented by a dart \e v, and the second - * vector has direction from the source node of \e v to the point \e p.\n - * - * ttl_util::scalarProduct2d can be used. - */ - static real_type scalarProduct2d(const Dart& v, const NodePtr& p) { - Dart d0 = v; d0.alpha0(); - return ttl_util::scalarProduct2d(d0.x() - v.x(), d0.y() - v.y(), - p->GetX() - v.x(), p->GetY() - v.y()); + return ttl_util::ScalarProduct2D( d0.X() - aV.X(), d0.Y() - aV.Y(), + aP->GetX() - aV.X(), aP->GetY() - aV.Y() ); } + /** + * Cross product between two vectors in the plane represented as darts. + * The z-component of the cross product is returned.\n + * + * ttl_util::CrossProduct2D can be used. + */ + static REAL_TYPE CrossProduct2D( const DART& aV1, const DART& aV2 ) + { + DART v10 = aV1; + v10.Alpha0(); - //---------------------------------------------------------------------------------------------- - /** Cross product between two vectors in the plane represented as darts. - * The z-component of the cross product is returned.\n - * - * ttl_util::crossProduct2d can be used. - */ - static real_type crossProduct2d(const Dart& v1, const Dart& v2) { - Dart v10 = v1; v10.alpha0(); - Dart v20 = v2; v20.alpha0(); - return ttl_util::crossProduct2d(v10.x()-v1.x(), v10.y()-v1.y(), - v20.x()-v2.x(), v20.y()-v2.y()); + DART v20 = aV2; + v20.Alpha0(); + + return ttl_util::CrossProduct2D( v10.X() - aV1.X(), v10.Y() - aV1.Y(), + v20.X() - aV2.X(), v20.Y() - aV2.Y() ); } + /** + * Cross product between two vectors in the plane. + * The first vector is represented by a dart \e v, and the second + * vector has direction from the source node of \e v to the point \e p. + * The z-component of the cross product is returned.\n + * + * ttl_util::CrossProduct2d can be used. + */ + static REAL_TYPE CrossProduct2D( const DART& aV, const NODE_PTR& aP ) + { + DART d0 = aV; + d0.Alpha0(); - //---------------------------------------------------------------------------------------------- - /** Cross product between two vectors in the plane. - * The first vector is represented by a dart \e v, and the second - * vector has direction from the source node of \e v to the point \e p. - * The z-component of the cross product is returned.\n - * - * ttl_util::crossProduct2d can be used. - */ - static real_type crossProduct2d(const Dart& v, const NodePtr& p) { - Dart d0 = v; d0.alpha0(); - return ttl_util::crossProduct2d(d0.x() - v.x(), d0.y() - v.y(), - p->GetX() - v.x(), p->GetY() - v.y()); + return ttl_util::CrossProduct2D( d0.X() - aV.X(), d0.Y() - aV.Y(), + aP->GetX() - aV.X(), aP->GetY() - aV.Y() ); } + /** + * Let \e n1 and \e n2 be the nodes associated with two darts, and let \e p + * be a point in the plane. Return a positive value if \e n1, \e n2, + * and \e p occur in counterclockwise order; a negative value if they occur + * in clockwise order; and zero if they are collinear. + */ + static REAL_TYPE Orient2D( const DART& aN1, const DART& aN2, const NODE_PTR& aP ) + { + REAL_TYPE pa[2]; + REAL_TYPE pb[2]; + REAL_TYPE pc[2]; - //---------------------------------------------------------------------------------------------- - /** Let \e n1 and \e n2 be the nodes associated with two darts, and let \e p - * be a point in the plane. Return a positive value if \e n1, \e n2, - * and \e p occur in counterclockwise order; a negative value if they occur - * in clockwise order; and zero if they are collinear. - */ - static real_type orient2d(const Dart& n1, const Dart& n2, const NodePtr& p) { - real_type pa[2]; real_type pb[2]; real_type pc[2]; - pa[0] = n1.x(); pa[1] = n1.y(); - pb[0] = n2.x(); pb[1] = n2.y(); - pc[0] = p->GetX(); pc[1] = p->GetY(); - return ttl_util::orient2dfast(pa, pb, pc); + pa[0] = aN1.X(); + pa[1] = aN1.Y(); + pb[0] = aN2.X(); + pb[1] = aN2.Y(); + pc[0] = aP->GetX(); + pc[1] = aP->GetY(); + + return ttl_util::Orient2DFast( pa, pb, pc ); } + /** + * This is the same predicate as represented with the function above, + * but with a slighty different interface: + * The last parameter is given as a dart where the source node of the dart + * represents a point in the plane. + * This function is required for constrained triangulation. + */ + static REAL_TYPE Orient2D( const DART& aN1, const DART& aN2, const DART& aP ) + { + REAL_TYPE pa[2]; + REAL_TYPE pb[2]; + REAL_TYPE pc[2]; - //---------------------------------------------------------------------------------------------- - /** This is the same predicate as represented with the function above, - * but with a slighty different interface: - * The last parameter is given as a dart where the source node of the dart - * represents a point in the plane. - * This function is required for constrained triangulation. - */ - static real_type orient2d(const Dart& n1, const Dart& n2, const Dart& p) { - real_type pa[2]; real_type pb[2]; real_type pc[2]; - pa[0] = n1.x(); pa[1] = n1.y(); - pb[0] = n2.x(); pb[1] = n2.y(); - pc[0] = p.x(); pc[1] = p.y(); - return ttl_util::orient2dfast(pa, pb, pc); + pa[0] = aN1.X(); + pa[1] = aN1.Y(); + pb[0] = aN2.X(); + pb[1] = aN2.Y(); + pc[0] = aP.X(); + pc[1] = aP.Y(); + + return ttl_util::Orient2DFast( pa, pb, pc ); } //@} // End of Geometric Predicates Group - }; +}; }; // End of hed namespace diff --git a/include/ttl/halfedge/hetriang.h b/include/ttl/halfedge/hetriang.h index 2c5380864e..f84c542e5a 100644 --- a/include/ttl/halfedge/hetriang.h +++ b/include/ttl/halfedge/hetriang.h @@ -42,11 +42,9 @@ #ifndef _HE_TRIANG_H_ #define _HE_TRIANG_H_ - #define TTL_USE_NODE_ID // Each node gets it's own unique id #define TTL_USE_NODE_FLAG // Each node gets a flag (can be set to true or false) - #include #include #include @@ -55,43 +53,40 @@ #include #include -namespace ttl { - class TriangulationHelper; +namespace ttl +{ + class TRIANGULATION_HELPER; }; -//-------------------------------------------------------------------------------------------------- -// The half-edge data structure -//-------------------------------------------------------------------------------------------------- - -namespace hed { - // Helper typedefs - class Node; - class Edge; - typedef boost::shared_ptr NodePtr; - typedef boost::shared_ptr EdgePtr; - typedef boost::weak_ptr EdgeWeakPtr; - typedef std::vector NodesContainer; - - //------------------------------------------------------------------------------------------------ - // Node class for data structures - //------------------------------------------------------------------------------------------------ - - /** \class Node - * \brief \b Node class for data structures (Inherits from HandleId) - * - * \note - * - To enable node IDs, TTL_USE_NODE_ID must be defined. - * - To enable node flags, TTL_USE_NODE_FLAG must be defined. - * - TTL_USE_NODE_ID and TTL_USE_NODE_FLAG should only be enabled if this functionality is - * required by the application, because they increase the memory usage for each Node object. - */ - - class Node { +/** + * The half-edge data structure + */ +namespace hed +{ +// Helper typedefs +class NODE; +class EDGE; +typedef boost::shared_ptr NODE_PTR; +typedef boost::shared_ptr EDGE_PTR; +typedef boost::weak_ptr EDGE_WEAK_PTR; +typedef std::vector NODES_CONTAINER; +/** + * \class NODE + * \brief \b Node class for data structures (Inherits from HandleId) + * + * \note + * - To enable node IDs, TTL_USE_NODE_ID must be defined. + * - To enable node flags, TTL_USE_NODE_FLAG must be defined. + * - TTL_USE_NODE_ID and TTL_USE_NODE_FLAG should only be enabled if this functionality is + * required by the application, because they increase the memory usage for each Node object. + */ +class NODE +{ protected: #ifdef TTL_USE_NODE_FLAG /// TTL_USE_NODE_FLAG must be defined - bool flag_; + bool m_flag; #endif #ifdef TTL_USE_NODE_ID @@ -99,303 +94,378 @@ protected: static int id_count; /// A unique id for each node (TTL_USE_NODE_ID must be defined) - int id_; + int m_id; #endif - int x_, y_; + /// Node coordinates + int m_x, m_y; - unsigned int refCount_; + /// Reference count + unsigned int m_refCount; public: /// Constructor - Node( int x = 0, int y = 0 ) : + NODE( int aX = 0, int aY = 0 ) : #ifdef TTL_USE_NODE_FLAG - flag_( false ), + m_flag( false ), #endif #ifdef TTL_USE_NODE_ID - id_( id_count++ ), + m_id( id_count++ ), #endif - x_( x ), y_( y ), refCount_( 0 ) {} + m_x( aX ), m_y( aY ), m_refCount( 0 ) + { + } /// Destructor - ~Node() {} + ~NODE() {} /// Returns the x-coordinate - int GetX() const { return x_; } + int GetX() const + { + return m_x; + } /// Returns the y-coordinate - int GetY() const { return y_; } + int GetY() const + { + return m_y; + } #ifdef TTL_USE_NODE_ID /// Returns the id (TTL_USE_NODE_ID must be defined) - int Id() const { return id_; } + int Id() const + { + return m_id; + } #endif #ifdef TTL_USE_NODE_FLAG /// Sets the flag (TTL_USE_NODE_FLAG must be defined) - void SetFlag(bool aFlag) { flag_ = aFlag; } + void SetFlag( bool aFlag ) + { + m_flag = aFlag; + } /// Returns the flag (TTL_USE_NODE_FLAG must be defined) - const bool& GetFlag() const { return flag_; } + const bool& GetFlag() const + { + return m_flag; + } #endif - void IncRefCount() { refCount_++; } - void DecRefCount() { refCount_--; } - unsigned int GetRefCount() const { return refCount_; } - }; // End of class Node + void IncRefCount() + { + m_refCount++; + } + + void DecRefCount() + { + m_refCount--; + } + + unsigned int GetRefCount() const + { + return m_refCount; + } +}; - //------------------------------------------------------------------------------------------------ - // Edge class in the half-edge data structure - //------------------------------------------------------------------------------------------------ - - /** \class Edge - * \brief \b %Edge class in the in the half-edge data structure. - */ - - class Edge { - public: +/** + * \class EDGE + * \brief \b %Edge class in the in the half-edge data structure. + */ +class EDGE +{ +public: /// Constructor - Edge() : weight_(0), isLeadingEdge_(false) {} + EDGE() : m_weight( 0 ), m_isLeadingEdge( false ) + { + } /// Destructor - virtual ~Edge() {} + virtual ~EDGE() + { + } /// Sets the source node - void setSourceNode(const NodePtr& node) { sourceNode_ = node; } + void SetSourceNode( const NODE_PTR& aNode ) + { + m_sourceNode = aNode; + } /// Sets the next edge in face - void setNextEdgeInFace(const EdgePtr& edge) { nextEdgeInFace_ = edge; } + void SetNextEdgeInFace( const EDGE_PTR& aEdge ) + { + m_nextEdgeInFace = aEdge; + } /// Sets the twin edge - void setTwinEdge(const EdgePtr& edge) { twinEdge_ = edge; } + void SetTwinEdge( const EDGE_PTR& aEdge ) + { + m_twinEdge = aEdge; + } /// Sets the edge as a leading edge - void setAsLeadingEdge(bool val=true) { isLeadingEdge_ = val; } + void SetAsLeadingEdge( bool aLeading = true ) + { + m_isLeadingEdge = aLeading; + } /// Checks if an edge is a leading edge - bool isLeadingEdge() const { return isLeadingEdge_; } + bool IsLeadingEdge() const + { + return m_isLeadingEdge; + } /// Returns the twin edge - EdgePtr getTwinEdge() const { return twinEdge_.lock(); }; + EDGE_PTR GetTwinEdge() const + { + return m_twinEdge.lock(); + } - void clearTwinEdge() { twinEdge_.reset(); } + void ClearTwinEdge() + { + m_twinEdge.reset(); + } /// Returns the next edge in face - const EdgePtr& getNextEdgeInFace() const { return nextEdgeInFace_; } + const EDGE_PTR& GetNextEdgeInFace() const + { + return m_nextEdgeInFace; + } /// Retuns the source node - const NodePtr& getSourceNode() const { return sourceNode_; } + const NODE_PTR& GetSourceNode() const + { + return m_sourceNode; + } /// Returns the target node - virtual const NodePtr& getTargetNode() const { return nextEdgeInFace_->getSourceNode(); } - - void setWeight( unsigned int weight ) { weight_ = weight; } - - unsigned int getWeight() const { return weight_; } - - void clear() + virtual const NODE_PTR& GetTargetNode() const { - sourceNode_.reset(); - nextEdgeInFace_.reset(); + return m_nextEdgeInFace->GetSourceNode(); + } - if( !twinEdge_.expired() ) + void SetWeight( unsigned int weight ) + { + m_weight = weight; + } + + unsigned int GetWeight() const + { + return m_weight; + } + + void Clear() + { + m_sourceNode.reset(); + m_nextEdgeInFace.reset(); + + if( !m_twinEdge.expired() ) { - twinEdge_.lock()->clearTwinEdge(); - twinEdge_.reset(); + m_twinEdge.lock()->ClearTwinEdge(); + m_twinEdge.reset(); } } - protected: - NodePtr sourceNode_; - EdgeWeakPtr twinEdge_; - EdgePtr nextEdgeInFace_; - unsigned int weight_; - bool isLeadingEdge_; - }; // End of class Edge +protected: + NODE_PTR m_sourceNode; + EDGE_WEAK_PTR m_twinEdge; + EDGE_PTR m_nextEdgeInFace; + unsigned int m_weight; + bool m_isLeadingEdge; +}; - /** \class EdgeMST - * \brief \b Specialization of %Edge class to be used for Minimum Spanning Tree algorithm. + /** + * \class EDGE_MST + * \brief \b Specialization of %EDGE class to be used for Minimum Spanning Tree algorithm. */ - class EdgeMST : public Edge - { - private: - NodePtr target_; +class EDGE_MST : public EDGE +{ +private: + NODE_PTR m_target; - public: - EdgeMST( const NodePtr& source, const NodePtr& target, unsigned int weight = 0 ) : - target_(target) - { sourceNode_ = source; weight_ = weight; } - - EdgeMST( const Edge& edge ) +public: + EDGE_MST( const NODE_PTR& aSource, const NODE_PTR& aTarget, unsigned int aWeight = 0 ) : + m_target( aTarget ) { - sourceNode_ = edge.getSourceNode(); - target_ = edge.getTargetNode(); - weight_ = edge.getWeight(); + m_sourceNode = aSource; + m_weight = aWeight; } - ~EdgeMST() {}; + EDGE_MST( const EDGE& edge ) + { + m_sourceNode = edge.GetSourceNode(); + m_target = edge.GetTargetNode(); + m_weight = edge.GetWeight(); + } + + ~EDGE_MST() + { + } /// @copydoc Edge::setSourceNode() - virtual const NodePtr& getTargetNode() const { return target_; } - }; + virtual const NODE_PTR& GetTargetNode() const + { + return m_target; + } +}; +class DART; // Forward declaration (class in this namespace) - //------------------------------------------------------------------------------------------------ - class Dart; // Forward declaration (class in this namespace) +/** + * \class TRIANGULATION + * \brief \b %Triangulation class for the half-edge data structure with adaption to TTL. + */ +class TRIANGULATION +{ +protected: + /// One half-edge for each arc + std::list m_leadingEdges; - //------------------------------------------------------------------------------------------------ - // Triangulation class in the half-edge data structure - //------------------------------------------------------------------------------------------------ + ttl::TRIANGULATION_HELPER* m_helper; - /** \class Triangulation - * \brief \b %Triangulation class for the half-edge data structure with adaption to TTL. - */ - - class Triangulation { - - protected: - std::list leadingEdges_; // one half-edge for each arc - - ttl::TriangulationHelper* helper; - - void addLeadingEdge(EdgePtr& edge) { - edge->setAsLeadingEdge(); - leadingEdges_.push_front( edge ); + void addLeadingEdge( EDGE_PTR& aEdge ) + { + aEdge->SetAsLeadingEdge(); + m_leadingEdges.push_front( aEdge ); } - bool removeLeadingEdgeFromList(EdgePtr& leadingEdge); + bool removeLeadingEdgeFromList( EDGE_PTR& aLeadingEdge ); void cleanAll(); - + /** Swaps the edge associated with \e dart in the actual data structure. - * - *
- * \image html swapEdge.gif - *
- * - * \param dart - * Some of the functions require a dart as output. - * If this is required by the actual function, the dart should be delivered - * back in a position as seen if it was glued to the edge when swapping (rotating) - * the edge CCW; see the figure. - * - * \note - * - If the edge is \e constrained, or if it should not be swapped for - * some other reason, this function need not do the actual swap of the edge. - * - Some functions in TTL require that \c swapEdge is implemented such that - * darts outside the quadrilateral are not affected by the swap. - */ - void swapEdge(Dart& dart); + * + *
+ * \image html swapEdge.gif + *
+ * + * \param aDart + * Some of the functions require a dart as output. + * If this is required by the actual function, the dart should be delivered + * back in a position as seen if it was glued to the edge when swapping (rotating) + * the edge CCW; see the figure. + * + * \note + * - If the edge is \e constrained, or if it should not be swapped for + * some other reason, this function need not do the actual swap of the edge. + * - Some functions in TTL require that \c swapEdge is implemented such that + * darts outside the quadrilateral are not affected by the swap. + */ + void swapEdge( DART& aDart ); - /** Splits the triangle associated with \e dart in the actual data structure into - * three new triangles joining at \e point. - * - *
- * \image html splitTriangle.gif - *
- * - * \param dart - * Output: A CCW dart incident with the new node; see the figure. - */ - void splitTriangle(Dart& dart, const NodePtr& point); + /** + * Splits the triangle associated with \e dart in the actual data structure into + * three new triangles joining at \e point. + * + *
+ * \image html splitTriangle.gif + *
+ * + * \param aDart + * Output: A CCW dart incident with the new node; see the figure. + */ + void splitTriangle( DART& aDart, const NODE_PTR& aPoint ); - /** The reverse operation of TTLtraits::splitTriangle. - * This function is only required for functions that involve - * removal of interior nodes; see for example TrinagulationHelper::removeInteriorNode. - * - *
- * \image html reverse_splitTriangle.gif - *
- */ - void reverse_splitTriangle(Dart& dart); + /** + * The reverse operation of TTLtraits::splitTriangle. + * This function is only required for functions that involve + * removal of interior nodes; see for example TrinagulationHelper::RemoveInteriorNode. + * + *
+ * \image html reverse_splitTriangle.gif + *
+ */ + void reverseSplitTriangle( DART& aDart ); - /** Removes a triangle with an edge at the boundary of the triangulation - * in the actual data structure - */ - void removeBoundaryTriangle(Dart& d); + /** + * Removes a triangle with an edge at the boundary of the triangulation + * in the actual data structure + */ + void removeBoundaryTriangle( DART& aDart ); - public: +public: /// Default constructor - Triangulation(); - + TRIANGULATION(); + /// Copy constructor - Triangulation(const Triangulation& tr); + TRIANGULATION( const TRIANGULATION& aTriangulation ); /// Destructor - ~Triangulation(); - + ~TRIANGULATION(); + /// Creates a Delaunay triangulation from a set of points - void createDelaunay(NodesContainer::iterator first, - NodesContainer::iterator last); + void CreateDelaunay( NODES_CONTAINER::iterator aFirst, NODES_CONTAINER::iterator aLast ); /// Creates an initial Delaunay triangulation from two enclosing triangles // When using rectangular boundary - loop through all points and expand. // (Called from createDelaunay(...) when starting) - EdgePtr initTwoEnclosingTriangles(NodesContainer::iterator first, - NodesContainer::iterator last); - + EDGE_PTR InitTwoEnclosingTriangles( NODES_CONTAINER::iterator aFirst, + NODES_CONTAINER::iterator aLast ); // These two functions are required by TTL for Delaunay triangulation - + /// Swaps the edge associated with diagonal - void swapEdge(EdgePtr& diagonal); + void SwapEdge( EDGE_PTR& aDiagonal ); /// Splits the triangle associated with edge into three new triangles joining at point - EdgePtr splitTriangle(EdgePtr& edge, const NodePtr& point); - + EDGE_PTR SplitTriangle( EDGE_PTR& aEdge, const NODE_PTR& aPoint ); // Functions required by TTL for removing nodes in a Delaunay triangulation - + /// Removes the boundary triangle associated with edge - void removeTriangle(EdgePtr& edge); // boundary triangle required + void RemoveTriangle( EDGE_PTR& aEdge ); // boundary triangle required /// The reverse operation of removeTriangle - void reverse_splitTriangle(EdgePtr& edge); + void ReverseSplitTriangle( EDGE_PTR& aEdge ); /// Creates an arbitrary CCW dart - Dart createDart(); + DART CreateDart(); /// Returns a list of "triangles" (one leading half-edge for each triangle) - const std::list& getLeadingEdges() const { return leadingEdges_; } + const std::list& GetLeadingEdges() const + { + return m_leadingEdges; + } /// Returns the number of triangles - int noTriangles() const { return (int)leadingEdges_.size(); } - + int NoTriangles() const + { + return (int) m_leadingEdges.size(); + } + /// Returns a list of half-edges (one half-edge for each arc) - std::list* getEdges(bool skip_boundary_edges = false) const; + std::list* GetEdges( bool aSkipBoundaryEdges = false ) const; #ifdef TTL_USE_NODE_FLAG /// Sets flag in all the nodes - void flagNodes(bool flag) const; + void FlagNodes( bool aFlag ) const; /// Returns a list of nodes. This function requires TTL_USE_NODE_FLAG to be defined. \see Node. - std::list* getNodes() const; + std::list* GetNodes() const; #endif /// Swaps edges until the triangulation is Delaunay (constrained edges are not swapped) - void optimizeDelaunay(); + void OptimizeDelaunay(); /// Checks if the triangulation is Delaunay - bool checkDelaunay() const; + bool CheckDelaunay() const; /// Returns an arbitrary interior node (as the source node of the returned edge) - EdgePtr getInteriorNode() const; + EDGE_PTR GetInteriorNode() const; - EdgePtr getBoundaryEdgeInTriangle(const EdgePtr& e) const; + EDGE_PTR GetBoundaryEdgeInTriangle( const EDGE_PTR& aEdge ) const; /// Returns an arbitrary boundary edge - EdgePtr getBoundaryEdge() const; + EDGE_PTR GetBoundaryEdge() const; /// Print edges for plotting with, e.g., gnuplot - void printEdges(std::ofstream& os) const; - - friend class ttl::TriangulationHelper; - - }; // End of class Triangulation - + void PrintEdges( std::ofstream& aOutput ) const; + friend class ttl::TRIANGULATION_HELPER; +}; }; // End of hed namespace #endif diff --git a/include/ttl/ttl.h b/include/ttl/ttl.h index 7de2e7b08d..fae9a8434d 100644 --- a/include/ttl/ttl.h +++ b/include/ttl/ttl.h @@ -40,19 +40,18 @@ #ifndef _TTL_H_ #define _TTL_H_ - #include #include // Debugging #ifdef DEBUG_TTL - static void errorAndExit(char* message) { - cout << "\n!!! ERROR: " << message << " !!!\n" << endl; +static void errorAndExit( char* aMessage ) +{ + cout << "\n!!! ERROR: " << aMessage << " !!!\n" << endl; exit(-1); - } +} #endif - // Next on TOPOLOGY: // - get triangle strips // - weighted graph, algorithms using a weight (real) for each edge, @@ -63,559 +62,557 @@ // - analyze in detail locateFace: e.g. detect 0-orbit in case of infinite loop // around a node etc. - -/** \brief Main interface to TTL +/** + * \brief Main interface to TTL * -* This namespace contains the basic generic algorithms for the TTL, -* the Triangulation Template Library.\n +* This namespace contains the basic generic algorithms for the TTL, +* the Triangulation Template Library.\n * -* Examples of functionality are: -* - Incremental Delaunay triangulation -* - Constrained triangulation -* - Insert/remove nodes and constrained edges -* - Traversal operations -* - Misc. queries for extracting information for visualisation systems etc. +* Examples of functionality are: +* - Incremental Delaunay triangulation +* - Constrained triangulation +* - Insert/remove nodes and constrained edges +* - Traversal operations +* - Misc. queries for extracting information for visualisation systems etc. * -* \par General requirements and assumptions: -* - \e DartType and \e TraitsType should be implemented in accordance with the description -* in \ref api. -* - A \b "Requires:" section in the documentation of a function template -* shows which functionality is required in \e TraitsType to -* support that specific function.\n -* Functionalty required in \e DartType is the same (almost) for all -* function templates; see \ref api and the example referred to. -* - When a reference to a \e dart object is passed to a function in TTL, -* it is assumed that it is oriented \e counterclockwise (CCW) in a triangle -* unless it is explicitly mentioned that it can also be \e clockwise (CW). -* The same applies for a dart that is passed from a function in TTL to -* the users TraitsType class (or struct). -* - When an edge (represented with a dart) is swapped, it is assumed that darts -* outside the quadrilateral where the edge is a diagonal are not affected by -* the swap. Thus, \ref hed::TTLtraits::swapEdge "TraitsType::swapEdge" -* must be implemented in accordance with this rule. +* \par General requirements and assumptions: +* - \e DART_TYPE and \e TRAITS_TYPE should be implemented in accordance with the description +* in \ref api. +* - A \b "Requires:" section in the documentation of a function template +* shows which functionality is required in \e TRAITS_TYPE to +* support that specific function.\n +* Functionalty required in \e DART_TYPE is the same (almost) for all +* function templates; see \ref api and the example referred to. +* - When a reference to a \e dart object is passed to a function in TTL, +* it is assumed that it is oriented \e counterclockwise (CCW) in a triangle +* unless it is explicitly mentioned that it can also be \e clockwise (CW). +* The same applies for a dart that is passed from a function in TTL to +* the users TRAITS_TYPE class (or struct). +* - When an edge (represented with a dart) is swapped, it is assumed that darts +* outside the quadrilateral where the edge is a diagonal are not affected by +* the swap. Thus, \ref hed::TTLtraits::swapEdge "TRAITS_TYPE::swapEdge" +* must be implemented in accordance with this rule. * -* \par Glossary: -* - General terms are explained in \ref api. -* - \e CCW - counterclockwise -* - \e CW - clockwise -* - \e 0_orbit, \e 1_orbit and \e 2_orbit: A sequence of darts around -* a node, around an edge and in a triangle respectively; -* see get_0_orbit_interior and get_0_orbit_boundary -* - \e arc - In a triangulation an arc is equivalent with an edge +* \par Glossary: +* - General terms are explained in \ref api. +* - \e CCW - counterclockwise +* - \e CW - clockwise +* - \e 0_orbit, \e 1_orbit and \e 2_orbit: A sequence of darts around +* a node, around an edge and in a triangle respectively; +* see get_0_orbit_interior and get_0_orbit_boundary +* - \e arc - In a triangulation an arc is equivalent with an edge * -* \see -* \ref ttl_util and \ref api +* \see +* \ref ttl_util and \ref api * -* \author -* �yvind Hjelle, oyvindhj@ifi.uio.no +* \author +* �yvind Hjelle, oyvindhj@ifi.uio.no */ -namespace ttl { - -class TriangulationHelper +namespace ttl +{ +class TRIANGULATION_HELPER { #ifndef DOXYGEN_SHOULD_SKIP_THIS public: - TriangulationHelper(hed::Triangulation& triang) : triangulation(triang) - { - } + TRIANGULATION_HELPER( hed::TRIANGULATION& aTriang ) : + m_triangulation( aTriang ) + { + } - // Delaunay Triangulation - // ---------------------- - template - bool insertNode(DartType& dart, PointType& point); + // Delaunay Triangulation + template + bool InsertNode( DART_TYPE& aDart, POINT_TYPE& aPoint ); - template - void removeRectangularBoundary(DartType& dart); + template + void RemoveRectangularBoundary( DART_TYPE& aDart ); - template - void removeNode(DartType& dart); + template + void RemoveNode( DART_TYPE& aDart ); - template - void removeBoundaryNode(DartType& dart); + template + void RemoveBoundaryNode( DART_TYPE& aDart ); - template - void removeInteriorNode(DartType& dart); + template + void RemoveInteriorNode( DART_TYPE& aDart ); + // Topological and Geometric Queries + // --------------------------------- + template + static bool LocateFaceSimplest( const POINT_TYPE& aPoint, DART_TYPE& aDart ); - // Topological and Geometric Queries - // --------------------------------- - template - static bool locateFaceSimplest(const PointType& point, DartType& dart); + template + static bool LocateTriangle( const POINT_TYPE& aPoint, DART_TYPE& aDart ); - template - static bool locateTriangle(const PointType& point, DartType& dart); + template + static bool InTriangleSimplest( const POINT_TYPE& aPoint, const DART_TYPE& aDart ); - template - static bool inTriangleSimplest(const PointType& point, const DartType& dart); + template + static bool InTriangle( const POINT_TYPE& aPoint, const DART_TYPE& aDart ); - template - static bool inTriangle(const PointType& point, const DartType& dart); + template + static void GetBoundary( const DART_TYPE& aDart, DART_LIST_TYPE& aBoundary ); - template - static void getBoundary(const DartType& dart, DartListType& boundary); + template + static bool IsBoundaryEdge( const DART_TYPE& aDart ); - template - static bool isBoundaryEdge(const DartType& dart); + template + static bool IsBoundaryFace( const DART_TYPE& aDart ); - template - static bool isBoundaryFace(const DartType& dart); + template + static bool IsBoundaryNode( const DART_TYPE& aDart ); - template - static bool isBoundaryNode(const DartType& dart); + template + static int GetDegreeOfNode( const DART_TYPE& aDart ); - template - static int getDegreeOfNode(const DartType& dart); + template + static void Get0OrbitInterior( const DART_TYPE& aDart, DART_LIST_TYPE& aOrbit ); - template - static void get_0_orbit_interior(const DartType& dart, DartListType& orbit); + template + static void Get0OrbitBoundary( const DART_TYPE& aDart, DART_LIST_TYPE& aOrbit ); - template - static void get_0_orbit_boundary(const DartType& dart, DartListType& orbit); + template + static bool Same0Orbit( const DART_TYPE& aD1, const DART_TYPE& aD2 ); - template - static bool same_0_orbit(const DartType& d1, const DartType& d2); + template + static bool Same1Orbit( const DART_TYPE& aD1, const DART_TYPE& aD2 ); - template - static bool same_1_orbit(const DartType& d1, const DartType& d2); + template + static bool Same2Orbit( const DART_TYPE& aD1, const DART_TYPE& aD2 ); - template - static bool same_2_orbit(const DartType& d1, const DartType& d2); + template + static bool SwappableEdge( const DART_TYPE& aDart, bool aAllowDegeneracy = false ); - template - static bool swappableEdge(const DartType& dart, bool allowDegeneracy = false); + template + static void PositionAtNextBoundaryEdge( DART_TYPE& aDart ); - template - static void positionAtNextBoundaryEdge(DartType& dart); + template + static bool ConvexBoundary( const DART_TYPE& aDart ); - template - static bool convexBoundary(const DartType& dart); + // Utilities for Delaunay Triangulation + // ------------------------------------ + template + void OptimizeDelaunay( DART_LIST_TYPE& aElist ); + template + void OptimizeDelaunay( DART_LIST_TYPE& aElist, const typename DART_LIST_TYPE::iterator aEnd ); - // Utilities for Delaunay Triangulation - // ------------------------------------ - template - void optimizeDelaunay(DartListType& elist); + template + bool SwapTestDelaunay( const DART_TYPE& aDart, bool aCyclingCheck = false ) const; - template - void optimizeDelaunay(DartListType& elist, const typename DartListType::iterator end); + template + void RecSwapDelaunay( DART_TYPE& aDiagonal ); - template - bool swapTestDelaunay(const DartType& dart, bool cycling_check = false) const; + template + void SwapEdgesAwayFromInteriorNode( DART_TYPE& aDart, LIST_TYPE& aSwappedEdges ); - template - void recSwapDelaunay(DartType& diagonal); + template + void SwapEdgesAwayFromBoundaryNode( DART_TYPE& aDart, LIST_TYPE& aSwappedEdges ); - template - void swapEdgesAwayFromInteriorNode(DartType& dart, ListType& swapped_edges); + template + void SwapEdgeInList( const typename DART_LIST_TYPE::iterator& aIt, DART_LIST_TYPE& aElist ); - template - void swapEdgesAwayFromBoundaryNode(DartType& dart, ListType& swapped_edges); - - template - void swapEdgeInList(const typename DartListType::iterator& it, DartListType& elist); - - - // Constrained Triangulation - // ------------------------- - template - static DartType insertConstraint(DartType& dstart, DartType& dend, bool optimize_delaunay); + // Constrained Triangulation + // ------------------------- + template + static DART_TYPE InsertConstraint( DART_TYPE& aDStart, DART_TYPE& aDEnd, bool aOptimizeDelaunay ); private: - hed::Triangulation& triangulation; + hed::TRIANGULATION& m_triangulation; - template - void insertNodes(ForwardIterator first, ForwardIterator last, DartType& dart); + template + void insertNodes( FORWARD_ITERATOR aFirst, FORWARD_ITERATOR aLast, DART_TYPE& aDart ); - template - static bool isMemberOfFace(const TopologyElementType& topologyElement, const DartType& dart); + template + static bool isMemberOfFace( const TOPOLOGY_ELEMENT_TYPE& aTopologyElement, const DART_TYPE& aDart ); - template - static bool locateFaceWithNode(const NodeType& node, DartType& dart_iter); + template + static bool locateFaceWithNode( const NODE_TYPE& aNode, DART_TYPE& aDartIter ); - template - static void getAdjacentTriangles(const DartType& dart, DartType& t1, DartType& t2, DartType& t3); + template + static void getAdjacentTriangles( const DART_TYPE& aDart, DART_TYPE& aT1, DART_TYPE& aT2, + DART_TYPE& aT3 ); - template - static void getNeighborNodes(const DartType& dart, std::list& node_list, bool& boundary); + template + static void getNeighborNodes( const DART_TYPE& aDart, std::list& aNodeList, + bool& aBoundary ); - template - static bool degenerateTriangle(const DartType& dart); + template + static bool degenerateTriangle( const DART_TYPE& aDart ); }; #endif // DOXYGEN_SHOULD_SKIP_THIS - //------------------------------------------------------------------------------------------------ - // ------------------------------- Delaunay Triangulation Group --------------------------------- - //------------------------------------------------------------------------------------------------ - /** @name Delaunay Triangulation */ - //@{ - - //------------------------------------------------------------------------------------------------ - /** Inserts a new node in an existing Delaunay triangulation and - * swaps edges to obtain a new Delaunay triangulation. - * This is the basic function for incremental Delaunay triangulation. - * When starting from a set of points, an initial Delaunay triangulation - * can be created as two triangles forming a rectangle that contains - * all the points. - * After \c insertNode has been called repeatedly with all the points, - * removeRectangularBoundary can be called to remove triangles - * at the boundary of the triangulation so that the boundary - * form the convex hull of the points. - * - * Note that this incremetal scheme will run much faster if the points - * have been sorted lexicographically on \e x and \e y. - * - * \param dart - * An arbitrary CCW dart in the tringulation.\n - * Output: A CCW dart incident to the new node. - * - * \param point - * A point (node) to be inserted in the triangulation. - * - * \retval bool - * \c true if \e point was inserted; \c false if not.\n - * If \e point is outside the triangulation, or the input dart is not valid, - * \c false is returned. - * - * \require - * - \ref hed::TTLtraits::splitTriangle "TraitsType::splitTriangle" (DartType&, const PointType&) - * - * \using - * - locateTriangle - * - recSwapDelaunay - * - * \note - * - For efficiency reasons \e dart should be close to the insertion \e point. - * - * \see - * removeRectangularBoundary - */ - template - bool TriangulationHelper::insertNode(DartType& dart, PointType& point) { +//@{ +/** + * Inserts a new node in an existing Delaunay triangulation and + * swaps edges to obtain a new Delaunay triangulation. + * This is the basic function for incremental Delaunay triangulation. + * When starting from a set of points, an initial Delaunay triangulation + * can be created as two triangles forming a rectangle that contains + * all the points. + * After \c insertNode has been called repeatedly with all the points, + * removeRectangularBoundary can be called to remove triangles + * at the boundary of the triangulation so that the boundary + * form the convex hull of the points. + * + * Note that this incremetal scheme will run much faster if the points + * have been sorted lexicographically on \e x and \e y. + * + * \param aDart + * An arbitrary CCW dart in the tringulation.\n + * Output: A CCW dart incident to the new node. + * + * \param aPoint + * A point (node) to be inserted in the triangulation. + * + * \retval bool + * \c true if \e point was inserted; \c false if not.\n + * If \e point is outside the triangulation, or the input dart is not valid, + * \c false is returned. + * + * \require + * - \ref hed::TTLtraits::splitTriangle "TRAITS_TYPE::splitTriangle" (DART_TYPE&, const POINT_TYPE&) + * + * \using + * - locateTriangle + * - RecSwapDelaunay + * + * \note + * - For efficiency reasons \e dart should be close to the insertion \e point. + * + * \see + * removeRectangularBoundary + */ +template +bool TRIANGULATION_HELPER::InsertNode( DART_TYPE& aDart, POINT_TYPE& aPoint ) +{ + bool found = LocateTriangle( aPoint, aDart ); - bool found = locateTriangle(point, dart); - if (!found) { + if( !found ) + { #ifdef DEBUG_TTL - cout << "ERROR: Triangulation::insertNode: NO triangle found. /n"; + cout << "ERROR: Triangulation::insertNode: NO triangle found. /n"; #endif - return false; + return false; } - + // ??? can we hide the dart? this is not possible if one triangle only - triangulation.splitTriangle(dart, point); - - DartType d1 = dart; - d1.alpha2().alpha1().alpha2().alpha0().alpha1(); - - DartType d2 = dart; - d2.alpha1().alpha0().alpha1(); - + m_triangulation.splitTriangle( aDart, aPoint ); + + DART_TYPE d1 = aDart; + d1.Alpha2().Alpha1().Alpha2().Alpha0().Alpha1(); + + DART_TYPE d2 = aDart; + d2.Alpha1().Alpha0().Alpha1(); + // Preserve a dart as output incident to the node and CCW - DartType d3 = dart; - d3.alpha2(); - dart = d3; // and see below - //DartType dsav = d3; - d3.alpha0().alpha1(); - - //if (!TraitsType::fixedEdge(d1) && !isBoundaryEdge(d1)) { - if (!isBoundaryEdge(d1)) { - d1.alpha2(); - recSwapDelaunay(d1); + DART_TYPE d3 = aDart; + d3.Alpha2(); + aDart = d3; // and see below + //DART_TYPE dsav = d3; + d3.Alpha0().Alpha1(); + + //if (!TRAITS_TYPE::fixedEdge(d1) && !IsBoundaryEdge(d1)) { + if( !IsBoundaryEdge( d1 ) ) + { + d1.Alpha2(); + RecSwapDelaunay( d1 ); } - - //if (!TraitsType::fixedEdge(d2) && !isBoundaryEdge(d2)) { - if (!isBoundaryEdge(d2)) { - d2.alpha2(); - recSwapDelaunay(d2); + + //if (!TRAITS_TYPE::fixedEdge(d2) && !IsBoundaryEdge(d2)) { + if( !IsBoundaryEdge( d2 ) ) + { + d2.Alpha2(); + RecSwapDelaunay( d2 ); } - + // Preserve the incoming dart as output incident to the node and CCW - //d = dsav.alpha2(); - dart.alpha2(); - //if (!TraitsType::fixedEdge(d3) && !isBoundaryEdge(d3)) { - if (!isBoundaryEdge(d3)) { - d3.alpha2(); - recSwapDelaunay(d3); + //d = dsav.Alpha2(); + aDart.Alpha2(); + //if (!TRAITS_TYPE::fixedEdge(d3) && !IsBoundaryEdge(d3)) { + if( !IsBoundaryEdge( d3 ) ) + { + d3.Alpha2(); + RecSwapDelaunay( d3 ); } - + return true; - } +} +//------------------------------------------------------------------------------------------------ +// Private/Hidden function (might change later) +template +void TRIANGULATION_HELPER::insertNodes( FORWARD_ITERATOR aFirst, FORWARD_ITERATOR aLast, + DART_TYPE& aDart ) +{ - //------------------------------------------------------------------------------------------------ - // Private/Hidden function (might change later) - template - void TriangulationHelper::insertNodes(ForwardIterator first, ForwardIterator last, DartType& dart) { - // Assumes that the dereferenced point objects are pointers. // References to the point objects are then passed to TTL. - - ForwardIterator it; - for (it = first; it != last; ++it) { - insertNode(dart, **it); + + FORWARD_ITERATOR it; + for( it = aFirst; it != aLast; ++it ) + { + InsertNode( aDart, **it ); } - } +} - //------------------------------------------------------------------------------------------------ - /** Removes the rectangular boundary of a triangulation as a final step of an - * incremental Delaunay triangulation. - * The four nodes at the corners will be removed and the resulting triangulation - * will have a convex boundary and be Delaunay. - * - * \param dart - * A CCW dart at the boundary of the triangulation\n - * Output: A CCW dart at the new boundary - * - * \using - * - removeBoundaryNode - * - * \note - * - This function requires that the boundary of the triangulation is - * a rectangle with four nodes (one in each corner). - */ - template - void TriangulationHelper::removeRectangularBoundary(DartType& dart) { - - DartType d_next = dart; - DartType d_iter; - - for (int i = 0; i < 4; i++) { - d_iter = d_next; - d_next.alpha0(); - positionAtNextBoundaryEdge(d_next); - removeBoundaryNode(d_iter); +/** Removes the rectangular boundary of a triangulation as a final step of an + * incremental Delaunay triangulation. + * The four nodes at the corners will be removed and the resulting triangulation + * will have a convex boundary and be Delaunay. + * + * \param dart + * A CCW dart at the boundary of the triangulation\n + * Output: A CCW dart at the new boundary + * + * \using + * - RemoveBoundaryNode + * + * \note + * - This function requires that the boundary of the m_triangulation is + * a rectangle with four nodes (one in each corner). + */ +template +void TRIANGULATION_HELPER::RemoveRectangularBoundary( DART_TYPE& aDart ) +{ + DART_TYPE d_next = aDart; + DART_TYPE d_iter; + + for( int i = 0; i < 4; i++ ) + { + d_iter = d_next; + d_next.Alpha0(); + PositionAtNextBoundaryEdge( d_next ); + RemoveBoundaryNode( d_iter ); } - - dart = d_next; // Return a dart at the new boundary - } + aDart = d_next; // Return a dart at the new boundary +} - //------------------------------------------------------------------------------------------------ - /** Removes the node associated with \e dart and - * updates the triangulation to be Delaunay. - * - * \using - * - removeBoundaryNode if \e dart represents a node at the boundary - * - removeInteriorNode if \e dart represents an interior node - * - * \note - * - The node cannot belong to a fixed (constrained) edge that is not - * swappable. (An endless loop is likely to occur in this case). - */ - template - void TriangulationHelper::removeNode(DartType& dart) { - - if (isBoundaryNode(dart)) - removeBoundaryNode(dart); +/** Removes the node associated with \e dart and + * updates the triangulation to be Delaunay. + * + * \using + * - RemoveBoundaryNode if \e dart represents a node at the boundary + * - RemoveInteriorNode if \e dart represents an interior node + * + * \note + * - The node cannot belong to a fixed (constrained) edge that is not + * swappable. (An endless loop is likely to occur in this case). + */ +template +void TRIANGULATION_HELPER::RemoveNode( DART_TYPE& aDart ) +{ + + if( isBoundaryNode( aDart ) ) + RemoveBoundaryNode( aDart ); else - removeInteriorNode(dart); - } + RemoveInteriorNode( aDart ); +} +/** Removes the boundary node associated with \e dart and + * updates the triangulation to be Delaunay. + * + * \using + * - SwapEdgesAwayFromBoundaryNode + * - OptimizeDelaunay + * + * \require + * - \ref hed::TTLtraits::removeBoundaryTriangle "TRAITS_TYPE::removeBoundaryTriangle" (Dart&) + */ +template +void TRIANGULATION_HELPER::RemoveBoundaryNode( DART_TYPE& aDart ) +{ - //------------------------------------------------------------------------------------------------ - /** Removes the boundary node associated with \e dart and - * updates the triangulation to be Delaunay. - * - * \using - * - swapEdgesAwayFromBoundaryNode - * - optimizeDelaunay - * - * \require - * - \ref hed::TTLtraits::removeBoundaryTriangle "TraitsType::removeBoundaryTriangle" (Dart&) - */ - template - void TriangulationHelper::removeBoundaryNode(DartType& dart) { - // ... and update Delaunay // - CCW dart must be given (for remove) // - No dart is delivered back now (but this is possible if - // we assume that there is not only one triangle left in the triangulation. - + // we assume that there is not only one triangle left in the m_triangulation. + // Position at boundary edge and CCW - if (!isBoundaryEdge(dart)) { - dart.alpha1(); // ensures that next function delivers back a CCW dart (if the given dart is CCW) - positionAtNextBoundaryEdge(dart); + if( !IsBoundaryEdge( aDart ) ) + { + aDart.Alpha1(); // ensures that next function delivers back a CCW dart (if the given dart is CCW) + PositionAtNextBoundaryEdge( aDart ); } - std::list swapped_edges; - swapEdgesAwayFromBoundaryNode(dart, swapped_edges); - + std::list swapped_edges; + SwapEdgesAwayFromBoundaryNode( aDart, swapped_edges ); + // Remove boundary triangles and remove the new boundary from the list // of swapped edges, see below. - DartType d_iter = dart; - DartType dnext = dart; + DART_TYPE d_iter = aDart; + DART_TYPE dnext = aDart; bool bend = false; - while (bend == false) { - dnext.alpha1().alpha2(); - if (isBoundaryEdge(dnext)) - bend = true; // Stop when boundary - - // Generic: Also remove the new boundary from the list of swapped edges - DartType n_bedge = d_iter; - n_bedge.alpha1().alpha0().alpha1().alpha2(); // new boundary edge - - // ??? can we avoid find if we do this in swap away? - typename std::list::iterator it; - it = find(swapped_edges.begin(), swapped_edges.end(), n_bedge); - - if (it != swapped_edges.end()) - swapped_edges.erase(it); - - // Remove the boundary triangle - triangulation.removeBoundaryTriangle(d_iter); - d_iter = dnext; + while( bend == false ) + { + dnext.Alpha1().Alpha2(); + if( IsBoundaryEdge( dnext ) ) + bend = true; // Stop when boundary + + // Generic: Also remove the new boundary from the list of swapped edges + DART_TYPE n_bedge = d_iter; + n_bedge.Alpha1().Alpha0().Alpha1().Alpha2(); // new boundary edge + + // ??? can we avoid find if we do this in swap away? + typename std::list::iterator it; + it = find( swapped_edges.begin(), swapped_edges.end(), n_bedge ); + + if( it != swapped_edges.end() ) + swapped_edges.erase( it ); + + // Remove the boundary triangle + m_triangulation.removeBoundaryTriangle( d_iter ); + d_iter = dnext; } - + // Optimize Delaunay - typedef std::list DartListType; - optimizeDelaunay(swapped_edges); - } + typedef std::list DART_LIST_TYPE; + OptimizeDelaunay( swapped_edges ); +} - //------------------------------------------------------------------------------------------------ - /** Removes the interior node associated with \e dart and - * updates the triangulation to be Delaunay. - * - * \using - * - swapEdgesAwayFromInteriorNode - * - optimizeDelaunay - * - * \require - * - \ref hed::TTLtraits::reverse_splitTriangle "TraitsType::reverse_splitTriangle" (Dart&) - * - * \note - * - The node cannot belong to a fixed (constrained) edge that is not - * swappable. (An endless loop is likely to occur in this case). - */ - template - void TriangulationHelper::removeInteriorNode(DartType& dart) { - +/** Removes the interior node associated with \e dart and + * updates the triangulation to be Delaunay. + * + * \using + * - SwapEdgesAwayFromInteriorNode + * - OptimizeDelaunay + * + * \require + * - \ref hed::TTLtraits::reverse_splitTriangle "TRAITS_TYPE::reverse_splitTriangle" (Dart&) + * + * \note + * - The node cannot belong to a fixed (constrained) edge that is not + * swappable. (An endless loop is likely to occur in this case). + */ +template +void TRIANGULATION_HELPER::RemoveInteriorNode( DART_TYPE& aDart ) +{ // ... and update to Delaunay. // Must allow degeneracy temporarily, see comments in swap edges away // Assumes: // - revese_splitTriangle does not affect darts // outside the resulting triangle. - + // 1) Swaps edges away from the node until degree=3 (generic) // 2) Removes the remaining 3 triangles and creates a new to fill the hole // unsplitTriangle which is required - // 3) Runs LOP on the platelet to obtain a Delaunay triangulation + // 3) Runs LOP on the platelet to obtain a Delaunay m_triangulation // (No dart is delivered as output) - + // Assumes dart is counterclockwise - - std::list swapped_edges; - swapEdgesAwayFromInteriorNode(dart, swapped_edges); - + + std::list swapped_edges; + SwapEdgesAwayFromInteriorNode( aDart, swapped_edges ); + // The reverse operation of split triangle: // Make one triangle of the three triangles at the node associated with dart - // TraitsType:: - triangulation.reverse_splitTriangle(dart); - + // TRAITS_TYPE:: + m_triangulation.reverseSplitTriangle( aDart ); + // ???? Not generic yet if we are very strict: // When calling unsplit triangle, darts at the three opposite sides may // change! // Should we hide them longer away??? This is possible since they cannot // be boundary edges. // ----> Or should we just require that they are not changed??? - + // Make the swapped-away edges Delaunay. // Note the theoretical result: if there are no edges in the list, // the triangulation is Delaunay already - - optimizeDelaunay(swapped_edges); - } - //@} // End of Delaunay Triangulation Group + OptimizeDelaunay( swapped_edges ); +} +//@} // End of Delaunay Triangulation Group - //------------------------------------------------------------------------------------------------ - // -------------------------- Topological and Geometric Queries Group --------------------------- - //------------------------------------------------------------------------------------------------ - - /** @name Topological and Geometric Queries */ - //@{ - - //------------------------------------------------------------------------------------------------ - // Private/Hidden function (might change later) - template - bool TriangulationHelper::isMemberOfFace(const TopologyElementType& topologyElement, const DartType& dart) { - +/** @name Topological and Geometric Queries */ +//@{ +//------------------------------------------------------------------------------------------------ +// Private/Hidden function (might change later) +template +bool TRIANGULATION_HELPER::isMemberOfFace( const TOPOLOGY_ELEMENT_TYPE& aTopologyElement, + const DART_TYPE& aDart ) +{ // Check if the given topology element (node, edge or face) is a member of the face // Assumes: - // - DartType::isMember(TopologyElementType) - - DartType dart_iter = dart; - do { - if (dart_iter.isMember(topologyElement)) - return true; - dart_iter.alpha0().alpha1(); - } while (dart_iter != dart); + // - DART_TYPE::isMember(TOPOLOGY_ELEMENT_TYPE) + + DART_TYPE dart_iter = aDart; + do + { + if( dart_iter.isMember( aTopologyElement ) ) + return true; + dart_iter.Alpha0().Alpha1(); + } + while( dart_iter != aDart ); + return false; - } +} - - //------------------------------------------------------------------------------------------------ - // Private/Hidden function (might change later) - template - bool TriangulationHelper::locateFaceWithNode(const NodeType& node, DartType& dart_iter) { +//------------------------------------------------------------------------------------------------ +// Private/Hidden function (might change later) +template +bool TRIANGULATION_HELPER::locateFaceWithNode( const NODE_TYPE& aNode, DART_TYPE& aDartIter ) +{ // Locate a face in the topology structure with the given node as a member // Assumes: - // - TraitsType::orient2d(DartType, DartType, NodeType) - // - DartType::isMember(NodeType) + // - TRAITS_TYPE::Orient2D(DART_TYPE, DART_TYPE, NODE_TYPE) + // - DART_TYPE::isMember(NODE_TYPE) // - Note that if false is returned, the node might still be in the // topology structure. Application programmer // should check all if by hypothesis the node is in the topology structure; - // see doc. on locateTriangle. - - bool status = locateFaceSimplest(node, dart_iter); - if (status == false) - return status; - - // True was returned from locateFaceSimplest, but if the located triangle is + // see doc. on LocateTriangle. + + bool status = LocateFaceSimplest( aNode, aDartIter ); + + if( status == false ) + return status; + + // True was returned from LocateFaceSimplest, but if the located triangle is // degenerate and the node is on the extension of the edges, // the node might still be inside. Check if node is a member and return false // if not. (Still the node might be in the topology structure, see doc. above - // and in locateTriangle(const PointType& point, DartType& dart_iter) - - return isMemberOfFace(node, dart_iter); - } + // and in locateTriangle(const POINT_TYPE& point, DART_TYPE& dart_iter) + return isMemberOfFace( aNode, aDartIter ); +} - //------------------------------------------------------------------------------------------------ - /** Locates the face containing a given point. - * It is assumed that the tessellation (e.g. a triangulation) is \e regular in the sense that - * there are no holes, the boundary is convex and there are no degenerate faces. - * - * \param point - * A point to be located - * - * \param dart - * An arbitrary CCW dart in the triangulation\n - * Output: A CCW dart in the located face - * - * \retval bool - * \c true if a face is found; \c false if not. - * - * \require - * - \ref hed::TTLtraits::orient2d "TraitsType::orient2d" (DartType&, DartType&, PointType&) - * - * \note - * - If \c false is returned, \e point may still be inside a face if the tessellation is not - * \e regular as explained above. - * - * \see - * locateTriangle - */ - template - bool TriangulationHelper::locateFaceSimplest(const PointType& point, DartType& dart) { +/** Locates the face containing a given point. + * It is assumed that the tessellation (e.g. a triangulation) is \e regular in the sense that + * there are no holes, the boundary is convex and there are no degenerate faces. + * + * \param aPoint + * A point to be located + * + * \param aDart + * An arbitrary CCW dart in the triangulation\n + * Output: A CCW dart in the located face + * + * \retval bool + * \c true if a face is found; \c false if not. + * + * \require + * - \ref hed::TTLtraits::Orient2D "TRAITS_TYPE::Orient2D" (DART_TYPE&, DART_TYPE&, POINT_TYPE&) + * + * \note + * - If \c false is returned, \e point may still be inside a face if the tessellation is not + * \e regular as explained above. + * + * \see + * LocateTriangle + */ +template +bool TRIANGULATION_HELPER::LocateFaceSimplest( const POINT_TYPE& aPoint, DART_TYPE& aDart ) +{ // Not degenerate triangles if point is on the extension of the edges // But inTriangle may be called in case of true (may update to inFace2) // Convex boundary @@ -623,867 +620,867 @@ private: // convex faces (works for general convex faces) // Not specialized for triangles, but ok? // - // TraitsType::orint2d(PointType) is the half open half-plane defined + // TRAITS_TYPE::orint2d(POINT_TYPE) is the half open half-plane defined // by the dart: // n1 = dart.node() - // n2 = dart.alpha0().node + // n2 = dart.Alpha0().node // Only the following gives true: // ((n2->x()-n1->x())*(point.y()-n1->y()) >= (point.x()-n1->x())*(n2->y()-n1->y())) - - DartType dart_start; - dart_start = dart; - DartType dart_prev; - - DartType d0; - for (;;) { - d0 = dart; - d0.alpha0(); - if (TraitsType::orient2d(dart, d0, point) >= 0) { - dart.alpha0().alpha1(); - if (dart == dart_start) - return true; // left to all edges in face - } - else { - dart_prev = dart; - dart.alpha2(); - if (dart == dart_prev) - return false; // iteration to outside boundary - - dart_start = dart; - dart_start.alpha0(); - - dart.alpha1(); // avoid twice on same edge and ccw in next - } + + DART_TYPE dart_start; + dart_start = aDart; + DART_TYPE dart_prev; + + DART_TYPE d0; + for( ;; ) + { + d0 = aDart; + d0.Alpha0(); + + if( TRAITS_TYPE::Orient2D( aDart, d0, aPoint ) >= 0 ) + { + aDart.Alpha0().Alpha1(); + if( aDart == dart_start ) + return true; // left to all edges in face + } + else + { + dart_prev = aDart; + aDart.Alpha2(); + + if( aDart == dart_prev ) + return false; // iteration to outside boundary + + dart_start = aDart; + dart_start.Alpha0(); + + aDart.Alpha1(); // avoid twice on same edge and ccw in next + } } - } +} - //------------------------------------------------------------------------------------------------ - /** Locates the triangle containing a given point. - * It is assumed that the triangulation is \e regular in the sense that there - * are no holes and the boundary is convex. - * This function deals with degeneracy to some extent, but round-off errors may still - * lead to a wrong result if triangles are degenerate. - * - * \param point - * A point to be located - * - * \param dart - * An arbitrary CCW dart in the triangulation\n - * Output: A CCW dart in the located triangle - * - * \retval bool - * \c true if a triangle is found; \c false if not.\n - * If \e point is outside the triangulation, in which case \c false is returned, - * then the edge associated with \e dart will be at the boundary of the triangulation. - * - * \using - * - locateFaceSimplest - * - inTriangle - */ - template - bool TriangulationHelper::locateTriangle(const PointType& point, DartType& dart) { +/** Locates the triangle containing a given point. + * It is assumed that the triangulation is \e regular in the sense that there + * are no holes and the boundary is convex. + * This function deals with degeneracy to some extent, but round-off errors may still + * lead to a wrong result if triangles are degenerate. + * + * \param point + * A point to be located + * + * \param dart + * An arbitrary CCW dart in the triangulation\n + * Output: A CCW dart in the located triangle + * + * \retval bool + * \c true if a triangle is found; \c false if not.\n + * If \e point is outside the m_triangulation, in which case \c false is returned, + * then the edge associated with \e dart will be at the boundary of the m_triangulation. + * + * \using + * - LocateFaceSimplest + * - InTriangle + */ +template +bool TRIANGULATION_HELPER::LocateTriangle( const POINT_TYPE& aPoint, DART_TYPE& aDart ) +{ // The purpose is to have a fast and stable procedure that // i) avoids concluding that a point is inside a triangle if it is not inside // ii) avoids infinite loops - + // Thus, if false is returned, the point might still be inside a triangle in // the triangulation. But this will probably only occur in the following cases: // i) There are holes in the triangulation which causes the procedure to stop. - // ii) The boundary of the triangulation is not convex. + // ii) The boundary of the m_triangulation is not convex. // ii) There might be degenerate triangles interior to the triangulation, or on the // the boundary, which in some cases might cause the procedure to stop there due // to the logic of the algorithm. - + // It is the application programmer's responsibility to check further if false is // returned. For example, if by hypothesis the point is inside a triangle // in the triangulation and and false is returned, then all triangles in the // triangulation should be checked by the application. This can be done using // the function: - // bool inTriangle(const PointType& point, const DartType& dart). - - + // bool inTriangle(const POINT_TYPE& point, const DART_TYPE& dart). + // Assumes: - // - crossProduct2d, scalarProduct2d etc., see functions called - - bool status = locateFaceSimplest(point, dart); - if (status == false) - return status; + // - CrossProduct2D, ScalarProduct2D etc., see functions called + + bool status = LocateFaceSimplest( aPoint, aDart ); + if( status == false ) + return status; + // There may be degeneracy, i.e., the point might be outside the triangle // on the extension of the edges of a degenerate triangle. - + // The next call returns true if inside a non-degenerate or a degenerate triangle, // but false if the point coincides with the "supernode" in the case where all // edges are degenerate. - return inTriangle(point, dart); - } + return InTriangle( aPoint, aDart ); +} - - //------------------------------------------------------------------------------------------------ - /** Checks if \e point is inside the triangle associated with \e dart. - * A fast and simple function that does not deal with degeneracy. - * - * \param dart - * A CCW dart in the triangle - * - * \require - * - \ref hed::TTLtraits::orient2d "TraitsType::orient2d" (DartType&, DartType&, PointType&) - * - * \see - * inTriangle for a more robust function - */ - template - bool TriangulationHelper::inTriangleSimplest(const PointType& point, const DartType& dart) { - +//------------------------------------------------------------------------------------------------ +/** Checks if \e point is inside the triangle associated with \e dart. + * A fast and simple function that does not deal with degeneracy. + * + * \param aDart + * A CCW dart in the triangle + * + * \require + * - \ref hed::TTLtraits::Orient2D "TRAITS_TYPE::Orient2D" (DART_TYPE&, DART_TYPE&, POINT_TYPE&) + * + * \see + * InTriangle for a more robust function + */ +template +bool TRIANGULATION_HELPER::InTriangleSimplest( const POINT_TYPE& aPoint, const DART_TYPE& aDart ) +{ // Fast and simple: Do not deal with degenerate faces, i.e., if there is // degeneracy, true will be returned if the point is on the extension of the // edges of a degenerate triangle + + DART_TYPE d_iter = aDart; + DART_TYPE d0 = d_iter; + d0.Alpha0(); - DartType d_iter = dart; - DartType d0 = d_iter; - d0.alpha0(); - if (!TraitsType::orient2d(d_iter, d0, point) >= 0) - return false; - - d_iter.alpha0().alpha1(); + if( !TRAITS_TYPE::Orient2D( d_iter, d0, aPoint ) >= 0 ) + return false; + + d_iter.Alpha0().Alpha1(); d0 = d_iter; - d0.alpha0(); - if (!TraitsType::orient2d(d_iter, d0, point) >= 0) - return false; + d0.Alpha0(); - d_iter.alpha0().alpha1(); + if( !TRAITS_TYPE::Orient2D( d_iter, d0, aPoint ) >= 0 ) + return false; + + d_iter.Alpha0().Alpha1(); d0 = d_iter; - d0.alpha0(); - if (!TraitsType::orient2d(d_iter, d0, point) >= 0) - return false; + d0.Alpha0(); + if( !TRAITS_TYPE::Orient2D( d_iter, d0, aPoint ) >= 0 ) + return false; + return true; - } +} +/** Checks if \e point is inside the triangle associated with \e dart. + * This function deals with degeneracy to some extent, but round-off errors may still + * lead to wrong result if the triangle is degenerate. + * + * \param aDart + * A CCW dart in the triangle + * + * \require + * - \ref hed::TTLtraits::CrossProduct2D "TRAITS_TYPE::CrossProduct2D" (DART_TYPE&, POINT_TYPE&) + * - \ref hed::TTLtraits::ScalarProduct2D "TRAITS_TYPE::ScalarProduct2D" (DART_TYPE&, POINT_TYPE&) + * + * \see + * InTriangleSimplest + */ +template +bool TRIANGULATION_HELPER::InTriangle( const POINT_TYPE& aPoint, const DART_TYPE& aDart ) +{ - //------------------------------------------------------------------------------------------------ - /** Checks if \e point is inside the triangle associated with \e dart. - * This function deals with degeneracy to some extent, but round-off errors may still - * lead to wrong result if the triangle is degenerate. - * - * \param dart - * A CCW dart in the triangle - * - * \require - * - \ref hed::TTLtraits::crossProduct2d "TraitsType::crossProduct2d" (DartType&, PointType&) - * - \ref hed::TTLtraits::scalarProduct2d "TraitsType::scalarProduct2d" (DartType&, PointType&) - * - * \see - * inTriangleSimplest - */ - template - bool TriangulationHelper::inTriangle(const PointType& point, const DartType& dart) { - // SHOULD WE INCLUDE A STRATEGY WITH EDGE X e_1 ETC? TO GUARANTEE THAT // ONLY ON ONE EDGE? BUT THIS DOES NOT SOLVE PROBLEMS WITH // notInE1 && notInE1.neghbour ? - - + // Returns true if inside (but not necessarily strictly inside) // Works for degenerate triangles, but not when all edges are degenerate, - // and the point coincides with all nodes; + // and the aPoint coincides with all nodes; // then false is always returned. - - typedef typename TraitsType::real_type real_type; - - DartType dart_iter = dart; - - real_type cr1 = TraitsType::crossProduct2d(dart_iter, point); - if (cr1 < 0) - return false; - - dart_iter.alpha0().alpha1(); - real_type cr2 = TraitsType::crossProduct2d(dart_iter, point); - - if (cr2 < 0) - return false; - - dart_iter.alpha0().alpha1(); - real_type cr3 = TraitsType::crossProduct2d(dart_iter, point); - if (cr3 < 0) - return false; - + + typedef typename TRAITS_TYPE::REAL_TYPE REAL_TYPE; + + DART_TYPE dart_iter = aDart; + + REAL_TYPE cr1 = TRAITS_TYPE::CrossProduct2D( dart_iter, aPoint ); + if( cr1 < 0 ) + return false; + + dart_iter.Alpha0().Alpha1(); + REAL_TYPE cr2 = TRAITS_TYPE::CrossProduct2D( dart_iter, aPoint ); + + if( cr2 < 0 ) + return false; + + dart_iter.Alpha0().Alpha1(); + REAL_TYPE cr3 = TRAITS_TYPE::CrossProduct2D( dart_iter, aPoint ); + if( cr3 < 0 ) + return false; + // All cross products are >= 0 // Check for degeneracy - - if (cr1 != 0 || cr2 != 0 || cr3 != 0) - return true; // inside non-degenerate face - + if( cr1 != 0 || cr2 != 0 || cr3 != 0 ) + return true; // inside non-degenerate face + // All cross-products are zero, i.e. degenerate triangle, check if inside - // Strategy: d.scalarProduct2d >= 0 && alpha0(d).d.scalarProduct2d >= 0 for one of - // the edges. But if all edges are degenerate and the point is on (all) the nodes, + // Strategy: d.ScalarProduct2D >= 0 && alpha0(d).d.ScalarProduct2D >= 0 for one of + // the edges. But if all edges are degenerate and the aPoint is on (all) the nodes, // then "false is returned". - - DartType dart_tmp = dart_iter; - real_type sc1 = TraitsType::scalarProduct2d(dart_tmp,point); - real_type sc2 = TraitsType::scalarProduct2d(dart_tmp.alpha0(), point); - - if (sc1 >= 0 && sc2 >= 0) { - // test for degenerate edge - if (sc1 != 0 || sc2 != 0) - return true; // interior to this edge or on a node (but see comment above) + + DART_TYPE dart_tmp = dart_iter; + REAL_TYPE sc1 = TRAITS_TYPE::ScalarProduct2D( dart_tmp, aPoint ); + REAL_TYPE sc2 = TRAITS_TYPE::ScalarProduct2D( dart_tmp.Alpha0(), aPoint ); + + if( sc1 >= 0 && sc2 >= 0 ) + { + // test for degenerate edge + if( sc1 != 0 || sc2 != 0 ) + return true; // interior to this edge or on a node (but see comment above) } + + dart_tmp = dart_iter.Alpha0().Alpha1(); + sc1 = TRAITS_TYPE::ScalarProduct2D( dart_tmp, aPoint ); + sc2 = TRAITS_TYPE::ScalarProduct2D( dart_tmp.Alpha0(), aPoint ); - dart_tmp = dart_iter.alpha0().alpha1(); - sc1 = TraitsType::scalarProduct2d(dart_tmp,point); - sc2 = TraitsType::scalarProduct2d(dart_tmp.alpha0(),point); - if (sc1 >= 0 && sc2 >= 0) { - // test for degenerate edge - if (sc1 != 0 || sc2 != 0) - return true; // interior to this edge or on a node (but see comment above) + if( sc1 >= 0 && sc2 >= 0 ) + { + // test for degenerate edge + if( sc1 != 0 || sc2 != 0 ) + return true; // interior to this edge or on a node (but see comment above) } + + dart_tmp = dart_iter.Alpha1(); + sc1 = TRAITS_TYPE::ScalarProduct2D( dart_tmp, aPoint ); + sc2 = TRAITS_TYPE::ScalarProduct2D( dart_tmp.Alpha0(), aPoint ); - dart_tmp = dart_iter.alpha1(); - sc1 = TraitsType::scalarProduct2d(dart_tmp,point); - sc2 = TraitsType::scalarProduct2d(dart_tmp.alpha0(),point); - if (sc1 >= 0 && sc2 >= 0) { - // test for degenerate edge - if (sc1 != 0 || sc2 != 0) - return true; // interior to this edge or on a node (but see comment above) + if( sc1 >= 0 && sc2 >= 0 ) + { + // test for degenerate edge + if( sc1 != 0 || sc2 != 0 ) + return true; // interior to this edge or on a node (but see comment above) } - + // Not on any of the edges of the degenerate triangle. - // The only possibility for the point to be "inside" is that all edges are degenerate + // The only possibility for the aPoint to be "inside" is that all edges are degenerate // and the point coincide with all nodes. So false is returned in this case. - + return false; - } +} //------------------------------------------------------------------------------------------------ - // Private/Hidden function (might change later) - template - void TriangulationHelper::getAdjacentTriangles(const DartType& dart, DartType& t1, DartType& t2, DartType& t3) { - - DartType dart_iter = dart; - +// Private/Hidden function (might change later) +template +void TRIANGULATION_HELPER::getAdjacentTriangles( const DART_TYPE& aDart, DART_TYPE& aT1, + DART_TYPE& aT2, DART_TYPE& aT3 ) +{ + + DART_TYPE dart_iter = aDart; + // add first - if (dart_iter.alpha2() != dart) { - t1 = dart_iter; - dart_iter = dart; + if( dart_iter.Alpha2() != aDart ) + { + aT1 = dart_iter; + dart_iter = aDart; } - + // add second - dart_iter.alpha0(); - dart_iter.alpha1(); - DartType dart_prev = dart_iter; - if ((dart_iter.alpha2()) != dart_prev) { - t2 = dart_iter; - dart_iter = dart_prev; + dart_iter.Alpha0(); + dart_iter.Alpha1(); + DART_TYPE dart_prev = dart_iter; + + if( ( dart_iter.Alpha2() ) != dart_prev ) + { + aT2 = dart_iter; + dart_iter = dart_prev; } - + // add third - dart_iter.alpha0(); - dart_iter.alpha1(); + dart_iter.Alpha0(); + dart_iter.Alpha1(); dart_prev = dart_iter; - if ((dart_iter.alpha2()) != dart_prev) - t3 = dart_iter; - } + if( ( dart_iter.Alpha2() ) != dart_prev ) + aT3 = dart_iter; +} - //------------------------------------------------------------------------------------------------ - /** Gets the boundary as sequence of darts, where the edges associated with the darts are boundary - * edges, given a dart with an associating edge at the boundary of a topology structure. - * The first dart in the sequence will be the given one, and the others will have the same - * orientation (CCW or CW) as the first. - * Assumes that the given dart is at the boundary. - * - * \param dart - * A dart at the boundary (CCW or CW) - * - * \param boundary - * A sequence of darts, where the associated edges are the boundary edges - * - * \require - * - DartListType::push_back (DartType&) - */ - template - void TriangulationHelper::getBoundary(const DartType& dart, DartListType& boundary) { +//------------------------------------------------------------------------------------------------ +/** Gets the boundary as sequence of darts, where the edges associated with the darts are boundary + * edges, given a dart with an associating edge at the boundary of a topology structure. + * The first dart in the sequence will be the given one, and the others will have the same + * orientation (CCW or CW) as the first. + * Assumes that the given dart is at the boundary. + * + * \param aDart + * A dart at the boundary (CCW or CW) + * + * \param aBoundary + * A sequence of darts, where the associated edges are the boundary edges + * + * \require + * - DART_LIST_TYPE::push_back (DART_TYPE&) + */ +template +void TRIANGULATION_HELPER::GetBoundary( const DART_TYPE& aDart, DART_LIST_TYPE& aBoundary ) +{ // assumes the given dart is at the boundary (by edge) - - DartType dart_iter(dart); - boundary.push_back(dart_iter); // Given dart as first element - dart_iter.alpha0(); - positionAtNextBoundaryEdge(dart_iter); - - while (dart_iter != dart) { - boundary.push_back(dart_iter); - dart_iter.alpha0(); - positionAtNextBoundaryEdge(dart_iter); + + DART_TYPE dart_iter( aDart ); + aBoundary.push_back( dart_iter ); // Given dart as first element + dart_iter.Alpha0(); + PositionAtNextBoundaryEdge( dart_iter ); + + while( dart_iter != aDart ) + { + aBoundary.push_back( dart_iter ); + dart_iter.Alpha0(); + PositionAtNextBoundaryEdge( dart_iter ); } - } +} - - //------------------------------------------------------------------------------------------------ - /* - // Asumes a fixed point (a boundary edge) is given - // - template - class boundary_1_Iterator { // i.e. "circulator" - - DartType current_; - public: - boundaryEdgeIterator(const DartType& dart) {current_ = dart;} - DartType& operator * () const {return current_;} - void operator ++ () {current_.alpha0(); positionAtNextBoundaryEdge(current_);} - }; - */ - - - //------------------------------------------------------------------------------------------------ - /** Checks if the edge associated with \e dart is at - * the boundary of the triangulation. - * - * \par Implements: - * \code - * DartType dart_iter = dart; - * if (dart_iter.alpha2() == dart) - * return true; - * else - * return false; - * \endcode - */ - template - bool TriangulationHelper::isBoundaryEdge(const DartType& dart) { +/** Checks if the edge associated with \e dart is at + * the boundary of the m_triangulation. + * + * \par Implements: + * \code + * DART_TYPE dart_iter = dart; + * if (dart_iter.Alpha2() == dart) + * return true; + * else + * return false; + * \endcode + */ +template +bool TRIANGULATION_HELPER::IsBoundaryEdge( const DART_TYPE& aDart ) +{ + DART_TYPE dart_iter = aDart; - DartType dart_iter = dart; - if (dart_iter.alpha2() == dart) - return true; - else - return false; - } - - - //------------------------------------------------------------------------------------------------ - /** Checks if the face associated with \e dart is at - * the boundary of the triangulation. - */ - template - bool TriangulationHelper::isBoundaryFace(const DartType& dart) { - - // Strategy: boundary if alpha2(d)=d - - DartType dart_iter(dart); - DartType dart_prev; - - do { - dart_prev = dart_iter; - - if (dart_iter.alpha2() == dart_prev) + if( dart_iter.Alpha2() == aDart ) return true; - else - dart_iter = dart_prev; // back again - - dart_iter.alpha0(); - dart_iter.alpha1(); - - } while (dart_iter != dart); - - return false; - } + else + return false; +} - - //------------------------------------------------------------------------------------------------ - /** Checks if the node associated with \e dart is at - * the boundary of the triangulation. - */ - template - bool TriangulationHelper::isBoundaryNode(const DartType& dart) { - +/** Checks if the face associated with \e dart is at + * the boundary of the m_triangulation. + */ +template +bool TRIANGULATION_HELPER::IsBoundaryFace( const DART_TYPE& aDart ) +{ // Strategy: boundary if alpha2(d)=d - - DartType dart_iter(dart); - DartType dart_prev; - + + DART_TYPE dart_iter( aDart ); + DART_TYPE dart_prev; + + do + { + dart_prev = dart_iter; + + if( dart_iter.Alpha2() == dart_prev ) + return true; + else + dart_iter = dart_prev; // back again + + dart_iter.Alpha0(); + dart_iter.Alpha1(); + + } while( dart_iter != aDart ); + + return false; +} + +/** Checks if the node associated with \e dart is at + * the boundary of the m_triangulation. + */ +template +bool TRIANGULATION_HELPER::IsBoundaryNode( const DART_TYPE& aDart ) +{ + // Strategy: boundary if alpha2(d)=d + + DART_TYPE dart_iter( aDart ); + DART_TYPE dart_prev; + // If input dart is reached again, then internal node // If alpha2(d)=d, then boundary - - do { - dart_iter.alpha1(); - dart_prev = dart_iter; - dart_iter.alpha2(); - - if (dart_iter == dart_prev) - return true; - - } while (dart_iter != dart); - + + do + { + dart_iter.Alpha1(); + dart_prev = dart_iter; + dart_iter.Alpha2(); + + if( dart_iter == dart_prev ) + return true; + + } while( dart_iter != aDart ); + return false; - } +} +/** Returns the degree of the node associated with \e dart. + * + * \par Definition: + * The \e degree (or valency) of a node \e V in a m_triangulation, + * is defined as the number of edges incident with \e V, i.e., + * the number of edges joining \e V with another node in the triangulation. + */ +template +int TRIANGULATION_HELPER::GetDegreeOfNode( const DART_TYPE& aDart ) +{ + DART_TYPE dart_iter( aDart ); + DART_TYPE dart_prev; - //------------------------------------------------------------------------------------------------ - /** Returns the degree of the node associated with \e dart. - * - * \par Definition: - * The \e degree (or valency) of a node \e V in a triangulation, - * is defined as the number of edges incident with \e V, i.e., - * the number of edges joining \e V with another node in the triangulation. - */ - template - int TriangulationHelper::getDegreeOfNode(const DartType& dart) { - - DartType dart_iter(dart); - DartType dart_prev; - // If input dart is reached again, then interior node // If alpha2(d)=d, then boundary - + int degree = 0; bool boundaryVisited = false; - do { - dart_iter.alpha1(); - degree++; - dart_prev = dart_iter; - - dart_iter.alpha2(); - - if (dart_iter == dart_prev) { - if (!boundaryVisited) { - boundaryVisited = true; - // boundary is reached first time, count in the reversed direction - degree++; // count the start since it is not done above - dart_iter = dart; - dart_iter.alpha2(); + do + { + dart_iter.Alpha1(); + degree++; + dart_prev = dart_iter; + + dart_iter.Alpha2(); + + if( dart_iter == dart_prev ) + { + if( !boundaryVisited ) + { + boundaryVisited = true; + // boundary is reached first time, count in the reversed direction + degree++; // count the start since it is not done above + dart_iter = aDart; + dart_iter.Alpha2(); + } else + return degree; } - else - return degree; - } - - } while (dart_iter != dart); - + + } while( dart_iter != aDart ); + return degree; - } +} +// Modification of GetDegreeOfNode: +// Strategy, reverse the list and start in the other direction if the boundary +// is reached. NB. copying of darts but ok., or we could have collected pointers, +// but the memory management. - //------------------------------------------------------------------------------------------------ - // Modification of getDegreeOfNode: - // Strategy, reverse the list and start in the other direction if the boundary - // is reached. NB. copying of darts but ok., or we could have collected pointers, - // but the memory management. - - // NOTE: not symmetry if we choose to collect opposite edges - // now we collect darts with radiating edges - - // Remember that we must also copy the node, but ok with push_back - // The size of the list will be the degree of the node - - // No CW/CCW since topology only - - - // Each dart consists of an incident edge and an adjacent node. - // But note that this is only how we interpret the dart in this implementation. - // Given this list, how can we find the opposite edges: - // We can perform alpha1 on each, but for boundary nodes we will get one edge twice. - // But this is will always be the last dart! - // The darts in the list are in sequence and starts with the alpha0(dart) - // alpha0, alpha1 and alpha2 +// NOTE: not symmetry if we choose to collect opposite edges +// now we collect darts with radiating edges - // Private/Hidden function - template - void TriangulationHelper::getNeighborNodes(const DartType& dart, - std::list& node_list, bool& boundary) { - - DartType dart_iter(dart); - - dart_iter.alpha0(); // position the dart at an opposite node - - DartType dart_prev = dart_iter; - +// Remember that we must also copy the node, but ok with push_back +// The size of the list will be the degree of the node + +// No CW/CCW since topology only + +// Each dart consists of an incident edge and an adjacent node. +// But note that this is only how we interpret the dart in this implementation. +// Given this list, how can we find the opposite edges: +// We can perform alpha1 on each, but for boundary nodes we will get one edge twice. +// But this is will always be the last dart! +// The darts in the list are in sequence and starts with the alpha0(dart) +// alpha0, alpha1 and alpha2 + +// Private/Hidden function +template +void TRIANGULATION_HELPER::getNeighborNodes( const DART_TYPE& aDart, + std::list& aNodeList, bool& aBoundary ) +{ + DART_TYPE dart_iter( aDart ); + dart_iter.Alpha0(); // position the dart at an opposite node + + DART_TYPE dart_prev = dart_iter; bool start_at_boundary = false; - dart_iter.alpha2(); - if (dart_iter == dart_prev) - start_at_boundary = true; + dart_iter.Alpha2(); + + if( dart_iter == dart_prev ) + start_at_boundary = true; else - dart_iter = dart_prev; // back again - - DartType dart_start = dart_iter; - - do { - node_list.push_back(dart_iter); - dart_iter.alpha1(); - dart_iter.alpha0(); - dart_iter.alpha1(); - dart_prev = dart_iter; - dart_iter.alpha2(); - if (dart_iter == dart_prev) { - // boundary reached - boundary = true; - if (start_at_boundary == true) { - // add the dart which now is positioned at the opposite boundary - node_list.push_back(dart_iter); - return; - } - else { - // call the function again such that we start at the boundary - // first clear the list and reposition to the initial node - dart_iter.alpha0(); - node_list.clear(); - getNeighborNodes(dart_iter, node_list, boundary); - return; // after one recursive step - } - } - } while (dart_iter != dart_start); - - boundary = false; - } + dart_iter = dart_prev; // back again + DART_TYPE dart_start = dart_iter; - //------------------------------------------------------------------------------------------------ - /** Gets the 0-orbit around an interior node. - * - * \param dart - * A dart (CCW or CW) positioned at an \e interior node. - * - * \retval orbit - * Sequence of darts with one orbit for each arc. All the darts have the same - * orientation (CCW or CW) as \e dart, and \e dart is the first element - * in the sequence. - * - * \require - * - DartListType::push_back (DartType&) - * - * \see - * get_0_orbit_boundary - */ - template - void TriangulationHelper::get_0_orbit_interior(const DartType& dart, DartListType& orbit) { - - DartType d_iter = dart; - orbit.push_back(d_iter); - d_iter.alpha1().alpha2(); - - while (d_iter != dart) { - orbit.push_back(d_iter); - d_iter.alpha1().alpha2(); + do + { + aNodeList.push_back( dart_iter ); + dart_iter.Alpha1(); + dart_iter.Alpha0(); + dart_iter.Alpha1(); + dart_prev = dart_iter; + dart_iter.Alpha2(); + + if( dart_iter == dart_prev ) + { + // boundary reached + aBoundary = true; + + if( start_at_boundary == true ) + { + // add the dart which now is positioned at the opposite boundary + aNodeList.push_back( dart_iter ); + return; + } + else + { + // call the function again such that we start at the boundary + // first clear the list and reposition to the initial node + dart_iter.Alpha0(); + aNodeList.clear(); + getNeighborNodes( dart_iter, aNodeList, aBoundary ); + + return; // after one recursive step + } + } } - } + while( dart_iter != dart_start ); + aBoundary = false; +} - //------------------------------------------------------------------------------------------------ - /** Gets the 0-orbit around a node at the boundary - * - * \param dart - * A dart (CCW or CW) positioned at a \e boundary \e node and at a \e boundary \e edge. - * - * \retval orbit - * Sequence of darts with one orbit for each arc. All the darts, \e exept \e the \e last one, - * have the same orientation (CCW or CW) as \e dart, and \e dart is the first element - * in the sequence. - * - * \require - * - DartListType::push_back (DartType&) - * - * \note - * - The last dart in the sequence have opposite orientation compared to the others! - * - * \see - * get_0_orbit_interior - */ - template - void TriangulationHelper::get_0_orbit_boundary(const DartType& dart, DartListType& orbit) { +/** Gets the 0-orbit around an interior node. + * + * \param aDart + * A dart (CCW or CW) positioned at an \e interior node. + * + * \retval aOrbit + * Sequence of darts with one orbit for each arc. All the darts have the same + * orientation (CCW or CW) as \e dart, and \e dart is the first element + * in the sequence. + * + * \require + * - DART_LIST_TYPE::push_back (DART_TYPE&) + * + * \see + * Get0OrbitBoundary + */ +template +void TRIANGULATION_HELPER::Get0OrbitInterior( const DART_TYPE& aDart, DART_LIST_TYPE& aOrbit ) +{ + DART_TYPE d_iter = aDart; + aOrbit.push_back( d_iter ); + d_iter.Alpha1().Alpha2(); + + while( d_iter != aDart ) + { + aOrbit.push_back( d_iter ); + d_iter.Alpha1().Alpha2(); + } +} + +/** Gets the 0-orbit around a node at the boundary + * + * \param aDart + * A dart (CCW or CW) positioned at a \e boundary \e node and at a \e boundary \e edge. + * + * \retval orbit + * Sequence of darts with one orbit for each arc. All the darts, \e exept \e the \e last one, + * have the same orientation (CCW or CW) as \e dart, and \e dart is the first element + * in the sequence. + * + * \require + * - DART_LIST_TYPE::push_back (DART_TYPE&) + * + * \note + * - The last dart in the sequence have opposite orientation compared to the others! + * + * \see + * Get0OrbitInterior + */ +template +void TRIANGULATION_HELPER::Get0OrbitBoundary( const DART_TYPE& aDart, DART_LIST_TYPE& aOrbit ) +{ + DART_TYPE dart_prev; + DART_TYPE d_iter = aDart; - DartType dart_prev; - DartType d_iter = dart; - do { - orbit.push_back(d_iter); - d_iter.alpha1(); - dart_prev = d_iter; - d_iter.alpha2(); - } while (d_iter != dart_prev); - - orbit.push_back(d_iter); // the last one with opposite orientation - } + do + { + aOrbit.push_back( d_iter ); + d_iter.Alpha1(); + dart_prev = d_iter; + d_iter.Alpha2(); + } + while( d_iter != dart_prev ); + aOrbit.push_back( d_iter ); // the last one with opposite orientation +} - //------------------------------------------------------------------------------------------------ - /** Checks if the two darts belong to the same 0-orbit, i.e., - * if they share a node. - * \e d1 and/or \e d2 can be CCW or CW. - * - * (This function also examines if the the node associated with - * \e d1 is at the boundary, which slows down the function (slightly). - * If it is known that the node associated with \e d1 is an interior - * node and a faster version is needed, the user should implement his/her - * own version.) - */ - template - bool TriangulationHelper::same_0_orbit(const DartType& d1, const DartType& d2) { - +/** Checks if the two darts belong to the same 0-orbit, i.e., + * if they share a node. + * \e d1 and/or \e d2 can be CCW or CW. + * + * (This function also examines if the the node associated with + * \e d1 is at the boundary, which slows down the function (slightly). + * If it is known that the node associated with \e d1 is an interior + * node and a faster version is needed, the user should implement his/her + * own version.) + */ +template +bool TRIANGULATION_HELPER::Same0Orbit( const DART_TYPE& aD1, const DART_TYPE& aD2 ) +{ // Two copies of the same dart - DartType d_iter = d2; - DartType d_end = d2; - - if (isBoundaryNode(d_iter)) { - // position at both boundary edges - positionAtNextBoundaryEdge(d_iter); - d_end.alpha1(); - positionAtNextBoundaryEdge(d_end); + DART_TYPE d_iter = aD2; + DART_TYPE d_end = aD2; + + if( isBoundaryNode( d_iter ) ) + { + // position at both boundary edges + PositionAtNextBoundaryEdge( d_iter ); + d_end.Alpha1(); + PositionAtNextBoundaryEdge( d_end ); } - - for (;;) { - if (d_iter == d1) - return true; - d_iter.alpha1(); - if (d_iter == d1) - return true; - d_iter.alpha2(); - if (d_iter == d_end) - break; + + for( ;; ) + { + if( d_iter == aD1 ) + return true; + + d_iter.Alpha1(); + + if( d_iter == aD1 ) + return true; + + d_iter.Alpha2(); + + if( d_iter == d_end ) + break; } - + return false; - } +} - - //------------------------------------------------------------------------------------------------ - /** Checks if the two darts belong to the same 1-orbit, i.e., - * if they share an edge. - * \e d1 and/or \e d2 can be CCW or CW. - */ - template - bool TriangulationHelper::same_1_orbit(const DartType& d1, const DartType& d2) { +/** Checks if the two darts belong to the same 1-orbit, i.e., + * if they share an edge. + * \e d1 and/or \e d2 can be CCW or CW. + */ +template +bool TRIANGULATION_HELPER::Same1Orbit( const DART_TYPE& aD1, const DART_TYPE& aD2 ) +{ + DART_TYPE d_iter = aD2; - DartType d_iter = d2; // (Also works at the boundary) - if (d_iter == d1 || d_iter.alpha0() == d1 || d_iter.alpha2() == d1 || d_iter.alpha0() == d1) - return true; - return false; - } + return ( d_iter == aD1 || d_iter.Alpha0() == aD1 || + d_iter.Alpha2() == aD1 || d_iter.Alpha0() == aD1 ); +} - - //------------------------------------------------------------------------------------------------ - /** Checks if the two darts belong to the same 2-orbit, i.e., - * if they lie in the same triangle. - * \e d1 and/or \e d2 can be CCW or CW - */ - template - bool TriangulationHelper::same_2_orbit(const DartType& d1, const DartType& d2) { +//------------------------------------------------------------------------------------------------ +/** Checks if the two darts belong to the same 2-orbit, i.e., + * if they lie in the same triangle. + * \e d1 and/or \e d2 can be CCW or CW + */ +template +bool TRIANGULATION_HELPER::Same2Orbit( const DART_TYPE& aD1, const DART_TYPE& aD2 ) +{ + DART_TYPE d_iter = aD2; - DartType d_iter = d2; - if (d_iter == d1 || d_iter.alpha0() == d1 || - d_iter.alpha1() == d1 || d_iter.alpha0() == d1 || - d_iter.alpha1() == d1 || d_iter.alpha0() == d1) - return true; - return false; - } - + return ( d_iter == aD1 || d_iter.Alpha0() == aD1 || d_iter.Alpha1() == aD1 || + d_iter.Alpha0() == aD1 || d_iter.Alpha1() == aD1 || d_iter.Alpha0() == aD1 ); +} - //------------------------------------------------------------------------------------------------ - // Private/Hidden function - template - bool TriangulationHelper::degenerateTriangle(const DartType& dart) { - +// Private/Hidden function +template +bool TRIANGULATION_HELPER::degenerateTriangle( const DART_TYPE& aDart ) +{ // Check if triangle is degenerate // Assumes CCW dart - - DartType d1 = dart; - DartType d2 = d1; - d2.alpha1(); - if (TraitsType::crossProduct2d(d1,d2) == 0) - return true; - - return false; - } - - //------------------------------------------------------------------------------------------------ - /** Checks if the edge associated with \e dart is swappable, i.e., if the edge - * is a diagonal in a \e strictly convex (or convex) quadrilateral. - * - * \param allowDegeneracy - * If set to true, the function will also return true if the numerical calculations - * indicate that the quadrilateral is convex only, and not necessarily strictly - * convex. - * - * \require - * - \ref hed::TTLtraits::crossProduct2d "TraitsType::crossProduct2d" (Dart&, Dart&) - */ - template - bool TriangulationHelper::swappableEdge(const DartType& dart, bool allowDegeneracy) { + DART_TYPE d1 = aDart; + DART_TYPE d2 = d1; + d2.Alpha1(); + return ( TRAITS_TYPE::CrossProduct2D( d1, d2 ) == 0 ); +} + +/** Checks if the edge associated with \e dart is swappable, i.e., if the edge + * is a diagonal in a \e strictly convex (or convex) quadrilateral. + * + * \param aAllowDegeneracy + * If set to true, the function will also return true if the numerical calculations + * indicate that the quadrilateral is convex only, and not necessarily strictly + * convex. + * + * \require + * - \ref hed::TTLtraits::CrossProduct2D "TRAITS_TYPE::CrossProduct2D" (Dart&, Dart&) + */ +template +bool TRIANGULATION_HELPER::SwappableEdge( const DART_TYPE& aDart, bool aAllowDegeneracy ) +{ // How "safe" is it? - - if (isBoundaryEdge(dart)) - return false; - + + if( IsBoundaryEdge( aDart ) ) + return false; + // "angles" are at the diagonal - DartType d1 = dart; - d1.alpha2().alpha1(); - DartType d2 = dart; - d2.alpha1(); - if (allowDegeneracy) { - if (TraitsType::crossProduct2d(d1,d2) < 0.0) - return false; + DART_TYPE d1 = aDart; + d1.Alpha2().Alpha1(); + DART_TYPE d2 = aDart; + d2.Alpha1(); + + if( aAllowDegeneracy ) + { + if( TRAITS_TYPE::CrossProduct2D( d1, d2 ) < 0.0 ) + return false; } - else { - if (TraitsType::crossProduct2d(d1,d2) <= 0.0) - return false; + else + { + if( TRAITS_TYPE::CrossProduct2D( d1, d2 ) <= 0.0 ) + return false; } - + // Opposite side (still angle at the diagonal) - d1 = dart; - d1.alpha0(); + d1 = aDart; + d1.Alpha0(); d2 = d1; - d1.alpha1(); - d2.alpha2().alpha1(); - - if (allowDegeneracy) { - if (TraitsType::crossProduct2d(d1,d2) < 0.0) - return false; + d1.Alpha1(); + d2.Alpha2().Alpha1(); + + if( aAllowDegeneracy ) + { + if( TRAITS_TYPE::CrossProduct2D( d1, d2 ) < 0.0 ) + return false; } - else { - if (TraitsType::crossProduct2d(d1,d2) <= 0.0) - return false; + else + { + if( TRAITS_TYPE::CrossProduct2D( d1, d2 ) <= 0.0 ) + return false; } + return true; - } +} +/** Given a \e dart, CCW or CW, positioned in a 0-orbit at the boundary of a tessellation. + * Position \e dart at a boundary edge in the same 0-orbit.\n + * If the given \e dart is CCW, \e dart is positioned at the left boundary edge + * and will be CW.\n + * If the given \e dart is CW, \e dart is positioned at the right boundary edge + * and will be CCW. + * + * \note + * - The given \e dart must have a source node at the boundary, otherwise an + * infinit loop occurs. + */ +template +void TRIANGULATION_HELPER::PositionAtNextBoundaryEdge( DART_TYPE& aDart ) +{ + DART_TYPE dart_prev; - //------------------------------------------------------------------------------------------------ - /** Given a \e dart, CCW or CW, positioned in a 0-orbit at the boundary of a tessellation. - * Position \e dart at a boundary edge in the same 0-orbit.\n - * If the given \e dart is CCW, \e dart is positioned at the left boundary edge - * and will be CW.\n - * If the given \e dart is CW, \e dart is positioned at the right boundary edge - * and will be CCW. - * - * \note - * - The given \e dart must have a source node at the boundary, otherwise an - * infinit loop occurs. - */ - template - void TriangulationHelper::positionAtNextBoundaryEdge(DartType& dart) { - - DartType dart_prev; - // If alpha2(d)=d, then boundary - - //old convention: dart.alpha0(); - do { - dart.alpha1(); - dart_prev = dart; - dart.alpha2(); - } while (dart != dart_prev); - } - - //------------------------------------------------------------------------------------------------ - /** Checks if the boundary of a triangulation is convex. - * - * \param dart - * A CCW dart at the boundary of the triangulation - * - * \require - * - \ref hed::TTLtraits::crossProduct2d "TraitsType::crossProduct2d" (const Dart&, const Dart&) - */ - template - bool TriangulationHelper::convexBoundary(const DartType& dart) { - - std::list blist; - getBoundary(dart, blist); - - int no; - no = (int)blist.size(); - typename std::list::const_iterator bit = blist.begin(); - DartType d1 = *bit; - ++bit; - DartType d2; - bool convex = true; - for (; bit != blist.end(); ++bit) { - d2 = *bit; - double crossProd = TraitsType::crossProduct2d(d1, d2); - if (crossProd < 0.0) { - //cout << "!!! Boundary is NOT convex: crossProd = " << crossProd << endl; - convex = false; - return convex; - } - d1 = d2; + //old convention: dart.Alpha0(); + do + { + aDart.Alpha1(); + dart_prev = aDart; + aDart.Alpha2(); } - + while( aDart != dart_prev ); +} + +/** Checks if the boundary of a triangulation is convex. + * + * \param dart + * A CCW dart at the boundary of the m_triangulation + * + * \require + * - \ref hed::TTLtraits::CrossProduct2D "TRAITS_TYPE::CrossProduct2D" (const Dart&, const Dart&) + */ +template +bool TRIANGULATION_HELPER::ConvexBoundary( const DART_TYPE& aDart ) +{ + std::list blist; + getBoundary( aDart, blist ); + + int no; + no = (int) blist.size(); + typename std::list::const_iterator bit = blist.begin(); + DART_TYPE d1 = *bit; + ++bit; + DART_TYPE d2; + bool convex = true; + + for( ; bit != blist.end(); ++bit ) + { + d2 = *bit; + double crossProd = TRAITS_TYPE::CrossProduct2D( d1, d2 ); + + if( crossProd < 0.0 ) + { + //cout << "!!! Boundary is NOT convex: crossProd = " << crossProd << endl; + convex = false; + return convex; + } + + d1 = d2; + } + // Check the last angle d2 = *blist.begin(); - double crossProd = TraitsType::crossProduct2d(d1, d2); - if (crossProd < 0.0) { - //cout << "!!! Boundary is NOT convex: crossProd = " << crossProd << endl; - convex = false; + double crossProd = TRAITS_TYPE::CrossProduct2D( d1, d2 ); + + if( crossProd < 0.0 ) + { + //cout << "!!! Boundary is NOT convex: crossProd = " << crossProd << endl; + convex = false; } - + //if (convex) // cout << "\n---> Boundary is convex\n" << endl; //cout << endl; return convex; - } +} - //@} // End of Topological and Geometric Queries Group +//@} // End of Topological and Geometric Queries Group +/** @name Utilities for Delaunay Triangulation */ +//@{ +//------------------------------------------------------------------------------------------------ +/** Optimizes the edges in the given sequence according to the + * \e Delaunay criterion, i.e., such that the edge will fullfill the + * \e circumcircle criterion (or equivalently the \e MaxMin + * angle criterion) with respect to the quadrilaterals where + * they are diagonals. + * + * \param aElist + * The sequence of edges + * + * \require + * - \ref hed::TTLtraits::swapEdge "TRAITS_TYPE::swapEdge" (DART_TYPE& \e dart)\n + * \b Note: Must be implemented such that \e dart is delivered back in a position as + * seen if it was glued to the edge when swapping (rotating) the edge CCW + * + * \using + * - swapTestDelaunay + */ +template +void TRIANGULATION_HELPER::OptimizeDelaunay( DART_LIST_TYPE& aElist ) +{ + OptimizeDelaunay( aElist, aElist.end() ); +} - //------------------------------------------------------------------------------------------------ - // ------------------------ Utilities for Delaunay Triangulation Group -------------------------- - //------------------------------------------------------------------------------------------------ - - /** @name Utilities for Delaunay Triangulation */ - //@{ - - //------------------------------------------------------------------------------------------------ - /** Optimizes the edges in the given sequence according to the - * \e Delaunay criterion, i.e., such that the edge will fullfill the - * \e circumcircle criterion (or equivalently the \e MaxMin - * angle criterion) with respect to the quadrilaterals where - * they are diagonals. - * - * \param elist - * The sequence of edges - * - * \require - * - \ref hed::TTLtraits::swapEdge "TraitsType::swapEdge" (DartType& \e dart)\n - * \b Note: Must be implemented such that \e dart is delivered back in a position as - * seen if it was glued to the edge when swapping (rotating) the edge CCW - * - * \using - * - swapTestDelaunay - */ - template - void TriangulationHelper::optimizeDelaunay(DartListType& elist) { - optimizeDelaunay(elist, elist.end()); - } - - - //------------------------------------------------------------------------------------------------ - template - void TriangulationHelper::optimizeDelaunay(DartListType& elist, const typename DartListType::iterator end) { - +//------------------------------------------------------------------------------------------------ +template +void TRIANGULATION_HELPER::OptimizeDelaunay( DART_LIST_TYPE& aElist, + const typename DART_LIST_TYPE::iterator aEnd ) +{ // CCW darts // Optimize here means Delaunay, but could be any criterion by // requiring a "should swap" in the traits class, or give // a function object? // Assumes that elist has only one dart for each arc. // Darts outside the quadrilateral are preserved - + // For some data structures it is possible to preserve // all darts when swapping. Thus a preserve_darts_when swapping // ccould be given to indicate this and we would gain performance by avoiding // find in list. - + // Requires that swap retuns a dart in the "same position when rotated CCW" // (A vector instead of a list may be better.) - + // First check that elist is not empty - if (elist.empty()) + if( aElist.empty() ) return; // Avoid cycling by more extensive circumcircle test bool cycling_check = true; bool optimal = false; - typename DartListType::iterator it; + typename DART_LIST_TYPE::iterator it; - typename DartListType::iterator end_opt = end; + typename DART_LIST_TYPE::iterator end_opt = aEnd; // Hmm... The following code is trying to derefence an iterator that may // be invalid. This may lead to debug error on Windows, so we comment out @@ -1491,231 +1488,240 @@ private: // problems... // // last_opt is passed the end of the "active list" - //typename DartListType::iterator end_opt; + //typename DART_LIST_TYPE::iterator end_opt; //if (*end != NULL) // end_opt = end; //else // end_opt = elist.end(); - while(!optimal) { - optimal = true; - for (it = elist.begin(); it != end_opt; ++it) { - if (swapTestDelaunay(*it, cycling_check)) { + while( !optimal ) + { + optimal = true; + for( it = aElist.begin(); it != end_opt; ++it ) + { + if( SwapTestDelaunay( *it, cycling_check ) ) + { + // Preserve darts. Potential darts in the list are: + // - The current dart + // - the four CCW darts on the boundary of the quadrilateral + // (the current arc has only one dart) - // Preserve darts. Potential darts in the list are: - // - The current dart - // - the four CCW darts on the boundary of the quadrilateral - // (the current arc has only one dart) - - swapEdgeInList(it, elist); - - optimal = false; - } // end if should swap - } // end for + SwapEdgeInList( it, aElist ); + + optimal = false; + } // end if should swap + } // end for } // end pass - } +} - - //------------------------------------------------------------------------------------------------ - /** Checks if the edge associated with \e dart should be swapped according - * to the \e Delaunay criterion, i.e., the \e circumcircle criterion (or - * equivalently the \e MaxMin angle criterion). - * - * \param cycling_check - * Must be set to \c true when used in connection with optimization algorithms, - * e.g., optimizeDelaunay. This will avoid cycling and infinite loops in nearly - * neutral cases. - * - * \require - * - \ref hed::TTLtraits::scalarProduct2d "TraitsType::scalarProduct2d" (DartType&, DartType&) - * - \ref hed::TTLtraits::crossProduct2d "TraitsType::crossProduct2d" (DartType&, DartType&) - */ - template +/** Checks if the edge associated with \e dart should be swapped according + * to the \e Delaunay criterion, i.e., the \e circumcircle criterion (or + * equivalently the \e MaxMin angle criterion). + * + * \param aCyclingCheck + * Must be set to \c true when used in connection with optimization algorithms, + * e.g., OptimizeDelaunay. This will avoid cycling and infinite loops in nearly + * neutral cases. + * + * \require + * - \ref hed::TTLtraits::ScalarProduct2D "TRAITS_TYPE::ScalarProduct2D" (DART_TYPE&, DART_TYPE&) + * - \ref hed::TTLtraits::CrossProduct2D "TRAITS_TYPE::CrossProduct2D" (DART_TYPE&, DART_TYPE&) + */ +template #if ((_MSC_VER > 0) && (_MSC_VER < 1300))//#ifdef _MSC_VER - bool TriangulationHelper::swapTestDelaunay(const DartType& dart, bool cycling_check = false) const { +bool TRIANGULATION_HELPER::SwapTestDelaunay(const DART_TYPE& aDart, bool aCyclingCheck = false) const +{ #else - bool TriangulationHelper::swapTestDelaunay(const DartType& dart, bool cycling_check) const { +bool TRIANGULATION_HELPER::SwapTestDelaunay( const DART_TYPE& aDart, bool aCyclingCheck ) const +{ #endif - // The general strategy is taken from Cline & Renka. They claim that // their algorithm insure numerical stability, but experiments show // that this is not correct for neutral, or almost neutral cases. // I have extended this strategy (without using tolerances) to avoid // cycling and infinit loops when used in connection with LOP algorithms; // see the comments below. - - typedef typename TraitsType::real_type real_type; - - if (isBoundaryEdge(dart)) - return false; - - DartType v11 = dart; - v11.alpha1().alpha0(); - DartType v12 = v11; - v12.alpha1(); - - DartType v22 = dart; - v22.alpha2().alpha1().alpha0(); - DartType v21 = v22; - v21.alpha1(); - - real_type cos1 = TraitsType::scalarProduct2d(v11,v12); - real_type cos2 = TraitsType::scalarProduct2d(v21,v22); - + + typedef typename TRAITS_TYPE::REAL_TYPE REAL_TYPE; + + if( IsBoundaryEdge( aDart ) ) + return false; + + DART_TYPE v11 = aDart; + v11.Alpha1().Alpha0(); + DART_TYPE v12 = v11; + v12.Alpha1(); + + DART_TYPE v22 = aDart; + v22.Alpha2().Alpha1().Alpha0(); + DART_TYPE v21 = v22; + v21.Alpha1(); + + REAL_TYPE cos1 = TRAITS_TYPE::ScalarProduct2D( v11, v12 ); + REAL_TYPE cos2 = TRAITS_TYPE::ScalarProduct2D( v21, v22 ); + // "Angles" are opposite to the diagonal. // The diagonals should be swapped iff (t1+t2) .gt. 180 // degrees. The following two tests insure numerical // stability according to Cline & Renka. But experiments show // that cycling may still happen; see the aditional test below. - if (cos1 >= 0 && cos2 >= 0) // both angles are grater or equual 90 - return false; - if (cos1 < 0 && cos2 < 0) // both angles are less than 90 - return true; - - real_type sin1 = TraitsType::crossProduct2d(v11,v12); - real_type sin2 = TraitsType::crossProduct2d(v21,v22); - real_type sin12 = sin1*cos2 + cos1*sin2; - if (sin12 >= 0) // equality represents a neutral case - return false; - - if (cycling_check) { - // situation so far is sin12 < 0. Test if this also - // happens for the swapped edge. - - // The numerical calculations so far indicate that the edge is - // not Delaunay and should not be swapped. But experiments show that - // in neutral cases, or almost neutral cases, it may happen that - // the swapped edge may again be found to be not Delaunay and thus - // be swapped if we return true here. This may lead to cycling and - // an infinte loop when used, e.g., in connection with optimizeDelaunay. - // - // In an attempt to avoid this we test if the swapped edge will - // also be found to be not Delaunay by repeating the last test above - // for the swapped edge. - // We now rely on the general requirement for TraitsType::swapEdge which - // should deliver CCW dart back in "the same position"; see the general - // description. This will insure numerical stability as the next calculation - // is the same as if this function was called again with the swapped edge. - // Cycling is thus impossible provided that the initial tests above does - // not result in ambiguity (and they should probably not do so). - - v11.alpha0(); - v12.alpha0(); - v21.alpha0(); - v22.alpha0(); - // as if the edge was swapped/rotated CCW - cos1 = TraitsType::scalarProduct2d(v22,v11); - cos2 = TraitsType::scalarProduct2d(v12,v21); - sin1 = TraitsType::crossProduct2d(v22,v11); - sin2 = TraitsType::crossProduct2d(v12,v21); - sin12 = sin1*cos2 + cos1*sin2; - if (sin12 < 0) { - // A neutral case, but the tests above lead to swapping + if( cos1 >= 0 && cos2 >= 0 ) // both angles are grater or equual 90 return false; - } + + if( cos1 < 0 && cos2 < 0 ) // both angles are less than 90 + return true; + + REAL_TYPE sin1 = TRAITS_TYPE::CrossProduct2D( v11, v12 ); + REAL_TYPE sin2 = TRAITS_TYPE::CrossProduct2D( v21, v22 ); + REAL_TYPE sin12 = sin1 * cos2 + cos1 * sin2; + + if( sin12 >= 0 ) // equality represents a neutral case + return false; + + if( aCyclingCheck ) + { + // situation so far is sin12 < 0. Test if this also + // happens for the swapped edge. + + // The numerical calculations so far indicate that the edge is + // not Delaunay and should not be swapped. But experiments show that + // in neutral cases, or almost neutral cases, it may happen that + // the swapped edge may again be found to be not Delaunay and thus + // be swapped if we return true here. This may lead to cycling and + // an infinte loop when used, e.g., in connection with OptimizeDelaunay. + // + // In an attempt to avoid this we test if the swapped edge will + // also be found to be not Delaunay by repeating the last test above + // for the swapped edge. + // We now rely on the general requirement for TRAITS_TYPE::swapEdge which + // should deliver CCW dart back in "the same position"; see the general + // description. This will insure numerical stability as the next calculation + // is the same as if this function was called again with the swapped edge. + // Cycling is thus impossible provided that the initial tests above does + // not result in ambiguity (and they should probably not do so). + + v11.Alpha0(); + v12.Alpha0(); + v21.Alpha0(); + v22.Alpha0(); + // as if the edge was swapped/rotated CCW + cos1 = TRAITS_TYPE::ScalarProduct2D( v22, v11 ); + cos2 = TRAITS_TYPE::ScalarProduct2D( v12, v21 ); + sin1 = TRAITS_TYPE::CrossProduct2D( v22, v11 ); + sin2 = TRAITS_TYPE::CrossProduct2D( v12, v21 ); + sin12 = sin1 * cos2 + cos1 * sin2; + + if( sin12 < 0 ) + { + // A neutral case, but the tests above lead to swapping + return false; + } } - + return true; - } +} +//----------------------------------------------------------------------- +// +// x +//" / \ " +// / | \ Darts: +//oe2 / | \ oe2 = oppEdge2 +// x....|....x +// \ d| d/ d = diagonal (input and output) +// \ | / +// oe1 \ / oe1 = oppEdge1 +// x +// +//----------------------------------------------------------------------- +/** Recursively swaps edges in the triangulation according to the \e Delaunay criterion. + * + * \param aDiagonal + * A CCW dart representing the edge where the recursion starts from. + * + * \require + * - \ref hed::TTLtraits::swapEdge "TRAITS_TYPE::swapEdge" (DART_TYPE&)\n + * \b Note: Must be implemented such that the darts outside the quadrilateral + * are not affected by the swap. + * + * \using + * - Calls itself recursively + */ +template +void TRIANGULATION_HELPER::RecSwapDelaunay( DART_TYPE& aDiagonal ) +{ + if( !SwapTestDelaunay( aDiagonal ) ) + // ??? swapTestDelaunay also checks if boundary, so this can be optimized + return; - //----------------------------------------------------------------------- - // - // x - //" / \ " - // / | \ Darts: - //oe2 / | \ oe2 = oppEdge2 - // x....|....x - // \ d| d/ d = diagonal (input and output) - // \ | / - // oe1 \ / oe1 = oppEdge1 - // x - // - //----------------------------------------------------------------------- - /** Recursively swaps edges in the triangulation according to the \e Delaunay criterion. - * - * \param diagonal - * A CCW dart representing the edge where the recursion starts from. - * - * \require - * - \ref hed::TTLtraits::swapEdge "TraitsType::swapEdge" (DartType&)\n - * \b Note: Must be implemented such that the darts outside the quadrilateral - * are not affected by the swap. - * - * \using - * - Calls itself recursively - */ - template - void TriangulationHelper::recSwapDelaunay(DartType& diagonal) { - - if (!swapTestDelaunay(diagonal)) - // ??? swapTestDelaunay also checks if boundary, so this can be optimized - return; - // Get the other "edges" of the current triangle; see illustration above. - DartType oppEdge1 = diagonal; - oppEdge1.alpha1(); + DART_TYPE oppEdge1 = aDiagonal; + oppEdge1.Alpha1(); bool b1; - if (isBoundaryEdge(oppEdge1)) - b1 = true; - else { - b1 = false; - oppEdge1.alpha2(); + + if( IsBoundaryEdge( oppEdge1 ) ) + b1 = true; + else + { + b1 = false; + oppEdge1.Alpha2(); } - - - DartType oppEdge2 = diagonal; - oppEdge2.alpha0().alpha1().alpha0(); + + DART_TYPE oppEdge2 = aDiagonal; + oppEdge2.Alpha0().Alpha1().Alpha0(); bool b2; - if (isBoundaryEdge(oppEdge2)) - b2 = true; - else { - b2 = false; - oppEdge2.alpha2(); + + if( IsBoundaryEdge( oppEdge2 ) ) + b2 = true; + else + { + b2 = false; + oppEdge2.Alpha2(); } - + // Swap the given diagonal - triangulation.swapEdge(diagonal); - - if (!b1) - recSwapDelaunay(oppEdge1); - if (!b2) - recSwapDelaunay(oppEdge2); - } + m_triangulation.swapEdge( aDiagonal ); + if( !b1 ) + RecSwapDelaunay( oppEdge1 ); + + if( !b2 ) + RecSwapDelaunay( oppEdge2 ); +} + +/** Swaps edges away from the (interior) node associated with + * \e dart such that that exactly three edges remain incident + * with the node. + * This function is used as a first step in RemoveInteriorNode + * + * \retval dart + * A CCW dart incident with the node + * + * \par Assumes: + * - The node associated with \e dart is interior to the + * triangulation. + * + * \require + * - \ref hed::TTLtraits::swapEdge "TRAITS_TYPE::swapEdge" (DART_TYPE& \e dart)\n + * \b Note: Must be implemented such that \e dart is delivered back in a position as + * seen if it was glued to the edge when swapping (rotating) the edge CCW + * + * \note + * - A degenerate triangle may be left at the node. + * - The function is not unique as it depends on which dart + * at the node that is given as input. + * + * \see + * SwapEdgesAwayFromBoundaryNode + */ +template +void TRIANGULATION_HELPER::SwapEdgesAwayFromInteriorNode( DART_TYPE& aDart, + LIST_TYPE& aSwappedEdges ) +{ - //------------------------------------------------------------------------------------------------ - /** Swaps edges away from the (interior) node associated with - * \e dart such that that exactly three edges remain incident - * with the node. - * This function is used as a first step in removeInteriorNode - * - * \retval dart - * A CCW dart incident with the node - * - * \par Assumes: - * - The node associated with \e dart is interior to the - * triangulation. - * - * \require - * - \ref hed::TTLtraits::swapEdge "TraitsType::swapEdge" (DartType& \e dart)\n - * \b Note: Must be implemented such that \e dart is delivered back in a position as - * seen if it was glued to the edge when swapping (rotating) the edge CCW - * - * \note - * - A degenerate triangle may be left at the node. - * - The function is not unique as it depends on which dart - * at the node that is given as input. - * - * \see - * swapEdgesAwayFromBoundaryNode - */ - template - void TriangulationHelper::swapEdgesAwayFromInteriorNode(DartType& dart, ListType& swapped_edges) { - // Same iteration as in fixEdgesAtCorner, but not boundary - DartType dnext = dart; - + DART_TYPE dnext = aDart; + // Allow degeneracy, otherwise we might end up with degree=4. // For example, the reverse operation of inserting a point on an // existing edge gives a situation where all edges are non-swappable. @@ -1724,53 +1730,56 @@ private: // ??? An alternative here is to wait with degeneracy till we get an // infinite loop with degree > 3. bool allowDegeneracy = true; - - int degree = getDegreeOfNode(dart); - DartType d_iter; - while (degree > 3) { - d_iter = dnext; - dnext.alpha1().alpha2(); - - if (swappableEdge(d_iter, allowDegeneracy)) { - triangulation.swapEdge(d_iter); // swap the edge away - // Collect swapped edges in the list - // "Hide" the dart on the other side of the edge to avoid it being changed for - // other swaps - DartType swapped_edge = d_iter; // it was delivered back - swapped_edge.alpha2().alpha0(); // CCW (if not at boundary) - swapped_edges.push_back(swapped_edge); - - degree--; - } + + int degree = getDegreeOfNode( aDart ); + DART_TYPE d_iter; + + while( degree > 3 ) + { + d_iter = dnext; + dnext.Alpha1().Alpha2(); + + if( SwappableEdge( d_iter, allowDegeneracy ) ) + { + m_triangulation.swapEdge( d_iter ); // swap the edge away + // Collect swapped edges in the list + // "Hide" the dart on the other side of the edge to avoid it being changed for + // other swaps + DART_TYPE swapped_edge = d_iter; // it was delivered back + swapped_edge.Alpha2().Alpha0(); // CCW (if not at boundary) + aSwappedEdges.push_back( swapped_edge ); + + degree--; + } } + // Output, incident to the node - dart = dnext; - } + aDart = dnext; +} - - //------------------------------------------------------------------------------------------------ - /** Swaps edges away from the (boundary) node associated with - * \e dart in such a way that when removing the edges that remain incident - * with the node, the boundary of the triangulation will be convex. - * This function is used as a first step in removeBoundaryNode - * - * \retval dart - * A CCW dart incident with the node - * - * \require - * - \ref hed::TTLtraits::swapEdge "TraitsType::swapEdge" (DartType& \e dart)\n - * \b Note: Must be implemented such that \e dart is delivered back in a position as - * seen if it was glued to the edge when swapping (rotating) the edge CCW - * - * \par Assumes: - * - The node associated with \e dart is at the boundary of the triangulation. - * - * \see - * swapEdgesAwayFromInteriorNode - */ - template - void TriangulationHelper::swapEdgesAwayFromBoundaryNode(DartType& dart, ListType& swapped_edges) { - +/** Swaps edges away from the (boundary) node associated with + * \e dart in such a way that when removing the edges that remain incident + * with the node, the boundary of the triangulation will be convex. + * This function is used as a first step in RemoveBoundaryNode + * + * \retval dart + * A CCW dart incident with the node + * + * \require + * - \ref hed::TTLtraits::swapEdge "TRAITS_TYPE::swapEdge" (DART_TYPE& \e dart)\n + * \b Note: Must be implemented such that \e dart is delivered back in a position as + * seen if it was glued to the edge when swapping (rotating) the edge CCW + * + * \par Assumes: + * - The node associated with \e dart is at the boundary of the m_triangulation. + * + * \see + * SwapEdgesAwayFromInteriorNode + */ +template +void TRIANGULATION_HELPER::SwapEdgesAwayFromBoundaryNode( DART_TYPE& aDart, + LIST_TYPE& aSwappedEdges ) +{ // All darts that are swappable. // To treat collinear nodes at an existing boundary, we must allow degeneracy // when swapping to the boundary. @@ -1780,98 +1789,108 @@ private: // Assume for the swap in the traits class: // - A dart on the swapped edge is delivered back in a position as // seen if it was glued to the edge when swapping (rotating) the edge CCW - + //int degree = getDegreeOfNode(dart); - -passes: - - // Swap swappable edges that radiate from the node away - DartType d_iter = dart; // ???? can simply use dart - d_iter.alpha1().alpha2(); // first not at boundary - DartType d_next = d_iter; - bool bend = false; - bool swapped_next_to_boundary = false; - bool swapped_in_pass = false; - - bool allowDegeneracy; // = true; - DartType tmp1, tmp2; - - while (!bend) { - - d_next.alpha1().alpha2(); - if (isBoundaryEdge(d_next)) - bend = true; // then it is CW since alpha2 - - // To allow removing among collinear nodes at the boundary, - // degenerate triangles must be allowed - // (they will be removed when used in connection with removeBoundaryNode) - tmp1 = d_iter; tmp1.alpha1(); - tmp2 = d_iter; tmp2.alpha2().alpha1(); // don't bother with boundary (checked later) - - if (isBoundaryEdge(tmp1) && isBoundaryEdge(tmp2)) - allowDegeneracy = true; - else - allowDegeneracy = false; - - if (swappableEdge(d_iter, allowDegeneracy)) { - triangulation.swapEdge(d_iter); - - // Collect swapped edges in the list - // "Hide" the dart on the other side of the edge to avoid it being changed for - // other swapps - DartType swapped_edge = d_iter; // it was delivered back - swapped_edge.alpha2().alpha0(); // CCW - swapped_edges.push_back(swapped_edge); - - //degree--; // if degree is 2, or bend=true, we are done - swapped_in_pass = true; - if (bend) - swapped_next_to_boundary = true; + + passes: + // Swap swappable edges that radiate from the node away + DART_TYPE d_iter = aDart; // ???? can simply use dart + d_iter.Alpha1().Alpha2(); // first not at boundary + DART_TYPE d_next = d_iter; + bool bend = false; + bool swapped_next_to_boundary = false; + bool swapped_in_pass = false; + + bool allowDegeneracy; // = true; + DART_TYPE tmp1, tmp2; + + while( !bend ) + { + d_next.Alpha1().Alpha2(); + + if( IsBoundaryEdge( d_next ) ) + bend = true; // then it is CW since alpha2 + + // To allow removing among collinear nodes at the boundary, + // degenerate triangles must be allowed + // (they will be removed when used in connection with RemoveBoundaryNode) + tmp1 = d_iter; + tmp1.Alpha1(); + tmp2 = d_iter; + tmp2.Alpha2().Alpha1(); // don't bother with boundary (checked later) + + if( IsBoundaryEdge( tmp1 ) && IsBoundaryEdge( tmp2 ) ) + allowDegeneracy = true; + else + allowDegeneracy = false; + + if( SwappableEdge( d_iter, allowDegeneracy ) ) + { + m_triangulation.swapEdge( d_iter ); + + // Collect swapped edges in the list + // "Hide" the dart on the other side of the edge to avoid it being changed for + // other swapps + DART_TYPE swapped_edge = d_iter; // it was delivered back + swapped_edge.Alpha2().Alpha0(); // CCW + aSwappedEdges.push_back( swapped_edge ); + + //degree--; // if degree is 2, or bend=true, we are done + swapped_in_pass = true; + if( bend ) + swapped_next_to_boundary = true; + } + + if( !bend ) + d_iter = d_next; } - if (!bend) - d_iter = d_next; - } - - // Deliver a dart as output in the same position as the incoming dart - if (swapped_next_to_boundary) { - // Assume that "swapping is CCW and dart is preserved in the same position - d_iter.alpha1().alpha0().alpha1(); // CW and see below - } - else { - d_iter.alpha1(); // CW and see below - } - positionAtNextBoundaryEdge(d_iter); // CCW - - dart = d_iter; // for next pass or output - - // If a dart was swapped in this iteration we must run it more - if (swapped_in_pass) - goto passes; - } + // Deliver a dart as output in the same position as the incoming dart + if( swapped_next_to_boundary ) + { + // Assume that "swapping is CCW and dart is preserved in the same position + d_iter.Alpha1().Alpha0().Alpha1(); // CW and see below + } + else + { + d_iter.Alpha1(); // CW and see below + } + PositionAtNextBoundaryEdge( d_iter ); // CCW - //------------------------------------------------------------------------------------------------ - /** Swap the the edge associated with iterator \e it and update affected darts - * in \e elist accordingly. - * The darts affected by the swap are those in the same quadrilateral. - * Thus, if one want to preserve one or more of these darts on should - * keep them in \e elist. - */ - template - void TriangulationHelper::swapEdgeInList(const typename DartListType::iterator& it, DartListType& elist) { + aDart = d_iter; // for next pass or output + + // If a dart was swapped in this iteration we must run it more + if( swapped_in_pass ) + goto passes; +} + +/** Swap the the edge associated with iterator \e it and update affected darts + * in \e elist accordingly. + * The darts affected by the swap are those in the same quadrilateral. + * Thus, if one want to preserve one or more of these darts on should + * keep them in \e elist. + */ +template +void TRIANGULATION_HELPER::SwapEdgeInList( const typename DART_LIST_TYPE::iterator& aIt, + DART_LIST_TYPE& aElist ) +{ + + typename DART_LIST_TYPE::iterator it1, it2, it3, it4; + DART_TYPE dart( *aIt ); + + //typename TRAITS_TYPE::DART_TYPE d1 = dart; d1.Alpha2().Alpha1(); + //typename TRAITS_TYPE::DART_TYPE d2 = d1; d2.Alpha0().Alpha1(); + //typename TRAITS_TYPE::DART_TYPE d3 = dart; d3.Alpha0().Alpha1(); + //typename TRAITS_TYPE::DART_TYPE d4 = d3; d4.Alpha0().Alpha1(); + DART_TYPE d1 = dart; + d1.Alpha2().Alpha1(); + DART_TYPE d2 = d1; + d2.Alpha0().Alpha1(); + DART_TYPE d3 = dart; + d3.Alpha0().Alpha1(); + DART_TYPE d4 = d3; + d4.Alpha0().Alpha1(); - typename DartListType::iterator it1, it2, it3, it4; - DartType dart(*it); - - //typename TraitsType::DartType d1 = dart; d1.alpha2().alpha1(); - //typename TraitsType::DartType d2 = d1; d2.alpha0().alpha1(); - //typename TraitsType::DartType d3 = dart; d3.alpha0().alpha1(); - //typename TraitsType::DartType d4 = d3; d4.alpha0().alpha1(); - DartType d1 = dart; d1.alpha2().alpha1(); - DartType d2 = d1; d2.alpha0().alpha1(); - DartType d3 = dart; d3.alpha0().alpha1(); - DartType d4 = d3; d4.alpha0().alpha1(); - // Find pinters to the darts that may change. // ??? Note, this is not very efficient since we must use find, which is O(N), // four times. @@ -1881,37 +1900,49 @@ passes: // - sould we use another container type or, // - erase them and reinsert? // - or use two lists? - it1 = find(elist.begin(), elist.end(), d1); - it2 = find(elist.begin(), elist.end(), d2); - it3 = find(elist.begin(), elist.end(), d3); - it4 = find(elist.begin(), elist.end(), d4); - - triangulation.swapEdge(dart); + it1 = find( aElist.begin(), aElist.end(), d1 ); + it2 = find( aElist.begin(), aElist.end(), d2 ); + it3 = find( aElist.begin(), aElist.end(), d3 ); + it4 = find( aElist.begin(), aElist.end(), d4 ); + + m_triangulation.swapEdge( dart ); // Update the current dart which may have changed - *it = dart; - + *aIt = dart; + // Update darts that may have changed again (if they were present) // Note that dart is delivered back after swapping - if (it1 != elist.end()) { - d1 = dart; d1.alpha1().alpha0(); - *it1 = d1; + if( it1 != aElist.end() ) + { + d1 = dart; + d1.Alpha1().Alpha0(); + *it1 = d1; } - if (it2 != elist.end()) { - d2 = dart; d2.alpha2().alpha1(); - *it2 = d2; + + if( it2 != aElist.end() ) + { + d2 = dart; + d2.Alpha2().Alpha1(); + *it2 = d2; } - if (it3 != elist.end()) { - d3 = dart; d3.alpha2().alpha1().alpha0().alpha1(); - *it3 = d3; + + if( it3 != aElist.end() ) + { + d3 = dart; + d3.Alpha2().Alpha1().Alpha0().Alpha1(); + *it3 = d3; } - if (it4 != elist.end()) { - d4 = dart; d4.alpha0().alpha1(); - *it4 = d4; + + if( it4 != aElist.end() ) + { + d4 = dart; + d4.Alpha0().Alpha1(); + *it4 = d4; } - } - - //@} // End of Utilities for Delaunay Triangulation Group - -}; // End of ttl namespace scope (but other files may also contain functions for ttl) +} + +//@} // End of Utilities for Delaunay Triangulation Group + +} +// End of ttl namespace scope (but other files may also contain functions for ttl) #endif // _TTL_H_ diff --git a/include/ttl/ttl_util.h b/include/ttl/ttl_util.h index cfdf509531..398f6f316e 100644 --- a/include/ttl/ttl_util.h +++ b/include/ttl/ttl_util.h @@ -3,11 +3,11 @@ * Applied Mathematics, Norway. * * Contact information: E-mail: tor.dokken@sintef.no - * SINTEF ICT, Department of Applied Mathematics, + * SINTEF ICT, DeaPArtment of Applied Mathematics, * P.O. Box 124 Blindern, * 0314 Oslo, Norway. * - * This file is part of TTL. + * This file is aPArt of TTL. * * TTL is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -16,7 +16,7 @@ * * TTL 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 + * MERCHANTABILITY or FITNESS FOR A aPARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public @@ -40,28 +40,22 @@ #ifndef _TTL_UTIL_H_ #define _TTL_UTIL_H_ - #include #include - #ifdef _MSC_VER # if _MSC_VER < 1300 # include # endif #endif - -//using namespace std; - - /** \brief Utilities * -* This name space contains utility functions for TTL.\n +* This name saPAce contains utility functions for TTL.\n * * Point and vector algebra such as scalar product and cross product * between vectors are implemented here. -* These functions are required by functions in the \ref ttl namespace, +* These functions are required by functions in the \ref ttl namesaPAce, * where they are assumed to be present in the \ref hed::TTLtraits "TTLtraits" class. * Thus, the user can call these functions from the traits class. * For efficiency reasons, the user may consider implementing these @@ -77,67 +71,59 @@ * ttl and \ref api * * \author -* Øyvind Hjelle, oyvindhj@ifi.uio.no +* �yvind Hjelle, oyvindhj@ifi.uio.no */ +namespace ttl_util +{ +/** @name Computational geometry */ +//@{ +/** Scalar product between two 2D vectors. + * + * \aPAr Returns: + * \code + * aDX1*aDX2 + aDY1*aDY2 + * \endcode + */ +template +REAL_TYPE ScalarProduct2D( REAL_TYPE aDX1, REAL_TYPE aDY1, REAL_TYPE aDX2, REAL_TYPE aDY2 ) +{ + return aDX1 * aDX2 + aDY1 * aDY2; +} -namespace ttl_util { +/** Cross product between two 2D vectors. (The z-component of the actual cross product.) + * + * \aPAr Returns: + * \code + * aDX1*aDY2 - aDY1*aDX2 + * \endcode + */ +template +REAL_TYPE CrossProduct2D( REAL_TYPE aDX1, REAL_TYPE aDY1, REAL_TYPE aDX2, REAL_TYPE aDY2 ) +{ + return aDX1 * aDY2 - aDY1 * aDX2; +} +/** Returns a positive value if the 2D nodes/points \e aPA, \e aPB, and + * \e aPC occur in counterclockwise order; a negative value if they occur + * in clockwise order; and zero if they are collinear. + * + * \note + * - This is a finite arithmetic fast version. It can be made more robust using + * exact arithmetic schemes by Jonathan Richard Shewchuk. See + * http://www-2.cs.cmu.edu/~quake/robust.html + */ +template +REAL_TYPE Orient2DFast( REAL_TYPE aPA[2], REAL_TYPE aPB[2], REAL_TYPE aPC[2] ) +{ + REAL_TYPE acx = aPA[0] - aPC[0]; + REAL_TYPE bcx = aPB[0] - aPC[0]; + REAL_TYPE acy = aPA[1] - aPC[1]; + REAL_TYPE bcy = aPB[1] - aPC[1]; - //------------------------------------------------------------------------------------------------ - // ------------------------------ Computational Geometry Group ---------------------------------- - //------------------------------------------------------------------------------------------------ - - /** @name Computational geometry */ - //@{ - - //------------------------------------------------------------------------------------------------ - /** Scalar product between two 2D vectors. - * - * \par Returns: - * \code - * dx1*dx2 + dy1*dy2 - * \endcode - */ - template - real_type scalarProduct2d(real_type dx1, real_type dy1, real_type dx2, real_type dy2) { - return dx1*dx2 + dy1*dy2; - } - - - //------------------------------------------------------------------------------------------------ - /** Cross product between two 2D vectors. (The z-component of the actual cross product.) - * - * \par Returns: - * \code - * dx1*dy2 - dy1*dx2 - * \endcode - */ - template - real_type crossProduct2d(real_type dx1, real_type dy1, real_type dx2, real_type dy2) { - return dx1*dy2 - dy1*dx2; - } - - - //------------------------------------------------------------------------------------------------ - /** Returns a positive value if the 2D nodes/points \e pa, \e pb, and - * \e pc occur in counterclockwise order; a negative value if they occur - * in clockwise order; and zero if they are collinear. - * - * \note - * - This is a finite arithmetic fast version. It can be made more robust using - * exact arithmetic schemes by Jonathan Richard Shewchuk. See - * http://www-2.cs.cmu.edu/~quake/robust.html - */ - template - real_type orient2dfast(real_type pa[2], real_type pb[2], real_type pc[2]) { - real_type acx = pa[0] - pc[0]; - real_type bcx = pb[0] - pc[0]; - real_type acy = pa[1] - pc[1]; - real_type bcy = pb[1] - pc[1]; return acx * bcy - acy * bcx; - } +} -}; // End of ttl_util namespace scope +} // namespace ttl_util #endif // _TTL_UTIL_H_ diff --git a/include/view/view.h b/include/view/view.h index f7a7e90984..694042724f 100644 --- a/include/view/view.h +++ b/include/view/view.h @@ -94,7 +94,7 @@ public: * first). * @return Number of found items. */ - int Query( const BOX2I& aRect, std::vector& aResult ); + int Query( const BOX2I& aRect, std::vector& aResult ) const; /** * Function SetRequired() @@ -140,7 +140,10 @@ public: * Function SetPainter() * Sets the painter object used by the view for drawing VIEW_ITEMS. */ - void SetPainter( PAINTER* aPainter ); + void SetPainter( PAINTER* aPainter ) + { + m_painter = aPainter; + } /** * Function GetPainter() @@ -181,7 +184,10 @@ public: * (depending on correct GAL unit length & DPI settings). * @param aScale: the scalefactor */ - void SetScale( double aScale ); + void SetScale( double aScale ) + { + SetScale( aScale, m_center ); + } /** * Function SetScale() @@ -226,6 +232,14 @@ public: */ VECTOR2D ToWorld( const VECTOR2D& aCoord, bool aAbsolute = true ) const; + /** + * Function ToWorld() + * Converts a screen space one dimensional size to a one dimensional size in world + * space coordinates. + * @param aCoord: the size to be converted + */ + double ToWorld( double aSize ) const; + /** * Function ToScreen() * Converts a world space point/vector to a point/vector in screen space coordinates. @@ -247,7 +261,7 @@ public: * Returns the size of the our rendering area, in pixels. * @return viewport screen size */ - VECTOR2D GetScreenPixelSize() const; + const VECTOR2I& GetScreenPixelSize() const; /** * Function AddLayer() @@ -279,11 +293,11 @@ public: */ inline void SetLayerVisible( int aLayer, bool aVisible = true ) { - if( m_layers[aLayer].enabled != aVisible ) + if( m_layers[aLayer].visible != aVisible ) { // Target has to be redrawn after changing its visibility MarkTargetDirty( m_layers[aLayer].target ); - m_layers[aLayer].enabled = aVisible; + m_layers[aLayer].visible = aVisible; } } @@ -294,7 +308,7 @@ public: */ inline bool IsLayerVisible( int aLayer ) const { - return m_layers.at( aLayer ).enabled; + return m_layers.at( aLayer ).visible; } /** @@ -402,18 +416,11 @@ public: */ void Redraw(); - /** - * Function PartialRedraw() - * Redraws only the parts of the view that have been affected by items - * for which ViewUpdate() function has been called since last redraw. - */ - void PartialRedraw(); - /** * Function RecacheAllItems() * Rebuilds GAL display lists. * @param aForceNow decides if every item should be instantly recached. Otherwise items are - * going to be recached when they become visible. + * going to be recached when they become visible. */ void RecacheAllItems( bool aForceNow = false ); @@ -432,7 +439,16 @@ public: * Returns true if any of the VIEW layers needs to be refreshened. * @return True in case if any of layers is marked as dirty. */ - bool IsDirty() const; + bool IsDirty() const + { + for( int i = 0; i < TARGETS_NUMBER; ++i ) + { + if( IsTargetDirty( i ) ) + return true; + } + + return false; + } /** * Function IsTargetDirty() @@ -440,7 +456,12 @@ public: * redrawn. * @return True if the above condition is fulfilled. */ - bool IsTargetDirty( int aTarget ) const; + bool IsTargetDirty( int aTarget ) const + { + wxASSERT( aTarget < TARGETS_NUMBER ); + + return m_dirtyTargets[aTarget]; + } /** * Function MarkTargetDirty() @@ -471,48 +492,33 @@ public: } /** - * Function SetPanBoundary() - * Sets limits for panning area. - * @param aBoundary is the box that limits panning area. + * Function MarkForUpdate() + * Adds an item to a list of items that are going to be refreshed upon the next frame rendering. + * @param aItem is the item to be refreshed. */ - void SetPanBoundary( const BOX2I& aBoundary ) + void MarkForUpdate( VIEW_ITEM* aItem ) { - m_panBoundary = aBoundary; + m_needsUpdate.push_back( aItem ); } /** - * Function SetScaleLimits() - * Sets minimum and maximum values for scale. - * @param aMaximum is the maximum value for scale.. - * @param aMinimum is the minimum value for scale. + * Function UpdateItems() + * Iterates through the list of items that asked for updating and updates them. */ - void SetScaleLimits( double aMaximum, double aMinimum ) - { - wxASSERT_MSG( aMaximum > aMinimum, wxT( "I guess you passed parameters in wrong order" ) ); + void UpdateItems(); - m_scaleLimits = VECTOR2D( aMaximum, aMinimum ); - } - - /** - * Function InvalidateItem() - * Manages dirty flags & redraw queueing when updating an item. - * @param aItem is the item to be updated. - * @param aUpdateFlags determines the way an item is refreshed. - */ - void InvalidateItem( VIEW_ITEM* aItem, int aUpdateFlags ); - - static const int VIEW_MAX_LAYERS = 128; ///* maximum number of layers that may be shown + static const int VIEW_MAX_LAYERS = 128; ///< maximum number of layers that may be shown private: struct VIEW_LAYER { - bool enabled; ///* is the layer to be rendered? - bool displayOnly; ///* is the layer display only? - VIEW_RTREE* items; ///* R-tree indexing all items on this layer. - int renderingOrder; ///* rendering order of this layer - int id; ///* layer ID - RENDER_TARGET target; ///* where the layer should be rendered - std::set requiredLayers; ///* layers that have to be enabled to show the layer + bool visible; ///< is the layer to be rendered? + bool displayOnly; ///< is the layer display only? + VIEW_RTREE* items; ///< R-tree indexing all items on this layer. + int renderingOrder; ///< rendering order of this layer + int id; ///< layer ID + RENDER_TARGET target; ///< where the layer should be rendered + std::set requiredLayers; ///< layers that have to be enabled to show the layer }; // Convenience typedefs @@ -532,7 +538,7 @@ private: ///* Redraws contents within rect aRect void redrawRect( const BOX2I& aRect ); - inline void clearTargetDirty( int aTarget ) + inline void markTargetClean( int aTarget ) { wxASSERT( aTarget < TARGETS_NUMBER ); @@ -549,7 +555,7 @@ private: * @param aImmediate dictates the way of drawing - it allows to force immediate drawing mode * for cached items. */ - void draw( VIEW_ITEM* aItem, int aLayer, bool aImmediate = false ) const; + void draw( VIEW_ITEM* aItem, int aLayer, bool aImmediate = false ); /** * Function draw() @@ -559,7 +565,7 @@ private: * @param aImmediate dictates the way of drawing - it allows to force immediate drawing mode * for cached items. */ - void draw( VIEW_ITEM* aItem, bool aImmediate = false ) const; + void draw( VIEW_ITEM* aItem, bool aImmediate = false ); /** * Function draw() @@ -569,7 +575,7 @@ private: * @param aImmediate dictates the way of drawing - it allows to force immediate drawing mode * for cached items. */ - void draw( VIEW_GROUP* aGroup, bool aImmediate = false ) const; + void draw( VIEW_GROUP* aGroup, bool aImmediate = false ); ///* Sorts m_orderedLayers when layer rendering order has changed void sortLayers(); @@ -578,6 +584,14 @@ private: ///* used by GAL) void clearGroupCache(); + /** + * Function invalidateItem() + * Manages dirty flags & redraw queueing when updating an item. + * @param aItem is the item to be updated. + * @param aUpdateFlags determines the way an item is refreshed. + */ + void invalidateItem( VIEW_ITEM* aItem, int aUpdateFlags ); + /// Updates colors that are used for an item to be drawn void updateItemColor( VIEW_ITEM* aItem, int aLayer ); @@ -633,11 +647,8 @@ private: /// Rendering order modifier for layers that are marked as top layers static const int TOP_LAYER_MODIFIER = -VIEW_MAX_LAYERS; - /// Panning boundaries - BOX2I m_panBoundary; - - /// Zoom limits - VECTOR2D m_scaleLimits; + /// Items to be updated + std::vector m_needsUpdate; }; } // namespace KIGFX diff --git a/include/view/view_controls.h b/include/view/view_controls.h index 5ec1a037a4..90fecd9ef9 100644 --- a/include/view/view_controls.h +++ b/include/view/view_controls.h @@ -46,14 +46,40 @@ class VIEW; class VIEW_CONTROLS { public: - VIEW_CONTROLS( VIEW* aView ) : m_view( aView ), m_forceCursorPosition( false ), - m_snappingEnabled( false ), m_grabMouse( false ), m_autoPanEnabled( false ), - m_autoPanMargin( 0.1 ), m_autoPanSpeed( 0.15 ) - {} + VIEW_CONTROLS( VIEW* aView ) : m_view( aView ), m_minScale( 4.0 ), m_maxScale( 15000 ), + m_forceCursorPosition( false ), m_snappingEnabled( false ), m_grabMouse( false ), + m_autoPanEnabled( false ), m_autoPanMargin( 0.1 ), m_autoPanSpeed( 0.15 ) + { + m_panBoundary.SetMaximum(); + } virtual ~VIEW_CONTROLS() {} + /** + * Function SetPanBoundary() + * Sets limits for panning area. + * @param aBoundary is the box that limits panning area. + */ + void SetPanBoundary( const BOX2I& aBoundary ) + { + m_panBoundary = aBoundary; + } + + /** + * Function SetScaleLimits() + * Sets minimum and maximum values for scale. + * @param aMaximum is the maximum value for scale. + * @param aMinimum is the minimum value for scale. + */ + void SetScaleLimits( double aMaximum, double aMinimum ) + { + wxASSERT_MSG( aMaximum > aMinimum, wxT( "I guess you passed parameters in wrong order" ) ); + + m_minScale = aMinimum; + m_maxScale = aMaximum; + } + /** * Function SetSnapping() * Enables/disables snapping cursor to grid. @@ -108,21 +134,22 @@ public: /** * Function GetMousePosition() - * Returns the current mouse pointer position in the screen coordinates. Note, that it may be + * Returns the current mouse pointer position in screen coordinates. Note, that it may be * different from the cursor position if snapping is enabled (@see GetCursorPosition()). * - * @return The current mouse pointer position. + * @return The current mouse pointer position in screen coordinates. */ - virtual const VECTOR2D GetMousePosition() const = 0; + virtual VECTOR2D GetMousePosition() const = 0; /** * Function GetCursorPosition() - * Returns the current cursor position in the screen coordinates. Note, that it may be - * different from the mouse pointer position if snapping is enabled (@see GetMousePosition()). + * Returns the current cursor position in world coordinates. Note, that it may be + * different from the mouse pointer position if snapping is enabled or cursor position + * is forced to specific point. * - * @return The current cursor position in screen coordinates. + * @return The current cursor position in world coordinates. */ - virtual const VECTOR2D GetCursorPosition() const = 0; + virtual VECTOR2D GetCursorPosition() const = 0; /** @@ -131,7 +158,7 @@ public: * @param aEnabled enable forced cursor position * @param aPosition the position */ - virtual void ForceCursorPosition( bool aEnabled, const VECTOR2D& aPosition = VECTOR2D(0, 0) ) + virtual void ForceCursorPosition( bool aEnabled, const VECTOR2D& aPosition = VECTOR2D( 0, 0 ) ) { m_forcedPosition = aPosition; m_forceCursorPosition = aEnabled; @@ -145,11 +172,23 @@ public: virtual void ShowCursor( bool aEnabled ); protected: + /// Sets center for VIEW, takes into account panning boundaries. + void setCenter( const VECTOR2D& aCenter ); + + /// Sets scale for VIEW, takes into account scale limits. + void setScale( double aScale, const VECTOR2D& aAnchor ); + /// Pointer to controlled VIEW. VIEW* m_view; - /// Current mouse position - VECTOR2D m_mousePosition; + /// Panning boundaries. + BOX2I m_panBoundary; + + /// Scale lower limit. + double m_minScale; + + /// Scale upper limit. + double m_maxScale; /// Current cursor position VECTOR2D m_cursorPosition; diff --git a/include/view/view_item.h b/include/view/view_item.h index f64bb4f1c7..5dfabd7c33 100644 --- a/include/view/view_item.h +++ b/include/view/view_item.h @@ -157,12 +157,16 @@ public: /** * Enum VIEW_UPDATE_FLAGS. * Defines the how severely the shape/appearance of the item has been changed: + * - NONE: TODO * - APPEARANCE: shape or layer set of the item have not been affected, * only colors or visibility. + * - COLOR: * - GEOMETRY: shape or layer set of the item have changed, VIEW may need to reindex it. - * - ALL: all flags above */ + * - LAYERS: TODO + * - ALL: all the flags above */ enum VIEW_UPDATE_FLAGS { + NONE = 0x00, /// No updates are required APPEARANCE = 0x01, /// Visibility flag has changed COLOR = 0x02, /// Color has changed GEOMETRY = 0x04, /// Position or shape has changed @@ -170,7 +174,8 @@ public: ALL = 0xff }; - VIEW_ITEM() : m_view( NULL ), m_visible( true ), m_groups( NULL ), m_groupsSize( 0 ) {} + VIEW_ITEM() : m_view( NULL ), m_visible( true ), m_requiredUpdate( ALL ), + m_groups( NULL ), m_groupsSize( 0 ) {} /** * Destructor. For dynamic views, removes the item from the view. @@ -179,7 +184,7 @@ public: { ViewRelease(); delete[] m_groups; - }; + } /** * Function Type @@ -262,9 +267,15 @@ public: * For dynamic VIEWs, informs the associated VIEW that the graphical representation of * this item has changed. For static views calling has no effect. * - * @param aUpdateFlags: how much the object has changed + * @param aUpdateFlags: how much the object has changed. */ - virtual void ViewUpdate( int aUpdateFlags = ALL ); + virtual void ViewUpdate( int aUpdateFlags = ALL ) + { + if( m_view && m_requiredUpdate == NONE ) + m_view->MarkForUpdate( this ); + + m_requiredUpdate |= aUpdateFlags; + } /** * Function ViewRelease() @@ -298,8 +309,9 @@ protected: deleteGroups(); } - VIEW* m_view; ///* Current dynamic view the item is assigned to. - bool m_visible; ///* Are we visible in the current dynamic VIEW. + VIEW* m_view; ///< Current dynamic view the item is assigned to. + bool m_visible; ///< Are we visible in the current dynamic VIEW. + int m_requiredUpdate; ///< Flag required for updating ///* Helper for storing cached items group ids typedef std::pair GroupPair; @@ -374,6 +386,24 @@ protected: m_layers.set( aLayers[i] ); } } + + /** + * Function viewRequiredUpdate() + * Returns current update flag for an item. + */ + virtual int viewRequiredUpdate() const + { + return m_requiredUpdate; + } + + /** + * Function clearUpdateFlags() + * Marks an item as already updated, so it is not going to be redrawn. + */ + void clearUpdateFlags() + { + m_requiredUpdate = NONE; + } }; } // namespace KIGFX diff --git a/include/view/wx_view_controls.h b/include/view/wx_view_controls.h index 41540e951b..d8722d5b78 100644 --- a/include/view/wx_view_controls.h +++ b/include/view/wx_view_controls.h @@ -58,13 +58,6 @@ public: void onEnter( wxMouseEvent& WXUNUSED( aEvent ) ); void onTimer( wxTimerEvent& WXUNUSED( aEvent ) ); - ///> @copydoc VIEW_CONTROLS::SetSnapping() - void SetSnapping( bool aEnabled ) - { - VIEW_CONTROLS::SetSnapping( aEnabled ); - updateCursor(); - } - /** * Function SetGrabMouse() * Enables/disables mouse cursor grabbing (limits the movement field only to the panel area). @@ -88,13 +81,10 @@ public: } /// @copydoc VIEW_CONTROLS::GetMousePosition() - const VECTOR2D GetMousePosition() const; + VECTOR2D GetMousePosition() const; /// @copydoc VIEW_CONTROLS::GetCursorPosition() - const VECTOR2D GetCursorPosition() const - { - return m_cursorPosition; - } + VECTOR2D GetCursorPosition() const; /// Event that forces mouse move event in the dispatcher (eg. used in autopanning, when mouse /// cursor does not move in screen coordinates, but does in world coordinates) @@ -119,12 +109,6 @@ private: */ bool handleAutoPanning( const wxMouseEvent& aEvent ); - /** - * Function updateCursor() - * Recomputes the cursor coordinates basing on the current snapping settings and mouse position. - */ - void updateCursor(); - /// Current state of VIEW_CONTROLS STATE m_state; diff --git a/include/wxBasePcbFrame.h b/include/wxBasePcbFrame.h index b518af6f12..b2ce7d9a23 100644 --- a/include/wxBasePcbFrame.h +++ b/include/wxBasePcbFrame.h @@ -76,8 +76,8 @@ public: EDA_UNITS_T m_UserGridUnit; wxRealPoint m_UserGridSize; - int m_FastGrid1; - int m_FastGrid2; + int m_FastGrid1; // 1st fast grid setting (index in EDA_DRAW_FRAME::m_gridSelectBox) + int m_FastGrid2; // 2nd fast grid setting (index in EDA_DRAW_FRAME::m_gridSelectBox) EDA_3D_FRAME* m_Draw3DFrame; @@ -90,7 +90,7 @@ protected: /// main window. wxAuiToolBar* m_auxiliaryToolBar; - TOOL_MANAGER* m_toolManager; + TOOL_MANAGER& m_toolManager; TOOL_DISPATCHER* m_toolDispatcher; void updateGridSelectBox(); @@ -203,13 +203,10 @@ public: * Function BestZoom * @return the "best" zoom to show the entire board or footprint on the screen. */ - virtual double BestZoom(); virtual void Show3D_Frame( wxCommandEvent& event ); -public: - // Read/write functions: EDA_ITEM* ReadDrawSegmentDescr( LINE_READER* aReader ); int ReadListeSegmentDescr( LINE_READER* aReader, @@ -634,6 +631,20 @@ public: void OnUpdateSelectGrid( wxUpdateUIEvent& aEvent ); void OnUpdateSelectZoom( wxUpdateUIEvent& aEvent ); + /** + * Function SetFastGrid1() + * + * Switches grid settings to the 1st "fast" setting predefined by user. + */ + void SetFastGrid1(); + + /** + * Function SetFastGrid2() + * + * Switches grid settings to the 1st "fast" setting predefined by user. + */ + void SetFastGrid2(); + DECLARE_EVENT_TABLE() }; diff --git a/include/wxPcbStruct.h b/include/wxPcbStruct.h index 21218d78a9..0e19dc8e22 100644 --- a/include/wxPcbStruct.h +++ b/include/wxPcbStruct.h @@ -134,38 +134,10 @@ protected: void createPopUpBlockMenu( wxMenu* menu ); void createPopUpMenuForMarkers( MARKER_PCB* aMarker, wxMenu* aPopMenu ); - /** - * Function setActiveLayer - * will change the currently active layer to \a aLayer and also - * update the PCB_LAYER_WIDGET. - */ - void setActiveLayer( LAYER_NUM aLayer, bool doLayerWidgetUpdate = true ); - - /** - * Function getActiveLayer - * returns the active layer - */ - LAYER_NUM getActiveLayer() - { - return ( (PCB_SCREEN*) GetScreen() )->m_Active_Layer; - } - - /** - * Function setHighContrastLayer - * takes care of display settings for the given layer to be displayed in high contrast mode. - */ - void setHighContrastLayer( LAYER_NUM aLayer ); - - /** - * Function setTopLayer - * moves the selected layer to the top, so it is displayed above all others. - */ - void setTopLayer( LAYER_NUM aLayer ); - /** * Function syncLayerWidgetLayer * updates the currently layer "selection" within the PCB_LAYER_WIDGET. - * The currently selected layer is defined by the return value of getActiveLayer(). + * The currently selected layer is defined by the return value of GetActiveLayer(). *

* This function cannot be inline without including layer_widget.h in * here and we do not want to do that. @@ -225,8 +197,6 @@ public: bool m_show_microwave_tools; bool m_show_layer_manager_tools; - -public: virtual ~PCB_EDIT_FRAME(); void OnQuit( wxCommandEvent& event ); @@ -560,6 +530,34 @@ public: */ virtual void OnModify(); + /** + * Function SetHighContrastLayer + * takes care of display settings for the given layer to be displayed in high contrast mode. + */ + void SetHighContrastLayer( LAYER_NUM aLayer ); + + /** + * Function SetTopLayer + * moves the selected layer to the top, so it is displayed above all others. + */ + void SetTopLayer( LAYER_NUM aLayer ); + + /** + * Function SetActiveLayer + * will change the currently active layer to \a aLayer and also + * update the PCB_LAYER_WIDGET. + */ + void SetActiveLayer( LAYER_NUM aLayer, bool doLayerWidgetUpdate = true ); + + /** + * Function GetActiveLayer + * returns the active layer + */ + LAYER_NUM GetActiveLayer() const + { + return ( (PCB_SCREEN*) GetScreen() )->m_Active_Layer; + } + /** * Function IsElementVisible * tests whether a given element category is visible. Keep this as an @@ -1479,7 +1477,7 @@ public: /** * Function ReadPcbNetlist - * reads \a aNetlistFileName and ppdates the footprints (load missing footprints and + * reads \a aNetlistFileName and updates the footprints (load missing footprints and * delete on demand extra footprints) on the board. * Update connectivity info, references, values and "TIME STAMP" * @@ -1680,12 +1678,6 @@ public: */ void UpdateTitle(); - void SetTopLayer( LAYER_NUM aLayer ) - { - setTopLayer( aLayer ); - } - - DECLARE_EVENT_TABLE() }; diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index 068f950f39..ae2292bf13 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -253,7 +253,12 @@ set( PCBNEW_CLASS_SRCS tools/selection_tool.cpp tools/selection_area.cpp tools/bright_box.cpp + tools/edit_points.cpp + tools/edit_constraints.cpp + tools/point_editor.cpp + tools/drawing_tool.cpp tools/edit_tool.cpp + tools/pcbnew_control.cpp tools/pcb_tools.cpp tools/common_actions.cpp ) diff --git a/pcbnew/basepcbframe.cpp b/pcbnew/basepcbframe.cpp index af02b79258..3bbade6770 100644 --- a/pcbnew/basepcbframe.cpp +++ b/pcbnew/basepcbframe.cpp @@ -51,7 +51,7 @@ #include #include -#include +#include #include #include #include @@ -78,6 +78,7 @@ static const wxString FastGrid2Entry( wxT( "FastGrid2" ) ); const LAYER_NUM PCB_BASE_FRAME::GAL_LAYER_ORDER[] = { ITEM_GAL_LAYER( GP_OVERLAY ), + ITEM_GAL_LAYER( DRC_VISIBLE ), NETNAMES_GAL_LAYER( PADS_NETNAMES_VISIBLE ), DRAW_N, COMMENT_N, ECO1_N, ECO2_N, EDGE_N, UNUSED_LAYER_29, UNUSED_LAYER_30, UNUSED_LAYER_31, @@ -86,7 +87,7 @@ const LAYER_NUM PCB_BASE_FRAME::GAL_LAYER_ORDER[] = ITEM_GAL_LAYER( RATSNEST_VISIBLE ), ITEM_GAL_LAYER( VIAS_HOLES_VISIBLE ), ITEM_GAL_LAYER( PADS_HOLES_VISIBLE ), - ITEM_GAL_LAYER( VIAS_VISIBLE ), ITEM_GAL_LAYER( PADS_VISIBLE ), + ITEM_GAL_LAYER( VIA_THROUGH_VISIBLE ), ITEM_GAL_LAYER( PADS_VISIBLE ), NETNAMES_GAL_LAYER( PAD_FR_NETNAMES_VISIBLE ), ITEM_GAL_LAYER( PAD_FR_VISIBLE ), SOLDERMASK_N_FRONT, NETNAMES_GAL_LAYER( LAYER_16_NETNAMES_VISIBLE ), LAYER_N_FRONT, @@ -132,10 +133,10 @@ END_EVENT_TABLE() PCB_BASE_FRAME::PCB_BASE_FRAME( KIWAY* aKiway, wxWindow* aParent, FRAME_T aFrameType, const wxString& aTitle, const wxPoint& aPos, const wxSize& aSize, long aStyle, const wxString & aFrameName ) : - EDA_DRAW_FRAME( aKiway, aParent, aFrameType, aTitle, aPos, aSize, aStyle, aFrameName ) + EDA_DRAW_FRAME( aKiway, aParent, aFrameType, aTitle, aPos, aSize, aStyle, aFrameName ), + m_toolManager( TOOL_MANAGER::Instance() ) { m_Pcb = NULL; - m_toolManager = NULL; m_toolDispatcher = NULL; m_DisplayPadFill = true; // How to draw pads @@ -156,7 +157,7 @@ PCB_BASE_FRAME::PCB_BASE_FRAME( KIWAY* aKiway, wxWindow* aParent, FRAME_T aFrame SetGalCanvas( new EDA_DRAW_PANEL_GAL( this, -1, wxPoint( 0, 0 ), m_FrameSize, - EDA_DRAW_PANEL_GAL::GAL_TYPE_OPENGL ) ); + EDA_DRAW_PANEL_GAL::GAL_TYPE_CAIRO ) ); // Hide by default, it has to be explicitly shown GetGalCanvas()->Hide(); @@ -480,7 +481,14 @@ void PCB_BASE_FRAME::OnTogglePadDrawMode( wxCommandEvent& aEvent ) KIGFX::PCB_RENDER_SETTINGS* settings = static_cast ( painter->GetSettings() ); settings->LoadDisplayOptions( DisplayOpt ); - GetGalCanvas()->GetView()->RecacheAllItems( true ); + + // Update pads + BOARD* board = GetBoard(); + for( MODULE* module = board->m_Modules; module; module = module->Next() ) + { + for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() ) + pad->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + } m_canvas->Refresh(); } @@ -641,7 +649,7 @@ void PCB_BASE_FRAME::SetToolID( int aId, int aCursor, const wxString& aToolMsg ) // handle color changes for transitions in and out of ID_TRACK_BUTT if( ( GetToolId() == ID_TRACK_BUTT && aId != ID_TRACK_BUTT ) - || ( GetToolId() != ID_TRACK_BUTT && aId== ID_TRACK_BUTT ) ) + || ( GetToolId() != ID_TRACK_BUTT && aId == ID_TRACK_BUTT ) ) { if( DisplayOpt.ContrastModeDisplay ) redraw = true; @@ -649,7 +657,7 @@ void PCB_BASE_FRAME::SetToolID( int aId, int aCursor, const wxString& aToolMsg ) // must do this after the tool has been set, otherwise pad::Draw() does // not show proper color when DisplayOpt.ContrastModeDisplay is true. - if( redraw && m_canvas) + if( redraw && m_canvas ) m_canvas->Refresh(); } @@ -838,6 +846,9 @@ void PCB_BASE_FRAME::LoadSettings( wxConfigBase* aCfg ) view->SetRequired( SOLDERPASTE_N_BACK, ITEM_GAL_LAYER( PAD_BK_VISIBLE ) ); view->SetRequired( SOLDERMASK_N_BACK, ITEM_GAL_LAYER( PAD_BK_VISIBLE ) ); + view->SetRequired( ITEM_GAL_LAYER( PAD_FR_VISIBLE ), ITEM_GAL_LAYER( MOD_FR_VISIBLE ) ); + view->SetRequired( ITEM_GAL_LAYER( PAD_BK_VISIBLE ), ITEM_GAL_LAYER( MOD_BK_VISIBLE ) ); + view->SetLayerTarget( ITEM_GAL_LAYER( GP_OVERLAY ), KIGFX::TARGET_OVERLAY ); view->SetLayerTarget( ITEM_GAL_LAYER( RATSNEST_VISIBLE ), KIGFX::TARGET_OVERLAY ); @@ -962,3 +973,29 @@ void PCB_BASE_FRAME::updateZoomSelectBox() m_zoomSelectBox->SetSelection( i + 1 ); } } + + +void PCB_BASE_FRAME::SetFastGrid1() +{ + if( m_gridSelectBox ) + { + m_gridSelectBox->SetSelection( m_FastGrid1 ); + + wxCommandEvent cmd( wxEVT_COMMAND_COMBOBOX_SELECTED ); + cmd.SetEventObject( this ); + OnSelectGrid( cmd ); + } +} + + +void PCB_BASE_FRAME::SetFastGrid2() +{ + if( m_gridSelectBox ) + { + m_gridSelectBox->SetSelection( m_FastGrid2 ); + + wxCommandEvent cmd( wxEVT_COMMAND_COMBOBOX_SELECTED ); + cmd.SetEventObject( this ); + OnSelectGrid( cmd ); + } +} diff --git a/pcbnew/board_undo_redo.cpp b/pcbnew/board_undo_redo.cpp index 96d4c844da..db51056d02 100644 --- a/pcbnew/board_undo_redo.cpp +++ b/pcbnew/board_undo_redo.cpp @@ -23,9 +23,10 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ +#include #include #include -#include +#include #include #include @@ -529,7 +530,7 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed if( item->Type() == PCB_MODULE_T ) { MODULE* oldModule = static_cast( item ); - oldModule->RunOnChildren( std::bind1st( std::mem_fun( &KIGFX::VIEW::Remove ), view ) ); + oldModule->RunOnChildren( boost::bind( &KIGFX::VIEW::Remove, view, _1 ) ); } ratsnest->Remove( item ); @@ -540,7 +541,7 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed if( item->Type() == PCB_MODULE_T ) { MODULE* newModule = static_cast( item ); - newModule->RunOnChildren( std::bind1st( std::mem_fun( &KIGFX::VIEW::Add ), view ) ); + newModule->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, view, _1 ) ); } ratsnest->Add( item ); @@ -556,7 +557,7 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed if( item->Type() == PCB_MODULE_T ) { MODULE* module = static_cast( item ); - module->RunOnChildren( std::bind1st( std::mem_fun( &KIGFX::VIEW::Remove ), view ) ); + module->RunOnChildren( boost::bind( &KIGFX::VIEW::Remove, view, _1 ) ); } view->Remove( item ); @@ -570,7 +571,7 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed if( item->Type() == PCB_MODULE_T ) { MODULE* module = static_cast( item ); - module->RunOnChildren( std::bind1st( std::mem_fun( &KIGFX::VIEW::Add ), view ) ); + module->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, view, _1) ); } view->Add( item ); @@ -636,7 +637,7 @@ void PCB_EDIT_FRAME::GetBoardFromUndoList( wxCommandEvent& aEvent ) // Inform tools that undo command was issued TOOL_EVENT event( TC_MESSAGE, TA_UNDO_REDO, AS_GLOBAL ); - m_toolManager->ProcessEvent( event ); + m_toolManager.ProcessEvent( event ); /* Get the old list */ PICKED_ITEMS_LIST* List = GetScreen()->PopCommandFromUndoList(); @@ -659,7 +660,7 @@ void PCB_EDIT_FRAME::GetBoardFromRedoList( wxCommandEvent& aEvent ) // Inform tools that redo command was issued TOOL_EVENT event( TC_MESSAGE, TA_UNDO_REDO, AS_GLOBAL ); - m_toolManager->ProcessEvent( event ); + m_toolManager.ProcessEvent( event ); /* Get the old list */ PICKED_ITEMS_LIST* List = GetScreen()->PopCommandFromRedoList(); diff --git a/pcbnew/class_board.h b/pcbnew/class_board.h index 516d09ca1f..308f69a13d 100644 --- a/pcbnew/class_board.h +++ b/pcbnew/class_board.h @@ -68,8 +68,6 @@ namespace KIGFX // non-owning container of item candidates when searching for items on the same track. typedef std::vector< TRACK* > TRACK_PTRS; -#define HISTORY_MAX_COUNT 8 - /** * Enum LAYER_T @@ -305,13 +303,13 @@ public: // the first value is always the value of the current NetClass // The others values are extra values - /// Vias size and drill list(max count = HISTORY_MAX_COUNT) - std::vector m_ViasDimensionsList; + // The first value is the current netclass via size // TODO verify + /// Vias size and drill list + std::vector m_ViasDimensionsList; - // The first value is the current netclass via size - // tracks widths (max count = HISTORY_MAX_COUNT) - // The first value is the current netclass track width - std::vector m_TrackWidthList; + // The first value is the current netclass track width // TODO verify + /// Track width list + std::vector m_TrackWidthList; BOARD(); diff --git a/pcbnew/class_board_design_settings.cpp b/pcbnew/class_board_design_settings.cpp index ef1b02159b..31ef22a23f 100644 --- a/pcbnew/class_board_design_settings.cpp +++ b/pcbnew/class_board_design_settings.cpp @@ -246,13 +246,13 @@ void BOARD_DESIGN_SETTINGS::SetEnabledLayers( LAYER_MSK aMask ) #ifndef NDEBUG -struct static_check { - static_check() +struct list_size_check { + list_size_check() { // Int (the type used for saving visibility settings) is only 32 bits guaranteed, // be sure that we do not cross the limit assert( END_PCB_VISIBLE_LIST <= 32 ); }; }; -static static_check check; +static list_size_check check; #endif diff --git a/pcbnew/class_dimension.cpp b/pcbnew/class_dimension.cpp index 59ff184ddc..2d554fc737 100644 --- a/pcbnew/class_dimension.cpp +++ b/pcbnew/class_dimension.cpp @@ -47,13 +47,9 @@ DIMENSION::DIMENSION( BOARD_ITEM* aParent ) : BOARD_ITEM( aParent, PCB_DIMENSION_T ), - m_Text( this ) + m_Width( Millimeter2iu( 0.2 ) ), m_Unit( INCHES ), m_Value( 0 ), m_Height( 0 ), m_Text( this ) { m_Layer = DRAW_N; - m_Width = Millimeter2iu( 0.2 ); - m_Value = 0; - m_Shape = 0; - m_Unit = INCHES; } @@ -99,6 +95,7 @@ void DIMENSION::Copy( DIMENSION* source ) SetLayer( source->GetLayer() ); m_Width = source->m_Width; m_Shape = source->m_Shape; + m_Height = source->m_Height; m_Unit = source->m_Unit; SetTimeStamp( GetNewTimeStamp() ); m_Text.Copy( &source->m_Text ); @@ -109,13 +106,9 @@ void DIMENSION::Copy( DIMENSION* source ) m_featureLineGF = source->m_featureLineGF; m_featureLineDO = source->m_featureLineDO; m_featureLineDF = source->m_featureLineDF; - m_arrowD1O = source->m_arrowD1O; m_arrowD1F = source->m_arrowD1F; - m_arrowD2O = source->m_arrowD2O; m_arrowD2F = source->m_arrowD2F; - m_arrowG1O = source->m_arrowG1O; m_arrowG1F = source->m_arrowG1F; - m_arrowG2O = source->m_arrowG2O; m_arrowG2F = source->m_arrowG2F; } @@ -129,13 +122,9 @@ void DIMENSION::Move( const wxPoint& offset ) m_featureLineGF += offset; m_featureLineDO += offset; m_featureLineDF += offset; - m_arrowG1O += offset; m_arrowG1F += offset; - m_arrowG2O += offset; m_arrowG2F += offset; - m_arrowD1O += offset; m_arrowD1F += offset; - m_arrowD2O += offset; m_arrowD2F += offset; } @@ -162,13 +151,9 @@ void DIMENSION::Rotate( const wxPoint& aRotCentre, double aAngle ) RotatePoint( &m_featureLineGF, aRotCentre, aAngle ); RotatePoint( &m_featureLineDO, aRotCentre, aAngle ); RotatePoint( &m_featureLineDF, aRotCentre, aAngle ); - RotatePoint( &m_arrowG1O, aRotCentre, aAngle ); RotatePoint( &m_arrowG1F, aRotCentre, aAngle ); - RotatePoint( &m_arrowG2O, aRotCentre, aAngle ); RotatePoint( &m_arrowG2F, aRotCentre, aAngle ); - RotatePoint( &m_arrowD1O, aRotCentre, aAngle ); RotatePoint( &m_arrowD1F, aRotCentre, aAngle ); - RotatePoint( &m_arrowD2O, aRotCentre, aAngle ); RotatePoint( &m_arrowD2F, aRotCentre, aAngle ); } @@ -190,15 +175,7 @@ void DIMENSION::Mirror( const wxPoint& axis_pos ) m_Text.SetTextPosition( newPos ); // invert angle - double newAngle = m_Text.GetOrientation(); - - if( newAngle >= 3600 ) - newAngle -= 3600; - - if( newAngle > 900 && newAngle < 2700 ) - newAngle -= 1800; - - m_Text.SetOrientation( newAngle ); + m_Text.SetOrientation( -m_Text.GetOrientation() ); INVERT( m_crossBarO.y ); INVERT( m_crossBarF.y ); @@ -206,17 +183,49 @@ void DIMENSION::Mirror( const wxPoint& axis_pos ) INVERT( m_featureLineGF.y ); INVERT( m_featureLineDO.y ); INVERT( m_featureLineDF.y ); - INVERT( m_arrowG1O.y ); INVERT( m_arrowG1F.y ); - INVERT( m_arrowG2O.y ); INVERT( m_arrowG2F.y ); - INVERT( m_arrowD1O.y ); INVERT( m_arrowD1F.y ); - INVERT( m_arrowD2O.y ); INVERT( m_arrowD2F.y ); } +void DIMENSION::SetOrigin( const wxPoint& aOrigin ) +{ + m_featureLineGO = aOrigin; + + AdjustDimensionDetails(); +} + + +void DIMENSION::SetEnd( const wxPoint& aEnd ) +{ + m_featureLineDO = aEnd; + + AdjustDimensionDetails(); +} + + +void DIMENSION::SetHeight( int aHeight ) +{ + m_Height = aHeight; + + AdjustDimensionDetails(); +} + + +void DIMENSION::UpdateHeight() +{ + VECTOR2D featureLine( m_crossBarO - m_featureLineGO ); + VECTOR2D crossBar( m_featureLineDO - m_featureLineGO ); + + if( featureLine.Cross( crossBar ) > 0 ) + m_Height = -featureLine.EuclideanNorm(); + else + m_Height = featureLine.EuclideanNorm(); +} + + void DIMENSION::AdjustDimensionDetails( bool aDoNotChangeText ) { const int arrowz = DMils2iu( 500 ); // size of arrows @@ -271,30 +280,28 @@ void DIMENSION::AdjustDimensionDetails( bool aDoNotChangeText ) arrow_dw_Y = wxRound( arrowz * sin( angle_f ) ); } - m_arrowG1O.x = m_crossBarO.x; - m_arrowG1O.y = m_crossBarO.y; + int dx = KiROUND( m_Height * cos( angle + M_PI / 2 ) ); + int dy = KiROUND( m_Height * sin( angle + M_PI / 2 ) ); + m_crossBarO.x = m_featureLineGO.x + dx; + m_crossBarO.y = m_featureLineGO.y + dy; + m_crossBarF.x = m_featureLineDO.x + dx; + m_crossBarF.y = m_featureLineDO.y + dy; + m_arrowG1F.x = m_crossBarO.x + arrow_up_X; m_arrowG1F.y = m_crossBarO.y + arrow_up_Y; - m_arrowG2O.x = m_crossBarO.x; - m_arrowG2O.y = m_crossBarO.y; m_arrowG2F.x = m_crossBarO.x + arrow_dw_X; m_arrowG2F.y = m_crossBarO.y + arrow_dw_Y; /* The right arrow is symmetrical to the left. * / = -\ and \ = -/ */ - m_arrowD1O.x = m_crossBarF.x; - m_arrowD1O.y = m_crossBarF.y; m_arrowD1F.x = m_crossBarF.x - arrow_dw_X; m_arrowD1F.y = m_crossBarF.y - arrow_dw_Y; - m_arrowD2O.x = m_crossBarF.x; - m_arrowD2O.y = m_crossBarF.y; m_arrowD2F.x = m_crossBarF.x - arrow_up_X; m_arrowD2F.y = m_crossBarF.y - arrow_up_Y; - m_featureLineGF.x = m_crossBarO.x + hx; m_featureLineGF.y = m_crossBarO.y + hy; @@ -358,13 +365,13 @@ void DIMENSION::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE mode_color, m_featureLineGF + offset, width, gcolor ); GRLine( panel->GetClipBox(), DC, m_featureLineDO + offset, m_featureLineDF + offset, width, gcolor ); - GRLine( panel->GetClipBox(), DC, m_arrowD1O + offset, + GRLine( panel->GetClipBox(), DC, m_crossBarF + offset, m_arrowD1F + offset, width, gcolor ); - GRLine( panel->GetClipBox(), DC, m_arrowD2O + offset, + GRLine( panel->GetClipBox(), DC, m_crossBarF + offset, m_arrowD2F + offset, width, gcolor ); - GRLine( panel->GetClipBox(), DC, m_arrowG1O + offset, + GRLine( panel->GetClipBox(), DC, m_crossBarO + offset, m_arrowG1F + offset, width, gcolor ); - GRLine( panel->GetClipBox(), DC, m_arrowG2O + offset, + GRLine( panel->GetClipBox(), DC, m_crossBarO + offset, m_arrowG2F + offset, width, gcolor ); break; @@ -375,13 +382,13 @@ void DIMENSION::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE mode_color, m_featureLineGF + offset, width, gcolor ); GRCSegm( panel->GetClipBox(), DC, m_featureLineDO + offset, m_featureLineDF + offset, width, gcolor ); - GRCSegm( panel->GetClipBox(), DC, m_arrowD1O + offset, + GRCSegm( panel->GetClipBox(), DC, m_crossBarF + offset, m_arrowD1F + offset, width, gcolor ); - GRCSegm( panel->GetClipBox(), DC, m_arrowD2O + offset, + GRCSegm( panel->GetClipBox(), DC, m_crossBarF + offset, m_arrowD2F + offset, width, gcolor ); - GRCSegm( panel->GetClipBox(), DC, m_arrowG1O + offset, + GRCSegm( panel->GetClipBox(), DC, m_crossBarO + offset, m_arrowG1F + offset, width, gcolor ); - GRCSegm( panel->GetClipBox(), DC, m_arrowG2O + offset, + GRCSegm( panel->GetClipBox(), DC, m_crossBarO + offset, m_arrowG2F + offset, width, gcolor ); break; } @@ -414,16 +421,16 @@ bool DIMENSION::HitTest( const wxPoint& aPosition ) const if( TestSegmentHit( aPosition, m_featureLineDO, m_featureLineDF, dist_max ) ) return true; - if( TestSegmentHit( aPosition, m_arrowD1O, m_arrowD1F, dist_max ) ) + if( TestSegmentHit( aPosition, m_crossBarF, m_arrowD1F, dist_max ) ) return true; - if( TestSegmentHit( aPosition, m_arrowD2O, m_arrowD2F, dist_max ) ) + if( TestSegmentHit( aPosition, m_crossBarF, m_arrowD2F, dist_max ) ) return true; - if( TestSegmentHit( aPosition, m_arrowG1O, m_arrowG1F, dist_max ) ) + if( TestSegmentHit( aPosition, m_crossBarO, m_arrowG1F, dist_max ) ) return true; - if( TestSegmentHit( aPosition, m_arrowG2O, m_arrowG2F, dist_max ) ) + if( TestSegmentHit( aPosition, m_crossBarO, m_arrowG2F, dist_max ) ) return true; return false; diff --git a/pcbnew/class_dimension.h b/pcbnew/class_dimension.h index d68fc7770d..440199353d 100644 --- a/pcbnew/class_dimension.h +++ b/pcbnew/class_dimension.h @@ -41,25 +41,40 @@ class TEXTE_PCB; class MSG_PANEL_ITEM; +/** + * Class DIMENSION + * + * For better understanding of the points that make a dimension: + * + * m_featureLineGO m_featureLineDO + * | | + * | | + * | | + * | m_arrowG2F m_arrowD2F | + * | / \ | + * m_crossBarO|/____________________________\|m_crossBarF + * |\ m_Text /| + * | \ / | + * | m_arrowG1F m_arrowD1F | + * | | + * m_featureLineGF m_featureLineDF + */ class DIMENSION : public BOARD_ITEM { - int m_Width; - int m_Shape; // / Currently always 0. - int m_Unit; // / 0 = inches, 1 = mm - int m_Value; // / value of PCB dimensions. - + int m_Width; ///< Line width + int m_Shape; ///< Currently always 0. + EDA_UNITS_T m_Unit; ///< 0 = inches, 1 = mm + int m_Value; ///< value of PCB dimensions. + int m_Height; ///< length of feature lines TEXTE_PCB m_Text; - public: -// private: These member should be private. they are public only due to legacy code +// TODO private: These member should be private. they are public only due to legacy code wxPoint m_crossBarO, m_crossBarF; wxPoint m_featureLineGO, m_featureLineGF; wxPoint m_featureLineDO, m_featureLineDF; - wxPoint m_arrowD1O, m_arrowD1F; - wxPoint m_arrowD2O, m_arrowD2F; - wxPoint m_arrowG1O, m_arrowG1F; - wxPoint m_arrowG2O, m_arrowG2F; + wxPoint m_arrowD1F, m_arrowD2F; + wxPoint m_arrowG1F, m_arrowG2F; DIMENSION( BOARD_ITEM* aParent ); @@ -88,6 +103,72 @@ public: int GetWidth() const { return m_Width; } void SetWidth( int aWidth ) { m_Width = aWidth; } + /** + * Function SetOrigin + * Sets a new origin of the crossbar line. All remaining lines are adjusted after that. + * @param aOrigin is the new point to be used as the new origin of the crossbar line. + */ + void SetOrigin( const wxPoint& aOrigin ); + + /** + * Function GetOrigin + * @return Origin of the crossbar line. + */ + const wxPoint& GetOrigin() const + { + return m_featureLineGO; + } + + /** + * Function SetEnd + * Sets a new end of the crossbar line. All remaining lines are adjusted after that. + * @param aEnd is the new point to be used as the new end of the crossbar line. + */ + void SetEnd( const wxPoint& aEnd ); + + /** + * Function GetEnd + * @return End of the crossbar line. + */ + const wxPoint& GetEnd() + { + return m_featureLineDO; + } + + /** + * Function SetHeight + * Sets the length of feature lines. + * @param aHeight is the new height. + */ + void SetHeight( int aHeight ); + + /** + * Function GetHeight + * Returns the length of feature lines. + */ + int GetHeight() const + { + return m_Height; + } + + /** + * Function UpdateHeight + * Updates stored height basing on points coordinates. + */ + void UpdateHeight(); + + /** + * Function GetAngle + * Returns angle of the crossbar. + * @return Angle of the crossbar line expressed in radians. + */ + double GetAngle() const + { + wxPoint delta( m_featureLineDO - m_featureLineGO ); + + return atan2( delta.y, delta.x ); + } + /** * Function AdjustDimensionDetails * Calculate coordinates of segments used to draw the dimension. diff --git a/pcbnew/class_drawsegment.h b/pcbnew/class_drawsegment.h index 3cae1d9dcf..8e1e22034e 100644 --- a/pcbnew/class_drawsegment.h +++ b/pcbnew/class_drawsegment.h @@ -34,6 +34,7 @@ #include #include #include +#include class LINE_READER; diff --git a/pcbnew/class_marker_pcb.cpp b/pcbnew/class_marker_pcb.cpp index 4e947e07cd..9222698696 100644 --- a/pcbnew/class_marker_pcb.cpp +++ b/pcbnew/class_marker_pcb.cpp @@ -46,7 +46,7 @@ MARKER_PCB::MARKER_PCB( BOARD_ITEM* aParent ) : BOARD_ITEM( aParent, PCB_MARKER_T ), - MARKER_BASE( ) + MARKER_BASE(), m_item( NULL ) { m_Color = WHITE; m_ScalingFactor = SCALING_FACTOR; @@ -57,8 +57,7 @@ MARKER_PCB::MARKER_PCB( int aErrorCode, const wxPoint& aMarkerPos, const wxString& aText, const wxPoint& aPos, const wxString& bText, const wxPoint& bPos ) : BOARD_ITEM( NULL, PCB_MARKER_T ), // parent set during BOARD::Add() - MARKER_BASE( aErrorCode, aMarkerPos, aText, aPos, bText, bPos ) - + MARKER_BASE( aErrorCode, aMarkerPos, aText, aPos, bText, bPos ), m_item( NULL ) { m_Color = WHITE; m_ScalingFactor = SCALING_FACTOR; @@ -67,7 +66,7 @@ MARKER_PCB::MARKER_PCB( int aErrorCode, const wxPoint& aMarkerPos, MARKER_PCB::MARKER_PCB( int aErrorCode, const wxPoint& aMarkerPos, const wxString& aText, const wxPoint& aPos ) : BOARD_ITEM( NULL, PCB_MARKER_T ), // parent set during BOARD::Add() - MARKER_BASE( aErrorCode, aMarkerPos, aText, aPos ) + MARKER_BASE( aErrorCode, aMarkerPos, aText, aPos ), m_item( NULL ) { m_Color = WHITE; m_ScalingFactor = SCALING_FACTOR; @@ -136,3 +135,10 @@ wxString MARKER_PCB::GetSelectMenuText() const return text; } + + +void MARKER_PCB::ViewGetLayers( int aLayers[], int& aCount ) const +{ + aCount = 1; + aLayers[0] = ITEM_GAL_LAYER( DRC_VISIBLE ); +} diff --git a/pcbnew/class_marker_pcb.h b/pcbnew/class_marker_pcb.h index 5e794a743c..05e73ef3da 100644 --- a/pcbnew/class_marker_pcb.h +++ b/pcbnew/class_marker_pcb.h @@ -64,6 +64,16 @@ public: const wxPoint& GetPosition() const { return m_Pos; } void SetPosition( const wxPoint& aPos ) { m_Pos = aPos; } + void SetItem( const BOARD_ITEM* aItem ) + { + m_item = aItem; + } + + const BOARD_ITEM* GetItem() const + { + return m_item; + } + bool HitTest( const wxPoint& aPosition ) const { return HitTestMarker( aPosition ); @@ -77,9 +87,22 @@ public: BITMAP_DEF GetMenuImage() const { return drc_xpm; } + ///> @copydoc VIEW_ITEM::ViewBBox() + virtual const BOX2I ViewBBox() const + { + return GetParent()->ViewBBox(); + } + + ///> @copydoc VIEW_ITEM::ViewGetLayers() + virtual void ViewGetLayers( int aLayers[], int& aCount ) const; + #if defined(DEBUG) void Show( int nestLevel, std::ostream& os ) const { ShowDummy( os ); } // override #endif + +protected: + ///> Pointer to BOARD_ITEM that causes DRC error. + const BOARD_ITEM* m_item; }; #endif // CLASS_MARKER_PCB_H diff --git a/pcbnew/class_module.cpp b/pcbnew/class_module.cpp index 257f34bd6e..bc55907cb3 100644 --- a/pcbnew/class_module.cpp +++ b/pcbnew/class_module.cpp @@ -749,20 +749,20 @@ void MODULE::ViewUpdate( int aUpdateFlags ) if( !m_view ) return; + // Update the module itself + VIEW_ITEM::ViewUpdate( aUpdateFlags ); + // Update pads for( D_PAD* pad = m_Pads.GetFirst(); pad; pad = pad->Next() ) - m_view->InvalidateItem( pad, aUpdateFlags ); + pad->ViewUpdate( aUpdateFlags ); // Update module's drawing (mostly silkscreen) for( BOARD_ITEM* drawing = m_Drawings.GetFirst(); drawing; drawing = drawing->Next() ) - m_view->InvalidateItem( drawing, aUpdateFlags ); + drawing->ViewUpdate( aUpdateFlags ); // Update module's texts - m_view->InvalidateItem( m_Reference, aUpdateFlags ); - m_view->InvalidateItem( m_Value, aUpdateFlags ); - - // Update the module itself - m_view->InvalidateItem( this, aUpdateFlags ); + m_Reference->ViewUpdate( aUpdateFlags ); + m_Value->ViewUpdate( aUpdateFlags ); } diff --git a/pcbnew/class_pcb_layer_widget.cpp b/pcbnew/class_pcb_layer_widget.cpp index 12f28370a5..41e346a2a0 100644 --- a/pcbnew/class_pcb_layer_widget.cpp +++ b/pcbnew/class_pcb_layer_widget.cpp @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include @@ -185,7 +185,7 @@ void PCB_LAYER_WIDGET::onPopupSelection( wxCommandEvent& event ) if( IsCopperLayer( layer ) ) { bool loc_visible = visible; - if( force_active_layer_visible && (layer == myframe->getActiveLayer() ) ) + if( force_active_layer_visible && (layer == myframe->GetActiveLayer() ) ) loc_visible = true; cb->SetValue( loc_visible ); @@ -356,7 +356,7 @@ bool PCB_LAYER_WIDGET::OnLayerSelect( LAYER_NUM aLayer ) { // the layer change from the PCB_LAYER_WIDGET can be denied by returning // false from this function. - myframe->setActiveLayer( aLayer, false ); + myframe->SetActiveLayer( aLayer, false ); if( m_alwaysShowActiveCopperLayer ) OnLayerSelected(); diff --git a/pcbnew/class_text_mod.h b/pcbnew/class_text_mod.h index 7ab96e516b..8c76e70c22 100644 --- a/pcbnew/class_text_mod.h +++ b/pcbnew/class_text_mod.h @@ -87,11 +87,13 @@ public: virtual void SetPosition( const wxPoint& aPos ) { m_Pos = aPos; + SetLocalCoord(); } void Move( const wxPoint& aMoveVector ) { m_Pos += aMoveVector; + SetLocalCoord(); } void Rotate( const wxPoint& aRotCentre, double aAngle ); @@ -106,7 +108,7 @@ public: void SetVisible( bool isVisible ) { m_NoShow = !isVisible; } bool IsVisible() const { return !m_NoShow; } - void SetPos0( const wxPoint& aPos ) { m_Pos0 = aPos; } + void SetPos0( const wxPoint& aPos ) { m_Pos0 = aPos; SetDrawCoord(); } const wxPoint& GetPos0() const { return m_Pos0; } void Copy( TEXTE_MODULE* source ); // copy structure diff --git a/pcbnew/class_track.cpp b/pcbnew/class_track.cpp index 02872390bf..130104e0b1 100644 --- a/pcbnew/class_track.cpp +++ b/pcbnew/class_track.cpp @@ -996,7 +996,7 @@ void VIA::Draw( EDA_DRAW_PANEL* panel, wxDC* aDC, GR_DRAWMODE aDrawMode, void VIA::ViewGetLayers( int aLayers[], int& aCount ) const { // Just show it on common via & via holes layers - aLayers[0] = ITEM_GAL_LAYER( VIAS_VISIBLE ); + aLayers[0] = ITEM_GAL_LAYER( VIA_THROUGH_VISIBLE ); aLayers[1] = ITEM_GAL_LAYER( VIAS_HOLES_VISIBLE ); aCount = 2; } diff --git a/pcbnew/class_zone.h b/pcbnew/class_zone.h index 2642937d06..332fc84144 100644 --- a/pcbnew/class_zone.h +++ b/pcbnew/class_zone.h @@ -362,19 +362,6 @@ public: */ bool HitTest( const EDA_RECT& aRect, bool aContained = true, int aAccuracy = 0 ) const; - /** - * Function Fill_Zone - * Calculate the zone filling - * The zone outline is a frontier, and can be complex (with holes) - * The filling starts from starting points like pads, tracks. - * If exists the old filling is removed - * @param frame = reference to the main frame - * @param DC = current Device Context - * @param verbose = true to show error messages - * @return error level (0 = no error) - */ - int Fill_Zone( PCB_EDIT_FRAME* frame, wxDC* DC, bool verbose = true ); - /** * Function FillZoneAreasWithSegments * Fill sub areas in a zone with segments with m_ZoneMinThickness width diff --git a/pcbnew/clean.cpp b/pcbnew/clean.cpp index 6c50bd1808..fce7fd632c 100644 --- a/pcbnew/clean.cpp +++ b/pcbnew/clean.cpp @@ -38,6 +38,7 @@ #include #include #include +#include // Helper class used to clean tracks and vias class TRACKS_CLEANER: CONNECTIONS @@ -225,6 +226,8 @@ bool TRACKS_CLEANER::remove_duplicates_of_via( const VIA *aVia ) (alt_via->GetStart() == aVia->GetStart()) ) { // delete via + m_Brd->GetRatsnest()->Remove( alt_via ); + alt_via->ViewRelease(); alt_via->DeleteStructure(); modified = true; } @@ -262,6 +265,8 @@ bool TRACKS_CLEANER::clean_vias() if( (pad->GetLayerMask() & ALL_CU_LAYERS) == ALL_CU_LAYERS ) { // redundant: delete the via + m_Brd->GetRatsnest()->Remove( via ); + via->ViewRelease(); via->DeleteStructure(); modified = true; break; @@ -372,6 +377,8 @@ bool TRACKS_CLEANER::deleteUnconnectedTracks() if( flag_erase ) { // remove segment from board + m_Brd->GetRatsnest()->Remove( track ); + track->ViewRelease(); track->DeleteStructure(); /* keep iterating, because a track connected to the deleted track @@ -398,6 +405,8 @@ bool TRACKS_CLEANER::delete_null_segments() if( segment->IsNull() ) // Length segment = 0; delete it { + m_Brd->GetRatsnest()->Remove( segment ); + segment->ViewRelease(); segment->DeleteStructure(); modified = true; } @@ -428,6 +437,8 @@ bool TRACKS_CLEANER::remove_duplicates_of_track( const TRACK *aTrack ) ((aTrack->GetStart() == other->GetEnd()) && (aTrack->GetEnd() == other->GetStart()))) { + m_Brd->GetRatsnest()->Remove( other ); + other->ViewRelease(); other->DeleteStructure(); modified = true; } @@ -476,6 +487,8 @@ bool TRACKS_CLEANER::merge_collinear_of_track( TRACK *aSegment ) if( segDelete ) { + m_Brd->GetRatsnest()->Remove( segDelete ); + segDelete->ViewRelease(); segDelete->DeleteStructure(); merged_this = true; } @@ -520,6 +533,8 @@ bool TRACKS_CLEANER::merge_collinear_of_track( TRACK *aSegment ) if( segDelete ) { + m_Brd->GetRatsnest()->Remove( segDelete ); + segDelete->ViewRelease(); segDelete->DeleteStructure(); merged_this = true; } @@ -663,6 +678,7 @@ TRACK* TRACKS_CLEANER::mergeCollinearSegmentIfPossible( TRACK* aTrackRef, TRACK* aTrackRef->SetStart( aCandidate->GetEnd()); aTrackRef->start = aCandidate->end; aTrackRef->SetState( START_ON_PAD, aCandidate->GetState( END_ON_PAD) ); + aTrackRef->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); return aCandidate; } else @@ -670,6 +686,7 @@ TRACK* TRACKS_CLEANER::mergeCollinearSegmentIfPossible( TRACK* aTrackRef, TRACK* aTrackRef->SetStart( aCandidate->GetStart() ); aTrackRef->start = aCandidate->start; aTrackRef->SetState( START_ON_PAD, aCandidate->GetState( START_ON_PAD) ); + aTrackRef->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); return aCandidate; } } @@ -686,6 +703,7 @@ TRACK* TRACKS_CLEANER::mergeCollinearSegmentIfPossible( TRACK* aTrackRef, TRACK* aTrackRef->SetEnd( aCandidate->GetEnd() ); aTrackRef->end = aCandidate->end; aTrackRef->SetState( END_ON_PAD, aCandidate->GetState( END_ON_PAD) ); + aTrackRef->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); return aCandidate; } else @@ -693,6 +711,7 @@ TRACK* TRACKS_CLEANER::mergeCollinearSegmentIfPossible( TRACK* aTrackRef, TRACK* aTrackRef->SetEnd( aCandidate->GetStart() ); aTrackRef->end = aCandidate->start; aTrackRef->SetState( END_ON_PAD, aCandidate->GetState( START_ON_PAD) ); + aTrackRef->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); return aCandidate; } } diff --git a/pcbnew/deltrack.cpp b/pcbnew/deltrack.cpp index 331fbd22ab..42c98cd605 100644 --- a/pcbnew/deltrack.cpp +++ b/pcbnew/deltrack.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -53,7 +54,7 @@ TRACK* PCB_EDIT_FRAME::Delete_Segment( wxDC* DC, TRACK* aTrack ) { if( g_CurrentTrackList.GetCount() > 0 ) { - LAYER_NUM previous_layer = getActiveLayer(); + LAYER_NUM previous_layer = GetActiveLayer(); DBG( g_CurrentTrackList.VerifyListIntegrity(); ) @@ -86,7 +87,7 @@ TRACK* PCB_EDIT_FRAME::Delete_Segment( wxDC* DC, TRACK* aTrack ) // Correct active layer which could change if a via // has been erased - setActiveLayer( previous_layer ); + SetActiveLayer( previous_layer ); UpdateStatusBar(); @@ -124,6 +125,8 @@ TRACK* PCB_EDIT_FRAME::Delete_Segment( wxDC* DC, TRACK* aTrack ) DLIST* container = (DLIST*)aTrack->GetList(); wxASSERT( container ); + GetBoard()->GetRatsnest()->Remove( aTrack ); + aTrack->ViewRelease(); container->Remove( aTrack ); // redraw the area where the track was @@ -174,6 +177,8 @@ void PCB_EDIT_FRAME::Delete_net( wxDC* DC, TRACK* aTrack ) if( segm->GetNetCode() != net_code_delete ) break; + GetBoard()->GetRatsnest()->Remove( segm ); + segm->ViewRelease(); GetBoard()->m_Track.Remove( segm ); // redraw the area where the track was @@ -219,6 +224,8 @@ void PCB_EDIT_FRAME::Remove_One_Track( wxDC* DC, TRACK* pt_segm ) << TO_UTF8( TRACK::ShowState( tracksegment->GetStatus() ) ) \ << std::endl; ) + GetBoard()->GetRatsnest()->Remove( tracksegment ); + tracksegment->ViewRelease(); GetBoard()->m_Track.Remove( tracksegment ); // redraw the area where the track was diff --git a/pcbnew/dialogs/dialog_display_options.cpp b/pcbnew/dialogs/dialog_display_options.cpp index 0aa91d1302..5ad1e752f4 100644 --- a/pcbnew/dialogs/dialog_display_options.cpp +++ b/pcbnew/dialogs/dialog_display_options.cpp @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include @@ -177,10 +177,7 @@ void DIALOG_DISPLAY_OPTIONS::OnOkClick(wxCommandEvent& event) settings->LoadDisplayOptions( DisplayOpt ); view->RecacheAllItems( true ); - if( m_Parent->IsGalCanvasActive() ) - m_Parent->GetGalCanvas()->Refresh(); - else - m_Parent->GetCanvas()->Refresh(); + m_Parent->GetCanvas()->Refresh(); EndModal( 1 ); } diff --git a/pcbnew/dialogs/dialog_general_options.cpp b/pcbnew/dialogs/dialog_general_options.cpp index cf2e5b607f..9adc32bdf6 100644 --- a/pcbnew/dialogs/dialog_general_options.cpp +++ b/pcbnew/dialogs/dialog_general_options.cpp @@ -40,9 +40,10 @@ #include #include #include +#include #include -#include +#include #include #include #include @@ -157,7 +158,7 @@ void PCB_EDIT_FRAME::OnSelectOptionToolbar( wxCommandEvent& event ) static_cast ( GetGalCanvas()->GetView()->GetPainter() ); KIGFX::PCB_RENDER_SETTINGS* settings = static_cast ( painter->GetSettings() ); - bool recache = false; + KICAD_T updateType = EOT; switch( id ) { @@ -192,31 +193,31 @@ void PCB_EDIT_FRAME::OnSelectOptionToolbar( wxCommandEvent& event ) case ID_TB_OPTIONS_SHOW_ZONES: DisplayOpt.DisplayZonesMode = 0; - recache = true; + updateType = PCB_ZONE_AREA_T; m_canvas->Refresh(); break; case ID_TB_OPTIONS_SHOW_ZONES_DISABLE: DisplayOpt.DisplayZonesMode = 1; - recache = true; + updateType = PCB_ZONE_AREA_T; m_canvas->Refresh(); break; case ID_TB_OPTIONS_SHOW_ZONES_OUTLINES_ONLY: DisplayOpt.DisplayZonesMode = 2; - recache = true; + updateType = PCB_ZONE_AREA_T; m_canvas->Refresh(); break; case ID_TB_OPTIONS_SHOW_VIAS_SKETCH: m_DisplayViaFill = DisplayOpt.DisplayViaFill = !state; - recache = true; + updateType = PCB_VIA_T; m_canvas->Refresh(); break; case ID_TB_OPTIONS_SHOW_TRACKS_SKETCH: m_DisplayPcbTrackFill = DisplayOpt.DisplayPcbTrackFill = !state; - recache = true; + updateType = PCB_TRACE_T; m_canvas->Refresh(); break; @@ -227,7 +228,7 @@ void PCB_EDIT_FRAME::OnSelectOptionToolbar( wxCommandEvent& event ) // Apply new display options to the GAL canvas (this is faster than recaching) settings->LoadDisplayOptions( DisplayOpt ); - setHighContrastLayer( getActiveLayer() ); + SetHighContrastLayer( GetActiveLayer() ); m_canvas->Refresh(); break; @@ -260,11 +261,18 @@ void PCB_EDIT_FRAME::OnSelectOptionToolbar( wxCommandEvent& event ) break; } - if( recache ) + if( updateType != EOT ) { // Apply new display options to the GAL canvas settings->LoadDisplayOptions( DisplayOpt ); - GetGalCanvas()->GetView()->RecacheAllItems( true ); + + // Find items that require update + KICAD_T scanList[] = { updateType, EOT }; + TYPE_COLLECTOR collector; + collector.Collect( GetBoard(), scanList ); + + for( int i = 0; i < collector.GetCount(); ++i ) + collector[i]->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } if( IsGalCanvasActive() ) diff --git a/pcbnew/dialogs/dialog_global_deletion.cpp b/pcbnew/dialogs/dialog_global_deletion.cpp index 69eec16422..318da30d64 100644 --- a/pcbnew/dialogs/dialog_global_deletion.cpp +++ b/pcbnew/dialogs/dialog_global_deletion.cpp @@ -1,7 +1,27 @@ -/** - * @file dialog_global_deletion.cpp +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 1992-2014 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ +#include #include #include @@ -9,6 +29,7 @@ #include #include #include +#include #include #include @@ -39,7 +60,7 @@ DIALOG_GLOBAL_DELETION::DIALOG_GLOBAL_DELETION( PCB_EDIT_FRAME* parent ) void PCB_EDIT_FRAME::InstallPcbGlobalDeleteFrame( const wxPoint& pos ) { DIALOG_GLOBAL_DELETION dlg( this ); - dlg.SetCurrentLayer( getActiveLayer() ); + dlg.SetCurrentLayer( GetActiveLayer() ); dlg.ShowModal(); } @@ -80,14 +101,15 @@ void DIALOG_GLOBAL_DELETION::AcceptPcbDelete( ) } else { - if( !IsOK( this, _( "Are you sure you want to delete the selected items?" ) ) ) return; BOARD* pcb = m_Parent->GetBoard(); PICKED_ITEMS_LIST pickersList; ITEM_PICKER itemPicker( NULL, UR_DELETED ); - BOARD_ITEM* item, * nextitem; + BOARD_ITEM* item; + BOARD_ITEM* nextitem; + RN_DATA* ratsnest = pcb->GetRatsnest(); LAYER_MSK layers_filter = ALL_LAYERS; @@ -101,12 +123,13 @@ void DIALOG_GLOBAL_DELETION::AcceptPcbDelete( ) while( item != NULL ) { - if( GetLayerMask( item->GetLayer() ) & layers_filter ) { itemPicker.SetItem( item ); pickersList.PushItem( itemPicker ); pcb->Remove( item ); + item->ViewRelease(); + ratsnest->Remove( item ); gen_rastnest = true; } else @@ -138,6 +161,7 @@ void DIALOG_GLOBAL_DELETION::AcceptPcbDelete( ) { itemPicker.SetItem( item ); pickersList.PushItem( itemPicker ); + item->ViewRelease(); item->UnLink(); } } @@ -155,6 +179,7 @@ void DIALOG_GLOBAL_DELETION::AcceptPcbDelete( ) { itemPicker.SetItem( item ); pickersList.PushItem( itemPicker ); + item->ViewRelease(); item->UnLink(); } } @@ -162,7 +187,6 @@ void DIALOG_GLOBAL_DELETION::AcceptPcbDelete( ) if( m_DelModules->GetValue() ) { - for( item = pcb->m_Modules; item; item = nextitem ) { nextitem = item->Next(); @@ -173,6 +197,10 @@ void DIALOG_GLOBAL_DELETION::AcceptPcbDelete( ) { itemPicker.SetItem( item ); pickersList.PushItem( itemPicker ); + static_cast( item )->RunOnChildren( + boost::bind( &KIGFX::VIEW_ITEM::ViewRelease, _1 ) ); + ratsnest->Remove( item ); + item->ViewRelease(); item->UnLink(); gen_rastnest = true; } @@ -189,27 +217,29 @@ void DIALOG_GLOBAL_DELETION::AcceptPcbDelete( ) if( !m_TrackFilterAR->GetValue() ) track_mask_filter |= TRACK_AR; - TRACK * nexttrack; + TRACK* nexttrack; for( TRACK *track = pcb->m_Track; track != NULL; track = nexttrack ) { nexttrack = track->Next(); - if( (track->GetState( TRACK_LOCKED | TRACK_AR ) & track_mask_filter) != 0 ) + if( ( track->GetState( TRACK_LOCKED | TRACK_AR ) & track_mask_filter ) != 0 ) continue; - if( (track->GetState( TRACK_LOCKED | TRACK_AR ) == 0) && + if( ( track->GetState( TRACK_LOCKED | TRACK_AR ) == 0 ) && !m_TrackFilterNormal->GetValue() ) continue; - if( (track->Type() == PCB_VIA_T) && !m_TrackFilterVias->GetValue() ) + if( ( track->Type() == PCB_VIA_T ) && !m_TrackFilterVias->GetValue() ) continue; - if( (track->GetLayerMask() & layers_filter) == 0 ) + if( ( track->GetLayerMask() & layers_filter ) == 0 ) continue; itemPicker.SetItem( track ); pickersList.PushItem( itemPicker ); + track->ViewRelease(); + ratsnest->Remove( track ); track->UnLink(); gen_rastnest = true; } diff --git a/pcbnew/dialogs/dialog_global_deletion.h b/pcbnew/dialogs/dialog_global_deletion.h index 4742a9ea04..e38b4955b0 100644 --- a/pcbnew/dialogs/dialog_global_deletion.h +++ b/pcbnew/dialogs/dialog_global_deletion.h @@ -1,6 +1,25 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: dialog_global_deletion.h -///////////////////////////////////////////////////////////////////////////// +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 1992-2014 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ #ifndef _DIALOG_GLOBAL_DELETION_H_ #define _DIALOG_GLOBAL_DELETION_H_ @@ -9,20 +28,20 @@ class DIALOG_GLOBAL_DELETION: public DIALOG_GLOBAL_DELETION_BASE { -private: - PCB_EDIT_FRAME * m_Parent; - LAYER_NUM m_currentLayer; - public: DIALOG_GLOBAL_DELETION( PCB_EDIT_FRAME* parent ); void SetCurrentLayer( LAYER_NUM aLayer ); private: + PCB_EDIT_FRAME* m_Parent; + LAYER_NUM m_currentLayer; + void OnOkClick( wxCommandEvent& event ) { AcceptPcbDelete(); EndModal(wxID_OK); } + void OnCancelClick( wxCommandEvent& event ) { EndModal(wxID_CANCEL); diff --git a/pcbnew/dialogs/dialog_layers_setup.cpp b/pcbnew/dialogs/dialog_layers_setup.cpp index 82b76e6c63..636cea9687 100644 --- a/pcbnew/dialogs/dialog_layers_setup.cpp +++ b/pcbnew/dialogs/dialog_layers_setup.cpp @@ -670,11 +670,11 @@ void PCB_EDIT_FRAME::InstallDialogLayerSetup() if( dlg.ShowModal() == wxID_CANCEL ) return; - wxLogDebug( wxT( "Current layer selected %d." ), getActiveLayer() ); + wxLogDebug( wxT( "Current layer selected %d." ), GetActiveLayer() ); // If the current active layer was removed, find the next avaiable layer to set as the // active layer. - if( !( GetLayerMask( getActiveLayer() ) & GetBoard()->GetEnabledLayers() ) ) + if( !( GetLayerMask( GetActiveLayer() ) & GetBoard()->GetEnabledLayers() ) ) { for( LAYER_NUM i = FIRST_LAYER; i < NB_LAYERS; ++i ) { @@ -685,14 +685,14 @@ void PCB_EDIT_FRAME::InstallDialogLayerSetup() if( GetLayerMask( tmp ) & GetBoard()->GetEnabledLayers() ) { - wxLogDebug( wxT( "Setting current layer to %d." ), getActiveLayer() ); - setActiveLayer( tmp, true ); + wxLogDebug( wxT( "Setting current layer to %d." ), GetActiveLayer() ); + SetActiveLayer( tmp, true ); break; } } } else { - setActiveLayer( getActiveLayer(), true ); + SetActiveLayer( GetActiveLayer(), true ); } } diff --git a/pcbnew/dimension.cpp b/pcbnew/dimension.cpp index da6745ebc1..fc1f828a89 100644 --- a/pcbnew/dimension.cpp +++ b/pcbnew/dimension.cpp @@ -255,16 +255,9 @@ DIMENSION* PCB_EDIT_FRAME::EditDimension( DIMENSION* aDimension, wxDC* aDC ) aDimension = new DIMENSION( GetBoard() ); aDimension->SetFlags( IS_NEW ); - - aDimension->SetLayer( getActiveLayer() ); - - aDimension->m_crossBarO = aDimension->m_crossBarF = pos; - aDimension->m_featureLineDO = aDimension->m_featureLineDF = pos; - aDimension->m_featureLineGO = aDimension->m_featureLineGF = pos; - aDimension->m_arrowG1O = aDimension->m_arrowG1F = pos; - aDimension->m_arrowG2O = aDimension->m_arrowG2F = pos; - aDimension->m_arrowD1O = aDimension->m_arrowD1F = pos; - aDimension->m_arrowD2O = aDimension->m_arrowD2F = pos; + aDimension->SetLayer( GetActiveLayer() ); + aDimension->SetOrigin( pos ); + aDimension->SetEnd( pos ); aDimension->Text().SetSize( GetBoard()->GetDesignSettings().m_PcbTextSize ); int width = GetBoard()->GetDesignSettings().m_PcbTextWidth; @@ -334,24 +327,12 @@ static void BuildDimension( EDA_DRAW_PANEL* aPanel, wxDC* aDC, } else { - wxPoint delta; - int dx, dy; - double angle, depl; - delta = Dimension->m_featureLineDO - Dimension->m_featureLineGO; - /* Calculating the direction of travel perpendicular to the selected axis. */ - angle = atan2( delta.y, delta.x ) + (M_PI / 2); + double angle = Dimension->GetAngle() + (M_PI / 2); - delta = pos - Dimension->m_featureLineDO; - depl = ( delta.x * cos( angle ) ) + ( delta.y * sin( angle ) ); - dx = KiROUND( depl * cos( angle ) ); - dy = KiROUND( depl * sin( angle ) ); - Dimension->m_crossBarO.x = Dimension->m_featureLineGO.x + dx; - Dimension->m_crossBarO.y = Dimension->m_featureLineGO.y + dy; - Dimension->m_crossBarF.x = Dimension->m_featureLineDO.x + dx; - Dimension->m_crossBarF.y = Dimension->m_featureLineDO.y + dy; - - Dimension->AdjustDimensionDetails( ); + wxPoint delta = pos - Dimension->m_featureLineDO; + double depl = ( delta.x * cos( angle ) ) + ( delta.y * sin( angle ) ); + Dimension->SetHeight( depl ); } Dimension->Draw( aPanel, aDC, GR_XOR ); diff --git a/pcbnew/drc.cpp b/pcbnew/drc.cpp index 07b8ebf0f9..b32ddb65b4 100644 --- a/pcbnew/drc.cpp +++ b/pcbnew/drc.cpp @@ -38,6 +38,8 @@ #include #include #include +#include +#include #include #include @@ -312,6 +314,7 @@ bool DRC::doNetClass( NETCLASS* nc, wxString& msg ) m_currentMarker = fillMarker( DRCE_NETCLASS_CLEARANCE, msg, m_currentMarker ); m_pcb->Add( m_currentMarker ); + m_mainWindow->GetGalCanvas()->GetView()->Add( m_currentMarker ); m_currentMarker = 0; ret = false; } @@ -327,6 +330,7 @@ bool DRC::doNetClass( NETCLASS* nc, wxString& msg ) m_currentMarker = fillMarker( DRCE_NETCLASS_TRACKWIDTH, msg, m_currentMarker ); m_pcb->Add( m_currentMarker ); + m_mainWindow->GetGalCanvas()->GetView()->Add( m_currentMarker ); m_currentMarker = 0; ret = false; } @@ -341,6 +345,7 @@ bool DRC::doNetClass( NETCLASS* nc, wxString& msg ) m_currentMarker = fillMarker( DRCE_NETCLASS_VIASIZE, msg, m_currentMarker ); m_pcb->Add( m_currentMarker ); + m_mainWindow->GetGalCanvas()->GetView()->Add( m_currentMarker ); m_currentMarker = 0; ret = false; } @@ -355,6 +360,7 @@ bool DRC::doNetClass( NETCLASS* nc, wxString& msg ) m_currentMarker = fillMarker( DRCE_NETCLASS_VIADRILLSIZE, msg, m_currentMarker ); m_pcb->Add( m_currentMarker ); + m_mainWindow->GetGalCanvas()->GetView()->Add( m_currentMarker ); m_currentMarker = 0; ret = false; } @@ -369,6 +375,7 @@ bool DRC::doNetClass( NETCLASS* nc, wxString& msg ) m_currentMarker = fillMarker( DRCE_NETCLASS_uVIASIZE, msg, m_currentMarker ); m_pcb->Add( m_currentMarker ); + m_mainWindow->GetGalCanvas()->GetView()->Add( m_currentMarker ); m_currentMarker = 0; ret = false; } @@ -383,6 +390,7 @@ bool DRC::doNetClass( NETCLASS* nc, wxString& msg ) m_currentMarker = fillMarker( DRCE_NETCLASS_uVIADRILLSIZE, msg, m_currentMarker ); m_pcb->Add( m_currentMarker ); + m_mainWindow->GetGalCanvas()->GetView()->Add( m_currentMarker ); m_currentMarker = 0; ret = false; } @@ -447,6 +455,7 @@ void DRC::testPad2Pad() { wxASSERT( m_currentMarker ); m_pcb->Add( m_currentMarker ); + m_mainWindow->GetGalCanvas()->GetView()->Add( m_currentMarker ); m_currentMarker = 0; } } @@ -493,6 +502,7 @@ void DRC::testTracks( bool aShowProgressBar ) { wxASSERT( m_currentMarker ); m_pcb->Add( m_currentMarker ); + m_mainWindow->GetGalCanvas()->GetView()->Add( m_currentMarker ); m_currentMarker = 0; } } @@ -554,6 +564,7 @@ void DRC::testZones() m_currentMarker = fillMarker( test_area, DRCE_NON_EXISTANT_NET_FOR_ZONE_OUTLINE, m_currentMarker ); m_pcb->Add( m_currentMarker ); + m_mainWindow->GetGalCanvas()->GetView()->Add( m_currentMarker ); m_currentMarker = 0; } } @@ -589,6 +600,7 @@ void DRC::testKeepoutAreas() 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; } } @@ -605,6 +617,7 @@ void DRC::testKeepoutAreas() 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; } } diff --git a/pcbnew/drc_marker_functions.cpp b/pcbnew/drc_marker_functions.cpp index 9a5002521d..3e4124164b 100644 --- a/pcbnew/drc_marker_functions.cpp +++ b/pcbnew/drc_marker_functions.cpp @@ -101,12 +101,17 @@ MARKER_PCB* DRC::fillMarker( const TRACK* aTrack, BOARD_ITEM* aItem, int aErrorC else { if( aItem ) + { fillMe = new MARKER_PCB( aErrorCode, position, textA, aTrack->GetPosition(), textB, posB ); + fillMe->SetItem( aItem ); + } else + { fillMe = new MARKER_PCB( aErrorCode, position, textA, aTrack->GetPosition() ); + } } return fillMe; @@ -122,9 +127,14 @@ MARKER_PCB* DRC::fillMarker( D_PAD* aPad, D_PAD* bPad, int aErrorCode, MARKER_PC wxPoint posB = bPad->GetPosition(); if( fillMe ) + { fillMe->SetData( aErrorCode, posA, textA, posA, textB, posB ); + } else + { fillMe = new MARKER_PCB( aErrorCode, posA, textA, posA, textB, posB ); + fillMe->SetItem( aPad ); // TODO it has to be checked + } return fillMe; } @@ -137,9 +147,14 @@ MARKER_PCB* DRC::fillMarker( ZONE_CONTAINER* aArea, int aErrorCode, MARKER_PCB* wxPoint posA = aArea->GetPosition(); if( fillMe ) + { fillMe->SetData( aErrorCode, posA, textA, posA ); + } else + { fillMe = new MARKER_PCB( aErrorCode, posA, textA, posA ); + fillMe->SetItem( aArea ); + } return fillMe; } @@ -155,9 +170,14 @@ MARKER_PCB* DRC::fillMarker( const ZONE_CONTAINER* aArea, wxPoint posA = aPos; if( fillMe ) + { fillMe->SetData( aErrorCode, posA, textA, posA ); + } else + { fillMe = new MARKER_PCB( aErrorCode, posA, textA, posA ); + fillMe->SetItem( aArea ); + } return fillMe; } diff --git a/pcbnew/edit.cpp b/pcbnew/edit.cpp index e76623b0e4..51de425839 100644 --- a/pcbnew/edit.cpp +++ b/pcbnew/edit.cpp @@ -55,6 +55,9 @@ #include #include +#include +#include + // Handles the selection of command events. void PCB_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) { @@ -419,14 +422,14 @@ void PCB_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) m_canvas->SetIgnoreMouseEvents( true ); wxPoint dlgPosition; wxGetMousePosition( &dlgPosition.x, &dlgPosition.y ); - LAYER_NUM layer = SelectLayer( getActiveLayer(), ALL_NO_CU_LAYERS, + LAYER_NUM layer = SelectLayer( GetActiveLayer(), ALL_NO_CU_LAYERS, dlgPosition ); m_canvas->SetIgnoreMouseEvents( false ); m_canvas->MoveCursorToCrossHair(); - if( getActiveLayer() != layer ) + if( GetActiveLayer() != layer ) { - GetScreen()->m_Route_Layer_TOP = getActiveLayer(); + GetScreen()->m_Route_Layer_TOP = GetActiveLayer(); GetScreen()->m_Route_Layer_BOTTOM = layer; Other_Layer_Route( (TRACK*) GetCurItem(), &dc ); } @@ -953,17 +956,17 @@ void PCB_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) break; case ID_POPUP_PCB_SELECT_LAYER: - itmp = SelectLayer( getActiveLayer() ); + itmp = SelectLayer( GetActiveLayer() ); if( itmp >= 0 ) { // if user changed colors and we are in high contrast mode, then redraw // because the PAD_SMD pads may change color. - if( DisplayOpt.ContrastModeDisplay && getActiveLayer() != itmp ) + if( DisplayOpt.ContrastModeDisplay && GetActiveLayer() != itmp ) { m_canvas->Refresh(); } - setActiveLayer( itmp ); + SetActiveLayer( itmp ); } m_canvas->MoveCursorToCrossHair(); @@ -974,19 +977,19 @@ void PCB_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) break; case ID_POPUP_PCB_SELECT_NO_CU_LAYER: - itmp = SelectLayer( getActiveLayer(), ALL_CU_LAYERS ); + itmp = SelectLayer( GetActiveLayer(), ALL_CU_LAYERS ); if( itmp >= 0 ) - setActiveLayer( itmp ); + SetActiveLayer( itmp ); m_canvas->MoveCursorToCrossHair(); break; case ID_POPUP_PCB_SELECT_CU_LAYER: - itmp = SelectLayer( getActiveLayer(), ALL_NO_CU_LAYERS ); + itmp = SelectLayer( GetActiveLayer(), ALL_NO_CU_LAYERS ); if( itmp >= 0 ) - setActiveLayer( itmp ); + SetActiveLayer( itmp ); break; @@ -996,7 +999,7 @@ void PCB_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) break; case ID_TOOLBARH_PCB_SELECT_LAYER: - setActiveLayer( m_SelLayerBox->GetLayerSelection() ); + SetActiveLayer( m_SelLayerBox->GetLayerSelection() ); if( DisplayOpt.ContrastModeDisplay ) m_canvas->Refresh( true ); @@ -1299,7 +1302,7 @@ void PCB_EDIT_FRAME::RemoveStruct( BOARD_ITEM* Item, wxDC* DC ) void PCB_EDIT_FRAME::SwitchLayer( wxDC* DC, LAYER_NUM layer ) { - LAYER_NUM curLayer = getActiveLayer(); + LAYER_NUM curLayer = GetActiveLayer(); // Check if the specified layer matches the present layer if( layer == curLayer ) @@ -1341,7 +1344,7 @@ void PCB_EDIT_FRAME::SwitchLayer( wxDC* DC, LAYER_NUM layer ) GetScreen()->m_Route_Layer_TOP = curLayer; GetScreen()->m_Route_Layer_BOTTOM = layer; - setActiveLayer( curLayer ); + SetActiveLayer( curLayer ); if( Other_Layer_Route( (TRACK*) GetScreen()->GetCurItem(), DC ) ) { @@ -1362,7 +1365,7 @@ void PCB_EDIT_FRAME::SwitchLayer( wxDC* DC, LAYER_NUM layer ) // and a non-copper layer, or vice-versa? // ... - setActiveLayer( layer ); + SetActiveLayer( layer ); if( DisplayOpt.ContrastModeDisplay ) m_canvas->Refresh(); @@ -1376,99 +1379,125 @@ void PCB_EDIT_FRAME::OnSelectTool( wxCommandEvent& aEvent ) if( GetToolId() == id ) return; - INSTALL_UNBUFFERED_DC( dc, m_canvas ); - - // Stop the current command and deselect the current tool. - m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() ); - - switch( id ) + if( IsGalCanvasActive() ) { - case ID_NO_TOOL_SELECTED: - SetToolID( id, m_canvas->GetDefaultCursor(), wxEmptyString ); - break; + std::string actionName = COMMON_ACTIONS::TranslateLegacyId( id ); - case ID_TRACK_BUTT: - if( g_Drc_On ) - SetToolID( id, wxCURSOR_PENCIL, _( "Add tracks" ) ); - else - SetToolID( id, wxCURSOR_QUESTION_ARROW, _( "Add tracks" ) ); - - if( (GetBoard()->m_Status_Pcb & LISTE_RATSNEST_ITEM_OK) == 0 ) + if( !actionName.empty() || id == ID_NO_TOOL_SELECTED ) { - Compile_Ratsnest( &dc, true ); + const int MAX_TRIALS = 10; + int trials = 0; + + // Cancel the current tool + // TODO while sending a lot of cancel events works for sure, it is not the most + // elegant way to cancel a tool, this should be probably done another way + while( m_toolManager.GetCurrentTool()->GetName() != "pcbnew.InteractiveSelection" && + trials++ < MAX_TRIALS ) + { + TOOL_EVENT cancel( TC_ANY, TA_CANCEL_TOOL ); + m_toolManager.ProcessEvent( cancel ); + } + + if( !actionName.empty() ) + m_toolManager.RunAction( actionName ); } + } + else + { + INSTALL_UNBUFFERED_DC( dc, m_canvas ); - break; + // Stop the current command and deselect the current tool. + m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() ); - case ID_PCB_MODULE_BUTT: - SetToolID( id, wxCURSOR_PENCIL, _( "Add module" ) ); - break; + switch( id ) + { + case ID_NO_TOOL_SELECTED: + SetToolID( id, m_canvas->GetDefaultCursor(), wxEmptyString ); + break; - case ID_PCB_ZONES_BUTT: - SetToolID( id, wxCURSOR_PENCIL, _( "Add zones" ) ); + case ID_TRACK_BUTT: + if( g_Drc_On ) + SetToolID( id, wxCURSOR_PENCIL, _( "Add tracks" ) ); + else + SetToolID( id, wxCURSOR_QUESTION_ARROW, _( "Add tracks" ) ); - if( DisplayOpt.DisplayZonesMode != 0 ) - DisplayInfoMessage( this, _( "Warning: zone display is OFF!!!" ) ); + if( (GetBoard()->m_Status_Pcb & LISTE_RATSNEST_ITEM_OK) == 0 ) + { + Compile_Ratsnest( &dc, true ); + } - if( !GetBoard()->IsHighLightNetON() && (GetBoard()->GetHighLightNetCode() > 0 ) ) - HighLight( &dc ); + break; - break; + case ID_PCB_MODULE_BUTT: + SetToolID( id, wxCURSOR_PENCIL, _( "Add module" ) ); + break; - case ID_PCB_KEEPOUT_AREA_BUTT: - SetToolID( id, wxCURSOR_PENCIL, _( "Add keepout" ) ); - break; + case ID_PCB_ZONES_BUTT: + SetToolID( id, wxCURSOR_PENCIL, _( "Add zones" ) ); - case ID_PCB_MIRE_BUTT: - SetToolID( id, wxCURSOR_PENCIL, _( "Add layer alignment target" ) ); - break; + if( DisplayOpt.DisplayZonesMode != 0 ) + DisplayInfoMessage( this, _( "Warning: zone display is OFF!!!" ) ); - case ID_PCB_PLACE_OFFSET_COORD_BUTT: - SetToolID( id, wxCURSOR_PENCIL, _( "Adjust zero" ) ); - break; + if( !GetBoard()->IsHighLightNetON() && (GetBoard()->GetHighLightNetCode() > 0 ) ) + HighLight( &dc ); - case ID_PCB_PLACE_GRID_COORD_BUTT: - SetToolID( id, wxCURSOR_PENCIL, _( "Adjust grid origin" ) ); - break; + break; - case ID_PCB_ADD_LINE_BUTT: - SetToolID( id, wxCURSOR_PENCIL, _( "Add graphic line" ) ); - break; + case ID_PCB_KEEPOUT_AREA_BUTT: + SetToolID( id, wxCURSOR_PENCIL, _( "Add keepout" ) ); + break; - case ID_PCB_ARC_BUTT: - SetToolID( id, wxCURSOR_PENCIL, _( "Add graphic arc" ) ); - break; + case ID_PCB_MIRE_BUTT: + SetToolID( id, wxCURSOR_PENCIL, _( "Add layer alignment target" ) ); + break; - case ID_PCB_CIRCLE_BUTT: - SetToolID( id, wxCURSOR_PENCIL, _( "Add graphic circle" ) ); - break; + case ID_PCB_PLACE_OFFSET_COORD_BUTT: + SetToolID( id, wxCURSOR_PENCIL, _( "Adjust zero" ) ); + break; - case ID_PCB_ADD_TEXT_BUTT: - SetToolID( id, wxCURSOR_PENCIL, _( "Add text" ) ); - break; + case ID_PCB_PLACE_GRID_COORD_BUTT: + SetToolID( id, wxCURSOR_PENCIL, _( "Adjust grid origin" ) ); + break; - case ID_COMPONENT_BUTT: - SetToolID( id, wxCURSOR_HAND, _( "Add module" ) ); - break; + case ID_PCB_ADD_LINE_BUTT: + SetToolID( id, wxCURSOR_PENCIL, _( "Add graphic line" ) ); + break; - case ID_PCB_DIMENSION_BUTT: - SetToolID( id, wxCURSOR_PENCIL, _( "Add dimension" ) ); - break; + case ID_PCB_ARC_BUTT: + SetToolID( id, wxCURSOR_PENCIL, _( "Add graphic arc" ) ); + break; - case ID_PCB_DELETE_ITEM_BUTT: - SetToolID( id, wxCURSOR_BULLSEYE, _( "Delete item" ) ); - break; + case ID_PCB_CIRCLE_BUTT: + SetToolID( id, wxCURSOR_PENCIL, _( "Add graphic circle" ) ); + break; - case ID_PCB_HIGHLIGHT_BUTT: - SetToolID( id, wxCURSOR_HAND, _( "Highlight net" ) ); - break; + case ID_PCB_ADD_TEXT_BUTT: + SetToolID( id, wxCURSOR_PENCIL, _( "Add text" ) ); + break; - case ID_PCB_SHOW_1_RATSNEST_BUTT: - SetToolID( id, wxCURSOR_HAND, _( "Select rats nest" ) ); + case ID_COMPONENT_BUTT: + SetToolID( id, wxCURSOR_HAND, _( "Add module" ) ); + break; - if( ( GetBoard()->m_Status_Pcb & LISTE_RATSNEST_ITEM_OK ) == 0 ) - Compile_Ratsnest( &dc, true ); + case ID_PCB_DIMENSION_BUTT: + SetToolID( id, wxCURSOR_PENCIL, _( "Add dimension" ) ); + break; - break; + case ID_PCB_DELETE_ITEM_BUTT: + SetToolID( id, wxCURSOR_BULLSEYE, _( "Delete item" ) ); + break; + + case ID_PCB_HIGHLIGHT_BUTT: + SetToolID( id, wxCURSOR_HAND, _( "Highlight net" ) ); + break; + + case ID_PCB_SHOW_1_RATSNEST_BUTT: + SetToolID( id, wxCURSOR_HAND, _( "Select rats nest" ) ); + + if( ( GetBoard()->m_Status_Pcb & LISTE_RATSNEST_ITEM_OK ) == 0 ) + Compile_Ratsnest( &dc, true ); + + break; + } } } diff --git a/pcbnew/edit_pcb_text.cpp b/pcbnew/edit_pcb_text.cpp index e4ecfcb5a2..277159a5ee 100644 --- a/pcbnew/edit_pcb_text.cpp +++ b/pcbnew/edit_pcb_text.cpp @@ -195,7 +195,8 @@ TEXTE_PCB* PCB_EDIT_FRAME::CreateTextePcb( wxDC* aDC, TEXTE_PCB* aText ) textePcb->Copy( aText ); GetBoard()->Add( textePcb ); textePcb->SetFlags( IS_NEW ); - StartMoveTextePcb( textePcb, aDC, false ); // Don't erase aText when copying + if( aDC ) + StartMoveTextePcb( textePcb, aDC, false ); // Don't erase aText when copying } else { @@ -222,7 +223,7 @@ TEXTE_PCB* PCB_EDIT_FRAME::CreateTextePcb( wxDC* aDC, TEXTE_PCB* aText ) textePcb->DeleteStructure(); textePcb = NULL; } - else + else if( aDC ) { StartMoveTextePcb( textePcb, aDC ); } diff --git a/pcbnew/editedge.cpp b/pcbnew/editedge.cpp index a85a0bf26e..207b515e66 100644 --- a/pcbnew/editedge.cpp +++ b/pcbnew/editedge.cpp @@ -246,7 +246,7 @@ DRAWSEGMENT* PCB_EDIT_FRAME::Begin_DrawSegment( DRAWSEGMENT* Segment, STROKE_T s s_large = GetDesignSettings().m_DrawSegmentWidth; - if( getActiveLayer() == EDGE_N ) + if( GetActiveLayer() == EDGE_N ) { s_large = GetDesignSettings().m_EdgeSegmentWidth; } @@ -255,7 +255,7 @@ DRAWSEGMENT* PCB_EDIT_FRAME::Begin_DrawSegment( DRAWSEGMENT* Segment, STROKE_T s { SetCurItem( Segment = new DRAWSEGMENT( GetBoard() ) ); Segment->SetFlags( IS_NEW ); - Segment->SetLayer( getActiveLayer() ); + Segment->SetLayer( GetActiveLayer() ); Segment->SetWidth( s_large ); Segment->SetShape( shape ); Segment->SetAngle( 900 ); diff --git a/pcbnew/editrack-part2.cpp b/pcbnew/editrack-part2.cpp index bedbcac572..ef7ed1642f 100644 --- a/pcbnew/editrack-part2.cpp +++ b/pcbnew/editrack-part2.cpp @@ -51,10 +51,10 @@ bool PCB_EDIT_FRAME::Other_Layer_Route( TRACK* aTrack, wxDC* DC ) if( aTrack == NULL ) { - if( getActiveLayer() != ((PCB_SCREEN*)GetScreen())->m_Route_Layer_TOP ) - setActiveLayer( ((PCB_SCREEN*)GetScreen())->m_Route_Layer_TOP ); + if( GetActiveLayer() != ((PCB_SCREEN*)GetScreen())->m_Route_Layer_TOP ) + SetActiveLayer( ((PCB_SCREEN*)GetScreen())->m_Route_Layer_TOP ); else - setActiveLayer(((PCB_SCREEN*)GetScreen())->m_Route_Layer_BOTTOM ); + SetActiveLayer(((PCB_SCREEN*)GetScreen())->m_Route_Layer_BOTTOM ); UpdateStatusBar(); return true; @@ -108,7 +108,7 @@ bool PCB_EDIT_FRAME::Other_Layer_Route( TRACK* aTrack, wxDC* DC ) via->SetLayerPair( LAYER_N_BACK, LAYER_N_FRONT ); via->SetDrill( GetBoard()->GetCurrentViaDrill() ); - LAYER_NUM first_layer = getActiveLayer(); + LAYER_NUM first_layer = GetActiveLayer(); LAYER_NUM last_layer; // prepare switch to new active layer: @@ -171,7 +171,7 @@ bool PCB_EDIT_FRAME::Other_Layer_Route( TRACK* aTrack, wxDC* DC ) return false; } - setActiveLayer( last_layer ); + SetActiveLayer( last_layer ); TRACK* lastNonVia = g_CurrentTrackSegment; @@ -193,7 +193,7 @@ bool PCB_EDIT_FRAME::Other_Layer_Route( TRACK* aTrack, wxDC* DC ) */ // set the layer to the new value - track->SetLayer( getActiveLayer() ); + track->SetLayer( GetActiveLayer() ); /* the start point is the via position and the end point is the cursor * which also is on the via (will change when moving mouse) diff --git a/pcbnew/hotkeys_board_editor.cpp b/pcbnew/hotkeys_board_editor.cpp index d48f77a2eb..14931a0fa4 100644 --- a/pcbnew/hotkeys_board_editor.cpp +++ b/pcbnew/hotkeys_board_editor.cpp @@ -152,7 +152,6 @@ void PCB_EDIT_FRAME::OnHotKey( wxDC* aDC, int aHotkeyCode, const wxPoint& aPosit cmd.SetEventObject( this ); LAYER_NUM ll; - unsigned int cnt; switch( hk_id ) { @@ -225,54 +224,23 @@ void PCB_EDIT_FRAME::OnHotKey( wxDC* aDC, int aHotkeyCode, const wxPoint& aPosit break; case HK_SWITCH_GRID_TO_FASTGRID1: - if( m_gridSelectBox ) - { - m_gridSelectBox->SetSelection( m_FastGrid1 ); - cmd.SetEventType( wxEVT_COMMAND_COMBOBOX_SELECTED ); - OnSelectGrid( cmd ); - } - + SetFastGrid1(); break; case HK_SWITCH_GRID_TO_FASTGRID2: - if( m_gridSelectBox ) - { - m_gridSelectBox->SetSelection( m_FastGrid2 ); - cmd.SetEventType( wxEVT_COMMAND_COMBOBOX_SELECTED ); - OnSelectGrid( cmd ); - } - + SetFastGrid2(); break; case HK_SWITCH_GRID_TO_NEXT: - if( m_gridSelectBox ) - { - m_gridSelectBox->SetSelection( ( m_gridSelectBox->GetSelection() + 1 ) % - m_gridSelectBox->GetCount() ); - cmd.SetEventType( wxEVT_COMMAND_COMBOBOX_SELECTED ); - OnSelectGrid( cmd ); - } + SetNextGrid(); break; case HK_SWITCH_GRID_TO_PREVIOUS: - if( m_gridSelectBox ) - { - cnt = m_gridSelectBox->GetSelection(); - - if ( cnt == 0 ) - cnt = m_gridSelectBox->GetCount() - 1; - else - cnt--; - - m_gridSelectBox->SetSelection( cnt ); - cmd.SetEventType( wxEVT_COMMAND_COMBOBOX_SELECTED ); - OnSelectGrid( cmd ); - } - + SetPrevGrid(); break; case HK_SWITCH_LAYER_TO_PREVIOUS: - ll = getActiveLayer(); + ll = GetActiveLayer(); if( (ll <= LAYER_N_BACK) || (ll > LAYER_N_FRONT) ) break; @@ -288,7 +256,7 @@ void PCB_EDIT_FRAME::OnHotKey( wxDC* aDC, int aHotkeyCode, const wxPoint& aPosit break; case HK_SWITCH_LAYER_TO_NEXT: - ll = getActiveLayer(); + ll = GetActiveLayer(); if( (ll < LAYER_N_BACK) || (ll >= LAYER_N_FRONT) ) break; @@ -395,8 +363,7 @@ void PCB_EDIT_FRAME::OnHotKey( wxDC* aDC, int aHotkeyCode, const wxPoint& aPosit break; case HK_SWITCH_TRACK_DISPLAY_MODE: - DisplayOpt.DisplayPcbTrackFill ^= 1; - DisplayOpt.DisplayPcbTrackFill &= 1; + DisplayOpt.DisplayPcbTrackFill = !DisplayOpt.DisplayPcbTrackFill; m_DisplayPcbTrackFill = DisplayOpt.DisplayPcbTrackFill; m_canvas->Refresh(); break; @@ -406,7 +373,7 @@ void PCB_EDIT_FRAME::OnHotKey( wxDC* aDC, int aHotkeyCode, const wxPoint& aPosit break; case HK_BACK_SPACE: - if( IsCopperLayer( getActiveLayer() ) ) + if( IsCopperLayer( GetActiveLayer() ) ) { if( !itemCurrentlyEdited ) { @@ -621,7 +588,7 @@ bool PCB_EDIT_FRAME::OnHotkeyDeleteItem( wxDC* aDC ) switch( GetToolId() ) { case ID_TRACK_BUTT: - if( getActiveLayer() > LAYER_N_FRONT ) + if( GetActiveLayer() > LAYER_N_FRONT ) return false; if( ItemFree ) @@ -982,7 +949,7 @@ bool PCB_EDIT_FRAME::OnHotkeyPlaceItem( wxDC* aDC ) TRACK * PCB_EDIT_FRAME::OnHotkeyBeginRoute( wxDC* aDC ) { - if( getActiveLayer() > LAYER_N_FRONT ) + if( GetActiveLayer() > LAYER_N_FRONT ) return NULL; bool itemCurrentlyEdited = (GetCurItem() && GetCurItem()->GetFlags()); diff --git a/pcbnew/initpcb.cpp b/pcbnew/initpcb.cpp index 80f6fc8135..dba920d780 100644 --- a/pcbnew/initpcb.cpp +++ b/pcbnew/initpcb.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include #include @@ -69,7 +69,7 @@ bool PCB_EDIT_FRAME::Clear_Pcb( bool aQuery ) GetBoard()->SetVisibleLayers( ALL_LAYERS ); // Set currently selected layer to be shown in high contrast mode, when enabled` - setHighContrastLayer( GetScreen()->m_Active_Layer ); + SetHighContrastLayer( GetScreen()->m_Active_Layer ); ReFillLayerWidget(); diff --git a/pcbnew/kicad_plugin.cpp b/pcbnew/kicad_plugin.cpp index 80015dc147..5c4b280dda 100644 --- a/pcbnew/kicad_plugin.cpp +++ b/pcbnew/kicad_plugin.cpp @@ -747,26 +747,26 @@ void PCB_IO::format( DIMENSION* aDimension, int aNestLevel ) const FMT_IU( aDimension->m_crossBarF.y ).c_str() ); m_out->Print( aNestLevel+1, "(arrow1a (pts (xy %s %s) (xy %s %s)))\n", - FMT_IU( aDimension->m_arrowD1O.x ).c_str(), - FMT_IU( aDimension->m_arrowD1O.y ).c_str(), + FMT_IU( aDimension->m_crossBarF.x ).c_str(), + FMT_IU( aDimension->m_crossBarF.y ).c_str(), FMT_IU( aDimension->m_arrowD1F.x ).c_str(), FMT_IU( aDimension->m_arrowD1F.y ).c_str() ); m_out->Print( aNestLevel+1, "(arrow1b (pts (xy %s %s) (xy %s %s)))\n", - FMT_IU( aDimension->m_arrowD2O.x ).c_str(), - FMT_IU( aDimension->m_arrowD2O.y ).c_str(), + FMT_IU( aDimension->m_crossBarF.x ).c_str(), + FMT_IU( aDimension->m_crossBarF.y ).c_str(), FMT_IU( aDimension->m_arrowD2F.x ).c_str(), FMT_IU( aDimension->m_arrowD2F.y ).c_str() ); m_out->Print( aNestLevel+1, "(arrow2a (pts (xy %s %s) (xy %s %s)))\n", - FMT_IU( aDimension->m_arrowG1O.x ).c_str(), - FMT_IU( aDimension->m_arrowG1O.y ).c_str(), + FMT_IU( aDimension->m_crossBarO.x ).c_str(), + FMT_IU( aDimension->m_crossBarO.y ).c_str(), FMT_IU( aDimension->m_arrowG1F.x ).c_str(), FMT_IU( aDimension->m_arrowG1F.y ).c_str() ); m_out->Print( aNestLevel+1, "(arrow2b (pts (xy %s %s) (xy %s %s)))\n", - FMT_IU( aDimension->m_arrowG2O.x ).c_str(), - FMT_IU( aDimension->m_arrowG2O.y ).c_str(), + FMT_IU( aDimension->m_crossBarO.x ).c_str(), + FMT_IU( aDimension->m_crossBarO.y ).c_str(), FMT_IU( aDimension->m_arrowG2F.x ).c_str(), FMT_IU( aDimension->m_arrowG2F.y ).c_str() ); diff --git a/pcbnew/legacy_plugin.cpp b/pcbnew/legacy_plugin.cpp index 12e500b023..d94852db4c 100644 --- a/pcbnew/legacy_plugin.cpp +++ b/pcbnew/legacy_plugin.cpp @@ -2340,7 +2340,7 @@ void LEGACY_PLUGIN::loadZONE_CONTAINER() arcsegcount = 32; zc->SetArcSegmentCount( arcsegcount ); - zc->SetIsFilled( fillstate == 'S' ? true : false ); + zc->SetIsFilled( fillstate == 'S' ); zc->SetThermalReliefGap( thermalReliefGap ); zc->SetThermalReliefCopperBridge( thermalReliefCopperBridge ); } @@ -2587,13 +2587,11 @@ void LEGACY_PLUGIN::loadDIMENSION() // sscanf( Line + 2, " %d %d %d %d %d %d", &Dummy, &m_arrowD1Ox, &m_arrowD1Oy, &m_arrowD1Fx, &m_arrowD1Fy, &Dummy ); int ignore = intParse( line + SZ( "S1" ), &data ); - BIU arrowD10x = biuParse( data, &data ); - BIU arrowD10y = biuParse( data, &data ); + biuParse( data, &data ); // skipping excessive data + biuParse( data, &data ); // skipping excessive data BIU arrowD1Fx = biuParse( data, &data ); BIU arrowD1Fy = biuParse( data ); - dim->m_arrowD1O.x = arrowD10x; - dim->m_arrowD1O.y = arrowD10y; dim->m_arrowD1F.x = arrowD1Fx; dim->m_arrowD1F.y = arrowD1Fy; (void) ignore; @@ -2604,13 +2602,11 @@ void LEGACY_PLUGIN::loadDIMENSION() // sscanf( Line + 2, " %d %d %d %d %d %d", &Dummy, &m_arrowD2Ox, &m_arrowD2Oy, &m_arrowD2Fx, &m_arrowD2Fy, &Dummy ); int ignore = intParse( line + SZ( "S2" ), &data ); - BIU arrowD2Ox = biuParse( data, &data ); - BIU arrowD2Oy = biuParse( data, &data ); + biuParse( data, &data ); // skipping excessive data + biuParse( data, &data ); // skipping excessive data BIU arrowD2Fx = biuParse( data, &data ); BIU arrowD2Fy = biuParse( data, &data ); - dim->m_arrowD2O.x = arrowD2Ox; - dim->m_arrowD2O.y = arrowD2Oy; dim->m_arrowD2F.x = arrowD2Fx; dim->m_arrowD2F.y = arrowD2Fy; (void) ignore; @@ -2620,13 +2616,11 @@ void LEGACY_PLUGIN::loadDIMENSION() { // sscanf( Line + 2, " %d %d %d %d %d %d\n", &Dummy, &m_arrowG1Ox, &m_arrowG1Oy, &m_arrowG1Fx, &m_arrowG1Fy, &Dummy ); int ignore = intParse( line + SZ( "S3" ), &data ); - BIU arrowG1Ox = biuParse( data, &data ); - BIU arrowG1Oy = biuParse( data, &data ); + biuParse( data, &data ); // skipping excessive data + biuParse( data, &data ); // skipping excessive data BIU arrowG1Fx = biuParse( data, &data ); BIU arrowG1Fy = biuParse( data, &data ); - dim->m_arrowG1O.x = arrowG1Ox; - dim->m_arrowG1O.y = arrowG1Oy; dim->m_arrowG1F.x = arrowG1Fx; dim->m_arrowG1F.y = arrowG1Fy; (void) ignore; @@ -2636,13 +2630,11 @@ void LEGACY_PLUGIN::loadDIMENSION() { // sscanf( Line + 2, " %d %d %d %d %d %d", &Dummy, &m_arrowG2Ox, &m_arrowG2Oy, &m_arrowG2Fx, &m_arrowG2Fy, &Dummy ); int ignore = intParse( line + SZ( "S4" ), &data ); - BIU arrowG2Ox = biuParse( data, &data ); - BIU arrowG2Oy = biuParse( data, &data ); + biuParse( data, &data ); // skipping excessive data + biuParse( data, &data ); // skipping excessive data BIU arrowG2Fx = biuParse( data, &data ); BIU arrowG2Fy = biuParse( data, &data ); - dim->m_arrowG2O.x = arrowG2Ox; - dim->m_arrowG2O.y = arrowG2Oy; dim->m_arrowG2F.x = arrowG2Fx; dim->m_arrowG2F.y = arrowG2Fy; (void) ignore; @@ -3805,22 +3797,22 @@ void LEGACY_PLUGIN::saveDIMENTION( const DIMENSION* me ) const fmtBIU( me->GetWidth() ).c_str() ); fprintf( m_fp, "S1 %d %s %s %s\n", S_SEGMENT, - fmtBIUPair( me->m_arrowD1O.x, me->m_arrowD1O.y ).c_str(), + fmtBIUPair( me->m_crossBarF.x, me->m_crossBarF.y ).c_str(), fmtBIUPair( me->m_arrowD1F.x, me->m_arrowD1F.y ).c_str(), fmtBIU( me->GetWidth() ).c_str() ); fprintf( m_fp, "S2 %d %s %s %s\n", S_SEGMENT, - fmtBIUPair( me->m_arrowD2O.x, me->m_arrowD2O.y ).c_str(), + fmtBIUPair( me->m_crossBarF.x, me->m_crossBarF.y ).c_str(), fmtBIUPair( me->m_arrowD2F.x, me->m_arrowD2F.y ).c_str(), fmtBIU( me->GetWidth() ).c_str() ); fprintf( m_fp, "S3 %d %s %s %s\n", S_SEGMENT, - fmtBIUPair( me->m_arrowG1O.x, me->m_arrowG1O.y ).c_str(), + fmtBIUPair( me->m_crossBarO.x, me->m_crossBarO.y ).c_str(), fmtBIUPair( me->m_arrowG1F.x, me->m_arrowG1F.y ).c_str(), fmtBIU( me->GetWidth() ).c_str() ); fprintf( m_fp, "S4 %d %s %s %s\n", S_SEGMENT, - fmtBIUPair( me->m_arrowG2O.x, me->m_arrowG2O.y ).c_str(), + fmtBIUPair( me->m_crossBarO.x, me->m_crossBarO.y ).c_str(), fmtBIUPair( me->m_arrowG2F.x, me->m_arrowG2F.y ).c_str(), fmtBIU( me->GetWidth() ).c_str() ); diff --git a/pcbnew/menubar_pcbframe.cpp b/pcbnew/menubar_pcbframe.cpp index 026e23df09..11aa831c27 100644 --- a/pcbnew/menubar_pcbframe.cpp +++ b/pcbnew/menubar_pcbframe.cpp @@ -292,13 +292,6 @@ void PCB_EDIT_FRAME::ReCreateMenuBar() _( "Reset text size and width of all module fields to current defaults" ), KiBitmap( reset_text_xpm ) ); - editMenu->AppendSeparator(); - - AddMenuItem( editMenu, ID_PNS_ROUTER_TOOL, - _( "Interactive router" ), - _( "Interactive router push&shove tool." ), - KiBitmap( ps_router_xpm ) ); - //----- View menu ----------------------------------------------------------- wxMenu* viewMenu = new wxMenu; @@ -344,33 +337,36 @@ void PCB_EDIT_FRAME::ReCreateMenuBar() viewMenu->AppendSeparator(); text = AddHotkeyName( _( "&Switch canvas to default" ), g_Pcbnew_Editor_Hokeys_Descr, - HK_CANVAS_DEFAULT, IS_ACCELERATOR ); + HK_CANVAS_DEFAULT ); + AddMenuItem( viewMenu, ID_MENU_CANVAS_DEFAULT, text, _( "Switch the canvas implementation to default" ), - KiBitmap( tools_xpm ) ); + KiBitmap( tools_xpm ) ); text = AddHotkeyName( _( "&Switch canvas to OpenGL" ), g_Pcbnew_Editor_Hokeys_Descr, - HK_CANVAS_OPENGL, IS_ACCELERATOR ); + HK_CANVAS_OPENGL ); + AddMenuItem( viewMenu, ID_MENU_CANVAS_OPENGL, text, _( "Switch the canvas implementation to OpenGL" ), - KiBitmap( tools_xpm ) ); + KiBitmap( tools_xpm ) ); text = AddHotkeyName( _( "&Switch canvas to Cairo" ), g_Pcbnew_Editor_Hokeys_Descr, - HK_CANVAS_CAIRO, IS_ACCELERATOR ); + HK_CANVAS_CAIRO ); + AddMenuItem( viewMenu, ID_MENU_CANVAS_CAIRO, text, _( "Switch the canvas implementation to Cairo" ), - KiBitmap( tools_xpm ) ); + KiBitmap( tools_xpm ) ); //----- Place Menu ---------------------------------------------------------- wxMenu* placeMenu = new wxMenu; text = AddHotkeyName( _( "&Module" ), g_Pcbnew_Editor_Hokeys_Descr, - HK_ADD_MODULE, IS_ACCELERATOR ); + HK_ADD_MODULE ); AddMenuItem( placeMenu, ID_PCB_MODULE_BUTT, text, _( "Add modules" ), KiBitmap( module_xpm ) ); text = AddHotkeyName( _( "&Track" ), g_Pcbnew_Editor_Hokeys_Descr, - HK_ADD_NEW_TRACK, IS_ACCELERATOR ); + HK_ADD_NEW_TRACK ); AddMenuItem( placeMenu, ID_TRACK_BUTT, text, _( "Add tracks and vias" ), KiBitmap( add_tracks_xpm ) ); diff --git a/pcbnew/netlist.cpp b/pcbnew/netlist.cpp index af65d26faf..bb840c658f 100644 --- a/pcbnew/netlist.cpp +++ b/pcbnew/netlist.cpp @@ -27,9 +27,11 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ +#include #include #include #include +#include #include #include #include @@ -59,6 +61,7 @@ void PCB_EDIT_FRAME::ReadPcbNetlist( const wxString& aNetlistFileName, wxString msg; NETLIST netlist; NETLIST_READER* netlistReader; + KIGFX::VIEW* view = GetGalCanvas()->GetView(); netlist.SetIsDryRun( aIsDryRun ); netlist.SetFindByTimeStamp( aSelectByTimeStamp ); @@ -93,6 +96,16 @@ void PCB_EDIT_FRAME::ReadPcbNetlist( const wxString& aNetlistFileName, if( !netlist.IsDryRun() ) GetScreen()->ClearUndoRedoList(); + if( !netlist.IsDryRun() ) + { + // Remove old modules + for( MODULE* module = GetBoard()->m_Modules; module; module = module->Next() ) + { + module->RunOnChildren( boost::bind( &KIGFX::VIEW::Remove, view, _1 ) ); + view->Remove( module ); + } + } + netlist.SortByReference(); GetBoard()->ReplaceNetlist( netlist, aDeleteSinglePadNets, aReporter ); @@ -104,6 +117,13 @@ void PCB_EDIT_FRAME::ReadPcbNetlist( const wxString& aNetlistFileName, SetCurItem( NULL ); + // Reload modules + for( MODULE* module = GetBoard()->m_Modules; module; module = module->Next() ) + { + module->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, view, _1 ) ); + GetGalCanvas()->GetView()->Add( module ); + } + if( aDeleteUnconnectedTracks && GetBoard()->m_Track ) { // Remove erroneous tracks. This should probably pushed down to the #BOARD object. diff --git a/pcbnew/onleftclick.cpp b/pcbnew/onleftclick.cpp index a86324ce5e..dc5b0b97ee 100644 --- a/pcbnew/onleftclick.cpp +++ b/pcbnew/onleftclick.cpp @@ -244,7 +244,7 @@ void PCB_EDIT_FRAME::OnLeftClick( wxDC* aDC, const wxPoint& aPosition ) if( GetToolId() == ID_PCB_ARC_BUTT ) shape = S_ARC; - if( IsCopperLayer( getActiveLayer() ) ) + if( IsCopperLayer( GetActiveLayer() ) ) { DisplayError( this, _( "Graphic not allowed on Copper layers" ) ); break; @@ -268,7 +268,7 @@ void PCB_EDIT_FRAME::OnLeftClick( wxDC* aDC, const wxPoint& aPosition ) break; case ID_TRACK_BUTT: - if( !IsCopperLayer( getActiveLayer() ) ) + if( !IsCopperLayer( GetActiveLayer() ) ) { DisplayError( this, _( "Tracks on Copper layers only " ) ); break; @@ -326,7 +326,7 @@ void PCB_EDIT_FRAME::OnLeftClick( wxDC* aDC, const wxPoint& aPosition ) break; case ID_PCB_ADD_TEXT_BUTT: - if( IsLayerInList( EDGE_LAYER, getActiveLayer() ) ) + if( IsLayerInList( EDGE_LAYER, GetActiveLayer() ) ) { DisplayError( this, _( "Texts not allowed on Edge Cut layer" ) ); @@ -376,7 +376,7 @@ void PCB_EDIT_FRAME::OnLeftClick( wxDC* aDC, const wxPoint& aPosition ) break; case ID_PCB_DIMENSION_BUTT: - if( IsLayerInList( EDGE_LAYER|ALL_CU_LAYERS, getActiveLayer() ) ) + if( IsLayerInList( EDGE_LAYER|ALL_CU_LAYERS, GetActiveLayer() ) ) { DisplayError( this, _( "Dimension not allowed on Copper or Edge Cut layers" ) ); diff --git a/pcbnew/pcb_painter.cpp b/pcbnew/pcb_painter.cpp index c2d98603ed..0465f450aa 100644 --- a/pcbnew/pcb_painter.cpp +++ b/pcbnew/pcb_painter.cpp @@ -34,9 +34,8 @@ #include #include #include -#include +#include -#include #include #include @@ -47,7 +46,7 @@ PCB_RENDER_SETTINGS::PCB_RENDER_SETTINGS() // By default everything should be displayed as filled for( unsigned int i = 0; i < END_PCB_VISIBLE_LIST; ++i ) { - m_sketchModeSelect[i] = false; + m_sketchMode[i] = false; } update(); @@ -67,15 +66,16 @@ void PCB_RENDER_SETTINGS::ImportLegacyColors( COLORS_DESIGN_SETTINGS* aSettings } // Default colors for specific layers - m_layerColors[ITEM_GAL_LAYER( VIAS_HOLES_VISIBLE )] = COLOR4D( 0.5, 0.4, 0.0, 1.0 ); - m_layerColors[ITEM_GAL_LAYER( PADS_HOLES_VISIBLE )] = COLOR4D( 0.0, 0.5, 0.5, 1.0 ); - m_layerColors[ITEM_GAL_LAYER( VIAS_VISIBLE )] = COLOR4D( 0.7, 0.7, 0.7, 1.0 ); - m_layerColors[ITEM_GAL_LAYER( PADS_VISIBLE )] = COLOR4D( 0.7, 0.7, 0.7, 1.0 ); - m_layerColors[NETNAMES_GAL_LAYER( PADS_NETNAMES_VISIBLE )] = COLOR4D( 0.8, 0.8, 0.8, 0.7 ); - m_layerColors[NETNAMES_GAL_LAYER( PAD_FR_NETNAMES_VISIBLE )] = COLOR4D( 0.8, 0.8, 0.8, 0.7 ); - m_layerColors[NETNAMES_GAL_LAYER( PAD_BK_NETNAMES_VISIBLE )] = COLOR4D( 0.8, 0.8, 0.8, 0.7 ); - m_layerColors[ITEM_GAL_LAYER( RATSNEST_VISIBLE )] = COLOR4D( 0.4, 0.4, 0.4, 0.7 ); - m_layerColors[ITEM_GAL_LAYER( WORKSHEET )] = COLOR4D( 0.5, 0.0, 0.0, 1.0 ); + m_layerColors[ITEM_GAL_LAYER( VIAS_HOLES_VISIBLE )] = COLOR4D( 0.5, 0.4, 0.0, 0.8 ); + m_layerColors[ITEM_GAL_LAYER( PADS_HOLES_VISIBLE )] = COLOR4D( 0.0, 0.5, 0.5, 0.8 ); + m_layerColors[ITEM_GAL_LAYER( VIA_THROUGH_VISIBLE )] = COLOR4D( 0.7, 0.7, 0.7, 0.8 ); + m_layerColors[ITEM_GAL_LAYER( PADS_VISIBLE )] = COLOR4D( 0.7, 0.7, 0.7, 0.8 ); + m_layerColors[NETNAMES_GAL_LAYER( PADS_NETNAMES_VISIBLE )] = COLOR4D( 0.8, 0.8, 0.8, 0.8 ); + m_layerColors[NETNAMES_GAL_LAYER( PAD_FR_NETNAMES_VISIBLE )] = COLOR4D( 0.8, 0.8, 0.8, 0.8 ); + m_layerColors[NETNAMES_GAL_LAYER( PAD_BK_NETNAMES_VISIBLE )] = COLOR4D( 0.8, 0.8, 0.8, 0.8 ); + m_layerColors[ITEM_GAL_LAYER( RATSNEST_VISIBLE )] = COLOR4D( 0.4, 0.4, 0.4, 0.8 ); + m_layerColors[ITEM_GAL_LAYER( WORKSHEET )] = COLOR4D( 0.5, 0.0, 0.0, 0.8 ); + m_layerColors[ITEM_GAL_LAYER( DRC_VISIBLE )] = COLOR4D( 1.0, 0.0, 0.0, 0.8 ); // Netnames for copper layers for( LAYER_NUM layer = FIRST_COPPER_LAYER; layer <= LAST_COPPER_LAYER; ++layer ) @@ -94,9 +94,9 @@ void PCB_RENDER_SETTINGS::LoadDisplayOptions( const DISPLAY_OPTIONS& aOptions ) m_padNumbers = aOptions.DisplayPadNum; // Whether to draw tracks, vias & pads filled or as outlines - m_sketchModeSelect[PADS_VISIBLE] = !aOptions.DisplayPadFill; - m_sketchModeSelect[VIAS_VISIBLE] = !aOptions.DisplayViaFill; - m_sketchModeSelect[TRACKS_VISIBLE] = !aOptions.DisplayPcbTrackFill; + m_sketchMode[PADS_VISIBLE] = !aOptions.DisplayPadFill; + m_sketchMode[VIA_THROUGH_VISIBLE] = !aOptions.DisplayViaFill; + m_sketchMode[TRACKS_VISIBLE] = !aOptions.DisplayPcbTrackFill; switch( aOptions.DisplayNetNamesMode ) { @@ -175,23 +175,15 @@ const COLOR4D& PCB_RENDER_SETTINGS::GetColor( const VIEW_ITEM* aItem, int aLayer void PCB_RENDER_SETTINGS::update() { + RENDER_SETTINGS::update(); + // Calculate darkened/highlighted variants of layer colors for( int i = 0; i < TOTAL_LAYER_COUNT; i++ ) { - m_layerColors[i].a = m_layerOpacity; m_layerColorsHi[i] = m_layerColors[i].Brightened( m_highlightFactor ); m_layerColorsDark[i] = m_layerColors[i].Darkened( 1.0 - m_highlightFactor ); m_layerColorsSel[i] = m_layerColors[i].Brightened( m_selectFactor ); } - - m_hiContrastColor = COLOR4D( m_hiContrastFactor, m_hiContrastFactor, m_hiContrastFactor, - m_layerOpacity ); -} - - -const COLOR4D& PCB_RENDER_SETTINGS::GetLayerColor( int aLayer ) const -{ - return m_layerColors[aLayer]; } @@ -246,6 +238,10 @@ bool PCB_PAINTER::Draw( const VIEW_ITEM* aItem, int aLayer ) draw( (PCB_TARGET*) aItem ); break; + case PCB_MARKER_T: + draw( (MARKER_PCB*) aItem ); + break; + default: // Painter does not know how to draw the object return false; @@ -261,14 +257,11 @@ void PCB_PAINTER::draw( const TRACK* aTrack, int aLayer ) VECTOR2D start( aTrack->GetStart() ); VECTOR2D end( aTrack->GetEnd() ); int width = aTrack->GetWidth(); - COLOR4D color; if( m_pcbSettings->m_netNamesOnTracks && IsNetnameLayer( aLayer ) ) { - int netCode = aTrack->GetNetCode(); - // If there is a net name - display it on the track - if( netCode > 0 ) + if( aTrack->GetNetCode() > NETINFO_LIST::UNCONNECTED ) { VECTOR2D line = ( end - start ); double length = line.EuclideanNorm(); @@ -277,17 +270,13 @@ void PCB_PAINTER::draw( const TRACK* aTrack, int aLayer ) if( length < 10 * width ) return; - NETINFO_ITEM* net = aTrack->GetNet(); - if( !net ) - return; - const wxString& netName = aTrack->GetShortNetname(); VECTOR2D textPosition = start + line / 2.0; // center of the track double textOrientation = -atan( line.y / line.x ); double textSize = std::min( static_cast( width ), length / netName.length() ); // Set a proper color for the label - color = m_pcbSettings->GetColor( aTrack, aTrack->GetLayer() ); + const COLOR4D& color = m_pcbSettings->GetColor( aTrack, aTrack->GetLayer() ); COLOR4D labelColor = m_pcbSettings->GetColor( NULL, aLayer ); if( color.GetBrightness() > 0.5 ) @@ -308,11 +297,11 @@ void PCB_PAINTER::draw( const TRACK* aTrack, int aLayer ) else if( IsCopperLayer( aLayer ) ) { // Draw a regular track - color = m_pcbSettings->GetColor( aTrack, aLayer ); + const COLOR4D& color = m_pcbSettings->GetColor( aTrack, aLayer ); m_gal->SetStrokeColor( color ); m_gal->SetIsStroke( true ); - if( m_pcbSettings->m_sketchModeSelect[TRACKS_VISIBLE] ) + if( m_pcbSettings->m_sketchMode[TRACKS_VISIBLE] ) { // Outline mode m_gal->SetLineWidth( m_pcbSettings->m_outlineWidth ); @@ -333,10 +322,9 @@ void PCB_PAINTER::draw( const VIA* aVia, int aLayer ) { VECTOR2D center( aVia->GetStart() ); double radius; - COLOR4D color; // Choose drawing settings depending on if we are drawing via's pad or hole - if( aLayer == ITEM_GAL_LAYER( VIAS_VISIBLE ) ) + if( aLayer == ITEM_GAL_LAYER( VIA_THROUGH_VISIBLE ) ) { radius = aVia->GetWidth() / 2.0; } @@ -347,9 +335,9 @@ void PCB_PAINTER::draw( const VIA* aVia, int aLayer ) else return; - color = m_pcbSettings->GetColor( aVia, aLayer ); + const COLOR4D& color = m_pcbSettings->GetColor( aVia, aLayer ); - if( m_pcbSettings->m_sketchModeSelect[VIAS_VISIBLE] ) + if( m_pcbSettings->m_sketchMode[VIA_THROUGH_VISIBLE] ) { // Outline mode m_gal->SetIsFill( false ); @@ -371,7 +359,6 @@ void PCB_PAINTER::draw( const VIA* aVia, int aLayer ) void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer ) { - COLOR4D color; VECTOR2D size; VECTOR2D position( aPad->GetPosition() ); PAD_SHAPE_T shape; @@ -386,7 +373,7 @@ void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer ) if( m_pcbSettings->m_netNamesOnPads || m_pcbSettings->m_padNumbers ) { // Min char count to calculate string size - #define MIN_CHAR_COUNT 3 + const int MIN_CHAR_COUNT = 3; bool displayNetname = ( m_pcbSettings->m_netNamesOnPads && !aPad->GetNetname().empty() ); @@ -406,9 +393,6 @@ void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer ) // If the text is displayed on a symmetrical pad, do not rotate it orientation = 0.0; } - else - { - } // Font size limits if( size > maxSize ) @@ -429,7 +413,7 @@ void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer ) m_gal->SetMirrored( false ); // Set a proper color for the label - color = m_pcbSettings->GetColor( aPad, aPad->GetLayer() ); + const COLOR4D& color = m_pcbSettings->GetColor( aPad, aPad->GetLayer() ); COLOR4D labelColor = m_pcbSettings->GetColor( NULL, aLayer ); if( color.GetBrightness() > 0.5 ) @@ -457,8 +441,7 @@ void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer ) VECTOR2D namesize( tsize, tsize ); m_gal->SetGlyphSize( namesize ); m_gal->SetLineWidth( namesize.x / 12.0 ); - m_gal->StrokeText( std::wstring( aPad->GetShortNetname().wc_str() ), - textpos, 0.0 ); + m_gal->StrokeText( aPad->GetShortNetname(), textpos, 0.0 ); } if( m_pcbSettings->m_padNumbers ) @@ -475,7 +458,7 @@ void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer ) m_gal->SetGlyphSize( numsize ); m_gal->SetLineWidth( numsize.x / 12.0 ); - m_gal->StrokeText( std::wstring( aPad->GetPadName().wc_str() ), textpos, 0.0 ); + m_gal->StrokeText( aPad->GetPadName(), textpos, 0.0 ); } m_gal->Restore(); @@ -484,8 +467,8 @@ void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer ) } // Pad drawing - color = m_pcbSettings->GetColor( aPad, aLayer ); - if( m_pcbSettings->m_sketchModeSelect[PADS_VISIBLE] ) + const COLOR4D& color = m_pcbSettings->GetColor( aPad, aLayer ); + if( m_pcbSettings->m_sketchMode[PADS_VISIBLE] ) { // Outline mode m_gal->SetIsFill( false ); @@ -548,7 +531,7 @@ void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer ) m = ( size.y - size.x ); n = size.x; - if( m_pcbSettings->m_sketchModeSelect[PADS_VISIBLE] ) + if( m_pcbSettings->m_sketchMode[PADS_VISIBLE] ) { // Outline mode m_gal->DrawArc( VECTOR2D( 0, -m ), n, -M_PI, 0 ); @@ -569,7 +552,7 @@ void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer ) m = ( size.x - size.y ); n = size.y; - if( m_pcbSettings->m_sketchModeSelect[PADS_VISIBLE] ) + if( m_pcbSettings->m_sketchMode[PADS_VISIBLE] ) { // Outline mode m_gal->DrawArc( VECTOR2D( -m, 0 ), n, M_PI / 2, 3 * M_PI / 2 ); @@ -605,7 +588,7 @@ void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer ) pointList.push_back( VECTOR2D( corners[2] ) ); pointList.push_back( VECTOR2D( corners[3] ) ); - if( m_pcbSettings->m_sketchModeSelect[PADS_VISIBLE] ) + if( m_pcbSettings->m_sketchMode[PADS_VISIBLE] ) { // Add the beginning point to close the outline pointList.push_back( pointList.front() ); @@ -629,7 +612,7 @@ void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer ) void PCB_PAINTER::draw( const DRAWSEGMENT* aSegment ) { - COLOR4D color = m_pcbSettings->GetColor( aSegment, aSegment->GetLayer() ); + const COLOR4D& color = m_pcbSettings->GetColor( aSegment, aSegment->GetLayer() ); m_gal->SetIsFill( false ); m_gal->SetIsStroke( true ); @@ -709,7 +692,7 @@ void PCB_PAINTER::draw( const TEXTE_PCB* aText, int aLayer ) if( aText->GetText().Length() == 0 ) return; - COLOR4D strokeColor = m_pcbSettings->GetColor( aText, aText->GetLayer() ); + const COLOR4D& strokeColor = m_pcbSettings->GetColor( aText, aText->GetLayer() ); VECTOR2D position( aText->GetTextPosition().x, aText->GetTextPosition().y ); double orientation = aText->GetOrientation() * M_PI / 1800.0; @@ -725,7 +708,7 @@ void PCB_PAINTER::draw( const TEXTE_MODULE* aText, int aLayer ) if( aText->GetLength() == 0 ) return; - COLOR4D strokeColor = m_pcbSettings->GetColor( aText, aLayer ); + const COLOR4D& strokeColor = m_pcbSettings->GetColor( aText, aLayer ); VECTOR2D position( aText->GetTextPosition().x, aText->GetTextPosition().y ); double orientation = aText->GetDrawRotation() * M_PI / 1800.0; @@ -738,7 +721,7 @@ void PCB_PAINTER::draw( const TEXTE_MODULE* aText, int aLayer ) void PCB_PAINTER::draw( const ZONE_CONTAINER* aZone ) { - COLOR4D color = m_pcbSettings->GetColor( aZone, aZone->GetLayer() ); + const COLOR4D& color = m_pcbSettings->GetColor( aZone, aZone->GetLayer() ); std::deque corners; PCB_RENDER_SETTINGS::DisplayZonesMode displayMode = m_pcbSettings->m_displayZoneMode; @@ -811,7 +794,7 @@ void PCB_PAINTER::draw( const ZONE_CONTAINER* aZone ) void PCB_PAINTER::draw( const DIMENSION* aDimension, int aLayer ) { - COLOR4D strokeColor = m_pcbSettings->GetColor( aDimension, aLayer ); + const COLOR4D& strokeColor = m_pcbSettings->GetColor( aDimension, aLayer ); m_gal->SetStrokeColor( strokeColor ); m_gal->SetIsFill( false ); @@ -824,10 +807,10 @@ void PCB_PAINTER::draw( const DIMENSION* aDimension, int aLayer ) VECTOR2D( aDimension->m_featureLineGF ) ); m_gal->DrawLine( VECTOR2D( aDimension->m_featureLineDO ), VECTOR2D( aDimension->m_featureLineDF ) ); - m_gal->DrawLine( VECTOR2D( aDimension->m_arrowD1O ), VECTOR2D( aDimension->m_arrowD1F ) ); - m_gal->DrawLine( VECTOR2D( aDimension->m_arrowD2O ), VECTOR2D( aDimension->m_arrowD2F ) ); - m_gal->DrawLine( VECTOR2D( aDimension->m_arrowG1O ), VECTOR2D( aDimension->m_arrowG1F ) ); - m_gal->DrawLine( VECTOR2D( aDimension->m_arrowG2O ), VECTOR2D( aDimension->m_arrowG2F ) ); + m_gal->DrawLine( VECTOR2D( aDimension->m_crossBarF ), VECTOR2D( aDimension->m_arrowD1F ) ); + m_gal->DrawLine( VECTOR2D( aDimension->m_crossBarF ), VECTOR2D( aDimension->m_arrowD2F ) ); + m_gal->DrawLine( VECTOR2D( aDimension->m_crossBarO ), VECTOR2D( aDimension->m_arrowG1F ) ); + m_gal->DrawLine( VECTOR2D( aDimension->m_crossBarO ), VECTOR2D( aDimension->m_arrowG2F ) ); // Draw text TEXTE_PCB& text = aDimension->Text(); @@ -836,13 +819,13 @@ void PCB_PAINTER::draw( const DIMENSION* aDimension, int aLayer ) m_gal->SetLineWidth( text.GetThickness() ); m_gal->SetTextAttributes( &text ); - m_gal->StrokeText( std::wstring( text.GetText().wc_str() ), position, orientation ); + m_gal->StrokeText( text.GetText(), position, orientation ); } void PCB_PAINTER::draw( const PCB_TARGET* aTarget ) { - COLOR4D strokeColor = m_pcbSettings->GetColor( aTarget, aTarget->GetLayer() ); + const COLOR4D& strokeColor = m_pcbSettings->GetColor( aTarget, aTarget->GetLayer() ); VECTOR2D position( aTarget->GetPosition() ); double size, radius; @@ -876,4 +859,23 @@ void PCB_PAINTER::draw( const PCB_TARGET* aTarget ) } +void PCB_PAINTER::draw( const MARKER_PCB* aMarker ) +{ + const BOARD_ITEM* item = aMarker->GetItem(); + + if( item ) // By default draw an item in a different color + { + Draw( item, ITEM_GAL_LAYER( DRC_VISIBLE ) ); + } + else // If there is no item associated - draw a circle marking the DRC error + { + m_gal->SetStrokeColor( COLOR4D( 1.0, 0.0, 0.0, 1.0 ) ); + m_gal->SetIsFill( false ); + m_gal->SetIsStroke( true ); + m_gal->SetLineWidth( 10000 ); + m_gal->DrawCircle( VECTOR2D( aMarker->GetPosition() ), 200000 ); + } +} + + const double PCB_RENDER_SETTINGS::MAX_FONT_SIZE = Millimeter2iu( 10.0 ); diff --git a/pcbnew/pcb_painter.h b/pcbnew/pcb_painter.h index 85b1192936..d9ef81b4e1 100644 --- a/pcbnew/pcb_painter.h +++ b/pcbnew/pcb_painter.h @@ -48,6 +48,7 @@ class TEXTE_PCB; class TEXTE_MODULE; class DIMENSION; class PCB_TARGET; +class MARKER_PCB; namespace KIGFX { @@ -96,7 +97,51 @@ public: * Returns the color used to draw a layer. * @param aLayer is the layer number. */ - const COLOR4D& GetLayerColor( int aLayer ) const; + const COLOR4D& GetLayerColor( int aLayer ) const + { + return m_layerColors[aLayer]; + } + + /** + * Function SetLayerColor + * Changes the color used to draw a layer. + * @param aLayer is the layer number. + * @param aColor is the new color. + */ + void SetLayerColor( int aLayer, const COLOR4D& aColor ) + { + m_layerColors[aLayer] = aColor; + + update(); // recompute other shades of the color + } + + /** + * Function SetSketchMode + * Turns on/off sketch mode for given item layer. + * @param aItemLayer is the item layer that is changed. + * @param aEnabled decides if it is drawn in sketch mode (true for sketched mode, + * false for filled mode). + */ + void SetSketchMode( int aItemLayer, bool aEnabled ) + { + // It is supposed to work only with item layers + assert( aItemLayer >= ITEM_GAL_LAYER( 0 ) ); + + m_sketchMode[aItemLayer] = aEnabled; + } + + /** + * Function GetSketchMode + * Returns sketch mode setting for a given item layer. + * @param aItemLayer is the item layer that is changed. + */ + bool GetSketchMode( int aItemLayer ) const + { + // It is supposed to work only with item layers + assert( aItemLayer >= ITEM_GAL_LAYER( 0 ) ); + + return m_sketchMode[aItemLayer]; + } protected: ///> @copydoc RENDER_SETTINGS::Update() @@ -114,8 +159,8 @@ protected: ///> Colors for all layers (darkened) COLOR4D m_layerColorsDark[TOTAL_LAYER_COUNT]; - ///> Flag determining if items on a given layer should be drawn as an outline or a full item - bool m_sketchModeSelect[TOTAL_LAYER_COUNT]; + ///> Flag determining if items on a given layer should be drawn as an outline or a filled item + bool m_sketchMode[TOTAL_LAYER_COUNT]; ///> Flag determining if pad numbers should be visible bool m_padNumbers; @@ -169,6 +214,7 @@ protected: void draw( const ZONE_CONTAINER* aZone ); void draw( const DIMENSION* aDimension, int aLayer ); void draw( const PCB_TARGET* aTarget ); + void draw( const MARKER_PCB* aMarker ); }; } // namespace KIGFX diff --git a/pcbnew/pcb_parser.cpp b/pcbnew/pcb_parser.cpp index 97e073d1d5..bfa1ea337d 100644 --- a/pcbnew/pcb_parser.cpp +++ b/pcbnew/pcb_parser.cpp @@ -1438,6 +1438,7 @@ DIMENSION* PCB_PARSER::parseDIMENSION() throw( IO_ERROR, PARSE_ERROR ) parseXY( &dimension->m_featureLineDO.x, &dimension->m_featureLineDO.y ); parseXY( &dimension->m_featureLineDF.x, &dimension->m_featureLineDF.y ); + dimension->UpdateHeight(); NeedRIGHT(); NeedRIGHT(); break; @@ -1451,6 +1452,7 @@ DIMENSION* PCB_PARSER::parseDIMENSION() throw( IO_ERROR, PARSE_ERROR ) parseXY( &dimension->m_featureLineGO.x, &dimension->m_featureLineGO.y ); parseXY( &dimension->m_featureLineGF.x, &dimension->m_featureLineGF.y ); + dimension->UpdateHeight(); NeedRIGHT(); NeedRIGHT(); break; @@ -1465,6 +1467,7 @@ DIMENSION* PCB_PARSER::parseDIMENSION() throw( IO_ERROR, PARSE_ERROR ) parseXY( &dimension->m_crossBarO.x, &dimension->m_crossBarO.y ); parseXY( &dimension->m_crossBarF.x, &dimension->m_crossBarF.y ); + dimension->UpdateHeight(); NeedRIGHT(); NeedRIGHT(); break; @@ -1476,7 +1479,7 @@ DIMENSION* PCB_PARSER::parseDIMENSION() throw( IO_ERROR, PARSE_ERROR ) if( token != T_pts ) Expecting( T_pts ); - parseXY( &dimension->m_arrowD1O.x, &dimension->m_arrowD1O.y ); + parseXY( &dimension->m_crossBarF.x, &dimension->m_crossBarF.y ); parseXY( &dimension->m_arrowD1F.x, &dimension->m_arrowD1F.y ); NeedRIGHT(); NeedRIGHT(); @@ -1489,7 +1492,7 @@ DIMENSION* PCB_PARSER::parseDIMENSION() throw( IO_ERROR, PARSE_ERROR ) if( token != T_pts ) Expecting( T_pts ); - parseXY( &dimension->m_arrowD2O.x, &dimension->m_arrowD2O.y ); + parseXY( &dimension->m_crossBarF.x, &dimension->m_crossBarF.y ); parseXY( &dimension->m_arrowD2F.x, &dimension->m_arrowD2F.y ); NeedRIGHT(); NeedRIGHT(); @@ -1502,7 +1505,7 @@ DIMENSION* PCB_PARSER::parseDIMENSION() throw( IO_ERROR, PARSE_ERROR ) if( token != T_pts ) Expecting( T_pts ); - parseXY( &dimension->m_arrowG1O.x, &dimension->m_arrowG1O.y ); + parseXY( &dimension->m_crossBarO.x, &dimension->m_crossBarO.y ); parseXY( &dimension->m_arrowG1F.x, &dimension->m_arrowG1F.y ); NeedRIGHT(); NeedRIGHT(); @@ -1515,7 +1518,7 @@ DIMENSION* PCB_PARSER::parseDIMENSION() throw( IO_ERROR, PARSE_ERROR ) if( token != T_pts ) Expecting( T_pts ); - parseXY( &dimension->m_arrowG2O.x, &dimension->m_arrowG2O.y ); + parseXY( &dimension->m_crossBarO.x, &dimension->m_crossBarO.y ); parseXY( &dimension->m_arrowG2F.x, &dimension->m_arrowG2F.y ); NeedRIGHT(); NeedRIGHT(); diff --git a/pcbnew/pcbframe.cpp b/pcbnew/pcbframe.cpp index a95e7804fa..3ed5d2583a 100644 --- a/pcbnew/pcbframe.cpp +++ b/pcbnew/pcbframe.cpp @@ -57,6 +57,7 @@ #include #include #include +#include #include #include @@ -73,7 +74,8 @@ #include #endif -#include +#include +#include // Keys used in read/write config #define OPTKEY_DEFAULT_LINEWIDTH_VALUE wxT( "PlotLineWidth_mm" ) @@ -127,12 +129,6 @@ BEGIN_EVENT_TABLE( PCB_EDIT_FRAME, PCB_BASE_FRAME ) EVT_MENU( wxID_EXIT, PCB_EDIT_FRAME::OnQuit ) // menu Config - - /* Tom's hacks start */ - EVT_MENU ( ID_PNS_ROUTER_TOOL, PCB_EDIT_FRAME::onGenericCommand ) - EVT_TOOL ( ID_PNS_ROUTER_TOOL, PCB_EDIT_FRAME::onGenericCommand ) - /* Tom's hacks end */ - EVT_MENU( ID_PCB_DRAWINGS_WIDTHS_SETUP, PCB_EDIT_FRAME::OnConfigurePcbOptions ) EVT_MENU( ID_PCB_LIB_TABLE_EDIT, PCB_EDIT_FRAME::Process_Config ) EVT_MENU( ID_CONFIG_SAVE, PCB_EDIT_FRAME::Process_Config ) @@ -492,17 +488,14 @@ void PCB_EDIT_FRAME::SetBoard( BOARD* aBoard ) { PCB_BASE_FRAME::SetBoard( aBoard ); - if( GetGalCanvas() ) + if( IsGalCanvasActive() ) { ViewReloadBoard( aBoard ); // update the tool manager with the new board and its view. - if( m_toolManager ) - { - m_toolManager->SetEnvironment( aBoard, GetGalCanvas()->GetView(), - GetGalCanvas()->GetViewControls(), this ); - m_toolManager->ResetTools( TOOL_BASE::MODEL_RELOAD ); - } + m_toolManager.SetEnvironment( aBoard, GetGalCanvas()->GetView(), + GetGalCanvas()->GetViewControls(), this ); + m_toolManager.ResetTools( TOOL_BASE::MODEL_RELOAD ); } } @@ -517,51 +510,26 @@ void PCB_EDIT_FRAME::ViewReloadBoard( const BOARD* aBoard ) const // Load zones for( int i = 0; i < aBoard->GetAreaCount(); ++i ) - { view->Add( (KIGFX::VIEW_ITEM*) ( aBoard->GetArea( i ) ) ); - } // Load drawings for( BOARD_ITEM* drawing = aBoard->m_Drawings; drawing; drawing = drawing->Next() ) - { view->Add( drawing ); - } // Load tracks for( TRACK* track = aBoard->m_Track; track; track = track->Next() ) - { view->Add( track ); - } // Load modules and its additional elements for( MODULE* module = aBoard->m_Modules; module; module = module->Next() ) { - // Load module's pads - for( D_PAD* pad = module->Pads().GetFirst(); pad; pad = pad->Next() ) - { - view->Add( pad ); - } - - // Load module's drawing (mostly silkscreen) - for( BOARD_ITEM* drawing = module->GraphicalItems().GetFirst(); drawing; - drawing = drawing->Next() ) - { - view->Add( drawing ); - } - - // Load module's texts (name and value) - view->Add( &module->Reference() ); - view->Add( &module->Value() ); - - // Add the module itself + module->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, view, _1 ) ); view->Add( module ); } // Segzones (equivalent of ZONE_CONTAINER for legacy boards) for( SEGZONE* zone = aBoard->m_Zone; zone; zone = zone->Next() ) - { view->Add( zone ); - } KIGFX::WORKSHEET_VIEWITEM* worksheet = aBoard->GetWorksheetViewItem(); worksheet->SetSheetName( std::string( GetScreenDesc().mb_str() ) ); @@ -578,7 +546,7 @@ void PCB_EDIT_FRAME::ViewReloadBoard( const BOARD* aBoard ) const view->Add( aBoard->GetRatsnestViewItem() ); // Limit panning to the size of worksheet frame - view->SetPanBoundary( aBoard->GetWorksheetViewItem()->ViewBBox() ); + GetGalCanvas()->GetViewControls()->SetPanBoundary( aBoard->GetWorksheetViewItem()->ViewBBox() ); view->RecacheAllItems( true ); if( IsGalCanvasActive() ) @@ -701,16 +669,16 @@ void PCB_EDIT_FRAME::UseGalCanvas( bool aEnable ) { EDA_DRAW_FRAME::UseGalCanvas( aEnable ); - ViewReloadBoard( m_Pcb ); - if( aEnable ) { + ViewReloadBoard( m_Pcb ); + // Update potential changes in the ratsnest m_Pcb->GetRatsnest()->Recalculate(); - m_toolManager->SetEnvironment( m_Pcb, GetGalCanvas()->GetView(), + m_toolManager.SetEnvironment( m_Pcb, GetGalCanvas()->GetView(), GetGalCanvas()->GetViewControls(), this ); - m_toolManager->ResetTools( TOOL_BASE::GAL_SWITCH ); + m_toolManager.ResetTools( TOOL_BASE::GAL_SWITCH ); } } @@ -722,6 +690,7 @@ void PCB_EDIT_FRAME::SwitchCanvas( wxCommandEvent& aEvent ) switch( id ) { case ID_MENU_CANVAS_DEFAULT: + Compile_Ratsnest( NULL, true ); UseGalCanvas( false ); break; @@ -832,7 +801,7 @@ void PCB_EDIT_FRAME::SetGridColor(EDA_COLOR_T aColor) bool PCB_EDIT_FRAME::IsMicroViaAcceptable() { int copperlayercnt = GetBoard()->GetCopperLayerCount( ); - LAYER_NUM currLayer = getActiveLayer(); + LAYER_NUM currLayer = GetActiveLayer(); if( !GetDesignSettings().m_MicroViasAllowed ) return false; // Obvious.. @@ -850,13 +819,13 @@ bool PCB_EDIT_FRAME::IsMicroViaAcceptable() } -void PCB_EDIT_FRAME::setHighContrastLayer( LAYER_NUM aLayer ) +void PCB_EDIT_FRAME::SetHighContrastLayer( LAYER_NUM aLayer ) { // Set display settings for high contrast mode KIGFX::VIEW* view = GetGalCanvas()->GetView(); KIGFX::RENDER_SETTINGS* rSettings = view->GetPainter()->GetSettings(); - setTopLayer( aLayer ); + SetTopLayer( aLayer ); rSettings->ClearActiveLayers(); rSettings->SetActiveLayer( aLayer ); @@ -867,7 +836,7 @@ void PCB_EDIT_FRAME::setHighContrastLayer( LAYER_NUM aLayer ) // fixme do not like the idea of storing the list of layers here, // should be done in some other way I guess.. LAYER_NUM layers[] = { - GetNetnameLayer( aLayer ), ITEM_GAL_LAYER( VIAS_VISIBLE ), + GetNetnameLayer( aLayer ), ITEM_GAL_LAYER( VIA_THROUGH_VISIBLE ), ITEM_GAL_LAYER( VIAS_HOLES_VISIBLE ), ITEM_GAL_LAYER( PADS_VISIBLE ), ITEM_GAL_LAYER( PADS_HOLES_VISIBLE ), NETNAMES_GAL_LAYER( PADS_NETNAMES_VISIBLE ), ITEM_GAL_LAYER( GP_OVERLAY ), ITEM_GAL_LAYER( RATSNEST_VISIBLE ) @@ -893,7 +862,7 @@ void PCB_EDIT_FRAME::setHighContrastLayer( LAYER_NUM aLayer ) } -void PCB_EDIT_FRAME::setTopLayer( LAYER_NUM aLayer ) +void PCB_EDIT_FRAME::SetTopLayer( LAYER_NUM aLayer ) { // Set display settings for high contrast mode KIGFX::VIEW* view = GetGalCanvas()->GetView(); @@ -907,10 +876,11 @@ void PCB_EDIT_FRAME::setTopLayer( LAYER_NUM aLayer ) // fixme do not like the idea of storing the list of layers here, // should be done in some other way I guess.. LAYER_NUM layers[] = { - GetNetnameLayer( aLayer ), ITEM_GAL_LAYER( VIAS_VISIBLE ), + GetNetnameLayer( aLayer ), ITEM_GAL_LAYER( VIA_THROUGH_VISIBLE ), ITEM_GAL_LAYER( VIAS_HOLES_VISIBLE ), ITEM_GAL_LAYER( PADS_VISIBLE ), ITEM_GAL_LAYER( PADS_HOLES_VISIBLE ), NETNAMES_GAL_LAYER( PADS_NETNAMES_VISIBLE ), - ITEM_GAL_LAYER( GP_OVERLAY ), ITEM_GAL_LAYER( RATSNEST_VISIBLE ), DRAW_N + ITEM_GAL_LAYER( GP_OVERLAY ), ITEM_GAL_LAYER( RATSNEST_VISIBLE ), DRAW_N, + ITEM_GAL_LAYER( DRC_VISIBLE ) }; for( unsigned int i = 0; i < sizeof( layers ) / sizeof( LAYER_NUM ); ++i ) @@ -935,11 +905,11 @@ void PCB_EDIT_FRAME::setTopLayer( LAYER_NUM aLayer ) } -void PCB_EDIT_FRAME::setActiveLayer( LAYER_NUM aLayer, bool doLayerWidgetUpdate ) +void PCB_EDIT_FRAME::SetActiveLayer( LAYER_NUM aLayer, bool doLayerWidgetUpdate ) { ( (PCB_SCREEN*) GetScreen() )->m_Active_Layer = aLayer; - setHighContrastLayer( aLayer ); + SetHighContrastLayer( aLayer ); if( doLayerWidgetUpdate ) syncLayerWidgetLayer(); @@ -951,7 +921,7 @@ void PCB_EDIT_FRAME::setActiveLayer( LAYER_NUM aLayer, bool doLayerWidgetUpdate void PCB_EDIT_FRAME::syncLayerWidgetLayer() { - m_Layers->SelectLayer( getActiveLayer() ); + m_Layers->SelectLayer( GetActiveLayer() ); m_Layers->OnLayerSelected(); } @@ -1008,6 +978,7 @@ bool PCB_EDIT_FRAME::IsElementVisible( int aElement ) const void PCB_EDIT_FRAME::SetElementVisibility( int aElement, bool aNewState ) { + GetGalCanvas()->GetView()->SetLayerVisible( ITEM_GAL_LAYER( aElement ), aNewState ); GetBoard()->SetElementVisibility( aElement, aNewState ); m_Layers->SetRenderState( aElement, aNewState ); } diff --git a/pcbnew/pcbnew_id.h b/pcbnew/pcbnew_id.h index 608bac920a..0ceb7ccde8 100644 --- a/pcbnew/pcbnew_id.h +++ b/pcbnew/pcbnew_id.h @@ -370,9 +370,7 @@ enum pcbnew_ids ID_FOOTPRINT_WIZARD_PAGES_WINDOW, ID_FOOTPRINT_WIZARD_PARAMETERS_WINDOW, ID_FOOTPRINT_WIZARD_SELECT_WIZARD, - ID_FOOTPRINT_WIZARD_EXPORT_TO_BOARD, - - ID_PNS_ROUTER_TOOL + ID_FOOTPRINT_WIZARD_EXPORT_TO_BOARD }; #endif // PCBNEW_ID_H_ diff --git a/pcbnew/plot_brditems_plotter.cpp b/pcbnew/plot_brditems_plotter.cpp index 8494eb560b..00dbeede81 100644 --- a/pcbnew/plot_brditems_plotter.cpp +++ b/pcbnew/plot_brditems_plotter.cpp @@ -275,19 +275,19 @@ void BRDITEMS_PLOTTER::PlotDimension( DIMENSION* aDim ) draw.SetEnd( aDim->m_featureLineDF ); PlotDrawSegment( &draw ); - draw.SetStart( aDim->m_arrowD1O ); + draw.SetStart( aDim->m_crossBarF ); draw.SetEnd( aDim->m_arrowD1F ); PlotDrawSegment( &draw ); - draw.SetStart( aDim->m_arrowD2O ); + draw.SetStart( aDim->m_crossBarF ); draw.SetEnd( aDim->m_arrowD2F ); PlotDrawSegment( &draw ); - draw.SetStart( aDim->m_arrowG1O ); + draw.SetStart( aDim->m_crossBarO ); draw.SetEnd( aDim->m_arrowG1F ); PlotDrawSegment( &draw ); - draw.SetStart( aDim->m_arrowG2O ); + draw.SetStart( aDim->m_crossBarO ); draw.SetEnd( aDim->m_arrowG2F ); PlotDrawSegment( &draw ); } diff --git a/pcbnew/ratsnest_data.cpp b/pcbnew/ratsnest_data.cpp index 26a0d34bf2..4b4c063485 100644 --- a/pcbnew/ratsnest_data.cpp +++ b/pcbnew/ratsnest_data.cpp @@ -68,7 +68,7 @@ bool sortDistance( const RN_NODE_PTR& aOrigin, const RN_NODE_PTR& aNode1, bool sortWeight( const RN_EDGE_PTR& aEdge1, const RN_EDGE_PTR& aEdge2 ) { - return aEdge1->getWeight() < aEdge2->getWeight(); + return aEdge1->GetWeight() < aEdge2->GetWeight(); } @@ -92,7 +92,7 @@ bool operator!=( const RN_NODE_PTR& aFirst, const RN_NODE_PTR& aSecond ) bool isEdgeConnectingNode( const RN_EDGE_PTR& aEdge, const RN_NODE_PTR& aNode ) { - return aEdge->getSourceNode() == aNode || aEdge->getTargetNode() == aNode; + return aEdge->GetSourceNode() == aNode || aEdge->GetTargetNode() == aNode; } @@ -125,8 +125,8 @@ std::vector* kruskalMST( RN_LINKS::RN_EDGE_LIST& aEdges, { RN_EDGE_PTR& dt = *aEdges.begin(); - int srcTag = tags[dt->getSourceNode()]; - int trgTag = tags[dt->getTargetNode()]; + int srcTag = tags[dt->GetSourceNode()]; + int trgTag = tags[dt->GetTargetNode()]; // Check if by adding this edge we are going to join two different forests if( srcTag != trgTag ) @@ -139,7 +139,7 @@ std::vector* kruskalMST( RN_LINKS::RN_EDGE_LIST& aEdges, // Move nodes that were marked with old tag to the list marked with the new tag cycles[srcTag].splice( cycles[srcTag].end(), cycles[trgTag] ); - if( dt->getWeight() == 0 ) // Skip already existing connections (weight == 0) + if( dt->GetWeight() == 0 ) // Skip already existing connections (weight == 0) { mstExpectedSize--; } @@ -148,9 +148,9 @@ std::vector* kruskalMST( RN_LINKS::RN_EDGE_LIST& aEdges, // Do a copy of edge, but make it RN_EDGE_MST. In contrary to RN_EDGE, // RN_EDGE_MST saves both source and target node and does not require any other // edges to exist for getting source/target nodes - RN_EDGE_MST_PTR newEdge = boost::make_shared( dt->getSourceNode(), - dt->getTargetNode(), - dt->getWeight() ); + RN_EDGE_MST_PTR newEdge = boost::make_shared( dt->GetSourceNode(), + dt->GetTargetNode(), + dt->GetWeight() ); mst->push_back( newEdge ); ++mstSize; } @@ -169,8 +169,8 @@ std::vector* kruskalMST( RN_LINKS::RN_EDGE_LIST& aEdges, void RN_NET::validateEdge( RN_EDGE_PTR& aEdge ) { - RN_NODE_PTR source = aEdge->getSourceNode(); - RN_NODE_PTR target = aEdge->getTargetNode(); + RN_NODE_PTR source = aEdge->GetSourceNode(); + RN_NODE_PTR target = aEdge->GetTargetNode(); bool valid = true; // If any of nodes belonging to the edge has the flag set, @@ -280,13 +280,13 @@ void RN_NET::compute() std::partial_sort_copy( boardNodes.begin(), boardNodes.end(), nodes.begin(), nodes.end() ); TRIANGULATOR triangulator; - triangulator.createDelaunay( nodes.begin(), nodes.end() ); - boost::scoped_ptr triangEdges( triangulator.getEdges() ); + triangulator.CreateDelaunay( nodes.begin(), nodes.end() ); + boost::scoped_ptr triangEdges( triangulator.GetEdges() ); // Compute weight/distance for edges resulting from triangulation RN_LINKS::RN_EDGE_LIST::iterator eit, eitEnd; for( eit = (*triangEdges).begin(), eitEnd = (*triangEdges).end(); eit != eitEnd; ++eit ) - (*eit)->setWeight( getDistance( (*eit)->getSourceNode(), (*eit)->getTargetNode() ) ); + (*eit)->SetWeight( getDistance( (*eit)->GetSourceNode(), (*eit)->GetTargetNode() ) ); // Add the currently existing connections list to the results of triangulation std::copy( boardEdges.begin(), boardEdges.end(), std::front_inserter( *triangEdges ) ); @@ -508,8 +508,8 @@ void RN_NET::RemoveItem( const TRACK* aTrack ) RN_EDGE_PTR& edge = m_tracks.at( aTrack ); // Save nodes, so they can be cleared later - RN_NODE_PTR aBegin = edge->getSourceNode(); - RN_NODE_PTR aEnd = edge->getTargetNode(); + RN_NODE_PTR aBegin = edge->GetSourceNode(); + RN_NODE_PTR aEnd = edge->GetTargetNode(); m_links.RemoveConnection( edge ); // Remove nodes associated with the edge. It is done in a safe way, there is a check @@ -696,8 +696,8 @@ std::list RN_NET::GetNodes( const BOARD_CONNECTED_ITEM* aItem ) con const TRACK* track = static_cast( aItem ); RN_EDGE_PTR edge = m_tracks.at( track ); - nodes.push_back( edge->getSourceNode() ); - nodes.push_back( edge->getTargetNode() ); + nodes.push_back( edge->GetSourceNode() ); + nodes.push_back( edge->GetTargetNode() ); } break; @@ -982,6 +982,7 @@ void RN_DATA::ProcessBoard() for( int i = 0; i < m_board->GetAreaCount(); ++i ) { ZONE_CONTAINER* zone = m_board->GetArea( i ); + netCode = zone->GetNetCode(); if( netCode > 0 ) @@ -1023,7 +1024,7 @@ void RN_DATA::updateNet( int aNetCode ) { assert( aNetCode < (int) m_nets.size() ); - if( aNetCode < 1 ) + if( aNetCode < 1 || aNetCode > (int) m_nets.size() ) return; m_nets[aNetCode].ClearSimple(); diff --git a/pcbnew/ratsnest_data.h b/pcbnew/ratsnest_data.h index 59f3f0e356..348c31902e 100644 --- a/pcbnew/ratsnest_data.h +++ b/pcbnew/ratsnest_data.h @@ -50,13 +50,13 @@ class ZONE_CONTAINER; class CPolyPt; // Preserve KiCad coding style policy -typedef hed::Node RN_NODE; -typedef hed::NodePtr RN_NODE_PTR; -typedef hed::Edge RN_EDGE; -typedef hed::EdgePtr RN_EDGE_PTR; -typedef hed::EdgeMST RN_EDGE_MST; -typedef boost::shared_ptr RN_EDGE_MST_PTR; -typedef hed::Triangulation TRIANGULATOR; +typedef hed::NODE RN_NODE; +typedef hed::NODE_PTR RN_NODE_PTR; +typedef hed::EDGE RN_EDGE; +typedef hed::EDGE_PTR RN_EDGE_PTR; +typedef hed::EDGE_MST RN_EDGE_MST; +typedef hed::TRIANGULATION TRIANGULATOR; +typedef boost::shared_ptr RN_EDGE_MST_PTR; bool operator==( const RN_NODE_PTR& aFirst, const RN_NODE_PTR& aSecond ); bool operator!=( const RN_NODE_PTR& aFirst, const RN_NODE_PTR& aSecond ); diff --git a/pcbnew/ratsnest_viewitem.cpp b/pcbnew/ratsnest_viewitem.cpp index 5de2527111..ffe88c3c7f 100644 --- a/pcbnew/ratsnest_viewitem.cpp +++ b/pcbnew/ratsnest_viewitem.cpp @@ -97,8 +97,8 @@ void RATSNEST_VIEWITEM::ViewDraw( int aLayer, GAL* aGal ) const BOOST_FOREACH( const RN_EDGE_PTR& edge, *edges ) { - const RN_NODE_PTR& sourceNode = edge->getSourceNode(); - const RN_NODE_PTR& targetNode = edge->getTargetNode(); + const RN_NODE_PTR& sourceNode = edge->GetSourceNode(); + const RN_NODE_PTR& targetNode = edge->GetTargetNode(); VECTOR2D source( sourceNode->GetX(), sourceNode->GetY() ); VECTOR2D target( targetNode->GetX(), targetNode->GetY() ); diff --git a/pcbnew/router/direction.h b/pcbnew/router/direction.h index 0b7d8cb62d..ad38fcbdef 100644 --- a/pcbnew/router/direction.h +++ b/pcbnew/router/direction.h @@ -133,10 +133,7 @@ public: */ DIRECTION_45 Opposite() const { - if( m_dir == UNDEFINED ) - return UNDEFINED; - - const Directions OppositeMap[] = { S, SW, W, NW, N, NE, E, SE }; + const Directions OppositeMap[] = { S, SW, W, NW, N, NE, E, SE, UNDEFINED }; return OppositeMap[m_dir]; } diff --git a/pcbnew/router/pns_router.cpp b/pcbnew/router/pns_router.cpp index 5f63911751..9a57b50b16 100644 --- a/pcbnew/router/pns_router.cpp +++ b/pcbnew/router/pns_router.cpp @@ -341,9 +341,13 @@ void PNS_ROUTER::ClearWorld() if( m_placer ) delete m_placer; + if( m_previewItems ) + delete m_previewItems; + m_clearanceFunc = NULL; m_world = NULL; m_placer = NULL; + m_previewItems = NULL; } @@ -466,6 +470,8 @@ void PNS_ROUTER::EraseView() item->ViewSetVisible( true ); } + m_hiddenItems.clear(); + if( m_previewItems ) { m_previewItems->FreeItems(); diff --git a/pcbnew/router/router_tool.cpp b/pcbnew/router/router_tool.cpp index 558b4dfab6..8fe733fb8c 100644 --- a/pcbnew/router/router_tool.cpp +++ b/pcbnew/router/router_tool.cpp @@ -21,16 +21,19 @@ #include #include -#include "class_drawpanel_gal.h" +#include "class_draw_panel_gal.h" #include "class_board_item.h" #include "class_board.h" #include +#include +#include #include #include #include #include +#include #include @@ -42,11 +45,11 @@ using namespace KIGFX; using boost::optional; -static TOOL_ACTION ACT_AutoEndRoute( "AutoEndRoute", AS_CONTEXT, 'F' ); -static TOOL_ACTION ACT_PlaceVia( "PlaceVia", AS_CONTEXT, 'V' ); -static TOOL_ACTION ACT_OpenRouteOptions( "OpenRouterOptions", AS_CONTEXT, 'E' ); -static TOOL_ACTION ACT_SwitchPosture( "SwitchPosture", AS_CONTEXT, '/' ); -static TOOL_ACTION ACT_EndTrack( "SwitchPosture", AS_CONTEXT, WXK_END ); +//static TOOL_ACTION ACT_AutoEndRoute( "pcbnew.InteractiveRouter.AutoEndRoute", AS_CONTEXT, 'G' ); +//static TOOL_ACTION ACT_PlaceVia( "pcbnew.InteractiveRouter.PlaceVia", AS_CONTEXT, 'V' ); +//static TOOL_ACTION ACT_OpenRouteOptions( "pcbnew.InteractiveRouter.OpenRouterOptions", AS_CONTEXT, 'T' ); +//static TOOL_ACTION ACT_SwitchPosture( "pcbnew.InteractiveRouter.SwitchPosture", AS_CONTEXT, '/' ); +//static TOOL_ACTION ACT_EndTrack( "pcbnew.InteractiveRouter.EndTrack", AS_CONTEXT, WXK_END ); ROUTER_TOOL::ROUTER_TOOL() : TOOL_INTERACTIVE( "pcbnew.InteractiveRouter" ) @@ -88,7 +91,7 @@ void ROUTER_TOOL::Reset( RESET_REASON aReason ) if( getView() ) m_router->SetView( getView() ); - Go( &ROUTER_TOOL::Main, TOOL_EVENT( TC_COMMAND, TA_ACTION, GetName() ) ); + Go( &ROUTER_TOOL::Main, COMMON_ACTIONS::routerActivate.MakeEvent() ); } @@ -281,7 +284,7 @@ void ROUTER_TOOL::updateEndItem( TOOL_EVENT& aEvent ) else { m_endItem = NULL; - m_endSnapPoint = getView()->ToWorld( ctls->GetCursorPosition() ); + m_endSnapPoint = ctls->GetCursorPosition(); ctls->ForceCursorPosition( false ); } @@ -364,9 +367,9 @@ void ROUTER_TOOL::startRouting() m_router->Move( m_endSnapPoint, m_endItem ); } - else if( evt->IsKeyUp() ) + else if( evt->IsKeyPressed() ) { - switch( evt->KeyCode() ) + switch( std::toupper( evt->KeyCode() ) ) { case 'V': { @@ -430,6 +433,7 @@ int ROUTER_TOOL::Main( TOOL_EVENT& aEvent ) // SetContextMenu ( m_menu ); // setMsgPanel(true, 0, wxT("KiRouter"), wxT("Pick an item to start routing")); + getEditFrame()->SetToolID( ID_TRACK_BUTT, wxCURSOR_PENCIL, _( "Add tracks" ) ); ctls->SetSnapping( true ); ctls->ShowCursor( true ); @@ -463,6 +467,7 @@ int ROUTER_TOOL::Main( TOOL_EVENT& aEvent ) ctls->ShowCursor( false ); ctls->ForceCursorPosition( false ); + getEditFrame()->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString ); + return 0; } - diff --git a/pcbnew/target_edit.cpp b/pcbnew/target_edit.cpp index 46310d4aae..5a0d860d30 100644 --- a/pcbnew/target_edit.cpp +++ b/pcbnew/target_edit.cpp @@ -127,7 +127,8 @@ void TARGET_PROPERTIES_DIALOG_EDITOR::OnCancelClick( wxCommandEvent& event ) */ void TARGET_PROPERTIES_DIALOG_EDITOR::OnOkClick( wxCommandEvent& event ) { - m_Target->Draw( m_Parent->GetCanvas(), m_DC, GR_XOR ); + if( m_DC ) + m_Target->Draw( m_Parent->GetCanvas(), m_DC, GR_XOR ); // Save old item in undo list, if is is not currently edited (will be later if so) if( m_Target->GetFlags() == 0 ) @@ -145,7 +146,8 @@ void TARGET_PROPERTIES_DIALOG_EDITOR::OnOkClick( wxCommandEvent& event ) m_Target->SetShape( m_TargetShape->GetSelection() ? 1 : 0 ); - m_Target->Draw( m_Parent->GetCanvas(), m_DC, ( m_Target->IsMoving() ) ? GR_XOR : GR_OR ); + if( m_DC ) + m_Target->Draw( m_Parent->GetCanvas(), m_DC, ( m_Target->IsMoving() ) ? GR_XOR : GR_OR ); m_Parent->OnModify(); EndModal( 1 ); diff --git a/pcbnew/tool_pcb.cpp b/pcbnew/tool_pcb.cpp index 6038bf41ff..ec4d07df7d 100644 --- a/pcbnew/tool_pcb.cpp +++ b/pcbnew/tool_pcb.cpp @@ -105,7 +105,7 @@ void PCB_EDIT_FRAME::PrepareLayerIndicator() previous_Route_Layer_BOTTOM_color, previous_via_color; /* get colors, and redraw bitmap button only on changes */ - active_layer_color = GetBoard()->GetLayerColor(getActiveLayer()); + active_layer_color = GetBoard()->GetLayerColor(GetActiveLayer()); if( previous_active_layer_color != active_layer_color ) { diff --git a/pcbnew/toolbars_update_user_interface.cpp b/pcbnew/toolbars_update_user_interface.cpp index a042ea072b..ac2f65a490 100644 --- a/pcbnew/toolbars_update_user_interface.cpp +++ b/pcbnew/toolbars_update_user_interface.cpp @@ -96,7 +96,7 @@ void PCB_EDIT_FRAME::OnUpdateSelectViaSize( wxUpdateUIEvent& aEvent ) void PCB_EDIT_FRAME::OnUpdateLayerSelectBox( wxUpdateUIEvent& aEvent ) { - m_SelLayerBox->SetLayerSelection( getActiveLayer() ); + m_SelLayerBox->SetLayerSelection( GetActiveLayer() ); } diff --git a/pcbnew/tools/bright_box.cpp b/pcbnew/tools/bright_box.cpp index ef76a91647..7901de2995 100644 --- a/pcbnew/tools/bright_box.cpp +++ b/pcbnew/tools/bright_box.cpp @@ -28,48 +28,34 @@ using namespace KIGFX; -const double BRIGHT_BOX::LineWidth = 100000.0; +const double BRIGHT_BOX::LINE_WIDTH = 100000.0; +const COLOR4D BRIGHT_BOX::BOX_COLOR = KIGFX::COLOR4D( 0.0, 1.0, 0.0, 1.0 ); BRIGHT_BOX::BRIGHT_BOX( BOARD_ITEM* aItem ) : EDA_ITEM( NOT_USED ), // this item is never added to a BOARD so it needs no type - item( aItem ) + m_item( aItem ) { } -const BOX2I BRIGHT_BOX::ViewBBox() const -{ - return item->ViewBBox(); -} - - -void BRIGHT_BOX::ViewGetLayers( int aLayers[], int& aCount ) const -{ - aLayers[0] = BrightBoxLayer; - aCount = 1; -} - - void BRIGHT_BOX::ViewDraw( int aLayer, GAL* aGal ) const { aGal->SetIsStroke( true ); aGal->SetIsFill( false ); - aGal->SetLineWidth( LineWidth ); - aGal->SetStrokeColor( BrightColor ); + aGal->SetLineWidth( LINE_WIDTH ); + aGal->SetStrokeColor( BOX_COLOR ); - if( item->Type() == PCB_TRACE_T ) + if( m_item->Type() == PCB_TRACE_T ) { - const TRACK* track = static_cast( item ); + const TRACK* track = static_cast( m_item ); aGal->DrawSegment( track->GetStart(), track->GetEnd(), track->GetWidth() ); } else { - BOX2I box = item->ViewBBox(); + BOX2I box = m_item->ViewBBox(); aGal->DrawRectangle( box.GetOrigin(), box.GetOrigin() + box.GetSize() ); } } - -const COLOR4D BRIGHT_BOX::BrightColor = KIGFX::COLOR4D( 0.0, 1.0, 0.0, 1.0 ); diff --git a/pcbnew/tools/bright_box.h b/pcbnew/tools/bright_box.h index b963b0409c..f75a7d0115 100644 --- a/pcbnew/tools/bright_box.h +++ b/pcbnew/tools/bright_box.h @@ -42,21 +42,28 @@ public: BRIGHT_BOX( BOARD_ITEM* aItem ); ~BRIGHT_BOX() {}; - virtual const BOX2I ViewBBox() const; + virtual const BOX2I ViewBBox() const + { + return m_item->ViewBBox(); + } void ViewDraw( int aLayer, KIGFX::GAL* aGal ) const; - void ViewGetLayers( int aLayers[], int& aCount ) const; + + void ViewGetLayers( int aLayers[], int& aCount ) const + { + aLayers[0] = ITEM_GAL_LAYER( GP_OVERLAY ); + aCount = 1; + } void Show( int x, std::ostream& st ) const { } private: - static const int BrightBoxLayer = ITEM_GAL_LAYER( GP_OVERLAY ); - static const KIGFX::COLOR4D BrightColor; - static const double LineWidth; + static const KIGFX::COLOR4D BOX_COLOR; + static const double LINE_WIDTH; - BOARD_ITEM* item; + BOARD_ITEM* m_item; }; #endif diff --git a/pcbnew/tools/common_actions.cpp b/pcbnew/tools/common_actions.cpp index f1fb3befd6..3ff65af56b 100644 --- a/pcbnew/tools/common_actions.cpp +++ b/pcbnew/tools/common_actions.cpp @@ -24,6 +24,7 @@ #include "common_actions.h" #include +#include #include // Selection tool actions @@ -41,12 +42,12 @@ TOOL_ACTION COMMON_ACTIONS::editActivate( "pcbnew.InteractiveEdit", AS_GLOBAL, 'M', "Move", "Moves the selected item(s)" ); -TOOL_ACTION COMMON_ACTIONS::rotate( "pcbnew.InteractiveEdit.rotate", - AS_CONTEXT, 'R', +TOOL_ACTION COMMON_ACTIONS::rotate( "pcbnew.rotate", + AS_GLOBAL, 'R', "Rotate", "Rotates selected item(s)" ); -TOOL_ACTION COMMON_ACTIONS::flip( "pcbnew.InteractiveEdit.flip", - AS_CONTEXT, 'F', +TOOL_ACTION COMMON_ACTIONS::flip( "pcbnew.flip", + AS_GLOBAL, 'F', "Flip", "Flips selected item(s)" ); TOOL_ACTION COMMON_ACTIONS::remove( "pcbnew.InteractiveEdit.remove", @@ -56,3 +57,239 @@ TOOL_ACTION COMMON_ACTIONS::remove( "pcbnew.InteractiveEdit.remove", TOOL_ACTION COMMON_ACTIONS::properties( "pcbnew.InteractiveEdit.properties", AS_GLOBAL, 'E', "Properties...", "Displays properties window" ); + + +// Drawing tool actions +TOOL_ACTION COMMON_ACTIONS::drawLine( "pcbnew.InteractiveDrawing.line", + AS_GLOBAL, 0, + "Draw a line", "Draw a line" ); + +TOOL_ACTION COMMON_ACTIONS::drawCircle( "pcbnew.InteractiveDrawing.circle", + AS_GLOBAL, 0, + "Draw a circle", "Draw a circle" ); + +TOOL_ACTION COMMON_ACTIONS::drawArc( "pcbnew.InteractiveDrawing.arc", + AS_GLOBAL, 0, + "Draw an arc", "Draw an arc" ); + +TOOL_ACTION COMMON_ACTIONS::placeText( "pcbnew.InteractiveDrawing.text", + AS_GLOBAL, 0, + "Add a text", "Add a text" ); + +TOOL_ACTION COMMON_ACTIONS::drawDimension( "pcbnew.InteractiveDrawing.dimension", + AS_GLOBAL, 0, + "Add a dimension", "Add a dimension" ); + +TOOL_ACTION COMMON_ACTIONS::drawZone( "pcbnew.InteractiveDrawing.zone", + AS_GLOBAL, 0, + "Add a filled zone", "Add a filled zone" ); + +TOOL_ACTION COMMON_ACTIONS::drawKeepout( "pcbnew.InteractiveDrawing.keepout", + AS_GLOBAL, 0, + "Add a keepout area", "Add a keepout area" ); + +TOOL_ACTION COMMON_ACTIONS::placeTarget( "pcbnew.InteractiveDrawing.placeTarget", + AS_GLOBAL, 0, + "Add layer alignment target", "Add layer alignment target" ); + +TOOL_ACTION COMMON_ACTIONS::placeModule( "pcbnew.InteractiveDrawing.placeModule", + AS_GLOBAL, 'O', + "Add modules", "Add modules" ); + +TOOL_ACTION COMMON_ACTIONS::routerActivate( "pcbnew.InteractiveRouter", + AS_GLOBAL, 'X', + "Run push & shove router", "Run push & shove router" ); + +TOOL_ACTION COMMON_ACTIONS::pointEditorUpdate( "pcbnew.PointEditor.update", + AS_GLOBAL, 0, "", "" ); // No description, it is not supposed to be shown anywhere + + +// View Controls +TOOL_ACTION COMMON_ACTIONS::zoomIn( "pcbnew.zoomIn", + AS_GLOBAL, WXK_F1, + "", "" ); + +TOOL_ACTION COMMON_ACTIONS::zoomOut( "pcbnew.zoomOut", + AS_GLOBAL, WXK_F2, + "", "" ); + +TOOL_ACTION COMMON_ACTIONS::zoomInCenter( "pcbnew.zoomInCenter", + AS_GLOBAL, 0, + "", "" ); + +TOOL_ACTION COMMON_ACTIONS::zoomOutCenter( "pcbnew.zoomOutCenter", + AS_GLOBAL, 0, + "", "" ); + +TOOL_ACTION COMMON_ACTIONS::zoomCenter( "pcbnew.zoomCenter", + AS_GLOBAL, WXK_F4, + "", "" ); + +TOOL_ACTION COMMON_ACTIONS::zoomFitScreen( "pcbnew.zoomFitScreen", + AS_GLOBAL, WXK_HOME, + "", "" ); + + +// Display modes +TOOL_ACTION COMMON_ACTIONS::trackDisplayMode( "pcbnew.trackDisplayMode", + AS_GLOBAL, 'K', + "", "" ); + +TOOL_ACTION COMMON_ACTIONS::padDisplayMode( "pcbnew.padDisplayMode", + AS_GLOBAL, 'J', // TODO temporarily, find a better hot key + "", "" ); + +TOOL_ACTION COMMON_ACTIONS::viaDisplayMode( "pcbnew.viaDisplayMode", + AS_GLOBAL, 'L', // TODO temporarily, find a better hot key + "", "" ); + +TOOL_ACTION COMMON_ACTIONS::highContrastMode( "pcbnew.highContrastMode", + AS_GLOBAL, 'H', + "", "" ); + +TOOL_ACTION COMMON_ACTIONS::highContrastInc( "pcbnew.highContrastInc", + AS_GLOBAL, '>', + "", "" ); + +TOOL_ACTION COMMON_ACTIONS::highContrastDec( "pcbnew.highContrastDec", + AS_GLOBAL, '<', + "", "" ); + + +// Layer control +TOOL_ACTION COMMON_ACTIONS::layerTop( "pcbnew.layerTop", + AS_GLOBAL, WXK_PAGEUP, + "", "" ); + +TOOL_ACTION COMMON_ACTIONS::layerInner1( "pcbnew.layerInner1", + AS_GLOBAL, WXK_F5, + "", "" ); + +TOOL_ACTION COMMON_ACTIONS::layerInner2( "pcbnew.layerInner2", + AS_GLOBAL, WXK_F6, + "", "" ); + +TOOL_ACTION COMMON_ACTIONS::layerInner3( "pcbnew.layerInner3", + AS_GLOBAL, WXK_F7, + "", "" ); + +TOOL_ACTION COMMON_ACTIONS::layerInner4( "pcbnew.layerInner4", + AS_GLOBAL, WXK_F8, + "", "" ); + +TOOL_ACTION COMMON_ACTIONS::layerInner5( "pcbnew.layerInner5", + AS_GLOBAL, WXK_F9, + "", "" ); + +TOOL_ACTION COMMON_ACTIONS::layerInner6( "pcbnew.layerInner6", + AS_GLOBAL, WXK_F10, + "", "" ); + +TOOL_ACTION COMMON_ACTIONS::layerBottom( "pcbnew.layerBottom", + AS_GLOBAL, WXK_PAGEDOWN, + "", "" ); + +TOOL_ACTION COMMON_ACTIONS::layerNext( "pcbnew.layerNext", + AS_GLOBAL, '=', + "", "" ); + +TOOL_ACTION COMMON_ACTIONS::layerPrev( "pcbnew.layerPrev", + AS_GLOBAL, '-', + "", "" ); + +TOOL_ACTION COMMON_ACTIONS::layerAlphaInc( "pcbnew.layerAlphaInc", + AS_GLOBAL, '}', + "", "" ); + +TOOL_ACTION COMMON_ACTIONS::layerAlphaDec( "pcbnew.layerAlphaDec", + AS_GLOBAL, '{', + "", "" ); + + +// Grid control +TOOL_ACTION COMMON_ACTIONS::gridFast1( "pcbnew.gridFast1", + AS_GLOBAL, MD_ALT + '1', + "", "" ); + +TOOL_ACTION COMMON_ACTIONS::gridFast2( "pcbnew.gridFast2", + AS_GLOBAL, MD_ALT + '2', + "", "" ); + +TOOL_ACTION COMMON_ACTIONS::gridNext( "pcbnew.gridNext", + AS_GLOBAL, '`', + "", "" ); + +TOOL_ACTION COMMON_ACTIONS::gridPrev( "pcbnew.gridPrev", + AS_GLOBAL, MD_CTRL + '`', + "", "" ); + + +// Track & via size control +TOOL_ACTION COMMON_ACTIONS::trackWidthInc( "pcbnew.trackWidthInc", + AS_GLOBAL, '[', + "", "" ); + +TOOL_ACTION COMMON_ACTIONS::trackWidthDec( "pcbnew.trackWidthDec", + AS_GLOBAL, ']', + "", "" ); + +TOOL_ACTION COMMON_ACTIONS::viaSizeInc( "pcbnew.viaSizeInc", + AS_GLOBAL, '\'', + "", "" ); + +TOOL_ACTION COMMON_ACTIONS::viaSizeDec( "pcbnew.viaSizeDec", + AS_GLOBAL, '\\', + "", "" ); + + +// Miscellaneous +TOOL_ACTION COMMON_ACTIONS::resetCoords( "pcbnew.resetCoords", + AS_GLOBAL, ' ', + "", "" ); + +TOOL_ACTION COMMON_ACTIONS::switchUnits( "pcbnew.switchUnits", + AS_GLOBAL, MD_CTRL + 'U', + "", "" ); + +TOOL_ACTION COMMON_ACTIONS::showHelp( "pcbnew.showHelp", + AS_GLOBAL, '?', + "", "" ); + + +std::string COMMON_ACTIONS::TranslateLegacyId( int aId ) +{ + switch( aId ) + { + case ID_PCB_MODULE_BUTT: + return COMMON_ACTIONS::placeModule.GetName(); + + case ID_TRACK_BUTT: + return COMMON_ACTIONS::routerActivate.GetName(); + + case ID_PCB_ZONES_BUTT: + return COMMON_ACTIONS::drawZone.GetName(); + + case ID_PCB_KEEPOUT_AREA_BUTT: + return COMMON_ACTIONS::drawKeepout.GetName(); + + case ID_PCB_ADD_LINE_BUTT: + return COMMON_ACTIONS::drawLine.GetName(); + + case ID_PCB_CIRCLE_BUTT: + return COMMON_ACTIONS::drawCircle.GetName(); + + case ID_PCB_ARC_BUTT: + return COMMON_ACTIONS::drawArc.GetName(); + + case ID_PCB_ADD_TEXT_BUTT: + return COMMON_ACTIONS::placeText.GetName(); + + case ID_PCB_DIMENSION_BUTT: + return COMMON_ACTIONS::drawDimension.GetName(); + + case ID_PCB_MIRE_BUTT: + return COMMON_ACTIONS::placeTarget.GetName(); + } + + return ""; +} diff --git a/pcbnew/tools/common_actions.h b/pcbnew/tools/common_actions.h index 86aafe5894..38569af29a 100644 --- a/pcbnew/tools/common_actions.h +++ b/pcbnew/tools/common_actions.h @@ -33,6 +33,7 @@ class COMMON_ACTIONS { public: + // Selection Tool /// Activation of the selection tool static TOOL_ACTION selectionActivate; @@ -42,6 +43,7 @@ public: /// Clears the current selection static TOOL_ACTION selectionClear; + // Edit Tool /// Activation of the edit tool static TOOL_ACTION editActivate; @@ -56,4 +58,96 @@ public: /// Deleting a BOARD_ITEM static TOOL_ACTION remove; + + // Drawing Tool + /// Activation of the drawing tool (line) + static TOOL_ACTION drawLine; + + /// Activation of the drawing tool (circle) + static TOOL_ACTION drawCircle; + + /// Activation of the drawing tool (arc) + static TOOL_ACTION drawArc; + + /// Activation of the drawing tool (text) + static TOOL_ACTION placeText; + + /// Activation of the drawing tool (dimension) + static TOOL_ACTION drawDimension; + + /// Activation of the drawing tool (drawing a ZONE) + static TOOL_ACTION drawZone; + + /// Activation of the drawing tool (drawing a keepout area) + static TOOL_ACTION drawKeepout; + + /// Activation of the drawing tool (placing a TARGET) + static TOOL_ACTION placeTarget; + + /// Activation of the drawing tool (placing a MODULE) + static TOOL_ACTION placeModule; + + // Push and Shove Router Tool + /// Activation of the Push and Shove router + static TOOL_ACTION routerActivate; + + // Point Editor + /// Update edit points + static TOOL_ACTION pointEditorUpdate; + + // View controls + static TOOL_ACTION zoomIn; + static TOOL_ACTION zoomOut; + static TOOL_ACTION zoomInCenter; + static TOOL_ACTION zoomOutCenter; + static TOOL_ACTION zoomCenter; + static TOOL_ACTION zoomFitScreen; + + // Display modes + static TOOL_ACTION trackDisplayMode; + static TOOL_ACTION padDisplayMode; + static TOOL_ACTION viaDisplayMode; + static TOOL_ACTION highContrastMode; + static TOOL_ACTION highContrastInc; + static TOOL_ACTION highContrastDec; + + // Layer control + static TOOL_ACTION layerTop; + static TOOL_ACTION layerInner1; + static TOOL_ACTION layerInner2; + static TOOL_ACTION layerInner3; + static TOOL_ACTION layerInner4; + static TOOL_ACTION layerInner5; + static TOOL_ACTION layerInner6; + static TOOL_ACTION layerBottom; + static TOOL_ACTION layerNext; + static TOOL_ACTION layerPrev; + static TOOL_ACTION layerAlphaInc; + static TOOL_ACTION layerAlphaDec; + + // Grid control + static TOOL_ACTION gridFast1; + static TOOL_ACTION gridFast2; + static TOOL_ACTION gridNext; + static TOOL_ACTION gridPrev; + + // Track & via size control + static TOOL_ACTION trackWidthInc; + static TOOL_ACTION trackWidthDec; + static TOOL_ACTION viaSizeInc; + static TOOL_ACTION viaSizeDec; + + // Miscellaneous + static TOOL_ACTION resetCoords; + static TOOL_ACTION switchUnits; + static TOOL_ACTION showHelp; + + /** + * Function TranslateLegacyId() + * Translates legacy tool ids to the corresponding TOOL_ACTION name. + * @param aId is legacy tool id to be translated. + * @return std::string is name of the corresponding TOOL_ACTION. It may be empty, if there is + * no corresponding TOOL_ACTION. + */ + static std::string TranslateLegacyId( int aId ); }; diff --git a/pcbnew/tools/drawing_tool.cpp b/pcbnew/tools/drawing_tool.cpp new file mode 100644 index 0000000000..c9a5467583 --- /dev/null +++ b/pcbnew/tools/drawing_tool.cpp @@ -0,0 +1,1183 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014 CERN + * @author Maciej Suminski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include "drawing_tool.h" +#include "common_actions.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +DRAWING_TOOL::DRAWING_TOOL() : + TOOL_INTERACTIVE( "pcbnew.InteractiveDrawing" ) +{ +} + + +DRAWING_TOOL::~DRAWING_TOOL() +{ +} + + +void DRAWING_TOOL::Reset( RESET_REASON aReason ) +{ + // Init variables used by every drawing tool + m_view = getView(); + m_controls = getViewControls(); + m_board = getModel( PCB_T ); + m_frame = getEditFrame(); + + setTransitions(); +} + + +int DRAWING_TOOL::DrawLine( TOOL_EVENT& aEvent ) +{ + m_frame->SetToolID( ID_PCB_ADD_LINE_BUTT, wxCURSOR_PENCIL, _( "Add graphic line" ) ); + + return drawSegment( S_SEGMENT, true ); +} + + +int DRAWING_TOOL::DrawCircle( TOOL_EVENT& aEvent ) +{ + m_frame->SetToolID( ID_PCB_CIRCLE_BUTT, wxCURSOR_PENCIL, _( "Add graphic circle" ) ); + + return drawSegment( S_CIRCLE, false ); +} + + +int DRAWING_TOOL::DrawArc( TOOL_EVENT& aEvent ) +{ + bool clockwise = true; // drawing direction of the arc + double startAngle = 0.0f; // angle of the first arc line + VECTOR2I cursorPos = m_controls->GetCursorPosition(); + + DRAWSEGMENT* arc = NULL; + DRAWSEGMENT helperLine; + helperLine.SetShape( S_SEGMENT ); + helperLine.SetLayer( DRAW_N ); + helperLine.SetWidth( 1 ); + + // 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 ); + m_controls->ShowCursor( true ); + m_controls->SetSnapping( true ); + + Activate(); + m_frame->SetToolID( ID_PCB_ARC_BUTT, wxCURSOR_PENCIL, _( "Add graphic arc" ) ); + + enum ARC_STEPS + { + SET_ORIGIN = 0, + SET_END, + SET_ANGLE, + FINISHED + }; + int step = SET_ORIGIN; + + // Main loop: keep receiving events + while( OPT_TOOL_EVENT evt = Wait() ) + { + cursorPos = m_controls->GetCursorPosition(); + + if( evt->IsCancel() ) + { + if( step != SET_ORIGIN ) // start from the beginning + { + preview.Clear(); + preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + + delete arc; + step = SET_ORIGIN; + } + else + break; + } + + else if( evt->IsKeyPressed() && step != SET_ORIGIN ) + { + int width = arc->GetWidth(); + + // Modify the new item width + if( evt->KeyCode() == '-' && width > WIDTH_STEP ) + arc->SetWidth( width - WIDTH_STEP ); + else if( evt->KeyCode() == '=' ) + arc->SetWidth( width + WIDTH_STEP ); + else if( evt->KeyCode() == '/' ) + { + if( clockwise ) + arc->SetAngle( arc->GetAngle() - 3600.0 ); + else + arc->SetAngle( arc->GetAngle() + 3600.0 ); + + clockwise = !clockwise; + } + + preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + } + + else if( evt->IsClick( BUT_LEFT ) ) + { + switch( step ) + { + case SET_ORIGIN: + { + LAYER_NUM layer = m_frame->GetScreen()->m_Active_Layer; + + if( IsCopperLayer( layer ) ) + { + DisplayInfoMessage( NULL, _( "Graphic not allowed on Copper layers" ) ); + --step; + } + else + { + // Init the new item attributes + arc = new DRAWSEGMENT( m_board ); + arc->SetShape( S_ARC ); + arc->SetAngle( 0.0 ); + arc->SetWidth( m_board->GetDesignSettings().m_DrawSegmentWidth ); + arc->SetCenter( wxPoint( cursorPos.x, cursorPos.y ) ); + arc->SetLayer( layer ); + + helperLine.SetStart( arc->GetCenter() ); + helperLine.SetEnd( arc->GetCenter() ); + + preview.Add( arc ); + preview.Add( &helperLine ); + + m_controls->SetAutoPan( true ); + } + } + break; + + case SET_END: + { + if( wxPoint( cursorPos.x, cursorPos.y ) != arc->GetCenter() ) + { + VECTOR2D startLine( arc->GetArcStart() - arc->GetCenter() ); + startAngle = startLine.Angle(); + arc->SetArcStart( wxPoint( cursorPos.x, cursorPos.y ) ); + } + else + --step; // one another chance to draw a proper arc + + } + break; + + case SET_ANGLE: + { + if( wxPoint( cursorPos.x, cursorPos.y ) != arc->GetArcStart() ) + { + assert( arc->GetAngle() != 0 ); + assert( arc->GetArcStart() != arc->GetArcEnd() ); + assert( arc->GetWidth() > 0 ); + + m_view->Add( arc ); + m_board->Add( arc ); + arc->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + + m_frame->OnModify(); + m_frame->SaveCopyInUndoList( arc, UR_NEW ); + + preview.Remove( arc ); + preview.Remove( &helperLine ); + } + else + --step; // one another chance to draw a proper arc + } + break; + } + + if( ++step == FINISHED ) + { + step = SET_ORIGIN; + m_controls->SetAutoPan( false ); + } + } + + else if( evt->IsMotion() ) + { + switch( step ) + { + case SET_END: + helperLine.SetEnd( wxPoint( cursorPos.x, cursorPos.y ) ); + arc->SetArcStart( wxPoint( cursorPos.x, cursorPos.y ) ); + break; + + case SET_ANGLE: + { + VECTOR2D endLine( wxPoint( cursorPos.x, cursorPos.y ) - arc->GetCenter() ); + double newAngle = RAD2DECIDEG( endLine.Angle() - startAngle ); + + // Adjust the new angle to (counter)clockwise setting + if( clockwise && newAngle < 0.0 ) + newAngle += 3600.0; + else if( !clockwise && newAngle > 0.0 ) + newAngle -= 3600.0; + + arc->SetAngle( newAngle ); + } + break; + } + + // Show a preview of the item + preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + } + } + + m_controls->ShowCursor( false ); + m_controls->SetSnapping( false ); + m_controls->SetAutoPan( false ); + m_view->Remove( &preview ); + + setTransitions(); + m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString ); + + return 0; +} + + +int DRAWING_TOOL::PlaceText( TOOL_EVENT& aEvent ) +{ + TEXTE_PCB* text = NULL; + + // 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 ); + m_controls->ShowCursor( true ); + m_controls->SetSnapping( true ); + m_controls->SetAutoPan( true ); + + Activate(); + m_frame->SetToolID( ID_PCB_ADD_TEXT_BUTT, wxCURSOR_PENCIL, _( "Add text" ) ); + + // Main loop: keep receiving events + while( OPT_TOOL_EVENT evt = Wait() ) + { + VECTOR2I cursorPos = m_controls->GetCursorPosition(); + + if( evt->IsCancel() ) + { + if( text ) + { + // Delete the old text and have another try + m_board->Delete( text ); // it was already added by CreateTextPcb() + text = NULL; + + preview.Clear(); + preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + m_controls->ShowCursor( true ); + } + else + break; + } + + else if( text && evt->Category() == TC_COMMAND ) + { + if( evt->IsAction( &COMMON_ACTIONS::rotate ) ) + { + text->Rotate( text->GetPosition(), m_frame->GetRotationAngle() ); + preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + } + else if( evt->IsAction( &COMMON_ACTIONS::flip ) ) + { + text->Flip( text->GetPosition() ); + preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + } + } + + else if( evt->IsClick( BUT_LEFT ) ) + { + if( !text ) + { + // Init the new item attributes + text = m_frame->CreateTextePcb( NULL ); + + if( text == NULL ) + continue; + + m_controls->ShowCursor( false ); + preview.Add( text ); + } + else + { + assert( text->GetText().Length() > 0 ); + assert( text->GetSize().x > 0 && text->GetSize().y > 0 ); + + text->ClearFlags(); + m_view->Add( text ); + // m_board->Add( text ); // it is already added by CreateTextePcb() + text->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + + m_frame->OnModify(); + m_frame->SaveCopyInUndoList( text, UR_NEW ); + + preview.Remove( text ); + m_controls->ShowCursor( true ); + + text = NULL; + } + } + + else if( text && evt->IsMotion() ) + { + text->SetTextPosition( wxPoint( cursorPos.x, cursorPos.y ) ); + + // Show a preview of the item + preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + } + } + + m_controls->ShowCursor( false ); + m_controls->SetSnapping( false ); + m_controls->SetAutoPan( false ); + m_view->Remove( &preview ); + + setTransitions(); + m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString ); + + return 0; +} + + +int DRAWING_TOOL::DrawDimension( TOOL_EVENT& aEvent ) +{ + DIMENSION* dimension = NULL; + int width, maxThickness; + + // 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 ); + m_controls->ShowCursor( true ); + m_controls->SetSnapping( true ); + + Activate(); + m_frame->SetToolID( ID_PCB_DIMENSION_BUTT, wxCURSOR_PENCIL, _( "Add dimension" ) ); + + enum DIMENSION_STEPS + { + SET_ORIGIN = 0, + SET_END, + SET_HEIGHT, + FINISHED + }; + int step = SET_ORIGIN; + + // Main loop: keep receiving events + while( OPT_TOOL_EVENT evt = Wait() ) + { + VECTOR2I cursorPos = m_controls->GetCursorPosition(); + + if( evt->IsCancel() ) + { + if( step != SET_ORIGIN ) // start from the beginning + { + preview.Clear(); + preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + + delete dimension; + step = SET_ORIGIN; + } + else + break; + } + + else if( evt->IsKeyPressed() && step != SET_ORIGIN ) + { + width = dimension->GetWidth(); + + // Modify the new item width + if( evt->KeyCode() == '-' && width > WIDTH_STEP ) + dimension->SetWidth( width - WIDTH_STEP ); + else if( evt->KeyCode() == '=' ) + dimension->SetWidth( width + WIDTH_STEP ); + + preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + } + + else if( evt->IsClick( BUT_LEFT ) ) + { + switch( step ) + { + case SET_ORIGIN: + { + LAYER_NUM layer = m_frame->GetScreen()->m_Active_Layer; + + if( IsCopperLayer( layer ) || layer == EDGE_N ) + { + DisplayInfoMessage( NULL, _( "Dimension not allowed on Copper or Edge Cut layers" ) ); + --step; + } + else + { + // Init the new item attributes + dimension = new DIMENSION( m_board ); + dimension->SetLayer( layer ); + dimension->SetOrigin( wxPoint( cursorPos.x, cursorPos.y ) ); + dimension->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) ); + dimension->Text().SetSize( m_board->GetDesignSettings().m_PcbTextSize ); + + width = m_board->GetDesignSettings().m_PcbTextWidth; + maxThickness = Clamp_Text_PenSize( width, dimension->Text().GetSize() ); + + if( width > maxThickness ) + width = maxThickness; + + dimension->Text().SetThickness( width ); + dimension->SetWidth( width ); + dimension->AdjustDimensionDetails(); + + preview.Add( dimension ); + + m_controls->SetAutoPan( true ); + } + } + break; + + case SET_END: + dimension->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) ); + + // Dimensions that have origin and end in the same spot are not valid + if( dimension->GetOrigin() == dimension->GetEnd() ) + --step; + break; + + case SET_HEIGHT: + { + if( wxPoint( cursorPos.x, cursorPos.y ) != dimension->GetPosition() ) + { + assert( dimension->GetOrigin() != dimension->GetEnd() ); + assert( dimension->GetWidth() > 0 ); + + m_view->Add( dimension ); + m_board->Add( dimension ); + dimension->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + + m_frame->OnModify(); + m_frame->SaveCopyInUndoList( dimension, UR_NEW ); + + preview.Remove( dimension ); + } + } + break; + } + + if( ++step == FINISHED ) + { + step = SET_ORIGIN; + m_controls->SetAutoPan( false ); + } + } + + else if( evt->IsMotion() ) + { + switch( step ) + { + case SET_END: + dimension->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) ); + break; + + case SET_HEIGHT: + { + // Calculating the direction of travel perpendicular to the selected axis + double angle = dimension->GetAngle() + ( M_PI / 2 ); + + wxPoint pos( cursorPos.x, cursorPos.y ); + wxPoint delta( pos - dimension->m_featureLineDO ); + double height = ( delta.x * cos( angle ) ) + ( delta.y * sin( angle ) ); + dimension->SetHeight( height ); + } + break; + } + + // Show a preview of the item + preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + } + } + + if( step != SET_ORIGIN ) + delete dimension; + + m_controls->ShowCursor( false ); + m_controls->SetSnapping( false ); + m_controls->SetAutoPan( false ); + m_view->Remove( &preview ); + + setTransitions(); + m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString ); + + return 0; +} + + +int DRAWING_TOOL::DrawZone( TOOL_EVENT& aEvent ) +{ + m_frame->SetToolID( ID_PCB_ZONES_BUTT, wxCURSOR_PENCIL, _( "Add zones" ) ); + + return drawZone( false ); +} + + +int DRAWING_TOOL::DrawKeepout( TOOL_EVENT& aEvent ) +{ + m_frame->SetToolID( ID_PCB_KEEPOUT_AREA_BUTT, wxCURSOR_PENCIL, _( "Add keepout" ) ); + + return drawZone( true ); +} + + +int DRAWING_TOOL::PlaceTarget( TOOL_EVENT& aEvent ) +{ + PCB_TARGET* target = new PCB_TARGET( m_board ); + + // Init the new item attributes + target->SetLayer( EDGE_N ); + target->SetWidth( m_board->GetDesignSettings().m_EdgeSegmentWidth ); + target->SetSize( Millimeter2iu( 5 ) ); + VECTOR2I cursorPos = m_controls->GetCursorPosition(); + target->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) ); + + // Add a VIEW_GROUP that serves as a preview for the new item + KIGFX::VIEW_GROUP preview( m_view ); + preview.Add( target ); + m_view->Add( &preview ); + preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + + m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear ); + m_controls->SetSnapping( true ); + m_controls->SetAutoPan( true ); + + Activate(); + m_frame->SetToolID( ID_PCB_MIRE_BUTT, wxCURSOR_PENCIL, _( "Add layer alignment target" ) ); + + // Main loop: keep receiving events + while( OPT_TOOL_EVENT evt = Wait() ) + { + cursorPos = m_controls->GetCursorPosition(); + + if( evt->IsCancel() ) + break; + + else if( evt->IsKeyPressed() ) + { + int width = target->GetWidth(); + + // Modify the new item width + if( evt->KeyCode() == '-' && width > WIDTH_STEP ) + target->SetWidth( width - WIDTH_STEP ); + else if( evt->KeyCode() == '=' ) + target->SetWidth( width + WIDTH_STEP ); + + preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + } + + else if( evt->IsClick( BUT_LEFT ) ) + { + assert( target->GetSize() > 0 ); + assert( target->GetWidth() > 0 ); + + m_view->Add( target ); + m_board->Add( target ); + target->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + + m_frame->OnModify(); + m_frame->SaveCopyInUndoList( target, UR_NEW ); + + preview.Remove( target ); + + // Create next PCB_TARGET + target = new PCB_TARGET( *target ); + preview.Add( target ); + } + + else if( evt->IsMotion() ) + { + target->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) ); + preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + } + } + + delete target; + + m_controls->SetSnapping( false ); + m_controls->SetAutoPan( false ); + m_view->Remove( &preview ); + + setTransitions(); + m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString ); + + return 0; +} + + +int DRAWING_TOOL::PlaceModule( TOOL_EVENT& aEvent ) +{ + MODULE* module = NULL; + + // 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 ); + m_controls->ShowCursor( true ); + m_controls->SetSnapping( true ); + m_controls->SetAutoPan( true ); + + Activate(); + m_frame->SetToolID( ID_PCB_MODULE_BUTT, wxCURSOR_HAND, _( "Add module" ) ); + + // Main loop: keep receiving events + while( OPT_TOOL_EVENT evt = Wait() ) + { + VECTOR2I cursorPos = m_controls->GetCursorPosition(); + + if( evt->IsCancel() ) + { + if( module ) + { + m_board->Delete( module ); // it was added by LoadModuleFromLibrary() + module = NULL; + + preview.Clear(); + preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + m_controls->ShowCursor( true ); + } + else + break; + } + + else if( module && evt->Category() == TC_COMMAND ) + { + if( evt->IsAction( &COMMON_ACTIONS::rotate ) ) + { + module->Rotate( module->GetPosition(), m_frame->GetRotationAngle() ); + preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + } + else if( evt->IsAction( &COMMON_ACTIONS::flip ) ) + { + module->Flip( module->GetPosition() ); + preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + } + } + + else if( evt->IsClick( BUT_LEFT ) ) + { + if( !module ) + { + // Init the new item attributes + module = m_frame->LoadModuleFromLibrary( wxEmptyString, + m_frame->Prj().PcbFootprintLibs(), + true, NULL ); + if( module == NULL ) + continue; + + m_controls->ShowCursor( false ); + module->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) ); + + // Add all the drawable parts to preview + preview.Add( module ); + module->RunOnChildren( boost::bind( &KIGFX::VIEW_GROUP::Add, &preview, _1 ) ); + + preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + } + else + { + module->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, m_view, _1 ) ); + m_view->Add( module ); + module->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + + m_frame->OnModify(); + m_frame->SaveCopyInUndoList( module, UR_NEW ); + + // Remove from preview + preview.Remove( module ); + module->RunOnChildren( boost::bind( &KIGFX::VIEW_GROUP::Remove, &preview, _1 ) ); + module = NULL; // to indicate that there is no module that we currently modify + + m_controls->ShowCursor( true ); + } + } + + else if( module && evt->IsMotion() ) + { + module->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) ); + preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + } + } + + m_controls->ShowCursor( false ); + m_controls->SetSnapping( false ); + m_controls->SetAutoPan( false ); + m_view->Remove( &preview ); + + setTransitions(); + m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString ); + + return 0; +} + + +int DRAWING_TOOL::drawSegment( int aShape, bool aContinous ) +{ + // Only two shapes are currently supported + assert( aShape == S_SEGMENT || aShape == S_CIRCLE ); + + DRAWSEGMENT* graphic = NULL; + 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 ); + m_controls->ShowCursor( true ); + m_controls->SetSnapping( true ); + + Activate(); + + bool direction45 = false; // 45 degrees only mode + int addedSegments = 0; + + // 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 ) && graphic && aShape == S_SEGMENT ) + { + direction45 = evt->Modifier( MD_CTRL ); + + if( direction45 ) + { + preview.Add( &line45 ); + make45DegLine( graphic, &line45 ); + } + else + { + preview.Remove( &line45 ); + graphic->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) ); + } + + updatePreview = true; + } + + if( evt->IsCancel() ) + { + if( !graphic ) + break; + + preview.Clear(); + updatePreview = true; + + delete graphic; + graphic = NULL; + + m_controls->SetAutoPan( false ); + } + + else if( graphic && evt->IsKeyPressed() ) + { + int width = graphic->GetWidth(); + + // Modify the new item width + if( evt->KeyCode() == '-' && width > WIDTH_STEP ) + graphic->SetWidth( width - WIDTH_STEP ); + else if( evt->KeyCode() == '=' ) + graphic->SetWidth( width + WIDTH_STEP ); + + updatePreview = true; + } + + else if( evt->IsClick( BUT_LEFT ) ) + { + if( !graphic ) + { + LAYER_NUM layer = m_frame->GetScreen()->m_Active_Layer; + + if( IsCopperLayer( layer ) ) + { + DisplayInfoMessage( NULL, _( "Graphic not allowed on Copper layers" ) ); + } + else + { + // Init the new item attributes + graphic = new DRAWSEGMENT( m_board ); + graphic->SetShape( (STROKE_T) aShape ); + graphic->SetWidth( m_board->GetDesignSettings().m_DrawSegmentWidth ); + graphic->SetStart( wxPoint( cursorPos.x, cursorPos.y ) ); + graphic->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) ); + graphic->SetLayer( layer ); + + if( aShape == S_SEGMENT ) + { + line45 = *graphic; // used only for direction 45 mode with lines + line45.SetLayer( layer ); + } + + preview.Add( graphic ); + m_controls->SetAutoPan( true ); + } + } + else + { + if( graphic->GetEnd() != graphic->GetStart() ) + { + assert( graphic->GetLength() > 0 ); + assert( graphic->GetWidth() > 0 ); + + m_view->Add( graphic ); + m_board->Add( graphic ); + graphic->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + + m_frame->OnModify(); + m_frame->SaveCopyInUndoList( graphic, UR_NEW ); + + preview.Remove( graphic ); + ++addedSegments; + + if( aContinous ) + { + graphic = new DRAWSEGMENT( *graphic ); + + // Start the new line in the same spot where the previous one has ended + graphic->SetStart( graphic->GetEnd() ); + + if( direction45 ) + graphic->SetEnd( line45.GetEnd() ); + + preview.Add( graphic ); + } + else // start a new graphic + { + addedSegments = 0; + m_controls->SetAutoPan( false ); + graphic = NULL; + } + } + else if( addedSegments > 0 ) // User has clicked twice in the same spot + { // a clear sign that the current drawing is finished + preview.Clear(); // but only if at least one graphic was created + // otherwise - force user to draw more or cancel + delete graphic; + graphic = NULL; + + m_controls->SetAutoPan( false ); + } + } + } + + else if( graphic && evt->IsMotion() ) + { + // 45 degree lines + if( direction45 && aShape == S_SEGMENT ) + make45DegLine( graphic, &line45 ); + else + graphic->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) ); + + updatePreview = true; + } + + if( updatePreview ) + preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + } + + m_controls->ShowCursor( false ); + m_controls->SetSnapping( false ); + m_controls->SetAutoPan( false ); + m_view->Remove( &preview ); + + setTransitions(); + m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString ); + + return 0; +} + + +int DRAWING_TOOL::drawZone( bool aKeepout ) +{ + ZONE_CONTAINER* zone = NULL; + DRAWSEGMENT line45; + DRAWSEGMENT* helperLine = NULL; // we will need more than one helper line + + // 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 ); + m_controls->ShowCursor( true ); + m_controls->SetSnapping( true ); + + Activate(); + + VECTOR2I lastCursorPos = m_controls->GetCursorPosition(); + 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() ) + { + if( numPoints > 0 ) // cancel the current zone + { + delete zone; + zone = NULL; + m_controls->SetAutoPan( 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; + } + + else if( evt->IsClick( BUT_LEFT ) ) + { + // Check if it is double click / closing line (so we have to finish the zone) + if( lastCursorPos == cursorPos || ( numPoints > 0 && cursorPos == origin ) ) + { + if( numPoints > 2 ) // valid zone consists of more than 2 points + { + assert( zone->GetNumCorners() > 2 ); + + // Finish the zone + zone->Outline()->CloseLastContour(); + zone->Outline()->RemoveNullSegments(); + + m_board->Add( zone ); + m_view->Add( zone ); + + if( !aKeepout ) + m_frame->Fill_Zone( zone ); + + zone->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + + m_frame->OnModify(); + m_frame->SaveCopyInUndoList( zone, UR_NEW ); + + zone = NULL; + } + else + { + delete zone; + zone = NULL; + } + + numPoints = 0; + m_controls->SetAutoPan( 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 ); + + // 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 ); + continue; + } + + // Apply the selected settings + zone = new ZONE_CONTAINER( m_board ); + zoneInfo.ExportSetting( *zone ); + m_frame->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; + } + + lastCursorPos = cursorPos; + } + + 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_view->Remove( &preview ); + + setTransitions(); + m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString ); + + return 0; +} + + +void DRAWING_TOOL::make45DegLine( DRAWSEGMENT* aSegment, DRAWSEGMENT* aHelper ) const +{ + VECTOR2I cursorPos = m_controls->GetCursorPosition(); + VECTOR2I origin( aSegment->GetStart() ); + DIRECTION_45 direction( origin - cursorPos ); + SHAPE_LINE_CHAIN newChain = direction.BuildInitialTrace( origin, cursorPos ); + + if( newChain.PointCount() > 2 ) + { + aSegment->SetEnd( wxPoint( newChain.Point( -2 ).x, newChain.Point( -2 ).y ) ); + aHelper->SetStart( wxPoint( newChain.Point( -2 ).x, newChain.Point( -2 ).y ) ); + aHelper->SetEnd( wxPoint( newChain.Point( -1 ).x, newChain.Point( -1 ).y ) ); + } + else + { + aSegment->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) ); + aHelper->SetStart( wxPoint( cursorPos.x, cursorPos.y ) ); + aHelper->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) ); + } +} + + +void DRAWING_TOOL::setTransitions() +{ + Go( &DRAWING_TOOL::DrawLine, COMMON_ACTIONS::drawLine.MakeEvent() ); + Go( &DRAWING_TOOL::DrawCircle, COMMON_ACTIONS::drawCircle.MakeEvent() ); + Go( &DRAWING_TOOL::DrawArc, COMMON_ACTIONS::drawArc.MakeEvent() ); + Go( &DRAWING_TOOL::DrawDimension, COMMON_ACTIONS::drawDimension.MakeEvent() ); + Go( &DRAWING_TOOL::DrawZone, COMMON_ACTIONS::drawZone.MakeEvent() ); + Go( &DRAWING_TOOL::DrawKeepout, COMMON_ACTIONS::drawKeepout.MakeEvent() ); + Go( &DRAWING_TOOL::PlaceText, COMMON_ACTIONS::placeText.MakeEvent() ); + Go( &DRAWING_TOOL::PlaceTarget, COMMON_ACTIONS::placeTarget.MakeEvent() ); + Go( &DRAWING_TOOL::PlaceModule, COMMON_ACTIONS::placeModule.MakeEvent() ); +} diff --git a/pcbnew/tools/drawing_tool.h b/pcbnew/tools/drawing_tool.h new file mode 100644 index 0000000000..e05a3a59ce --- /dev/null +++ b/pcbnew/tools/drawing_tool.h @@ -0,0 +1,152 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014 CERN + * @author Maciej Suminski + * + * 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 + */ + +#ifndef __DRAWING_TOOL_H +#define __DRAWING_TOOL_H + +#include + +namespace KIGFX +{ + class VIEW; + class VIEW_CONTROLS; +} +class BOARD; +class PCB_EDIT_FRAME; +class DRAWSEGMENT; + +/** + * Class DRAWING_TOOL + * + * Tool responsible for drawing graphical elements like lines, arcs, circles, etc. + */ + +class DRAWING_TOOL : public TOOL_INTERACTIVE +{ +public: + DRAWING_TOOL(); + ~DRAWING_TOOL(); + + /// @copydoc TOOL_INTERACTIVE::Reset() + void Reset( RESET_REASON aReason ); + + /** + * Function DrawLine() + * Starts interactively drawing a line. After invoking the function it expects the user + * to click at least two times to determine the origin and the end for a line. If there are + * more clicks, the line is drawn as a continous polyline. + */ + int DrawLine( TOOL_EVENT& aEvent ); + + /** + * Function DrawCircle() + * Starts interactively drawing a circle. After invoking the function it expects the user + * to first click on a point that is going to be used as the center of the circle. The second + * click determines the circle radius. + */ + int DrawCircle( TOOL_EVENT& aEvent ); + + /** + * Function DrawArc() + * Starts interactively drawing an arc. After invoking the function it expects the user + * to first click on a point that is going to be used as the center of the arc. The second + * click determines the origin and radius, the third one - the angle. + */ + int DrawArc( TOOL_EVENT& aEvent ); + + /** + * Function DrawText() + * Displays a dialog that allows to input text and its settings and then lets the user decide + * where to place the text. + */ + int PlaceText( TOOL_EVENT& aEvent ); + + /** + * Function DrawDimension() + * Starts interactively drawing a dimension. After invoking the function it expects the user + * to first click on a point that is going to be used as the origin of the dimension. + * The second click determines the end and the third click modifies its height. + */ + int DrawDimension( TOOL_EVENT& aEvent ); + + /** + * Function DrawZone() + * Starts interactively drawing a zone. After invoking the function a zone settings dialog + * is displayed. After confirmation it allows the user to set points that are going to be used + * as a boundary polygon of the zone. Double click or clicking on the origin of the boundary + * polyline finishes the drawing. + */ + int DrawZone( TOOL_EVENT& aEvent ); + + /** + * Function DrawKeepout() + * Starts interactively drawing a keepout area. After invoking the function an area settings + * dialog is displayed. After confirmation it allows the user to set points that are going to + * be used as a boundary polygon of the area. Double click or clicking on the origin of the + * boundary polyline finishes the drawing. + */ + int DrawKeepout( TOOL_EVENT& aEvent ); + + /** + * Function PlaceTarget() + * Allows user to place a layer alignment target. + */ + int PlaceTarget( TOOL_EVENT& aEvent ); + + /** + * Function PlaceModule() + * Displays a dialog to selected a module to be added and then allows user to set its position. + */ + int PlaceModule( TOOL_EVENT& aEvent ); + +private: + ///> Starts drawing a selected shape (i.e. DRAWSEGMENT). + ///> @param aShape is the type of created shape (@see STROKE_T). + ///> @param aContinous decides if there is only one or multiple shapes to draw. + int drawSegment( int aShape, bool aContinous ); + + ///> Draws a polygon, that is added as a zone or a keepout area. + ///> @param aKeepout decides if the drawn polygon is a zone or a keepout area. + int drawZone( bool aKeepout ); + + ///> Forces a DRAWSEGMENT to be drawn at multiple of 45 degrees. The origin + ///> stays the same, the end of the aSegment is modified according to the + ///> current cursor position. + ///> @param aSegment is the segment that is currently drawn. + ///> @param aHelper is a helper line that shows the next possible segment. + void make45DegLine( DRAWSEGMENT* aSegment, DRAWSEGMENT* aHelper ) const; + + ///> Sets up handlers for various events. + void setTransitions(); + + KIGFX::VIEW* m_view; + KIGFX::VIEW_CONTROLS* m_controls; + BOARD* m_board; + PCB_EDIT_FRAME* m_frame; + + // How does line width change after one -/+ key press. + static const int WIDTH_STEP = 100000; +}; + +#endif /* __DRAWING_TOOL_H */ diff --git a/pcbnew/tools/edit_constraints.cpp b/pcbnew/tools/edit_constraints.cpp new file mode 100644 index 0000000000..f0edf9bc8b --- /dev/null +++ b/pcbnew/tools/edit_constraints.cpp @@ -0,0 +1,189 @@ +/* + * This program source code file is part of KICAD, a free EDA CAD application. + * + * Copyright (C) 2014 CERN + * @author Maciej Suminski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "edit_constraints.h" +#include "edit_points.h" + +#include + +void EC_VERTICAL::Apply( EDIT_POINT& aHandle ) +{ + VECTOR2I point = aHandle.GetPosition(); + point.x = m_constrainer.GetPosition().x; + aHandle.SetPosition( point ); +} + + +void EC_HORIZONTAL::Apply( EDIT_POINT& aHandle ) +{ + VECTOR2I point = aHandle.GetPosition(); + point.y = m_constrainer.GetPosition().y; + aHandle.SetPosition( point ); +} + + +void EC_45DEGREE::Apply( EDIT_POINT& aHandle ) +{ + // Current line vector + VECTOR2I lineVector( aHandle.GetPosition() - m_constrainer.GetPosition() ); + double angle = lineVector.Angle(); + + // Find the closest angle, which is a multiple of 45 degrees + double newAngle = round( angle / ( M_PI / 4.0 ) ) * M_PI / 4.0; + VECTOR2I newLineVector = lineVector.Rotate( newAngle - angle ); + + aHandle.SetPosition( m_constrainer.GetPosition() + newLineVector ); +} + + +EC_LINE::EC_LINE( EDIT_POINT& aConstrained, const EDIT_POINT& aConstrainer ) : + EDIT_CONSTRAINT( aConstrained ), m_constrainer( aConstrainer ) +{ + m_line = m_constrained.GetPosition() - m_constrainer.GetPosition(); +} + + +void EC_LINE::Apply( EDIT_POINT& aHandle ) +{ + SEG main( m_constrainer.GetPosition(), m_constrainer.GetPosition() + m_line ); + SEG projection( aHandle.GetPosition(), aHandle.GetPosition() + m_line.Perpendicular() ); + + if( OPT_VECTOR2I intersect = projection.IntersectLines( main ) ) + aHandle.SetPosition( *intersect ); +} + + +void EC_CIRCLE::Apply( EDIT_POINT& aHandle ) +{ + VECTOR2I centerToEnd = m_end.GetPosition() - m_center.GetPosition(); + VECTOR2I centerToPoint = aHandle.GetPosition() - m_center.GetPosition(); + + int radius = centerToEnd.EuclideanNorm(); + double angle = centerToPoint.Angle(); + + VECTOR2I newLine( radius, 0 ); + newLine = newLine.Rotate( angle ); + + aHandle.SetPosition( m_center.GetPosition() + newLine ); +} + + +EC_CONVERGING::EC_CONVERGING( EDIT_LINE& aLine, EDIT_POINTS& aPoints ) : + EDIT_CONSTRAINT( aLine ), + m_colinearConstraint( NULL ), m_editPoints( aPoints ) +{ + // Dragged segment endings + EDIT_POINT& origin = aLine.GetOrigin(); + EDIT_POINT& end = aLine.GetEnd(); + + // Previous and next points, to make constraining lines (adjacent to the dragged line) + EDIT_POINT& prevOrigin = *aPoints.Previous( origin ); + EDIT_POINT& nextEnd = *aPoints.Next( end ); + + // Constraints for segments adjacent to the dragged one + m_originSideConstraint = new EC_LINE( origin, prevOrigin ); + m_endSideConstraint = new EC_LINE( end, nextEnd ); + + // Store the current vector of the line + m_draggedVector = end.GetPosition() - origin.GetPosition(); + + // Check for colinearity + SEG originSide( origin.GetPosition(), prevOrigin.GetPosition() ); + SEG endSide( end.GetPosition(), nextEnd.GetPosition() ); + SEG dragged( origin.GetPosition(), end.GetPosition() ); + + if( dragged.Collinear( originSide ) ) + m_colinearConstraint = m_originSideConstraint; + else if( dragged.Collinear( endSide ) ) + m_colinearConstraint = m_endSideConstraint; +} + + +EC_CONVERGING::~EC_CONVERGING() +{ + delete m_originSideConstraint; + delete m_endSideConstraint; + // m_colinearConstraint should not be freed, it is a pointer to one of the above +} + + +void EC_CONVERGING::Apply( EDIT_LINE& aHandle ) +{ + // The dragged segment endpoints + EDIT_POINT& origin = aHandle.GetOrigin(); + EDIT_POINT& end = aHandle.GetEnd(); + + if( m_colinearConstraint ) + { + m_colinearConstraint->Apply( origin ); + m_colinearConstraint->Apply( end ); + } + + // The dragged segment + SEG dragged( origin.GetPosition(), origin.GetPosition() + m_draggedVector ); + + // Do not allow points on the adjacent segments move freely + m_originSideConstraint->Apply(); + m_endSideConstraint->Apply(); + + EDIT_POINT& prevOrigin = *m_editPoints.Previous( origin ); + EDIT_POINT& nextEnd = *m_editPoints.Next( end ); + + // Two segments adjacent to the dragged segment + SEG originSide = SEG( origin.GetPosition(), prevOrigin.GetPosition() ); + SEG endSide = SEG( end.GetPosition(), nextEnd.GetPosition() ); + + // First intersection point (dragged segment against origin side) + if( OPT_VECTOR2I originIntersect = dragged.IntersectLines( originSide ) ) + origin.SetPosition( *originIntersect ); + + // Second intersection point (dragged segment against end side) + if( OPT_VECTOR2I endIntersect = dragged.IntersectLines( endSide ) ) + end.SetPosition( *endIntersect ); + + // Check if adjacent segments intersect (did we dragged the line to the point that it may + // create a selfintersecting polygon?) + originSide = SEG( origin.GetPosition(), prevOrigin.GetPosition() ); + endSide = SEG( end.GetPosition(), nextEnd.GetPosition() ); + + if( OPT_VECTOR2I originEndIntersect = endSide.Intersect( originSide ) ) + { + origin.SetPosition( *originEndIntersect ); + end.SetPosition( *originEndIntersect ); + } +} + + +EC_SNAPLINE::EC_SNAPLINE( EDIT_LINE& aLine, V2D_TRANSFORM_FUN aSnapFun ) : + EDIT_CONSTRAINT( aLine ), m_snapFun( aSnapFun ) +{} + + +void EC_SNAPLINE::Apply( EDIT_LINE& aHandle ) +{ + VECTOR2D delta = aHandle.GetEnd().GetPosition() - aHandle.GetOrigin().GetPosition(); + + aHandle.GetOrigin().SetPosition( m_snapFun( aHandle.GetOrigin().GetPosition() ) ); + aHandle.GetEnd().SetPosition( aHandle.GetOrigin().GetPosition() + delta ); +} diff --git a/pcbnew/tools/edit_constraints.h b/pcbnew/tools/edit_constraints.h new file mode 100644 index 0000000000..6df17e438d --- /dev/null +++ b/pcbnew/tools/edit_constraints.h @@ -0,0 +1,267 @@ +/* + * This program source code file is part of KICAD, a free EDA CAD application. + * + * Copyright (C) 2014 CERN + * @author Maciej Suminski + * + * 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 + */ + +#ifndef EDIT_CONSTRAINTS_H_ +#define EDIT_CONSTRAINTS_H_ + +#include +#include + +class EDIT_POINT; +class EDIT_LINE; +class EDIT_POINTS; + +/** + * Class EDIT_CONSTRAINT + * + * Allows to describe constraints between two edit handles. After the constrained handle is changed, + * Apply() has to be called to fix its coordinates according to the implemented constraint. + */ +template +class EDIT_CONSTRAINT +{ +public: + /** + * Constructor + * + * @param aConstrained is EDIT_POINT to which the constraint is applied. + */ + EDIT_CONSTRAINT( EDIT_TYPE& aConstrained ) : m_constrained( aConstrained ) {}; + + virtual ~EDIT_CONSTRAINT() {}; + + /** + * Function Apply() + * + * Corrects coordinates of the constrained edit handle. + */ + virtual void Apply( EDIT_TYPE& aHandle ) = 0; + + /** + * Function Apply() + * + * Corrects coordinates of the constrained edit handle. + */ + void Apply() + { + Apply( m_constrained ); + } + +protected: + EDIT_TYPE& m_constrained; ///< Point that is constrained by rules implemented by Apply() +}; + + +/** + * Class EC_VERTICAL. + * + * EDIT_CONSTRAINT that imposes a constraint that two points have to have the same X coordinate. + */ +class EC_VERTICAL : public EDIT_CONSTRAINT +{ +public: + /** + * Constructor. + * + * @param aConstrained is the point that is put under constrain. + * @param aConstrainer is the point that is the source of the constrain. + */ + EC_VERTICAL( EDIT_POINT& aConstrained, const EDIT_POINT& aConstrainer ) : + EDIT_CONSTRAINT( aConstrained ), m_constrainer( aConstrainer ) + {} + + ///> @copydoc EDIT_CONSTRAINT::Apply() + virtual void Apply( EDIT_POINT& aHandle ); + +private: + const EDIT_POINT& m_constrainer; ///< Point that imposes the constraint. +}; + + +/** + * Class EC_HORIZONTAL. + * + * EDIT_CONSTRAINT that imposes a constraint that two points have to have the same Y coordinate. + */ +class EC_HORIZONTAL : public EDIT_CONSTRAINT +{ +public: + /** + * Constructor. + * + * @param aConstrained is the point that is put under constrain. + * @param aConstrainer is the point that is the source of the constrain. + */ + EC_HORIZONTAL( EDIT_POINT& aConstrained, const EDIT_POINT& aConstrainer ) : + EDIT_CONSTRAINT( aConstrained ), m_constrainer( aConstrainer ) + {} + + ///> @copydoc EDIT_CONSTRAINT::Apply() + virtual void Apply( EDIT_POINT& aHandle ); + +private: + const EDIT_POINT& m_constrainer; ///< Point that imposes the constraint. +}; + + +/** + * Class EC_45DEGREE + * + * EDIT_CONSTRAINT that imposes a constraint that two points have to be located at angle of 45 + * degree multiplicity. + */ +class EC_45DEGREE : public EDIT_CONSTRAINT +{ +public: + /** + * Constructor. + * + * @param aConstrained is the point that is put under constrain. + * @param aConstrainer is the point that is the source of the constrain. + */ + EC_45DEGREE( EDIT_POINT& aConstrained, const EDIT_POINT& aConstrainer ) : + EDIT_CONSTRAINT( aConstrained ), m_constrainer( aConstrainer ) + {} + + ///> @copydoc EDIT_CONSTRAINT::Apply() + virtual void Apply( EDIT_POINT& aHandle ); + +private: + const EDIT_POINT& m_constrainer; ///< Point that imposes the constraint. +}; + + +/** + * Class EC_LINE + * + * EDIT_CONSTRAINT that imposes a constraint that a point has to lie on a line (determined + * by 2 points). + */ +class EC_LINE : public EDIT_CONSTRAINT +{ +public: + EC_LINE( EDIT_POINT& aConstrained, const EDIT_POINT& aConstrainer ); + + ///> @copydoc EDIT_CONSTRAINT::Apply() + virtual void Apply( EDIT_POINT& aHandle ); + +private: + const EDIT_POINT& m_constrainer; ///< Point that imposes the constraint. + VECTOR2I m_line; ///< Vector representing the constraining line. +}; + + +/** + * Class EC_CIRCLE. + * + * EDIT_CONSTRAINT that imposes a constraint that a point has to lie on a circle. + */ +class EC_CIRCLE : public EDIT_CONSTRAINT +{ +public: + /** + * Constructor. + * + * @param aConstrained is the point that is put under constrain. + * @parama aCenter is the point that is the center of the circle. + * @parama aEnd is the point that decides on the radius of the circle. + */ + EC_CIRCLE( EDIT_POINT& aConstrained, const EDIT_POINT& aCenter, const EDIT_POINT& aEnd ) : + EDIT_CONSTRAINT( aConstrained ), m_center( aCenter ), m_end( aEnd ) + {} + + ///> @copydoc EDIT_CONSTRAINT::Apply() + virtual void Apply( EDIT_POINT& aHandle ); + +private: + ///> Point that imposes the constraint (center of the circle). + const EDIT_POINT& m_center; + + ///> Point that imposes the constraint (decides on the radius of the circle). + const EDIT_POINT& m_end; +}; + + +/** + * Class EC_CONVERGING + * + * EDIT_CONSTRAINT for 3 segments: dragged and two adjacent ones, enforcing to keep their slopes + * and allows only to change ending points. Applied to zones. + */ +class EC_CONVERGING : public EDIT_CONSTRAINT +{ +public: + EC_CONVERGING( EDIT_LINE& aLine, EDIT_POINTS& aPoints ); + + virtual ~EC_CONVERGING(); + + ///> @copydoc EDIT_CONSTRAINT::Apply() + virtual void Apply( EDIT_LINE& aHandle ); + +private: + ///> Constraint for origin side segment. + EDIT_CONSTRAINT* m_originSideConstraint; + + ///> Constraint for end side segment. + EDIT_CONSTRAINT* m_endSideConstraint; + + ///> Additional constriant, applied when at least two points are collinear. It is a pointer to + ///> m_[origin/end]SideConstraint, so it should not be freed. + EDIT_CONSTRAINT* m_colinearConstraint; + + ///> EDIT_POINTS instance that stores currently modified lines. + EDIT_POINTS& m_editPoints; + + ///> Vector that represents the initial direction of the dragged segment. + VECTOR2I m_draggedVector; +}; + + +/** + * Class EC_SNAPLINE + * + * EDIT_CONSTRAINT for a EDIT_LINE, one of the ends is snapped to a spot determined by a + * transform function passed as parameter (e.g. it can be snapped to a grid), instead of having + * the line center snapped to a point. + */ +class EC_SNAPLINE : public EDIT_CONSTRAINT +{ +public: + ///> Typedef for a function that determines snapping point. + typedef boost::function V2D_TRANSFORM_FUN; + + EC_SNAPLINE( EDIT_LINE& aLine, V2D_TRANSFORM_FUN aSnapFun ); + + virtual ~EC_SNAPLINE() + {} + + ///> @copydoc EDIT_CONSTRAINT::Apply() + virtual void Apply( EDIT_LINE& aHandle ); + +private: + ///> Function that determines snapping point. + V2D_TRANSFORM_FUN m_snapFun; +}; + +#endif /* EDIT_CONSTRAINTS_H_ */ diff --git a/pcbnew/tools/edit_points.cpp b/pcbnew/tools/edit_points.cpp new file mode 100644 index 0000000000..1c24722862 --- /dev/null +++ b/pcbnew/tools/edit_points.cpp @@ -0,0 +1,158 @@ +/* + * This program source code file is part of KICAD, a free EDA CAD application. + * + * Copyright (C) 2014 CERN + * @author Maciej Suminski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include + +#include +#include "edit_points.h" + +bool EDIT_POINT::WithinPoint( const VECTOR2I& aPoint, unsigned int aSize ) const +{ + // Corners of the EDIT_POINT square + VECTOR2I topLeft = GetPosition() - aSize; + VECTOR2I bottomRight = GetPosition() + aSize; + + return ( aPoint.x > topLeft.x && aPoint.y > topLeft.y && + aPoint.x < bottomRight.x && aPoint.y < bottomRight.y ); +} + + +EDIT_POINTS::EDIT_POINTS( EDA_ITEM* aParent ) : + EDA_ITEM( NOT_USED ), m_parent( aParent ) +{ +} + + +EDIT_POINT* EDIT_POINTS::FindPoint( const VECTOR2I& aLocation ) +{ + float size = m_view->ToWorld( EDIT_POINT::POINT_SIZE ); + + std::deque::iterator pit, pitEnd; + for( pit = m_points.begin(), pitEnd = m_points.end(); pit != pitEnd; ++pit ) + { + EDIT_POINT& point = *pit; + + if( point.WithinPoint( aLocation, size ) ) + return &point; + } + + std::deque::iterator lit, litEnd; + for( lit = m_lines.begin(), litEnd = m_lines.end(); lit != litEnd; ++lit ) + { + EDIT_LINE& point = *lit; + + if( point.WithinPoint( aLocation, size ) ) + return &point; + } + + return NULL; +} + + +EDIT_POINT* EDIT_POINTS::Previous( const EDIT_POINT& aPoint ) +{ + for( unsigned int i = 0; i < m_points.size(); ++i ) + { + if( m_points[i] == aPoint ) + { + if( i == 0 ) + return &m_points[m_points.size() - 1]; + else + return &m_points[i - 1]; + } + } + + return NULL; +} + + +EDIT_LINE* EDIT_POINTS::Previous( const EDIT_LINE& aLine ) +{ + for( unsigned int i = 0; i < m_lines.size(); ++i ) + { + if( m_lines[i] == aLine ) + { + if( i == 0 ) + return &m_lines[m_lines.size() - 1]; + else + return &m_lines[i - 1]; + } + } + + return NULL; +} + + +EDIT_POINT* EDIT_POINTS::Next( const EDIT_POINT& aPoint ) +{ + for( unsigned int i = 0; i < m_points.size(); ++i ) + { + if( m_points[i] == aPoint ) + { + if( i == m_points.size() - 1 ) + return &m_points[0]; + else + return &m_points[i + 1]; + } + } + + return NULL; +} + + +EDIT_LINE* EDIT_POINTS::Next( const EDIT_LINE& aLine ) +{ + for( unsigned int i = 0; i < m_lines.size(); ++i ) + { + if( m_lines[i] == aLine ) + { + if( i == m_lines.size() - 1 ) + return &m_lines[0]; + else + return &m_lines[i + 1]; + } + } + + return NULL; +} + + +void EDIT_POINTS::ViewDraw( int aLayer, KIGFX::GAL* aGal ) const +{ + aGal->SetFillColor( KIGFX::COLOR4D( 1.0, 1.0, 1.0, 1.0 ) ); + aGal->SetIsFill( true ); + aGal->SetIsStroke( false ); + aGal->PushDepth(); + aGal->SetLayerDepth( -512.0 ); // TODO no hardcoded depths? + + float size = m_view->ToWorld( EDIT_POINT::POINT_SIZE ); + + BOOST_FOREACH( const EDIT_POINT& point, m_points ) + aGal->DrawRectangle( point.GetPosition() - size / 2, point.GetPosition() + size / 2 ); + + BOOST_FOREACH( const EDIT_LINE& line, m_lines ) + aGal->DrawCircle( line.GetPosition(), size / 2 ); + + aGal->PopDepth(); +} diff --git a/pcbnew/tools/edit_points.h b/pcbnew/tools/edit_points.h new file mode 100644 index 0000000000..b06ec30975 --- /dev/null +++ b/pcbnew/tools/edit_points.h @@ -0,0 +1,466 @@ +/* + * This program source code file is part of KICAD, a free EDA CAD application. + * + * Copyright (C) 2014 CERN + * @author Maciej Suminski + * + * 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 + */ + +#ifndef EDIT_POINTS_H_ +#define EDIT_POINTS_H_ + +#include + +#include +#include + +#include "edit_constraints.h" + +/** + * Class EDIT_POINT + * + * Represents a single point that can be used for modifying items. It is directly related to one + * of points in a graphical item (e.g. vertex of a zone or center of a circle). + */ +class EDIT_POINT +{ +public: + /** + * Constructor + * + * @param aPoint stores coordinates for EDIT_POINT. + */ + EDIT_POINT( const VECTOR2I& aPoint ) : + m_position( aPoint ) {}; + + virtual ~EDIT_POINT() {} + + /** + * Function GetPosition() + * + * Returns coordinates of an EDIT_POINT. Note that it may be different than coordinates of + * a graphical item that is bound to the EDIT_POINT. + */ + virtual VECTOR2I GetPosition() const + { + return m_position; + } + + /** + * Function GetX() + * + * Returns X coordinate of an EDIT_POINT. + */ + int GetX() const + { + return GetPosition().x; + } + + /** + * Function GetY() + * + * Returns Y coordinate of an EDIT_POINT. + */ + int GetY() const + { + return GetPosition().y; + } + + /** + * Function SetPosition() + * + * Sets new coordinates for an EDIT_POINT. It does not change the coordinates of a graphical + * item. + * @param aPosition are new coordinates. + */ + virtual void SetPosition( const VECTOR2I& aPosition ) + { + m_position = aPosition; + } + + /** + * Function WithinPoint() + * + * Checks if given point is within a square centered in the EDIT_POINT position. + * @param aPoint is point to be checked. + * @param aSize is length of the square side. + */ + bool WithinPoint( const VECTOR2I& aPoint, unsigned int aSize ) const; + + /** + * Function SetConstraint() + * + * Sets a constraint for and EDIT_POINT. + * @param aConstraint is the constraint to be set. + */ + void SetConstraint( EDIT_CONSTRAINT* aConstraint ) + { + m_constraint.reset( aConstraint ); + } + + /** + * Function GetConstraint() + * + * Returns the constraint imposed on an EDIT_POINT. If there are no constraints, NULL is + * returned. + */ + EDIT_CONSTRAINT* GetConstraint() const + { + return m_constraint.get(); + } + + /** + * Function ClearConstraint() + * + * Removes previously set constraint. + */ + void ClearConstraint() + { + m_constraint.reset(); + } + + /** + * Function IsConstrained() + * + * Checks if point is constrained. + * @return True is point is constrained, false otherwise. + */ + bool IsConstrained() const + { + return m_constraint != NULL; + } + + /** + * Function ApplyConstraint() + * + * Corrects coordinates of an EDIT_POINT by applying previously set constraint. + */ + virtual void ApplyConstraint() + { + if( m_constraint ) + m_constraint->Apply(); + } + + bool operator==( const EDIT_POINT& aOther ) const + { + return m_position == aOther.m_position; + } + + ///> Single point size in pixels + static const int POINT_SIZE = 10; + +private: + ///> Position of EDIT_POINT + VECTOR2I m_position; + + ///> Constraint for the point, NULL if none + boost::shared_ptr > m_constraint; +}; + + +/** + * Class EDIT_LINE + * + * Represents a line connecting two EDIT_POINTs. That allows to move them both by dragging the + * EDIT_POINT in the middle. As it uses references to EDIT_POINTs, all coordinates are + * automatically synchronized. + */ +class EDIT_LINE : public EDIT_POINT +{ +public: + /** + * Constructor + * + * @param aOrigin is the origin of EDIT_LINE. + * @param aEnd is the end of EDIT_LINE. + */ + EDIT_LINE( EDIT_POINT& aOrigin, EDIT_POINT& aEnd ) : + EDIT_POINT( aOrigin.GetPosition() + ( aEnd.GetPosition() - aOrigin.GetPosition() ) / 2 ), + m_origin( aOrigin ), m_end( aEnd ) + { + } + + ///> @copydoc EDIT_POINT::GetPosition() + virtual VECTOR2I GetPosition() const + { + return ( m_origin.GetPosition() + m_end.GetPosition() ) / 2; + } + + ///> @copydoc EDIT_POINT::GetPosition() + virtual void SetPosition( const VECTOR2I& aPosition ) + { + VECTOR2I difference = aPosition - GetPosition(); + + m_origin.SetPosition( m_origin.GetPosition() + difference ); + m_end.SetPosition( m_end.GetPosition() + difference ); + } + + ///> @copydoc EDIT_POINT::ApplyConstraint() + virtual void ApplyConstraint() + { + m_origin.ApplyConstraint(); + m_end.ApplyConstraint(); + + if( m_constraint ) + m_constraint->Apply(); + } + + /** + * Function SetConstraint() + * + * Sets a constraint for and EDIT_POINT. + * @param aConstraint is the constraint to be set. + */ + void SetConstraint( EDIT_CONSTRAINT* aConstraint ) + { + m_constraint.reset( aConstraint ); + } + + /** + * Function GetConstraint() + * + * Returns the constraint imposed on an EDIT_POINT. If there are no constraints, NULL is + * returned. + */ + EDIT_CONSTRAINT* GetConstraint() const + { + return m_constraint.get(); + } + + + /** + * Function GetOrigin() + * + * Returns the origin EDIT_POINT. + */ + EDIT_POINT& GetOrigin() + { + return m_origin; + } + + const EDIT_POINT& GetOrigin() const + { + return m_origin; + } + + /** + * Function GetEnd() + * + * Returns the end EDIT_POINT. + */ + EDIT_POINT& GetEnd() + { + return m_end; + } + + const EDIT_POINT& GetEnd() const + { + return m_end; + } + + bool operator==( const EDIT_POINT& aOther ) const + { + return GetPosition() == aOther.GetPosition(); + } + + bool operator==( const EDIT_LINE& aOther ) const + { + return m_origin == aOther.m_origin && m_end == aOther.m_end; + } + +private: + EDIT_POINT& m_origin; ///< Origin point for a line + EDIT_POINT& m_end; ///< End point for a line + + ///> Constraint for the point, NULL if none + boost::shared_ptr > m_constraint; +}; + + +/** + * Class EDIT_POINTS + * + * EDIT_POINTS is a VIEW_ITEM that manages EDIT_POINTs and EDIT_LINEs and draws them. + */ +class EDIT_POINTS : public EDA_ITEM +{ +public: + /** + * Constructor. + * + * @param aParent is the item to which EDIT_POINTs are related. + */ + EDIT_POINTS( EDA_ITEM* aParent ); + + /** + * Function FindPoint() + * + * Returns a point that is at given coordinates or NULL if there is no such point. + * @param aLocation is the location for searched point. + */ + EDIT_POINT* FindPoint( const VECTOR2I& aLocation ); + + /** + * Function GetParent() + * + * Returns parent of the EDIT_POINTS. + */ + EDA_ITEM* GetParent() const + { + return m_parent; + } + + /** + * Function AddPoint() + * + * Adds an EDIT_POINT. + * @param aPoint is the new point. + */ + void AddPoint( const EDIT_POINT& aPoint ) + { + m_points.push_back( aPoint ); + } + + /** + * Function AddPoint() + * + * Adds an EDIT_POINT. + * @param aPoint are coordinates of the new point. + */ + void AddPoint( const VECTOR2I& aPoint ) + { + AddPoint( EDIT_POINT( aPoint ) ); + } + + /** + * Function AddLine() + * + * Adds an EDIT_LINE. + * @param aLine is the new line. + */ + void AddLine( const EDIT_LINE& aLine ) + { + m_lines.push_back( aLine ); + } + + /** + * Function AddLine() + * + * Adds an EDIT_LINE. + * @param aOrigin is the origin for a new line. + * @param aEnd is the end for a new line. + */ + void AddLine( EDIT_POINT& aOrigin, EDIT_POINT& aEnd ) + { + m_lines.push_back( EDIT_LINE( aOrigin, aEnd ) ); + } + + /** + * Function Previous() + * + * Returns the point that is after the given point in the list. + * @param aPoint is the point that is supposed to be preceding the searched point. + * @return The point following aPoint in the list. If aPoint is the first in + * the list, the last from the list will be returned. If there are no points at all, NULL + * is returned. + */ + EDIT_POINT* Previous( const EDIT_POINT& aPoint ); + + EDIT_LINE* Previous( const EDIT_LINE& aLine ); + + /** + * Function Next() + * + * Returns the point that is before the given point in the list. + * @param aPoint is the point that is supposed to be following the searched point. + * @return The point preceding aPoint in the list. If aPoint is the last in + * the list, the first point from the list will be returned. If there are no points at all, + * NULL is returned. + */ + EDIT_POINT* Next( const EDIT_POINT& aPoint ); + + EDIT_LINE* Next( const EDIT_LINE& aLine ); + + EDIT_POINT& Point( unsigned int aIndex ) + { + return m_points[aIndex]; + } + + const EDIT_POINT& Point( unsigned int aIndex ) const + { + return m_points[aIndex]; + } + + EDIT_LINE& Line( unsigned int aIndex ) + { + return m_lines[aIndex]; + } + + const EDIT_LINE& Line( unsigned int aIndex ) const + { + return m_lines[aIndex]; + } + + /** + * Function PointsSize() + * + * Returns number of stored EDIT_POINTs. + */ + unsigned int PointsSize() const + { + return m_points.size(); + } + + /** + * Function LinesSize() + * + * Returns number of stored EDIT_LINEs. + */ + unsigned int LinesSize() const + { + return m_lines.size(); + } + + ///> @copydoc VIEW_ITEM::ViewBBox() + virtual const BOX2I ViewBBox() const + { + return m_parent->ViewBBox(); + } + + ///> @copydoc VIEW_ITEM::ViewDraw() + virtual void ViewDraw( int aLayer, KIGFX::GAL* aGal ) const; + + ///> @copydoc VIEW_ITEM::ViewGetLayers() + virtual void ViewGetLayers( int aLayers[], int& aCount ) const + { + aCount = 1; + aLayers[0] = ITEM_GAL_LAYER( GP_OVERLAY ); + } + + void Show( int x, std::ostream& st ) const + { + } + +private: + EDA_ITEM* m_parent; ///< Parent of the EDIT_POINTs + std::deque m_points; ///< EDIT_POINTs for modifying m_parent + std::deque m_lines; ///< EDIT_LINEs for modifying m_parent +}; + +#endif /* EDIT_POINTS_H_ */ diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp index f5f1c3b0ff..8dac46385c 100644 --- a/pcbnew/tools/edit_tool.cpp +++ b/pcbnew/tools/edit_tool.cpp @@ -30,16 +30,15 @@ #include #include #include + #include #include +#include #include "common_actions.h" #include "selection_tool.h" #include "edit_tool.h" -using namespace KIGFX; -using boost::optional; - EDIT_TOOL::EDIT_TOOL() : TOOL_INTERACTIVE( "pcbnew.InteractiveEdit" ), m_selectionTool( NULL ) { @@ -79,16 +78,24 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) // Be sure that there is at least one item that we can modify if( !makeSelection( selection ) ) - return 0; + { + setTransitions(); + + return 0; + } + + Activate(); - VECTOR2D dragPosition; // The last position of the cursor while dragging m_dragging = false; // Are selected items being dragged? bool restore = false; // Should items' state be restored when finishing the tool? // By default, modified items need to update their geometry m_updateFlag = KIGFX::VIEW_ITEM::GEOMETRY; - VIEW_CONTROLS* controls = getViewControls(); + // Offset from the dragged item's center (anchor) + wxPoint offset; + + KIGFX::VIEW_CONTROLS* controls = getViewControls(); PCB_EDIT_FRAME* editFrame = static_cast( m_toolMgr->GetEditFrame() ); controls->ShowCursor( true ); controls->SetSnapping( true ); @@ -104,6 +111,12 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) break; // Finish } + else if( evt->Action() == TA_UNDO_REDO ) + { + unselect = true; + break; + } + // Dispatch TOOL_ACTIONs else if( evt->Category() == TC_COMMAND ) { @@ -128,30 +141,35 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) else if( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) ) { + VECTOR2I cursor( controls->GetCursorPosition() ); + if( m_dragging ) { + wxPoint movement = wxPoint( cursor.x, cursor.y ) - + static_cast( selection.items.GetPickedItem( 0 ) )->GetPosition(); + // Drag items to the current cursor position - VECTOR2D movement = ( getView()->ToWorld( controls->GetCursorPosition() ) - - dragPosition ); for( unsigned int i = 0; i < selection.items.GetCount(); ++i ) { BOARD_ITEM* item = static_cast( selection.items.GetPickedItem( i ) ); - item->Move( wxPoint( movement.x, movement.y ) ); + item->Move( movement + offset ); } updateRatsnest( true ); } - else + else // Prepare to start dragging { - // Prepare to drag - save items, so changes can be undone + // Save items, so changes can be undone editFrame->OnModify(); editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED ); + offset = static_cast( selection.items.GetPickedItem( 0 ) )->GetPosition() - + wxPoint( cursor.x, cursor.y ); m_dragging = true; } - selection.group->ViewUpdate( VIEW_ITEM::GEOMETRY ); - dragPosition = getView()->ToWorld( controls->GetCursorPosition() ); + selection.group->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + m_toolMgr->RunAction( COMMON_ACTIONS::pointEditorUpdate ); } else if( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) ) @@ -173,7 +191,7 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) } if( unselect ) - m_toolMgr->RunAction( "pcbnew.InteractiveSelection.Clear" ); + m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear ); RN_DATA* ratsnest = getModel( PCB_T )->GetRatsnest(); ratsnest->ClearSimple(); @@ -198,14 +216,18 @@ int EDIT_TOOL::Properties( TOOL_EVENT& aEvent ) bool unselect = selection.Empty(); if( !makeSelection( selection ) ) + { + setTransitions(); + return 0; + } // Properties are displayed when there is only one item selected if( selection.Size() == 1 ) { // Display properties dialog BOARD_ITEM* item = static_cast( selection.items.GetPickedItem( 0 ) ); - VECTOR2I cursor = getView()->ToWorld( getViewControls()->GetCursorPosition() ); + VECTOR2I cursor = getViewControls()->GetCursorPosition(); // Check if user wants to edit pad or module properties if( item->Type() == PCB_MODULE_T ) @@ -231,9 +253,10 @@ int EDIT_TOOL::Properties( TOOL_EVENT& aEvent ) getModel( PCB_T )->GetRatsnest()->Recalculate(); if( unselect ) - m_toolMgr->RunAction( "pcbnew.InteractiveSelection.Clear" ); + m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear ); } + m_toolMgr->RunAction( COMMON_ACTIONS::pointEditorUpdate ); setTransitions(); return 0; @@ -249,7 +272,11 @@ int EDIT_TOOL::Rotate( TOOL_EVENT& aEvent ) bool unselect = selection.Empty(); if( !makeSelection( selection ) ) + { + setTransitions(); + return 0; + } wxPoint rotatePoint = getModificationPoint( selection ); @@ -269,8 +296,7 @@ int EDIT_TOOL::Rotate( TOOL_EVENT& aEvent ) item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } - setTransitions(); - updateRatsnest( true ); + updateRatsnest( m_dragging ); if( m_dragging ) selection.group->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); @@ -278,7 +304,10 @@ int EDIT_TOOL::Rotate( TOOL_EVENT& aEvent ) getModel( PCB_T )->GetRatsnest()->Recalculate(); if( unselect ) - m_toolMgr->RunAction( "pcbnew.InteractiveSelection.Clear" ); + m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear ); + + m_toolMgr->RunAction( COMMON_ACTIONS::pointEditorUpdate ); + setTransitions(); return 0; } @@ -293,7 +322,11 @@ int EDIT_TOOL::Flip( TOOL_EVENT& aEvent ) bool unselect = selection.Empty(); if( !makeSelection( selection ) ) + { + setTransitions(); + return 0; + } wxPoint flipPoint = getModificationPoint( selection ); @@ -313,8 +346,7 @@ int EDIT_TOOL::Flip( TOOL_EVENT& aEvent ) item->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS ); } - setTransitions(); - updateRatsnest( true ); + updateRatsnest( m_dragging ); if( m_dragging ) selection.group->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); @@ -322,7 +354,10 @@ int EDIT_TOOL::Flip( TOOL_EVENT& aEvent ) getModel( PCB_T )->GetRatsnest()->Recalculate(); if( unselect ) - m_toolMgr->RunAction( "pcbnew.InteractiveSelection.Clear" ); + m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear ); + + m_toolMgr->RunAction( COMMON_ACTIONS::pointEditorUpdate ); + setTransitions(); return 0; } @@ -333,18 +368,23 @@ int EDIT_TOOL::Remove( TOOL_EVENT& aEvent ) const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); if( !makeSelection( selection ) ) + { + setTransitions(); + return 0; + } // Get a copy of the selected items set PICKED_ITEMS_LIST selectedItems = selection.items; PCB_EDIT_FRAME* editFrame = static_cast( m_toolMgr->GetEditFrame() ); // As we are about to remove items, they have to be removed from the selection first - m_toolMgr->RunAction( "pcbnew.InteractiveSelection.Clear" ); + m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear ); // Save them for( unsigned int i = 0; i < selectedItems.GetCount(); ++i ) selectedItems.SetPickedItemStatus( UR_DELETED, i ); + editFrame->OnModify(); editFrame->SaveCopyInUndoList( selectedItems, UR_DELETED ); @@ -355,13 +395,9 @@ int EDIT_TOOL::Remove( TOOL_EVENT& aEvent ) remove( item ); } - // Rebuild list of pads and nets if necessary - BOARD* board = getModel( PCB_T ); - if( !( board->m_Status_Pcb & NET_CODES_OK ) ) - board->BuildListOfNets(); + getModel( PCB_T )->GetRatsnest()->Recalculate(); setTransitions(); - board->GetRatsnest()->Recalculate(); return 0; } @@ -377,7 +413,7 @@ void EDIT_TOOL::remove( BOARD_ITEM* aItem ) { MODULE* module = static_cast( aItem ); module->ClearFlags(); - module->RunOnChildren( std::bind1st( std::mem_fun( &KIGFX::VIEW::Remove ), getView() ) ); + module->RunOnChildren( boost::bind( &KIGFX::VIEW::Remove, getView(), _1 ) ); // Module itself is deleted after the switch scope is finished // list of pads is rebuild by BOARD::BuildListOfNets() @@ -451,7 +487,7 @@ wxPoint EDIT_TOOL::getModificationPoint( const SELECTION_TOOL::SELECTION& aSelec } else { - VECTOR2I cursor = getView()->ToWorld( getViewControls()->GetCursorPosition() ); + VECTOR2I cursor = getViewControls()->GetCursorPosition(); return wxPoint( cursor.x, cursor.y ); } } @@ -459,20 +495,8 @@ wxPoint EDIT_TOOL::getModificationPoint( const SELECTION_TOOL::SELECTION& aSelec bool EDIT_TOOL::makeSelection( const SELECTION_TOOL::SELECTION& aSelection ) { - if( aSelection.Empty() ) - { - // Try to find an item that could be modified - m_toolMgr->RunAction( "pcbnew.InteractiveSelection.Single" ); + if( aSelection.Empty() ) // Try to find an item that could be modified + m_toolMgr->RunAction( COMMON_ACTIONS::selectionSingle ); - if( aSelection.Empty() ) - { - // This is necessary, so later the tool may be activated upon - // reception of the activation event - setTransitions(); - - return false; // Still no items to work with - } - } - - return true; + return !aSelection.Empty(); } diff --git a/pcbnew/tools/edit_tool.h b/pcbnew/tools/edit_tool.h index d31b159aa5..b5f6f1fc0d 100644 --- a/pcbnew/tools/edit_tool.h +++ b/pcbnew/tools/edit_tool.h @@ -101,7 +101,7 @@ private: ///> Removes and frees a single BOARD_ITEM. void remove( BOARD_ITEM* aItem ); - ///> Sets up handlers for various events + ///> Sets up handlers for various events. void setTransitions(); ///> The required update flag for modified items @@ -114,6 +114,9 @@ private: m_updateFlag = aFlag; } + ///> Updates ratsnest for selected items. + ///> @param aRedraw says if selected items should be drawn using the simple mode (e.g. one line + ///> per item). void updateRatsnest( bool aRedraw ); ///> Returns the right modification point (e.g. for rotation), depending on the number of diff --git a/pcbnew/tools/pcb_tools.cpp b/pcbnew/tools/pcb_tools.cpp index a4b4f21a24..0decc244d7 100644 --- a/pcbnew/tools/pcb_tools.cpp +++ b/pcbnew/tools/pcb_tools.cpp @@ -31,52 +31,62 @@ #include #include -#include +#include #include #include "selection_tool.h" #include "edit_tool.h" +#include "drawing_tool.h" +#include "point_editor.h" +#include "pcbnew_control.h" #include "common_actions.h" #include void PCB_EDIT_FRAME::setupTools() { // Create the manager and dispatcher & route draw panel events to the dispatcher - m_toolManager = new TOOL_MANAGER; - m_toolDispatcher = new TOOL_DISPATCHER( m_toolManager, this ); + m_toolManager = TOOL_MANAGER::Instance(); + m_toolDispatcher = new TOOL_DISPATCHER( &m_toolManager, this ); GetGalCanvas()->SetEventDispatcher( m_toolDispatcher ); - // Register tool actions - m_toolManager->RegisterAction( &COMMON_ACTIONS::selectionSingle ); - m_toolManager->RegisterAction( &COMMON_ACTIONS::selectionClear ); - m_toolManager->RegisterAction( &COMMON_ACTIONS::editActivate ); - m_toolManager->RegisterAction( &COMMON_ACTIONS::rotate ); - m_toolManager->RegisterAction( &COMMON_ACTIONS::flip ); - m_toolManager->RegisterAction( &COMMON_ACTIONS::remove ); - m_toolManager->RegisterAction( &COMMON_ACTIONS::properties ); + // Connect handlers to toolbar buttons +#if wxCHECK_VERSION( 3, 0, 0 ) + Connect( wxEVT_TOOL, wxCommandEventHandler( PCB_EDIT_FRAME::onGenericCommand ), NULL, this ); +#else + Connect( wxEVT_COMMAND_MENU_SELECTED, + wxCommandEventHandler( PCB_EDIT_FRAME::onGenericCommand ), NULL, this ); + Connect( wxEVT_COMMAND_TOOL_CLICKED, + wxCommandEventHandler( PCB_EDIT_FRAME::onGenericCommand ), NULL, this ); +#endif // Register tools - m_toolManager->RegisterTool( new SELECTION_TOOL ); - m_toolManager->RegisterTool( new ROUTER_TOOL ); - m_toolManager->RegisterTool( new EDIT_TOOL ); + m_toolManager.RegisterTool( new SELECTION_TOOL ); + m_toolManager.RegisterTool( new ROUTER_TOOL ); + m_toolManager.RegisterTool( new EDIT_TOOL ); + m_toolManager.RegisterTool( new DRAWING_TOOL ); + m_toolManager.RegisterTool( new POINT_EDITOR ); + m_toolManager.RegisterTool( new PCBNEW_CONTROL ); - m_toolManager->SetEnvironment( NULL, GetGalCanvas()->GetView(), - GetGalCanvas()->GetViewControls(), this ); - m_toolManager->ResetTools( TOOL_BASE::RUN ); + m_toolManager.SetEnvironment( NULL, GetGalCanvas()->GetView(), + GetGalCanvas()->GetViewControls(), this ); + m_toolManager.ResetTools( TOOL_BASE::RUN ); // Run the selection tool, it is supposed to be always active - m_toolManager->InvokeTool( "pcbnew.InteractiveSelection" ); + m_toolManager.InvokeTool( "pcbnew.InteractiveSelection" ); } void PCB_EDIT_FRAME::destroyTools() { - delete m_toolManager; + m_toolManager.DeleteAll(); delete m_toolDispatcher; } void PCB_EDIT_FRAME::onGenericCommand( wxCommandEvent& aEvent ) { - m_toolDispatcher->DispatchWxCommand( aEvent ); + if( IsGalCanvasActive() ) + m_toolDispatcher->DispatchWxCommand( aEvent ); + else + aEvent.Skip(); } diff --git a/pcbnew/tools/pcbnew_control.cpp b/pcbnew/tools/pcbnew_control.cpp new file mode 100644 index 0000000000..f01203178f --- /dev/null +++ b/pcbnew/tools/pcbnew_control.cpp @@ -0,0 +1,586 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014 CERN + * @author Maciej Suminski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "pcbnew_control.h" +#include "common_actions.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +PCBNEW_CONTROL::PCBNEW_CONTROL() : + TOOL_INTERACTIVE( "pcbnew.Control" ) +{ +} + + +void PCBNEW_CONTROL::Reset( RESET_REASON aReason ) +{ + m_frame = getEditFrame(); +} + + +bool PCBNEW_CONTROL::Init() +{ + setTransitions(); + + return true; +} + + +int PCBNEW_CONTROL::ZoomInOut( TOOL_EVENT& aEvent ) +{ + KIGFX::VIEW* view = m_frame->GetGalCanvas()->GetView(); + KIGFX::GAL* gal = m_frame->GetGalCanvas()->GetGAL(); + + if( aEvent.IsAction( &COMMON_ACTIONS::zoomIn ) ) + m_frame->SetPrevZoom(); + else if( aEvent.IsAction( &COMMON_ACTIONS::zoomOut ) ) + m_frame->SetNextZoom(); + + double zoomFactor = gal->GetWorldScale() / gal->GetZoomFactor(); + double zoom = 1.0 / ( zoomFactor * m_frame->GetZoom() ); + + view->SetScale( zoom, getViewControls()->GetCursorPosition() ); + setTransitions(); + + return 0; +} + + +int PCBNEW_CONTROL::ZoomInOutCenter( TOOL_EVENT& aEvent ) +{ + KIGFX::VIEW* view = m_frame->GetGalCanvas()->GetView(); + KIGFX::GAL* gal = m_frame->GetGalCanvas()->GetGAL(); + + if( aEvent.IsAction( &COMMON_ACTIONS::zoomInCenter ) ) + m_frame->SetPrevZoom(); + else if( aEvent.IsAction( &COMMON_ACTIONS::zoomOutCenter ) ) + m_frame->SetNextZoom(); + + double zoomFactor = gal->GetWorldScale() / gal->GetZoomFactor(); + double zoom = 1.0 / ( zoomFactor * m_frame->GetZoom() ); + + view->SetScale( zoom ); + setTransitions(); + + return 0; +} + + +int PCBNEW_CONTROL::ZoomCenter( TOOL_EVENT& aEvent ) +{ + KIGFX::VIEW* view = m_frame->GetGalCanvas()->GetView(); + view->SetCenter( getViewControls()->GetCursorPosition() ); + setTransitions(); + + return 0; +} + + +int PCBNEW_CONTROL::ZoomFitScreen( TOOL_EVENT& aEvent ) +{ + KIGFX::VIEW* view = m_frame->GetGalCanvas()->GetView(); + KIGFX::GAL* gal = m_frame->GetGalCanvas()->GetGAL(); + BOX2I boardBBox = getModel( PCB_T )->ViewBBox(); + VECTOR2I screenSize = gal->GetScreenPixelSize(); + + double iuPerX = screenSize.x ? boardBBox.GetWidth() / screenSize.x : 1.0; + double iuPerY = screenSize.y ? boardBBox.GetHeight() / screenSize.y : 1.0; + + double bestZoom = std::max( iuPerX, iuPerY ); + // This is needed to avoid "jumpy" zooms if first hot key was used and then mouse scroll + // (or other way round). + m_frame->GetScreen()->SetZoom( bestZoom ); + + double zoomFactor = gal->GetWorldScale() / gal->GetZoomFactor(); + double zoom = 1.0 / ( zoomFactor * bestZoom ); + + view->SetScale( zoom ); + view->SetCenter( boardBBox.Centre() ); + setTransitions(); + + return 0; +} + + +int PCBNEW_CONTROL::TrackDisplayMode( TOOL_EVENT& aEvent ) +{ + KIGFX::PCB_PAINTER* painter = + static_cast( m_frame->GetGalCanvas()->GetView()->GetPainter() ); + KIGFX::PCB_RENDER_SETTINGS* settings = + static_cast ( painter->GetSettings() ); + + // Apply new display options to the GAL canvas + DisplayOpt.DisplayPcbTrackFill = !DisplayOpt.DisplayPcbTrackFill; + m_frame->m_DisplayPcbTrackFill = DisplayOpt.DisplayPcbTrackFill; + settings->LoadDisplayOptions( DisplayOpt ); + + BOARD* board = getModel( PCB_T ); + for( TRACK* track = board->m_Track; track; track = track->Next() ) + track->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + + setTransitions(); + + return 0; +} + + +int PCBNEW_CONTROL::PadDisplayMode( TOOL_EVENT& aEvent ) +{ + wxCommandEvent dummy; + getEditFrame()->OnTogglePadDrawMode( dummy ); + setTransitions(); + + return 0; +} + + +int PCBNEW_CONTROL::ViaDisplayMode( TOOL_EVENT& aEvent ) +{ + KIGFX::PCB_PAINTER* painter = + static_cast( m_frame->GetGalCanvas()->GetView()->GetPainter() ); + KIGFX::PCB_RENDER_SETTINGS* settings = + static_cast ( painter->GetSettings() ); + + // Apply new display options to the GAL canvas + DisplayOpt.DisplayViaFill = !DisplayOpt.DisplayViaFill; + m_frame->m_DisplayViaFill = DisplayOpt.DisplayViaFill; + settings->LoadDisplayOptions( DisplayOpt ); + + BOARD* board = getModel( PCB_T ); + for( TRACK* track = board->m_Track; track; track = track->Next() ) + { + if( track->Type() == PCB_VIA_T ) + track->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + } + + setTransitions(); + + return 0; +} + + +int PCBNEW_CONTROL::HighContrastMode( TOOL_EVENT& aEvent ) +{ + KIGFX::PCB_PAINTER* painter = + static_cast( m_frame->GetGalCanvas()->GetView()->GetPainter() ); + KIGFX::PCB_RENDER_SETTINGS* settings = + static_cast ( painter->GetSettings() ); + + DisplayOpt.ContrastModeDisplay = !DisplayOpt.ContrastModeDisplay; + settings->LoadDisplayOptions( DisplayOpt ); + m_frame->SetHighContrastLayer( m_frame->GetActiveLayer() ); + + setTransitions(); + + return 0; +} + + +int PCBNEW_CONTROL::HighContrastInc( TOOL_EVENT& aEvent ) +{ + std::cout << __PRETTY_FUNCTION__ << std::endl; + setTransitions(); + + return 0; +} + + +int PCBNEW_CONTROL::HighContrastDec( TOOL_EVENT& aEvent ) +{ + std::cout << __PRETTY_FUNCTION__ << std::endl; + setTransitions(); + + return 0; +} + + +// Layer control +int PCBNEW_CONTROL::LayerTop( TOOL_EVENT& aEvent ) +{ + getEditFrame()->SwitchLayer( NULL, LAYER_N_FRONT ); + getEditFrame()->GetGalCanvas()->SetFocus(); + setTransitions(); + + return 0; +} + + +int PCBNEW_CONTROL::LayerInner1( TOOL_EVENT& aEvent ) +{ + getEditFrame()->SwitchLayer( NULL, LAYER_N_2 ); + getEditFrame()->GetGalCanvas()->SetFocus(); + setTransitions(); + + return 0; +} + + +int PCBNEW_CONTROL::LayerInner2( TOOL_EVENT& aEvent ) +{ + getEditFrame()->SwitchLayer( NULL, LAYER_N_3 ); + getEditFrame()->GetGalCanvas()->SetFocus(); + setTransitions(); + + return 0; +} + + +int PCBNEW_CONTROL::LayerInner3( TOOL_EVENT& aEvent ) +{ + getEditFrame()->SwitchLayer( NULL, LAYER_N_4 ); + getEditFrame()->GetGalCanvas()->SetFocus(); + setTransitions(); + + return 0; +} + + +int PCBNEW_CONTROL::LayerInner4( TOOL_EVENT& aEvent ) +{ + getEditFrame()->SwitchLayer( NULL, LAYER_N_5 ); + getEditFrame()->GetGalCanvas()->SetFocus(); + setTransitions(); + + return 0; +} + + +int PCBNEW_CONTROL::LayerInner5( TOOL_EVENT& aEvent ) +{ + getEditFrame()->SwitchLayer( NULL, LAYER_N_6 ); + getEditFrame()->GetGalCanvas()->SetFocus(); + setTransitions(); + + return 0; +} + + +int PCBNEW_CONTROL::LayerInner6( TOOL_EVENT& aEvent ) +{ + getEditFrame()->SwitchLayer( NULL, LAYER_N_7 ); + getEditFrame()->GetGalCanvas()->SetFocus(); + setTransitions(); + + return 0; +} + + +int PCBNEW_CONTROL::LayerBottom( TOOL_EVENT& aEvent ) +{ + getEditFrame()->SetActiveLayer( LAYER_N_BACK, true ); + getEditFrame()->GetGalCanvas()->SetFocus(); + setTransitions(); + + return 0; +} + + +int PCBNEW_CONTROL::LayerNext( TOOL_EVENT& aEvent ) +{ + PCB_EDIT_FRAME* editFrame = getEditFrame(); + LAYER_NUM layer = editFrame->GetActiveLayer(); + layer = ( layer + 1 ) % ( LAST_COPPER_LAYER + 1 ); + assert( IsCopperLayer( layer ) ); + + editFrame->SwitchLayer( NULL, layer ); + editFrame->GetGalCanvas()->SetFocus(); + setTransitions(); + + return 0; +} + + +int PCBNEW_CONTROL::LayerPrev( TOOL_EVENT& aEvent ) +{ + PCB_EDIT_FRAME* editFrame = getEditFrame(); + LAYER_NUM layer = editFrame->GetActiveLayer(); + + if( --layer < 0 ) + layer = LAST_COPPER_LAYER; + + assert( IsCopperLayer( layer ) ); + editFrame->SwitchLayer( NULL, layer ); + editFrame->GetGalCanvas()->SetFocus(); + setTransitions(); + + return 0; +} + + +int PCBNEW_CONTROL::LayerAlphaInc( TOOL_EVENT& aEvent ) +{ + KIGFX::PCB_PAINTER* painter = + static_cast( m_frame->GetGalCanvas()->GetView()->GetPainter() ); + KIGFX::PCB_RENDER_SETTINGS* settings = + static_cast ( painter->GetSettings() ); + + LAYER_NUM currentLayer = m_frame->GetActiveLayer(); + KIGFX::COLOR4D currentColor = settings->GetLayerColor( currentLayer ); + + if( currentColor.a <= 0.95 ) + { + currentColor.a += 0.05; + settings->SetLayerColor( currentLayer, currentColor ); + m_frame->GetGalCanvas()->GetView()->UpdateLayerColor( currentLayer ); + } + + setTransitions(); + + return 0; +} + + +int PCBNEW_CONTROL::LayerAlphaDec( TOOL_EVENT& aEvent ) +{ + KIGFX::PCB_PAINTER* painter = + static_cast( m_frame->GetGalCanvas()->GetView()->GetPainter() ); + KIGFX::PCB_RENDER_SETTINGS* settings = + static_cast ( painter->GetSettings() ); + + LAYER_NUM currentLayer = m_frame->GetActiveLayer(); + KIGFX::COLOR4D currentColor = settings->GetLayerColor( currentLayer ); + + if( currentColor.a >= 0.05 ) + { + currentColor.a -= 0.05; + settings->SetLayerColor( currentLayer, currentColor ); + m_frame->GetGalCanvas()->GetView()->UpdateLayerColor( currentLayer ); + } + + setTransitions(); + + return 0; +} + + +// Grid control +int PCBNEW_CONTROL::GridFast1( TOOL_EVENT& aEvent ) +{ + getEditFrame()->SetFastGrid1(); + setTransitions(); + + return 0; +} + + +int PCBNEW_CONTROL::GridFast2( TOOL_EVENT& aEvent ) +{ + getEditFrame()->SetFastGrid2(); + setTransitions(); + + return 0; +} + + +int PCBNEW_CONTROL::GridNext( TOOL_EVENT& aEvent ) +{ + getEditFrame()->SetNextGrid(); + setTransitions(); + + return 0; +} + + +int PCBNEW_CONTROL::GridPrev( TOOL_EVENT& aEvent ) +{ + getEditFrame()->SetPrevGrid(); + setTransitions(); + + return 0; +} + + +// Track & via size control +int PCBNEW_CONTROL::TrackWidthInc( TOOL_EVENT& aEvent ) +{ + BOARD* board = getModel( PCB_T ); + int widthIndex = board->GetTrackWidthIndex() + 1; + + if( widthIndex >= (int) board->m_TrackWidthList.size() ) + widthIndex = board->m_TrackWidthList.size() - 1; + + board->SetTrackWidthIndex( widthIndex ); + + wxUpdateUIEvent dummy; + getEditFrame()->OnUpdateSelectTrackWidth( dummy ); + setTransitions(); + + return 0; +} + + +int PCBNEW_CONTROL::TrackWidthDec( TOOL_EVENT& aEvent ) +{ + BOARD* board = getModel( PCB_T ); + int widthIndex = board->GetTrackWidthIndex() - 1; + + if( widthIndex < 0 ) + widthIndex = 0; + + board->SetTrackWidthIndex( widthIndex ); + + wxUpdateUIEvent dummy; + getEditFrame()->OnUpdateSelectTrackWidth( dummy ); + setTransitions(); + + return 0; +} + + +int PCBNEW_CONTROL::ViaSizeInc( TOOL_EVENT& aEvent ) +{ + BOARD* board = getModel( PCB_T ); + int sizeIndex = board->GetViaSizeIndex() + 1; + + if( sizeIndex >= (int) board->m_ViasDimensionsList.size() ) + sizeIndex = board->m_ViasDimensionsList.size() - 1; + + board->SetViaSizeIndex( sizeIndex ); + + wxUpdateUIEvent dummy; + getEditFrame()->OnUpdateSelectViaSize( dummy ); + setTransitions(); + + return 0; +} + + +int PCBNEW_CONTROL::ViaSizeDec( TOOL_EVENT& aEvent ) +{ + BOARD* board = getModel( PCB_T ); + int sizeIndex = board->GetViaSizeIndex() - 1; + + if( sizeIndex < 0 ) + sizeIndex = 0; + + board->SetViaSizeIndex( sizeIndex ); + + wxUpdateUIEvent dummy; + getEditFrame()->OnUpdateSelectViaSize( dummy ); + setTransitions(); + + return 0; +} + + +// Miscellaneous +int PCBNEW_CONTROL::ResetCoords( TOOL_EVENT& aEvent ) +{ + VECTOR2I cursorPos = getViewControls()->GetCursorPosition(); + + m_frame->GetScreen()->m_O_Curseur = wxPoint( cursorPos.x, cursorPos.y ); + m_frame->UpdateStatusBar(); + setTransitions(); + + return 0; +} + + +int PCBNEW_CONTROL::SwitchUnits( TOOL_EVENT& aEvent ) +{ + // TODO should not it be refactored to pcb_frame member function? + wxCommandEvent evt( wxEVT_COMMAND_MENU_SELECTED ); + + if( g_UserUnit == INCHES ) + evt.SetId( ID_TB_OPTIONS_SELECT_UNIT_MM ); + else + evt.SetId( ID_TB_OPTIONS_SELECT_UNIT_INCH ); + + m_frame->ProcessEvent( evt ); + setTransitions(); + + return 0; +} + + +int PCBNEW_CONTROL::ShowHelp( TOOL_EVENT& aEvent ) +{ + // TODO + DisplayInfoMessage( m_frame, _( "Not implemented yet." ) ); + setTransitions(); + + return 0; +} + + +void PCBNEW_CONTROL::setTransitions() +{ + // View controls + Go( &PCBNEW_CONTROL::ZoomInOut, COMMON_ACTIONS::zoomIn.MakeEvent() ); + Go( &PCBNEW_CONTROL::ZoomInOut, COMMON_ACTIONS::zoomOut.MakeEvent() ); + Go( &PCBNEW_CONTROL::ZoomInOutCenter, COMMON_ACTIONS::zoomInCenter.MakeEvent() ); + Go( &PCBNEW_CONTROL::ZoomInOutCenter, COMMON_ACTIONS::zoomOutCenter.MakeEvent() ); + Go( &PCBNEW_CONTROL::ZoomCenter, COMMON_ACTIONS::zoomCenter.MakeEvent() ); + Go( &PCBNEW_CONTROL::ZoomFitScreen, COMMON_ACTIONS::zoomFitScreen.MakeEvent() ); + + // Display modes + Go( &PCBNEW_CONTROL::TrackDisplayMode, COMMON_ACTIONS::trackDisplayMode.MakeEvent() ); + Go( &PCBNEW_CONTROL::PadDisplayMode, COMMON_ACTIONS::padDisplayMode.MakeEvent() ); + Go( &PCBNEW_CONTROL::ViaDisplayMode, COMMON_ACTIONS::viaDisplayMode.MakeEvent() ); + Go( &PCBNEW_CONTROL::HighContrastMode, COMMON_ACTIONS::highContrastMode.MakeEvent() ); + Go( &PCBNEW_CONTROL::HighContrastInc, COMMON_ACTIONS::highContrastInc.MakeEvent() ); + Go( &PCBNEW_CONTROL::HighContrastDec, COMMON_ACTIONS::highContrastDec.MakeEvent() ); + + // Layer control + Go( &PCBNEW_CONTROL::LayerTop, COMMON_ACTIONS::layerTop.MakeEvent() ); + Go( &PCBNEW_CONTROL::LayerInner1, COMMON_ACTIONS::layerInner1.MakeEvent() ); + Go( &PCBNEW_CONTROL::LayerInner2, COMMON_ACTIONS::layerInner2.MakeEvent() ); + Go( &PCBNEW_CONTROL::LayerInner3, COMMON_ACTIONS::layerInner3.MakeEvent() ); + Go( &PCBNEW_CONTROL::LayerInner4, COMMON_ACTIONS::layerInner4.MakeEvent() ); + Go( &PCBNEW_CONTROL::LayerInner5, COMMON_ACTIONS::layerInner5.MakeEvent() ); + Go( &PCBNEW_CONTROL::LayerInner6, COMMON_ACTIONS::layerInner6.MakeEvent() ); + Go( &PCBNEW_CONTROL::LayerBottom, COMMON_ACTIONS::layerBottom.MakeEvent() ); + Go( &PCBNEW_CONTROL::LayerNext, COMMON_ACTIONS::layerNext.MakeEvent() ); + Go( &PCBNEW_CONTROL::LayerPrev, COMMON_ACTIONS::layerPrev.MakeEvent() ); + Go( &PCBNEW_CONTROL::LayerAlphaInc, COMMON_ACTIONS::layerAlphaInc.MakeEvent() ); + Go( &PCBNEW_CONTROL::LayerAlphaDec , COMMON_ACTIONS::layerAlphaDec.MakeEvent() ); + + // Grid control + Go( &PCBNEW_CONTROL::GridFast1, COMMON_ACTIONS::gridFast1.MakeEvent() ); + Go( &PCBNEW_CONTROL::GridFast2, COMMON_ACTIONS::gridFast2.MakeEvent() ); + Go( &PCBNEW_CONTROL::GridNext, COMMON_ACTIONS::gridNext.MakeEvent() ); + Go( &PCBNEW_CONTROL::GridPrev, COMMON_ACTIONS::gridPrev.MakeEvent() ); + + // Track & via size control + Go( &PCBNEW_CONTROL::TrackWidthInc, COMMON_ACTIONS::trackWidthInc.MakeEvent() ); + Go( &PCBNEW_CONTROL::TrackWidthDec, COMMON_ACTIONS::trackWidthDec.MakeEvent() ); + Go( &PCBNEW_CONTROL::ViaSizeInc, COMMON_ACTIONS::viaSizeInc.MakeEvent() ); + Go( &PCBNEW_CONTROL::ViaSizeDec, COMMON_ACTIONS::viaSizeDec.MakeEvent() ); + + // Miscellaneous + Go( &PCBNEW_CONTROL::ResetCoords, COMMON_ACTIONS::resetCoords.MakeEvent() ); + Go( &PCBNEW_CONTROL::SwitchUnits, COMMON_ACTIONS::switchUnits.MakeEvent() ); + Go( &PCBNEW_CONTROL::ShowHelp, COMMON_ACTIONS::showHelp.MakeEvent() ); +} diff --git a/pcbnew/tools/pcbnew_control.h b/pcbnew/tools/pcbnew_control.h new file mode 100644 index 0000000000..8acc0fba8c --- /dev/null +++ b/pcbnew/tools/pcbnew_control.h @@ -0,0 +1,102 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014 CERN + * @author Maciej Suminski + * + * 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 + */ + +#ifndef PCBNEW_CONTROL_H +#define PCBNEW_CONTROL_H + +#include + +class PCB_EDIT_FRAME; + +/** + * Class PCBNEW_CONTROL + * + * Handles hot keys that are not accepted by any other tool. + */ + +class PCBNEW_CONTROL : public TOOL_INTERACTIVE +{ +public: + PCBNEW_CONTROL(); + + /// @copydoc TOOL_INTERACTIVE::Reset() + void Reset( RESET_REASON aReason ); + + /// @copydoc TOOL_INTERACTIVE::Init() + bool Init(); + + // View controls + int ZoomInOut( TOOL_EVENT& aEvent ); + int ZoomInOutCenter( TOOL_EVENT& aEvent ); + int ZoomCenter( TOOL_EVENT& aEvent ); + int ZoomFitScreen( TOOL_EVENT& aEvent ); + + // Display modes + int TrackDisplayMode( TOOL_EVENT& aEvent ); + int PadDisplayMode( TOOL_EVENT& aEvent ); + int ViaDisplayMode( TOOL_EVENT& aEvent ); + int HighContrastMode( TOOL_EVENT& aEvent ); + int HighContrastInc( TOOL_EVENT& aEvent ); + int HighContrastDec( TOOL_EVENT& aEvent ); + + // Layer control + int LayerTop( TOOL_EVENT& aEvent ); + int LayerInner1( TOOL_EVENT& aEvent ); + int LayerInner2( TOOL_EVENT& aEvent ); + int LayerInner3( TOOL_EVENT& aEvent ); + int LayerInner4( TOOL_EVENT& aEvent ); + int LayerInner5( TOOL_EVENT& aEvent ); + int LayerInner6( TOOL_EVENT& aEvent ); + int LayerBottom( TOOL_EVENT& aEvent ); + int LayerNext( TOOL_EVENT& aEvent ); + int LayerPrev( TOOL_EVENT& aEvent ); + int LayerAlphaInc( TOOL_EVENT& aEvent ); + int LayerAlphaDec( TOOL_EVENT& aEvent ); + + // Grid control + int GridFast1( TOOL_EVENT& aEvent ); + int GridFast2( TOOL_EVENT& aEvent ); + int GridNext( TOOL_EVENT& aEvent ); + int GridPrev( TOOL_EVENT& aEvent ); + + // Track & via size control + int TrackWidthInc( TOOL_EVENT& aEvent ); + int TrackWidthDec( TOOL_EVENT& aEvent ); + int ViaSizeInc( TOOL_EVENT& aEvent ); + int ViaSizeDec( TOOL_EVENT& aEvent ); + + // Miscellaneous + int ResetCoords( TOOL_EVENT& aEvent ); + int SwitchUnits( TOOL_EVENT& aEvent ); + int ShowHelp( TOOL_EVENT& aEvent ); + +private: + ///> Sets up handlers for various events. + void setTransitions(); + + ///> Pointerto the currently used edit frame. + PCB_EDIT_FRAME* m_frame; +}; + +#endif diff --git a/pcbnew/tools/point_editor.cpp b/pcbnew/tools/point_editor.cpp new file mode 100644 index 0000000000..f7e5b374c2 --- /dev/null +++ b/pcbnew/tools/point_editor.cpp @@ -0,0 +1,728 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 CERN + * @author Maciej Suminski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include "common_actions.h" +#include "selection_tool.h" +#include "point_editor.h" + +#include +#include +#include +#include +#include + +// Few constants to avoid using bare numbers for point indices +enum SEG_POINTS +{ + SEG_START, SEG_END +}; + +enum ARC_POINTS +{ + ARC_CENTER, ARC_START, ARC_END +}; + +enum CIRCLE_POINTS +{ + CIRC_CENTER, CIRC_END +}; + +enum DIMENSION_POINTS +{ + DIM_CROSSBARO, + DIM_CROSSBARF, + DIM_FEATUREGO, + DIM_FEATUREDO, +}; + + +class EDIT_POINTS_FACTORY +{ +public: + static boost::shared_ptr Make( EDA_ITEM* aItem, KIGFX::GAL* aGal ) + { + boost::shared_ptr points = boost::make_shared( aItem ); + + // Generate list of edit points basing on the item type + switch( aItem->Type() ) + { + case PCB_LINE_T: + { + const DRAWSEGMENT* segment = static_cast( aItem ); + + switch( segment->GetShape() ) + { + case S_SEGMENT: + points->AddPoint( segment->GetStart() ); + points->AddPoint( segment->GetEnd() ); + break; + + case S_ARC: + points->AddPoint( segment->GetCenter() ); + points->AddPoint( segment->GetArcStart() ); + points->AddPoint( segment->GetArcEnd() ); + + // Set constraints + // Arc end has to stay at the same radius as the start + points->Point( ARC_END ).SetConstraint( new EC_CIRCLE( points->Point( ARC_END ), + points->Point( ARC_CENTER ), + points->Point( ARC_START ) ) ); + break; + + case S_CIRCLE: + points->AddPoint( segment->GetCenter() ); + points->AddPoint( segment->GetEnd() ); + break; + + default: // suppress warnings + break; + } + + break; + } + + case PCB_ZONE_AREA_T: + { + const CPolyLine* outline = static_cast( aItem )->Outline(); + int cornersCount = outline->GetCornersCount(); + + for( int i = 0; i < cornersCount; ++i ) + points->AddPoint( outline->GetPos( i ) ); + + // Lines have to be added after creating edit points, + // as they use EDIT_POINT references + for( int i = 0; i < cornersCount - 1; ++i ) + { + points->AddLine( points->Point( i ), points->Point( i + 1 ) ); + points->Line( i ).SetConstraint( + new EC_SNAPLINE( points->Line( i ), + boost::bind( &KIGFX::GAL::GetGridPoint, aGal, _1 ) ) ); + } + + // The last missing line, connecting the last and the first polygon point + points->AddLine( points->Point( cornersCount - 1 ), points->Point( 0 ) ); + points->Line( points->LinesSize() - 1 ).SetConstraint( + new EC_SNAPLINE( points->Line( points->LinesSize() - 1 ), + boost::bind( &KIGFX::GAL::GetGridPoint, aGal, _1 ) ) ); + break; + } + + case PCB_DIMENSION_T: + { + const DIMENSION* dimension = static_cast( aItem ); + + points->AddPoint( dimension->m_crossBarO ); + points->AddPoint( dimension->m_crossBarF ); + points->AddPoint( dimension->m_featureLineGO ); + points->AddPoint( dimension->m_featureLineDO ); + + // Dimension height setting - edit points should move only along the feature lines + points->Point( DIM_CROSSBARO ).SetConstraint( new EC_LINE( points->Point( DIM_CROSSBARO ), + points->Point( DIM_FEATUREGO ) ) ); + points->Point( DIM_CROSSBARF ).SetConstraint( new EC_LINE( points->Point( DIM_CROSSBARF ), + points->Point( DIM_FEATUREDO ) ) ); + + break; + } + + default: + points.reset(); + break; + } + + return points; + } + +private: + EDIT_POINTS_FACTORY() {}; +}; + + +POINT_EDITOR::POINT_EDITOR() : + TOOL_INTERACTIVE( "pcbnew.PointEditor" ), m_selectionTool( NULL ), m_dragPoint( NULL ), + m_original( VECTOR2I( 0, 0 ) ), m_altConstrainer( VECTOR2I( 0, 0 ) ) +{ +} + + +void POINT_EDITOR::Reset( RESET_REASON aReason ) +{ + m_editPoints.reset(); + m_altConstraint.reset(); +} + + +bool POINT_EDITOR::Init() +{ + // Find the selection tool, so they can cooperate + m_selectionTool = static_cast( m_toolMgr->FindTool( "pcbnew.InteractiveSelection" ) ); + + if( !m_selectionTool ) + { + DisplayError( NULL, wxT( "pcbnew.InteractiveSelection tool is not available" ) ); + return false; + } + + setTransitions(); + + return true; +} + + +int POINT_EDITOR::OnSelectionChange( TOOL_EVENT& aEvent ) +{ + const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); + + if( selection.Size() == 1 ) + { + Activate(); + + KIGFX::VIEW_CONTROLS* controls = getViewControls(); + KIGFX::VIEW* view = getView(); + PCB_EDIT_FRAME* editFrame = getEditFrame(); + EDA_ITEM* item = selection.items.GetPickedItem( 0 ); + + m_editPoints = EDIT_POINTS_FACTORY::Make( item, m_toolMgr->GetView()->GetGAL() ); + if( !m_editPoints ) + { + setTransitions(); + return 0; + } + + view->Add( m_editPoints.get() ); + m_dragPoint = NULL; + bool modified = false; + + // Main loop: keep receiving events + while( OPT_TOOL_EVENT evt = Wait() ) + { + if( !m_editPoints || + evt->Matches( m_selectionTool->ClearedEvent ) || + evt->Matches( m_selectionTool->DeselectedEvent ) || + evt->Matches( m_selectionTool->SelectedEvent ) ) + { + break; + } + + if( evt->IsMotion() ) + { + EDIT_POINT* point = m_editPoints->FindPoint( evt->Position() ); + + if( m_dragPoint != point ) + { + if( point ) + { + controls->ShowCursor( true ); + controls->SetSnapping( true ); + controls->ForceCursorPosition( true, point->GetPosition() ); + } + else + { + controls->ShowCursor( false ); + controls->SetSnapping( false ); + controls->ForceCursorPosition( false ); + } + } + + m_dragPoint = point; + } + + else if( evt->IsDblClick( BUT_LEFT ) ) + { + breakOutline( controls->GetCursorPosition() ); + } + + else if( evt->IsDrag( BUT_LEFT ) && m_dragPoint ) + { + if( !modified ) + { + // Save items, so changes can be undone + editFrame->OnModify(); + editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED ); + controls->ForceCursorPosition( false ); + m_original = *m_dragPoint; // Save the original position + controls->SetAutoPan( true ); + modified = true; + } + + bool enableAltConstraint = !!evt->Modifier( MD_CTRL ); + if( enableAltConstraint != (bool) m_altConstraint ) // alternative constraint + setAltConstraint( enableAltConstraint ); + + m_dragPoint->SetPosition( controls->GetCursorPosition() ); + + if( m_altConstraint ) + m_altConstraint->Apply(); + else + m_dragPoint->ApplyConstraint(); + + updateItem(); + updatePoints(); + + m_editPoints->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + } + + else if( evt->IsAction( &COMMON_ACTIONS::pointEditorUpdate ) ) + { + updatePoints(); + } + + else if( evt->IsMouseUp( BUT_LEFT ) ) + { + controls->SetAutoPan( false ); + setAltConstraint( false ); + modified = false; + } + + else if( evt->IsCancel() ) + { + if( modified ) // Restore the last change + { + wxCommandEvent dummy; + editFrame->GetBoardFromUndoList( dummy ); + + updatePoints(); + modified = false; + } + + // Let the selection tool receive the event too + m_toolMgr->PassEvent(); + + break; + } + + else + { + m_toolMgr->PassEvent(); + } + } + + if( m_editPoints ) + { + finishItem(); + item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + view->Remove( m_editPoints.get() ); + m_editPoints.reset(); + } + + controls->ShowCursor( false ); + controls->SetAutoPan( false ); + controls->SetSnapping( false ); + controls->ForceCursorPosition( false ); + } + + setTransitions(); + + return 0; +} + + +void POINT_EDITOR::updateItem() const +{ + EDA_ITEM* item = m_editPoints->GetParent(); + + switch( item->Type() ) + { + case PCB_LINE_T: + { + DRAWSEGMENT* segment = static_cast( 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; + } + + break; + } + + case PCB_ZONE_AREA_T: + { + ZONE_CONTAINER* zone = static_cast( item ); + zone->ClearFilledPolysList(); + CPolyLine* outline = zone->Outline(); + + for( int i = 0; i < outline->GetCornersCount(); ++i ) + { + outline->SetX( i, m_editPoints->Point( i ).GetPosition().x ); + outline->SetY( i, m_editPoints->Point( i ).GetPosition().y ); + } + + break; + } + + case PCB_DIMENSION_T: + { + DIMENSION* dimension = static_cast( item ); + + // Check which point is currently modified and updated dimension's points respectively + if( isModified( m_editPoints->Point( DIM_CROSSBARO ) ) ) + { + VECTOR2D featureLine( m_dragPoint->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_dragPoint->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_dragPoint->GetPosition().x, m_dragPoint->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_dragPoint->GetPosition().x, m_dragPoint->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; + } +} + + +void POINT_EDITOR::finishItem() const +{ + EDA_ITEM* item = m_editPoints->GetParent(); + + if( item->Type() == PCB_ZONE_AREA_T ) + { + ZONE_CONTAINER* zone = static_cast( item ); + + if( zone->IsFilled() ) + getEditFrame()->Fill_Zone( zone ); + } +} + + +void POINT_EDITOR::updatePoints() const +{ + EDA_ITEM* item = m_editPoints->GetParent(); + + switch( item->Type() ) + { + case PCB_LINE_T: + { + const DRAWSEGMENT* segment = static_cast( item ); + { + switch( segment->GetShape() ) + { + case S_SEGMENT: + m_editPoints->Point( SEG_START ).SetPosition( segment->GetStart() ); + m_editPoints->Point( SEG_END ).SetPosition( segment->GetEnd() ); + break; + + case S_ARC: + m_editPoints->Point( ARC_CENTER ).SetPosition( segment->GetCenter() ); + m_editPoints->Point( ARC_START).SetPosition( segment->GetArcStart() ); + m_editPoints->Point( ARC_END ).SetPosition( segment->GetArcEnd() ); + break; + + case S_CIRCLE: + m_editPoints->Point( CIRC_CENTER ).SetPosition( segment->GetCenter() ); + m_editPoints->Point( CIRC_END ).SetPosition( segment->GetEnd() ); + break; + + default: // suppress warnings + break; + } + + break; + } + } + + case PCB_ZONE_AREA_T: + { + const ZONE_CONTAINER* zone = static_cast( item ); + const CPolyLine* outline = zone->Outline(); + + for( int i = 0; i < outline->GetCornersCount(); ++i ) + m_editPoints->Point( i ).SetPosition( outline->GetPos( i ) ); + + break; + } + + case PCB_DIMENSION_T: + { + const DIMENSION* dimension = static_cast( item ); + + m_editPoints->Point( DIM_CROSSBARO ).SetPosition( dimension->m_crossBarO ); + m_editPoints->Point( DIM_CROSSBARF ).SetPosition( dimension->m_crossBarF ); + m_editPoints->Point( DIM_FEATUREGO ).SetPosition( dimension->m_featureLineGO ); + m_editPoints->Point( DIM_FEATUREDO ).SetPosition( dimension->m_featureLineDO ); + break; + } + + default: + break; + } +} + + +void POINT_EDITOR::setAltConstraint( bool aEnabled ) +{ + if( aEnabled ) + { + EDIT_LINE* line = dynamic_cast( m_dragPoint ); + + if( line ) + { + if( m_editPoints->GetParent()->Type() == PCB_ZONE_AREA_T ) + m_altConstraint.reset( (EDIT_CONSTRAINT*)( new EC_CONVERGING( *line, *m_editPoints ) ) ); + } + else + { + // Find a proper constraining point for 45 degrees mode + m_altConstrainer = get45DegConstrainer(); + m_altConstraint.reset( new EC_45DEGREE( *m_dragPoint, m_altConstrainer ) ); + } + } + else + { + m_altConstraint.reset(); + } +} + + +EDIT_POINT POINT_EDITOR::get45DegConstrainer() const +{ + EDA_ITEM* item = m_editPoints->GetParent(); + + switch( item->Type() ) + { + case PCB_LINE_T: + { + const DRAWSEGMENT* segment = static_cast( item ); + { + switch( segment->GetShape() ) + { + case S_SEGMENT: + return *( m_editPoints->Next( *m_dragPoint ) ); // select the other end of line + + case S_ARC: + case S_CIRCLE: + return m_editPoints->Point( CIRC_CENTER ); + + default: // suppress warnings + break; + } + } + + break; + } + + case PCB_DIMENSION_T: + { + // Constraint for crossbar + if( isModified( m_editPoints->Point( DIM_FEATUREGO ) ) ) + return m_editPoints->Point( DIM_FEATUREDO ); + + else if( isModified( m_editPoints->Point( DIM_FEATUREDO ) ) ) + return m_editPoints->Point( DIM_FEATUREGO ); + + else + return EDIT_POINT( m_dragPoint->GetPosition() ); // no constraint + + break; + } + + default: + break; + } + + // In any other case we may align item to its original position + return m_original; +} + + +void POINT_EDITOR::breakOutline( const VECTOR2I& aBreakPoint ) +{ + EDA_ITEM* item = m_editPoints->GetParent(); + const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); + + if( item->Type() == PCB_ZONE_AREA_T ) + { + getEditFrame()->OnModify(); + getEditFrame()->SaveCopyInUndoList( selection.items, UR_CHANGED ); + + ZONE_CONTAINER* zone = static_cast( 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 ) + { + getEditFrame()->OnModify(); + getEditFrame()->SaveCopyInUndoList( selection.items, UR_CHANGED ); + + DRAWSEGMENT* segment = static_cast( 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 = new DRAWSEGMENT( *segment ); + newSegment->ClearSelected(); + newSegment->SetStart( wxPoint( nearestPoint.x, nearestPoint.y ) ); + newSegment->SetEnd( wxPoint( seg.B.x, seg.B.y ) ); + + getModel( PCB_T )->Add( newSegment ); + getView()->Add( newSegment ); + } + } +} diff --git a/pcbnew/tools/point_editor.h b/pcbnew/tools/point_editor.h new file mode 100644 index 0000000000..b87224f613 --- /dev/null +++ b/pcbnew/tools/point_editor.h @@ -0,0 +1,109 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 CERN + * @author Maciej Suminski + * + * 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 + */ + +#ifndef __POINT_EDITOR_H +#define __POINT_EDITOR_H + +#include + +#include +#include "edit_points.h" + +class SELECTION_TOOL; + +/** + * Class POINT_EDITOR + * + * Tool that displays edit points allowing to modify items by dragging the points. + */ +class POINT_EDITOR : public TOOL_INTERACTIVE +{ +public: + POINT_EDITOR(); + + /// @copydoc TOOL_INTERACTIVE::Reset() + void Reset( RESET_REASON aReason ); + + /// @copydoc TOOL_INTERACTIVE::Init() + bool Init(); + + /** + * Function OnSelected() + * + * Change selection event handler. + */ + int OnSelectionChange( TOOL_EVENT& aEvent ); + +private: + ///> Selection tool used for obtaining selected items + SELECTION_TOOL* m_selectionTool; + + ///> Currently edited point, NULL if there is none. + EDIT_POINT* m_dragPoint; + + ///> Original position for the current drag point. + EDIT_POINT m_original; + + ///> Currently available edit points. + boost::shared_ptr m_editPoints; + + // Alternative constraint, enabled while a modifier key is held + boost::shared_ptr > m_altConstraint; + + // EDIT_POINT for alternative constraint mode + EDIT_POINT m_altConstrainer; + + ///> Updates item's points with edit points. + void updateItem() const; + + ///> Applies the last changes to the edited item. + void finishItem() const; + + ///> Updates edit points with item's points. + void updatePoints() const; + + ///> Returns true if aPoint is the currently modified point. + inline bool isModified( const EDIT_POINT& aPoint ) const + { + return m_dragPoint == &aPoint; + } + + ///> Sets up an alternative constraint (typically enabled upon a modifier key being pressed). + void setAltConstraint( bool aEnabled ); + + ///> Returns a point that should be used as a constrainer for 45 degrees mode. + EDIT_POINT get45DegConstrainer() const; + + ///> Adds a new edit point on a zone outline. + void breakOutline( const VECTOR2I& aBreakPoint ); + + ///> Sets up handlers for various events. + void setTransitions() + { + Go( &POINT_EDITOR::OnSelectionChange, m_selectionTool->SelectedEvent ); + Go( &POINT_EDITOR::OnSelectionChange, m_selectionTool->DeselectedEvent ); + } +}; + +#endif diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index d5d85b5431..2511cb687e 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -25,9 +25,10 @@ #include #include +#include #include -#include +#include #include #include #include @@ -50,7 +51,11 @@ using boost::optional; SELECTION_TOOL::SELECTION_TOOL() : - TOOL_INTERACTIVE( "pcbnew.InteractiveSelection" ), m_additive( false ), m_multiple( false ) + TOOL_INTERACTIVE( "pcbnew.InteractiveSelection" ), + SelectedEvent( TC_MESSAGE, TA_ACTION, "pcbnew.InteractiveSelection.selected" ), + DeselectedEvent( TC_MESSAGE, TA_ACTION, "pcbnew.InteractiveSelection.deselected" ), + ClearedEvent( TC_MESSAGE, TA_ACTION, "pcbnew.InteractiveSelection.cleared" ), + m_additive( false ), m_multiple( false ) { m_selArea = new SELECTION_AREA; m_selection.group = new KIGFX::VIEW_GROUP; @@ -94,6 +99,7 @@ int SELECTION_TOOL::Main( TOOL_EVENT& aEvent ) if( evt->IsAction( &COMMON_ACTIONS::selectionSingle ) ) { + // GetMousePosition() is used, as it is independent of snapping settings selectSingle( getView()->ToWorld( getViewControls()->GetMousePosition() ) ); } @@ -106,10 +112,17 @@ int SELECTION_TOOL::Main( TOOL_EVENT& aEvent ) // single click? Select single object else if( evt->IsClick( BUT_LEFT ) ) { - if( !m_additive ) - clearSelection(); + if( evt->Modifier( MD_CTRL ) ) + { + highlightNet( evt->Position() ); + } + else + { + if( !m_additive ) + clearSelection(); - selectSingle( evt->Position() ); + selectSingle( evt->Position() ); + } } // right click? if there is any object - show the context menu @@ -128,7 +141,7 @@ int SELECTION_TOOL::Main( TOOL_EVENT& aEvent ) if( m_selection.Empty() ) selectSingle( evt->Position() ); - m_toolMgr->RunAction( "pcbnew.InteractiveEdit.properties" ); + m_toolMgr->RunAction( COMMON_ACTIONS::properties ); } // drag with LMB? Select multiple objects (or at least draw a selection box) or drag them @@ -136,14 +149,22 @@ int SELECTION_TOOL::Main( TOOL_EVENT& aEvent ) { if( m_selection.Empty() || m_additive ) { - // If nothings has been selected or user wants to select more - // draw the selection box - selectMultiple(); + if( !selectSingle( getView()->ToWorld( getViewControls()->GetMousePosition() ), false ) ) + { + // If nothings has been selected or user wants to select more + // draw the selection box + selectMultiple(); + } + else + { + m_toolMgr->InvokeTool( "pcbnew.InteractiveEdit" ); + } } + else { // Check if dragging has started within any of selected items bounding box - if( containsSelected( evt->Position() ) ) + if( selectionContains( evt->Position() ) ) { // Yes -> run the move tool and wait till it finishes m_toolMgr->InvokeTool( "pcbnew.InteractiveEdit" ); @@ -177,6 +198,10 @@ void SELECTION_TOOL::toggleSelection( BOARD_ITEM* aItem ) if( aItem->IsSelected() ) { deselect( aItem ); + + // Inform other potentially interested tools + TOOL_EVENT deselectEvent( DeselectedEvent ); + m_toolMgr->ProcessEvent( deselectEvent ); } else { @@ -185,12 +210,18 @@ void SELECTION_TOOL::toggleSelection( BOARD_ITEM* aItem ) // Prevent selection of invisible or inactive items if( selectable( aItem ) ) + { select( aItem ); + + // Inform other potentially interested tools + TOOL_EVENT selectEvent( SelectedEvent ); + m_toolMgr->ProcessEvent( selectEvent ); + } } } -void SELECTION_TOOL::selectSingle( const VECTOR2I& aWhere ) +bool SELECTION_TOOL::selectSingle( const VECTOR2I& aWhere, bool aAllowDisambiguation ) { BOARD* pcb = getModel( PCB_T ); BOARD_ITEM* item; @@ -205,15 +236,17 @@ void SELECTION_TOOL::selectSingle( const VECTOR2I& aWhere ) case 0: if( !m_additive ) clearSelection(); - break; + + return false; case 1: toggleSelection( collector[0] ); - break; + + return true; default: // Remove unselectable items - for( int i = collector.GetCount() - 1; i >= 0 ; --i ) + for( int i = collector.GetCount() - 1; i >= 0; --i ) { if( !selectable( collector[i] ) ) collector.Remove( i ); @@ -223,17 +256,25 @@ void SELECTION_TOOL::selectSingle( const VECTOR2I& aWhere ) if( collector.GetCount() == 1 ) { toggleSelection( collector[0] ); + + return true; } - else if( collector.GetCount() > 1 ) + + else if( aAllowDisambiguation && collector.GetCount() > 1 ) { item = disambiguationMenu( &collector ); if( item ) + { toggleSelection( item ); - } + return true; + } + } break; } + + return false; } @@ -283,13 +324,23 @@ bool SELECTION_TOOL::selectMultiple() BOARD_ITEM* item = static_cast( it->first ); // Add only those items that are visible and fully within the selection box - if( !item->IsSelected() && selectable( item ) && selectionBox.Contains( item->ViewBBox() ) ) + if( !item->IsSelected() && selectable( item ) && + selectionBox.Contains( item->ViewBBox() ) ) + { select( item ); + } } // Do not display information about selected item,as there is more than one getEditFrame()->SetCurItem( NULL ); + if( !m_selection.Empty() ) + { + // Inform other potentially interested tools + TOOL_EVENT selectEvent( SelectedEvent ); + m_toolMgr->ProcessEvent( selectEvent ); + } + break; // Stop waiting for events } } @@ -320,6 +371,13 @@ void SELECTION_TOOL::clearSelection() m_selection.clear(); getEditFrame()->SetCurItem( NULL ); + + // Do not show the context menu when there is nothing selected + SetContextMenu( &m_menu, CMENU_OFF ); + + // Inform other potentially interested tools + TOOL_EVENT clearEvent( ClearedEvent ); + m_toolMgr->ProcessEvent( clearEvent ); } @@ -358,7 +416,9 @@ BOARD_ITEM* SELECTION_TOOL::disambiguationMenu( GENERAL_COLLECTOR* aCollector ) current->SetBrightened(); } else + { current = NULL; + } } else if( evt->Action() == TA_CONTEXT_MENU_CHOICE ) { @@ -504,7 +564,7 @@ void SELECTION_TOOL::select( BOARD_ITEM* aItem ) if( aItem->Type() == PCB_MODULE_T ) { MODULE* module = static_cast( aItem ); - module->RunOnChildren( std::bind1st( std::mem_fun( &SELECTION_TOOL::selectVisually ), this ) ); + module->RunOnChildren( boost::bind( &SELECTION_TOOL::selectVisually, this, _1 ) ); } selectVisually( aItem ); @@ -516,6 +576,9 @@ void SELECTION_TOOL::select( BOARD_ITEM* aItem ) { // Set as the current item, so the information about selection is displayed getEditFrame()->SetCurItem( aItem, true ); + + // Now the context menu should be enabled + SetContextMenu( &m_menu, CMENU_BUTTON ); } else if( m_selection.Size() == 2 ) // Check only for 2, so it will not be { // called for every next selected item @@ -532,7 +595,7 @@ void SELECTION_TOOL::deselect( BOARD_ITEM* aItem ) if( aItem->Type() == PCB_MODULE_T ) { MODULE* module = static_cast( aItem ); - module->RunOnChildren( std::bind1st( std::mem_fun( &SELECTION_TOOL::deselectVisually ), this ) ); + module->RunOnChildren( boost::bind( &SELECTION_TOOL::deselectVisually, this, _1 ) ); } deselectVisually( aItem ); @@ -543,7 +606,14 @@ void SELECTION_TOOL::deselect( BOARD_ITEM* aItem ) // If there is nothing selected, disable the context menu if( m_selection.Empty() ) + { + SetContextMenu( &m_menu, CMENU_OFF ); getEditFrame()->SetCurItem( NULL ); + } + + // Inform other potentially interested tools + TOOL_EVENT deselected( DeselectedEvent ); + m_toolMgr->ProcessEvent( deselected ); } @@ -567,7 +637,7 @@ void SELECTION_TOOL::deselectVisually( BOARD_ITEM* aItem ) const } -bool SELECTION_TOOL::containsSelected( const VECTOR2I& aPoint ) const +bool SELECTION_TOOL::selectionContains( const VECTOR2I& aPoint ) const { const unsigned GRIP_MARGIN = 20; VECTOR2D margin = getView()->ToWorld( VECTOR2D( GRIP_MARGIN, GRIP_MARGIN ), false ); @@ -587,6 +657,30 @@ bool SELECTION_TOOL::containsSelected( const VECTOR2I& aPoint ) const } +void SELECTION_TOOL::highlightNet( const VECTOR2I& aPoint ) +{ + KIGFX::RENDER_SETTINGS* render = getView()->GetPainter()->GetSettings(); + GENERAL_COLLECTORS_GUIDE guide = getEditFrame()->GetCollectorsGuide(); + GENERAL_COLLECTOR collector; + int net = -1; + + // Find a connected item for which we are going to highlight a net + collector.Collect( getModel( PCB_T ), GENERAL_COLLECTOR::PadsTracksOrZones, + wxPoint( aPoint.x, aPoint.y ), guide ); + bool enableHighlight = ( collector.GetCount() > 0 ); + + // Obtain net code for the clicked item + if( enableHighlight ) + net = static_cast( collector[0] )->GetNetCode(); + + if( enableHighlight != render->GetHighlight() || net != render->GetHighlightNetCode() ) + { + render->SetHighlight( enableHighlight, net ); + getView()->UpdateAllLayersColor(); + } +} + + void SELECTION_TOOL::SELECTION::clear() { items.ClearItemsList(); diff --git a/pcbnew/tools/selection_tool.h b/pcbnew/tools/selection_tool.h index 4c5e4b2d9a..609fcafda5 100644 --- a/pcbnew/tools/selection_tool.h +++ b/pcbnew/tools/selection_tool.h @@ -114,6 +114,15 @@ public: */ void AddMenuItem( const TOOL_ACTION& aAction ); + ///> Event sent after an item is selected. + const TOOL_EVENT SelectedEvent; + + ///> Event sent after an item is deselected. + const TOOL_EVENT DeselectedEvent; + + ///> Event sent after selection is cleared. + const TOOL_EVENT ClearedEvent; + private: /** * Function selectSingle() @@ -121,8 +130,11 @@ private: * place, there is a menu displayed that allows to choose the item. * * @param aWhere is the place where the item should be selected. + * @param aAllowDisambiguation decides what to do in case of disambiguation. If true, then + * a menu is shown, otherise function finishes without selecting anything. + * @return True if an item was selected, false otherwise. */ - void selectSingle( const VECTOR2I& aWhere ); + bool selectSingle( const VECTOR2I& aWhere, bool aAllowDisambiguation = true ); /** * Function selectMultiple() @@ -207,7 +219,15 @@ private: * * @return True if the given point is contained in any of selected items' bouding box. */ - bool containsSelected( const VECTOR2I& aPoint ) const; + bool selectionContains( const VECTOR2I& aPoint ) const; + + /** + * Function highlightNet() + * Looks for a BOARD_CONNECTED_ITEM in a given spot, and if one is found - it enables + * highlight for its net. + * @param aPoint is the point where an item is expected (world coordinates). + */ + void highlightNet( const VECTOR2I& aPoint ); /// Visual representation of selection box SELECTION_AREA* m_selArea; diff --git a/pcbnew/zone_filling_algorithm.cpp b/pcbnew/zone_filling_algorithm.cpp index 04da8e2fdc..aadcc66c2a 100644 --- a/pcbnew/zone_filling_algorithm.cpp +++ b/pcbnew/zone_filling_algorithm.cpp @@ -54,8 +54,7 @@ * to add holes for pads and tracks and other items not in net. */ -bool ZONE_CONTAINER::BuildFilledSolidAreasPolygons( BOARD* aPcb, - CPOLYGONS_LIST* aCornerBuffer ) +bool ZONE_CONTAINER::BuildFilledSolidAreasPolygons( BOARD* aPcb, CPOLYGONS_LIST* aCornerBuffer ) { if( aCornerBuffer == NULL ) m_FilledPolysList.RemoveAllContours(); @@ -80,9 +79,11 @@ bool ZONE_CONTAINER::BuildFilledSolidAreasPolygons( BOARD* aPcb, case ZONE_SETTINGS::SMOOTHING_CHAMFER: m_smoothedPoly = m_Poly->Chamfer( m_cornerRadius ); break; + case ZONE_SETTINGS::SMOOTHING_FILLET: m_smoothedPoly = m_Poly->Fillet( m_cornerRadius, m_ArcToSegmentsCount ); break; + default: m_smoothedPoly = new CPolyLine; m_smoothedPoly->Copy( m_Poly ); @@ -90,18 +91,16 @@ bool ZONE_CONTAINER::BuildFilledSolidAreasPolygons( BOARD* aPcb, } if( aCornerBuffer ) - ConvertPolysListWithHolesToOnePolygon( m_smoothedPoly->m_CornersList, - *aCornerBuffer ); + ConvertPolysListWithHolesToOnePolygon( m_smoothedPoly->m_CornersList, *aCornerBuffer ); else - ConvertPolysListWithHolesToOnePolygon( m_smoothedPoly->m_CornersList, - m_FilledPolysList ); + ConvertPolysListWithHolesToOnePolygon( m_smoothedPoly->m_CornersList, m_FilledPolysList ); /* For copper layers, we now must add holes in the Polygon list. * holes are pads and tracks with their clearance area * for non copper layers just recalculate the m_FilledPolysList * with m_ZoneMinThickness taken in account */ - if( ! aCornerBuffer ) + if( !aCornerBuffer ) { if( IsOnCopperLayer() ) AddClearanceAreasPolygonsToPolysList( aPcb ); @@ -124,16 +123,19 @@ bool ZONE_CONTAINER::BuildFilledSolidAreasPolygons( BOARD* aPcb, m_FilledPolysList.RemoveAllContours(); CopyPolygonsFromKiPolygonListToFilledPolysList( polyset_zone_solid_areas ); } - if ( m_FillMode ) // if fill mode uses segments, create them: - FillZoneAreasWithSegments( ); + + if( m_FillMode ) // if fill mode uses segments, create them: + FillZoneAreasWithSegments(); } + m_IsFilled = true; + return 1; } // Sort function to build filled zones -static bool SortByXValues( const int& a, const int &b) +static bool SortByXValues( const int& a, const int &b ) { return a < b; } @@ -141,13 +143,11 @@ static bool SortByXValues( const int& a, const int &b) int ZONE_CONTAINER::FillZoneAreasWithSegments() { - int ics, ice; + int ics, ice; int count = 0; std::vector x_coordinates; bool error = false; - - int istart, iend; // index of the starting and the endif corner of one filled area in m_FilledPolysList - + int istart, iend; // index of the starting and the endif corner of one filled area in m_FilledPolysList int margin = m_ZoneMinThickness * 2 / 10; int minwidth = Mils2iu( 2 ); margin = std::max ( minwidth, margin ); @@ -157,28 +157,25 @@ int ZONE_CONTAINER::FillZoneAreasWithSegments() // Read all filled areas in m_FilledPolysList m_FillSegmList.clear(); istart = 0; - int end_list = m_FilledPolysList.GetCornersCount()-1; + int end_list = m_FilledPolysList.GetCornersCount() - 1; for( int ic = 0; ic <= end_list; ic++ ) { CPolyPt* corner = &m_FilledPolysList[ic]; - if ( corner->end_contour || (ic == end_list) ) + if ( corner->end_contour || ( ic == end_list ) ) { iend = ic; EDA_RECT rect = CalculateSubAreaBoundaryBox( istart, iend ); // Calculate the y limits of the zone - int refy = rect.GetY(); - int endy = rect.GetBottom(); - - for( ; refy < endy; refy += step ) + for( int refy = rect.GetY(), endy = rect.GetBottom(); refy < endy; refy += step ) { // find all intersection points of an infinite line with polyline sides x_coordinates.clear(); for( ics = istart, ice = iend; ics <= iend; ice = ics, ics++ ) { - if ( m_FilledPolysList[ice].m_utility ) + if( m_FilledPolysList[ice].m_utility ) continue; int seg_startX = m_FilledPolysList[ics].x; @@ -203,7 +200,7 @@ int ZONE_CONTAINER::FillZoneAreasWithSegments() // the segment start point: seg_endX -= seg_startX; seg_endY -= seg_startY; - double newrefy = (double) (refy - seg_startY); + double newrefy = (double) ( refy - seg_startY ); double intersec_x; if ( seg_endY == 0 ) // horizontal segment on the same line: skip @@ -217,9 +214,9 @@ int ZONE_CONTAINER::FillZoneAreasWithSegments() // intersec_x = refy/slope = refy * inv_slope // Note: because horizontal segments are already tested and skipped, slope // exists (seg_end_y not O) - double inv_slope = (double)seg_endX / seg_endY; + double inv_slope = (double) seg_endX / seg_endY; intersec_x = newrefy * inv_slope; - x_coordinates.push_back((int) intersec_x + seg_startX); + x_coordinates.push_back( (int) intersec_x + seg_startX ); } // A line scan is finished: build list of segments @@ -239,12 +236,12 @@ int ZONE_CONTAINER::FillZoneAreasWithSegments() error = true; } - if ( error ) + if( error ) break; - int iimax = x_coordinates.size()-1; + int iimax = x_coordinates.size() - 1; - for (int ii = 0; ii < iimax; ii +=2 ) + for( int ii = 0; ii < iimax; ii +=2 ) { wxPoint seg_start, seg_end; count++; @@ -257,16 +254,19 @@ int ZONE_CONTAINER::FillZoneAreasWithSegments() } } //End examine segments in one area - if ( error ) + if( error ) break; istart = iend + 1; // istart points the first corner of the next area } // End find one end of outline - if ( error ) + if( error ) break; } // End examine all areas + if( !error ) + m_IsFilled = true; + return count; } diff --git a/pcbnew/zones_by_polygon.cpp b/pcbnew/zones_by_polygon.cpp index 7b40a598e8..00492f4334 100644 --- a/pcbnew/zones_by_polygon.cpp +++ b/pcbnew/zones_by_polygon.cpp @@ -523,7 +523,7 @@ int PCB_EDIT_FRAME::Begin_Zone( wxDC* DC ) // Verify if a new zone is allowed on this layer: if( zone == NULL ) { - if( GetToolId() == ID_PCB_KEEPOUT_AREA_BUTT && !IsCopperLayer( getActiveLayer() ) ) + if( GetToolId() == ID_PCB_KEEPOUT_AREA_BUTT && !IsCopperLayer( GetActiveLayer() ) ) { DisplayError( this, _( "Error: a keepout area is allowed only on copper layers" ) ); @@ -546,7 +546,7 @@ int PCB_EDIT_FRAME::Begin_Zone( wxDC* DC ) ZONE_EDIT_T edited; // Init zone params to reasonable values - zone->SetLayer( getActiveLayer() ); + zone->SetLayer( GetActiveLayer() ); // Prompt user for parameters: m_canvas->SetIgnoreMouseEvents( true ); @@ -612,7 +612,7 @@ int PCB_EDIT_FRAME::Begin_Zone( wxDC* DC ) } // Switch active layer to the selected zone layer - setActiveLayer( zoneInfo.m_CurrentZone_Layer ); + SetActiveLayer( zoneInfo.m_CurrentZone_Layer ); SetZoneSettings( zoneInfo ); } else @@ -621,7 +621,7 @@ int PCB_EDIT_FRAME::Begin_Zone( wxDC* DC ) // zone (add cutout or similar zone) zoneInfo.m_CurrentZone_Layer = s_CurrentZone->GetLayer(); - setActiveLayer( s_CurrentZone->GetLayer() ); + SetActiveLayer( s_CurrentZone->GetLayer() ); zoneInfo << *s_CurrentZone;