diff --git a/common/eda_shape.cpp b/common/eda_shape.cpp index 10e63e9b43..7f0595459b 100644 --- a/common/eda_shape.cpp +++ b/common/eda_shape.cpp @@ -592,51 +592,12 @@ void EDA_SHAPE::UpdateHatching() const if( spacing == 0 ) return; - auto addHatchLines = - [&]( const std::vector& hatchLines ) - { - for( const SEG& seg : hatchLines ) - { - // This is essentially TransformOvalToPolygon(), but without the rounded ends, which - // in our case are nothing but a performance sink. - - VECTOR2I endp = seg.B - seg.A; - VECTOR2I startp = seg.A; - - // normalize the position in order to have endp.x >= 0 - // it makes calculations more easy to understand - if( endp.x < 0 ) - { - endp = seg.A - seg.B; - startp = seg.B; - } - - EDA_ANGLE delta_angle( endp ); - int seg_len = endp.EuclideanNorm(); - int halfwidth = lineWidth / 2; - - // Build the polygon (a horizontal rectangle). - SHAPE_POLY_SET polyshape; - polyshape.NewOutline(); - polyshape.Append( -halfwidth, halfwidth ); - polyshape.Append( -halfwidth, -halfwidth ); - polyshape.Append( halfwidth + seg_len, -halfwidth ); - polyshape.Append( halfwidth + seg_len, halfwidth ); - - // Rotate and move the polygon to its right location - polyshape.Rotate( -delta_angle ); - polyshape.Move( startp ); - - m_hatching.Append( polyshape); - } - }; - switch( m_shape ) { case SHAPE_T::ARC: case SHAPE_T::SEGMENT: case SHAPE_T::BEZIER: - break; + return; case SHAPE_T::RECTANGLE: shapeBuffer.NewOutline(); @@ -644,26 +605,84 @@ void EDA_SHAPE::UpdateHatching() const for( const VECTOR2I& pt : GetRectCorners() ) shapeBuffer.Append( pt ); - addHatchLines( shapeBuffer.GenerateHatchLines( slopes, spacing, -1 ) ); break; case SHAPE_T::CIRCLE: - TransformCircleToPolygon( shapeBuffer, getCenter(), GetRadius(), ARC_HIGH_DEF, ERROR_INSIDE ); - addHatchLines( shapeBuffer.GenerateHatchLines( slopes, spacing, -1 ) ); + TransformCircleToPolygon( shapeBuffer, getCenter(), GetRadius() + GetWidth(), + ARC_HIGH_DEF, ERROR_INSIDE ); break; case SHAPE_T::POLY: - if( IsClosed() ) - addHatchLines( m_poly.GenerateHatchLines( slopes, spacing, -1 ) ); + if( !IsClosed() ) + return; + shapeBuffer = m_poly.CloneDropTriangulation(); break; default: UNIMPLEMENTED_FOR( SHAPE_T_asString() ); - break; + return; + } + + if( GetFillMode() == FILL_T::HATCH || GetFillMode() == FILL_T::REVERSE_HATCH ) + { + for( const SEG& seg : shapeBuffer.GenerateHatchLines( slopes, spacing, -1 ) ) + { + // We don't really need the rounded ends at all, so don't spend any extra time on them + int maxError = lineWidth; + + TransformOvalToPolygon( m_hatching, seg.A, seg.B, lineWidth, maxError, ERROR_INSIDE ); + } + + m_hatching.Fracture(); } + else + { + // Generate a grid of holes for a cross-hatch. This is about 3X the speed of the above + // algorithm, even when modified for the 45-degree fracture problem. + + int gridsize = GetHatchLineSpacing(); + int hole_size = gridsize - GetHatchLineWidth(); + + m_hatching = shapeBuffer.CloneDropTriangulation(); + m_hatching.Rotate( -ANGLE_45 ); + + // Build hole shape + SHAPE_LINE_CHAIN hole_base; + VECTOR2I corner( 0, 0 );; + hole_base.Append( corner ); + corner.x += hole_size; + hole_base.Append( corner ); + corner.y += hole_size; + hole_base.Append( corner ); + corner.x = 0; + hole_base.Append( corner ); + hole_base.SetClosed( true ); - m_hatching.Fracture(); + // Build holes + BOX2I bbox = m_hatching.BBox( 0 ); + SHAPE_POLY_SET holes; + + int x_offset = bbox.GetX() - ( bbox.GetX() ) % gridsize - gridsize; + int y_offset = bbox.GetY() - ( bbox.GetY() ) % gridsize - gridsize; + + for( int xx = x_offset; xx <= bbox.GetRight(); xx += gridsize ) + { + for( int yy = y_offset; yy <= bbox.GetBottom(); yy += gridsize ) + { + SHAPE_LINE_CHAIN hole( hole_base ); + hole.Move( VECTOR2I( xx, yy ) ); + holes.AddOutline( hole ); + } + } + + m_hatching.BooleanSubtract( holes ); + m_hatching.Fracture(); + + // Must re-rotate after Fracture(). Clipper struggles mightily with fracturing + // 45-degree holes. + m_hatching.Rotate( ANGLE_45 ); + } } diff --git a/eeschema/tools/sch_point_editor.cpp b/eeschema/tools/sch_point_editor.cpp index 6f5bd19aba..b413de3495 100644 --- a/eeschema/tools/sch_point_editor.cpp +++ b/eeschema/tools/sch_point_editor.cpp @@ -1115,6 +1115,14 @@ int SCH_POINT_EDITOR::Main( const TOOL_EVENT& aEvent ) if( !inDrag ) { commit.Modify( m_editPoints->GetParent(), m_frame->GetScreen() ); + + if( SCH_SHAPE* shape = dynamic_cast( item ) ) + { + shape->SetFlags( IS_MOVING ); + shape->SetHatchingDirty(); + shape->UpdateHatching(); + } + inDrag = true; } @@ -1135,6 +1143,14 @@ int SCH_POINT_EDITOR::Main( const TOOL_EVENT& aEvent ) commit.Push( _( "Move Point" ) ); controls->SetAutoPan( false ); + + if( SCH_SHAPE* shape = dynamic_cast( item ) ) + { + shape->ClearFlags( IS_MOVING ); + shape->SetHatchingDirty(); + shape->UpdateHatching(); + } + inDrag = false; } else if( evt->IsCancelInteractive() || evt->IsActivate() ) @@ -1173,6 +1189,13 @@ int SCH_POINT_EDITOR::Main( const TOOL_EVENT& aEvent ) controls->CaptureCursor( inDrag ); } + if( SCH_SHAPE* shape = dynamic_cast( item ) ) + { + shape->ClearFlags( IS_MOVING ); + shape->SetHatchingDirty(); + shape->UpdateHatching(); + } + controls->SetAutoPan( false ); controls->CaptureCursor( false ); setEditedPoint( nullptr ); diff --git a/include/tool/point_editor_behavior.h b/include/tool/point_editor_behavior.h index e8b7565cb7..fe416230ca 100644 --- a/include/tool/point_editor_behavior.h +++ b/include/tool/point_editor_behavior.h @@ -180,8 +180,7 @@ class EDA_POLYGON_POINT_EDIT_BEHAVIOR : public POLYGON_POINT_EDIT_BEHAVIOR public: // Editing the underlying polygon shape in-place is enough EDA_POLYGON_POINT_EDIT_BEHAVIOR( EDA_SHAPE& aPolygon ) : - POLYGON_POINT_EDIT_BEHAVIOR( aPolygon.GetPolyShape() ), - m_shape( aPolygon ) + POLYGON_POINT_EDIT_BEHAVIOR( aPolygon.GetPolyShape() ) { wxASSERT( aPolygon.GetShape() == SHAPE_T::POLY ); } @@ -190,12 +189,7 @@ public: std::vector& aUpdatedItems ) override { POLYGON_POINT_EDIT_BEHAVIOR::UpdateItem( aEditedPoint, aPoints, aCommit, aUpdatedItems ); - m_shape.SetHatchingDirty(); - m_shape.UpdateHatching(); } - -private: - EDA_SHAPE& m_shape; }; diff --git a/pcbnew/tools/pcb_point_editor.cpp b/pcbnew/tools/pcb_point_editor.cpp index c78b137132..5b5085b3cd 100644 --- a/pcbnew/tools/pcb_point_editor.cpp +++ b/pcbnew/tools/pcb_point_editor.cpp @@ -2267,6 +2267,15 @@ int PCB_POINT_EDITOR::OnSelectionChange( const TOOL_EVENT& aEvent ) BOARD_ITEM* clone = static_cast( item->Clone() ); clone->SetParent( nullptr ); clone->SetParentGroup( nullptr ); + + if( PCB_SHAPE* shape= dynamic_cast( item ) ) + { + shape->SetFlags( IS_MOVING ); + shape->UpdateHatching(); + + static_cast( clone )->SetFillMode( FILL_T::NO_FILL ); + } + clones.emplace_back( clone ); grid.AddConstructionItems( { clone }, false, true ); } @@ -2370,6 +2379,12 @@ int PCB_POINT_EDITOR::OnSelectionChange( const TOOL_EVENT& aEvent ) commit.Push( _( "Move Point" ) ); } + if( PCB_SHAPE* shape= dynamic_cast( item ) ) + { + shape->ClearFlags( IS_MOVING ); + shape->UpdateHatching(); + } + inDrag = false; frame()->UndoRedoBlock( false ); @@ -2387,6 +2402,12 @@ int PCB_POINT_EDITOR::OnSelectionChange( const TOOL_EVENT& aEvent ) } commit.Revert(); + if( PCB_SHAPE* shape= dynamic_cast( item ) ) + { + shape->ClearFlags( IS_MOVING ); + shape->UpdateHatching(); + } + inDrag = false; frame()->UndoRedoBlock( false ); } @@ -2417,6 +2438,12 @@ int PCB_POINT_EDITOR::OnSelectionChange( const TOOL_EVENT& aEvent ) } } + if( PCB_SHAPE* shape= dynamic_cast( item ) ) + { + shape->ClearFlags( IS_MOVING ); + shape->UpdateHatching(); + } + m_preview.FreeItems(); getView()->Remove( &m_preview ); @@ -2798,8 +2825,6 @@ int PCB_POINT_EDITOR::addCorner( const TOOL_EVENT& aEvent ) if( item->Type() == PCB_ZONE_T ) static_cast( item )->HatchBorder(); - else - graphicItem->SetHatchingDirty(); commit.Push( _( "Add Zone Corner" ) ); } @@ -2930,8 +2955,6 @@ int PCB_POINT_EDITOR::removeCorner( const TOOL_EVENT& aEvent ) if( item->Type() == PCB_ZONE_T ) static_cast( item )->HatchBorder(); - else if( item->Type() == PCB_SHAPE_T ) - static_cast( item )->SetHatchingDirty(); updatePoints(); } @@ -3031,8 +3054,6 @@ int PCB_POINT_EDITOR::chamferCorner( const TOOL_EVENT& aEvent ) if( item->Type() == PCB_ZONE_T ) static_cast( item )->HatchBorder(); - else if( item->Type() == PCB_SHAPE_T ) - static_cast( item )->SetHatchingDirty(); updatePoints();