← Back to team overview

kicad-developers team mailing list archive

[PATCH] Eeschema: make field autoplace grid flexible with field height

 

Okay, here's a patch to make the autoplacement grid for fields flexible, 
so fields are positioned sanely when they have different heights. Just 
finished this an hour ago, as opposed to the main autoplacement patch 
which got months of testing, so somebody else might want to try this 
out.

I'm going to prepare one more patch, to handle a slightly quirky field 
placement in a specific arrangement with a long component symbol 
sandwiched between wires. That should be it.

--
Chris
commit b8fdf66034c0028ae33a3d372937279919427916
Author: Chris Pavlina <cpavlin1@xxxxxxxxxxxxxx>
Date:   Sat Dec 12 16:29:19 2015 -0500

    Make vertical autoplacement grid flexible

diff --git a/eeschema/autoplace_fields.cpp b/eeschema/autoplace_fields.cpp
index 001127a..5849309 100644
--- a/eeschema/autoplace_fields.cpp
+++ b/eeschema/autoplace_fields.cpp
@@ -63,9 +63,11 @@
 #include <vector>
 #include <algorithm>
 
-#define FIELD_V_SPACING 100
+#define FIELD_PADDING 10            // arbitrarily chosen for aesthetics
+#define FIELD_PADDING_ALIGNED 18    // aligns 50 mil text to a 100 mil grid
+#define WIRE_V_SPACING 100
 #define HPADDING 25
-#define VPADDING 50
+#define VPADDING 25
 
 /**
  * Function round_n
@@ -127,7 +129,7 @@ public:
         Kiface().KifaceSettings()->Read( AUTOPLACE_ALIGN_KEY, &m_align_to_grid, false );
 
         m_comp_bbox = m_component->GetBodyBoundingBox();
-        m_fbox_size = ComputeFBoxSize();
+        m_fbox_size = ComputeFBoxSize( /* aDynamic */ true );
 
         m_power_symbol = ! m_component->IsInNetlist();
 
@@ -143,17 +145,16 @@ public:
      */
     void DoAutoplace( bool aManual )
     {
+        bool force_wire_spacing = false;
         SIDE field_side = choose_side_for_fields( aManual );
         wxPoint fbox_pos = field_box_placement( field_side );
         EDA_RECT field_box( fbox_pos, m_fbox_size );
 
         if( aManual )
-        {
-            fbox_pos = fit_fields_between_wires( field_box, field_side );
-            field_box.SetOrigin( fbox_pos );
-        }
+            force_wire_spacing = fit_fields_between_wires( &field_box, field_side );
 
         // Move the fields
+        int last_y_coord = field_box.GetTop();
         for( int field_idx = 0; field_idx < m_fields.size(); ++field_idx )
         {
             SCH_FIELD* field = m_fields[field_idx];
@@ -163,7 +164,7 @@ public:
 
             wxPoint pos(
                 field_horiz_placement( field, field_box ),
-                field_box.GetY() + (FIELD_V_SPACING * field_idx) );
+                field_vert_placement( field, field_box, &last_y_coord, !force_wire_spacing ) );
 
             if( m_align_to_grid )
             {
@@ -179,29 +180,40 @@ public:
 protected:
     /**
      * Compute and return the size of the fields' bounding box.
+     * @param aDynamic - if true, use dynamic spacing
      */
-    wxSize ComputeFBoxSize()
+    wxSize ComputeFBoxSize( bool aDynamic )
     {
         int max_field_width = 0;
+        int total_height = 0;
+
         BOOST_FOREACH( SCH_FIELD* field, m_fields )
         {
             int field_width;
+            int field_height;
 
             if( m_component->GetTransform().y1 )
             {
                 field->SetOrientation( TEXT_ORIENT_VERT );
-                field_width = field->GetBoundingBox().GetHeight();
             }
             else
             {
                 field->SetOrientation( TEXT_ORIENT_HORIZ );
-                field_width = field->GetBoundingBox().GetWidth();
             }
 
+            field_width = field->GetBoundingBox().GetWidth();
+            field_height = field->GetBoundingBox().GetHeight();
+
             max_field_width = std::max( max_field_width, field_width );
+
+            if( aDynamic )
+                total_height += field_height + get_field_padding();
+            else
+                total_height += WIRE_V_SPACING;
+
         }
 
-        return wxSize( max_field_width, int( FIELD_V_SPACING * (m_fields.size() - 1) ) );
+        return wxSize( max_field_width, total_height );
     }
 
 
@@ -519,16 +531,16 @@ protected:
     /**
      * Function fit_fields_between_wires
      * Shift a field box up or down a bit to make the fields fit between some wires.
-     * Returns the new position of the field bounding box.
+     * Returns true if a shift was made.
      */
-    wxPoint fit_fields_between_wires( const EDA_RECT& aBox, SIDE aSide )
+    bool fit_fields_between_wires( EDA_RECT* aBox, SIDE aSide )
     {
         if( aSide != SIDE_TOP && aSide != SIDE_BOTTOM )
-            return aBox.GetPosition();
+            return false;
 
-        std::vector<SCH_ITEM*> colliders = filtered_colliders( aBox );
+        std::vector<SCH_ITEM*> colliders = filtered_colliders( *aBox );
         if( colliders.empty() )
-            return aBox.GetPosition();
+            return false;
 
         // Find the offset of the wires for proper positioning
         int offset = 0;
@@ -537,24 +549,28 @@ protected:
         {
             SCH_LINE* line = dynamic_cast<SCH_LINE*>( item );
             if( !line )
-                return aBox.GetPosition();
+                return false;
             wxPoint start = line->GetStartPoint(), end = line->GetEndPoint();
             if( start.y != end.y )
-                return aBox.GetPosition();
+                return false;
 
-            int this_offset = (3 * FIELD_V_SPACING / 2) - ( start.y % FIELD_V_SPACING );
+            int this_offset = (3 * WIRE_V_SPACING / 2) - ( start.y % WIRE_V_SPACING );
             if( offset == 0 )
                 offset = this_offset;
             else if( offset != this_offset )
-                return aBox.GetPosition();
+                return false;
         }
 
         if( aSide == SIDE_TOP )
             offset = -offset;
 
-        wxPoint pos = aBox.GetPosition();
-        pos.y = round_n( pos.y - offset, FIELD_V_SPACING, aSide == SIDE_BOTTOM ) + offset;
-        return pos;
+        wxPoint pos = aBox->GetPosition();
+        pos.y = round_n( pos.y - offset, WIRE_V_SPACING, aSide == SIDE_BOTTOM ) + offset;
+
+        // Compensate for padding
+        pos.y += WIRE_V_SPACING / 2;
+        aBox->SetOrigin( pos );
+        return true;
     }
 
 
@@ -597,6 +613,59 @@ protected:
         return field_xcoord;
     }
 
+    /**
+     * Function field_vert_placement
+     * Place a field vertically. Because field vertical placements accumulate,
+     * this takes a pointer to a vertical position accumulator.
+     *
+     * @param aField - the field to place.
+     * @param aFieldBox - box in which fields will be placed.
+     * @param aPosAccum - pointer to a position accumulator
+     * @param aDynamic - use dynamic spacing
+     *
+     * @return Correct field vertical position
+     */
+    int field_vert_placement( SCH_FIELD *aField, const EDA_RECT &aFieldBox, int *aPosAccum,
+            bool aDynamic )
+    {
+        int field_height;
+        int padding;
+
+        if( aDynamic )
+        {
+            if( m_component->GetTransform().y1 )
+                field_height = aField->GetBoundingBox().GetWidth();
+            else
+                field_height = aField->GetBoundingBox().GetHeight();
+            field_height = aField->GetBoundingBox().GetHeight();
+
+            padding = get_field_padding();
+        }
+        else
+        {
+            field_height = WIRE_V_SPACING / 2;
+            padding = WIRE_V_SPACING / 2;
+        }
+
+        int placement = *aPosAccum + padding / 2 + field_height / 2;
+
+        *aPosAccum += padding + field_height;
+
+        return placement;
+    }
+
+    /**
+     * Function get_field_padding
+     * Return the desired padding between fields.
+     */
+    int get_field_padding()
+    {
+        if( m_align_to_grid )
+            return FIELD_PADDING_ALIGNED;
+        else
+            return FIELD_PADDING;
+    }
+
 };
 
 const AUTOPLACER::SIDE AUTOPLACER::SIDE_TOP( 0, -1 );

Follow ups