ADDED: Fillet Tracks tool in pcbnew
Select two or more track segments and run the "Fillet Tracks" tool.
This commit is contained in:
parent
4da340b153
commit
006c462d8f
|
@ -180,6 +180,8 @@ set( COMMON_DLG_SRCS
|
|||
dialogs/dialog_print_generic.cpp
|
||||
dialogs/dialog_print_generic_base.cpp
|
||||
dialogs/dialog_text_entry.cpp
|
||||
dialogs/dialog_unit_entry.cpp
|
||||
dialogs/dialog_unit_entry_base.cpp
|
||||
dialogs/eda_list_dialog.cpp
|
||||
dialogs/eda_list_dialog_base.cpp
|
||||
dialogs/eda_view_switcher.cpp
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2020 Roberto Fernandez Bautista <roberto.fer.bau@gmail.com>
|
||||
* Copyright (C) 2020 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 "dialog_unit_entry.h"
|
||||
|
||||
|
||||
WX_UNIT_ENTRY_DIALOG::WX_UNIT_ENTRY_DIALOG( EDA_DRAW_FRAME* aParent, const wxString& aLabel,
|
||||
const wxString& aCaption, const long long& aDefaultValue )
|
||||
: WX_UNIT_ENTRY_DIALOG_BASE( ( wxWindow* ) aParent, wxID_ANY, aCaption ),
|
||||
m_unit_binder( aParent, m_label, m_textCtrl, m_unit_label, true )
|
||||
{
|
||||
m_label->SetLabel( aLabel );
|
||||
m_unit_binder.SetValue( aDefaultValue );
|
||||
m_sdbSizer1OK->SetDefault();
|
||||
}
|
||||
|
||||
|
||||
long long WX_UNIT_ENTRY_DIALOG::GetValue()
|
||||
{
|
||||
return m_unit_binder.GetValue();
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2020 Roberto Fernandez Bautista <roberto.fer.bau@gmail.com>
|
||||
* Copyright (C) 2020 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
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* An extension of WX_TEXT_ENTRY_DIALOG that uses UNIT_BINDER to request a dimension
|
||||
* (e.g. mm, inches, etc) from the user according to the selected units
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _DIALOG_UNIT_ENTRY_H_
|
||||
#define _DIALOG_UNIT_ENTRY_H_
|
||||
|
||||
|
||||
#include <widgets/unit_binder.h>
|
||||
|
||||
#include "dialog_unit_entry_base.h"
|
||||
|
||||
class WX_UNIT_ENTRY_DIALOG : public WX_UNIT_ENTRY_DIALOG_BASE
|
||||
{
|
||||
public:
|
||||
WX_UNIT_ENTRY_DIALOG( EDA_DRAW_FRAME* aParent, const wxString& aLabel, const wxString& aCaption,
|
||||
const long long& aDefaultValue = 0 );
|
||||
|
||||
|
||||
/**
|
||||
* Returns the value in internal units
|
||||
*/
|
||||
long long GetValue();
|
||||
|
||||
private:
|
||||
UNIT_BINDER m_unit_binder;
|
||||
};
|
||||
|
||||
#endif // _DIALOG_UNIT_ENTRY_H_
|
|
@ -0,0 +1,63 @@
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ code generated with wxFormBuilder (version Oct 26 2018)
|
||||
// http://www.wxformbuilder.org/
|
||||
//
|
||||
// PLEASE DO *NOT* EDIT THIS FILE!
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "dialog_unit_entry_base.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WX_UNIT_ENTRY_DIALOG_BASE::WX_UNIT_ENTRY_DIALOG_BASE( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : DIALOG_SHIM( parent, id, title, pos, size, style )
|
||||
{
|
||||
this->SetSizeHints( wxDefaultSize, wxDefaultSize );
|
||||
|
||||
wxBoxSizer* bSizerMain;
|
||||
bSizerMain = new wxBoxSizer( wxVERTICAL );
|
||||
|
||||
wxBoxSizer* bSizerContent;
|
||||
bSizerContent = new wxBoxSizer( wxVERTICAL );
|
||||
|
||||
m_label = new wxStaticText( this, wxID_ANY, _("MyLabel"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_label->Wrap( -1 );
|
||||
bSizerContent->Add( m_label, 0, wxALL|wxEXPAND, 5 );
|
||||
|
||||
wxBoxSizer* bSizerTextAndUnit;
|
||||
bSizerTextAndUnit = new wxBoxSizer( wxHORIZONTAL );
|
||||
|
||||
m_textCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_textCtrl->SetMinSize( wxSize( 300,-1 ) );
|
||||
|
||||
bSizerTextAndUnit->Add( m_textCtrl, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND, 5 );
|
||||
|
||||
m_unit_label = new wxStaticText( this, wxID_ANY, _("unit"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_unit_label->Wrap( -1 );
|
||||
bSizerTextAndUnit->Add( m_unit_label, 0, wxALL, 5 );
|
||||
|
||||
|
||||
bSizerContent->Add( bSizerTextAndUnit, 1, wxEXPAND, 5 );
|
||||
|
||||
|
||||
bSizerMain->Add( bSizerContent, 1, wxALL|wxEXPAND, 5 );
|
||||
|
||||
m_sdbSizer1 = new wxStdDialogButtonSizer();
|
||||
m_sdbSizer1OK = new wxButton( this, wxID_OK );
|
||||
m_sdbSizer1->AddButton( m_sdbSizer1OK );
|
||||
m_sdbSizer1Cancel = new wxButton( this, wxID_CANCEL );
|
||||
m_sdbSizer1->AddButton( m_sdbSizer1Cancel );
|
||||
m_sdbSizer1->Realize();
|
||||
|
||||
bSizerMain->Add( m_sdbSizer1, 0, wxALL|wxALIGN_RIGHT, 5 );
|
||||
|
||||
|
||||
this->SetSizer( bSizerMain );
|
||||
this->Layout();
|
||||
bSizerMain->Fit( this );
|
||||
|
||||
this->Centre( wxBOTH );
|
||||
}
|
||||
|
||||
WX_UNIT_ENTRY_DIALOG_BASE::~WX_UNIT_ENTRY_DIALOG_BASE()
|
||||
{
|
||||
}
|
|
@ -0,0 +1,290 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||
<wxFormBuilder_Project>
|
||||
<FileVersion major="1" minor="15" />
|
||||
<object class="Project" expanded="1">
|
||||
<property name="class_decoration"></property>
|
||||
<property name="code_generation">C++</property>
|
||||
<property name="disconnect_events">1</property>
|
||||
<property name="disconnect_mode">source_name</property>
|
||||
<property name="disconnect_php_events">0</property>
|
||||
<property name="disconnect_python_events">0</property>
|
||||
<property name="embedded_files_path">res</property>
|
||||
<property name="encoding">UTF-8</property>
|
||||
<property name="event_generation">connect</property>
|
||||
<property name="file">dialog_unit_entry_base</property>
|
||||
<property name="first_id">1000</property>
|
||||
<property name="help_provider">none</property>
|
||||
<property name="indent_with_spaces"></property>
|
||||
<property name="internationalize">1</property>
|
||||
<property name="name">dialog_unit_entry_base</property>
|
||||
<property name="namespace"></property>
|
||||
<property name="path">.</property>
|
||||
<property name="precompiled_header"></property>
|
||||
<property name="relative_path">1</property>
|
||||
<property name="skip_lua_events">1</property>
|
||||
<property name="skip_php_events">1</property>
|
||||
<property name="skip_python_events">1</property>
|
||||
<property name="ui_table">UI</property>
|
||||
<property name="use_enum">0</property>
|
||||
<property name="use_microsoft_bom">0</property>
|
||||
<object class="Dialog" expanded="1">
|
||||
<property name="aui_managed">0</property>
|
||||
<property name="aui_manager_style">wxAUI_MGR_DEFAULT</property>
|
||||
<property name="bg"></property>
|
||||
<property name="center">wxBOTH</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="event_handler">impl_virtual</property>
|
||||
<property name="extra_style"></property>
|
||||
<property name="fg"></property>
|
||||
<property name="font"></property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">WX_UNIT_ENTRY_DIALOG_BASE</property>
|
||||
<property name="pos"></property>
|
||||
<property name="size">-1,-1</property>
|
||||
<property name="style">wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</property>
|
||||
<property name="subclass">DIALOG_SHIM; dialog_shim.h</property>
|
||||
<property name="title"></property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<object class="wxBoxSizer" expanded="1">
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">bSizerMain</property>
|
||||
<property name="orient">wxVERTICAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL|wxEXPAND</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="wxBoxSizer" expanded="1">
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">bSizerContent</property>
|
||||
<property name="orient">wxVERTICAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="0">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL|wxEXPAND</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxStaticText" expanded="0">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="label">MyLabel</property>
|
||||
<property name="markup">0</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_label</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass">; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<property name="wrap">-1</property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxEXPAND</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="wxBoxSizer" expanded="1">
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">bSizerTextAndUnit</property>
|
||||
<property name="orient">wxHORIZONTAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="0">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxTextCtrl" expanded="0">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="maxlength"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size">300,-1</property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_textCtrl</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass">; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="validator_data_type"></property>
|
||||
<property name="validator_style">wxFILTER_NONE</property>
|
||||
<property name="validator_type">wxDefaultValidator</property>
|
||||
<property name="validator_variable"></property>
|
||||
<property name="value"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxStaticText" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="label">unit</property>
|
||||
<property name="markup">0</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_unit_label</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass">; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<property name="wrap">-1</property>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="0">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL|wxALIGN_RIGHT</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxStdDialogButtonSizer" expanded="0">
|
||||
<property name="Apply">0</property>
|
||||
<property name="Cancel">1</property>
|
||||
<property name="ContextHelp">0</property>
|
||||
<property name="Help">0</property>
|
||||
<property name="No">0</property>
|
||||
<property name="OK">1</property>
|
||||
<property name="Save">0</property>
|
||||
<property name="Yes">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">m_sdbSizer1</property>
|
||||
<property name="permission">protected</property>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</wxFormBuilder_Project>
|
|
@ -0,0 +1,49 @@
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ code generated with wxFormBuilder (version Oct 26 2018)
|
||||
// http://www.wxformbuilder.org/
|
||||
//
|
||||
// PLEASE DO *NOT* EDIT THIS FILE!
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wx/artprov.h>
|
||||
#include <wx/xrc/xmlres.h>
|
||||
#include <wx/intl.h>
|
||||
#include "dialog_shim.h"
|
||||
#include <wx/string.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/gdicmn.h>
|
||||
#include <wx/font.h>
|
||||
#include <wx/colour.h>
|
||||
#include <wx/settings.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/button.h>
|
||||
#include <wx/dialog.h>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// Class WX_UNIT_ENTRY_DIALOG_BASE
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
class WX_UNIT_ENTRY_DIALOG_BASE : public DIALOG_SHIM
|
||||
{
|
||||
private:
|
||||
|
||||
protected:
|
||||
wxStaticText* m_label;
|
||||
wxTextCtrl* m_textCtrl;
|
||||
wxStaticText* m_unit_label;
|
||||
wxStdDialogButtonSizer* m_sdbSizer1;
|
||||
wxButton* m_sdbSizer1OK;
|
||||
wxButton* m_sdbSizer1Cancel;
|
||||
|
||||
public:
|
||||
|
||||
WX_UNIT_ENTRY_DIALOG_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
|
||||
~WX_UNIT_ENTRY_DIALOG_BASE();
|
||||
|
||||
};
|
||||
|
|
@ -34,6 +34,11 @@ class SHAPE_LINE_CHAIN;
|
|||
class SHAPE_ARC : public SHAPE
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief This is the minimum precision for all the points in the arc shape.
|
||||
*/
|
||||
static const int MIN_PRECISION_IU = 4;
|
||||
|
||||
SHAPE_ARC() :
|
||||
SHAPE( SH_ARC ), m_width( 0 ) {};
|
||||
|
||||
|
@ -56,6 +61,16 @@ public:
|
|||
*/
|
||||
SHAPE_ARC( const VECTOR2I& aArcStart, const VECTOR2I& aArcMid,
|
||||
const VECTOR2I& aArcEnd, int aWidth );
|
||||
|
||||
/**
|
||||
* SHAPE_ARC ctor.
|
||||
* Builds a SHAPE_ARC which is tangent to two segments and a given radius
|
||||
* @param aSegmentA is the first segment
|
||||
* @param aSegmentB is the second segment
|
||||
* @param aRadius is the arc radius
|
||||
* @param aWidth is the arc line thickness
|
||||
*/
|
||||
SHAPE_ARC( const SEG& aSegmentA, const SEG& aSegmentB, int aRadius, int aWidth = 0 );
|
||||
|
||||
SHAPE_ARC( const SHAPE_ARC& aOther );
|
||||
|
||||
|
|
|
@ -54,6 +54,109 @@ SHAPE_ARC::SHAPE_ARC( const VECTOR2I& aArcStart, const VECTOR2I& aArcMid,
|
|||
}
|
||||
|
||||
|
||||
SHAPE_ARC::SHAPE_ARC( const SEG& aSegmentA, const SEG& aSegmentB, int aRadius, int aWidth )
|
||||
: SHAPE( SH_ARC )
|
||||
{
|
||||
/*
|
||||
* Construct an arc that is tangent to two segments with a given radius.
|
||||
*
|
||||
* p
|
||||
* A
|
||||
* A \
|
||||
* / \
|
||||
* / , * , \ segB
|
||||
* /* *\
|
||||
* segA / c \
|
||||
* / B
|
||||
* /
|
||||
* /
|
||||
* B
|
||||
*
|
||||
*
|
||||
* segA is the fist segment (with its points A and B)
|
||||
* segB is the second segment (with its points A and B)
|
||||
* p is the point at which segA and segB would intersect if they were projected
|
||||
* c is the centre of the arc to be constructed
|
||||
* rad is the radius of the arc to be constructed
|
||||
*
|
||||
* We can create two vectors, betweeen point p and segA /segB
|
||||
* pToA = p - segA.B //< note that segA.A would also be valid as it is colinear
|
||||
* pToB = p - segB.B //< note that segB.A would also be valid as it is colinear
|
||||
*
|
||||
* Let the angle formed by segA and segB be called 'alpha':
|
||||
* alpha = angle( pToA ) - angle( pToB )
|
||||
*
|
||||
* The distance PC can be computed as
|
||||
* distPC = rad / abs( sin( alpha / 2 ) )
|
||||
*
|
||||
* The polar angle of the vector PC can be computed as:
|
||||
* anglePC = angle( pToA ) + alpha / 2
|
||||
*
|
||||
* Therefore:
|
||||
* C.x = P.x + distPC*cos( anglePC )
|
||||
* C.y = P.y + distPC*sin( anglePC )
|
||||
*/
|
||||
|
||||
OPT_VECTOR2I p = aSegmentA.Intersect( aSegmentB, true, true );
|
||||
|
||||
if( !p || aSegmentA.Length() == 0 || aSegmentB.Length() == 0 )
|
||||
{
|
||||
// Catch bugs in debug
|
||||
wxASSERT_MSG( false, "The input segments do not intersect or one is zero length." );
|
||||
|
||||
// Make a 180 degree arc around aSegmentA in case we end up here in release
|
||||
m_start = aSegmentA.A;
|
||||
m_end = aSegmentA.B;
|
||||
m_mid = m_start;
|
||||
|
||||
VECTOR2I arcCenter = aSegmentA.Center();
|
||||
RotatePoint( m_mid, arcCenter, 900.0 ); // mid point at 90 degrees
|
||||
}
|
||||
else
|
||||
{
|
||||
VECTOR2I pToA = aSegmentA.B - p.get();
|
||||
VECTOR2I pToB = aSegmentB.B - p.get();
|
||||
|
||||
if( pToA.EuclideanNorm() == 0 )
|
||||
pToA = aSegmentA.A - p.get();
|
||||
|
||||
if( pToB.EuclideanNorm() == 0 )
|
||||
pToB = aSegmentB.A - p.get();
|
||||
|
||||
double pToAangle = ArcTangente( pToA.y, pToA.x );
|
||||
double pToBangle = ArcTangente( pToB.y, pToB.x );
|
||||
|
||||
double alpha = NormalizeAngle180( pToAangle - pToBangle );
|
||||
|
||||
double distPC = (double) aRadius / abs( sin( DECIDEG2RAD( alpha / 2 ) ) );
|
||||
double angPC = pToAangle - alpha / 2;
|
||||
|
||||
VECTOR2I arcCenter;
|
||||
|
||||
arcCenter.x = p.get().x + KiROUND( distPC * cos( DECIDEG2RAD( angPC ) ) );
|
||||
arcCenter.y = p.get().y + KiROUND( distPC * sin( DECIDEG2RAD( angPC ) ) );
|
||||
|
||||
// The end points of the arc are the orthogonal projected lines from the line segments
|
||||
// to the center of the arc
|
||||
m_start = aSegmentA.LineProject( arcCenter );
|
||||
m_end = aSegmentB.LineProject( arcCenter );
|
||||
|
||||
//The mid point is rotated start point around center, half the angle of the arc.
|
||||
VECTOR2I startVector = m_start - arcCenter;
|
||||
VECTOR2I endVector = m_end - arcCenter;
|
||||
|
||||
double startAngle = ArcTangente( startVector.y, startVector.x );
|
||||
double endAngle = ArcTangente( endVector.y, endVector.x );
|
||||
|
||||
double midPointRotAngle = NormalizeAngle180( startAngle - endAngle ) / 2;
|
||||
m_mid = m_start;
|
||||
RotatePoint( m_mid, arcCenter, midPointRotAngle );
|
||||
}
|
||||
|
||||
update_bbox();
|
||||
}
|
||||
|
||||
|
||||
SHAPE_ARC::SHAPE_ARC( const SHAPE_ARC& aOther )
|
||||
: SHAPE( SH_ARC )
|
||||
{
|
||||
|
|
|
@ -56,6 +56,7 @@ using namespace std::placeholders;
|
|||
#include <router/router_tool.h>
|
||||
#include <dialogs/dialog_move_exact.h>
|
||||
#include <dialogs/dialog_track_via_properties.h>
|
||||
#include <dialogs/dialog_unit_entry.h>
|
||||
#include <board_commit.h>
|
||||
#include <zone_filler.h>
|
||||
|
||||
|
@ -193,6 +194,7 @@ bool EDIT_TOOL::Init()
|
|||
&& SELECTION_CONDITIONS::OnlyTypes( GENERAL_COLLECTOR::Tracks ) );
|
||||
menu.AddItem( PCB_ACTIONS::drag45Degree, SELECTION_CONDITIONS::OnlyTypes( GENERAL_COLLECTOR::Tracks ) );
|
||||
menu.AddItem( PCB_ACTIONS::dragFreeAngle, SELECTION_CONDITIONS::OnlyTypes( GENERAL_COLLECTOR::Tracks ) );
|
||||
menu.AddItem( PCB_ACTIONS::filletTracks, SELECTION_CONDITIONS::OnlyTypes( GENERAL_COLLECTOR::Tracks ) );
|
||||
menu.AddItem( PCB_ACTIONS::rotateCcw, SELECTION_CONDITIONS::NotEmpty );
|
||||
menu.AddItem( PCB_ACTIONS::rotateCw, SELECTION_CONDITIONS::NotEmpty );
|
||||
menu.AddItem( PCB_ACTIONS::flip, SELECTION_CONDITIONS::NotEmpty );
|
||||
|
@ -704,6 +706,182 @@ int EDIT_TOOL::ChangeTrackWidth( const TOOL_EVENT& aEvent )
|
|||
}
|
||||
|
||||
|
||||
int EDIT_TOOL::FilletTracks( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
// Store last used fillet radius to allow pressing "enter" if repeat fillet is required
|
||||
static long long filletRadiusIU = 0;
|
||||
|
||||
auto& selection = m_selectionTool->RequestSelection(
|
||||
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, SELECTION_TOOL* sTool )
|
||||
{
|
||||
EditToolSelectionFilter(
|
||||
aCollector, EXCLUDE_LOCKED | EXCLUDE_LOCKED_PADS | EXCLUDE_TRANSIENTS, sTool );
|
||||
},
|
||||
nullptr, !m_dragging );
|
||||
|
||||
if( selection.Size() < 2 )
|
||||
{
|
||||
m_statusPopup.reset( new STATUS_TEXT_POPUP( frame() ) );
|
||||
m_statusPopup->SetText( _( "A minimum of two straight track segments must be selected." ) );
|
||||
m_statusPopup->Move( wxGetMousePosition() + wxPoint( 20, 20 ) );
|
||||
m_statusPopup->PopupFor( 2000 );
|
||||
return 0;
|
||||
}
|
||||
|
||||
WX_UNIT_ENTRY_DIALOG dia(
|
||||
frame(), _( "Enter fillet radius:" ), _( "Fillet Tracks" ), filletRadiusIU );
|
||||
|
||||
if( dia.ShowModal() == wxID_CANCEL )
|
||||
return 0;
|
||||
|
||||
filletRadiusIU = dia.GetValue();
|
||||
|
||||
if( filletRadiusIU == 0 )
|
||||
{
|
||||
m_statusPopup.reset( new STATUS_TEXT_POPUP( frame() ) );
|
||||
m_statusPopup->SetText( _( "A radius of zero was entered.\n"
|
||||
"The fillet operation was not performed." ) );
|
||||
m_statusPopup->Move( wxGetMousePosition() + wxPoint( 20, 20 ) );
|
||||
m_statusPopup->PopupFor( 2000 );
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool operationPerformedOnAtLeastOne = false;
|
||||
bool didOneAttemptFail = false;
|
||||
|
||||
std::vector<BOARD_ITEM*> itemsToAddToSelection;
|
||||
|
||||
for( auto it = selection.begin(); it != selection.end(); it++ )
|
||||
{
|
||||
TRACK* track1 = dyn_cast<TRACK*>( *it );
|
||||
|
||||
if( !track1 || track1->Type() != PCB_TRACE_T || track1->IsLocked()
|
||||
|| track1->GetLength() == 0 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for( auto it2 = it + 1; it2 != selection.end(); it2++ )
|
||||
{
|
||||
TRACK* track2 = dyn_cast<TRACK*>( *it2 );
|
||||
|
||||
if( !track2 || track2->Type() != PCB_TRACE_T || track2->IsLocked()
|
||||
|| track2->GetLength() == 0 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
bool trackOnStart = track1->IsPointOnEnds( track2->GetStart() );
|
||||
bool trackOnEnd = track1->IsPointOnEnds( track2->GetEnd() );
|
||||
|
||||
if( trackOnStart && trackOnEnd )
|
||||
continue; // Ignore duplicate tracks
|
||||
|
||||
if( ( trackOnStart || trackOnEnd ) && track1->GetLayer() == track2->GetLayer() )
|
||||
{
|
||||
SEG t1Seg( track1->GetStart(), track1->GetEnd() );
|
||||
SEG t2Seg( track2->GetStart(), track2->GetEnd() );
|
||||
|
||||
if( t1Seg.ApproxCollinear( t2Seg ) )
|
||||
continue;
|
||||
|
||||
SHAPE_ARC sArc( t1Seg, t2Seg, filletRadiusIU );
|
||||
|
||||
wxPoint t1newPoint, t2newPoint;
|
||||
|
||||
auto setIfPointOnSeg =
|
||||
[]( wxPoint& aPointToSet, SEG aSegment, VECTOR2I aVecToTest )
|
||||
{
|
||||
// Find out if we are within the segment
|
||||
if( ( aSegment.NearestPoint( aVecToTest ) - aVecToTest ).EuclideanNorm()
|
||||
< SHAPE_ARC::MIN_PRECISION_IU )
|
||||
{
|
||||
aPointToSet.x = aVecToTest.x;
|
||||
aPointToSet.y = aVecToTest.y;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
//Do not draw a fillet if the end points of the arc are not within the track segments
|
||||
if( !setIfPointOnSeg( t1newPoint, t1Seg, sArc.GetP0() )
|
||||
&& !setIfPointOnSeg( t2newPoint, t2Seg, sArc.GetP0() ) )
|
||||
{
|
||||
didOneAttemptFail = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if( !setIfPointOnSeg( t1newPoint, t1Seg, sArc.GetP1() )
|
||||
&& !setIfPointOnSeg( t2newPoint, t2Seg, sArc.GetP1() ) )
|
||||
{
|
||||
didOneAttemptFail = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
ARC* tArc = new ARC( frame()->GetBoard(), &sArc );
|
||||
tArc->SetLayer( track1->GetLayer() );
|
||||
tArc->SetWidth( track1->GetWidth() );
|
||||
tArc->SetNet( track1->GetNet() );
|
||||
m_commit->Add( tArc );
|
||||
itemsToAddToSelection.push_back( tArc );
|
||||
|
||||
m_commit->Modify( track1 );
|
||||
m_commit->Modify( track2 );
|
||||
|
||||
if( track1->GetStart() == track2->GetStart() )
|
||||
{
|
||||
track1->SetStart( t1newPoint );
|
||||
track2->SetStart( t2newPoint );
|
||||
}
|
||||
else if( track1->GetStart() == track2->GetEnd() )
|
||||
{
|
||||
track1->SetStart( t1newPoint );
|
||||
track2->SetEnd( t2newPoint );
|
||||
}
|
||||
else if( track1->GetEnd() == track2->GetEnd() )
|
||||
{
|
||||
track1->SetEnd( t1newPoint );
|
||||
track2->SetEnd( t2newPoint );
|
||||
}
|
||||
else
|
||||
{
|
||||
track1->SetEnd( t1newPoint );
|
||||
track2->SetStart( t2newPoint );
|
||||
}
|
||||
|
||||
operationPerformedOnAtLeastOne = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_commit->Push( _( "Fillet Tracks" ) );
|
||||
|
||||
//select the newly created arcs
|
||||
for( BOARD_ITEM* item : itemsToAddToSelection )
|
||||
{
|
||||
m_selectionTool->AddItemToSel( item );
|
||||
}
|
||||
|
||||
if( !operationPerformedOnAtLeastOne )
|
||||
{
|
||||
m_statusPopup.reset( new STATUS_TEXT_POPUP( frame() ) );
|
||||
m_statusPopup->SetText( _( "Unable to fillet the selected track segments." ) );
|
||||
m_statusPopup->Move( wxGetMousePosition() + wxPoint( 20, 20 ) );
|
||||
m_statusPopup->PopupFor( 2000 );
|
||||
}
|
||||
else if( didOneAttemptFail )
|
||||
{
|
||||
m_statusPopup.reset( new STATUS_TEXT_POPUP( frame() ) );
|
||||
m_statusPopup->SetText( _( "Some of the track segments could not be filleted." ) );
|
||||
m_statusPopup->Move( wxGetMousePosition() + wxPoint( 20, 20 ) );
|
||||
m_statusPopup->PopupFor( 2000 );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int EDIT_TOOL::Properties( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
|
||||
|
@ -1692,6 +1870,7 @@ void EDIT_TOOL::setTransitions()
|
|||
Go( &EDIT_TOOL::CreateArray, PCB_ACTIONS::createArray.MakeEvent() );
|
||||
Go( &EDIT_TOOL::Mirror, PCB_ACTIONS::mirror.MakeEvent() );
|
||||
Go( &EDIT_TOOL::ChangeTrackWidth, PCB_ACTIONS::changeTrackWidth.MakeEvent() );
|
||||
Go( &EDIT_TOOL::FilletTracks, PCB_ACTIONS::filletTracks.MakeEvent() );
|
||||
|
||||
Go( &EDIT_TOOL::copyToClipboard, ACTIONS::copy.MakeEvent() );
|
||||
Go( &EDIT_TOOL::cutToClipboard, ACTIONS::cut.MakeEvent() );
|
||||
|
|
|
@ -123,6 +123,12 @@ public:
|
|||
|
||||
int ChangeTrackWidth( const TOOL_EVENT& aEvent );
|
||||
|
||||
/**
|
||||
* Function FilletTracks()
|
||||
* Fillets (i.e. adds an arc tangent to) all selected straight tracks by a user defined radius
|
||||
*/
|
||||
int FilletTracks( const TOOL_EVENT& aEvent );
|
||||
|
||||
/**
|
||||
* Function Remove()
|
||||
* Deletes currently selected items. The rotation point is the current cursor position.
|
||||
|
|
|
@ -292,6 +292,10 @@ TOOL_ACTION PCB_ACTIONS::changeTrackWidth( "pcbnew.InteractiveEdit.changeTrackWi
|
|||
AS_GLOBAL, 0, "",
|
||||
_( "Change Track Width" ), _( "Updates selected track & via sizes" ) );
|
||||
|
||||
TOOL_ACTION PCB_ACTIONS::filletTracks( "pcbnew.InteractiveEdit.filletTracks",
|
||||
AS_GLOBAL, 0, "",
|
||||
_( "Fillet Tracks" ), _( "Adds arcs tangent to the selected straight track segments" ) );
|
||||
|
||||
TOOL_ACTION PCB_ACTIONS::deleteFull( "pcbnew.InteractiveEdit.deleteFull",
|
||||
AS_GLOBAL,
|
||||
MD_SHIFT + WXK_DELETE, LEGACY_HK_NAME( "Delete Full Track" ),
|
||||
|
|
|
@ -110,6 +110,9 @@ public:
|
|||
/// Updates selected tracks & vias to the current track & via dimensions
|
||||
static TOOL_ACTION changeTrackWidth;
|
||||
|
||||
/// Fillets (i.e. adds an arc tangent to) all selected straight tracks by a user defined radius
|
||||
static TOOL_ACTION filletTracks;
|
||||
|
||||
/// Activation of the edit tool
|
||||
static TOOL_ACTION properties;
|
||||
|
||||
|
|
|
@ -51,8 +51,11 @@ struct ARC_PROPERTIES
|
|||
|
||||
/**
|
||||
* Check a #SHAPE_ARC against a given set of geometric properties
|
||||
* @param aArc Arc to test
|
||||
* @param aProps Properties to test against
|
||||
* @param aSynErrIU Permitted error for synthetic points and dimensions (currently radius and center)
|
||||
*/
|
||||
static void CheckArcGeom( const SHAPE_ARC& aArc, const ARC_PROPERTIES& aProps )
|
||||
static void CheckArcGeom( const SHAPE_ARC& aArc, const ARC_PROPERTIES& aProps, const int aSynErrIU = 1 )
|
||||
{
|
||||
// Angular error - note this can get quite large for very small arcs,
|
||||
// as the integral position rounding has a relatively greater effect
|
||||
|
@ -66,7 +69,7 @@ static void CheckArcGeom( const SHAPE_ARC& aArc, const ARC_PROPERTIES& aProps )
|
|||
BOOST_CHECK_PREDICATE(
|
||||
KI_TEST::IsVecWithinTol<VECTOR2I>, ( aArc.GetP1() )( aProps.m_end_point )( pos_tol ) );
|
||||
BOOST_CHECK_PREDICATE( KI_TEST::IsVecWithinTol<VECTOR2I>,
|
||||
( aArc.GetCenter() )( aProps.m_center_point )( pos_tol ) );
|
||||
( aArc.GetCenter() )( aProps.m_center_point )( aSynErrIU ) );
|
||||
BOOST_CHECK_PREDICATE( KI_TEST::IsWithinWrapped<double>,
|
||||
( aArc.GetCentralAngle() )( aProps.m_center_angle )( 360.0 )( angle_tol_deg ) );
|
||||
BOOST_CHECK_PREDICATE( KI_TEST::IsWithinWrapped<double>,
|
||||
|
@ -74,7 +77,7 @@ static void CheckArcGeom( const SHAPE_ARC& aArc, const ARC_PROPERTIES& aProps )
|
|||
BOOST_CHECK_PREDICATE( KI_TEST::IsWithinWrapped<double>,
|
||||
( aArc.GetEndAngle() )( aProps.m_end_angle )( 360.0 )( angle_tol_deg ) );
|
||||
BOOST_CHECK_PREDICATE(
|
||||
KI_TEST::IsWithin<double>, ( aArc.GetRadius() )( aProps.m_radius )( pos_tol ) );
|
||||
KI_TEST::IsWithin<double>, ( aArc.GetRadius() )( aProps.m_radius )( aSynErrIU ) );
|
||||
|
||||
/// Check the chord agrees
|
||||
const auto chord = aArc.GetChord();
|
||||
|
@ -96,11 +99,14 @@ static void CheckArcGeom( const SHAPE_ARC& aArc, const ARC_PROPERTIES& aProps )
|
|||
|
||||
/**
|
||||
* Check an arcs geometry and other class functions
|
||||
* @param aArc Arc to test
|
||||
* @param aProps Properties to test against
|
||||
* @param aSynErrIU Permitted error for synthetic points and dimensions (currently radius and center)
|
||||
*/
|
||||
static void CheckArc( const SHAPE_ARC& aArc, const ARC_PROPERTIES& aProps )
|
||||
static void CheckArc( const SHAPE_ARC& aArc, const ARC_PROPERTIES& aProps, const int aSynErrIU = 1 )
|
||||
{
|
||||
// Check the original arc
|
||||
CheckArcGeom( aArc, aProps );
|
||||
CheckArcGeom( aArc, aProps, aSynErrIU );
|
||||
|
||||
// Test the Clone function (also tests copy-ctor)
|
||||
std::unique_ptr<SHAPE> new_shape{ aArc.Clone() };
|
||||
|
@ -112,7 +118,7 @@ static void CheckArc( const SHAPE_ARC& aArc, const ARC_PROPERTIES& aProps )
|
|||
BOOST_REQUIRE( new_arc != nullptr );
|
||||
|
||||
/// Should have identical geom props
|
||||
CheckArcGeom( *new_arc, aProps );
|
||||
CheckArcGeom( *new_arc, aProps, aSynErrIU );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -328,6 +334,152 @@ BOOST_AUTO_TEST_CASE( BasicCPAGeom )
|
|||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Info to set up an arc by tangent to two segments and a radius
|
||||
*/
|
||||
struct ARC_TAN_TAN_RADIUS
|
||||
{
|
||||
SEG m_segment_1;
|
||||
SEG m_segment_2;
|
||||
int m_radius;
|
||||
};
|
||||
|
||||
|
||||
struct ARC_TTR_CASE
|
||||
{
|
||||
/// The text context name
|
||||
std::string m_ctx_name;
|
||||
|
||||
/// Geom of the arc
|
||||
ARC_TAN_TAN_RADIUS m_geom;
|
||||
|
||||
/// Arc line width
|
||||
int m_width;
|
||||
|
||||
/// Expected properties
|
||||
ARC_PROPERTIES m_properties;
|
||||
};
|
||||
|
||||
|
||||
static const std::vector<ARC_TTR_CASE> arc_ttr_cases = {
|
||||
{
|
||||
"90 degree segments intersecting",
|
||||
{
|
||||
{ 0, 0, 0, 1000 },
|
||||
{ 0, 0, 1000, 0 },
|
||||
1000,
|
||||
},
|
||||
0,
|
||||
{
|
||||
{ 1000, 1000 },
|
||||
{ 0, 1000 }, //start on first segment
|
||||
{ 1000, 0 }, //end on second segment
|
||||
90, //positive angle due to start/end
|
||||
180,
|
||||
270,
|
||||
1000,
|
||||
{ { 0, 0 }, { 1000, 1000 } },
|
||||
}
|
||||
},
|
||||
{
|
||||
"45 degree segments intersecting",
|
||||
{
|
||||
{ 0, 0, 0, 1000 },
|
||||
{ 0, 0, 1000, 1000 },
|
||||
1000,
|
||||
},
|
||||
0,
|
||||
{
|
||||
{ 1000, 2414 },
|
||||
{ 0, 2414 }, //start on first segment
|
||||
{ 1707, 1707 }, //end on second segment
|
||||
135, //positive angle due to start/end
|
||||
180,
|
||||
225,
|
||||
1000,
|
||||
{ { 0, 1414 }, { 1707, 1000 } },
|
||||
}
|
||||
},
|
||||
{
|
||||
"135 degree segments intersecting",
|
||||
{
|
||||
{ 0, 0, 0, 1000 },
|
||||
{ 0, 0, 1000, -1000 },
|
||||
1000,
|
||||
},
|
||||
0,
|
||||
{
|
||||
{ 1000, 414 },
|
||||
{ 0, 414 }, //start on first segment ( radius * tan(45 /2) )
|
||||
{ 293, -293 }, //end on second segment (radius * 1-cos(45)) )
|
||||
45, //positive angle due to start/end
|
||||
180,
|
||||
225,
|
||||
1000,
|
||||
{ { 0, -293 }, { 293, 707 } },
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( BasicTTRGeom )
|
||||
{
|
||||
for( const auto& c : arc_ttr_cases )
|
||||
{
|
||||
BOOST_TEST_CONTEXT( c.m_ctx_name )
|
||||
{
|
||||
for( int testCase = 0; testCase < 8; ++testCase )
|
||||
{
|
||||
SEG seg1 = c.m_geom.m_segment_1;
|
||||
SEG seg2 = c.m_geom.m_segment_2;
|
||||
ARC_PROPERTIES props = c.m_properties;
|
||||
|
||||
if( testCase > 3 )
|
||||
{
|
||||
//Swap input segments.
|
||||
seg1 = c.m_geom.m_segment_2;
|
||||
seg2 = c.m_geom.m_segment_1;
|
||||
|
||||
//The result should swap start and end points and invert the angles:
|
||||
props.m_end_point = c.m_properties.m_start_point;
|
||||
props.m_start_point = c.m_properties.m_end_point;
|
||||
props.m_start_angle = c.m_properties.m_end_angle;
|
||||
props.m_end_angle = c.m_properties.m_start_angle;
|
||||
props.m_center_angle = -c.m_properties.m_center_angle;
|
||||
}
|
||||
|
||||
//Test all combinations of start and end points for the segments
|
||||
if( ( testCase % 4 ) == 1 || ( testCase % 4 ) == 3 )
|
||||
{
|
||||
//Swap start and end points for seg1
|
||||
VECTOR2I temp = seg1.A;
|
||||
seg1.A = seg1.B;
|
||||
seg1.B = temp;
|
||||
}
|
||||
|
||||
if( ( testCase % 4 ) == 2 || ( testCase % 4 ) == 3 )
|
||||
{
|
||||
//Swap start and end points for seg2
|
||||
VECTOR2I temp = seg2.A;
|
||||
seg2.A = seg2.B;
|
||||
seg2.B = temp;
|
||||
}
|
||||
|
||||
const auto this_arc = SHAPE_ARC{ seg1, seg2,
|
||||
c.m_geom.m_radius, c.m_width };
|
||||
|
||||
// Error of 4 IU permitted for the center and radius calculation
|
||||
CheckArc( this_arc, props, SHAPE_ARC::MIN_PRECISION_IU );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct ARC_TO_POLYLINE_CASE
|
||||
{
|
||||
std::string m_ctx_name;
|
||||
|
|
Loading…
Reference in New Issue