Don't truncate polar coordinates in position relative dialog/move exact dialog

This commit is contained in:
Andrew Downing 2020-02-29 02:21:18 +00:00 committed by Seth Hillbrand
parent 3f31d48b5e
commit 2f7ac2b5b4
6 changed files with 163 additions and 61 deletions

View File

@ -195,6 +195,12 @@ void UNIT_BINDER::SetValue( int aValue )
} }
void UNIT_BINDER::SetDoubleValue( double aValue )
{
SetValue( StringFromValue( m_units, aValue, false, m_useMils ) );
}
void UNIT_BINDER::SetValue( wxString aValue ) void UNIT_BINDER::SetValue( wxString aValue )
{ {
auto textEntry = dynamic_cast<wxTextEntry*>( m_value ); auto textEntry = dynamic_cast<wxTextEntry*>( m_value );
@ -257,6 +263,28 @@ long long int UNIT_BINDER::GetValue()
} }
double UNIT_BINDER::GetDoubleValue()
{
auto textEntry = dynamic_cast<wxTextEntry*>( m_value );
auto staticText = dynamic_cast<wxStaticText*>( m_value );
wxString value;
if( textEntry )
{
if( m_needsEval && m_eval.Process( textEntry->GetValue() ) )
value = m_eval.Result();
else
value = textEntry->GetValue();
}
else if( staticText )
value = staticText->GetLabel();
else
return 0.0;
return DoubleValueFromString( m_units, value, m_useMils );
}
bool UNIT_BINDER::IsIndeterminate() const bool UNIT_BINDER::IsIndeterminate() const
{ {
auto textEntry = dynamic_cast<wxTextEntry*>( m_value ); auto textEntry = dynamic_cast<wxTextEntry*>( m_value );

View File

@ -71,6 +71,13 @@ public:
void SetValue( wxString aValue ); void SetValue( wxString aValue );
/**
* Function SetDoubleValue
* Sets new value (in Internal Units) for the text field, taking care of units conversion.
* @param aValue is the new value.
*/
virtual void SetDoubleValue( double aValue );
/** /**
* Function ChangeValue * Function ChangeValue
* Changes the value (in Internal Units) for the text field, taking care of units conversion * Changes the value (in Internal Units) for the text field, taking care of units conversion
@ -87,6 +94,12 @@ public:
*/ */
virtual long long int GetValue(); virtual long long int GetValue();
/**
* Function GetValue
* Returns the current value in Internal Units.
*/
virtual double GetDoubleValue();
/** /**
* Function IsIndeterminate * Function IsIndeterminate
* Returns true if the control holds the indeterminate value (for instance, if it * Returns true if the control holds the indeterminate value (for instance, if it

View File

@ -41,7 +41,11 @@ DIALOG_MOVE_EXACT::DIALOG_MOVE_EXACT( PCB_BASE_FRAME *aParent, wxPoint& aTransla
m_bbox( aBbox ), m_bbox( aBbox ),
m_moveX( aParent, m_xLabel, m_xEntry, m_xUnit ), m_moveX( aParent, m_xLabel, m_xEntry, m_xUnit ),
m_moveY( aParent, m_yLabel, m_yEntry, m_yUnit ), m_moveY( aParent, m_yLabel, m_yEntry, m_yUnit ),
m_rotate( aParent, m_rotLabel, m_rotEntry, m_rotUnit ) m_rotate( aParent, m_rotLabel, m_rotEntry, m_rotUnit ),
m_stateX( 0.0 ),
m_stateY( 0.0 ),
m_stateRadius( 0.0 ),
m_stateTheta( 0.0 )
{ {
// We can't set the tab order through wxWidgets due to shortcomings in their mnemonics // We can't set the tab order through wxWidgets due to shortcomings in their mnemonics
// implementation on MSW // implementation on MSW
@ -66,8 +70,8 @@ DIALOG_MOVE_EXACT::DIALOG_MOVE_EXACT( PCB_BASE_FRAME *aParent, wxPoint& aTransla
// and set up the entries according to the saved options // and set up the entries according to the saved options
m_polarCoords->SetValue( m_options.polarCoords ); m_polarCoords->SetValue( m_options.polarCoords );
m_moveX.SetValue( m_options.entry1 ); m_moveX.SetDoubleValue( m_options.entry1 );
m_moveY.SetValue( m_options.entry2 ); m_moveY.SetDoubleValue( m_options.entry2 );
m_rotate.SetUnits( EDA_UNITS::DEGREES ); m_rotate.SetUnits( EDA_UNITS::DEGREES );
m_rotate.SetValue( m_options.entryRotation ); m_rotate.SetValue( m_options.entryRotation );
@ -115,12 +119,12 @@ void DIALOG_MOVE_EXACT::ToPolarDeg( double x, double y, double& r, double& q )
} }
bool DIALOG_MOVE_EXACT::GetTranslationInIU ( wxPoint& val, bool polar ) bool DIALOG_MOVE_EXACT::GetTranslationInIU( wxRealPoint& val, bool polar )
{ {
if( polar ) if( polar )
{ {
const int r = m_moveX.GetValue(); const double r = m_moveX.GetDoubleValue();
const double q = m_moveY.GetValue(); const double q = m_moveY.GetDoubleValue();
val.x = r * cos( DEG2RAD( q / 10.0 ) ); val.x = r * cos( DEG2RAD( q / 10.0 ) );
val.y = r * sin( DEG2RAD( q / 10.0 ) ); val.y = r * sin( DEG2RAD( q / 10.0 ) );
@ -128,8 +132,8 @@ bool DIALOG_MOVE_EXACT::GetTranslationInIU ( wxPoint& val, bool polar )
else else
{ {
// direct read // direct read
val.x = m_moveX.GetValue(); val.x = m_moveX.GetDoubleValue();
val.y = m_moveY.GetValue(); val.y = m_moveY.GetDoubleValue();
} }
// no validation to do here, but in future, you could return false here // no validation to do here, but in future, you could return false here
@ -140,33 +144,50 @@ bool DIALOG_MOVE_EXACT::GetTranslationInIU ( wxPoint& val, bool polar )
void DIALOG_MOVE_EXACT::OnPolarChanged( wxCommandEvent& event ) void DIALOG_MOVE_EXACT::OnPolarChanged( wxCommandEvent& event )
{ {
bool newPolar = m_polarCoords->IsChecked(); bool newPolar = m_polarCoords->IsChecked();
wxPoint val; double moveX = m_moveX.GetDoubleValue();
double moveY = m_moveY.GetDoubleValue();
// get the value as previously stored
GetTranslationInIU( val, !newPolar );
// now switch the controls to the new representations
updateDialogControls( newPolar ); updateDialogControls( newPolar );
if( newPolar ) if( newPolar )
{ {
// convert to polar coordinates if( moveX != m_stateX || moveY != m_stateY )
double r, q; {
ToPolarDeg( val.x, val.y, r, q ); m_stateX = moveX;
m_stateY = moveY;
ToPolarDeg( m_stateX, m_stateY, m_stateRadius, m_stateTheta );
m_stateTheta *= 10.0;
m_moveX.SetValue( KiROUND( r / 10.0) * 10 ); m_moveX.SetDoubleValue( m_stateRadius );
m_moveY.SetValue( q * 10 ); m_stateRadius = m_moveX.GetDoubleValue();
m_moveY.SetDoubleValue( m_stateTheta );
m_stateTheta = m_moveY.GetDoubleValue();
} }
else else
{ {
// vector is already in Cartesian, so just render out m_moveX.SetDoubleValue( m_stateRadius );
// note - round off the last decimal place (10nm) to prevent m_moveY.SetDoubleValue( m_stateTheta );
// (some) rounding causing errors when round-tripping
// you can never eliminate entirely, however
m_moveX.SetValue( KiROUND( val.x / 10.0 ) * 10 );
m_moveY.SetValue( KiROUND( val.y / 10.0 ) * 10 );
} }
}
else
{
if( moveX != m_stateRadius || moveY != m_stateTheta )
{
m_stateRadius = moveX;
m_stateTheta = moveY;
m_stateX = m_stateRadius * cos( DEG2RAD( m_stateTheta / 10.0 ) );
m_stateY = m_stateRadius * sin( DEG2RAD( m_stateTheta / 10.0 ) );
m_moveX.SetDoubleValue( m_stateX );
m_stateX = m_moveX.GetDoubleValue();
m_moveY.SetDoubleValue( m_stateY );
m_stateY = m_moveY.GetDoubleValue();
}
else
{
m_moveX.SetDoubleValue( m_stateX );
m_moveY.SetDoubleValue( m_stateY );
}
}
} }
@ -214,7 +235,10 @@ void DIALOG_MOVE_EXACT::OnClear( wxCommandEvent& event )
bool DIALOG_MOVE_EXACT::TransferDataFromWindow() bool DIALOG_MOVE_EXACT::TransferDataFromWindow()
{ {
// for the output, we only deliver a Cartesian vector // for the output, we only deliver a Cartesian vector
bool ok = GetTranslationInIU( m_translation, m_polarCoords->IsChecked() ); wxRealPoint translation;
bool ok = GetTranslationInIU( translation, m_polarCoords->IsChecked() );
m_translation.x = KiROUND(translation.x);
m_translation.y = KiROUND(translation.y);
m_rotation = m_rotate.GetValue(); m_rotation = m_rotate.GetValue();
m_rotationAnchor = m_menuIDs[ m_anchorOptions->GetSelection() ]; m_rotationAnchor = m_menuIDs[ m_anchorOptions->GetSelection() ];
@ -222,8 +246,8 @@ bool DIALOG_MOVE_EXACT::TransferDataFromWindow()
{ {
// save the settings // save the settings
m_options.polarCoords = m_polarCoords->GetValue(); m_options.polarCoords = m_polarCoords->GetValue();
m_options.entry1 = m_moveX.GetValue(); m_options.entry1 = m_moveX.GetDoubleValue();
m_options.entry2 = m_moveY.GetValue(); m_options.entry2 = m_moveY.GetDoubleValue();
m_options.entryRotation = m_rotate.GetValue(); m_options.entryRotation = m_rotate.GetValue();
m_options.entryAnchorSelection = (size_t) std::max( m_anchorOptions->GetSelection(), 0 ); m_options.entryAnchorSelection = (size_t) std::max( m_anchorOptions->GetSelection(), 0 );
return true; return true;
@ -247,8 +271,8 @@ void DIALOG_MOVE_EXACT::OnTextFocusLost( wxFocusEvent& event )
void DIALOG_MOVE_EXACT::OnTextChanged( wxCommandEvent& event ) void DIALOG_MOVE_EXACT::OnTextChanged( wxCommandEvent& event )
{ {
double delta_x = m_moveX.GetValue(); double delta_x = m_moveX.GetDoubleValue();
double delta_y = m_moveY.GetValue(); double delta_y = m_moveY.GetDoubleValue();
double max_border = std::numeric_limits<int>::max() * 0.7071; double max_border = std::numeric_limits<int>::max() * 0.7071;
if( m_bbox.GetLeft() + delta_x < -max_border || if( m_bbox.GetLeft() + delta_x < -max_border ||

View File

@ -57,6 +57,12 @@ private:
std::vector<ROTATION_ANCHOR> m_menuIDs; std::vector<ROTATION_ANCHOR> m_menuIDs;
double m_stateX;
double m_stateY;
double m_stateRadius;
double m_stateTheta;
public: public:
// Constructor and destructor // Constructor and destructor
DIALOG_MOVE_EXACT(PCB_BASE_FRAME *aParent, wxPoint& aTranslate, DIALOG_MOVE_EXACT(PCB_BASE_FRAME *aParent, wxPoint& aTranslate,
@ -92,7 +98,7 @@ private:
* @param polar interpret as polar coords * @param polar interpret as polar coords
* @return false if error (though the text conversion functions don't report errors) * @return false if error (though the text conversion functions don't report errors)
*/ */
bool GetTranslationInIU ( wxPoint& val, bool polar ); bool GetTranslationInIU( wxRealPoint& val, bool polar );
void buildRotationAnchorMenu(); void buildRotationAnchorMenu();

View File

@ -38,7 +38,11 @@ DIALOG_POSITION_RELATIVE::DIALOG_POSITION_RELATIVE( PCB_BASE_FRAME* aParent, wxP
m_translation( translation ), m_translation( translation ),
m_anchor_position( anchor ), m_anchor_position( anchor ),
m_xOffset( aParent, m_xLabel, m_xEntry, m_xUnit ), m_xOffset( aParent, m_xLabel, m_xEntry, m_xUnit ),
m_yOffset( aParent, m_yLabel, m_yEntry, m_yUnit ) m_yOffset( aParent, m_yLabel, m_yEntry, m_yUnit ),
m_stateX( 0.0 ),
m_stateY( 0.0 ),
m_stateRadius( 0.0 ),
m_stateTheta( 0.0 )
{ {
// We can't set the tab order through wxWidgets due to shortcomings in their mnemonics // We can't set the tab order through wxWidgets due to shortcomings in their mnemonics
// implementation on MSW // implementation on MSW
@ -55,8 +59,8 @@ DIALOG_POSITION_RELATIVE::DIALOG_POSITION_RELATIVE( PCB_BASE_FRAME* aParent, wxP
m_polarCoords->SetValue( m_options.polarCoords ); m_polarCoords->SetValue( m_options.polarCoords );
updateDialogControls( m_polarCoords->IsChecked() ); updateDialogControls( m_polarCoords->IsChecked() );
m_xOffset.SetValue( m_options.entry1 ); m_xOffset.SetDoubleValue( m_options.entry1 );
m_yOffset.SetValue( m_options.entry2 ); m_yOffset.SetDoubleValue( m_options.entry2 );
m_stdButtonsOK->SetDefault(); m_stdButtonsOK->SetDefault();
@ -73,12 +77,12 @@ void DIALOG_POSITION_RELATIVE::ToPolarDeg( double x, double y, double& r, double
} }
bool DIALOG_POSITION_RELATIVE::GetTranslationInIU ( wxPoint& val, bool polar ) bool DIALOG_POSITION_RELATIVE::GetTranslationInIU( wxRealPoint& val, bool polar )
{ {
if( polar ) if( polar )
{ {
const int r = m_xOffset.GetValue(); const double r = m_xOffset.GetDoubleValue();
const double q = m_yOffset.GetValue(); const double q = m_yOffset.GetDoubleValue();
val.x = r * cos( DEG2RAD( q / 10.0 ) ); val.x = r * cos( DEG2RAD( q / 10.0 ) );
val.y = r * sin( DEG2RAD( q / 10.0 ) ); val.y = r * sin( DEG2RAD( q / 10.0 ) );
@ -86,8 +90,8 @@ bool DIALOG_POSITION_RELATIVE::GetTranslationInIU ( wxPoint& val, bool polar )
else else
{ {
// direct read // direct read
val.x = m_xOffset.GetValue(); val.x = m_xOffset.GetDoubleValue();
val.y = m_yOffset.GetValue(); val.y = m_yOffset.GetDoubleValue();
} }
// no validation to do here, but in future, you could return false here // no validation to do here, but in future, you could return false here
@ -98,31 +102,49 @@ bool DIALOG_POSITION_RELATIVE::GetTranslationInIU ( wxPoint& val, bool polar )
void DIALOG_POSITION_RELATIVE::OnPolarChanged( wxCommandEvent& event ) void DIALOG_POSITION_RELATIVE::OnPolarChanged( wxCommandEvent& event )
{ {
bool newPolar = m_polarCoords->IsChecked(); bool newPolar = m_polarCoords->IsChecked();
wxPoint val; double xOffset = m_xOffset.GetDoubleValue();
double yOffset = m_yOffset.GetDoubleValue();
// get the value as previously stored
GetTranslationInIU( val, !newPolar );
// now switch the controls to the new representations
updateDialogControls( newPolar ); updateDialogControls( newPolar );
if( newPolar ) if( newPolar )
{ {
// convert to polar coordinates if( xOffset != m_stateX || yOffset != m_stateY )
double r, q; {
ToPolarDeg( val.x, val.y, r, q ); m_stateX = xOffset;
m_stateY = yOffset;
ToPolarDeg( m_stateX, m_stateY, m_stateRadius, m_stateTheta );
m_stateTheta *= 10.0;
m_xOffset.SetValue( KiROUND( r / 10.0) * 10 ); m_xOffset.SetDoubleValue( m_stateRadius );
m_yOffset.SetValue( q * 10 ); m_stateRadius = m_xOffset.GetDoubleValue();
m_yOffset.SetDoubleValue( m_stateTheta );
m_stateTheta = m_yOffset.GetDoubleValue();
} }
else else
{ {
// vector is already in Cartesian, so just render out m_xOffset.SetDoubleValue( m_stateRadius );
// note - round off the last decimal place (10nm) to prevent m_yOffset.SetDoubleValue( m_stateTheta );
// (some) rounding causing errors when round-tripping }
// you can never eliminate entirely, however }
m_xOffset.SetValue( KiROUND( val.x / 10.0 ) * 10 ); else
m_yOffset.SetValue( KiROUND( val.y / 10.0 ) * 10 ); {
if( xOffset != m_stateRadius || yOffset != m_stateTheta )
{
m_stateRadius = xOffset;
m_stateTheta = yOffset;
m_stateX = m_stateRadius * cos( DEG2RAD( m_stateTheta / 10.0 ) );
m_stateY = m_stateRadius * sin( DEG2RAD( m_stateTheta / 10.0 ) );
m_xOffset.SetDoubleValue( m_stateX );
m_stateX = m_xOffset.GetDoubleValue();
m_yOffset.SetDoubleValue( m_stateY );
m_stateY = m_yOffset.GetDoubleValue();
}
else
{
m_xOffset.SetDoubleValue( m_stateX );
m_yOffset.SetDoubleValue( m_stateY );
}
} }
} }
@ -209,14 +231,17 @@ void DIALOG_POSITION_RELATIVE::UpdateAnchor( EDA_ITEM* aItem )
void DIALOG_POSITION_RELATIVE::OnOkClick( wxCommandEvent& event ) void DIALOG_POSITION_RELATIVE::OnOkClick( wxCommandEvent& event )
{ {
// for the output, we only deliver a Cartesian vector // for the output, we only deliver a Cartesian vector
bool ok = GetTranslationInIU( m_translation, m_polarCoords->IsChecked() ); wxRealPoint translation;
bool ok = GetTranslationInIU( translation, m_polarCoords->IsChecked() );
m_translation.x = KiROUND( translation.x );
m_translation.y = KiROUND( translation.y );
if( ok ) if( ok )
{ {
// save the settings // save the settings
m_options.polarCoords = m_polarCoords->GetValue(); m_options.polarCoords = m_polarCoords->GetValue();
m_options.entry1 = m_xOffset.GetValue(); m_options.entry1 = m_xOffset.GetDoubleValue();
m_options.entry2 = m_yOffset.GetValue(); m_options.entry2 = m_yOffset.GetDoubleValue();
POSITION_RELATIVE_TOOL* posrelTool = m_toolMgr->GetTool<POSITION_RELATIVE_TOOL>(); POSITION_RELATIVE_TOOL* posrelTool = m_toolMgr->GetTool<POSITION_RELATIVE_TOOL>();
wxASSERT( posrelTool ); wxASSERT( posrelTool );

View File

@ -43,6 +43,12 @@ private:
UNIT_BINDER m_xOffset; UNIT_BINDER m_xOffset;
UNIT_BINDER m_yOffset; UNIT_BINDER m_yOffset;
double m_stateX;
double m_stateY;
double m_stateRadius;
double m_stateTheta;
public: public:
// Constructor and destructor // Constructor and destructor
DIALOG_POSITION_RELATIVE( PCB_BASE_FRAME* aParent, wxPoint& translation, wxPoint& anchor ); DIALOG_POSITION_RELATIVE( PCB_BASE_FRAME* aParent, wxPoint& translation, wxPoint& anchor );
@ -79,7 +85,7 @@ private:
* @param polar interpret as polar coords * @param polar interpret as polar coords
* @return false if error (though the text conversion functions don't report errors) * @return false if error (though the text conversion functions don't report errors)
*/ */
bool GetTranslationInIU( wxPoint& val, bool polar ); bool GetTranslationInIU( wxRealPoint& val, bool polar );
// Update controls and their labels after changing the coordinates type (polar/cartesian) // Update controls and their labels after changing the coordinates type (polar/cartesian)
void updateDialogControls( bool aPolar ); void updateDialogControls( bool aPolar );