kicad-developers team mailing list archive
-
kicad-developers team
-
Mailing list archive
-
Message #21985
Re: [PATCH] Eeschema: make field autoplace grid flexible with field height
#6377 changed a bit in the vicinity of this patch, so here's an updated one to preempt any merge conflicts.
On Sun, Dec 13, 2015 at 12:53:53PM -0500, Chris Pavlina wrote:
> 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 );
diff --git a/eeschema/autoplace_fields.cpp b/eeschema/autoplace_fields.cpp
index 1efd40e..c8a7aa6 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( unsigned 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
References