Commit 0153fbf3 authored by Clownce Deng's avatar Clownce Deng

chore: first add

parents
cmake_minimum_required(VERSION 3.1)
cmake_policy(VERSION 3.1)
# Enable policy to not use RPATH settings for install_name on macOS.
if(POLICY CMP0068)
cmake_policy(SET CMP0068 NEW)
endif()
# Enable policy to run automoc on generated files.
if(POLICY CMP0071)
cmake_policy(SET CMP0071 NEW)
endif()
# Consider changing the project name to something relevant for you.
project(pcbcam LANGUAGES CXX)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
find_package(Qt5 5.12 REQUIRED COMPONENTS Core Gui Widgets)
# ================================ General configuration ======================================
# Set CPP standard to C++11 minimum.
set(CMAKE_CXX_STANDARD 11)
# The library for which we will create bindings. You can change the name to something
# relevant for your project.
set(project_library "libpcbcam")
# The name of the generated bindings module (as imported in Python). You can change the name
# to something relevant for your project.
set(bindings_library "pcbcam")
# The header file with all the types and functions for which bindings will be generated.
# Usually it simply includes other headers of the library you are creating bindings for.
set(wrapped_header ${CMAKE_SOURCE_DIR}/bindings.h)
# The typesystem xml file which defines the relationships between the C++ types / functions
# and the corresponding Python equivalents.
set(typesystem_file ${CMAKE_SOURCE_DIR}/bindings.xml)
# Specify which C++ files will be generated by shiboken. This includes the module wrapper
# and a '.cpp' file per C++ type. These are needed for generating the module shared
# library.
set(generated_sources
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcam_module_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamabstractdataio_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamattrdefine_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcam_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcam_attrcompareinfo_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcam_featureselectionfilter_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamconfig_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamcore_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamfeature_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamfeatureline_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamfeaturepad_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamfeaturearc_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamfeaturetext_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamfeaturebarcode_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamfeaturesurface_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamfont_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamfontcharline_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamjob_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamlayer_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcammath_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcammatrixlayer_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamstep_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamsteprepeat_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamsymbol_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamsymbolr_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamsymbols_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamsymbolrect_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamsymbolrectr_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamsymbolrectc_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamsymboloval_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamsymboldi_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamsymboloct_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamsymboldonutr_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamsymboldonuts_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamsymbolhexl_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamsymbolhexs_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamsymbolbfr_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamsymbolbfs_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamsymboltri_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamsymbolovalh_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamsymbolthr_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamsymbolths_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamsymbolsths_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamsymbolstho_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamsymbolsrths_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamsymbolrcths_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamsymbolrctho_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamsymbolel_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamsymbolmoire_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamsymboluser_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamsymbolfactory_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamutil_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamodbfeatureparser_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamodbmatrixparser_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamparserhelper_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcamcanvas_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/pcbcampopviewwindow_wrapper.cpp)
# ================================== Shiboken detection ======================================
# Use provided python interpreter if given.
if(NOT python_interpreter)
find_program(python_interpreter "python")
endif()
message(STATUS "Using python interpreter: ${python_interpreter}")
# Macro to get various pyside / python include / link flags and paths.
# Uses the not entirely supported utils/pyside2_config.py file.
macro(pyside2_config option output_var)
if(${ARGC} GREATER 2)
set(is_list ${ARGV2})
else()
set(is_list "")
endif()
execute_process(
COMMAND ${python_interpreter} "${CMAKE_SOURCE_DIR}/pyside2_config.py"
${option}
OUTPUT_VARIABLE ${output_var}
OUTPUT_STRIP_TRAILING_WHITESPACE)
if ("${${output_var}}" STREQUAL "")
message(FATAL_ERROR "Error: Calling pyside2_config.py ${option} returned no output.")
endif()
if(is_list)
string (REPLACE " " ";" ${output_var} "${${output_var}}")
endif()
endmacro()
# Query for the shiboken generator path, Python path, include paths and linker flags.
pyside2_config(--shiboken2-module-path shiboken2_module_path)
pyside2_config(--shiboken2-generator-path shiboken2_generator_path)
pyside2_config(--pyside2-path pyside2_path)
pyside2_config(--pyside2-include-path pyside2_include_dir 1)
pyside2_config(--python-include-path python_include_dir)
pyside2_config(--shiboken2-generator-include-path shiboken_include_dir 1)
pyside2_config(--shiboken2-module-shared-libraries-cmake shiboken_shared_libraries 0)
pyside2_config(--python-link-flags-cmake python_linking_data 0)
pyside2_config(--pyside2-shared-libraries-cmake pyside2_shared_libraries 0)
set(shiboken_path "${shiboken2_generator_path}/shiboken2${CMAKE_EXECUTABLE_SUFFIX}")
if(NOT EXISTS ${shiboken_path})
message(FATAL_ERROR "Shiboken executable not found at path: ${shiboken_path}")
endif()
# ==================================== RPATH configuration ====================================
# =============================================================================================
# !!! (The section below is deployment related, so in a real world application you will want to
# take care of this properly with some custom script or tool).
# =============================================================================================
# Enable rpaths so that the built shared libraries find their dependencies.
set(CMAKE_SKIP_BUILD_RPATH FALSE)
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
set(CMAKE_INSTALL_RPATH ${shiboken2_module_path} ${CMAKE_CURRENT_SOURCE_DIR})
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
# =============================================================================================
# !!! End of dubious section.
# =============================================================================================
# =============================== CMake target - project_library ===============================
# Get all relevant Qt include dirs, to pass them on to shiboken.
get_property(QT_CORE_INCLUDE_DIRS TARGET Qt5::Core PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
get_property(QT_GUI_INCLUDE_DIRS TARGET Qt5::Gui PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
get_property(QT_WIDGETS_INCLUDE_DIRS TARGET Qt5::Widgets PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
set(QT_INCLUDE_DIRS ${QT_CORE_INCLUDE_DIRS} ${QT_GUI_INCLUDE_DIRS} ${QT_WIDGETS_INCLUDE_DIRS})
set(INCLUDES "")
foreach(INCLUDE_DIR ${QT_INCLUDE_DIRS})
list(APPEND INCLUDES "-I${INCLUDE_DIR}")
endforeach()
# On macOS, check if Qt is a framework build. This affects how include paths should be handled.
get_target_property(QtCore_is_framework Qt5::Core FRAMEWORK)
if (QtCore_is_framework)
get_target_property(qt_core_library_location Qt5::Core LOCATION)
get_filename_component(qt_core_library_location_dir "${qt_core_library_location}" DIRECTORY)
get_filename_component(lib_dir "${qt_core_library_location_dir}/../" ABSOLUTE)
list(APPEND INCLUDES "--framework-include-paths=${lib_dir}")
endif()
# We need to include the headers for the module bindings that we use.
set(pyside2_additional_includes "")
foreach(INCLUDE_DIR ${pyside2_include_dir})
list(APPEND pyside2_additional_includes "${INCLUDE_DIR}/QtCore")
list(APPEND pyside2_additional_includes "${INCLUDE_DIR}/QtGui")
list(APPEND pyside2_additional_includes "${INCLUDE_DIR}/QtWidgets")
endforeach()
# Define the wiggly shared library for which we will create bindings.
set(${project_library}_sources
lib/core/abstractdataio.h
lib/core/attrdefine.cpp
lib/core/common.h
lib/core/config.cpp
lib/core/core.cpp
lib/core/feature.cpp
lib/core/font.cpp
lib/core/fontcharline.cpp
lib/core/job.cpp
lib/core/layer.cpp
lib/core/math.cpp
lib/core/matrixlayer.cpp
lib/core/step.cpp
lib/core/steprepeat.cpp
lib/core/symbol.cpp
lib/core/symbolfactory.cpp
lib/core/util.cpp
lib/parser/odbfeatureparser.cpp
lib/parser/odbmatrixparser.cpp
lib/parser/parserhelper.cpp
lib/widget/canvas.cpp
lib/widget/popviewwindow.cpp)
add_library(${project_library} SHARED ${${project_library}_sources})
set_property(TARGET ${project_library} PROPERTY PREFIX "")
# Needed mostly on Windows to export symbols, and create a .lib file, otherwise the binding
# library can't link to the wiggly library.
target_compile_definitions(${project_library} PRIVATE BINDINGS_BUILD)
# ====================== Shiboken target for generating binding C++ files ====================
# Set up the options to pass to shiboken.
set(shiboken_options --generator-set=shiboken --enable-parent-ctor-heuristic
--enable-pyside-extensions --enable-return-value-heuristic --use-isnull-as-nb_nonzero
--avoid-protected-hack
${INCLUDES}
-I${CMAKE_SOURCE_DIR}
-T${CMAKE_SOURCE_DIR}
-T${pyside2_path}/typesystems
--output-directory=${CMAKE_CURRENT_BINARY_DIR}
)
set(generated_sources_dependencies ${wrapped_header} ${typesystem_file})
# Add custom target to run shiboken to generate the binding cpp files.
add_custom_command(OUTPUT ${generated_sources}
COMMAND ${shiboken_path}
${shiboken_options} ${wrapped_header} ${typesystem_file}
DEPENDS ${generated_sources_dependencies}
#IMPLICIT_DEPENDS CXX ${wrapped_header}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Running generator for ${typesystem_file}.")
# =============================== CMake target - bindings_library =============================
# Set the cpp files which will be used for the bindings library.
set(${bindings_library}_sources ${generated_sources})
# Define and build the bindings library.
add_library(${bindings_library} SHARED ${${bindings_library}_sources})
# Apply relevant include and link flags.
target_include_directories(${bindings_library} PRIVATE ${pyside2_additional_includes})
target_include_directories(${bindings_library} PRIVATE ${pyside2_include_dir})
target_include_directories(${bindings_library} PRIVATE ${python_include_dir})
target_include_directories(${bindings_library} PRIVATE ${shiboken_include_dir})
target_link_libraries(${project_library} PRIVATE Qt5::Widgets)
target_link_libraries(${bindings_library} PRIVATE Qt5::Widgets)
target_link_libraries(${bindings_library} PRIVATE ${project_library})
target_link_libraries(${bindings_library} PRIVATE ${pyside2_shared_libraries})
target_link_libraries(${bindings_library} PRIVATE ${shiboken_shared_libraries})
# Adjust the name of generated module.
set_property(TARGET ${bindings_library} PROPERTY PREFIX "")
set_property(TARGET ${bindings_library} PROPERTY OUTPUT_NAME
"${bindings_library}${PYTHON_EXTENSION_SUFFIX}")
if(WIN32)
set_property(TARGET ${bindings_library} PROPERTY SUFFIX ".pyd")
endif()
# Make sure the linker doesn't complain about not finding Python symbols on macOS.
if(APPLE)
set_target_properties(${bindings_library} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup")
endif(APPLE)
# Find and link to the python import library only on Windows.
# On Linux and macOS, the undefined symbols will get resolved by the dynamic linker
# (the symbols will be picked up in the Python executable).
if (WIN32)
list(GET python_linking_data 0 python_libdir)
list(GET python_linking_data 1 python_lib)
find_library(python_link_flags ${python_lib} PATHS ${python_libdir} HINTS ${python_libdir})
target_link_libraries(${bindings_library} PRIVATE ${python_link_flags})
endif()
# ================================= Dubious deployment section ================================
set(windows_shiboken_shared_libraries)
if(WIN32)
# =========================================================================================
# !!! (The section below is deployment related, so in a real world application you will
# want to take care of this properly (this is simply to eliminate errors that users usually
# encounter.
# =========================================================================================
# Circumvent some "#pragma comment(lib)"s in "include/pyconfig.h" which might force to link
# against a wrong python shared library.
set(python_versions_list 3 32 33 34 35 36 37 38)
set(python_additional_link_flags "")
foreach(ver ${python_versions_list})
set(python_additional_link_flags
"${python_additional_link_flags} /NODEFAULTLIB:\"python${ver}_d.lib\"")
set(python_additional_link_flags
"${python_additional_link_flags} /NODEFAULTLIB:\"python${ver}.lib\"")
endforeach()
set_target_properties(${bindings_library}
PROPERTIES LINK_FLAGS "${python_additional_link_flags}")
# Compile a list of shiboken shared libraries to be installed, so that
# the user doesn't have to set the PATH manually to point to the PySide2 package.
foreach(library_path ${shiboken_shared_libraries})
string(REGEX REPLACE ".lib$" ".dll" library_path ${library_path})
file(TO_CMAKE_PATH ${library_path} library_path)
list(APPEND windows_shiboken_shared_libraries "${library_path}")
endforeach()
# =========================================================================================
# !!! End of dubious section.
# =========================================================================================
endif()
# =============================================================================================
# !!! (The section below is deployment related, so in a real world application you will want to
# take care of this properly with some custom script or tool).
# =============================================================================================
# Install the library and the bindings module into the source folder near the main.py file, so
# that the Python interpeter successfully imports the used module.
install(TARGETS ${bindings_library} ${project_library}
LIBRARY DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}
RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}
)
install(FILES ${windows_shiboken_shared_libraries} DESTINATION ${CMAKE_CURRENT_SOURCE_DIR})
# =============================================================================================
# !!! End of dubious section.
# =============================================================================================
File added
#ifndef BINDINGS_H
#define BINDINGS_H
#include "lib/core/abstractdataio.h"
#include "lib/core/attrdefine.h"
#include "lib/core/common.h"
#include "lib/core/config.h"
#include "lib/core/core.h"
#include "lib/core/feature.h"
#include "lib/core/font.h"
#include "lib/core/fontcharline.h"
#include "lib/core/job.h"
#include "lib/core/layer.h"
#include "lib/core/math.h"
#include "lib/core/matrixlayer.h"
#include "lib/core/step.h"
#include "lib/core/steprepeat.h"
#include "lib/core/symbol.h"
#include "lib/core/symbolfactory.h"
#include "lib/core/util.h"
#include "lib/parser/odbfeatureparser.h"
#include "lib/parser/odbmatrixparser.h"
#include "lib/parser/parserhelper.h"
#include "lib/widget/canvas.h"
#include "lib/widget/popviewwindow.h"
#endif // BINDINGS_H
<?xml version="1.0" encoding="UTF-8"?>
<typesystem package="pcbcam">
<load-typesystem name="typesystem_core.xml" generate="no"/>
<load-typesystem name="typesystem_gui.xml" generate="no"/>
<load-typesystem name="typesystem_widgets.xml" generate="no"/>
<!--abstractdataio-->
<object-type name="PcbCamAbstractDataIo"/>
<!--attrdefine-->
<object-type name="PcbCamAttrDefine">
<enum-type name="DataType"/>
<enum-type name="EntityFlag" flags="Entity"/>
<enum-type name="Units"/>
</object-type>
<!--common-->
<object-type name="PcbCam">
<enum-type name="LayerContext" flags="LayerContexts"/>
<enum-type name="FeatureType" flags="FeatureTypes"/>
<enum-type name="Polarity" flags="Polarities"/>
<enum-type name="ProfileRegion" flags="ProfileRegions"/>
<enum-type name="Orient"/>
<enum-type name="SymbolType"/>
<enum-type name="BarcodeTextPos"/>
<enum-type name="FeatureSelectionOperation"/>
<enum-type name="FeatureSelectionMode"/>
<enum-type name="UnitsType"/>
<enum-type name="LogicOperator"/>
<enum-type name="SnapMode" flags="SnapModes"/>
<enum-type name="DisplayOption" flags="DisplayOptions"/>
<enum-type name="MessageType"/>
<object-type name="FeatureSelectionFilter"/>
<object-type name="AttrCompareInfo"/>
</object-type>
<!--config-->
<object-type name="PcbCamConfig"/>
<!--core-->
<object-type name="PcbCamCore"/>
<!--feature-->
<object-type name="PcbCamFeature"/>
<object-type name="PcbCamFeatureLine"/>
<object-type name="PcbCamFeaturePad"/>
<object-type name="PcbCamFeatureArc"/>
<object-type name="PcbCamFeatureText"/>
<object-type name="PcbCamFeatureBarcode"/>
<object-type name="PcbCamFeatureSurface"/>
<!--font-->
<object-type name="PcbCamFont"/>
<!--fontcharline-->
<object-type name="PcbCamFontCharLine">
<enum-type name="LineShape"/>
</object-type>
<!--job-->
<object-type name="PcbCamJob"/>
<!--layer-->
<object-type name="PcbCamLayer"/>
<!--math-->
<object-type name="PcbCamMath"/>
<!--matrixlayer-->
<value-type name="PcbCamMatrixLayer"/>
<!--step-->
<object-type name="PcbCamStep"/>
<!--steprepeat-->
<object-type name="PcbCamStepRepeat"/>
<!--symbol-->
<object-type name="PcbCamSymbol"/>
<object-type name="PcbCamSymbolR"/>
<object-type name="PcbCamSymbolS"/>
<object-type name="PcbCamSymbolRect"/>
<object-type name="PcbCamSymbolRectR"/>
<object-type name="PcbCamSymbolRectC"/>
<object-type name="PcbCamSymbolOval"/>
<object-type name="PcbCamSymbolDi"/>
<object-type name="PcbCamSymbolOct"/>
<object-type name="PcbCamSymbolDonutR"/>
<object-type name="PcbCamSymbolDonutS"/>
<object-type name="PcbCamSymbolHexL"/>
<object-type name="PcbCamSymbolHexS"/>
<object-type name="PcbCamSymbolBfr"/>
<object-type name="PcbCamSymbolBfs"/>
<object-type name="PcbCamSymbolTri"/>
<object-type name="PcbCamSymbolOvalH"/>
<object-type name="PcbCamSymbolThr"/>
<object-type name="PcbCamSymbolThs"/>
<object-type name="PcbCamSymbolSThs"/>
<object-type name="PcbCamSymbolSTho"/>
<object-type name="PcbCamSymbolSrThs"/>
<object-type name="PcbCamSymbolRcThs"/>
<object-type name="PcbCamSymbolRcTho"/>
<object-type name="PcbCamSymbolEl"/>
<object-type name="PcbCamSymbolMoire"/>
<object-type name="PcbCamSymbolUser"/>
<!--symbolfactory-->
<object-type name="PcbCamSymbolFactory"/>
<!--util-->
<rejection class="PcbCamUtil" function-name="point2segDist"/>
<rejection class="PcbCamUtil" function-name="point2polylineDist"/>
<object-type name="PcbCamUtil"/>
<!--odbfeatureparser-->
<object-type name="PcbCamOdbFeatureParser"/>
<!--odbmatrixparser-->
<object-type name="PcbCamOdbMatrixParser"/>
<!--parserhelper-->
<object-type name="PcbCamParserHelper"/>
<!--canvas-->
<object-type name="PcbCamCanvas">
<enum-type name="MouseMode"/>
<enum-type name="LayerScope" flags="LayerScopes"/>
</object-type>
<!--popviewwindow-->
<object-type name="PcbCamPopViewWindow"/>
</typesystem>
\ No newline at end of file
#ifndef TITAN_PCBCAM_ABSTRACTDATAIO_H
#define TITAN_PCBCAM_ABSTRACTDATAIO_H
#include "../titanpcbcamglobal.h"
#include <QObject>
TITAN_BEGIN_NAMESPACE
class TITAN_PCBCAM_EXPORT PcbCamAbstractDataIo : public QObject
{
Q_OBJECT
public:
explicit PcbCamAbstractDataIo(QObject *parent = nullptr):QObject(parent){}
~PcbCamAbstractDataIo(){}
virtual void clearJobDataCache(const QString &/*iJobPath*/) {}
virtual QVariantList getDbList() = 0;
virtual QVariantList getJobList(const QString &iDb = "") = 0;
virtual QByteArray readJobData(const QString &iJobPath, const QString &iRealtivePath, QString *oError = nullptr) = 0;
virtual bool writeJobData(const QString &iJobPath, const QString &iRealtivePath, const QByteArray &iData, const QString *oError = nullptr) = 0;
};
TITAN_END_NAMESPACE
#endif // TITAN_PCBCAM_ABSTRACTDATAIO_H
#include "arcpainterinfo.h"
#include <QtMath>
#include <QDebug>
TITAN_BEGIN_NAMESPACE
class PcbCamArcPainterInfoData : public QSharedData
{
public:
PcbCamArcPainterInfoData() { }
PcbCamArcPainterInfoData(const PcbCamArcPainterInfoData &other): QSharedData(other){ }
~PcbCamArcPainterInfoData() { }
QRectF rect;
qreal startAngle {0.0};
qreal spanAngle {0.0};
};
PcbCamArcPainterInfo::PcbCamArcPainterInfo(qreal xs, qreal ys, qreal xe, qreal ye, qreal xc, qreal yc, bool cw) : d(new PcbCamArcPainterInfoData)
{
qreal sax = xs - xc, say = ys - yc;
qreal eax = xe - xc, eay = ye - yc;
qreal r = qSqrt(sax * sax + say * say);
qreal sa = qAtan2(-say, sax);
qreal ea = qAtan2(-eay, eax);
if (cw) {
if (ea <= sa) {
ea += 2.0 * M_PI;
}
}
else {
if (sa <= ea) {
sa += 2.0 * M_PI;
}
}
d->rect = QRectF(xc - r, yc - r, r * 2.0, r * 2.0);
d->startAngle = sa * (180.0 / M_PI) *16;
d->spanAngle = (ea - sa) * (180.0 / M_PI) * 16;
}
PcbCamArcPainterInfo::PcbCamArcPainterInfo(const PcbCamArcPainterInfo &rhs) : d(rhs.d)
{
}
PcbCamArcPainterInfo &PcbCamArcPainterInfo::operator=(const PcbCamArcPainterInfo &rhs)
{
if (this != &rhs)
d.operator=(rhs.d);
return *this;
}
PcbCamArcPainterInfo::~PcbCamArcPainterInfo()
{
}
QRectF PcbCamArcPainterInfo::rect() const
{
return d->rect;
}
qreal PcbCamArcPainterInfo::startAngle() const
{
return d->startAngle;
}
qreal PcbCamArcPainterInfo::spanAngle() const
{
return d->spanAngle;
}
TITAN_END_NAMESPACE
#ifndef TITAN_PCBCAM_ARCPAINTERINFO_H
#define TITAN_PCBCAM_ARCPAINTERINFO_H
#include "titanpcbcamglobal.h"
#include <QSharedDataPointer>
#include <QRectF>
TITAN_BEGIN_NAMESPACE
class PcbCamArcPainterInfoData;
class TITAN_PCBCAM_EXPORT PcbCamArcPainterInfo
{
public:
PcbCamArcPainterInfo(qreal xs, qreal ys, qreal xe, qreal ye, qreal xc, qreal yc, bool cw);
PcbCamArcPainterInfo(const PcbCamArcPainterInfo &);
PcbCamArcPainterInfo &operator=(const PcbCamArcPainterInfo &);
~PcbCamArcPainterInfo();
QRectF rect() const;
qreal startAngle() const;
qreal spanAngle() const;
private:
QSharedDataPointer<PcbCamArcPainterInfoData> d;
};
TITAN_END_NAMESPACE
#endif // TITAN_PCBCAM_ARCPAINTERINFO_H
#include "attrdefine.h"
TITAN_BEGIN_NAMESPACE
class PcbCamAttrDefineData : public QSharedData
{
public:
PcbCamAttrDefineData() { }
PcbCamAttrDefineData(const PcbCamAttrDefineData &other): QSharedData(other),
dataType(other.dataType),
name(other.name),
prompt(other.prompt),
entity(other.entity),
defaultValue(other.defaultValue),
minLength(other.minLength),
maxLength(other.maxLength),
options(other.options),
deleted(other.deleted),
units(other.units),
index(other.index) { }
~PcbCamAttrDefineData() { }
//数据类型
PcbCamAttrDefine::DataType dataType {PcbCamAttrDefine::Text};
//属性名称
QString name;
//属性标题
QString prompt;
//属性适用范围
PcbCamAttrDefine::Entity entity {PcbCamAttrDefine::Feature};
//默认值
QVariant defaultValue;
//最小长度
uint minLength {0};
//最大长度
uint maxLength {100};
//选项列表
QStringList options;
//暂时不知道干什么用的,规范文档里描述如下:
//A semi colon (;) separated list of the values YES and NO.This
//corresponds to the list of options, possibly causing an option to be
//deleted (YES value)
QStringList deleted;
//属性单位
PcbCamAttrDefine::Units units {PcbCamAttrDefine::NoUnits};
//排序
int index {0};
};
PcbCamAttrDefine::PcbCamAttrDefine() : d(new PcbCamAttrDefineData)
{
}
PcbCamAttrDefine::PcbCamAttrDefine(const PcbCamAttrDefine &rhs) : d(rhs.d)
{
}
PcbCamAttrDefine &PcbCamAttrDefine::operator=(const PcbCamAttrDefine &rhs)
{
if (this != &rhs)
d.operator=(rhs.d);
return *this;
}
PcbCamAttrDefine::~PcbCamAttrDefine()
{
}
PcbCamAttrDefine::DataType PcbCamAttrDefine::dataType() const
{
return d->dataType;
}
void PcbCamAttrDefine::setDataType(PcbCamAttrDefine::DataType iDataType)
{
d->dataType = iDataType;
}
QString PcbCamAttrDefine::name() const
{
return d->name;
}
void PcbCamAttrDefine::setName(const QString &iName)
{
d->name = iName;
}
QString PcbCamAttrDefine::prompt() const
{
return d->prompt;
}
void PcbCamAttrDefine::setPrompt(const QString &iPrompt)
{
d->prompt = iPrompt;
}
PcbCamAttrDefine::Entity PcbCamAttrDefine::entity() const
{
return d->entity;
}
void PcbCamAttrDefine::setEntity(PcbCamAttrDefine::Entity iEntity)
{
d->entity = iEntity;
}
QVariant PcbCamAttrDefine::defaultValue() const
{
return d->defaultValue;
}
void PcbCamAttrDefine::setDefaultValue(const QVariant &iValue)
{
d->defaultValue = iValue;
}
uint PcbCamAttrDefine::minLength() const
{
return d->minLength;
}
void PcbCamAttrDefine::setMinLength(uint iLen)
{
d->minLength = iLen;
}
uint PcbCamAttrDefine::maxLength() const
{
return d->maxLength;
}
void PcbCamAttrDefine::setMaxLength(uint iLen)
{
d->maxLength = iLen;
}
QStringList PcbCamAttrDefine::options() const
{
return d->options;
}
void PcbCamAttrDefine::setOptions(const QStringList &iOptions)
{
d->options = iOptions;
}
QStringList PcbCamAttrDefine::deleted() const
{
return d->deleted;
}
void PcbCamAttrDefine::setDeleted(const QStringList &iList)
{
d->deleted = iList;
}
PcbCamAttrDefine::Units PcbCamAttrDefine::units() const
{
return d->units;
}
void PcbCamAttrDefine::setUnits(PcbCamAttrDefine::Units iUnits)
{
d->units = iUnits;
}
int PcbCamAttrDefine::index() const
{
return d->index;
}
void PcbCamAttrDefine::setIndex(int iIndex)
{
d->index = iIndex;
}
PcbCamAttrDefine::DataType PcbCamAttrDefine::dataTypeFromString(const QString &iStr)
{
QString str = iStr.toUpper();
if (str == "BOOLEAN") {
return PcbCamAttrDefine::Boolean;
}
else if (str == "OPTION") {
return PcbCamAttrDefine::Option;
}
else if (str == "INTEGER") {
return PcbCamAttrDefine::Integer;
}
else if (str == "FLOAT") {
return PcbCamAttrDefine::Float;
}
return PcbCamAttrDefine::Text;
}
PcbCamAttrDefine::Entity PcbCamAttrDefine::entityFromString(const QString &iStr)
{
QStringList list = iStr.trimmed().toUpper().split(";", Qt::SkipEmptyParts);
PcbCamAttrDefine::Entity entity;
for (const QString &item : list) {
if (item == "JOB"){
entity |= PcbCamAttrDefine::Job;
}
else if (item == "STEP"){
entity |= PcbCamAttrDefine::Step;
}
else if (item == "SYMBOL"){
entity |= PcbCamAttrDefine::Symbol;
}
else if (item == "LAYER"){
entity |= PcbCamAttrDefine::Layer;
}
else if (item == "STACKUP"){
entity |= PcbCamAttrDefine::Stackup;
}
else if (item == "WHEEL"){
entity |= PcbCamAttrDefine::Wheel;
}
else if (item == "FEATURE"){
entity |= PcbCamAttrDefine::Feature;
}
else if (item == "COMPONENT"){
entity |= PcbCamAttrDefine::Component;
}
else if (item == "ALL") {
entity = PcbCamAttrDefine::All;
}
}
return entity;
}
TITAN_END_NAMESPACE
#ifndef TITAN_PCBCAM_ATTRDEFINE_H
#define TITAN_PCBCAM_ATTRDEFINE_H
#include "../titanpcbcamglobal.h"
#include <QSharedDataPointer>
#include <QStringList>
#include <QVariant>
TITAN_BEGIN_NAMESPACE
class PcbCamAttrDefineData;
class TITAN_PCBCAM_EXPORT PcbCamAttrDefine
{
public:
enum DataType {
Boolean,
Text,
Option,
Integer,
Float
};
enum EntityFlag {
Job = 0x0001,
Step = 0x0002,
Symbol = 0x0004,
Layer = 0x0008,
Stackup = 0x0010,
Wheel = 0x0020,
Feature = 0x0040,
Component = 0x0080,
All = Job | Step | Symbol | Layer | Stackup | Wheel | Feature | Component
};
Q_DECLARE_FLAGS(Entity, EntityFlag)
enum Units {
NoUnits,
InchMm,
MilMicrons
};
PcbCamAttrDefine();
PcbCamAttrDefine(const PcbCamAttrDefine &);
PcbCamAttrDefine &operator=(const PcbCamAttrDefine &);
~PcbCamAttrDefine();
PcbCamAttrDefine::DataType dataType() const;
void setDataType(DataType iDataType);
QString name() const;
void setName(const QString &iName);
QString prompt() const;
void setPrompt(const QString &iPrompt);
PcbCamAttrDefine::Entity entity() const;
void setEntity(Entity iEntity);
QVariant defaultValue() const;
void setDefaultValue(const QVariant &iValue);
uint minLength() const;
void setMinLength(uint iLen);
uint maxLength() const;
void setMaxLength(uint iLen);
QStringList options() const;
void setOptions(const QStringList &iOptions);
QStringList deleted() const;
void setDeleted(const QStringList &iList);
Units units() const;
void setUnits(Units iUnits);
int index() const;
void setIndex(int iIndex);
static PcbCamAttrDefine::DataType dataTypeFromString(const QString &iStr);
static PcbCamAttrDefine::Entity entityFromString(const QString &iStr);
private:
QSharedDataPointer<PcbCamAttrDefineData> d;
};
TITAN_END_NAMESPACE
Q_DECLARE_OPERATORS_FOR_FLAGS(titan::PcbCamAttrDefine::Entity)
#endif // TITAN_PCBCAM_ATTRDEFINE_H
#ifndef TITAN_PCBCAM_COMMON_H
#define TITAN_PCBCAM_COMMON_H
#include "../titanpcbcamglobal.h"
#include <Qt>
#include <QString>
#include <QRegularExpression>
TITAN_BEGIN_NAMESPACE
class TITAN_PCBCAM_EXPORT PcbCam : public QObject
{
Q_OBJECT
public:
enum LayerContext {
BoardContext = 0x01,
MiscContext = 0x02,
AllContext = BoardContext|MiscContext,
};
Q_ENUM(LayerContext)
Q_DECLARE_FLAGS(LayerContexts, LayerContext)
Q_FLAGS(LayerContexts)
enum FeatureType {
LineFeature = 0x0001,
PadFeature = 0x0002,
ArcFeature = 0x0004,
TextFeature = 0x0008,
BarcodeFeature = 0x0010,
SurfaceFeature = 0x0200,
PathFeature = 0x0400, // profile and package
ComponentFeature = 0x0800, // component
AllFeatures = LineFeature|PadFeature|ArcFeature|TextFeature|BarcodeFeature|SurfaceFeature|PathFeature|ComponentFeature,
};
Q_ENUM(FeatureType)
Q_DECLARE_FLAGS(FeatureTypes, FeatureType)
Q_FLAGS(FeatureTypes)
enum Polarity {
Positive = 0x01,
Negative = 0x02,
BothPolarity = Positive|Negative,
};
Q_ENUM(Polarity)
Q_DECLARE_FLAGS(Polarities, Polarity)
Q_FLAGS(Polarities)
enum ProfileRegion {
InProfile = 0x01,
OutProfile = 0x02,
AllProfile = InProfile|OutProfile,
};
Q_ENUM(ProfileRegion)
Q_DECLARE_FLAGS(ProfileRegions, ProfileRegion)
Q_FLAGS(Polarities)
enum Orient {
Orient_N_0 = 0,
Orient_N_90 = 1,
Orient_N_180 = 2,
Orient_N_270 = 3,
Orient_Y_0 = 4,
Orient_Y_90 = 5,
Orient_Y_180 = 6,
Orient_Y_270 = 7
};
enum SymbolType {
Sym_R,
Sym_S,
Sym_Rect,
Sym_RectR,
Sym_RectC,
Sym_Oval,
Sym_Di,
Sym_Oct,
Sym_DonutR,
Sym_DonutS,
Sym_HexL,
Sym_HexS,
Sym_Bfr,
Sym_Bfs,
Sym_Tri,
Sym_OvalH,
Sym_Thr,
Sym_Ths,
Sym_SThs,
Sym_STho,
Sym_SrThs,
Sym_RcThs,
Sym_RcTho,
Sym_El,
Sym_Moire,
Sym_Hole,
Sym_User = 1000,
};
enum BarcodeTextPos {
BarcodeTextPos_Top,
BarcodeTextPos_Bot,
};
enum FeatureSelectionOperation {
NoFeatureSelection,
ReplaceFeatureSelection,
AppendFeatureSelection,
RemoveFeatureSelection,
};
enum FeatureSelectionMode {
ContainsFeatureShape,
IntersectsFeatureShape,
};
enum UnitsType {
Units_Unknow,
Units_Inch,
Units_Mm
};
enum ZerosOmit
{
ZerosOmit_Unknow,
ZerosOmit_None,
ZerosOmit_Leading,
ZerosOmit_Training,
ZerosOmit_Decimal,
};
enum CoordNotation
{
CoordUnknow,
CoordAbsoulte,
CoordIncremental,
};
enum LogicOperator {
Logic_And,
Logic_Or,
};
enum SnapMode {
SnapOff = 0x0000,
SnapCenter = 0x0001,
SnapSkeleton = 0x0002,
SnapEdge = 0x0004,
SnapIntersect = 0x0008,
SnapMidPoint = 0x0010,
SnapProfile = 0x0020,
SnapBetween = 0x0040,
AllSnapMode = SnapCenter|SnapSkeleton|SnapEdge|SnapIntersect|SnapMidPoint|SnapProfile|SnapBetween,
};
Q_ENUM(SnapMode)
Q_DECLARE_FLAGS(SnapModes, SnapMode)
Q_FLAGS(SnapModes)
enum DisplayOption {
DisplayFill = 0x0001,
DisplayOutline = 0x0002,
DisplaySketeon = 0x0004,
DisplayNegative = 0x0008,
DisplayMultiLayer = 0x0010,
DisplayStepRepeat = 0x0020,
DisplayTextValue = 0x0040,
DisplayProfile = 0x0080,
DisplayDatumn = 0x0100,
DisplayFullCursor = 0x0200,
};
Q_ENUM(DisplayOption)
Q_DECLARE_FLAGS(DisplayOptions, DisplayOption)
Q_FLAGS(DisplayOptions)
enum MessageType {
Message_Error,
Message_Warn,
Message_Info,
Message_Ok,
};
struct FeatureSelectionFilter {
FeatureTypes type {FeatureType::AllFeatures};
Polarities polarity {Polarity::BothPolarity};
ProfileRegions profile {ProfileRegion::AllProfile};
QStringList includeSymbols;
QStringList excludeSymbols;
QStringList includeAttributes;
QStringList excludeAttributes;
LogicOperator includeAttributesLogic {LogicOperator::Logic_And};
LogicOperator excludeAttributesLogic {LogicOperator::Logic_And};
bool isEmpty() const {
return ((type == FeatureType::AllFeatures)
&& (polarity == Polarity::BothPolarity)
&& (profile == ProfileRegion::AllProfile)
&& (includeSymbols.isEmpty())
&& (excludeSymbols.isEmpty())
&& (includeAttributes.isEmpty())
&& (excludeAttributes.isEmpty()));
}
};
struct AttrCompareInfo {
ushort type {0}; //比较类型(0:是否有此属性; 1:属性值是否相等; 2:数值是否在范围)
QString name;
QString strValue;
double minValue = INTMAX_MIN;
double maxValue = INTMAX_MAX;
AttrCompareInfo() {}
AttrCompareInfo(const QString &iAttrStr) {
auto idx = iAttrStr.indexOf("=");
if (idx != -1) {
this->type = 1;
this->name = iAttrStr.left(idx).trimmed();
this->strValue = iAttrStr.mid(idx+1).trimmed();
auto vidx = this->strValue.indexOf('~');
if (vidx != -1) {
this->type = 2;
auto minstr = this->strValue.left(vidx).trimmed();
auto maxstr = this->strValue.mid(vidx+1).trimmed();
if (!minstr.isEmpty()) {
this->minValue = minstr.toDouble();
}
if (!maxstr.isEmpty()) {
this->maxValue = maxstr.toDouble();
}
}
}
else {
this->name = iAttrStr.trimmed();
}
}
};
};
TITAN_END_NAMESPACE
#endif //TITAN_PCBCAM_COMMON_H
#include "config.h"
TITAN_BEGIN_NAMESPACE
class PcbCamConfigData : public QSharedData
{
public:
PcbCamConfigData() { }
PcbCamConfigData(const PcbCamConfigData &other): QSharedData(other),
gzipCmd(other.gzipCmd),
tarCmd(other.tarCmd){ }
~PcbCamConfigData() { }
QString gzipCmd {"gzip"};
QString tarCmd {"tar"};
};
PcbCamConfig::PcbCamConfig() : d(new PcbCamConfigData)
{
}
PcbCamConfig::PcbCamConfig(const PcbCamConfig &rhs) : d(rhs.d)
{
}
PcbCamConfig &PcbCamConfig::operator=(const PcbCamConfig &rhs)
{
if (this != &rhs)
d.operator=(rhs.d);
return *this;
}
PcbCamConfig::~PcbCamConfig()
{
}
QString PcbCamConfig::gzipCmd() const
{
return d->gzipCmd;
}
void PcbCamConfig::setGzipCmd(const QString &iCmd)
{
d->gzipCmd = iCmd;
}
QString PcbCamConfig::tarCmd() const
{
return d->tarCmd;
}
void PcbCamConfig::setTarCmd(const QString &iCmd)
{
d->tarCmd = iCmd;
}
TITAN_END_NAMESPACE
#ifndef TITAN_PCBCAM_CONFIG_H
#define TITAN_PCBCAM_CONFIG_H
#include "../titanpcbcamglobal.h"
#include <QSharedDataPointer>
TITAN_BEGIN_NAMESPACE
class PcbCamConfigData;
class TITAN_PCBCAM_EXPORT PcbCamConfig
{
public:
PcbCamConfig();
PcbCamConfig(const PcbCamConfig &);
PcbCamConfig &operator=(const PcbCamConfig &);
~PcbCamConfig();
QString gzipCmd() const;
void setGzipCmd(const QString &iCmd);
QString tarCmd() const;
void setTarCmd(const QString &iCmd);
private:
QSharedDataPointer<PcbCamConfigData> d;
};
TITAN_END_NAMESPACE
#endif // TITAN_PCBCAM_CONFIG_H
#include "core.h"
#include <QFile>
#include <QDir>
TITAN_BEGIN_NAMESPACE
class PcbCamCorePrivate
{
Q_DECLARE_PUBLIC(PcbCamCore)
public:
explicit PcbCamCorePrivate(PcbCamCore *qptr):q_ptr(qptr){}
~PcbCamCorePrivate(){}
PcbCamConfig config;
PcbCamAbstractDataIo *dataIo {nullptr};
protected:
PcbCamCore * const q_ptr;
};
PcbCamCore *PcbCamCore::instance()
{
static PcbCamCore gInstance;
return &gInstance;
}
void PcbCamCore::setConfig(const PcbCamConfig &iConf)
{
Q_D(PcbCamCore);
d->config = iConf;
}
PcbCamConfig &PcbCamCore::config()
{
Q_D(PcbCamCore);
return d->config;
}
void PcbCamCore::setDataIo(PcbCamAbstractDataIo *iDataIo)
{
Q_D(PcbCamCore);
d->dataIo = iDataIo;
}
PcbCamAbstractDataIo *PcbCamCore::dataIo()
{
Q_D(PcbCamCore);
return d->dataIo;
}
void PcbCamCore::notifyMessage(const QString &iMessage, const QString &iType, const QString &iCategory, const QVariant &iUserData)
{
emit messageNotified(iMessage, iType, iCategory, iUserData);
}
PcbCamCore::PcbCamCore() : QObject(nullptr),
d_ptr(new PcbCamCorePrivate(this))
{
}
PcbCamCore::~PcbCamCore()
{
}
TITAN_END_NAMESPACE
#ifndef TITAN_PCBCAM_CORE_H
#define TITAN_PCBCAM_CORE_H
#include "../titanpcbcamglobal.h"
#include <QObject>
#include <QVariant>
#include <QString>
#include "./abstractdataio.h"
#include "./config.h"
TITAN_BEGIN_NAMESPACE
class PcbCamCorePrivate;
class TITAN_PCBCAM_EXPORT PcbCamCore : public QObject
{
Q_OBJECT
public:
static PcbCamCore *instance();
void setConfig(const PcbCamConfig &iConf);
PcbCamConfig &config();
void setDataIo(PcbCamAbstractDataIo *iDataIo);
PcbCamAbstractDataIo *dataIo();
signals:
void messageNotified(const QString &iMessage, const QString &iType, const QString &iCategory, const QVariant &iUserData) const;
public slots:
void notifyMessage(const QString &iMessage, const QString &iType = "INFO", const QString &iCategory = "", const QVariant &iUserData = QVariant());
private:
PcbCamCore();
~PcbCamCore();
protected:
const QScopedPointer<PcbCamCorePrivate> d_ptr;
private:
Q_DECLARE_PRIVATE(PcbCamCore)
Q_DISABLE_COPY(PcbCamCore)
};
TITAN_END_NAMESPACE
#endif // TITAN_PCBCAM_CORE_H
#include "feature.h"
#include <QDebug>
#include "./symbol.h"
#include "./util.h"
#include "./font.h"
TITAN_BEGIN_NAMESPACE
class PcbCamFeaturePrivate
{
Q_DECLARE_PUBLIC(PcbCamFeature)
public:
explicit PcbCamFeaturePrivate() { }
virtual ~PcbCamFeaturePrivate() {}
PcbCam::FeatureType type {PcbCam::PadFeature};
PcbCam::Polarity polarity {PcbCam::Positive};
QVariantMap attrMap;
int index {0};
int decode {0};
PcbCamSymbol *symbol {nullptr};
bool selected {false};
mutable QPainterPath shape;
protected:
PcbCamFeature *q_ptr {nullptr};
};
PcbCamFeature::PcbCamFeature()
: d_ptr(new PcbCamFeaturePrivate)
{
d_ptr->q_ptr = this;
}
PcbCamFeature::~PcbCamFeature()
{
}
PcbCam::FeatureType PcbCamFeature::type() const
{
Q_D(const PcbCamFeature);
return d->type;
}
PcbCam::Polarity PcbCamFeature::polarity() const
{
Q_D(const PcbCamFeature);
return d->polarity;
}
void PcbCamFeature::setPolarity(PcbCam::Polarity iPolarity)
{
Q_D(PcbCamFeature);
d->polarity = iPolarity;
}
int PcbCamFeature::index() const
{
Q_D(const PcbCamFeature);
return d->index;
}
void PcbCamFeature::setIndex(int iIndex)
{
Q_D(PcbCamFeature);
d->index = iIndex;
}
int PcbCamFeature::dcode() const
{
Q_D(const PcbCamFeature);
return d->decode;
}
void PcbCamFeature::setDcode(int iDcode)
{
Q_D(PcbCamFeature);
d->decode = iDcode;
}
void PcbCamFeature::setSymbol(PcbCamSymbol *iSymbol)
{
Q_D(PcbCamFeature);
d->symbol = iSymbol;
d->shape = QPainterPath();
}
PcbCamSymbol *PcbCamFeature::symbol() const
{
Q_D(const PcbCamFeature);
return d->symbol;
}
QVariantMap PcbCamFeature::attr() const
{
Q_D(const PcbCamFeature);
return d->attrMap;
}
QVariant PcbCamFeature::attr(const QString &iName) const
{
Q_D(const PcbCamFeature);
return d->attrMap.value(iName.toLower());
}
bool PcbCamFeature::hasAttr(const QString &iName) const
{
Q_D(const PcbCamFeature);
return d->attrMap.contains(iName.toLower());
}
void PcbCamFeature::setAttr(const QString &iName, const QVariant &iValue)
{
Q_D(PcbCamFeature);
d->attrMap.insert(iName.toLower(), iValue);
}
void PcbCamFeature::setAttr(const QVariantMap &iAttrMap)
{
Q_D(PcbCamFeature);
d->attrMap = iAttrMap;
}
void PcbCamFeature::removeAttr(const QString &iName)
{
Q_D(PcbCamFeature);
d->attrMap.remove(iName.toLower());
}
void PcbCamFeature::clearAttr()
{
Q_D(PcbCamFeature);
d->attrMap.clear();
}
void PcbCamFeature::setSelected(bool iSel)
{
Q_D(PcbCamFeature);
d->selected = iSel;
}
bool PcbCamFeature::isSelected() const
{
Q_D(const PcbCamFeature);
return d->selected;
}
PcbCamFeature::PcbCamFeature(PcbCamFeaturePrivate &dd)
: d_ptr(&dd)
{
d_ptr->q_ptr = this;
}
/*******************************************LINE*********************************************/
class PcbCamFeatureLinePrivate : public PcbCamFeaturePrivate
{
Q_DECLARE_PUBLIC(PcbCamFeatureLine)
public:
PcbCamFeatureLinePrivate() : PcbCamFeaturePrivate() { }
~PcbCamFeatureLinePrivate() { }
QLineF line ;
};
PcbCamFeatureLine::PcbCamFeatureLine()
: PcbCamFeature(*new PcbCamFeatureLinePrivate)
{
Q_D(PcbCamFeatureLine);
d->type = PcbCam::LineFeature;
}
PcbCamFeatureLine::~PcbCamFeatureLine()
{
}
void PcbCamFeatureLine::setLine(const QLineF &iLine)
{
Q_D(PcbCamFeatureLine);
d->line = iLine;
d->shape = QPainterPath();
}
QLineF PcbCamFeatureLine::line() const
{
Q_D(const PcbCamFeatureLine);
return d->line;
}
QPainterPath PcbCamFeatureLine::shape() const
{
Q_D(const PcbCamFeatureLine);
if (d->shape.isEmpty()) {
//当起点和终点在一起的线,PainterPathStroker不会创建对象,会造成图像丢失,因此需做特殊处理;
if (d->line.length() < 0.00000001) {
QPainterPath path = symbol()->shape();
d->shape = PcbCamUtil::matrix(d->line.p1(), PcbCam::Orient_N_0).map(path);
}
else {
QPainterPathStroker stroker(PcbCamUtil::sym2pen(symbol()));
d->shape = stroker.createStroke(PcbCamUtil::line2path(d->line));
}
}
return d->shape;
}
QRectF PcbCamFeatureLine::boundingRect() const
{
return shape().controlPointRect();
}
/*******************************************PAD*********************************************/
class PcbCamFeaturePadPrivate : public PcbCamFeaturePrivate
{
Q_DECLARE_PUBLIC(PcbCamFeaturePad)
public:
PcbCamFeaturePadPrivate() : PcbCamFeaturePrivate() { }
~PcbCamFeaturePadPrivate() { }
QPointF pos {0.0, 0.0};
PcbCam::Orient orient {PcbCam::Orient_N_0};
};
PcbCamFeaturePad::PcbCamFeaturePad()
: PcbCamFeature(*new PcbCamFeaturePadPrivate)
{
Q_D(PcbCamFeaturePad);
d->type = PcbCam::PadFeature;
}
PcbCamFeaturePad::~PcbCamFeaturePad()
{
}
QPointF PcbCamFeaturePad::pos() const
{
Q_D(const PcbCamFeaturePad);
return d->pos;
}
void PcbCamFeaturePad::setPos(const QPointF &iPos)
{
Q_D(PcbCamFeaturePad);
d->pos = iPos;
}
PcbCam::Orient PcbCamFeaturePad::orient() const
{
Q_D(const PcbCamFeaturePad);
return d->orient;
}
void PcbCamFeaturePad::setOrient(PcbCam::Orient iOrient)
{
Q_D(PcbCamFeaturePad);
d->orient = iOrient;
}
QPainterPath PcbCamFeaturePad::shape() const
{
Q_D(const PcbCamFeaturePad);
QPainterPath path = symbol()->shape();
return PcbCamUtil::matrix(d->pos, d->orient).map(path);
}
QRectF PcbCamFeaturePad::boundingRect() const
{
Q_D(const PcbCamFeaturePad);
//return shape().controlPointRect();
return PcbCamUtil::matrix(d->pos, d->orient).mapRect(symbol()->boundingRect());
}
/*******************************************ARC*********************************************/
class PcbCamFeatureArcPrivate : public PcbCamFeaturePrivate
{
public:
PcbCamFeatureArcPrivate() : PcbCamFeaturePrivate() { }
~PcbCamFeatureArcPrivate() { }
QPointF ps;
QPointF pe;
QPointF pc;
bool cw {false};
};
PcbCamFeatureArc::PcbCamFeatureArc()
: PcbCamFeature(*new PcbCamFeatureArcPrivate)
{
Q_D(PcbCamFeatureArc);
d->type = PcbCam::ArcFeature;
}
PcbCamFeatureArc::~PcbCamFeatureArc()
{
}
void PcbCamFeatureArc::setData(const QPointF &iPs, const QPointF &iPe, const QPointF &iPc, bool iCw)
{
Q_D(PcbCamFeatureArc);
d->ps = iPs;
d->pe = iPe;
d->pc = iPc;
d->cw = iCw;
d->shape = QPainterPath();
}
QPointF PcbCamFeatureArc::ps() const
{
Q_D(const PcbCamFeatureArc);
return d->ps;
}
QPointF PcbCamFeatureArc::pe() const
{
Q_D(const PcbCamFeatureArc);
return d->pe;
}
QPointF PcbCamFeatureArc::pc() const
{
Q_D(const PcbCamFeatureArc);
return d->pc;
}
bool PcbCamFeatureArc::cw() const
{
Q_D(const PcbCamFeatureArc);
return d->cw;
}
QPainterPath PcbCamFeatureArc::shape() const
{
Q_D(const PcbCamFeatureArc);
if (d->shape.isEmpty()) {
QPainterPathStroker stroker(PcbCamUtil::sym2pen(symbol()));
d->shape = stroker.createStroke(PcbCamUtil::arc2path(d->ps, d->pe, d->pc, d->cw));
}
return d->shape;
}
QRectF PcbCamFeatureArc::boundingRect() const
{
return shape().controlPointRect();
}
/*******************************************TEXT*********************************************/
class PcbCamFeatureTextPrivate : public PcbCamFeaturePrivate
{
public:
PcbCamFeatureTextPrivate() : PcbCamFeaturePrivate() { }
~PcbCamFeatureTextPrivate() {
clearFeatures();
}
QPointF pos;
PcbCamFont *font {nullptr};
PcbCam::Orient orient {PcbCam::Orient_N_0};
QSizeF size;
qreal widthFactor {1.0};
QString text;
int version {1};
QString dynamicText;
QList<PcbCamFeature *> features;
QMap<QString, PcbCamSymbol*> lineSymbolsMap;
void clearFeatures()
{
for (auto k : lineSymbolsMap.keys()) {
PcbCamSymbol *sym = lineSymbolsMap.value(k, nullptr);
if (sym != nullptr) {
delete sym;
sym = nullptr;
}
}
lineSymbolsMap.clear();
for (PcbCamFeature *f : features) {
delete f;
f = nullptr;
}
features.clear();
}
void genFeatures()
{
clearFeatures();
//找出原点:ODB++手册上说是所有Char的左下角不原点,但经测试发现在genesis里是以“M"字母的左下角为原点
QList<PcbCamFontCharLine> mlines = this->font->charLines(QChar('M'));
QPainterPath mpath;
for (const PcbCamFontCharLine &l : mlines) {
QPainterPathStroker stroker;
QTransform mat((this->size.width()-this->widthFactor*l.width())/(this->font->sizeX()), 0, 0, (this->size.height()-this->widthFactor*l.width())/this->font->sizeY(), 0, 0);
stroker.setCapStyle(l.shape() == PcbCamFontCharLine::LineShape_S ? Qt::SquareCap : Qt::RoundCap);
stroker.setWidth(l.width() * this->widthFactor);
QPainterPath path;
path.moveTo(l.line().p1());
path.lineTo(l.line().p2());
path = mat.map(path);
mpath.addPath(stroker.createStroke(path));
}
QPointF origin = mpath.boundingRect().topLeft();
QString tmptext = this->dynamicText;
for (int i = 0; i < tmptext.length(); ++i) {
QList<PcbCamFontCharLine> lines = this->font->charLines(tmptext.at(i));
for (const PcbCamFontCharLine &line : lines) {
QTransform mat((this->size.width()-this->widthFactor*line.width())/(this->font->sizeX()), 0, 0, (this->size.height()-this->widthFactor*line.width())/this->font->sizeY(), 0, 0);
double symsize = line.width() * this->widthFactor * 1000;
QString symname = QString( line.shape() == PcbCamFontCharLine::LineShape_S ? "s%1" : "r%1").arg(symsize, 0, 'f', 6);
if (!lineSymbolsMap.contains(symname)) {
if (line.shape() == PcbCamFontCharLine::LineShape_S) {
lineSymbolsMap.insert(symname, new PcbCamSymbolS(symname));
}
else {
lineSymbolsMap.insert(symname, new PcbCamSymbolR(symname));
}
}
PcbCamFeatureLine *f = new PcbCamFeatureLine();
f->setPolarity(line.polarity());
f->setLine(mat.map(line.line()).translated(i*this->size.width() -origin.x(), -origin.y()));
f->setSymbol(lineSymbolsMap[symname]);
features.append(f);
}
}
}
};
PcbCamFeatureText::PcbCamFeatureText()
: PcbCamFeature(*new PcbCamFeatureTextPrivate)
{
Q_D(PcbCamFeatureText);
d->type = PcbCam::TextFeature;
}
PcbCamFeatureText::~PcbCamFeatureText()
{
}
void PcbCamFeatureText::setData(const QPointF &iPos, PcbCamFont *iFont, PcbCam::Orient iOrient, const QSizeF &iSize, qreal iWithFactor, const QString &iText, int iVersion)
{
Q_D(PcbCamFeatureText);
d->pos = iPos;
d->font = iFont;
d->orient = iOrient;
d->size = iSize;
d->widthFactor = iWithFactor;
d->text = iText;
d->version = iVersion;
d->dynamicText = iText;
d->shape = QPainterPath();
d->genFeatures();
}
QPointF PcbCamFeatureText::pos() const
{
Q_D(const PcbCamFeatureText);
return d->pos;
}
PcbCamFont *PcbCamFeatureText::font() const
{
Q_D(const PcbCamFeatureText);
return d->font;
}
PcbCam::Orient PcbCamFeatureText::orient() const
{
Q_D(const PcbCamFeatureText);
return d->orient;
}
QSizeF PcbCamFeatureText::size() const
{
Q_D(const PcbCamFeatureText);
return d->size;
}
qreal PcbCamFeatureText::widthFactor() const
{
Q_D(const PcbCamFeatureText);
return d->widthFactor;
}
QString PcbCamFeatureText::text() const
{
Q_D(const PcbCamFeatureText);
return d->text;
}
int PcbCamFeatureText::version() const
{
Q_D(const PcbCamFeatureText);
return d->version;
}
QString PcbCamFeatureText::dynamicText() const
{
Q_D(const PcbCamFeatureText);
return d->dynamicText;
}
void PcbCamFeatureText::setDynamicText(const QString &iText)
{
Q_D(PcbCamFeatureText);
d->dynamicText = iText;
d->shape = QPainterPath();
d->genFeatures();
}
QList<PcbCamFeature*> PcbCamFeatureText::features() const
{
Q_D(const PcbCamFeatureText);
return d->features;
}
QPainterPath PcbCamFeatureText::shape() const
{
Q_D(const PcbCamFeatureText);
if (d->shape.isEmpty() && d->font != nullptr) {
for (const PcbCamFeature *feat : d->features) {
d->shape.addPath(feat->shape());
}
}
return PcbCamUtil::matrix(d->pos, d->orient).map(d->shape);
}
QRectF PcbCamFeatureText::boundingRect() const
{
return shape().boundingRect();
}
/*******************************************BARCODE*********************************************/
class PcbCamFeatureBarcodePrivate : public PcbCamFeaturePrivate
{
public:
PcbCamFeatureBarcodePrivate() : PcbCamFeaturePrivate(){ }
~PcbCamFeatureBarcodePrivate() { }
QPointF pos;
QString barcode;
QString font {"standard"};
PcbCam::Orient orient {PcbCam::Orient_N_0};
QSizeF size;
bool fullAscii {false};
bool checkSum {false};
bool background {false};
bool additionStr {false};
PcbCam::BarcodeTextPos additionStrPos {PcbCam::BarcodeTextPos_Top};
QString text;
};
PcbCamFeatureBarcode::PcbCamFeatureBarcode()
: PcbCamFeature(*new PcbCamFeatureBarcodePrivate)
{
Q_D(PcbCamFeatureBarcode);
d->type = PcbCam::BarcodeFeature;
}
PcbCamFeatureBarcode::~PcbCamFeatureBarcode()
{
}
QPointF PcbCamFeatureBarcode::pos() const
{
Q_D(const PcbCamFeatureBarcode);
return d->pos;
}
void PcbCamFeatureBarcode::setPos(const QPointF &iPos)
{
Q_D(PcbCamFeatureBarcode);
d->pos = iPos;
}
QString PcbCamFeatureBarcode::barcode() const
{
Q_D(const PcbCamFeatureBarcode);
return d->barcode;
}
void PcbCamFeatureBarcode::setBarcode(const QString &iBarcode)
{
Q_D(PcbCamFeatureBarcode);
d->barcode = iBarcode;
}
QString PcbCamFeatureBarcode::font() const
{
Q_D(const PcbCamFeatureBarcode);
return d->font;
}
void PcbCamFeatureBarcode::setFont(const QString &iFont)
{
Q_D(PcbCamFeatureBarcode);
d->font = iFont;
}
PcbCam::Orient PcbCamFeatureBarcode::orient() const
{
Q_D(const PcbCamFeatureBarcode);
return d->orient;
}
void PcbCamFeatureBarcode::setOrient(PcbCam::Orient iOrient)
{
Q_D(PcbCamFeatureBarcode);
d->orient = iOrient;
}
QSizeF PcbCamFeatureBarcode::size() const
{
Q_D(const PcbCamFeatureBarcode);
return d->size;
}
void PcbCamFeatureBarcode::setSize(const QSizeF &iSize)
{
Q_D(PcbCamFeatureBarcode);
d->size = iSize;
}
bool PcbCamFeatureBarcode::fullAscii() const
{
Q_D(const PcbCamFeatureBarcode);
return d->fullAscii;
}
void PcbCamFeatureBarcode::setFullAscii(bool iBol)
{
Q_D(PcbCamFeatureBarcode);
d->fullAscii = iBol;
}
bool PcbCamFeatureBarcode::checkSum() const
{
Q_D(const PcbCamFeatureBarcode);
return d->checkSum;
}
void PcbCamFeatureBarcode::setCheckSum(bool iBol)
{
Q_D(PcbCamFeatureBarcode);
d->checkSum = iBol;
}
bool PcbCamFeatureBarcode::background() const
{
Q_D(const PcbCamFeatureBarcode);
return d->background;
}
void PcbCamFeatureBarcode::setBackground(bool iBol)
{
Q_D(PcbCamFeatureBarcode);
d->background = iBol;
}
bool PcbCamFeatureBarcode::additionStr() const
{
Q_D(const PcbCamFeatureBarcode);
return d->additionStr;
}
void PcbCamFeatureBarcode::setAdditionStr(bool iBol)
{
Q_D(PcbCamFeatureBarcode);
d->additionStr = iBol;
}
PcbCam::BarcodeTextPos PcbCamFeatureBarcode::additiontStrPos() const
{
Q_D(const PcbCamFeatureBarcode);
return d->additionStrPos;
}
void PcbCamFeatureBarcode::setAdditionStrPos(PcbCam::BarcodeTextPos iTorB)
{
Q_D(PcbCamFeatureBarcode);
d->additionStrPos = iTorB;
}
QString PcbCamFeatureBarcode::text() const
{
Q_D(const PcbCamFeatureBarcode);
return d->text;
}
void PcbCamFeatureBarcode::setText(const QString &iText)
{
Q_D(PcbCamFeatureBarcode);
d->text = iText;
}
QPainterPath PcbCamFeatureBarcode::shape() const
{
Q_D(const PcbCamFeatureBarcode);
if (d->shape.isEmpty()) {
QPainterPath path;
path.addRect(d->pos.x(), d->pos.y(), d->size.width(), d->size.height());
d->shape = path;
}
return d->shape;
}
QRectF PcbCamFeatureBarcode::boundingRect() const
{
return shape().boundingRect();
}
/*******************************************SURFACE*********************************************/
class PcbCamFeatureSurfacePrivate : public PcbCamFeaturePrivate
{
public:
PcbCamFeatureSurfacePrivate() : PcbCamFeaturePrivate() { }
~PcbCamFeatureSurfacePrivate() { }
QPainterPath path;
};
PcbCamFeatureSurface::PcbCamFeatureSurface()
: PcbCamFeature(*new PcbCamFeatureSurfacePrivate)
{
Q_D(PcbCamFeatureSurface);
d->type = PcbCam::SurfaceFeature;
}
PcbCamFeatureSurface::~PcbCamFeatureSurface()
{
}
QPainterPath PcbCamFeatureSurface::path() const
{
Q_D(const PcbCamFeatureSurface);
return d->path;
}
void PcbCamFeatureSurface::setPath(const QPainterPath &iPath)
{
Q_D(PcbCamFeatureSurface);
d->path = iPath;
}
QPainterPath PcbCamFeatureSurface::shape() const
{
Q_D(const PcbCamFeatureSurface);
return d->path;
}
QRectF PcbCamFeatureSurface::boundingRect() const
{
Q_D(const PcbCamFeatureSurface);
return d->path.controlPointRect();
}
/*******************************************PATH*********************************************/
class PcbCamFeaturePathPrivate : public PcbCamFeaturePrivate
{
public:
PcbCamFeaturePathPrivate() : PcbCamFeaturePrivate() { }
~PcbCamFeaturePathPrivate() { }
QPainterPath path;
int width {1};
};
PcbCamFeaturePath::PcbCamFeaturePath()
: PcbCamFeature(*new PcbCamFeaturePathPrivate)
{
Q_D(PcbCamFeaturePath);
d->type = PcbCam::PathFeature;
}
PcbCamFeaturePath::~PcbCamFeaturePath()
{
}
QPainterPath PcbCamFeaturePath::path() const
{
Q_D(const PcbCamFeaturePath);
return d->path;
}
void PcbCamFeaturePath::setPath(const QPainterPath &iPath)
{
Q_D(PcbCamFeaturePath);
d->path = iPath;
}
int PcbCamFeaturePath::width() const
{
Q_D(const PcbCamFeaturePath);
return d->width;
}
void PcbCamFeaturePath::setWidth(int iWidth)
{
Q_D(PcbCamFeaturePath);
d->width = iWidth;
}
QPainterPath PcbCamFeaturePath::shape() const
{
Q_D(const PcbCamFeaturePath);
return d->path;
}
QRectF PcbCamFeaturePath::boundingRect() const
{
Q_D(const PcbCamFeaturePath);
return d->path.controlPointRect();
}
/*******************************************COMPONENT*********************************************/
class PcbCamFeatureComponentPrivate : public PcbCamFeaturePrivate
{
public:
PcbCamFeatureComponentPrivate() : PcbCamFeaturePrivate() { }
~PcbCamFeatureComponentPrivate() { }
QPointF pos;
double rotation {0.0};
bool mirror {false};
QString compName;
QString partName;
};
PcbCamFeatureComponent::PcbCamFeatureComponent()
: PcbCamFeature(*new PcbCamFeatureComponentPrivate)
{
Q_D(PcbCamFeatureComponent);
d->type = PcbCam::ComponentFeature;
}
PcbCamFeatureComponent::~PcbCamFeatureComponent()
{
}
void PcbCamFeatureComponent::setData(const QPointF &iPos, double iRotation, bool iMirror, const QString &iCompName, const QString &iPartName)
{
Q_D(PcbCamFeatureComponent);
d->pos = iPos;
d->rotation = iRotation;
d->mirror = iMirror;
d->compName = iCompName;
d->partName = iPartName;
}
QPointF PcbCamFeatureComponent::pos() const
{
Q_D(const PcbCamFeatureComponent);
return d->pos;
}
double PcbCamFeatureComponent::rotation() const
{
Q_D(const PcbCamFeatureComponent);
return d->rotation;
}
bool PcbCamFeatureComponent::mirror() const
{
Q_D(const PcbCamFeatureComponent);
return d->mirror;
}
QString PcbCamFeatureComponent::compName() const
{
Q_D(const PcbCamFeatureComponent);
return d->compName;
}
QString PcbCamFeatureComponent::partName() const
{
Q_D(const PcbCamFeatureComponent);
return d->partName;
}
QPainterPath PcbCamFeatureComponent::shape() const
{
Q_D(const PcbCamFeatureComponent);
QPainterPath path;
if (d->shape.isEmpty()) {
auto sym = static_cast<PcbCamSymbolUser *>(d->symbol);
if (sym != nullptr) {
auto symfeats = sym->features();
if (!symfeats.isEmpty()) {
path = symfeats.at(0)->shape();
}
}
}
return PcbCamUtil::matrix(d->pos, QPointF(0, 0), d->rotation, d->mirror).map(path);
}
QRectF PcbCamFeatureComponent::boundingRect() const
{
Q_D(const PcbCamFeatureComponent);
//return shape().controlPointRect();
return PcbCamUtil::matrix(d->pos, QPointF(0, 0), d->rotation, d->mirror).mapRect(symbol()->boundingRect());
}
TITAN_END_NAMESPACE
#ifndef TITAN_PCBCAM_FEATURE_H
#define TITAN_PCBCAM_FEATURE_H
#include "../titanpcbcamglobal.h"
#include <QPointF>
#include <QVariantMap>
#include <QSizeF>
#include <QPainterPath>
#include <QLineF>
#include "./common.h"
#include "./font.h"
TITAN_BEGIN_NAMESPACE
class PcbCamSymbol;
class PcbCamFeaturePrivate;
class TITAN_PCBCAM_EXPORT PcbCamFeature
{
public:
PcbCamFeature();
virtual ~PcbCamFeature();
PcbCam::FeatureType type() const;
PcbCam::Polarity polarity() const;
void setPolarity(PcbCam::Polarity iPolarity);
int index() const;
void setIndex(int iIndex);
int dcode() const;
void setDcode(int iDcode);
void setSymbol(PcbCamSymbol *iSymbol);
PcbCamSymbol *symbol() const;
QVariantMap attr() const;
QVariant attr(const QString &iName) const;
bool hasAttr(const QString &iName) const;
void setAttr(const QString &iName, const QVariant &iValue);
void setAttr(const QVariantMap &iAttrMap);
void removeAttr(const QString &iName);
void clearAttr();
void setSelected(bool iSel = true);
bool isSelected() const;
virtual QPainterPath shape() const = 0;
virtual QRectF boundingRect() const = 0;
protected:
PcbCamFeature(PcbCamFeaturePrivate &dd);
const QScopedPointer<PcbCamFeaturePrivate> d_ptr;
private:
Q_DECLARE_PRIVATE(PcbCamFeature)
Q_DISABLE_COPY(PcbCamFeature)
};
class PcbCamFeatureLinePrivate;
class TITAN_PCBCAM_EXPORT PcbCamFeatureLine : public PcbCamFeature
{
public:
PcbCamFeatureLine();
~PcbCamFeatureLine();
void setLine(const QLineF &iLine);
QLineF line() const;
QPainterPath shape() const;
QRectF boundingRect() const;
private:
Q_DECLARE_PRIVATE(PcbCamFeatureLine)
Q_DISABLE_COPY(PcbCamFeatureLine)
};
class PcbCamFeaturePadPrivate;
class TITAN_PCBCAM_EXPORT PcbCamFeaturePad : public PcbCamFeature
{
public:
PcbCamFeaturePad();
~PcbCamFeaturePad();
QPointF pos() const;
void setPos(const QPointF &iPos);
PcbCam::Orient orient() const;
void setOrient(PcbCam::Orient iOrient);
QPainterPath shape() const;
QRectF boundingRect() const;
private:
Q_DECLARE_PRIVATE(PcbCamFeaturePad)
Q_DISABLE_COPY(PcbCamFeaturePad)
};
class PcbCamFeatureArcPrivate;
class TITAN_PCBCAM_EXPORT PcbCamFeatureArc : public PcbCamFeature
{
public:
PcbCamFeatureArc();
~PcbCamFeatureArc();
void setData(const QPointF &iPs, const QPointF &iPe, const QPointF &iPc, bool iCw);
QPointF ps() const;
QPointF pe() const;
QPointF pc() const;
bool cw() const;
QPainterPath shape() const;
QRectF boundingRect() const;
private:
Q_DECLARE_PRIVATE(PcbCamFeatureArc)
Q_DISABLE_COPY(PcbCamFeatureArc)
};
class PcbCamFeatureTextPrivate;
class TITAN_PCBCAM_EXPORT PcbCamFeatureText : public PcbCamFeature
{
public:
PcbCamFeatureText();
~PcbCamFeatureText();
void setData(const QPointF &iPos,
PcbCamFont *iFont,
PcbCam::Orient iOrient,
const QSizeF &iSize,
qreal iWithFactor,
const QString &iText,
int iVersion = 1);
QPointF pos() const;
PcbCamFont *font() const;
PcbCam::Orient orient() const;
QSizeF size() const;
qreal widthFactor() const;
QString text() const;
int version() const;
QString dynamicText() const;
void setDynamicText(const QString &iText);
QList<PcbCamFeature *> features() const;
QPainterPath shape() const;
QRectF boundingRect() const;
private:
Q_DECLARE_PRIVATE(PcbCamFeatureText)
Q_DISABLE_COPY(PcbCamFeatureText)
};
class PcbCamFeatureBarcodePrivate;
class TITAN_PCBCAM_EXPORT PcbCamFeatureBarcode : public PcbCamFeature
{
public:
PcbCamFeatureBarcode();
~PcbCamFeatureBarcode();
QPointF pos() const;
void setPos(const QPointF &iPos);
QString barcode() const;
void setBarcode(const QString &iBarcode);
QString font() const;
void setFont(const QString &iFont);
PcbCam::Orient orient() const;
void setOrient(PcbCam::Orient iOrient);
QSizeF size() const;
void setSize(const QSizeF &iSize);
bool fullAscii() const;
void setFullAscii(bool iBol);
bool checkSum() const;
void setCheckSum(bool iBol);
bool background() const;
void setBackground(bool iBol);
bool additionStr() const;
void setAdditionStr(bool iBol);
PcbCam::BarcodeTextPos additiontStrPos() const;
void setAdditionStrPos(PcbCam::BarcodeTextPos iTorB);
QString text() const;
void setText(const QString &iText);
QPainterPath shape() const;
QRectF boundingRect() const;
private:
Q_DECLARE_PRIVATE(PcbCamFeatureBarcode)
Q_DISABLE_COPY(PcbCamFeatureBarcode)
};
class PcbCamFeatureSurfacePrivate;
class TITAN_PCBCAM_EXPORT PcbCamFeatureSurface : public PcbCamFeature
{
public:
PcbCamFeatureSurface();
~PcbCamFeatureSurface();
QPainterPath path() const;
void setPath(const QPainterPath &iPath);
QPainterPath shape() const;
QRectF boundingRect() const;
private:
Q_DECLARE_PRIVATE(PcbCamFeatureSurface)
Q_DISABLE_COPY(PcbCamFeatureSurface)
};
class PcbCamFeaturePathPrivate;
class TITAN_PCBCAM_EXPORT PcbCamFeaturePath : public PcbCamFeature
{
public:
PcbCamFeaturePath();
~PcbCamFeaturePath();
QPainterPath path() const;
void setPath(const QPainterPath &iPath);
int width() const;
void setWidth(int iWidth);
QPainterPath shape() const;
QRectF boundingRect() const;
private:
Q_DECLARE_PRIVATE(PcbCamFeaturePath)
Q_DISABLE_COPY(PcbCamFeaturePath)
};
class PcbCamFeatureComponentPrivate;
class TITAN_PCBCAM_EXPORT PcbCamFeatureComponent : public PcbCamFeature
{
public:
PcbCamFeatureComponent();
~PcbCamFeatureComponent();
void setData(const QPointF &iPos,
double iRotation,
bool iMirror,
const QString &iCompName,
const QString &iPartName);
QPointF pos() const;
double rotation() const;
bool mirror() const;
QString compName() const;
QString partName() const;
QPainterPath shape() const;
QRectF boundingRect() const;
private:
Q_DECLARE_PRIVATE(PcbCamFeatureComponent)
Q_DISABLE_COPY(PcbCamFeatureComponent)
};
TITAN_END_NAMESPACE
#endif // TITAN_PCBCAM_FEATURE_H
#include "font.h"
TITAN_BEGIN_NAMESPACE
class PcbCamFontData : public QSharedData
{
public:
PcbCamFontData() { }
PcbCamFontData(const PcbCamFontData &other): QSharedData(other),
name(other.name),
sizeX(other.sizeX),
sizeY(other.sizeY),
offset(other.offset),
charLinesMap(other.charLinesMap){ }
~PcbCamFontData() { }
QString name {"standard"};
double sizeX {0.0};
double sizeY {0.0};
double offset {0.0};
QMap<QChar, QList<PcbCamFontCharLine> > charLinesMap;
};
PcbCamFont::PcbCamFont() : d(new PcbCamFontData)
{
}
PcbCamFont::PcbCamFont(const PcbCamFont &rhs) : d (rhs.d)
{
}
PcbCamFont &PcbCamFont::operator=(const PcbCamFont &rhs)
{
if (this != &rhs)
d.operator=(rhs.d);
return *this;
}
PcbCamFont::~PcbCamFont()
{
}
void PcbCamFont::setName(const QString &iName)
{
d->name = iName;
}
QString PcbCamFont::name() const
{
return d->name;
}
void PcbCamFont::setSizeX(double iSizeX)
{
d->sizeX = iSizeX;
}
void PcbCamFont::setSizeY(double iSizeY)
{
d->sizeY = iSizeY;
}
double PcbCamFont::sizeX() const
{
return d->sizeX;
}
double PcbCamFont::sizeY()
{
return d->sizeY;
}
void PcbCamFont::setOffset(double iOffset)
{
d->offset = iOffset;
}
double PcbCamFont::offset() const
{
return d->offset;
}
QList<PcbCamFontCharLine> PcbCamFont::charLines(QChar iChar) const
{
return d->charLinesMap.value(iChar);
}
void PcbCamFont::setCharLines(QChar iChar, const QList<PcbCamFontCharLine> &iLines)
{
d->charLinesMap.insert(iChar, iLines);
}
TITAN_END_NAMESPACE
#ifndef TITAN_PCBCAM_FONT_H
#define TITAN_PCBCAM_FONT_H
#include "../titanpcbcamglobal.h"
#include <QSharedDataPointer>
#include "./common.h"
#include "./fontcharline.h"
TITAN_BEGIN_NAMESPACE
class PcbCamFontData;
class TITAN_PCBCAM_EXPORT PcbCamFont
{
public:
PcbCamFont();
PcbCamFont(const PcbCamFont &);
PcbCamFont &operator=(const PcbCamFont &);
~PcbCamFont();
void setName(const QString &iName);
QString name() const;
void setSizeX(double iSizeX);
void setSizeY(double iSizeY);
double sizeX() const;
double sizeY();
void setOffset(double iOffset);
double offset() const;
QList<PcbCamFontCharLine> charLines(QChar iChar) const;
void setCharLines(QChar iChar, const QList<PcbCamFontCharLine> &iLines);
private:
QSharedDataPointer<PcbCamFontData> d;
};
TITAN_END_NAMESPACE
#endif // TITAN_PCBCAM_FONT_H
#include "fontcharline.h"
TITAN_BEGIN_NAMESPACE
class PcbCamFontCharLineData : public QSharedData
{
public:
PcbCamFontCharLineData() { }
PcbCamFontCharLineData(const PcbCamFontCharLineData &other): QSharedData(other),
line(other.line),
polarity(other.polarity),
shape(other.shape),
width(other.width) { }
~PcbCamFontCharLineData() { }
QLineF line;
PcbCam::Polarity polarity {PcbCam::Positive};
PcbCamFontCharLine::LineShape shape {PcbCamFontCharLine::LineShape_R};
double width {0.0};
};
PcbCamFontCharLine::PcbCamFontCharLine() : d(new PcbCamFontCharLineData)
{
}
PcbCamFontCharLine::PcbCamFontCharLine(const PcbCamFontCharLine &rhs) : d(rhs.d)
{
}
PcbCamFontCharLine &PcbCamFontCharLine::operator=(const PcbCamFontCharLine &rhs)
{
if (this != &rhs)
d.operator=(rhs.d);
return *this;
}
PcbCamFontCharLine::~PcbCamFontCharLine()
{
}
QLineF PcbCamFontCharLine::line() const
{
return d->line;
}
void PcbCamFontCharLine::setLine(const QLineF &iLine)
{
d->line = iLine;
}
PcbCam::Polarity PcbCamFontCharLine::polarity() const
{
return d->polarity;
}
void PcbCamFontCharLine::setPolarity(PcbCam::Polarity iPolarity)
{
d->polarity = iPolarity;
}
PcbCamFontCharLine::LineShape PcbCamFontCharLine::shape() const
{
return d->shape;
}
void PcbCamFontCharLine::setShape(LineShape iShape)
{
d->shape = iShape;
}
double PcbCamFontCharLine::width() const
{
return d->width;
}
void PcbCamFontCharLine::setWidth(double iWidth)
{
d->width = iWidth;
}
TITAN_END_NAMESPACE
#ifndef TITAN_PCBCAM_FONTCHARLINE_H
#define TITAN_PCBCAM_FONTCHARLINE_H
#include "../titanpcbcamglobal.h"
#include <QSharedDataPointer>
#include <QLineF>
#include "./common.h"
TITAN_BEGIN_NAMESPACE
class PcbCamFontCharLineData;
class TITAN_PCBCAM_EXPORT PcbCamFontCharLine {
public:
enum LineShape {
LineShape_R,
LineShape_S
};
PcbCamFontCharLine();
PcbCamFontCharLine(const PcbCamFontCharLine &);
PcbCamFontCharLine &operator=(const PcbCamFontCharLine &);
~PcbCamFontCharLine();
QLineF line() const;
void setLine(const QLineF &iLine);
PcbCam::Polarity polarity() const;
void setPolarity(PcbCam::Polarity iPolarity);
LineShape shape() const;
void setShape(LineShape iShape);
double width() const;
void setWidth(double iWidth);
private:
QSharedDataPointer<PcbCamFontCharLineData> d;
};
TITAN_END_NAMESPACE
#endif // TITAN_PCBCAM_FONTCHARLINE_H
#include "job.h"
#include <QVariantMap>
#include <QVariantList>
#include <QFile>
#include <QProcess>
#include <QElapsedTimer>
#include <QPen>
#include <QFileInfo>
#include <QDir>
#include <QSet>
#include <QJsonDocument>
#include <QDebug>
#include "../parser/parserhelper.h"
#include "../parser/odbmatrixparser.h"
#include "../parser/odbedadataparser.h"
#include "../parser/odbcomponentparser.h"
#include "../parser/gerber274xparser.h"
#include "../parser/drillparser.h"
#include "./common.h"
#include "./util.h"
#include "./symbolfactory.h"
#include "./config.h"
#include "./core.h"
TITAN_BEGIN_NAMESPACE
class PcbCamJobPrivate
{
Q_DECLARE_PUBLIC(PcbCamJob)
public:
explicit PcbCamJobPrivate(PcbCamJob *qptr) : q_ptr(qptr) {}
~PcbCamJobPrivate()
{
qDeleteAll(stepsMap);
qDeleteAll(layersMap);
qDeleteAll(symbolsMap);
qDeleteAll(fontsMap);
stepsMap.clear();
layersMap.clear();
symbolsMap.clear();
fontsMap.clear();
auto dataio = PcbCamCore::instance()->dataIo();
if (dataio != nullptr) {
dataio->clearJobDataCache(jobPath);
}
}
//料号名
QString jobname;
//ODB++主版本号
uint odbVersionMajor {0};
//ODB++次版本号
uint odbVersionMinor {0};
//创建时间
QDateTime creationDate;
//保存时间
QDateTime saveDate;
//保存此料号数据的App名称
QString saveApp;
//保存此料号数据的用户名;
QString saveUser;
//料号属性
QVariantMap jobAttrMap;
//自定义属性定义
QHash<QString, PcbCamAttrDefine> userAttrDefineMap;
//Steps
QHash<QString, PcbCamStep*> stepsMap;
//Layers
QHash<QString, PcbCamLayer*> layersMap;
//料号路径
QString jobPath;
//日志中显示的料号路径
QString logJobPath;
//层别
QList<PcbCamMatrixLayer> matrixLayers;
QHash<QString, int> matrixSteps;
QHash<QString, PcbCamSymbol*> symbolsMap;
QHash<QString, PcbCamFont*> fontsMap;
int getMaxStepNum() const {
int ret = 0;
for (auto n : matrixSteps.values()) {
if (ret < n) ret = n;
}
return ret;
}
int getMaxLayerRow() const {
int ret = 0;
for (auto layer: matrixLayers) {
if (ret < layer.row()) ret = layer.row();
}
return ret;
}
int getMaxLayerId() const {
int ret = 0;
for (auto layer: matrixLayers) {
if (ret < layer.id()) ret = layer.id();
}
return ret;
}
int getMaxConstructSymbolNum() const {
QRegularExpression regx("^construct\\+(\\d+)");
int ret = 0;
for (auto sym : symbolsMap.keys()) {
auto match = regx.match(sym);
if (match.hasMatch()) {
int n = match.captured(1).toInt();
if (ret < n) ret = n;
}
}
return ret;
}
protected:
PcbCamJob * const q_ptr;
};
PcbCamJob::PcbCamJob(QObject *parent) : QObject(parent),
d_ptr(new PcbCamJobPrivate(this))
{
}
PcbCamJob::~PcbCamJob()
{
}
QString PcbCamJob::jobname() const
{
Q_D(const PcbCamJob);
return d->jobname;
}
void PcbCamJob::setJobname(const QString &iJobname)
{
Q_D(PcbCamJob);
d->jobname = iJobname;
}
uint PcbCamJob::odbVersionMajor() const
{
Q_D(const PcbCamJob);
return d->odbVersionMajor;
}
void PcbCamJob::setOdbVersionMajor(uint iVersion)
{
Q_D(PcbCamJob);
d->odbVersionMajor = iVersion;
}
uint PcbCamJob::odbVersionMinor() const
{
Q_D(const PcbCamJob);
return d->odbVersionMinor;
}
void PcbCamJob::setOdbVersionMinor(uint iVersion)
{
Q_D(PcbCamJob);
d->odbVersionMinor = iVersion;
}
QDateTime PcbCamJob::creationDate() const
{
Q_D(const PcbCamJob);
return d->creationDate;
}
void PcbCamJob::setCreationDate(QDateTime iDt)
{
Q_D(PcbCamJob);
d->creationDate = iDt;
}
QDateTime PcbCamJob::saveDate() const
{
Q_D(const PcbCamJob);
return d->saveDate;
}
void PcbCamJob::setSaveDate(QDateTime iDt)
{
Q_D(PcbCamJob);
d->saveDate = iDt;
}
QString PcbCamJob::saveApp() const
{
Q_D(const PcbCamJob);
return d->saveApp;
}
void PcbCamJob::setSaveApp(const QString &iApp)
{
Q_D(PcbCamJob);
d->saveApp = iApp;
}
QString PcbCamJob::saveUser() const
{
Q_D(const PcbCamJob);
return d->saveUser;
}
void PcbCamJob::setSaveUser(const QString &iUser)
{
Q_D(PcbCamJob);
d->saveUser = iUser;
}
QVariant PcbCamJob::jobAttr(const QString &iName) const
{
Q_D(const PcbCamJob);
return d->jobAttrMap.value(iName.toLower());
}
bool PcbCamJob::hasJobAttr(const QString &iName) const
{
Q_D(const PcbCamJob);
return d->jobAttrMap.contains(iName.toLower());
}
void PcbCamJob::setJobAttr(const QString &iName, const QVariant &iValue)
{
Q_D(PcbCamJob);
d->jobAttrMap.insert(iName.toLower(), iValue);
}
PcbCamAttrDefine PcbCamJob::userAttrDefine(const QString &iName) const
{
Q_D(const PcbCamJob);
return d->userAttrDefineMap.value(iName.toLower());
}
QHash<QString, PcbCamAttrDefine> PcbCamJob::userAttrDefine() const
{
Q_D(const PcbCamJob);
return d->userAttrDefineMap;
}
void PcbCamJob::addUserAttrDefine(const PcbCamAttrDefine &iAttrDefine)
{
Q_D(PcbCamJob);
d->userAttrDefineMap.insert(iAttrDefine.name().toLower(), iAttrDefine);
}
PcbCamStep *PcbCamJob::step(const QString &iStepName) const
{
Q_D(const PcbCamJob);
return d->stepsMap.value(iStepName.toLower(), nullptr);
}
QHash<QString, PcbCamStep *> PcbCamJob::allSteps() const
{
Q_D(const PcbCamJob);
return d->stepsMap;
}
//void PcbCamJob::addStep(PcbCamStep *iStep)
//{
// addStep(QVector<PcbCamStep*>() << iStep);
//}
//void PcbCamJob::addStep(const QVector<PcbCamStep *> &iStep)
//{
// Q_D(PcbCamJob);
// QStringList stepNames;
// for (PcbCamStep *step: iStep) {
// QString stepName = step->name().toLower();
// stepNames.append(stepName);
// if (d->stepsMap.contains(stepName)) {
// delete d->stepsMap[stepName];
// }
// d->stepsMap.insert(stepName, step);
// d->matrixSteps.insert(stepName, d->stepsMap.count() + 1);
// }
// emit actionNotified("add_step", QVariantMap{{"steps",stepNames}});
//}
bool PcbCamJob::createStep(const QString &iStepName)
{
Q_D(PcbCamJob);
if (isStepExists(iStepName)) return false;
auto step = new PcbCamStep;
step->setName(iStepName.toLower());
d->stepsMap.insert(step->name(), step);
d->matrixSteps.insert(step->name(), d->getMaxStepNum() + 1);
return true;
}
bool PcbCamJob::deleteStep(const QString &iStepName)
{
Q_D(PcbCamJob);
if (!isStepExists(iStepName)) return false;
auto step = d->stepsMap[iStepName];
delete step;
d->stepsMap.remove(iStepName);
d->matrixSteps.remove(iStepName);
return true;
}
bool PcbCamJob::renameStep(const QString &iOldStepName, const QString &iNewStepName)
{
Q_D(PcbCamJob);
if (!isStepExists(iOldStepName)) return false;
auto step = d->stepsMap[iOldStepName];
step->setName(iNewStepName.toLower());
d->stepsMap.remove(iOldStepName);
d->stepsMap.insert(iNewStepName.toLower(), step);
auto stepSeq = d->matrixSteps.value(iOldStepName);
d->matrixSteps.remove(iOldStepName);
d->matrixSteps.insert(iNewStepName.toLower(), stepSeq);
// TODO 改名后应该把其它step的SR中的stepname也改掉;还有加载原始文件路径问题
return true;
}
bool PcbCamJob::createLayer(const QString &iLayerName, PcbCam::LayerContext iLayerContext, const QString &iLayerType)
{
Q_D(PcbCamJob);
PcbCamMatrixLayer layer;
layer.setName(iLayerName);
layer.setContext(iLayerContext);
layer.setType(iLayerType);
layer.setRow(d->getMaxLayerRow() + 1);
layer.setId(d->getMaxLayerId() + 1);
d->matrixLayers.append(layer);
emit actionNotified("create_layer", QVariantMap{{"name", iLayerName}, {"context", (int)iLayerContext}, {"type", iLayerType}});
return true;
}
bool PcbCamJob::isStepExists(const QString &iStepName) const
{
Q_D(const PcbCamJob);
return d->stepsMap.contains(iStepName.toLower());
}
PcbCamLayer *PcbCamJob::layer(const QString &iStepName, const QString &iLayerName)
{
Q_D(const PcbCamJob);
loadStepLayer(iStepName, iLayerName);
PcbCamLayer *layer = d->layersMap.value(iStepName.toLower() + "/" + iLayerName.toLower(), nullptr);
if (layer == nullptr && isStepExists(iStepName)) {
loadStepLayer(iStepName, iLayerName);
layer = new PcbCamLayer(this);
layer->setName(iLayerName.toLower());
layer->setStep(iStepName.toLower());
}
return layer;
}
bool PcbCamJob::isStepLayerExists(const QString &iStepName, const QString &iLayerName) const
{
Q_D(const PcbCamJob);
return d->layersMap.contains(iStepName.toLower() + "/" + iLayerName.toLower());
}
bool PcbCamJob::renameLayer(const QString &iOldLayerName, const QString &iNewLayerName)
{
Q_D(PcbCamJob);
auto old_ln = iOldLayerName.toLower();
auto new_ln = iNewLayerName.toLower();
if (isLayerExists(new_ln)) return false;
for (auto &layer : d->matrixLayers) {
if (layer.name() == old_ln) {
layer.setName(iNewLayerName.toLower());
for (auto key: d->layersMap.keys()) {
auto tmp = key.split("/");
auto step = tmp.value(0);
auto ln = tmp.value(1);
if (ln == old_ln) {
auto steplayer = d->layersMap.value(key);
steplayer->setName(new_ln);
d->layersMap.remove(key);
d->layersMap.insert(step + "/" + new_ln, steplayer);
}
}
emit actionNotified("rename_layer", QVariantMap{{"old_name", iOldLayerName}, {"new_name", iNewLayerName}});
return true;
}
}
return false;
}
void PcbCamJob::setLayerType(const QString &iLayerName, const QString &iLayerType)
{
Q_D(PcbCamJob);
for (auto &layer : d->matrixLayers) {
if (layer.name() == iLayerName) {
layer.setType(iLayerType);
break;
}
}
}
void PcbCamJob::setLayerContext(const QString &iLayerName, PcbCam::LayerContext iLayerContext)
{
Q_D(PcbCamJob);
for (auto &layer : d->matrixLayers) {
if (layer.name() == iLayerName) {
layer.setContext(iLayerContext);
break;
}
}
}
void PcbCamJob::setLayerPolarity(const QString &iLayerName, PcbCam::Polarity iLayerPolarity)
{
Q_D(PcbCamJob);
for (auto &layer : d->matrixLayers) {
if (layer.name() == iLayerName) {
layer.setPolarity(iLayerPolarity);
break;
}
}
}
void PcbCamJob::setLayerSpan(const QString &iLayerName, const QString &iStartLayer, const QString &iEndLayer)
{
Q_D(PcbCamJob);
for (auto &layer : d->matrixLayers) {
if (layer.name() == iLayerName) {
layer.setStartName(iStartLayer);
layer.setEndName(iEndLayer);
break;
}
}
}
void PcbCamJob::setLayerRow(const QString &iLayerName, int iRow)
{
Q_D(PcbCamJob);
for (auto &layer : d->matrixLayers) {
if (layer.name() == iLayerName) {
layer.setRow(iRow);
break;
}
}
}
void PcbCamJob::setStepWorkLayer(const QString &iStepName, const QString &iLayerName)
{
auto oldwoklayer = stepWorkLayer(iStepName);
this->loadStepLayer(iStepName, iLayerName);
auto newworklayer = this->layer(iStepName, iLayerName);
if (oldwoklayer == newworklayer) return;
if (newworklayer != nullptr) newworklayer->setWorkLayer(true);
if (oldwoklayer != nullptr) {
oldwoklayer->setWorkLayer(false);
if (!oldwoklayer->isAffectedLayer()) {
oldwoklayer->clearSelection();
}
}
}
void PcbCamJob::setStepLayerAffected(const QString &iStepName, const QString &iLayerName, bool iAffected)
{
if (iAffected) {
this->loadStepLayer(iStepName, iLayerName);
}
auto layer = this->layer(iStepName, iLayerName);
if (layer != nullptr) {
layer->setAffectedLayer(iAffected);
if (iAffected == false) {
layer->clearSelection();
}
}
}
void PcbCamJob::setStepLayerDisplayColor(const QString &iStepName, const QString &iLayerName, const QString iColor)
{
auto layer = this->layer(iStepName, iLayerName);
if (layer != nullptr) {
layer->setDisplayColor(iColor);
}
}
void PcbCamJob::clearStepAffectedLayer(const QString &iStepName)
{
Q_D(PcbCamJob);
for (auto layer: d->layersMap.values()) {
if (layer->step() != iStepName) continue;
layer->setAffectedLayer(false);
layer->clearSelection();
}
}
void PcbCamJob::resetStepAttectedLayer(const QString &iStepName, const QStringList &iAffectedLayers)
{
Q_D(PcbCamJob);
for (auto l : iAffectedLayers) {
this->loadStepLayer(iStepName, l);
}
for (auto layer: d->layersMap.values()) {
if (layer->step() != iStepName) continue;
if (iAffectedLayers.contains(layer->name())) {
layer->setAffectedLayer(true);
}
else {
layer->setAffectedLayer(false);
if (!layer->isWorkLayer()) {
layer->clearSelection();
}
}
}
}
void PcbCamJob::clearStepWorkLayer(const QString &iStepName)
{
Q_D(PcbCamJob);
for (auto layer: d->layersMap.values()) {
if (layer->step() != iStepName) continue;
layer->setWorkLayer(false);
layer->clearSelection();
}
}
void PcbCamJob::clearStepDisplayLayer(const QString &iStepName)
{
Q_D(PcbCamJob);
for (auto layer: d->layersMap.values()) {
if (layer->step() != iStepName) continue;
layer->setDisplayColor("");
}
}
PcbCamLayer *PcbCamJob::stepWorkLayer(const QString &iStepName) const
{
Q_D(const PcbCamJob);
for (const auto layer: d->layersMap.values()) {
if (layer->step() == iStepName && layer->isWorkLayer()) {
return layer;
}
}
return nullptr;
}
QList<PcbCamLayer *> PcbCamJob::stepAffectedLayer(const QString &iStepName) const
{
Q_D(const PcbCamJob);
QList<PcbCamLayer *> result;
for (const auto layer: d->layersMap.values()) {
if (layer->step() == iStepName && layer->isAffectedLayer()) {
result.append(layer);
}
}
return result;
}
QList<PcbCamLayer *> PcbCamJob::stepDispalyLayer(const QString &iStepName) const
{
Q_D(const PcbCamJob);
QList<PcbCamLayer *> result;
for (const auto layer : d->layersMap.values()) {
if (layer->step() == iStepName && !layer->displayColor().isEmpty()) {
result.append(layer);
}
}
return result;
}
QString PcbCamJob::jobPath() const
{
Q_D(const PcbCamJob);
return d->jobPath;
}
void PcbCamJob::setJobPath(const QString &iPath)
{
Q_D(PcbCamJob);
d->jobPath = iPath;
d->logJobPath = iPath;
d->jobname = QFileInfo(iPath).fileName();
}
void PcbCamJob::setLogJobPath(const QString &iPath)
{
Q_D(PcbCamJob);
d->logJobPath = iPath;
}
QList<PcbCamMatrixLayer> PcbCamJob::matrixLayers() const
{
Q_D(const PcbCamJob);
return d->matrixLayers;
}
QHash<QString, int> PcbCamJob::matrixSteps() const
{
Q_D(const PcbCamJob);
return d->matrixSteps;
}
bool PcbCamJob::isLayerExists(const QString &iLayerName) const
{
Q_D(const PcbCamJob);
auto ln = iLayerName.toLower();
for (auto layer: d->matrixLayers) {
if (layer.name() == ln) {
return true;
}
}
return false;
}
PcbCamMatrixLayer PcbCamJob::matrixLayer(const QString &iLayerName) const
{
Q_D(const PcbCamJob);
auto ln = iLayerName.toLower();
for (auto layer: d->matrixLayers) {
if (layer.name() == ln) {
return layer;
}
}
return PcbCamMatrixLayer();
}
bool PcbCamJob::isSymbolExists(const QString &iSymbolName) const
{
Q_D(const PcbCamJob);
return d->symbolsMap.contains(iSymbolName);
}
PcbCamSymbol *PcbCamJob::symbol(const QString &iSymbolName) const
{
Q_D(const PcbCamJob);
return d->symbolsMap.value(iSymbolName, nullptr);
}
QHash<QString, PcbCamSymbol*> PcbCamJob::symbols() const
{
Q_D(const PcbCamJob);
return d->symbolsMap;
}
bool PcbCamJob::isFontExists(const QString &iFontName) const
{
Q_D(const PcbCamJob);
return d->fontsMap.contains(iFontName);
}
PcbCamFont *PcbCamJob::font(const QString &iFontName) const
{
Q_D(const PcbCamJob);
return d->fontsMap.value(iFontName, nullptr);
}
void PcbCamJob::openJob()
{
readMiscInfo();
readMiscUserattr();
readMiscAttrlist();
readMatrix();
readSteps();
}
void PcbCamJob::loadStepLayer(const QString &iStep, const QString &iLayer)
{
Q_D(PcbCamJob);
//QElapsedTimer et; et.start();
if (!isStepExists(iStep) || iLayer.isEmpty()) {
return;
}
PcbCamStep *step = this->step(iStep);
if (!d->layersMap.contains(iStep.toLower() + "/" + iLayer.toLower())) {
QSet<QString> srsteps;
for (const PcbCamStepRepeat &sr : step->repeats()) {
srsteps.insert(sr.step());
}
for (const QString &srstep: srsteps) {
this->loadStepLayer(srstep, iLayer);
}
PcbCamLayer *layer = new PcbCamLayer(this);
layer->setName(iLayer.toLower());
layer->setStep(step->name());
if (iLayer.startsWith("comp_+_")) {
QList<PcbCamSymbolUser*> pkgSymbols = step->edaPackageSymbols();
if (pkgSymbols.isEmpty()) {
auto pkgs = readEdaPackagesFeature(iStep);
for (int i = 0; i < pkgs.count(); i++) {
auto userSymbol = new PcbCamSymbolUser(QString("%1/pkgs/%2").arg(iStep).arg(i));
auto feats = pkgs.at(i);
for (const PcbCamOdbFeatureInfo &f : feats) {
userSymbol->addFeature(createFeature(f));
}
pkgSymbols.append(userSymbol);
}
step->setEdaPackageSymbols(pkgSymbols);
}
QList<PcbCamOdbFeatureInfo> feats = readLayerComponent(iStep, iLayer);
for (int i = 0; i < feats.count(); i++) {
auto f = feats.at(i);
if (iLayer.endsWith("_bot")) { //背面的需Mirror
f.cw = !f.cw;
}
auto feat = createFeature(f);
feat->setSymbol(pkgSymbols.value(f.symbol.toInt(), nullptr));
layer->addFeature(feat);
}
}
else {
QList<PcbCamOdbFeatureInfo> feats = readLayerFeature(iStep, iLayer);
for (const PcbCamOdbFeatureInfo &f : feats) {
if (!f.symbol.isEmpty() && !d->symbolsMap.contains(f.symbol)) {
this->loadSymbol(f.symbol);
}
if (f.type == PcbCam::TextFeature && !d->fontsMap.contains(f.font)) {
this->loadFont(f.font);
}
layer->addFeature(createFeature(f));
}
}
QString err;
QVariantMap attr = PcbCamParserHelper::parseOdbStructuredText(readJobFile("steps/"+iStep.toLower()+"/layers/"+iLayer.toLower()+"/attrlist"), &err);
if (!err.isEmpty()) {
notifyMessage(err, "ERROR");
}
layer->initAttr(attr);
d->layersMap.insert(layer->step() + "/" + layer->name(), layer);
}
}
void PcbCamJob::loadSymbol(const QString &iSymbolName)
{
Q_D(PcbCamJob);
PcbCamSymbol *sym = PcbCamSymbolFactory::create(iSymbolName);
if (sym->type() == PcbCam::Sym_User) {
PcbCamSymbolUser *userSymbol = static_cast<PcbCamSymbolUser*>(sym);
QList<PcbCamOdbFeatureInfo> feats = readSymbolFeature(iSymbolName);
for (const PcbCamOdbFeatureInfo &f : feats) {
if (!f.symbol.isEmpty() && !d->symbolsMap.contains(f.symbol)) {
this->loadSymbol(f.symbol);
}
if (f.type == PcbCam::TextFeature && !d->fontsMap.contains(f.font)) {
this->loadFont(f.font);
}
userSymbol->addFeature(createFeature(f));
}
}
d->symbolsMap.insert(sym->name(), sym);
}
void PcbCamJob::loadFont(const QString &iFontName)
{
Q_D(PcbCamJob);
auto fontData = readJobFile("fonts/" + iFontName);
if (fontData.isEmpty()) {
QFile sysFontFile(":/res/misc/fonts/" + iFontName);
if (sysFontFile.open(QFile::ReadOnly | QFile::Text)) {
fontData = sysFontFile.readAll();
sysFontFile.close();
} else {
notifyMessage(QString("read file %1 failed!").arg(":/res/misc/fonts/" + iFontName), "ERROR");
}
}
QString err;
PcbCamFont *font = new PcbCamFont();
font->setName(iFontName);
if (PcbCamParserHelper::parseOdbFont(fontData, font, &err)) {
d->fontsMap.insert(iFontName, font);
} else {
delete font;
font = nullptr;
notifyMessage(err, "ERROR");
}
}
void PcbCamJob::notifyMessage(const QString &iText, const QString &iType, const QVariant &iUserData) const
{
emit messageNotified(iText, iType, iUserData);
PcbCamCore::instance()->notifyMessage(iText, iType, "JOB", iUserData);
}
bool PcbCamJob::readMiscInfo()
{
QString err;
QVariantMap data = PcbCamParserHelper::parseOdbStructuredText(readJobFile("misc/info"), &err);
if (!err.isEmpty()) {
notifyMessage(err, "ERROR");
return false;
}
this->setOdbVersionMajor(data.value("ODB_VERSION_MAJOR").toInt());
this->setOdbVersionMinor(data.value("ODB_VERSION_MINOR").toInt());
this->setCreationDate(QDateTime::fromString(data.value("CREATION_DATE").toString(), "yyyyMMdd.hhmmss"));
this->setSaveDate(QDateTime::fromString(data.value("SAVE_DATE").toString(), "yyyyMMdd.hhmmss"));
this->setSaveApp(data.value("SAVE_APP").toString());
this->setSaveUser(data.value("SAVE_APP").toString());
return true;
}
bool PcbCamJob::readMiscAttrlist()
{
Q_D(PcbCamJob);
QString err;
QVariantMap data = PcbCamParserHelper::parseOdbStructuredText(readJobFile("misc/attrlist"), &err);
if (!err.isEmpty()) {
notifyMessage(err, "ERROR");
return false;
}
d->jobAttrMap = data;
return true;
}
bool PcbCamJob::readMiscUserattr()
{
Q_D(PcbCamJob);
d->userAttrDefineMap.clear();
QString err;
QFile sysattrfile(":/res/misc/sysattr");
sysattrfile.open(QFile::ReadOnly | QFile::Text);
auto sysattrdata = sysattrfile.readAll();
sysattrfile.close();
QVariantMap sysdata = PcbCamParserHelper::parseOdbStructuredText(sysattrdata, &err);
if (!err.isEmpty()) {
notifyMessage(err, "ERROR");
}
sysdata.remove("FORCE_LIB");
for (const QString &k : sysdata.keys()) {
for (const QVariant &it : sysdata.value(k).toList()) {
QVariantMap item = it.toMap();
PcbCamAttrDefine attr;
attr.setDataType(PcbCamAttrDefine::dataTypeFromString(k));
attr.setEntity(PcbCamAttrDefine::entityFromString(item.value("ENTITY").toString()));
attr.setName(item.value("NAME").toString().toLower());
attr.setPrompt(item.value("PROMPT").toString());
attr.setDefaultValue(item.value("DEF"));
attr.setMinLength(item.value("MIN_LEN").toInt());
attr.setMaxLength(item.value("MAX_LEN").toInt());
attr.setOptions(item.value("OPTIONS").toString().split(";", Qt::SkipEmptyParts));
attr.setDeleted(item.value("DELETED").toString().split(";", Qt::SkipEmptyParts));
d->userAttrDefineMap.insert(attr.name(), attr);
}
}
QVariantMap userdata = PcbCamParserHelper::parseOdbStructuredText(readJobFile("misc/userattr"), &err);
if (!err.isEmpty()) {
notifyMessage(err, "ERROR");
return false;
}
userdata.remove("FORCE_LIB");
for (const QString &k : userdata.keys()) {
for (const QVariant &it : userdata.value(k).toList()) {
QVariantMap item = it.toMap();
PcbCamAttrDefine attr;
attr.setDataType(PcbCamAttrDefine::dataTypeFromString(k));
attr.setEntity(PcbCamAttrDefine::entityFromString(item.value("ENTITY").toString()));
attr.setName(item.value("NAME").toString().toLower());
attr.setPrompt(item.value("PROMPT").toString());
attr.setDefaultValue(item.value("DEF"));
attr.setMinLength(item.value("MIN_LEN").toInt());
attr.setMaxLength(item.value("MAX_LEN").toInt());
attr.setOptions(item.value("OPTIONS").toString().split(";", Qt::SkipEmptyParts));
attr.setDeleted(item.value("DELETED").toString().split(";", Qt::SkipEmptyParts));
d->userAttrDefineMap.insert(attr.name(), attr);
}
}
return true;
}
bool PcbCamJob::readMatrix()
{
Q_D(PcbCamJob);
QString err;
QVariantMap data = PcbCamParserHelper::parseOdbStructuredText(readJobFile("matrix/matrix"), &err);
if (!err.isEmpty()) {
notifyMessage(err, "ERROR");
return false;
}
d->matrixSteps.clear();
d->matrixLayers.clear();
for (const QVariant &step : data.value("STEP").toList()) {
QVariantMap stepinfo = step.toMap();
d->matrixSteps.insert(stepinfo.value("NAME").toString().toLower(),
stepinfo.value("COL").toInt());
}
for (const QVariant &l : data.value("LAYER").toList()) {
QVariantMap layerinfo = l.toMap();
PcbCamMatrixLayer layer;
auto layerid = layerinfo.value("ID", 0).toInt();
if (layerid <= 0) layerid = d->getMaxLayerId() + 1;
layer.setId(layerid);
layer.setRow(layerinfo.value("ROW").toInt());
layer.setContext(layerinfo.value("CONTEXT").toString()=="BOARD" ? PcbCam::BoardContext : PcbCam::MiscContext);
layer.setType(layerinfo.value("TYPE").toString().toLower());
layer.setName(layerinfo.value("NAME").toString().toLower());
layer.setPolarity(layerinfo.value("POLARITY").toString() == "NEGATIVE" ? PcbCam::Negative : PcbCam::Positive);
layer.setStartName(layerinfo.value("START_NAME").toString().toLower());
layer.setEndName(layerinfo.value("END_NAME").toString().toLower());
layer.setOldName(layerinfo.value("OLD_NAME").toString().toLower());
d->matrixLayers.append(layer);
}
return true;
}
bool PcbCamJob::readSteps()
{
Q_D(PcbCamJob);
/*
notifyMessage(QString("read steps - %1/steps").arg(this->jobPath()), "INFO");
QString err;
QByteArray stepsba = readJobFile("steps", &err);
if (!err.isEmpty()) {
notifyMessage(QString("read steps - %1/steps failed! %2").arg(this->jobPath()).arg(err), "ERROR");
return false;
}
if (stepsba.isEmpty()) stepsba.append("[]");
QJsonParseError jsonerr;
auto jsondoc = QJsonDocument::fromJson(stepsba, &jsonerr);
if (jsonerr.error != QJsonParseError::NoError) {
notifyMessage(QString("read steps - %1/steps failed! %2").arg(this->jobPath()).arg(jsonerr.errorString()), "ERROR");
return false;
}
QStringList steps;
for (auto it : jsondoc.toVariant().toList()) {
steps << it.toString();
}
*/
QStringList steps = d->matrixSteps.keys();
for (auto stepname : steps) {
QString err;
QVariantMap data = PcbCamParserHelper::parseOdbStructuredText(readJobFile("steps/" + stepname + "/stephdr"), &err);
if (!err.isEmpty()) {
notifyMessage(err, "ERROR");
}
PcbCamStep *step = new PcbCamStep();
step->setName(stepname);
step->setDatum(QPointF(data.value("X_DATUM").toDouble(), data.value("Y_DATUM").toDouble()));
step->setOrigin(QPointF(data.value("X_ORIGIN").toDouble(), data.value("Y_ORIGIN").toDouble()));
step->setActiveMargin(QMarginsF(data.value("LEFT_ACTIVE").toDouble(),
data.value("TOP_ACTIVE").toDouble(),
data.value("RIGHT_ACTIVE").toDouble(),
data.value("BOTTOM_ACTIVE").toDouble()));
for (const QVariant &row : data.value("STEP-REPEAT").toList()) {
QVariantMap srinfo = row.toMap();
PcbCamStepRepeat sr;
sr.setStep(srinfo.value("NAME").toString().toLower());
sr.setX(srinfo.value("X").toDouble());
sr.setY(srinfo.value("Y").toDouble());
sr.setDx(srinfo.value("DX").toDouble());
sr.setDy(srinfo.value("DY").toDouble());
sr.setNx(srinfo.value("NX").toInt());
sr.setNy(srinfo.value("NY").toInt());
sr.setAngle(srinfo.value("ANGLE").toDouble());
sr.setMirror(srinfo.value("MIRROR").toString() == "YES" ? true : false);
step->addRepeat(sr);
}
QPainterPath profile = PcbCamParserHelper::parseOdbProfile(readJobFile("steps/" + stepname + "/profile"));
step->setProfile(profile);
QVariantMap stepattr = PcbCamParserHelper::parseOdbStructuredText(readJobFile("steps/" + stepname + "/attrlist"), &err);
step->initAttr(stepattr);
d->stepsMap.insert(stepname, step);
}
//addStep(newSteps);
return true;
}
QList<PcbCamOdbFeatureInfo> PcbCamJob::readLayerFeature(const QString &iStep, const QString &iLayer)
{
QString relpath = "steps/" + iStep.toLower() + "/layers/" + iLayer.toLower() + "/features";
auto featdata = readJobFile(relpath);
PcbCamOdbFeatureParser parser(featdata);
parser.parse();
QStringList errs = parser.errors();
if (!errs.isEmpty()) {
notifyMessage(errs.join(";"), "ERROR");
}
return parser.features();
}
QList<PcbCamOdbFeatureInfo> PcbCamJob::readSymbolFeature(const QString &iSymbol)
{
QString relpath = "symbols/" + iSymbol.toLower() + "/features";
auto featdata = readJobFile(relpath);
PcbCamOdbFeatureParser parser(featdata);
parser.parse();
QStringList errs = parser.errors();
if (!errs.isEmpty()) {
notifyMessage(errs.join(";"), "ERROR");
}
return parser.features();
}
QList<QList<PcbCamOdbFeatureInfo>> PcbCamJob::readEdaPackagesFeature(const QString &iStep)
{
QString relpath = "steps/" + iStep.toLower() + "/eda/data";
auto featdata = readJobFile(relpath);
PcbCamOdbEdaDataParser parser(featdata);
parser.parse();
QStringList errs = parser.errors();
if (!errs.isEmpty()) {
notifyMessage(errs.join(";"), "ERROR");
}
return parser.packageFeatures();
}
QList<PcbCamOdbFeatureInfo> PcbCamJob::readLayerComponent(const QString &iStep, const QString &iLayer)
{
QString relpath = "steps/" + iStep.toLower() + "/layers/" + iLayer.toLower() + "/components";
auto featdata = readJobFile(relpath);
PcbCamOdbComponentParser parser(featdata);
parser.parse();
QStringList errs = parser.errors();
if (!errs.isEmpty()) {
notifyMessage(errs.join(";"), "ERROR");
}
return parser.features();
}
bool PcbCamJob::importGerber274X(const QString &iGerberFile, const QString &iStep, const QString &iLayer)
{
Q_D(PcbCamJob);
if (!isStepExists(iStep)) createStep(iStep);
if (!isLayerExists(iLayer)) createLayer(iLayer);
auto layer = this->layer(iStep, iLayer);
if (layer == nullptr) return false;
layer->clearFeatures();
QFile gbrfile(iGerberFile);
if (!gbrfile.open(QFile::ReadOnly|QFile::Text)) return false;
PcbCamGerber274XParser parser;
parser.parse(&gbrfile);
gbrfile.close();
auto apertures = parser.apertures();
QHash<int, QString> dcodeSymbolMap;
auto sym_num = d->getMaxConstructSymbolNum();
for (auto ap : apertures.values()) {
auto sym_name = ap.name;
if (!ap.isStandard) {
sym_name = QString("construct+%1").arg(++sym_num);
}
if (!d->symbolsMap.contains(sym_name)) {
PcbCamSymbol *sym = PcbCamSymbolFactory::create(sym_name);
if (sym->type() == PcbCam::Sym_User) {
PcbCamSymbolUser *userSymbol = static_cast<PcbCamSymbolUser*>(sym);
for (const PcbCamOdbFeatureInfo &f : ap.features) {
userSymbol->addFeature(createFeature(f));
}
}
d->symbolsMap.insert(sym->name(), sym);
}
dcodeSymbolMap.insert(ap.dcode, sym_name);
}
auto features = parser.features();
int featindex = 1;
for (auto f: features) {
if (!dcodeSymbolMap.contains(f.decode)) {
QString sym_name = "r0";
dcodeSymbolMap.insert(f.decode, sym_name);
if (!d->symbolsMap.contains(sym_name)) {
PcbCamSymbol *sym = PcbCamSymbolFactory::create(sym_name);
d->symbolsMap.insert(sym_name, sym);
}
}
f.index = featindex++;
f.symbol = dcodeSymbolMap.value(f.decode);
layer->addFeature(createFeature(f));
}
d->layersMap.insert(layer->step() + "/" + layer->name(), layer);
return true;
}
bool PcbCamJob::importDrill(const QString &iDrlFile, const QString &iStep, const QString &iLayer, const QVariantMap &iStatement)
{
Q_D(PcbCamJob);
if (!isStepExists(iStep)) createStep(iStep);
if (!isLayerExists(iLayer)) createLayer(iLayer);
auto layer = this->layer(iStep, iLayer);
if (layer == nullptr) return false;
layer->clearFeatures();
PcbCamDrillParser parser(iDrlFile, PcbCamDrillParser::DrillStatement(iStatement));
parser.parser();
for (auto symname: parser.symbols()) {
if (!d->symbolsMap.contains(symname)) {
auto sym = PcbCamSymbolFactory::create(symname);
d->symbolsMap.insert(sym->name(), sym);
}
}
auto features = parser.features();
int featindex = 1;
for (auto f: features) {
f.index = featindex++;
layer->addFeature(createFeature(f));
}
d->layersMap.insert(layer->step() + "/" + layer->name(), layer);
return true;
}
QByteArray PcbCamJob::readJobFile(const QString &iRelPath, QString *oErrStr) const
{
Q_D(const PcbCamJob);
QString filepath = d->logJobPath + "/" + iRelPath;
notifyMessage(QString("read file - %1").arg(filepath), "INFO");
QString err;
auto result = PcbCamCore::instance()->dataIo()->readJobData(this->jobPath(), iRelPath, &err);
if (!err.isEmpty()) {
notifyMessage(QString("read file -%1 failed! %2").arg(filepath).arg(err), "ERROR");
}
if (oErrStr != nullptr) {
*oErrStr = err;
}
return result;
}
PcbCamFeature *PcbCamJob::createFeature(const PcbCamOdbFeatureInfo &iFeat)
{
Q_D(const PcbCamJob);
if (iFeat.type == PcbCam::LineFeature) {
PcbCamFeatureLine *f = new PcbCamFeatureLine();
f->setPolarity(iFeat.polarity);
f->setIndex(iFeat.index);
f->setDcode(iFeat.decode);
f->setSymbol(d->symbolsMap[iFeat.symbol]);
f->setAttr(iFeat.attributes);
f->setLine(QLineF(iFeat.ps, iFeat.pe));
return f;
}
else if (iFeat.type == PcbCam::PadFeature) {
PcbCamFeaturePad *f = new PcbCamFeaturePad();
f->setPolarity(iFeat.polarity);
f->setIndex(iFeat.index);
f->setDcode(iFeat.decode);
f->setSymbol(d->symbolsMap[iFeat.symbol]);
f->setAttr(iFeat.attributes);
f->setPos(iFeat.ps);
f->setOrient(iFeat.orient);
return f;
}
else if (iFeat.type == PcbCam::ArcFeature) {
PcbCamFeatureArc *f = new PcbCamFeatureArc();
f->setPolarity(iFeat.polarity);
f->setIndex(iFeat.index);
f->setDcode(iFeat.decode);
f->setSymbol(d->symbolsMap[iFeat.symbol]);
f->setAttr(iFeat.attributes);
f->setData(iFeat.ps, iFeat.pe, iFeat.pc, iFeat.cw);
return f;
}
else if (iFeat.type == PcbCam::TextFeature) {
PcbCamFeatureText *f = new PcbCamFeatureText();
f->setPolarity(iFeat.polarity);
f->setIndex(iFeat.index);
f->setAttr(iFeat.attributes);
f->setData(iFeat.ps, d->fontsMap.value(iFeat.font), iFeat.orient, iFeat.size, iFeat.widthFactor, iFeat.text, iFeat.version);
return f;
}
else if (iFeat.type == PcbCam::BarcodeFeature) {
PcbCamFeatureBarcode *f = new PcbCamFeatureBarcode();
f->setIndex(iFeat.index);
f->setPos(iFeat.ps);
f->setBarcode(iFeat.barcode);
f->setFont(iFeat.font);
f->setPolarity(iFeat.polarity);
f->setOrient(iFeat.orient);
f->setSize(iFeat.size);
f->setFullAscii(iFeat.fullAscii);
f->setCheckSum(iFeat.checkSum);
f->setBackground(iFeat.background);
f->setAdditionStr(iFeat.additionStr);
f->setAdditionStrPos(iFeat.additionStrPos);
f->setText(iFeat.text);
f->setAttr(iFeat.attributes);
return f;
}
else if (iFeat.type == PcbCam::SurfaceFeature) {
PcbCamFeatureSurface *f = new PcbCamFeatureSurface();
f->setIndex(iFeat.index);
f->setPolarity(iFeat.polarity);
f->setAttr(iFeat.attributes);
f->setPath(iFeat.path);
return f;
}
else if (iFeat.type == PcbCam::PathFeature) {
PcbCamFeaturePath *f = new PcbCamFeaturePath();
f->setIndex(iFeat.index);
f->setPolarity(iFeat.polarity);
f->setAttr(iFeat.attributes);
f->setPath(iFeat.path);
f->setWidth(iFeat.widthFactor);
return f;
}
else if (iFeat.type == PcbCam::ComponentFeature) {
PcbCamFeatureComponent *f = new PcbCamFeatureComponent();
f->setIndex(iFeat.index);
f->setPolarity(iFeat.polarity);
f->setAttr(iFeat.attributes);
f->setData(iFeat.ps, iFeat.widthFactor, iFeat.cw, iFeat.text, iFeat.font);
return f;
}
return nullptr;
}
TITAN_END_NAMESPACE
#ifndef TITAN_PCBCAM_JOB_H
#define TITAN_PCBCAM_JOB_H
#include "../titanpcbcamglobal.h"
#include <QObject>
#include <QDateTime>
#include <QVariant>
#include <QVariantMap>
#include "./attrdefine.h"
#include "./step.h"
#include "./layer.h"
#include "./matrixlayer.h"
#include "./symbol.h"
#include "../parser/odbfeatureparser.h"
TITAN_BEGIN_NAMESPACE
class PcbCamJobPrivate;
class TITAN_PCBCAM_EXPORT PcbCamJob : public QObject
{
Q_OBJECT
public:
explicit PcbCamJob(QObject *parent = 0);
~PcbCamJob();
signals:
void messageNotified(const QString &iMessage, const QString &iType, const QVariant &iUserData) const;
void actionNotified(const QString &iActionName, const QVariantMap &iUserData) const;
public slots:
QString jobname() const;
void setJobname(const QString &iJobname);
uint odbVersionMajor() const;
void setOdbVersionMajor(uint iVersion);
uint odbVersionMinor() const;
void setOdbVersionMinor(uint iVersion);
QDateTime creationDate() const;
void setCreationDate(QDateTime iDt);
QDateTime saveDate() const;
void setSaveDate(QDateTime iDt);
QString saveApp() const;
void setSaveApp(const QString &iApp);
QString saveUser() const;
void setSaveUser(const QString &iUser);
QVariant jobAttr(const QString &iName) const;
bool hasJobAttr(const QString &iName) const;
void setJobAttr(const QString &iName, const QVariant &iValue);
PcbCamAttrDefine userAttrDefine(const QString &iName) const;
QHash<QString, PcbCamAttrDefine> userAttrDefine() const;
void addUserAttrDefine(const PcbCamAttrDefine &iAttrDefine);
PcbCamStep *step(const QString &iStepName) const;
bool isStepExists(const QString &iStepName) const;
QHash<QString, PcbCamStep*> allSteps() const;
// void addStep(PcbCamStep *iStep);
// void addStep(const QVector<PcbCamStep*> &iStep);
bool createStep(const QString &iStepName);
bool deleteStep(const QString &iStepName);
bool renameStep(const QString &iOldStepName, const QString &iNewStepName);
bool createLayer(const QString &iLayerName, PcbCam::LayerContext iLayerContext = PcbCam::MiscContext, const QString &iLayerType="document");
PcbCamLayer *layer(const QString &iStepName, const QString &iLayerName);
bool isStepLayerExists(const QString &iStepName, const QString &iLayerName) const;
bool renameLayer(const QString &iOldLayerName, const QString &iNewLayerName);
void setLayerType(const QString &iLayerName, const QString &iLayerType);
void setLayerContext(const QString &iLayerName, PcbCam::LayerContext iLayerContext);
void setLayerPolarity(const QString &iLayerName, PcbCam::Polarity iLayerPolarity);
void setLayerSpan(const QString &iLayerName, const QString &iStartLayer, const QString &iEndLayer);
void setLayerRow(const QString &iLayerName, int iRow);
void setStepWorkLayer(const QString &iStepName, const QString &iLayerName);
void setStepLayerAffected(const QString &iStepName, const QString &iLayerName, bool iAffected = true);
void setStepLayerDisplayColor(const QString &iStepName, const QString &iLayerName, const QString iColor);
void clearStepAffectedLayer(const QString &iStepName);
void resetStepAttectedLayer(const QString &iStepName, const QStringList &iAffectedLayers);
void clearStepWorkLayer(const QString &iStepName);
void clearStepDisplayLayer(const QString &iStepName);
PcbCamLayer *stepWorkLayer(const QString &iStepName) const;
QList<PcbCamLayer *> stepAffectedLayer(const QString &iStepName) const;
QList<PcbCamLayer *> stepDispalyLayer(const QString &iStepName) const;
QString jobPath() const;
void setJobPath(const QString &iPath);
void setLogJobPath(const QString &iPath);
QList<PcbCamMatrixLayer> matrixLayers() const;
QHash<QString, int> matrixSteps() const;
bool isLayerExists(const QString &iLayerName) const;
PcbCamMatrixLayer matrixLayer(const QString &iLayerName) const;
bool isSymbolExists(const QString &iSymbolName) const;
PcbCamSymbol *symbol(const QString &iSymbolName) const;
QHash<QString, PcbCamSymbol*> symbols() const;
bool isFontExists(const QString &iFontName) const;
PcbCamFont *font(const QString &iFontName) const;
void openJob();
void loadStepLayer(const QString &iStep, const QString &iLayer);
void loadSymbol(const QString &iSymbolName);
void loadFont(const QString &iFontName);
void notifyMessage(const QString &iText, const QString &iType, const QVariant &iUserData = QVariant()) const;
QByteArray readJobFile(const QString &iRelPath, QString *oErrStr = nullptr) const;
bool importGerber274X(const QString &iGerberFile, const QString &iStep, const QString &iLayer);
bool importDrill(const QString &iDrlFile, const QString &iStep, const QString &iLayer, const QVariantMap &iStatement);
private:
bool readMiscInfo();
bool readMiscAttrlist();
bool readMiscUserattr();
bool readMatrix();
bool readSteps();
QList<PcbCamOdbFeatureInfo> readLayerFeature(const QString &iStep, const QString &iLayer);
QList<PcbCamOdbFeatureInfo> readSymbolFeature(const QString &iSymbol);
QList<QList<PcbCamOdbFeatureInfo>> readEdaPackagesFeature(const QString &iStep);
QList<PcbCamOdbFeatureInfo> readLayerComponent(const QString &iStep, const QString &iLayer);
PcbCamFeature *createFeature(const PcbCamOdbFeatureInfo &iFeat);
protected:
const QScopedPointer<PcbCamJobPrivate> d_ptr;
private:
Q_DECLARE_PRIVATE(PcbCamJob)
Q_DISABLE_COPY(PcbCamJob)
};
TITAN_END_NAMESPACE
#endif // TITAN_PCBCAM_JOB_H
#include "layer.h"
#include "./feature.h"
#include "./symbol.h"
#include "./job.h"
#include "./util.h"
#include <QDebug>
#include <QHash>
TITAN_BEGIN_NAMESPACE
class PcbCamLayerPrivate
{
Q_DECLARE_PUBLIC(PcbCamLayer)
public:
PcbCamLayerPrivate(PcbCamLayer *qptr) : q_ptr(qptr) { }
~PcbCamLayerPrivate() {
destoryFeatures();
}
void destoryFeatures() {
qDeleteAll(features);
features.clear();
}
PcbCamJob *job {nullptr};
//Layer名称
QString layerName;
//Step名称
QString stepName;
//Layer属性
QVariantMap layerAttrMap;
//是否影响层
bool isAffectedLayer {false};
//是否工作层
bool isWorkLayer {false};
//是否已经加载
bool loaded {false};
int maxIndex {0};
QString displayColor;
QList<PcbCamFeature*> features;
mutable QRectF boundingRect;
protected:
PcbCamLayer * const q_ptr;
};
PcbCamLayer::PcbCamLayer(PcbCamJob *iJob)
: d_ptr(new PcbCamLayerPrivate(this))
{
Q_D(PcbCamLayer);
d->job = iJob;
}
PcbCamLayer::~PcbCamLayer()
{
}
PcbCamJob *PcbCamLayer::job() const
{
Q_D(const PcbCamLayer);
return d->job;
}
QString PcbCamLayer::name() const
{
Q_D(const PcbCamLayer);
return d->layerName;
}
void PcbCamLayer::setName(const QString &iName)
{
Q_D(PcbCamLayer);
d->layerName = iName.toLower();
}
QString PcbCamLayer::step() const
{
Q_D(const PcbCamLayer);
return d->stepName;
}
void PcbCamLayer::setStep(const QString &iStep)
{
Q_D(PcbCamLayer);
d->stepName = iStep.toLower();
}
QVariant PcbCamLayer::attr(const QString &iName) const
{
Q_D(const PcbCamLayer);
return d->layerAttrMap.value(iName.toLower());
}
bool PcbCamLayer::hasAttr(const QString &iName) const
{
Q_D(const PcbCamLayer);
return d->layerAttrMap.contains(iName.toLower());
}
void PcbCamLayer::initAttr(const QVariantMap &iAttrMap)
{
Q_D(PcbCamLayer);
d->layerAttrMap = iAttrMap;
}
void PcbCamLayer::setAttr(const QString &iName, const QVariant &iValue)
{
Q_D(PcbCamLayer);
d->layerAttrMap.insert(iName.toLower(), iValue);
}
void PcbCamLayer::setAffectedLayer(bool iAffected)
{
Q_D(PcbCamLayer);
d->isAffectedLayer = iAffected;
}
bool PcbCamLayer::isAffectedLayer() const
{
Q_D(const PcbCamLayer);
return d->isAffectedLayer;
}
void PcbCamLayer::setWorkLayer(bool iBol)
{
Q_D(PcbCamLayer);
d->isWorkLayer = iBol;
}
bool PcbCamLayer::isWorkLayer() const
{
Q_D(const PcbCamLayer);
return d->isWorkLayer;
}
void PcbCamLayer::setDisplayColor(const QString &iColor)
{
Q_D(PcbCamLayer);
d->displayColor = iColor;
}
QString PcbCamLayer::displayColor() const
{
Q_D(const PcbCamLayer);
return d->displayColor;
}
QList<PcbCamFeature *> PcbCamLayer::features() const
{
Q_D(const PcbCamLayer);
return d->features;
}
void PcbCamLayer::clearFeatures()
{
Q_D(PcbCamLayer);
d->destoryFeatures();
d->maxIndex = 0;
}
void PcbCamLayer::addFeature(PcbCamFeature *iFeature)
{
Q_D(PcbCamLayer);
iFeature->setIndex(++d->maxIndex);
d->features.append(iFeature);
}
void PcbCamLayer::addFeatures(const QList<PcbCamFeature *> &iFeatures)
{
for (PcbCamFeature *feat : iFeatures) {
addFeature(feat);
}
}
PcbCamFeature *PcbCamLayer::addLine(const QLineF &iLine, const QString &iSymbol, PcbCam::Polarity iPolarity, const QVariantMap &iAttr)
{
Q_D(PcbCamLayer);
if (d->job == nullptr) return nullptr;
if (!d->job->isSymbolExists(iSymbol)) {
d->job->loadSymbol(iSymbol);
}
auto sym = d->job->symbol(iSymbol);
auto feat = new PcbCamFeatureLine();
feat->setLine(iLine);
feat->setPolarity(iPolarity);
feat->setSymbol(sym);
feat->setAttr(iAttr);
addFeature(feat);
return feat;
}
PcbCamFeature *PcbCamLayer::addPad(const QPointF &iPos, const QString &iSymbol, PcbCam::Orient iOrient, PcbCam::Polarity iPolarity, const QVariantMap &iAttr)
{
Q_D(PcbCamLayer);
if (d->job == nullptr) return nullptr;
if (!d->job->isSymbolExists(iSymbol)) {
d->job->loadSymbol(iSymbol);
}
auto sym = d->job->symbol(iSymbol);
auto feat = new PcbCamFeaturePad();
feat->setPos(iPos);
feat->setOrient(iOrient);
feat->setPolarity(iPolarity);
feat->setSymbol(sym);
feat->setAttr(iAttr);
addFeature(feat);
return feat;
}
PcbCamFeature *PcbCamLayer::addArc(const QPointF &iPs, const QPointF &iPe, const QPointF &iPc, bool iCw, const QString &iSymbol, PcbCam::Polarity iPolarity, const QVariantMap &iAttr)
{
Q_D(PcbCamLayer);
if (d->job == nullptr) return nullptr;
if (!d->job->isSymbolExists(iSymbol)) {
d->job->loadSymbol(iSymbol);
}
auto sym = d->job->symbol(iSymbol);
auto feat = new PcbCamFeatureArc();
feat->setData(iPs, iPe, iPc, iCw);
feat->setPolarity(iPolarity);
feat->setSymbol(sym);
feat->setAttr(iAttr);
addFeature(feat);
return feat;
}
PcbCamFeature *PcbCamLayer::addText(const QPointF &iPos, const QString &iText, const QSizeF &iSize, PcbCam::Orient iOrient, PcbCam::Polarity iPolarity, const QVariantMap &iAttr, qreal iWidthFactor, const QString &iFont)
{
Q_D(PcbCamLayer);
if (d->job == nullptr) return nullptr;
if (!d->job->isSymbolExists(iFont)) {
d->job->loadFont(iFont);
}
auto font = d->job->font(iFont);
auto feat = new PcbCamFeatureText();
feat->setData(iPos, font, iOrient, iSize, iWidthFactor, iText);
feat->setPolarity(iPolarity);
feat->setAttr(iAttr);
addFeature(feat);
return feat;
}
PcbCamFeature *PcbCamLayer::addSurface(const QPainterPath &iPath, PcbCam::Polarity iPolarity, const QVariantMap &iAttr)
{
Q_D(PcbCamLayer);
if (d->job == nullptr) return nullptr;
auto feat = new PcbCamFeatureSurface();
feat->setPath(iPath);
feat->setPolarity(iPolarity);
feat->setAttr(iAttr);
addFeature(feat);
return feat;
}
PcbCamFeature *PcbCamLayer::addPath(const QPainterPath &iPath, int iWidth, PcbCam::Polarity iPolarity, const QVariantMap &iAttr)
{
Q_D(PcbCamLayer);
if (d->job == nullptr) return nullptr;
auto feat = new PcbCamFeaturePath();
feat->setPath(iPath);
feat->setWidth(iWidth);
feat->setPolarity(iPolarity);
feat->setAttr(iAttr);
addFeature(feat);
return feat;
}
void PcbCamLayer::deleteFeature(int iIndex)
{
Q_D(PcbCamLayer);
for (int i = 0; i < d->features.count(); ++i) {
PcbCamFeature *feat = d->features[i];
if (feat->index() == iIndex) {
d->features.removeAt(i);
delete feat;
return;
}
}
}
QList<PcbCamFeature *> PcbCamLayer::selectFeature(const QPainterPath &iRegionPath,
const PcbCam::FeatureSelectionFilter &iFilter,
PcbCam::FeatureSelectionOperation iSelOp,
PcbCam::FeatureSelectionMode iSelMode)
{
Q_D(PcbCamLayer);
QList<PcbCamFeature *> result;
auto stepProfile = d->job->step(d->stepName)->profile();
bool isFilterRange = !iRegionPath.isEmpty();
bool isFilterProfile = (iFilter.profile != PcbCam::AllProfile && !stepProfile.isEmpty());
bool isFilterInclueSym = !iFilter.includeSymbols.isEmpty();
bool isFilterExcludeSym = !iFilter.excludeSymbols.isEmpty();
bool isFilterIncludeAttr = !iFilter.includeAttributes.isEmpty();
bool isFilterExcludeAttr = !iFilter.excludeAttributes.isEmpty();
QSet<PcbCamSymbol*> includeSymbols;
for (auto symname : iFilter.includeSymbols) {
auto symbol = d->job->symbol(symname);
if (symbol != nullptr) {
includeSymbols.insert(symbol);
}
}
QSet<PcbCamSymbol*> excludeSymbols;
for (auto symname : iFilter.excludeSymbols) {
auto symbol = d->job->symbol(symname);
if (symbol != nullptr) {
excludeSymbols.insert(symbol);
}
}
QList<PcbCam::AttrCompareInfo> includeAttrs;
for (auto attr : iFilter.includeAttributes) {
includeAttrs.append(PcbCam::AttrCompareInfo(attr));
}
QList<PcbCam::AttrCompareInfo> excludeAttrs;
for (auto attr : iFilter.excludeAttributes) {
excludeAttrs.append(PcbCam::AttrCompareInfo(attr));
}
if (iSelOp == PcbCam::ReplaceFeatureSelection) {
this->clearSelection();
}
for (auto feat : d->features) {
//是否满足过滤条件
bool feat_match = PcbCamUtil::isFeatMatchFilter(feat,
iFilter.type,
iFilter.polarity,
isFilterProfile,
iFilter.profile,
stepProfile,
isFilterInclueSym,
includeSymbols,
isFilterExcludeSym,
excludeSymbols,
isFilterIncludeAttr,
includeAttrs,
iFilter.includeAttributesLogic,
isFilterExcludeAttr,
excludeAttrs,
iFilter.excludeAttributesLogic);
if (!feat_match) continue;
if (isFilterRange) {
bool range_match = false;
if (iSelMode == PcbCam::ContainsFeatureShape) {
if (iRegionPath.contains(feat->boundingRect())) range_match = true;
}
else if (iSelMode == PcbCam::IntersectsFeatureShape) {
if (iRegionPath.intersects(feat->shape())) range_match = true;
}
if (!range_match) continue;
}
result.append(feat);
if (iSelOp == PcbCam::ReplaceFeatureSelection || iSelOp == PcbCam::AppendFeatureSelection) {
feat->setSelected(true);
}
else if (iSelOp == PcbCam::RemoveFeatureSelection) {
feat->setSelected(false);
}
}
return result;
}
QList<PcbCamFeature *> PcbCamLayer::selectedFeatures() const
{
Q_D(const PcbCamLayer);
QList<PcbCamFeature*> result;
for ( PcbCamFeature* feat : d->features) {
if (feat->isSelected()) result.append(feat);
}
return result;
}
void PcbCamLayer::clearSelection()
{
Q_D(PcbCamLayer);
for (PcbCamFeature* feat : d->features) {
if (feat->isSelected()) feat->setSelected(false);
}
}
bool PcbCamLayer::hasFeatureSelected() const
{
Q_D(const PcbCamLayer);
for ( PcbCamFeature* feat : d->features) {
if (feat->isSelected()) return true;
}
return false;
}
QRectF PcbCamLayer::boundingRect() const
{
Q_D(const PcbCamLayer);
if (d->boundingRect.isEmpty()) {
for (const PcbCamFeature* feat : d->features) {
d->boundingRect = d->boundingRect.united(feat->boundingRect());
}
}
return d->boundingRect;
}
TITAN_END_NAMESPACE
#ifndef TITAN_PCBCAM_LAYER_H
#define TITAN_PCBCAM_LAYER_H
#include "../titanpcbcamglobal.h"
#include <QString>
#include <QVariantMap>
#include <QPainterPath>
#include "./common.h"
TITAN_BEGIN_NAMESPACE
class PcbCamJob;
class PcbCamFeature;
class PcbCamLayerPrivate;
class TITAN_PCBCAM_EXPORT PcbCamLayer
{
public:
PcbCamLayer(PcbCamJob *iJob);
~PcbCamLayer();
PcbCamJob *job() const;
QString name() const;
void setName(const QString &iName);
QString step() const;
void setStep(const QString &iStep);
QVariant attr(const QString &iName) const;
bool hasAttr(const QString &iName) const;
void initAttr(const QVariantMap &iAttrMap);
void setAttr(const QString &iName, const QVariant &iValue);
void setAffectedLayer(bool iAffected = true);
bool isAffectedLayer() const;
void setWorkLayer(bool iBol = true);
bool isWorkLayer() const;
void setDisplayColor(const QString &iColor);
QString displayColor() const;
QList<PcbCamFeature*> features() const;
void clearFeatures();
void addFeature(PcbCamFeature *iFeature);
void addFeatures(const QList<PcbCamFeature *> &iFeatures);
PcbCamFeature *addLine(const QLineF &iLine,
const QString &iSymbol,
PcbCam::Polarity iPolarity = PcbCam::Positive,
const QVariantMap &iAttr = QVariantMap());
PcbCamFeature *addPad(const QPointF &iPos,
const QString &iSymbol,
PcbCam::Orient iOrient = PcbCam::Orient_N_0,
PcbCam::Polarity iPolarity = PcbCam::Positive,
const QVariantMap &iAttr = QVariantMap());
PcbCamFeature *addArc(const QPointF &iPs,
const QPointF &iPe,
const QPointF &iPc,
bool iCw,
const QString &iSymbol,
PcbCam::Polarity iPolarity = PcbCam::Positive,
const QVariantMap &iAttr = QVariantMap());
PcbCamFeature *addText(const QPointF &iPos,
const QString &iText,
const QSizeF &iSize,
PcbCam::Orient iOrient = PcbCam::Orient_N_0,
PcbCam::Polarity iPolarity = PcbCam::Positive,
const QVariantMap &iAttr = QVariantMap(),
qreal iWidthFactor = 1.0,
const QString &iFont = "standard"
);
PcbCamFeature *addSurface(const QPainterPath &iPath,
PcbCam::Polarity iPolarity = PcbCam::Positive,
const QVariantMap &iAttr = QVariantMap());
PcbCamFeature *addPath(const QPainterPath &iPath,
int iWidth = 1,
PcbCam::Polarity iPolarity = PcbCam::Positive,
const QVariantMap &iAttr = QVariantMap());
void deleteFeature(int iIndex);
QList<PcbCamFeature *> selectFeature(const QPainterPath &iRegionPath,
const PcbCam::FeatureSelectionFilter &iFilter,
PcbCam::FeatureSelectionOperation iSelOp,
PcbCam::FeatureSelectionMode iSelMode);
QList<PcbCamFeature *> selectedFeatures() const;
void clearSelection();
bool hasFeatureSelected() const;
QRectF boundingRect() const;
protected:
const QScopedPointer<PcbCamLayerPrivate> d_ptr;
private:
Q_DECLARE_PRIVATE(PcbCamLayer)
Q_DISABLE_COPY(PcbCamLayer)
};
TITAN_END_NAMESPACE
#endif // TITAN_PCBCAM_LAYER_H
#include "math.h"
#ifndef TITAN_PCBCAM_MATH_H
#define TITAN_PCBCAM_MATH_H
#include "../titanpcbcamglobal.h"
#include <QPointF>
#include <QLineF>
#include <QPolygonF>
#include <cmath>
TITAN_BEGIN_NAMESPACE
class TITAN_PCBCAM_EXPORT PcbCamMath
{
public:
/* 计算两点之间距离 */
static inline double point2pointDist(const QPointF &p1, const QPointF &p2)
{
return sqrt( (p1.x()-p2.x())*(p1.x()-p2.x())+(p1.y()-p2.y())*(p1.y()-p2.y()));
}
/* 计算矢量(sp->op)和(ep->op)的叉积,其结果r的几何意义如下
* r>0: ep在矢量(os->sp)的逆时针方向
* r=0: op,sp,ep三点共线
* r<0: ep在矢量(os->sp)的顺时针方向
*/
static inline double crossMultiply(const QPointF &sp, const QPointF &ep, const QPointF &op)
{
return((sp.x()-op.x())*(ep.y()-op.y())-(ep.x()-op.x())*(sp.y()-op.y()));
}
/* 计算矢量(p1->p0)和(p2->p0)的点积,其结果r的几何含意如下
* r<0: 两矢量的夹角为锐角
* r=0: 两矢量的夹角为直角
* r>0: 两矢量的夹角为钝角
*/
static inline double dotMultiply(const QPointF &p1, const QPointF &p2, const QPointF &p0)
{
return ((p1.x()-p0.x())*(p2.x()-p0.x())+(p1.y()-p0.y())*(p2.y()-p0.y()));
}
/* 判断点是否在直线上*/
static inline bool isPointOnLine(const QPointF &p, const QLineF &l)
{
//判断条件: (点在线段所在的直线上) 并且 (点在线段对角线的矩形范围内)
return (crossMultiply(l.p2(), p, l.p1())==0) && ( ( (p.x()-l.p1().x())*(p.x()-l.p2().x())<=0 )&&( (p.y()-l.p1().y())*(p.y()-l.p2().y())<=0 ) );
}
/* 计算点到线段的垂足系数
*
* AC dot AB
* r = ---------------
* ||AB||^2
*
* 结果r的几何含意如下:
* r=0: 垂足=A
* r=1: 垂足=B
* r<0: 垂足在线段AB的反向延长线上
* r>1: 垂足在线段AB的正向延长线上
* 0<r<1: 垂足在线段AB中
*/
static inline double pedalFactor(const QPointF &p, const QLineF &l)
{
QLineF tl(l.p1(), p);
return dotMultiply(tl.p2(),l.p2(),l.p1())/(point2pointDist(l.p1(),l.p2())*point2pointDist(l.p1(),l.p2()));
}
/* 计算点到线段的垂足 */
static inline QPointF pedalPoint(const QPointF &p, const QLineF &l)
{
double r = pedalFactor(p, l);
return QPointF(l.p1().x()+r*(l.p2().x()-l.p1().x()), l.p1().y()+r*(l.p2().y()-l.p1().y()));
}
/* 计算点到线段的最近距离和点 */
static inline double point2lineDist(const QPointF &p, const QLineF &l, QPointF &np)
{
double r=pedalFactor(p, l);
if(r<0) np = l.p1();
else if(r>1) np = l.p2();
else np = pedalPoint(p, l);
return point2pointDist(p, np);
}
/* 计算点到多段线的最近距离和点 */
static inline double point2polylineDist(const QPointF &p, const QPolygonF &polyline, QPointF &np)
{
double dist = 9999999;
double tmpdist;
QLineF line;
QPointF tnp;
for (int i = 0; i < polyline.count() -1; ++i) {
line.setP1(polyline.at(i));
line.setP2(polyline.at(i+1));
tmpdist = point2lineDist(p, line, tnp);
if (tmpdist < dist) {
dist = tmpdist;
np = tnp;
}
}
return dist;
}
};
TITAN_END_NAMESPACE
#endif // TITAN_PCBCAM_MATH_H
#include "matrixlayer.h"
TITAN_BEGIN_NAMESPACE
class PcbCamMatrixLayerData : public QSharedData
{
public:
PcbCamMatrixLayerData() { }
PcbCamMatrixLayerData(const PcbCamMatrixLayerData &other): QSharedData(other),
id(other.id),
row(other.row),
context(other.context),
type(other.type),
name(other.name),
oldName(other.oldName),
polarity(other.polarity),
startName(other.startName),
endName(other.endName){ }
~PcbCamMatrixLayerData() { }
int id {0};
int row {0};
PcbCam::LayerContext context {PcbCam::MiscContext};
QString type {"signal"};
QString name ;
QString oldName;
PcbCam::Polarity polarity {PcbCam::Positive};
QString startName;
QString endName;
};
PcbCamMatrixLayer::PcbCamMatrixLayer() : d(new PcbCamMatrixLayerData)
{
}
PcbCamMatrixLayer::PcbCamMatrixLayer(const PcbCamMatrixLayer &rhs) : d(rhs.d)
{
}
PcbCamMatrixLayer &PcbCamMatrixLayer::operator=(const PcbCamMatrixLayer &rhs)
{
if (this != &rhs)
d.operator=(rhs.d);
return *this;
}
PcbCamMatrixLayer::~PcbCamMatrixLayer()
{
}
int PcbCamMatrixLayer::id() const
{
return d->id;
}
void PcbCamMatrixLayer::setId(int iId)
{
d->id = iId;
}
int PcbCamMatrixLayer::row() const
{
return d->row;
}
void PcbCamMatrixLayer::setRow(int iRow)
{
d->row = iRow;
}
PcbCam::LayerContext PcbCamMatrixLayer::context() const
{
return d->context;
}
void PcbCamMatrixLayer::setContext(PcbCam::LayerContext iContext)
{
d->context = iContext;
}
QString PcbCamMatrixLayer::type() const
{
return d->type;
}
void PcbCamMatrixLayer::setType(const QString &iType)
{
d->type = iType;
}
QString PcbCamMatrixLayer::name() const
{
return d->name;
}
void PcbCamMatrixLayer::setName(const QString &iName)
{
d->name = iName;
}
QString PcbCamMatrixLayer::oldName() const
{
return d->oldName;
}
void PcbCamMatrixLayer::setOldName(const QString &iOldName)
{
d->oldName = iOldName;
}
PcbCam::Polarity PcbCamMatrixLayer::polarity() const
{
return d->polarity;
}
void PcbCamMatrixLayer::setPolarity(PcbCam::Polarity iPolarity)
{
d->polarity = iPolarity;
}
QString PcbCamMatrixLayer::startName() const
{
return d->startName;
}
void PcbCamMatrixLayer::setStartName(const QString iName)
{
d->startName = iName;
}
QString PcbCamMatrixLayer::endName() const
{
return d->endName;
}
void PcbCamMatrixLayer::setEndName(const QString &iName)
{
d->endName = iName;
}
TITAN_END_NAMESPACE
#ifndef TITAN_PCBCAM_MATRIXLAYER_H
#define TITAN_PCBCAM_MATRIXLAYER_H
#include "../titanpcbcamglobal.h"
#include <QSharedDataPointer>
#include "./common.h"
TITAN_BEGIN_NAMESPACE
class PcbCamMatrixLayerData;
class TITAN_PCBCAM_EXPORT PcbCamMatrixLayer
{
public:
PcbCamMatrixLayer();
PcbCamMatrixLayer(const PcbCamMatrixLayer &);
PcbCamMatrixLayer &operator=(const PcbCamMatrixLayer &);
~PcbCamMatrixLayer();
int id() const;
void setId(int iId);
int row() const;
void setRow(int iRow);
PcbCam::LayerContext context() const;
void setContext(PcbCam::LayerContext iContext);
QString type() const;
void setType(const QString &iType);
QString name() const;
void setName(const QString &iName);
QString oldName() const;
void setOldName(const QString &iOldName);
PcbCam::Polarity polarity() const;
void setPolarity(PcbCam::Polarity iPolarity);
QString startName() const;
void setStartName(const QString iName);
QString endName() const;
void setEndName(const QString &iName);
private:
QSharedDataPointer<PcbCamMatrixLayerData> d;
};
TITAN_END_NAMESPACE
#endif // TITAN_PCBCAM_MATRIXLAYER_H
#include "step.h"
#include <QDebug>
TITAN_BEGIN_NAMESPACE
class PcbCamStepData : public QSharedData
{
public:
PcbCamStepData() { }
PcbCamStepData(const PcbCamStepData &other): QSharedData(other),
stepName(other.stepName),
stepAttrMap(other.stepAttrMap),
origin(other.origin),
datum(other.datum),
repeats(other.repeats),
activeMargin(other.activeMargin),
profile(other.profile),
edaPackageSymbols(other.edaPackageSymbols) { }
~PcbCamStepData() {
qDeleteAll(edaPackageSymbols);
}
//Step名称
QString stepName;
//Step属性
QVariantMap stepAttrMap;
//原点
QPointF origin;
//datum点
QPointF datum;
//Step Repeat
QList<PcbCamStepRepeat> repeats;
//Active Margin;
QMarginsF activeMargin;
//Profile
QPainterPath profile;
//EDA Package Symbols;
QList<PcbCamSymbolUser*> edaPackageSymbols;
};
PcbCamStep::PcbCamStep() : d(new PcbCamStepData)
{
}
PcbCamStep::PcbCamStep(const PcbCamStep &rhs) : d(rhs.d)
{
}
PcbCamStep &PcbCamStep::operator=(const PcbCamStep &rhs)
{
if (this != &rhs)
d.operator=(rhs.d);
return *this;
}
PcbCamStep::~PcbCamStep()
{
}
QString PcbCamStep::name() const
{
return d->stepName;
}
void PcbCamStep::setName(const QString &iName)
{
d->stepName = iName.toLower();
}
QVariant PcbCamStep::attr(const QString &iName) const
{
return d->stepAttrMap.value(iName.toLower());
}
bool PcbCamStep::hasAttr(const QString &iName) const
{
return d->stepAttrMap.contains(iName.toLower());
}
void PcbCamStep::initAttr(const QVariantMap &iAttrMap)
{
d->stepAttrMap = iAttrMap;
}
void PcbCamStep::setAttr(const QString &iName, const QVariant &iValue)
{
d->stepAttrMap.insert(iName.toLower(), iValue);
}
QPointF PcbCamStep::origin() const
{
return d->origin;
}
void PcbCamStep::setOrigin(const QPointF &iOrigin)
{
d->origin = iOrigin;
}
QPointF PcbCamStep::datum() const
{
return d->datum;
}
void PcbCamStep::setDatum(const QPointF &iDatum)
{
d->datum = iDatum;
}
QMarginsF PcbCamStep::activeMargin() const
{
return d->activeMargin;
}
void PcbCamStep::setActiveMargin(const QMarginsF &iMargin)
{
d->activeMargin = iMargin;
}
QPainterPath PcbCamStep::profile() const
{
return d->profile;
}
void PcbCamStep::setProfile(const QPainterPath &iProfile)
{
d->profile = iProfile;
}
QList<PcbCamStepRepeat> PcbCamStep::repeats() const
{
return d->repeats;
}
PcbCamStepRepeat PcbCamStep::repeat(int iIndex) const
{
return d->repeats.value(iIndex);
}
void PcbCamStep::addRepeat(const PcbCamStepRepeat &iRepeat)
{
d->repeats.append(iRepeat);
}
void PcbCamStep::clearRepeats()
{
d->repeats.clear();
}
QList<PcbCamStepRepeat> PcbCamStep::getBreakedRepeats() const
{
QList<PcbCamStepRepeat> res;
for (const PcbCamStepRepeat &sr : d->repeats) {
for (uint i = 0; i < sr.nx(); i++) {
for (uint j = 0; j < sr.ny(); j++) {
PcbCamStepRepeat rpt;
rpt.setId(sr.id());
rpt.setStep(sr.step());
rpt.setX(sr.x() + sr.dx() * i);
rpt.setY(sr.y() + sr.dy() * j);
rpt.setDx(0.0);
rpt.setDy(0.0);
rpt.setNx(1);
rpt.setNy(1);
rpt.setAngle(sr.angle());
rpt.setMirror(sr.mirror());
rpt.setSelected(sr.isSelected());
res.append(rpt);
}
}
}
return res;
}
void PcbCamStep::setEdaPackageSymbols(const QList<PcbCamSymbolUser *> iPkgSymbols)
{
d->edaPackageSymbols = iPkgSymbols;
}
QList<PcbCamSymbolUser *> PcbCamStep::edaPackageSymbols() const
{
return d->edaPackageSymbols;
}
TITAN_END_NAMESPACE
#ifndef TITAN_PCBCAM_STEP_H
#define TITAN_PCBCAM_STEP_H
#include "../titanpcbcamglobal.h"
#include <QSharedDataPointer>
#include <QString>
#include <QVariantMap>
#include <QPointF>
#include <QMarginsF>
#include <QPainterPath>
#include "./steprepeat.h"
#include "./symbol.h"
TITAN_BEGIN_NAMESPACE
class PcbCamStepData;
class TITAN_PCBCAM_EXPORT PcbCamStep
{
public:
PcbCamStep();
PcbCamStep(const PcbCamStep &);
PcbCamStep &operator=(const PcbCamStep &);
~PcbCamStep();
QString name() const;
void setName(const QString &iName);
QVariant attr(const QString &iName) const;
bool hasAttr(const QString &iName) const;
void initAttr(const QVariantMap &iAttrMap);
void setAttr(const QString &iName, const QVariant &iValue);
QPointF origin() const;
void setOrigin(const QPointF &iOrigin);
QPointF datum() const;
void setDatum(const QPointF &iDatum);
QMarginsF activeMargin() const;
void setActiveMargin(const QMarginsF &iMargin);
QPainterPath profile() const;
void setProfile(const QPainterPath &iProfile);
QList<PcbCamStepRepeat> repeats() const;
PcbCamStepRepeat repeat(int iIndex) const;
void addRepeat(const PcbCamStepRepeat &iRepeat);
void clearRepeats();
QList<PcbCamStepRepeat> getBreakedRepeats() const;
void setEdaPackageSymbols(const QList<PcbCamSymbolUser *> iPkgSymbols);
QList<PcbCamSymbolUser *> edaPackageSymbols() const;
private:
QSharedDataPointer<PcbCamStepData> d;
};
TITAN_END_NAMESPACE
#endif // TITAN_PCBCAM_STEP_H
#include "steprepeat.h"
TITAN_BEGIN_NAMESPACE
class PcbCamStepRepeatData : public QSharedData
{
public:
PcbCamStepRepeatData() { }
PcbCamStepRepeatData(const PcbCamStepRepeatData &other): QSharedData(other),
id(other.id),
step(other.step),
x(other.x),
y(other.y),
dx(other.dx),
dy(other.dy),
nx(other.nx),
ny(other.ny),
angle(other.angle),
mirror(other.mirror),
selected(other.selected){ }
~PcbCamStepRepeatData() { }
QString id;
QString step;
qreal x {0.0};
qreal y {0.0};
qreal dx {0.0};
qreal dy {0.0};
uint nx {1};
uint ny {1};
qreal angle {0};
bool mirror {false};
bool selected {false};
};
PcbCamStepRepeat::PcbCamStepRepeat() : d(new PcbCamStepRepeatData)
{
}
PcbCamStepRepeat::PcbCamStepRepeat(const PcbCamStepRepeat &rhs) : d(rhs.d)
{
}
PcbCamStepRepeat &PcbCamStepRepeat::operator=(const PcbCamStepRepeat &rhs)
{
if (this != &rhs)
d.operator=(rhs.d);
return *this;
}
PcbCamStepRepeat::~PcbCamStepRepeat()
{
}
QString PcbCamStepRepeat::id() const
{
return d->id;
}
void PcbCamStepRepeat::setId(const QString &iId)
{
d->id = iId;
}
QString PcbCamStepRepeat::step() const
{
return d->step;
}
void PcbCamStepRepeat::setStep(const QString &iStep)
{
d->step = iStep;
}
qreal PcbCamStepRepeat::x() const
{
return d->x;
}
void PcbCamStepRepeat::setX(qreal iX)
{
d->x = iX;
}
qreal PcbCamStepRepeat::y() const
{
return d->y;
}
void PcbCamStepRepeat::setY(qreal iY)
{
d->y = iY;
}
qreal PcbCamStepRepeat::dx() const
{
return d->dx;
}
void PcbCamStepRepeat::setDx(qreal iDx)
{
d->dx = iDx;
}
qreal PcbCamStepRepeat::dy() const
{
return d->dy;
}
void PcbCamStepRepeat::setDy(qreal iDy)
{
d->dy = iDy;
}
uint PcbCamStepRepeat::nx() const
{
return d->nx;
}
void PcbCamStepRepeat::setNx(uint iNx)
{
d->nx = iNx;
}
uint PcbCamStepRepeat::ny() const
{
return d->ny;
}
void PcbCamStepRepeat::setNy(uint iNy)
{
d->ny = iNy;
}
qreal PcbCamStepRepeat::angle() const
{
return d->angle;
}
void PcbCamStepRepeat::setAngle(qreal iAngle)
{
d->angle = iAngle;
}
bool PcbCamStepRepeat::mirror() const
{
return d->mirror;
}
void PcbCamStepRepeat::setMirror(bool iMirror)
{
d->mirror = iMirror;
}
bool PcbCamStepRepeat::isSelected() const
{
return d->selected;
}
void PcbCamStepRepeat::setSelected(bool iSelected)
{
d->selected = iSelected;
}
TITAN_END_NAMESPACE
#ifndef TITAN_PCBCAM_STEPREPEAT_H
#define TITAN_PCBCAM_STEPREPEAT_H
#include "../titanpcbcamglobal.h"
#include <QSharedDataPointer>
TITAN_BEGIN_NAMESPACE
class PcbCamStepRepeatData;
class TITAN_PCBCAM_EXPORT PcbCamStepRepeat
{
public:
PcbCamStepRepeat();
PcbCamStepRepeat(const PcbCamStepRepeat &);
PcbCamStepRepeat &operator=(const PcbCamStepRepeat &);
~PcbCamStepRepeat();
QString id() const;
void setId(const QString &iId);
QString step() const;
void setStep(const QString &iStep);
qreal x() const;
void setX(qreal iX);
qreal y() const;
void setY(qreal iY);
qreal dx() const;
void setDx(qreal iDx);
qreal dy() const;
void setDy(qreal iDy);
uint nx() const;
void setNx(uint iNx);
uint ny() const;
void setNy(uint iNy);
qreal angle() const;
void setAngle(qreal iAngle);
bool mirror() const;
void setMirror(bool iMirror);
bool isSelected() const;
void setSelected(bool iSelected);
private:
QSharedDataPointer<PcbCamStepRepeatData> d;
};
TITAN_END_NAMESPACE
#endif // TITAN_PCBCAM_STEPREPEAT_H
#include "symbol.h"
#include <QDebug>
#include <QtMath>
#include <QTransform>
TITAN_BEGIN_NAMESPACE
class PcbCamSymbolPrivate
{
Q_DECLARE_PUBLIC(PcbCamSymbol)
public:
PcbCamSymbolPrivate() { }
virtual ~PcbCamSymbolPrivate() { }
QString name;
PcbCam::SymbolType type {PcbCam::Sym_User};
mutable QPainterPath shape;
mutable QRectF boundingRect;
public:
PcbCamSymbol *q_ptr {nullptr};
};
PcbCamSymbol::PcbCamSymbol()
: d_ptr(new PcbCamSymbolPrivate)
{
d_ptr->q_ptr = this;
}
PcbCamSymbol::~PcbCamSymbol()
{
}
QString PcbCamSymbol::name() const
{
Q_D(const PcbCamSymbol);
return d->name;
}
QRectF PcbCamSymbol::boundingRect() const
{
Q_D(const PcbCamSymbol);
if (d->boundingRect.isEmpty()) {
d->boundingRect = shape().controlPointRect();
}
return d->boundingRect;
}
PcbCam::SymbolType PcbCamSymbol::type() const
{
Q_D(const PcbCamSymbol);
return d->type;
}
PcbCamSymbol::PcbCamSymbol(PcbCamSymbolPrivate &dd)
: d_ptr(&dd)
{
d_ptr->q_ptr = this;
}
/********************* r10 *****************/
class PcbCamSymbolRPrivate : public PcbCamSymbolPrivate
{
Q_DECLARE_PUBLIC(PcbCamSymbolR)
public:
PcbCamSymbolRPrivate() : PcbCamSymbolPrivate() { }
~PcbCamSymbolRPrivate() { }
qreal size {0.0};
};
PcbCamSymbolR::PcbCamSymbolR(const QString iName)
: PcbCamSymbol(*new PcbCamSymbolRPrivate)
{
Q_D(PcbCamSymbolR);
d->type = PcbCam::Sym_R;
d->name = iName;
QRegularExpression re("^r([0-9.]+)$");
d->size = re.match(d->name).captured(1).toDouble()/1000.0;
}
PcbCamSymbolR::~PcbCamSymbolR()
{
}
QPainterPath PcbCamSymbolR::shape() const
{
Q_D(const PcbCamSymbolR);
if (d->shape.isEmpty()) {
d->shape.addEllipse(QRectF(-d->size/2.0, -d->size/2.0, d->size, d->size));
}
return d->shape;
}
qreal PcbCamSymbolR::size() const
{
Q_D(const PcbCamSymbolR);
return d->size;
}
/********************* s10 *****************/
class PcbCamSymbolSPrivate : public PcbCamSymbolPrivate
{
Q_DECLARE_PUBLIC(PcbCamSymbolS)
public:
PcbCamSymbolSPrivate() : PcbCamSymbolPrivate() { }
~PcbCamSymbolSPrivate() { }
qreal size {0.0};
};
PcbCamSymbolS::PcbCamSymbolS(const QString iName)
: PcbCamSymbol(*new PcbCamSymbolSPrivate)
{
Q_D(PcbCamSymbolS);
d->type = PcbCam::Sym_S;
d->name = iName;
QRegularExpression re("^s([0-9.]+)$");
d->size = re.match(d->name).captured(1).toDouble()/1000.0;
}
PcbCamSymbolS::~PcbCamSymbolS()
{
}
QPainterPath PcbCamSymbolS::shape() const
{
Q_D(const PcbCamSymbolS);
if (d->shape.isEmpty()) {
d->shape.addRect(QRectF(-d->size/2.0, -d->size/2.0, d->size, d->size));
}
return d->shape;
}
qreal PcbCamSymbolS::size() const
{
Q_D(const PcbCamSymbolS);
return d->size;
}
/********************* rect10x20 *****************/
class PcbCamSymbolRectPrivate : public PcbCamSymbolPrivate
{
Q_DECLARE_PUBLIC(PcbCamSymbolRect)
public:
PcbCamSymbolRectPrivate() : PcbCamSymbolPrivate() { }
~PcbCamSymbolRectPrivate() { }
QSizeF size ;
};
PcbCamSymbolRect::PcbCamSymbolRect(const QString iName)
: PcbCamSymbol(*new PcbCamSymbolRectPrivate)
{
Q_D(PcbCamSymbolRect);
d->type = PcbCam::Sym_Rect;
d->name = iName;
QRegularExpression re("^rect([0-9.]+)x([0-9.]+)$");
QRegularExpressionMatch match = re.match(d->name);
d->size = QSizeF(match.captured(1).toDouble()/1000.0, match.captured(2).toDouble()/1000.0);
}
PcbCamSymbolRect::~PcbCamSymbolRect()
{
}
QPainterPath PcbCamSymbolRect::shape() const
{
Q_D(const PcbCamSymbolRect);
if (d->shape.isEmpty()) {
d->shape.addRect(QRectF(-d->size.width()/2.0, -d->size.height()/2.0, d->size.width(), d->size.height()));
}
return d->shape;
}
QSizeF PcbCamSymbolRect::size() const
{
Q_D(const PcbCamSymbolRect);
return d->size;
}
/********************* rect60x30xr5x13 *****************/
class PcbCamSymbolRectRPrivate : public PcbCamSymbolPrivate
{
Q_DECLARE_PUBLIC(PcbCamSymbolRectR)
public:
PcbCamSymbolRectRPrivate() : PcbCamSymbolPrivate() { }
~PcbCamSymbolRectRPrivate() { }
qreal width {0.0} ;
qreal height {0.0} ;
qreal radius {0.0};
QString corners {""};
};
PcbCamSymbolRectR::PcbCamSymbolRectR(const QString iName)
: PcbCamSymbol(*new PcbCamSymbolRectRPrivate)
{
Q_D(PcbCamSymbolRectR);
d->type = PcbCam::Sym_RectR;
d->name = iName;
QRegularExpression re("^rect([0-9.]+)x([0-9.]+)xr([0-9.]+)(?:x([1-4]+))?$");
QRegularExpressionMatch match = re.match(d->name);
d->width = match.captured(1).toDouble()/1000.0;
d->height = match.captured(2).toDouble()/1000.0;
d->radius = match.captured(3).toDouble()/1000.0;
d->corners = match.captured(4);
}
PcbCamSymbolRectR::~PcbCamSymbolRectR()
{
}
QPainterPath PcbCamSymbolRectR::shape() const
{
Q_D(const PcbCamSymbolRectR);
if (d->shape.isEmpty()) {
QRectF rect(-d->width/2.0, -d->height/2.0, d->width, d->height);
QRectF r = rect.normalized();
qreal x = r.x();
qreal y = r.y();
qreal w = r.width();
qreal h = r.height();
QString cor = d->corners;
if (cor.isEmpty()) cor = "1234";
if (cor.contains('3')) {
d->shape.arcMoveTo(x, y, d->radius*2.0, d->radius*2.0, 180);
d->shape.arcTo(x, y, d->radius*2.0, d->radius*2.0, 180, -90);
}
else {
d->shape.moveTo(x, y);
d->shape.lineTo(x + w - d->radius, y);
}
if (cor.contains('4')) {
d->shape.arcTo(x + w - d->radius*2.0, y, d->radius*2.0 , d->radius*2.0, 90, -90);
}
else {
d->shape.lineTo(x + w, y);
d->shape.lineTo(x + w, y + h - d->radius);
}
if (cor.contains('1')) {
d->shape.arcTo(x + w - d->radius*2.0, y + h - d->radius*2.0, d->radius*2.0, d->radius*2.0, 0, -90);
}
else {
d->shape.lineTo(x + w, y + h);
d->shape.lineTo(x + d->radius, y + h);
}
if (cor.contains('2')) {
d->shape.arcTo(x, y + h - d->radius*2.0, d->radius*2.0, d->radius*2.0, 270, -90);
}
else {
d->shape.lineTo(x, y + h);
}
d->shape.closeSubpath();
}
return d->shape;
}
qreal PcbCamSymbolRectR::width() const
{
Q_D(const PcbCamSymbolRectR);
return d->width;
}
qreal PcbCamSymbolRectR::height() const
{
Q_D(const PcbCamSymbolRectR);
return d->height;
}
qreal PcbCamSymbolRectR::radius() const
{
Q_D(const PcbCamSymbolRectR);
return d->radius;
}
QString PcbCamSymbolRectR::corners() const
{
Q_D(const PcbCamSymbolRectR);
return d->corners;
}
/********************* rect60x30xc5x13 *****************/
class PcbCamSymbolRectCPrivate : public PcbCamSymbolPrivate
{
Q_DECLARE_PUBLIC(PcbCamSymbolRectC)
public:
PcbCamSymbolRectCPrivate() : PcbCamSymbolPrivate() { }
~PcbCamSymbolRectCPrivate() { }
qreal width {0.0} ;
qreal height {0.0} ;
qreal radius {0.0};
QString corners {""};
};
PcbCamSymbolRectC::PcbCamSymbolRectC(const QString iName)
: PcbCamSymbol(*new PcbCamSymbolRectCPrivate)
{
Q_D(PcbCamSymbolRectC);
d->type = PcbCam::Sym_RectC;
d->name = iName;
QRegularExpression re("^rect([0-9.]+)x([0-9.]+)xc([0-9.]+)(?:x([1-4]+))?$");
QRegularExpressionMatch match = re.match(d->name);
d->width = match.captured(1).toDouble()/1000.0;
d->height = match.captured(2).toDouble()/1000.0;
d->radius = match.captured(3).toDouble()/1000.0;
d->corners = match.captured(4);
}
PcbCamSymbolRectC::~PcbCamSymbolRectC()
{
}
QPainterPath PcbCamSymbolRectC::shape() const
{
Q_D(const PcbCamSymbolRectC);
if (d->shape.isEmpty()) {
QRectF rect(-d->width/2.0, -d->height/2.0, d->width, d->height);
QRectF r = rect.normalized();
qreal x = r.x();
qreal y = r.y();
qreal w = r.width();
qreal h = r.height();
QString cor = d->corners;
if (cor.isEmpty()) cor = "1234";
if (cor.contains('3')) {
d->shape.moveTo(x, y + d->radius);
d->shape.lineTo(x + d->radius, y);
d->shape.lineTo(x + w - d->radius, y);
}
else {
d->shape.moveTo(x, y);
d->shape.lineTo(x + w - d->radius, y);
}
if (cor.contains('4')) {
d->shape.lineTo(x + w, y + d->radius);
d->shape.lineTo(x + w, y + h - d->radius);
}
else {
d->shape.lineTo(x + w, y);
d->shape.lineTo(x + w, y + h - d->radius);
}
if (cor.contains('1')) {
d->shape.lineTo(x + w - d->radius, y + h);
d->shape.lineTo(x + d->radius, y + h);
}
else {
d->shape.lineTo(x + w, y + h);
d->shape.lineTo(x + d->radius, y + h);
}
if (cor.contains('2')) {
d->shape.lineTo(x, y + h - d->radius);
}
else {
d->shape.lineTo(x, y + h);
}
d->shape.closeSubpath();
}
return d->shape;
}
qreal PcbCamSymbolRectC::width() const
{
Q_D(const PcbCamSymbolRectC);
return d->width;
}
qreal PcbCamSymbolRectC::height() const
{
Q_D(const PcbCamSymbolRectC);
return d->height;
}
qreal PcbCamSymbolRectC::radius() const
{
Q_D(const PcbCamSymbolRectC);
return d->radius;
}
QString PcbCamSymbolRectC::corners() const
{
Q_D(const PcbCamSymbolRectC);
return d->corners;
}
/********************* oval100x50 *****************/
class PcbCamSymbolOvalPrivate : public PcbCamSymbolPrivate
{
Q_DECLARE_PUBLIC(PcbCamSymbolOval)
public:
PcbCamSymbolOvalPrivate() : PcbCamSymbolPrivate() { }
~PcbCamSymbolOvalPrivate() { }
QSizeF size ;
};
PcbCamSymbolOval::PcbCamSymbolOval(const QString iName)
: PcbCamSymbol(*new PcbCamSymbolOvalPrivate)
{
Q_D(PcbCamSymbolOval);
d->type = PcbCam::Sym_Oval;
d->name = iName;
QRegularExpression re("^oval([0-9.]+)x([0-9.]+)$");
QRegularExpressionMatch match = re.match(d->name);
d->size = QSizeF(match.captured(1).toDouble()/1000.0, match.captured(2).toDouble()/1000.0);
}
PcbCamSymbolOval::~PcbCamSymbolOval()
{
}
QPainterPath PcbCamSymbolOval::shape() const
{
Q_D(const PcbCamSymbolOval);
if (d->shape.isEmpty()) {
qreal w = d->size.width();
qreal h = d->size.height();
if (w > h) {
qreal rad = h / 2.0;
d->shape.moveTo(-w/2.0 + rad, -h/2.0);
d->shape.lineTo(w/2.0 - rad, -h/2.0);
d->shape.arcTo(w/2.0 -rad*2.0, -h/2.0, h, h, 90, -180);
d->shape.lineTo(-w/2.0 + rad, h/2.0);
d->shape.arcTo(-w/2.0, -h/2.0, h, h, -90, -180);
d->shape.closeSubpath();
}
else {
qreal rad = w/2.0;
d->shape.moveTo(w/2.0, -h/2.0 + rad);
d->shape.lineTo(w/2.0, h/2.0 - rad);
d->shape.arcTo(-w/2.0, h/2.0 - rad*2.0, w, w, 0, -180);
d->shape.lineTo(-w/2.0,-h/2.0 + rad);
d->shape.arcTo(-w/2.0, -h/2.0, w, w, 180, -180);
d->shape.closeSubpath();
}
}
return d->shape;
}
QSizeF PcbCamSymbolOval::size() const
{
Q_D(const PcbCamSymbolOval);
return d->size;
}
/********************* di100x50 *****************/
class PcbCamSymbolDiPrivate : public PcbCamSymbolPrivate
{
Q_DECLARE_PUBLIC(PcbCamSymbolDi)
public:
PcbCamSymbolDiPrivate() : PcbCamSymbolPrivate() { }
~PcbCamSymbolDiPrivate() { }
QSizeF size ;
};
PcbCamSymbolDi::PcbCamSymbolDi(const QString iName)
: PcbCamSymbol(*new PcbCamSymbolDiPrivate)
{
Q_D(PcbCamSymbolDi);
d->type = PcbCam::Sym_Di;
d->name = iName;
QRegularExpression re("^di([0-9.]+)x([0-9.]+)$");
QRegularExpressionMatch match = re.match(d->name);
d->size = QSizeF(match.captured(1).toDouble()/1000.0, match.captured(2).toDouble()/1000.0);
}
PcbCamSymbolDi::~PcbCamSymbolDi()
{
}
QPainterPath PcbCamSymbolDi::shape() const
{
Q_D(const PcbCamSymbolDi);
if (d->shape.isEmpty()) {
qreal w = d->size.width();
qreal h = d->size.height();
qreal x = -w/2.0;
qreal y = -h/2.0;
qreal wh = w/2.0;
qreal hh = h/2.0;
d->shape.moveTo(x, y+hh);
d->shape.lineTo(x+wh, y);
d->shape.lineTo(x+w, y + hh);
d->shape.lineTo(x + wh, y + h);
d->shape.closeSubpath();
}
return d->shape;
}
QSizeF PcbCamSymbolDi::size() const
{
Q_D(const PcbCamSymbolDi);
return d->size;
}
/********************* oct100x50x20 *****************/
class PcbCamSymbolOctPrivate : public PcbCamSymbolPrivate
{
Q_DECLARE_PUBLIC(PcbCamSymbolOct)
public:
PcbCamSymbolOctPrivate() : PcbCamSymbolPrivate() { }
~PcbCamSymbolOctPrivate() { }
qreal width {0.0} ;
qreal height {0.0} ;
qreal radius {0.0};
};
PcbCamSymbolOct::PcbCamSymbolOct(const QString iName)
: PcbCamSymbol(*new PcbCamSymbolOctPrivate)
{
Q_D(PcbCamSymbolOct);
d->type = PcbCam::Sym_Oct;
d->name = iName;
QRegularExpression re("^oct([0-9.]+)x([0-9.]+)x([0-9.]+)$");
QRegularExpressionMatch match = re.match(d->name);
d->width = match.captured(1).toDouble()/1000.0;
d->height = match.captured(2).toDouble()/1000.0;
d->radius = match.captured(3).toDouble()/1000.0;
}
PcbCamSymbolOct::~PcbCamSymbolOct()
{
}
QPainterPath PcbCamSymbolOct::shape() const
{
Q_D(const PcbCamSymbolOct);
if (d->shape.isEmpty()) {
qreal x = -d->width/2.0;
qreal y = -d->height/2.0;
d->shape.moveTo(x, y + d->height - d->radius);
d->shape.lineTo(x, y + d->radius);
d->shape.lineTo(x + d->radius, y);
d->shape.lineTo(x + d->width - d->radius, y);
d->shape.lineTo(x + d->width, y + d->radius);
d->shape.lineTo(x + d->width, y + d->height - d->radius);
d->shape.lineTo(x + d->width - d->radius, y + d->height);
d->shape.lineTo(x + d->radius, y + d->height);
d->shape.closeSubpath();
}
return d->shape;
}
qreal PcbCamSymbolOct::width() const
{
Q_D(const PcbCamSymbolOct);
return d->width;
}
qreal PcbCamSymbolOct::height() const
{
Q_D(const PcbCamSymbolOct);
return d->height;
}
qreal PcbCamSymbolOct::radius() const
{
Q_D(const PcbCamSymbolOct);
return d->radius;
}
/********************* donut_r100x50 *****************/
class PcbCamSymbolDonutRPrivate : public PcbCamSymbolPrivate
{
Q_DECLARE_PUBLIC(PcbCamSymbolDonutR)
public:
PcbCamSymbolDonutRPrivate() : PcbCamSymbolPrivate() { }
~PcbCamSymbolDonutRPrivate() { }
qreal outerDiam {0.0} ;
qreal innerDiam {0.0} ;
};
PcbCamSymbolDonutR::PcbCamSymbolDonutR(const QString iName)
: PcbCamSymbol(*new PcbCamSymbolDonutRPrivate)
{
Q_D(PcbCamSymbolDonutR);
d->type = PcbCam::Sym_DonutR;
d->name = iName;
QRegularExpression re("^donut_r([0-9.]+)x([0-9.]+)$");
QRegularExpressionMatch match = re.match(d->name);
d->outerDiam = match.captured(1).toDouble()/1000.0;
d->innerDiam = match.captured(2).toDouble()/1000.0;
}
PcbCamSymbolDonutR::~PcbCamSymbolDonutR()
{
}
QPainterPath PcbCamSymbolDonutR::shape() const
{
Q_D(const PcbCamSymbolDonutR);
if (d->shape.isEmpty()) {
d->shape.addEllipse(-d->outerDiam/2.0, -d->outerDiam/2.0, d->outerDiam, d->outerDiam);
d->shape.addEllipse(-d->innerDiam/2.0, -d->innerDiam/2.0, d->innerDiam, d->innerDiam);
}
return d->shape;
}
qreal PcbCamSymbolDonutR::outerDiam() const
{
Q_D(const PcbCamSymbolDonutR);
return d->outerDiam;
}
qreal PcbCamSymbolDonutR::innerDiam() const
{
Q_D(const PcbCamSymbolDonutR);
return d->innerDiam;
}
/********************* donut_s100x50 *****************/
class PcbCamSymbolDonutSPrivate : public PcbCamSymbolPrivate
{
Q_DECLARE_PUBLIC(PcbCamSymbolDonutS)
public:
PcbCamSymbolDonutSPrivate() : PcbCamSymbolPrivate() { }
~PcbCamSymbolDonutSPrivate() { }
qreal outerDiam {0.0} ;
qreal innerDiam {0.0} ;
};
PcbCamSymbolDonutS::PcbCamSymbolDonutS(const QString iName)
: PcbCamSymbol(*new PcbCamSymbolDonutSPrivate)
{
Q_D(PcbCamSymbolDonutS);
d->type = PcbCam::Sym_DonutS;
d->name = iName;
QRegularExpression re("^donut_s([0-9.]+)x([0-9.]+)$");
QRegularExpressionMatch match = re.match(d->name);
d->outerDiam = match.captured(1).toDouble()/1000.0;
d->innerDiam = match.captured(2).toDouble()/1000.0;
}
PcbCamSymbolDonutS::~PcbCamSymbolDonutS()
{
}
QPainterPath PcbCamSymbolDonutS::shape() const
{
Q_D(const PcbCamSymbolDonutS);
if (d->shape.isEmpty()) {
d->shape.addRect(-d->outerDiam/2.0, -d->outerDiam/2.0, d->outerDiam, d->outerDiam);
d->shape.addRect(-d->innerDiam/2.0, -d->innerDiam/2.0, d->innerDiam, d->innerDiam);
}
return d->shape;
}
qreal PcbCamSymbolDonutS::outerDiam() const
{
Q_D(const PcbCamSymbolDonutS);
return d->outerDiam;
}
qreal PcbCamSymbolDonutS::innerDiam() const
{
Q_D(const PcbCamSymbolDonutS);
return d->innerDiam;
}
/********************* hex_l100x50x20 *****************/
class PcbCamSymbolHexLPrivate : public PcbCamSymbolPrivate
{
Q_DECLARE_PUBLIC(PcbCamSymbolHexL)
public:
PcbCamSymbolHexLPrivate() : PcbCamSymbolPrivate() { }
~PcbCamSymbolHexLPrivate() { }
qreal width {0.0} ;
qreal height {0.0} ;
qreal radius {0.0};
};
PcbCamSymbolHexL::PcbCamSymbolHexL(const QString iName)
: PcbCamSymbol(*new PcbCamSymbolHexLPrivate)
{
Q_D(PcbCamSymbolHexL);
d->type = PcbCam::Sym_HexL;
d->name = iName;
QRegularExpression re("^hex_l([0-9.]+)x([0-9.]+)x([0-9.]+)$");
QRegularExpressionMatch match = re.match(d->name);
d->width = match.captured(1).toDouble()/1000.0;
d->height = match.captured(2).toDouble()/1000.0;
d->radius = match.captured(3).toDouble()/1000.0;
}
PcbCamSymbolHexL::~PcbCamSymbolHexL()
{
}
QPainterPath PcbCamSymbolHexL::shape() const
{
Q_D(const PcbCamSymbolHexL);
if (d->shape.isEmpty()) {
d->shape.moveTo(-d->width/2.0 + d->radius, -d->height/2.0);
d->shape.lineTo(-d->width/2.0, 0);
d->shape.lineTo(-d->width/2.0 + d->radius, d->height/2.0);
d->shape.lineTo(d->width/2.0 - d->radius, d->height/2.0);
d->shape.lineTo(d->width/2.0, 0);
d->shape.lineTo(d->width/2.0 - d->radius, -d->height/2.0);
d->shape.closeSubpath();
}
return d->shape;
}
qreal PcbCamSymbolHexL::width() const
{
Q_D(const PcbCamSymbolHexL);
return d->width;
}
qreal PcbCamSymbolHexL::height() const
{
Q_D(const PcbCamSymbolHexL);
return d->height;
}
qreal PcbCamSymbolHexL::radius() const
{
Q_D(const PcbCamSymbolHexL);
return d->radius;
}
/********************* hex_s100x50x20 *****************/
class PcbCamSymbolHexSPrivate : public PcbCamSymbolPrivate
{
Q_DECLARE_PUBLIC(PcbCamSymbolHexS)
public:
PcbCamSymbolHexSPrivate() : PcbCamSymbolPrivate() { }
~PcbCamSymbolHexSPrivate() { }
qreal width {0.0} ;
qreal height {0.0} ;
qreal radius {0.0};
};
PcbCamSymbolHexS::PcbCamSymbolHexS(const QString iName)
: PcbCamSymbol(*new PcbCamSymbolHexSPrivate)
{
Q_D(PcbCamSymbolHexS);
d->type = PcbCam::Sym_HexS;
d->name = iName;
QRegularExpression re("^hex_s([0-9.]+)x([0-9.]+)x([0-9.]+)$");
QRegularExpressionMatch match = re.match(d->name);
d->width = match.captured(1).toDouble()/1000.0;
d->height = match.captured(2).toDouble()/1000.0;
d->radius = match.captured(3).toDouble()/1000.0;
}
PcbCamSymbolHexS::~PcbCamSymbolHexS()
{
}
QPainterPath PcbCamSymbolHexS::shape() const
{
Q_D(const PcbCamSymbolHexS);
if (d->shape.isEmpty()) {
d->shape.moveTo(0, -d->height/2.0);
d->shape.lineTo(-d->width/2.0, -d->height/2.0 + d->radius);
d->shape.lineTo(-d->width/2.0, d->height/2.0 - d->radius);
d->shape.lineTo(0, d->height/2.0);
d->shape.lineTo(d->width/2.0, d->height/2.0 - d->radius);
d->shape.lineTo(d->width/2.0, -d->height/2.0 + d->radius);
d->shape.closeSubpath();
}
return d->shape;
}
qreal PcbCamSymbolHexS::width() const
{
Q_D(const PcbCamSymbolHexS);
return d->width;
}
qreal PcbCamSymbolHexS::height() const
{
Q_D(const PcbCamSymbolHexS);
return d->height;
}
qreal PcbCamSymbolHexS::radius() const
{
Q_D(const PcbCamSymbolHexS);
return d->radius;
}
/********************* bfr10 *****************/
class PcbCamSymbolBfrPrivate : public PcbCamSymbolPrivate
{
Q_DECLARE_PUBLIC(PcbCamSymbolBfr)
public:
PcbCamSymbolBfrPrivate() : PcbCamSymbolPrivate() { }
~PcbCamSymbolBfrPrivate() { }
qreal size {0.0};
};
PcbCamSymbolBfr::PcbCamSymbolBfr(const QString iName)
: PcbCamSymbol(*new PcbCamSymbolBfrPrivate)
{
Q_D(PcbCamSymbolBfr);
d->type = PcbCam::Sym_Bfr;
d->name = iName;
QRegularExpression re("^bfr([0-9.]+)$");
d->size = re.match(d->name).captured(1).toDouble()/1000.0;
}
PcbCamSymbolBfr::~PcbCamSymbolBfr()
{
}
QPainterPath PcbCamSymbolBfr::shape() const
{
Q_D(const PcbCamSymbolBfr);
if (d->shape.isEmpty()) {
d->shape.moveTo(0, 0);
d->shape.arcTo(-d->size/2.0, -d->size/2.0, d->size, d->size, 0, 90);
d->shape.closeSubpath();
d->shape.moveTo(0, 0);
d->shape.arcTo(-d->size/2.0, -d->size/2.0, d->size, d->size, -90, -90);
d->shape.closeSubpath();
}
return d->shape;
}
qreal PcbCamSymbolBfr::size() const
{
Q_D(const PcbCamSymbolBfr);
return d->size;
}
/********************* bfs10 *****************/
class PcbCamSymbolBfsPrivate : public PcbCamSymbolPrivate
{
Q_DECLARE_PUBLIC(PcbCamSymbolBfs)
public:
PcbCamSymbolBfsPrivate() : PcbCamSymbolPrivate() { }
~PcbCamSymbolBfsPrivate() { }
qreal size {0.0};
};
PcbCamSymbolBfs::PcbCamSymbolBfs(const QString iName)
: PcbCamSymbol(*new PcbCamSymbolBfsPrivate)
{
Q_D(PcbCamSymbolBfs);
d->type = PcbCam::Sym_Bfs;
d->name = iName;
QRegularExpression re("^bfs([0-9.]+)$");
d->size = re.match(d->name).captured(1).toDouble()/1000.0;
}
PcbCamSymbolBfs::~PcbCamSymbolBfs()
{
}
QPainterPath PcbCamSymbolBfs::shape() const
{
Q_D(const PcbCamSymbolBfs);
if (d->shape.isEmpty()) {
d->shape.addRect(0, -d->size/2.0, d->size/2.0, d->size/2.0);
d->shape.addRect(-d->size/2.0, 0, d->size/2.0, d->size/2.0);
}
return d->shape;
}
qreal PcbCamSymbolBfs::size() const
{
Q_D(const PcbCamSymbolBfs);
return d->size;
}
/********************* tri10x20 *****************/
class PcbCamSymbolTriPrivate : public PcbCamSymbolPrivate
{
Q_DECLARE_PUBLIC(PcbCamSymbolTri)
public:
PcbCamSymbolTriPrivate() : PcbCamSymbolPrivate() { }
~PcbCamSymbolTriPrivate() { }
QSizeF size ;
};
PcbCamSymbolTri::PcbCamSymbolTri(const QString iName)
: PcbCamSymbol(*new PcbCamSymbolTriPrivate)
{
Q_D(PcbCamSymbolTri);
d->type = PcbCam::Sym_Tri;
d->name = iName;
QRegularExpression re("^tri([0-9.]+)x([0-9.]+)$");
QRegularExpressionMatch match = re.match(d->name);
d->size = QSizeF(match.captured(1).toDouble()/1000.0, match.captured(2).toDouble()/1000.0);
}
PcbCamSymbolTri::~PcbCamSymbolTri()
{
}
QPainterPath PcbCamSymbolTri::shape() const
{
Q_D(const PcbCamSymbolTri);
if (d->shape.isEmpty()) {
qreal w = d->size.width();
qreal h = d->size.height();
d->shape.moveTo(0, h/2.0);
d->shape.lineTo(-w/2.0, -h/2.0);
d->shape.lineTo(w/2.0, -h/2.0);
d->shape.closeSubpath();
}
return d->shape;
}
QSizeF PcbCamSymbolTri::size() const
{
Q_D(const PcbCamSymbolTri);
return d->size;
}
/********************* orval_h100x20 *****************/
class PcbCamSymbolOvalHPrivate : public PcbCamSymbolPrivate
{
Q_DECLARE_PUBLIC(PcbCamSymbolOvalH)
public:
PcbCamSymbolOvalHPrivate() : PcbCamSymbolPrivate() { }
~PcbCamSymbolOvalHPrivate() { }
QSizeF size ;
};
PcbCamSymbolOvalH::PcbCamSymbolOvalH(const QString iName)
: PcbCamSymbol(*new PcbCamSymbolOvalHPrivate)
{
Q_D(PcbCamSymbolOvalH);
d->type = PcbCam::Sym_OvalH;
d->name = iName;
QRegularExpression re("^oval_h([0-9.]+)x([0-9.]+)$");
QRegularExpressionMatch match = re.match(d->name);
d->size = QSizeF(match.captured(1).toDouble()/1000.0, match.captured(2).toDouble()/1000.0);
}
PcbCamSymbolOvalH::~PcbCamSymbolOvalH()
{
}
QPainterPath PcbCamSymbolOvalH::shape() const
{
Q_D(const PcbCamSymbolOvalH);
if (d->shape.isEmpty()) {
//TODO may have bug
qreal w = d->size.width();
qreal h = d->size.height();
d->shape.moveTo(w/2.0 - h, -h/2.0);
d->shape.arcTo(w/2.0 - h, -h/2.0, h, h, 90, -180);
d->shape.lineTo(-w/2.0, h/2.0);
d->shape.lineTo(-w/2.0, -h/2.0);
d->shape.closeSubpath();
}
return d->shape;
}
QSizeF PcbCamSymbolOvalH::size() const
{
Q_D(const PcbCamSymbolOvalH);
return d->size;
}
/********************* thr100x70x30x5x20 *****************/
class PcbCamSymbolThrPrivate : public PcbCamSymbolPrivate
{
Q_DECLARE_PUBLIC(PcbCamSymbolThr)
public:
PcbCamSymbolThrPrivate() : PcbCamSymbolPrivate() { }
~PcbCamSymbolThrPrivate() { }
qreal outerDiam {0.0} ;
qreal innerDiam {0.0} ;
qreal startAngle {0.0} ;
int numSpokes {1};
qreal spokesGap {0.0};
};
PcbCamSymbolThr::PcbCamSymbolThr(const QString iName)
: PcbCamSymbol(*new PcbCamSymbolThrPrivate)
{
Q_D(PcbCamSymbolThr);
d->type = PcbCam::Sym_Thr;
d->name = iName;
QRegularExpression re("^thr([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9]+)x([0-9.]+)$");
QRegularExpressionMatch match = re.match(d->name);
d->outerDiam = match.captured(1).toDouble()/1000.0;
d->innerDiam = match.captured(2).toDouble()/1000.0;
d->startAngle = match.captured(3).toDouble();
d->numSpokes = match.captured(4).toInt();
d->spokesGap = match.captured(5).toDouble()/1000.0;
}
PcbCamSymbolThr::~PcbCamSymbolThr()
{
}
QPainterPath PcbCamSymbolThr::shape() const
{
Q_D(const PcbCamSymbolThr);
if (d->shape.isEmpty()) {
qreal lineRadius = (d->outerDiam - d->innerDiam) / 4.0;
qreal centerRadius = d->innerDiam/2.0 + lineRadius;
qreal x1 = qSqrt(centerRadius*centerRadius - (lineRadius+d->spokesGap/2.0)*(lineRadius+d->spokesGap/2.0));
QPointF p1 = QPointF(x1, lineRadius+d->spokesGap/2.0);
qreal angle1 = qAtan2(p1.y(), p1.x()) * 180/M_PI;
QPainterPath path0;
path0.arcMoveTo(-centerRadius, -centerRadius, 2*centerRadius, 2*centerRadius, angle1);
path0.arcTo(-centerRadius, -centerRadius, 2*centerRadius, 2*centerRadius, angle1, 360.0/d->numSpokes - 2*angle1);
QPainterPathStroker stroker;
stroker.setWidth(lineRadius*2);
stroker.setJoinStyle(Qt::RoundJoin);
stroker.setCapStyle(Qt::RoundCap);
path0 = stroker.createStroke(path0);
for (int i = 0; i < d->numSpokes; ++i) {
QTransform trans;
trans.rotate(d->startAngle + (360.0 / d->numSpokes) * i);
d->shape.addPath(trans.map(path0));
}
}
return d->shape;
}
qreal PcbCamSymbolThr::outerDiam() const
{
Q_D(const PcbCamSymbolThr);
return d->outerDiam;
}
qreal PcbCamSymbolThr::innerDiam() const
{
Q_D(const PcbCamSymbolThr);
return d->innerDiam;
}
qreal PcbCamSymbolThr::startAngle() const
{
Q_D(const PcbCamSymbolThr);
return d->startAngle;
}
int PcbCamSymbolThr::numSpokes() const
{
Q_D(const PcbCamSymbolThr);
return d->numSpokes;
}
qreal PcbCamSymbolThr::spokesGap() const
{
Q_D(const PcbCamSymbolThr);
return d->spokesGap;
}
/********************* ths100x70x30x5x20 *****************/
class PcbCamSymbolThsPrivate : public PcbCamSymbolPrivate
{
Q_DECLARE_PUBLIC(PcbCamSymbolThs)
public:
PcbCamSymbolThsPrivate() : PcbCamSymbolPrivate() { }
~PcbCamSymbolThsPrivate() { }
qreal outerDiam {0.0} ;
qreal innerDiam {0.0} ;
qreal startAngle {0.0} ;
int numSpokes {1};
qreal spokesGap {0.0};
};
PcbCamSymbolThs::PcbCamSymbolThs(const QString iName)
: PcbCamSymbol(*new PcbCamSymbolThsPrivate)
{
Q_D(PcbCamSymbolThs);
d->type = PcbCam::Sym_Ths;
d->name = iName;
QRegularExpression re("^ths([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9]+)x([0-9.]+)$");
QRegularExpressionMatch match = re.match(d->name);
d->outerDiam = match.captured(1).toDouble()/1000.0;
d->innerDiam = match.captured(2).toDouble()/1000.0;
d->startAngle = match.captured(3).toDouble();
d->numSpokes = match.captured(4).toInt();
d->spokesGap = match.captured(5).toDouble()/1000.0;
}
PcbCamSymbolThs::~PcbCamSymbolThs()
{
}
QPainterPath PcbCamSymbolThs::shape() const
{
Q_D(const PcbCamSymbolThs);
if (d->shape.isEmpty()) {
qreal pie_angle = 360.0/d->numSpokes;
qreal half_inner_gap_angle = (180.0/M_PI) * (qAsin(d->spokesGap/d->innerDiam));
qreal half_outer_gap_angle = (180.0/M_PI) * (qAsin(d->spokesGap/d->outerDiam));
qreal inner_start_angle = d->startAngle + half_inner_gap_angle;
qreal inner_pie_angle = pie_angle - 2 * half_inner_gap_angle;
qreal outer_start_angle = d->startAngle + half_outer_gap_angle;
qreal outer_pie_angle = pie_angle - 2 * half_outer_gap_angle;
for (int i = 0; i < d->numSpokes; ++i) {
d->shape.arcMoveTo(-d->outerDiam/2.0, -d->outerDiam/2.0, d->outerDiam, d->outerDiam, outer_start_angle);
d->shape.arcTo(-d->outerDiam/2.0, -d->outerDiam/2.0, d->outerDiam, d->outerDiam, outer_start_angle, outer_pie_angle);
d->shape.arcTo(-d->innerDiam/2.0, -d->innerDiam/2.0, d->innerDiam, d->innerDiam, inner_start_angle + inner_pie_angle, 0);
d->shape.arcTo(-d->innerDiam/2.0, -d->innerDiam/2.0, d->innerDiam, d->innerDiam, inner_start_angle + inner_pie_angle, -inner_pie_angle);
d->shape.closeSubpath();
inner_start_angle += pie_angle;
outer_start_angle += pie_angle;
}
QTransform trans;
trans.scale(1, -1);
d->shape = trans.map(d->shape);
}
return d->shape;
}
qreal PcbCamSymbolThs::outerDiam() const
{
Q_D(const PcbCamSymbolThs);
return d->outerDiam;
}
qreal PcbCamSymbolThs::innerDiam() const
{
Q_D(const PcbCamSymbolThs);
return d->innerDiam;
}
qreal PcbCamSymbolThs::startAngle() const
{
Q_D(const PcbCamSymbolThs);
return d->startAngle;
}
int PcbCamSymbolThs::numSpokes() const
{
Q_D(const PcbCamSymbolThs);
return d->numSpokes;
}
qreal PcbCamSymbolThs::spokesGap() const
{
Q_D(const PcbCamSymbolThs);
return d->spokesGap;
}
/********************* s_ths100x70x30x5x20 *****************/
class PcbCamSymbolSThsPrivate : public PcbCamSymbolPrivate
{
Q_DECLARE_PUBLIC(PcbCamSymbolSThs)
public:
PcbCamSymbolSThsPrivate() : PcbCamSymbolPrivate() { }
~PcbCamSymbolSThsPrivate() { }
qreal outerDiam {0.0} ;
qreal innerDiam {0.0} ;
qreal startAngle {0.0} ;
int numSpokes {1};
qreal spokesGap {0.0};
};
PcbCamSymbolSThs::PcbCamSymbolSThs(const QString iName)
: PcbCamSymbol(*new PcbCamSymbolSThsPrivate)
{
Q_D(PcbCamSymbolSThs);
d->type = PcbCam::Sym_SThs;
d->name = iName;
QRegularExpression re("^s_ths([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9]+)x([0-9.]+)$");
QRegularExpressionMatch match = re.match(d->name);
d->outerDiam = match.captured(1).toDouble()/1000.0;
d->innerDiam = match.captured(2).toDouble()/1000.0;
d->startAngle = match.captured(3).toDouble();
d->numSpokes = match.captured(4).toInt();
d->spokesGap = match.captured(5).toDouble()/1000.0;
}
PcbCamSymbolSThs::~PcbCamSymbolSThs()
{
}
QPainterPath PcbCamSymbolSThs::shape() const
{
Q_D(const PcbCamSymbolSThs);
if (d->shape.isEmpty()) {
QPainterPath path;
path.addRect(-d->outerDiam/2.0, -d->outerDiam/2.0, d->outerDiam, d->outerDiam);
path.addRect(-d->innerDiam/2.0, -d->innerDiam/2.0, d->innerDiam, d->innerDiam);
QPainterPath bar;
bar.addRect(0, -d->spokesGap/2.0, d->outerDiam + 0.0001, d->spokesGap);
QPainterPath sub;
QTransform mat;
mat.rotate(d->startAngle);
qreal angle_div = 360.0 / d->numSpokes;
for (int i = 0; i < d->numSpokes; ++i) {
sub.addPath(mat.map(bar));
mat.rotate(angle_div);
}
d->shape = path.subtracted(sub);
}
return d->shape;
}
qreal PcbCamSymbolSThs::outerDiam() const
{
Q_D(const PcbCamSymbolSThs);
return d->outerDiam;
}
qreal PcbCamSymbolSThs::innerDiam() const
{
Q_D(const PcbCamSymbolSThs);
return d->innerDiam;
}
qreal PcbCamSymbolSThs::startAngle() const
{
Q_D(const PcbCamSymbolSThs);
return d->startAngle;
}
int PcbCamSymbolSThs::numSpokes() const
{
Q_D(const PcbCamSymbolSThs);
return d->numSpokes;
}
qreal PcbCamSymbolSThs::spokesGap() const
{
Q_D(const PcbCamSymbolSThs);
return d->spokesGap;
}
/********************* s_tho100x70x30x5x20 *****************/
class PcbCamSymbolSThoPrivate : public PcbCamSymbolPrivate
{
Q_DECLARE_PUBLIC(PcbCamSymbolSTho)
public:
PcbCamSymbolSThoPrivate() : PcbCamSymbolPrivate() { }
~PcbCamSymbolSThoPrivate() { }
int sign(qreal val) const {
return (val >= 0) + (val < 0) * (-1);
}
qreal outerDiam {0.0} ;
qreal innerDiam {0.0} ;
qreal startAngle {0.0} ;
int numSpokes {1};
qreal spokesGap {0.0};
};
PcbCamSymbolSTho::PcbCamSymbolSTho(const QString iName)
: PcbCamSymbol(*new PcbCamSymbolSThoPrivate)
{
Q_D(PcbCamSymbolSTho);
d->type = PcbCam::Sym_STho;
d->name = iName;
QRegularExpression re("^s_tho([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9]+)x([0-9.]+)$");
QRegularExpressionMatch match = re.match(d->name);
d->outerDiam = match.captured(1).toDouble()/1000.0;
d->innerDiam = match.captured(2).toDouble()/1000.0;
d->startAngle = match.captured(3).toDouble();
d->numSpokes = match.captured(4).toInt();
d->spokesGap = match.captured(5).toDouble()/1000.0;
}
PcbCamSymbolSTho::~PcbCamSymbolSTho()
{
}
QPainterPath PcbCamSymbolSTho::shape() const
{
Q_D(const PcbCamSymbolSTho);
if (d->shape.isEmpty()) {
if ((d->numSpokes != 1 && d->numSpokes != 2 && d->numSpokes != 4)
|| ((int)d->startAngle % 45 != 0))
{
//TOP8LOG.error() << "invalid symbol " << d->name;
return QPainterPath();
}
QPainterPath path;
path.addRect(-d->outerDiam/2.0, -d->outerDiam/2.0, d->outerDiam, d->outerDiam);
path.addRect(-d->innerDiam/2.0, -d->innerDiam/2.0, d->innerDiam, d->innerDiam);
QPainterPath sub;
qreal angle_div = 360.0/d->numSpokes;
if ((int)d->startAngle % 90 == 0) {
QPainterPath bar;
bar.addRect(0, -d->spokesGap/2.0, d->outerDiam, d->spokesGap);
QTransform mat;
mat.rotate(-d->startAngle);
for (int i = 0; i < d->numSpokes; ++i) {
sub.addPath(mat.map(bar));
mat.rotate(-angle_div);
}
}
else {
qreal side = d->spokesGap * qCos(M_PI/4.0) + (d->outerDiam - d->innerDiam)/2.0;
qreal offset = (d->outerDiam - side) /2.0;
QPainterPath box;
box.addRect(-side/2.0, -side/2.0, side, side);
for (int i = 0; i < d->numSpokes; ++i) {
QTransform mat;
mat.translate(offset * d->sign(qCos((d->startAngle + angle_div * i) * (M_PI/180.0))),
-offset * d->sign(qSin((d->startAngle + angle_div * i) * (M_PI/180.0))));
sub.addPath(mat.map(box));
}
}
QTransform mat;
mat.scale(1, -1);
d->shape = mat.map(path.subtracted(sub));
}
return d->shape;
}
qreal PcbCamSymbolSTho::outerDiam() const
{
Q_D(const PcbCamSymbolSTho);
return d->outerDiam;
}
qreal PcbCamSymbolSTho::innerDiam() const
{
Q_D(const PcbCamSymbolSTho);
return d->innerDiam;
}
qreal PcbCamSymbolSTho::startAngle() const
{
Q_D(const PcbCamSymbolSTho);
return d->startAngle;
}
int PcbCamSymbolSTho::numSpokes() const
{
Q_D(const PcbCamSymbolSTho);
return d->numSpokes;
}
qreal PcbCamSymbolSTho::spokesGap() const
{
Q_D(const PcbCamSymbolSTho);
return d->spokesGap;
}
/********************* sr_ths100x70x30x5x20 *****************/
class PcbCamSymbolSrThsPrivate : public PcbCamSymbolPrivate
{
Q_DECLARE_PUBLIC(PcbCamSymbolSrThs)
public:
PcbCamSymbolSrThsPrivate() : PcbCamSymbolPrivate() { }
~PcbCamSymbolSrThsPrivate() { }
int sign(qreal val) const {
return (val >= 0) + (val < 0) * (-1);
}
qreal outerDiam {0.0} ;
qreal innerDiam {0.0} ;
qreal startAngle {0.0} ;
int numSpokes {1};
qreal spokesGap {0.0};
};
PcbCamSymbolSrThs::PcbCamSymbolSrThs(const QString iName)
: PcbCamSymbol(*new PcbCamSymbolSrThsPrivate)
{
Q_D(PcbCamSymbolSrThs);
d->type = PcbCam::Sym_SrThs;
d->name = iName;
QRegularExpression re("^sr_ths([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9]+)x([0-9.]+)$");
QRegularExpressionMatch match = re.match(d->name);
d->outerDiam = match.captured(1).toDouble()/1000.0;
d->innerDiam = match.captured(2).toDouble()/1000.0;
d->startAngle = match.captured(3).toDouble();
d->numSpokes = match.captured(4).toInt();
d->spokesGap = match.captured(5).toDouble()/1000.0;
}
PcbCamSymbolSrThs::~PcbCamSymbolSrThs()
{
}
QPainterPath PcbCamSymbolSrThs::shape() const
{
Q_D(const PcbCamSymbolSrThs);
if (d->shape.isEmpty()) {
QPainterPath path;
path.addRect(-d->outerDiam/2.0, -d->outerDiam/2.0, d->outerDiam, d->outerDiam);
path.addEllipse(-d->innerDiam/2.0, -d->innerDiam/2.0, d->innerDiam, d->innerDiam);
QPainterPath bar;
bar.addRect(0, -d->spokesGap/2.0, d->outerDiam + 0.0001, d->spokesGap);
QPainterPath sub;
QTransform mat;
mat.rotate(d->startAngle);
qreal angle_div = 360.0 / d->numSpokes;
for (int i = 0; i < d->numSpokes; ++i) {
sub.addPath(mat.map(bar));
mat.rotate(angle_div);
}
//因为substracted会打段圆弧,造成精度丢失,所以我们放大1000倍来处理;
QTransform mat2;
mat2.scale(1000, 1000);
d->shape = mat2.map(path).subtracted(mat2.map(sub));
QTransform mat3;
mat3.scale(0.001, 0.001);
d->shape = mat3.map(d->shape);
}
return d->shape;
}
qreal PcbCamSymbolSrThs::outerDiam() const
{
Q_D(const PcbCamSymbolSrThs);
return d->outerDiam;
}
qreal PcbCamSymbolSrThs::innerDiam() const
{
Q_D(const PcbCamSymbolSrThs);
return d->innerDiam;
}
qreal PcbCamSymbolSrThs::startAngle() const
{
Q_D(const PcbCamSymbolSrThs);
return d->startAngle;
}
int PcbCamSymbolSrThs::numSpokes() const
{
Q_D(const PcbCamSymbolSrThs);
return d->numSpokes;
}
qreal PcbCamSymbolSrThs::spokesGap() const
{
Q_D(const PcbCamSymbolSrThs);
return d->spokesGap;
}
/********************* rc_ths100x70x30x5x20 *****************/
class PcbCamSymbolRcThsPrivate : public PcbCamSymbolPrivate
{
Q_DECLARE_PUBLIC(PcbCamSymbolRcThs)
public:
PcbCamSymbolRcThsPrivate() : PcbCamSymbolPrivate() { }
~PcbCamSymbolRcThsPrivate() { }
int sign(qreal val) const {
return (val >= 0) + (val < 0) * (-1);
}
qreal width {0.0} ;
qreal height {0.0} ;
qreal startAngle {0.0} ;
int numSpokes {1};
qreal spokesGap {0.0};
qreal airGap {0.0};
};
PcbCamSymbolRcThs::PcbCamSymbolRcThs(const QString iName)
: PcbCamSymbol(*new PcbCamSymbolRcThsPrivate)
{
Q_D(PcbCamSymbolRcThs);
d->type = PcbCam::Sym_RcThs;
d->name = iName;
QRegularExpression re("^rc_ths([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9]+)x([0-9.]+)x([0-9.]+)$");
QRegularExpressionMatch match = re.match(d->name);
d->width = match.captured(1).toDouble()/1000.0;
d->height = match.captured(2).toDouble()/1000.0;
d->startAngle = match.captured(3).toDouble();
d->numSpokes = match.captured(4).toInt();
d->spokesGap = match.captured(5).toDouble()/1000.0;
d->airGap = match.captured(6).toDouble()/1000.0;
}
PcbCamSymbolRcThs::~PcbCamSymbolRcThs()
{
}
QPainterPath PcbCamSymbolRcThs::shape() const
{
Q_D(const PcbCamSymbolRcThs);
if (d->shape.isEmpty()) {
//TODO 当开口数量为3时可能有Bug;
QPainterPath path;
path.addRect(-d->width / 2, -d->height / 2, d->width, d->height);
path.addRect(-d->width / 2 + d->airGap, -d->height / 2 + d->airGap,
d->width - 2 * d->airGap, d->height - 2 * d->airGap);
QPainterPath bar;
bar.addRect(0, -d->spokesGap / 2, d->width, d->spokesGap);
QPainterPath sub;
qreal angle_div = 360.0 / d->numSpokes;
qreal ang = d->startAngle;
for (int i = 0; i < d->numSpokes; ++i, ang += angle_div) {
QTransform mat;
ang = qCeil(ang / 45) * 45.0;
if ((int)ang % 90 != 0) {
if (d->width > d->height) {
mat.translate((d->width - d->height) / 2 * d->sign(qCos((ang) * (M_PI/180.0))), 0);
} else {
mat.translate(0, -(d->height - d->width) / 2 * d->sign(qSin((ang) * (M_PI/180.0))));
}
}
mat.rotate(-ang);
sub.addPath(mat.map(bar));
}
path = path.subtracted(sub);
QTransform mat;
mat.scale(1, -1);
d->shape = mat.map(path);
}
return d->shape;
}
qreal PcbCamSymbolRcThs::width() const
{
Q_D(const PcbCamSymbolRcThs);
return d->width;
}
qreal PcbCamSymbolRcThs::height() const
{
Q_D(const PcbCamSymbolRcThs);
return d->height;
}
qreal PcbCamSymbolRcThs::startAngle() const
{
Q_D(const PcbCamSymbolRcThs);
return d->startAngle;
}
int PcbCamSymbolRcThs::numSpokes() const
{
Q_D(const PcbCamSymbolRcThs);
return d->numSpokes;
}
qreal PcbCamSymbolRcThs::spokesGap() const
{
Q_D(const PcbCamSymbolRcThs);
return d->spokesGap;
}
qreal PcbCamSymbolRcThs::airGap() const
{
Q_D(const PcbCamSymbolRcThs);
return d->airGap;
}
/********************* rc_tho100x70x30x5x20 *****************/
class PcbCamSymbolRcThoPrivate : public PcbCamSymbolPrivate
{
Q_DECLARE_PUBLIC(PcbCamSymbolRcTho)
public:
PcbCamSymbolRcThoPrivate() : PcbCamSymbolPrivate() { }
~PcbCamSymbolRcThoPrivate() { }
int sign(qreal val) const {
return (val >= 0) + (val < 0) * (-1);
}
qreal width {0.0} ;
qreal height {0.0} ;
qreal startAngle {0.0} ;
int numSpokes {1};
qreal spokesGap {0.0};
qreal airGap {0.0};
};
PcbCamSymbolRcTho::PcbCamSymbolRcTho(const QString iName)
: PcbCamSymbol(*new PcbCamSymbolRcThoPrivate)
{
Q_D(PcbCamSymbolRcTho);
d->type = PcbCam::Sym_RcTho;
d->name = iName;
QRegularExpression re("^rc_tho([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9]+)x([0-9.]+)x([0-9.]+)$");
QRegularExpressionMatch match = re.match(d->name);
d->width = match.captured(1).toDouble()/1000.0;
d->height = match.captured(2).toDouble()/1000.0;
d->startAngle = match.captured(3).toDouble();
d->numSpokes = match.captured(4).toInt();
d->spokesGap = match.captured(5).toDouble()/1000.0;
d->airGap = match.captured(6).toDouble()/1000.0;
}
PcbCamSymbolRcTho::~PcbCamSymbolRcTho()
{
}
QPainterPath PcbCamSymbolRcTho::shape() const
{
Q_D(const PcbCamSymbolRcTho);
if (d->shape.isEmpty()) {
QPainterPath path;
qreal angle_div = 360.0 / d->numSpokes;
QPainterPath sub;
QTransform mat;
if ((d->numSpokes != 1 && d->numSpokes != 2 && d->numSpokes != 4) ||
((int)d->startAngle % 45 != 0))
{
//TOP8LOG.error() << "invalid symbol " << d->name;
return QPainterPath();
}
path.addRect(-d->width / 2, -d->height / 2, d->width, d->height);
path.addRect(-d->width / 2 + d->airGap, -d->height / 2 + d->airGap,
d->width - 2 * d->airGap, d->height - 2 * d->airGap);
if ((int)d->startAngle % 90 == 0) {
QPainterPath bar;
bar.addRect(0, -d->spokesGap / 2, d->width / 2, d->spokesGap);
for (int i = 0; i < d->numSpokes; ++i) {
sub.addPath(mat.map(bar));
mat.rotate(-angle_div);
}
} else {
qreal side = d->spokesGap * qCos(M_PI / 4) + d->airGap;
qreal offset_w = (d->width - side) / 2, offset_h = (d->height - side) / 2;
QPainterPath box;
box.addRect(-side / 2, -side / 2, side, side);
for (int i = 0; i < d->numSpokes; ++i) {
QTransform mat;
mat.translate(offset_w * d->sign(qCos((d->startAngle + angle_div * i) * (M_PI/180.0))),
-offset_h * d->sign(qSin((d->startAngle + angle_div * i) * (M_PI/180.0))));
sub.addPath(mat.map(box));
}
}
path = path.subtracted(sub);
QTransform mat2;
mat2.scale(1, -1);
d->shape = mat2.map(path);
}
return d->shape;
}
qreal PcbCamSymbolRcTho::width() const
{
Q_D(const PcbCamSymbolRcTho);
return d->width;
}
qreal PcbCamSymbolRcTho::height() const
{
Q_D(const PcbCamSymbolRcTho);
return d->height;
}
qreal PcbCamSymbolRcTho::startAngle() const
{
Q_D(const PcbCamSymbolRcTho);
return d->startAngle;
}
int PcbCamSymbolRcTho::numSpokes() const
{
Q_D(const PcbCamSymbolRcTho);
return d->numSpokes;
}
qreal PcbCamSymbolRcTho::spokesGap() const
{
Q_D(const PcbCamSymbolRcTho);
return d->spokesGap;
}
qreal PcbCamSymbolRcTho::airGap() const
{
Q_D(const PcbCamSymbolRcTho);
return d->airGap;
}
/********************* el10x20 *****************/
class PcbCamSymbolElPrivate : public PcbCamSymbolPrivate
{
Q_DECLARE_PUBLIC(PcbCamSymbolEl)
public:
PcbCamSymbolElPrivate() : PcbCamSymbolPrivate() { }
~PcbCamSymbolElPrivate() { }
QSizeF size ;
};
PcbCamSymbolEl::PcbCamSymbolEl(const QString iName)
: PcbCamSymbol(*new PcbCamSymbolElPrivate)
{
Q_D(PcbCamSymbolEl);
d->type = PcbCam::Sym_El;
d->name = iName;
QRegularExpression re("^el([0-9.]+)x([0-9.]+)$");
QRegularExpressionMatch match = re.match(d->name);
d->size = QSizeF(match.captured(1).toDouble()/1000.0, match.captured(2).toDouble()/1000.0);
}
PcbCamSymbolEl::~PcbCamSymbolEl()
{
}
QPainterPath PcbCamSymbolEl::shape() const
{
Q_D(const PcbCamSymbolEl);
if (d->shape.isEmpty()) {
d->shape.addEllipse(QRectF(-d->size.width()/2.0, -d->size.height()/2.0, d->size.width(), d->size.height()));
}
return d->shape;
}
QSizeF PcbCamSymbolEl::size() const
{
Q_D(const PcbCamSymbolEl);
return d->size;
}
/********************* moire10x10x3x1x100x30 *****************/
class PcbCamSymbolMoirePrivate : public PcbCamSymbolPrivate
{
Q_DECLARE_PUBLIC(PcbCamSymbolMoire)
public:
PcbCamSymbolMoirePrivate() : PcbCamSymbolPrivate() { }
~PcbCamSymbolMoirePrivate() { }
qreal ringWidth {0.0};
qreal ringGap {0.0};
int numRings {1};
qreal lineWidth {0.0};
qreal lineLength {0.0};
qreal lineAngle {0.0};
};
PcbCamSymbolMoire::PcbCamSymbolMoire(const QString iName)
: PcbCamSymbol(*new PcbCamSymbolMoirePrivate)
{
Q_D(PcbCamSymbolMoire);
d->type = PcbCam::Sym_Moire;
d->name = iName;
QRegularExpression re("^moire([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9.]+)$");
QRegularExpressionMatch match = re.match(d->name);
d->ringWidth = match.captured(1).toDouble()/1000.0;
d->ringGap = match.captured(2).toDouble()/1000.0;
d->numRings = match.captured(3).toInt();
d->lineWidth = match.captured(4).toDouble()/1000.0;
d->lineLength = match.captured(5).toDouble()/1000.0;
d->lineAngle = match.captured(6).toDouble();
}
PcbCamSymbolMoire::~PcbCamSymbolMoire()
{
}
QPainterPath PcbCamSymbolMoire::shape() const
{
Q_D(const PcbCamSymbolMoire);
if (d->shape.isEmpty()) {
QPainterPath ringpath;
ringpath.addEllipse(-d->ringWidth/2.0, -d->ringWidth/2.0, d->ringWidth, d->ringWidth);
QPainterPathStroker rstroker;
rstroker.setWidth(d->ringWidth);
rstroker.setJoinStyle(Qt::RoundJoin);
rstroker.setCapStyle(Qt::RoundCap);
for (int i = 1; i <= d->numRings; ++i) {
qreal rad = d->ringWidth/2.0 + (d->ringGap + d->ringWidth/2.0) * i;
QPainterPath p;
p.addEllipse(-rad, -rad, rad*2.0, rad*2.0);
ringpath.addPath(rstroker.createStroke(p));
}
QPainterPath linepath;
linepath.moveTo(-d->lineLength/2.0, 0);
linepath.lineTo(d->lineLength/2.0, 0);
linepath.moveTo(0, -d->lineLength/2.0);
linepath.lineTo(0, d->lineLength/2.0);
QPainterPathStroker lstroker;
lstroker.setWidth(d->lineWidth);
lstroker.setJoinStyle(Qt::RoundJoin);
lstroker.setCapStyle(Qt::RoundCap);
linepath = lstroker.createStroke(linepath);
QTransform mat1;
mat1.scale(1000, 1000);
ringpath = mat1.map(ringpath).simplified();
linepath = mat1.map(linepath).simplified();
QPainterPath path = ringpath.united(linepath);
QTransform mat2;
mat2.scale(0.001, 0.001);
mat2.rotate(-d->lineAngle);
d->shape = mat2.map(path);
}
return d->shape;
}
qreal PcbCamSymbolMoire::ringWidth() const
{
Q_D(const PcbCamSymbolMoire);
return d->ringWidth;
}
qreal PcbCamSymbolMoire::ringGap() const
{
Q_D(const PcbCamSymbolMoire);
return d->ringGap;
}
int PcbCamSymbolMoire::numRings() const
{
Q_D(const PcbCamSymbolMoire);
return d->numRings;
}
qreal PcbCamSymbolMoire::lineWidth() const
{
Q_D(const PcbCamSymbolMoire);
return d->lineWidth;
}
qreal PcbCamSymbolMoire::lineLength() const
{
Q_D(const PcbCamSymbolMoire);
return d->lineLength;
}
qreal PcbCamSymbolMoire::lineAngle() const
{
Q_D(const PcbCamSymbolMoire);
return d->lineAngle;
}
/********************* user symbol *****************/
class PcbCamSymbolUserPrivate : public PcbCamSymbolPrivate
{
Q_DECLARE_PUBLIC(PcbCamSymbolUser)
public:
PcbCamSymbolUserPrivate() : PcbCamSymbolPrivate() { }
~PcbCamSymbolUserPrivate() { }
void destoryFeatures() {
qDeleteAll(features);
features.clear();
}
QList<PcbCamFeature *> features;
int maxIndex {0};
};
PcbCamSymbolUser::PcbCamSymbolUser(const QString iName)
: PcbCamSymbol(*new PcbCamSymbolUserPrivate)
{
Q_D(PcbCamSymbolUser);
d->type = PcbCam::Sym_User;
d->name = iName;
}
PcbCamSymbolUser::~PcbCamSymbolUser()
{
}
QPainterPath PcbCamSymbolUser::shape() const
{
Q_D(const PcbCamSymbolUser);
if (d->shape.isEmpty()) {
for (auto feat : d->features) {
d->shape.addPath(feat->shape());
}
}
return d->shape;
}
QList<PcbCamFeature *> PcbCamSymbolUser::features() const
{
Q_D(const PcbCamSymbolUser);
return d->features;
}
void PcbCamSymbolUser::clearFeatures()
{
Q_D(PcbCamSymbolUser);
d->destoryFeatures();
d->maxIndex = 0;
}
void PcbCamSymbolUser::addFeature(PcbCamFeature *iFeature)
{
Q_D(PcbCamSymbolUser);
iFeature->setIndex(++d->maxIndex);
d->features.append(iFeature);
}
void PcbCamSymbolUser::addFeatures(const QList<PcbCamFeature *> &iFeatures)
{
for (PcbCamFeature *feat : iFeatures) {
addFeature(feat);
}
}
void PcbCamSymbolUser::deleteFeature(int iIndex)
{
Q_D(PcbCamSymbolUser);
for (int i = 0; i < d->features.count(); ++i) {
PcbCamFeature *feat = d->features[i];
if (feat->index() == iIndex) {
d->features.removeAt(i);
delete feat;
return;
}
}
}
TITAN_END_NAMESPACE
#ifndef TITAN_PCBCAM_SYMBOL_H
#define TITAN_PCBCAM_SYMBOL_H
#include "../titanpcbcamglobal.h"
#include <QSharedDataPointer>
#include "./feature.h"
#include "./common.h"
TITAN_BEGIN_NAMESPACE
class PcbCamSymbolPrivate;
class TITAN_PCBCAM_EXPORT PcbCamSymbol
{
public:
PcbCamSymbol();
virtual ~PcbCamSymbol();
virtual QString name() const;
virtual QPainterPath shape() const = 0;
virtual QRectF boundingRect() const;
virtual PcbCam::SymbolType type() const ;
protected:
PcbCamSymbol(PcbCamSymbolPrivate &dd);
QScopedPointer<PcbCamSymbolPrivate> d_ptr;
private:
Q_DECLARE_PRIVATE(PcbCamSymbol)
Q_DISABLE_COPY(PcbCamSymbol)
};
class PcbCamSymbolRPrivate;
class TITAN_PCBCAM_EXPORT PcbCamSymbolR : public PcbCamSymbol
{
public:
PcbCamSymbolR(const QString iName);
~PcbCamSymbolR();
QPainterPath shape() const;
qreal size() const;
private:
Q_DECLARE_PRIVATE(PcbCamSymbolR)
Q_DISABLE_COPY(PcbCamSymbolR)
};
class PcbCamSymbolSPrivate;
class TITAN_PCBCAM_EXPORT PcbCamSymbolS : public PcbCamSymbol
{
public:
PcbCamSymbolS(const QString iName);
~PcbCamSymbolS();
QPainterPath shape() const;
qreal size() const;
private:
Q_DECLARE_PRIVATE(PcbCamSymbolS)
Q_DISABLE_COPY(PcbCamSymbolS)
};
class PcbCamSymbolRectPrivate;
class TITAN_PCBCAM_EXPORT PcbCamSymbolRect : public PcbCamSymbol
{
public:
PcbCamSymbolRect(const QString iName);
~PcbCamSymbolRect();
QPainterPath shape() const;
QSizeF size() const;
private:
Q_DECLARE_PRIVATE(PcbCamSymbolRect)
Q_DISABLE_COPY(PcbCamSymbolRect)
};
class PcbCamSymbolRectRPrivate;
class TITAN_PCBCAM_EXPORT PcbCamSymbolRectR : public PcbCamSymbol
{
public:
PcbCamSymbolRectR(const QString iName);
~PcbCamSymbolRectR();
QPainterPath shape() const;
qreal width() const;
qreal height() const;
qreal radius() const;
QString corners() const;
private:
Q_DECLARE_PRIVATE(PcbCamSymbolRectR)
Q_DISABLE_COPY(PcbCamSymbolRectR)
};
class PcbCamSymbolRectCPrivate;
class TITAN_PCBCAM_EXPORT PcbCamSymbolRectC : public PcbCamSymbol
{
public:
PcbCamSymbolRectC(const QString iName);
~PcbCamSymbolRectC();
QPainterPath shape() const;
qreal width() const;
qreal height() const;
qreal radius() const;
QString corners() const;
private:
Q_DECLARE_PRIVATE(PcbCamSymbolRectC)
Q_DISABLE_COPY(PcbCamSymbolRectC)
};
class PcbCamSymbolOvalPrivate;
class TITAN_PCBCAM_EXPORT PcbCamSymbolOval : public PcbCamSymbol
{
public:
PcbCamSymbolOval(const QString iName);
~PcbCamSymbolOval();
QPainterPath shape() const;
QSizeF size() const;
private:
Q_DECLARE_PRIVATE(PcbCamSymbolOval)
Q_DISABLE_COPY(PcbCamSymbolOval)
};
class PcbCamSymbolDiPrivate;
class TITAN_PCBCAM_EXPORT PcbCamSymbolDi : public PcbCamSymbol
{
public:
PcbCamSymbolDi(const QString iName);
~PcbCamSymbolDi();
QPainterPath shape() const;
QSizeF size() const;
private:
Q_DECLARE_PRIVATE(PcbCamSymbolDi)
Q_DISABLE_COPY(PcbCamSymbolDi)
};
class PcbCamSymbolOctPrivate;
class TITAN_PCBCAM_EXPORT PcbCamSymbolOct : public PcbCamSymbol
{
public:
PcbCamSymbolOct(const QString iName);
~PcbCamSymbolOct();
QPainterPath shape() const;
qreal width() const;
qreal height() const;
qreal radius() const;
private:
Q_DECLARE_PRIVATE(PcbCamSymbolOct)
Q_DISABLE_COPY(PcbCamSymbolOct)
};
class PcbCamSymbolDonutRPrivate;
class TITAN_PCBCAM_EXPORT PcbCamSymbolDonutR : public PcbCamSymbol
{
public:
PcbCamSymbolDonutR(const QString iName);
~PcbCamSymbolDonutR();
QPainterPath shape() const;
qreal outerDiam() const;
qreal innerDiam() const;
private:
Q_DECLARE_PRIVATE(PcbCamSymbolDonutR)
Q_DISABLE_COPY(PcbCamSymbolDonutR)
};
class PcbCamSymbolDonutSPrivate;
class TITAN_PCBCAM_EXPORT PcbCamSymbolDonutS : public PcbCamSymbol
{
public:
PcbCamSymbolDonutS(const QString iName);
~PcbCamSymbolDonutS();
QPainterPath shape() const;
qreal outerDiam() const;
qreal innerDiam() const;
private:
Q_DECLARE_PRIVATE(PcbCamSymbolDonutS)
Q_DISABLE_COPY(PcbCamSymbolDonutS)
};
class PcbCamSymbolHexLPrivate;
class TITAN_PCBCAM_EXPORT PcbCamSymbolHexL : public PcbCamSymbol
{
public:
PcbCamSymbolHexL(const QString iName);
~PcbCamSymbolHexL();
QPainterPath shape() const;
qreal width() const;
qreal height() const;
qreal radius() const;
private:
Q_DECLARE_PRIVATE(PcbCamSymbolHexL)
Q_DISABLE_COPY(PcbCamSymbolHexL)
};
class PcbCamSymbolHexSPrivate;
class TITAN_PCBCAM_EXPORT PcbCamSymbolHexS : public PcbCamSymbol
{
public:
PcbCamSymbolHexS(const QString iName);
~PcbCamSymbolHexS();
QPainterPath shape() const;
qreal width() const;
qreal height() const;
qreal radius() const;
private:
Q_DECLARE_PRIVATE(PcbCamSymbolHexS)
Q_DISABLE_COPY(PcbCamSymbolHexS)
};
class PcbCamSymbolBfrPrivate;
class TITAN_PCBCAM_EXPORT PcbCamSymbolBfr : public PcbCamSymbol
{
public:
PcbCamSymbolBfr(const QString iName);
~PcbCamSymbolBfr();
QPainterPath shape() const;
qreal size() const;
private:
Q_DECLARE_PRIVATE(PcbCamSymbolBfr)
Q_DISABLE_COPY(PcbCamSymbolBfr)
};
class PcbCamSymbolBfsPrivate;
class TITAN_PCBCAM_EXPORT PcbCamSymbolBfs : public PcbCamSymbol
{
public:
PcbCamSymbolBfs(const QString iName);
~PcbCamSymbolBfs();
QPainterPath shape() const;
qreal size() const;
private:
Q_DECLARE_PRIVATE(PcbCamSymbolBfs)
Q_DISABLE_COPY(PcbCamSymbolBfs)
};
class PcbCamSymbolTriPrivate;
class TITAN_PCBCAM_EXPORT PcbCamSymbolTri : public PcbCamSymbol
{
public:
PcbCamSymbolTri(const QString iName);
~PcbCamSymbolTri();
QPainterPath shape() const;
QSizeF size() const;
private:
Q_DECLARE_PRIVATE(PcbCamSymbolTri)
Q_DISABLE_COPY(PcbCamSymbolTri)
};
class PcbCamSymbolOvalHPrivate;
class TITAN_PCBCAM_EXPORT PcbCamSymbolOvalH : public PcbCamSymbol
{
public:
PcbCamSymbolOvalH(const QString iName);
~PcbCamSymbolOvalH();
QPainterPath shape() const;
QSizeF size() const;
private:
Q_DECLARE_PRIVATE(PcbCamSymbolOvalH)
Q_DISABLE_COPY(PcbCamSymbolOvalH)
};
class PcbCamSymbolThrPrivate;
class TITAN_PCBCAM_EXPORT PcbCamSymbolThr : public PcbCamSymbol
{
public:
PcbCamSymbolThr(const QString iName);
~PcbCamSymbolThr();
QPainterPath shape() const;
qreal outerDiam() const;
qreal innerDiam() const;
qreal startAngle() const;
int numSpokes() const;
qreal spokesGap() const;
private:
Q_DECLARE_PRIVATE(PcbCamSymbolThr)
Q_DISABLE_COPY(PcbCamSymbolThr)
};
class PcbCamSymbolThsPrivate;
class TITAN_PCBCAM_EXPORT PcbCamSymbolThs : public PcbCamSymbol
{
public:
PcbCamSymbolThs(const QString iName);
~PcbCamSymbolThs();
QPainterPath shape() const;
qreal outerDiam() const;
qreal innerDiam() const;
qreal startAngle() const;
int numSpokes() const;
qreal spokesGap() const;
private:
Q_DECLARE_PRIVATE(PcbCamSymbolThs)
Q_DISABLE_COPY(PcbCamSymbolThs)
};
class PcbCamSymbolSThsPrivate;
class TITAN_PCBCAM_EXPORT PcbCamSymbolSThs : public PcbCamSymbol
{
public:
PcbCamSymbolSThs(const QString iName);
~PcbCamSymbolSThs();
QPainterPath shape() const;
qreal outerDiam() const;
qreal innerDiam() const;
qreal startAngle() const;
int numSpokes() const;
qreal spokesGap() const;
private:
Q_DECLARE_PRIVATE(PcbCamSymbolSThs)
Q_DISABLE_COPY(PcbCamSymbolSThs)
};
class PcbCamSymbolSThoPrivate;
class TITAN_PCBCAM_EXPORT PcbCamSymbolSTho : public PcbCamSymbol
{
public:
PcbCamSymbolSTho(const QString iName);
~PcbCamSymbolSTho();
QPainterPath shape() const;
qreal outerDiam() const;
qreal innerDiam() const;
qreal startAngle() const;
int numSpokes() const;
qreal spokesGap() const;
private:
Q_DECLARE_PRIVATE(PcbCamSymbolSTho)
Q_DISABLE_COPY(PcbCamSymbolSTho)
};
class PcbCamSymbolSrThsPrivate;
class TITAN_PCBCAM_EXPORT PcbCamSymbolSrThs : public PcbCamSymbol
{
public:
PcbCamSymbolSrThs(const QString iName);
~PcbCamSymbolSrThs();
QPainterPath shape() const;
qreal outerDiam() const;
qreal innerDiam() const;
qreal startAngle() const;
int numSpokes() const;
qreal spokesGap() const;
private:
Q_DECLARE_PRIVATE(PcbCamSymbolSrThs)
Q_DISABLE_COPY(PcbCamSymbolSrThs)
};
class PcbCamSymbolRcThsPrivate;
class TITAN_PCBCAM_EXPORT PcbCamSymbolRcThs : public PcbCamSymbol
{
public:
PcbCamSymbolRcThs(const QString iName);
~PcbCamSymbolRcThs();
QPainterPath shape() const;
qreal width() const;
qreal height() const;
qreal startAngle() const;
int numSpokes() const;
qreal spokesGap() const;
qreal airGap() const;
private:
Q_DECLARE_PRIVATE(PcbCamSymbolRcThs)
Q_DISABLE_COPY(PcbCamSymbolRcThs)
};
class PcbCamSymbolRcThoPrivate;
class TITAN_PCBCAM_EXPORT PcbCamSymbolRcTho : public PcbCamSymbol
{
public:
PcbCamSymbolRcTho(const QString iName);
~PcbCamSymbolRcTho();
QPainterPath shape() const;
qreal width() const;
qreal height() const;
qreal startAngle() const;
int numSpokes() const;
qreal spokesGap() const;
qreal airGap() const;
private:
Q_DECLARE_PRIVATE(PcbCamSymbolRcTho)
Q_DISABLE_COPY(PcbCamSymbolRcTho)
};
class PcbCamSymbolElPrivate;
class TITAN_PCBCAM_EXPORT PcbCamSymbolEl : public PcbCamSymbol
{
public:
PcbCamSymbolEl(const QString iName);
~PcbCamSymbolEl();
QPainterPath shape() const;
QSizeF size() const;
private:
Q_DECLARE_PRIVATE(PcbCamSymbolEl)
Q_DISABLE_COPY(PcbCamSymbolEl)
};
class PcbCamSymbolMoirePrivate;
class TITAN_PCBCAM_EXPORT PcbCamSymbolMoire : public PcbCamSymbol
{
public:
PcbCamSymbolMoire(const QString iName);
~PcbCamSymbolMoire();
QPainterPath shape() const;
qreal ringWidth() const;
qreal ringGap() const;
int numRings() const;
qreal lineWidth() const;
qreal lineLength() const;
qreal lineAngle() const;
private:
Q_DECLARE_PRIVATE(PcbCamSymbolMoire)
Q_DISABLE_COPY(PcbCamSymbolMoire)
};
class PcbCamSymbolUserPrivate;
class TITAN_PCBCAM_EXPORT PcbCamSymbolUser : public PcbCamSymbol {
public:
PcbCamSymbolUser(const QString iName);
~PcbCamSymbolUser();
QPainterPath shape() const;
QList<PcbCamFeature *> features() const;
void clearFeatures();
void addFeature(PcbCamFeature *iFeature);
void addFeatures(const QList<PcbCamFeature *> &iFeatures);
void deleteFeature(int iIndex);
private:
Q_DECLARE_PRIVATE(PcbCamSymbolUser)
Q_DISABLE_COPY(PcbCamSymbolUser)
};
TITAN_END_NAMESPACE
#endif // TITAN_PCBCAM_SYMBOL_H
#include "symbolfactory.h"
#include <QDebug>
#include "./symbol.h"
TITAN_BEGIN_NAMESPACE
static QString formatNumber(double iNumber, int iPercision = 6)
{
QString res = QString::number(iNumber, 'f', iPercision);
if (res.contains(".")) {
while (true) {
if (res.at(res.length() - 1) == '0') {
res.chop(1);
}
else {
if (res.at(res.length() - 1) == '.') {
res.chop(1);
}
break;
}
}
}
return res;
}
PcbCamSymbol *PcbCamSymbolFactory::create(const QString &iName)
{
QRegularExpression rx("^(r|s|rect|oval|di|oct|donut_r|donut_s|tri|hex_l|hex_s|bfr|bfs|ths|thr|oval_h|s_ths|s_tho|sr_ths|rc_ths|rc_tho|el|moire|hole)[0-9.]+");
QRegularExpressionMatch match = rx.match(iName);
if (!match.hasMatch()) {
return new PcbCamSymbolUser(iName);
}
rx.setPattern("^r([0-9.]+)$");
if (rx.match(iName).hasMatch()) {
return new PcbCamSymbolR(iName);
}
rx.setPattern("^s([0-9.]+)$");
if (rx.match(iName).hasMatch()) {
return new PcbCamSymbolS(iName);
}
rx.setPattern("^rect([0-9.]+)x([0-9.]+)$");
if (rx.match(iName).hasMatch()) {
return new PcbCamSymbolRect(iName);
}
rx.setPattern("^oval([0-9.]+)x([0-9.]+)$");
if (rx.match(iName).hasMatch()) {
return new PcbCamSymbolOval(iName);
}
rx.setPattern("^thr([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9]+)x([0-9.]+)$");
if (rx.match(iName).hasMatch()) {
return new PcbCamSymbolThr(iName);
}
rx.setPattern("^ths([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9]+)x([0-9.]+)$");
if (rx.match(iName).hasMatch()) {
return new PcbCamSymbolThs(iName);
}
rx.setPattern("^s_ths([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9]+)x([0-9.]+)$");
if (rx.match(iName).hasMatch()) {
return new PcbCamSymbolSThs(iName);
}
rx.setPattern("^s_tho([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9]+)x([0-9.]+)$");
if (rx.match(iName).hasMatch()) {
return new PcbCamSymbolSTho(iName);
}
rx.setPattern("^donut_r([0-9.]+)x([0-9.]+)$");
if (rx.match(iName).hasMatch()) {
return new PcbCamSymbolDonutR(iName);
}
rx.setPattern("^donut_s([0-9.]+)x([0-9.]+)$");
if (rx.match(iName).hasMatch()) {
return new PcbCamSymbolDonutS(iName);
}
rx.setPattern("^di([0-9.]+)x([0-9.]+)$");
if (rx.match(iName).hasMatch()) {
return new PcbCamSymbolDi(iName);
}
rx.setPattern("^oct([0-9.]+)x([0-9.]+)x([0-9.]+)$");
if (rx.match(iName).hasMatch()) {
return new PcbCamSymbolOct(iName);
}
rx.setPattern("^hex_l([0-9.]+)x([0-9.]+)x([0-9.]+)$");
if (rx.match(iName).hasMatch()) {
return new PcbCamSymbolHexL(iName);
}
rx.setPattern("^hex_s([0-9.]+)x([0-9.]+)x([0-9.]+)$");
if (rx.match(iName).hasMatch()) {
return new PcbCamSymbolHexS(iName);
}
rx.setPattern("^bfr([0-9.]+)$");
if (rx.match(iName).hasMatch()) {
return new PcbCamSymbolBfr(iName);
}
rx.setPattern("^bfs([0-9.]+)$");
if (rx.match(iName).hasMatch()) {
return new PcbCamSymbolBfs(iName);
}
rx.setPattern("^tri([0-9.]+)x([0-9.]+)$");
if (rx.match(iName).hasMatch()) {
return new PcbCamSymbolTri(iName);
}
rx.setPattern("^oval_h([0-9.]+)x([0-9.]+)$");
if (rx.match(iName).hasMatch()) {
return new PcbCamSymbolOvalH(iName);
}
rx.setPattern("^rect([0-9.]+)x([0-9.]+)xr([0-9.]+)(?:x([1-4]+))?$");
if (rx.match(iName).hasMatch()) {
return new PcbCamSymbolRectR(iName);
}
rx.setPattern("^rect([0-9.]+)x([0-9.]+)xc([0-9.]+)(?:x([1-4]+))?$");
if (rx.match(iName).hasMatch()) {
return new PcbCamSymbolRectC(iName);
}
rx.setPattern("^sr_ths([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9]+)x([0-9.]+)$");
if (rx.match(iName).hasMatch()) {
return new PcbCamSymbolSrThs(iName);
}
rx.setPattern("^rc_ths([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9]+)x([0-9.]+)x([0-9.]+)$");
if (rx.match(iName).hasMatch()) {
return new PcbCamSymbolRcThs(iName);
}
rx.setPattern("^rc_tho([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9]+)x([0-9.]+)x([0-9.]+)$");
if (rx.match(iName).hasMatch()) {
return new PcbCamSymbolRcTho(iName);
}
rx.setPattern("^moire([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9.]+)$");
if (rx.match(iName).hasMatch()) {
return new PcbCamSymbolMoire(iName);
}
rx.setPattern("^el([0-9.]+)x([0-9.]+)$");
if (rx.match(iName).hasMatch()) {
return new PcbCamSymbolEl(iName);
}
return new PcbCamSymbolUser(iName);
}
QString PcbCamSymbolFactory::symbolScaledName(const QString &iName, double iScale, int iPercision)
{
QRegularExpression rx("^(r|s|rect|oval|di|oct|donut_r|donut_s|tri|hex_l|hex_s|bfr|bfs|ths|thr|oval_h|s_ths|s_tho|sr_ths|rc_ths|rc_tho|el|moire|hole)[0-9.]+");
QRegularExpressionMatch match = rx.match(iName);
if (!match.hasMatch()) {
return iName;
}
rx.setPattern("^r([0-9.]+)$");
match = rx.match(iName);
if (match.hasMatch()) {
return QString("r%1")
.arg(formatNumber(match.captured(1).toDouble() * iScale, iPercision));
}
rx.setPattern("^s([0-9.]+)$");
match = rx.match(iName);
if (match.hasMatch()) {
return QString("s%1")
.arg(formatNumber(match.captured(1).toDouble() * iScale, iPercision));
}
rx.setPattern("^rect([0-9.]+)x([0-9.]+)$");
match = rx.match(iName);
if (match.hasMatch()) {
return QString("rect%1x%2")
.arg(formatNumber(match.captured(1).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(2).toDouble() * iScale, iPercision));
}
rx.setPattern("^oval([0-9.]+)x([0-9.]+)$");
match = rx.match(iName);
if (match.hasMatch()) {
return QString("oval%1x%2")
.arg(formatNumber(match.captured(1).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(2).toDouble() * iScale, iPercision));
}
rx.setPattern("^thr([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9]+)x([0-9.]+)$");
match = rx.match(iName);
if (match.hasMatch()) {
return QString("thr%1x%2x%3x%4x%5")
.arg(formatNumber(match.captured(1).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(2).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(3).toDouble() * iScale, iPercision))
.arg(match.captured(4))
.arg(formatNumber(match.captured(5).toDouble() * iScale, iPercision));
}
rx.setPattern("^ths([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9]+)x([0-9.]+)$");
match = rx.match(iName);
if (match.hasMatch()) {
return QString("ths%1x%2x%3x%4x%5")
.arg(formatNumber(match.captured(1).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(2).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(3).toDouble() * iScale, iPercision))
.arg(match.captured(4))
.arg(formatNumber(match.captured(5).toDouble() * iScale, iPercision));
}
rx.setPattern("^s_ths([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9]+)x([0-9.]+)$");
match = rx.match(iName);
if (match.hasMatch()) {
return QString("s_ths%1x%2x%3x%4x%5")
.arg(formatNumber(match.captured(1).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(2).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(3).toDouble() * iScale, iPercision))
.arg(match.captured(4))
.arg(formatNumber(match.captured(5).toDouble() * iScale, iPercision));
}
rx.setPattern("^s_tho([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9]+)x([0-9.]+)$");
match = rx.match(iName);
if (match.hasMatch()) {
return QString("s_tho%1x%2x%3x%4x%5")
.arg(formatNumber(match.captured(1).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(2).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(3).toDouble() * iScale, iPercision))
.arg(match.captured(4))
.arg(formatNumber(match.captured(5).toDouble() * iScale, iPercision));
}
rx.setPattern("^donut_r([0-9.]+)x([0-9.]+)$");
match = rx.match(iName);
if (match.hasMatch()) {
return QString("donut_r%1x%2")
.arg(formatNumber(match.captured(1).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(2).toDouble() * iScale, iPercision));
}
rx.setPattern("^donut_s([0-9.]+)x([0-9.]+)$");
match = rx.match(iName);
if (match.hasMatch()) {
return QString("donut_s%1x%2")
.arg(formatNumber(match.captured(1).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(2).toDouble() * iScale, iPercision));
}
rx.setPattern("^di([0-9.]+)x([0-9.]+)$");
match = rx.match(iName);
if (match.hasMatch()) {
return QString("di%1x%2")
.arg(formatNumber(match.captured(1).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(2).toDouble() * iScale, iPercision));
}
rx.setPattern("^oct([0-9.]+)x([0-9.]+)x([0-9.]+)$");
match = rx.match(iName);
if (match.hasMatch()) {
return QString("oct%1x%2x%3")
.arg(formatNumber(match.captured(1).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(2).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(3).toDouble() * iScale, iPercision));
}
rx.setPattern("^hex_l([0-9.]+)x([0-9.]+)x([0-9.]+)$");
match = rx.match(iName);
if (match.hasMatch()) {
return QString("hex_l%1x%2x%3")
.arg(formatNumber(match.captured(1).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(2).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(3).toDouble() * iScale, iPercision));
}
rx.setPattern("^hex_s([0-9.]+)x([0-9.]+)x([0-9.]+)$");
match = rx.match(iName);
if (match.hasMatch()) {
return QString("hex_s%1x%2x%3")
.arg(formatNumber(match.captured(1).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(2).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(3).toDouble() * iScale, iPercision));
}
rx.setPattern("^bfr([0-9.]+)$");
match = rx.match(iName);
if (match.hasMatch()) {
return QString("bfr%1")
.arg(formatNumber(match.captured(1).toDouble() * iScale, iPercision));
}
rx.setPattern("^bfs([0-9.]+)$");
match = rx.match(iName);
if (match.hasMatch()) {
return QString("bfs%1")
.arg(formatNumber(match.captured(1).toDouble() * iScale, iPercision));
}
rx.setPattern("^tri([0-9.]+)x([0-9.]+)$");
match = rx.match(iName);
if (match.hasMatch()) {
return QString("tri%1x%2")
.arg(formatNumber(match.captured(1).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(2).toDouble() * iScale, iPercision));
}
rx.setPattern("^oval_h([0-9.]+)x([0-9.]+)$");
match = rx.match(iName);
if (match.hasMatch()) {
return QString("oval_h%1x%2")
.arg(formatNumber(match.captured(1).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(2).toDouble() * iScale, iPercision));
}
rx.setPattern("^rect([0-9.]+)x([0-9.]+)xr([0-9.]+)(x([1-4]+))?$");
match = rx.match(iName);
if (match.hasMatch()) {
return QString("rect%1x%2xr%3%4")
.arg(formatNumber(match.captured(1).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(2).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(3).toDouble() * iScale, iPercision))
.arg(match.captured(4));
}
rx.setPattern("^rect([0-9.]+)x([0-9.]+)xc([0-9.]+)(x([1-4]+))?$");
match = rx.match(iName);
if (match.hasMatch()) {
return QString("rect%1x%2xc%3%4")
.arg(formatNumber(match.captured(1).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(2).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(3).toDouble() * iScale, iPercision))
.arg(match.captured(4));
}
rx.setPattern("^sr_ths([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9]+)x([0-9.]+)$");
match = rx.match(iName);
if (match.hasMatch()) {
return QString("sr_ths%1x%2x%3x%4x%5")
.arg(formatNumber(match.captured(1).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(2).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(3).toDouble() * iScale, iPercision))
.arg(match.captured(4))
.arg(formatNumber(match.captured(5).toDouble() * iScale, iPercision));
}
rx.setPattern("^rc_ths([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9]+)x([0-9.]+)x([0-9.]+)$");
match = rx.match(iName);
if (match.hasMatch()) {
return QString("rc_ths%1x%2x%3x%4x%5x%6")
.arg(formatNumber(match.captured(1).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(2).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(3).toDouble() * iScale, iPercision))
.arg(match.captured(4))
.arg(formatNumber(match.captured(5).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(6).toDouble() * iScale, iPercision));
}
rx.setPattern("^rc_tho([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9]+)x([0-9.]+)x([0-9.]+)$");
match = rx.match(iName);
if (match.hasMatch()) {
return QString("rc_tho%1x%2x%3x%4x%5x%6")
.arg(formatNumber(match.captured(1).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(2).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(3).toDouble() * iScale, iPercision))
.arg(match.captured(4))
.arg(formatNumber(match.captured(5).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(6).toDouble() * iScale, iPercision));
}
rx.setPattern("^moire([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9.]+)$");
match = rx.match(iName);
if (match.hasMatch()) {
return QString("moire%1x%2x%3x%4x%5x%6")
.arg(formatNumber(match.captured(1).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(2).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(3).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(4).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(5).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(6).toDouble() * iScale, iPercision));
}
rx.setPattern("^el([0-9.]+)x([0-9.]+)$");
match = rx.match(iName);
if (match.hasMatch()) {
return QString("el%1x%2")
.arg(formatNumber(match.captured(1).toDouble() * iScale, iPercision))
.arg(formatNumber(match.captured(2).toDouble() * iScale, iPercision));
}
return iName;
}
TITAN_END_NAMESPACE
#ifndef TITAN_PCBCAM_SYMBOLFACTORY_H
#define TITAN_PCBCAM_SYMBOLFACTORY_H
#include "../titanpcbcamglobal.h"
TITAN_BEGIN_NAMESPACE
class PcbCamSymbol;
class TITAN_PCBCAM_EXPORT PcbCamSymbolFactory
{
public:
static PcbCamSymbol *create(const QString &iName);
static QString symbolScaledName(const QString &iName, double iScale, int iPercision=6);
};
TITAN_END_NAMESPACE
#endif // TITAN_PCBCAM_SYMBOLFACTORY_H
#include "util.h"
#include <QTransform>
#include <QPainterPath>
#include <QtMath>
#include <QPainter>
#include <QDebug>
#include <QElapsedTimer>
#include <QMap>
#include <QString>
#include <QRegularExpression>
#include "./common.h"
#include "./feature.h"
TITAN_BEGIN_NAMESPACE
static QMap<int, QString> WEEK_DAY_STRING {
{1, "MONDAY"},
{2, "TUESDAY"},
{3, "WEDNESDAY"},
{4, "THURSDAY"},
{5, "FRIDAY"},
{6, "SATURDAY"},
{7, "SUNDAY"}
};
QString PcbCamUtil::formatNumber(double iNumber, int iPercision)
{
QString res = QString::number(iNumber, 'f', iPercision);
if (res.contains(".")) {
while (true) {
if (res.at(res.length() - 1) == '0') {
res.chop(1);
}
else {
if (res.at(res.length() - 1) == '.') {
res.chop(1);
}
break;
}
}
}
return res;
}
QRectF PcbCamUtil::calcPathArc(const QPointF &iPs, const QPointF &iPe, const QPointF &iPc, bool iCw, double *oStartAngle, double *oSweepLength)
{
qreal xs = iPs.x();
qreal ys = iPs.y();
qreal xe = iPe.x();
qreal ye = iPe.y();
qreal xc = iPc.x();
qreal yc = iPc.y();
qreal sax = xs - xc, say = ys - yc;
qreal eax = xe - xc, eay = ye - yc;
qreal r = qSqrt(sax * sax + say * say);
qreal sa = qAtan2(-say, sax);
qreal ea = qAtan2(-eay, eax);
if (iCw) {
if (ea <= sa) {
ea += 2.0 * M_PI;
}
}
else {
if (sa <= ea) {
sa += 2.0 * M_PI;
}
}
*oStartAngle = sa * (180.0 / M_PI) ;
*oSweepLength = (ea - sa) * (180.0 / M_PI);
return QRectF(xc - r, yc - r, r * 2.0, r * 2.0);
}
QPainterPath PcbCamUtil::arc2path(const QPointF &iPs, const QPointF &iPe, const QPointF &iPc, bool iCw)
{
QPainterPath path;
double startAngle;
double sweepLength;
auto rect = calcPathArc(iPs, iPe, iPc, iCw, &startAngle, &sweepLength);
path.arcMoveTo(rect, startAngle);
path.arcTo(rect, startAngle, sweepLength);
return path;
}
QPainterPath PcbCamUtil::line2path(const QLineF &iLine)
{
QPainterPath path;
path.moveTo(iLine.p1());
path.lineTo(iLine.p2());
return path;
}
QPen PcbCamUtil::sym2pen(PcbCamSymbol *iSymbol)
{
QPen pen;
if (iSymbol->type() == PcbCam::Sym_R) {
const PcbCamSymbolR *sym = static_cast<const PcbCamSymbolR*>(iSymbol);
pen.setCapStyle(Qt::RoundCap);
pen.setWidthF(sym->size() > 0.0 ? sym->size() : 0.00001);
}
else if (iSymbol->type() == PcbCam::Sym_S) {
const PcbCamSymbolR *sym = static_cast<const PcbCamSymbolR*>(iSymbol);
pen.setCapStyle(Qt::SquareCap);
pen.setWidthF(sym->size() > 0.0 ? sym->size() : 0.00001);
}
else if (iSymbol->type() == PcbCam::Sym_DonutR) {
const PcbCamSymbolDonutR *sym = static_cast<const PcbCamSymbolDonutR*>(iSymbol);
pen.setCapStyle(Qt::RoundCap);
pen.setWidthF(sym->outerDiam() > 0.0 ? sym->outerDiam() : 0.00001);
}
else if (iSymbol->type() == PcbCam::Sym_DonutS) {
const PcbCamSymbolDonutS *sym = static_cast<const PcbCamSymbolDonutS*>(iSymbol);
pen.setCapStyle(Qt::SquareCap);
pen.setWidthF(sym->outerDiam() > 0.0 ? sym->outerDiam() : 0.00001);
}
else if (iSymbol->type() == PcbCam::Sym_Rect) {
pen.setCapStyle(Qt::SquareCap);
pen.setWidthF(qMin(iSymbol->boundingRect().width(), iSymbol->boundingRect().height()));
}
else {
pen.setCapStyle(Qt::RoundCap);
pen.setWidthF(qMin(iSymbol->boundingRect().width(), iSymbol->boundingRect().height()));
}
return pen;
}
QTransform PcbCamUtil::matrix(const QPointF &iPos, PcbCam::Orient iOrient)
{
if (iOrient == PcbCam::Orient_N_0) {
return QTransform(1, 0, 0, 1, iPos.x(), iPos.y());
}
else if (iOrient == PcbCam::Orient_N_90) {
return QTransform(0, -1, 1, 0, iPos.x(), iPos.y());
}
else if (iOrient == PcbCam::Orient_N_180) {
return QTransform(-1, 0, 0, -1, iPos.x(), iPos.y());
}
else if (iOrient == PcbCam::Orient_N_270) {
return QTransform(0, 1, -1, 0, iPos.x(), iPos.y());
}
else if (iOrient == PcbCam::Orient_Y_0) {
return QTransform(-1, 0, 0, 1, iPos.x(), iPos.y());
}
else if (iOrient == PcbCam::Orient_Y_90) {
return QTransform(0, -1, -1, 0, iPos.x(), iPos.y());
}
else if (iOrient == PcbCam::Orient_Y_180) {
return QTransform(1, 0, 0, -1, iPos.x(), iPos.y());
}
else if (iOrient == PcbCam::Orient_Y_270) {
return QTransform(0, 1, 1, 0, iPos.x(), iPos.y());
}
return QTransform(1, 0, 0, 1, iPos.x(), iPos.y());
}
QTransform PcbCamUtil::matrix(const QPointF &iPos, const QPointF &iDatum, qreal iAngle, bool iMirror)
{
QTransform mat1, mat2, mat3, mat4;
mat1.translate(-iDatum.x() , -iDatum.y());
mat2.rotate((iAngle > 0) ? 360.0 - iAngle : 0);
if (iMirror) mat3.scale(-1, 1);
mat4.translate(iPos.x(), iPos.y());
return mat1 * mat2 * mat3* mat4 ;
}
void PcbCamUtil::drawFeatures(QPainter *painter,
const QList<PcbCamFeature *> &iFeatures,
PcbCam::Polarity iPolarity,
const QColor &iColor,
const QTransform &iMatrix,
const QRectF &iSceneRect,
PcbCam::DisplayOptions iDispOption,
PcbCamJob *iJob,
PcbCamStep *iStep,
PcbCamLayer *iLayer)
{
painter->save();
painter->setTransform(iMatrix);
QSizeF minSize = iMatrix.inverted().mapRect(QRectF(0, 0, 2, 2)).size();
QPainterPath clipPath;
clipPath.addRect(iSceneRect);
//边线Pen
QPen outlinePen(iColor);
outlinePen.setWidth(1);
outlinePen.setCosmetic(true);
outlinePen.setCapStyle(Qt::RoundCap);
outlinePen.setJoinStyle(Qt::RoundJoin);
QPen pointPen(iColor);
pointPen.setWidth(1);
pointPen.setCosmetic(true);
pointPen.setCapStyle(Qt::SquareCap);
//填充Brush
QBrush fillBrush(iColor);
//NegativeBrush
QBrush negativeBrush(iColor);
negativeBrush.setStyle(Qt::Dense4Pattern);
negativeBrush.setTransform(iMatrix.inverted());
QRectF featrect;
for ( PcbCamFeature *feat : iFeatures) {
featrect = feat->boundingRect();
if (!iSceneRect.intersects(featrect)) continue;
PcbCam::Polarity featPolarity = (iPolarity == PcbCam::Positive)
? feat->polarity()
: (feat->polarity() == PcbCam::Positive)
? PcbCam::Negative : PcbCam::Positive;
if (featPolarity == PcbCam::Negative && iDispOption & PcbCam::DisplayFill && !(iDispOption & PcbCam::DisplayNegative)) {
painter->setCompositionMode(QPainter::CompositionMode_Clear);
}
else {
painter->setCompositionMode(QPainter::CompositionMode_SourceOver);
}
if (featrect.width() < minSize.width() && featrect.height() < minSize.height()) {
painter->setPen(pointPen);
painter->drawPoint(featrect.center());
continue;
}
if (iDispOption & PcbCam::DisplayFill) { //填充模式
painter->setBrush(fillBrush);
painter->setPen(Qt::NoPen);
}
else {
painter->setPen(outlinePen);
painter->setBrush(Qt::NoBrush);
}
if ((feat->type() == PcbCam::LineFeature || feat->type() == PcbCam::ArcFeature)
&& (feat->symbol()->boundingRect().width() < minSize.width() || feat->symbol()->boundingRect().height() < minSize.width()))
{
// 处理细线的情况
painter->setPen(outlinePen);
painter->setBrush(Qt::NoBrush);
if (feat->type() == PcbCam::LineFeature) {
const PcbCamFeatureLine *f = static_cast<const PcbCamFeatureLine*>(feat);
painter->drawPath(PcbCamUtil::line2path(f->line()));
}
else if (feat->type() == PcbCam::ArcFeature) {
const PcbCamFeatureArc *f = static_cast<const PcbCamFeatureArc*>(feat);
painter->drawPath(PcbCamUtil::arc2path(f->ps(), f->pe(), f->pc(), f->cw()));
}
continue;
}
else if (featrect.width() < minSize.width() || featrect.height() < minSize.height()) {
painter->drawRect(featrect);
continue;
}
if (feat->type() == PcbCam::PadFeature && feat->symbol()->type() == PcbCam::Sym_User) {
const PcbCamFeaturePad *f = static_cast<const PcbCamFeaturePad*>(feat);
const PcbCamSymbolUser *s = static_cast<const PcbCamSymbolUser*>(f->symbol());
QTransform mat = matrix(f->pos(), f->orient()) * iMatrix ;
drawFeatures(painter, s->features(), featPolarity, iColor,
mat, mat.inverted().mapRect(iMatrix.mapRect(iSceneRect)),
iDispOption, iJob, iStep, iLayer);
continue;
}
else if (feat->type() == PcbCam::PathFeature) {
const PcbCamFeaturePath *f = static_cast<const PcbCamFeaturePath*>(feat);
QPen pathpen(iColor);
pathpen.setWidth(f->width());
pathpen.setCosmetic(true);
pathpen.setCapStyle(Qt::RoundCap);
pathpen.setJoinStyle(Qt::RoundJoin);
painter->setPen(pathpen);
painter->setBrush(Qt::NoBrush);
painter->drawPath(f->path());
continue;
}
else if (feat->type() == PcbCam::ComponentFeature) {
const PcbCamFeatureComponent *f = static_cast<const PcbCamFeatureComponent*>(feat);
const PcbCamSymbolUser *s = static_cast<const PcbCamSymbolUser*>(f->symbol());
QTransform mat = matrix(f->pos(), QPointF(0, 0), f->rotation(), f->mirror()) * iMatrix ;
drawFeatures(painter, s->features(), featPolarity, iColor,
mat, mat.inverted().mapRect(iMatrix.mapRect(iSceneRect)),
iDispOption, iJob, iStep, iLayer);
painter->save();
QTransform txtmat;
txtmat.scale(100, -100);
painter->scale(0.01, -0.01);
QFont font;
font.setFamily(painter->font().family());
font.setPixelSize(2);
painter->setFont(font);
painter->setPen(QColor(iColor));
painter->drawText(txtmat.mapRect(f->boundingRect()), Qt::AlignCenter|Qt::TextDontClip, f->compName());
painter->restore();
continue;
}
else if (feat->type() == PcbCam::TextFeature) {
PcbCamFeatureText *f = static_cast< PcbCamFeatureText*>(feat);
if (iStep != nullptr && iLayer != nullptr) {
//替换动态文字
if (f->text().contains("$$")) {
QString old_dynamic_text = f->dynamicText();
QString new_dynamic_text = f->text();
if (iDispOption & PcbCam::DisplayTextValue) {
//找出需替换的替换字符
const QDate &date = QDate::currentDate();
const QTime &time = QTime::currentTime();
QRegularExpression rx("\\$\\$(\\S+)");
int replace_offset = 0;
auto match_iter = rx.globalMatch(new_dynamic_text);
while (match_iter.hasNext()) {
auto match = match_iter.next();
QString attrname = match.captured(1).toLower();
QString varname = match.captured(0);
int capture_start = match.capturedStart(0);
QString replacement;
if (attrname == "job" && iJob != nullptr) {
replacement = iJob->jobname().toUpper();
}
else if (attrname == "step" && iStep != nullptr) {
replacement = iStep->name().toUpper();
}
else if (attrname == "layer" && iLayer != nullptr) {
replacement = iLayer->name().toUpper();
}
else if (attrname == "x_mm") {
//TODO 目前都会后补7个零,后续需把后面的零去除
replacement = QString("%1").arg(f->pos().x() * 25.4, 0, 'f', 7);
}
else if (attrname == "y_mm") {
replacement = QString("%1").arg(f->pos().y() * 25.4, 0, 'f', 7);
}
else if (attrname == "x") {
replacement = QString("%1").arg(f->pos().x(), 0, 'f', 7);
}
else if (attrname == "y") {
replacement = QString("%1").arg(f->pos().y() , 0, 'f', 7);
}
else if (attrname == "date-mmddyy" || attrname == "date") {
replacement = QString().asprintf("%02d/%02d/%02d", date.month(), date.day(), date.year()%100);
}
else if (attrname == "date-ddmmyy" ) {
replacement = QString().asprintf("%02d/%02d/%02d", date.day(), date.month(), date.year()%100);
}
else if (attrname == "date-mmddyyyy") {
replacement = QString().asprintf("%02d/%02d/%04d", date.month(), date.day(), date.year());
}
else if (attrname == "date-ddmmyyyy") {
replacement = QString().asprintf("%02d/%02d/%04d", date.day(), date.month(), date.year());
}
else if (attrname == "dd") {
replacement = QString().asprintf("%02d", date.day());
}
else if (attrname == "mm") {
replacement = QString().asprintf("%02d", date.month());
}
else if (attrname == "yy") {
replacement = QString().asprintf("%02d", date.year()%100);
}
else if (attrname == "yyyy") {
replacement = QString().asprintf("%04d", date.year());
}
else if (attrname == "week-day") {
replacement = WEEK_DAY_STRING.value(date.dayOfWeek());
}
else if (attrname == "ww") {
replacement = QString().asprintf("%02d", date.weekNumber());
}
else if (attrname == "time") {
replacement = QString().asprintf("%02d:%02d", time.hour(), time.minute());
}
else if (f->hasAttr(attrname)) {
replacement = f->attr(attrname).toString().toUpper();
}
else if (iLayer != nullptr && iLayer->hasAttr(attrname)) {
replacement = iLayer->attr(attrname).toString().toUpper();
}
else if (iStep != nullptr && iStep->hasAttr(attrname)) {
replacement = iStep->attr(attrname).toString().toUpper();
}
else if (iJob != nullptr && iJob->hasJobAttr(attrname)) {
replacement = iJob->jobAttr(attrname).toString().toUpper();
}
else {
replacement = varname;
}
new_dynamic_text.replace(capture_start + replace_offset, varname.length(), replacement);
replace_offset += replacement.length() - varname.length();
}
}
if (new_dynamic_text != old_dynamic_text) {
f->setDynamicText(new_dynamic_text);
}
}
}
QTransform mat = matrix(f->pos(), f->orient()) * iMatrix ;
drawFeatures(painter, f->features(), featPolarity, iColor,
mat, mat.inverted().mapRect(iMatrix.mapRect(iSceneRect)),
iDispOption, iJob, iStep, iLayer);
continue;
}
else if ((feat->type() == PcbCam::LineFeature || feat->type() == PcbCam::ArcFeature)
&& ((feat->symbol()->type() == PcbCam::Sym_R && static_cast<PcbCamSymbolR*>(feat->symbol())->size() <= 0.0000001)
|| (feat->symbol()->type() == PcbCam::Sym_S && static_cast<PcbCamSymbolS*>(feat->symbol())->size() <= 0.0000001)))
{
// 处理r0 s0的情况
painter->setPen(outlinePen);
painter->setBrush(Qt::NoBrush);
if (feat->type() == PcbCam::LineFeature) {
const PcbCamFeatureLine *f = static_cast<const PcbCamFeatureLine*>(feat);
painter->drawPath(PcbCamUtil::line2path(f->line()));
}
else if (feat->type() == PcbCam::ArcFeature) {
const PcbCamFeatureArc *f = static_cast<const PcbCamFeatureArc*>(feat);
painter->drawPath(PcbCamUtil::arc2path(f->ps(), f->pe(), f->pc(), f->cw()));
}
continue;
}
QTransform tmpmat;
if (iDispOption & PcbCam::DisplayOutline) { //边线模式
painter->drawPath(feat->shape().intersected(clipPath));
if (feat->type() == PcbCam::LineFeature) {
}
else if (feat->type() == PcbCam::ArcFeature) {
}
}
else if (iDispOption & PcbCam::DisplaySketeon) { //中心线模式
if (feat->type() == PcbCam::LineFeature) {
const PcbCamFeatureLine *f = static_cast<const PcbCamFeatureLine*>(feat);
painter->drawPath(PcbCamUtil::line2path(f->line()));
}
else if (feat->type() == PcbCam::ArcFeature) {
const PcbCamFeatureArc *f = static_cast<const PcbCamFeatureArc*>(feat);
painter->drawPath(PcbCamUtil::arc2path(f->ps(), f->pe(), f->pc(), f->cw()));
}
else {
painter->drawPath(feat->shape().intersected(clipPath));
}
}
else { //填充模式
if (featPolarity == PcbCam::Negative && (iDispOption & PcbCam::DisplayNegative)) {
painter->setBrush(fillBrush);
painter->setCompositionMode(QPainter::CompositionMode_Clear);
painter->drawPath(feat->shape().intersected(clipPath));
painter->setBrush(negativeBrush);
painter->setCompositionMode(QPainter::CompositionMode_SourceOver);
painter->drawPath(feat->shape().intersected(clipPath));
}
else {
painter->setBrush(fillBrush);
painter->drawPath(feat->shape().intersected(clipPath));
}
}
}
painter->restore();
}
int PcbCamUtil::orient2angle(PcbCam::Orient iOrient)
{
switch (iOrient) {
case PcbCam::Orient_N_0:
case PcbCam::Orient_Y_0:
return 0;
case PcbCam::Orient_N_90:
case PcbCam::Orient_Y_90:
return 90;
case PcbCam::Orient_N_180:
case PcbCam::Orient_Y_180:
return 180;
case PcbCam::Orient_N_270:
case PcbCam::Orient_Y_270:
return 270;
default:
return 0;
}
}
bool PcbCamUtil::orient2mirror(PcbCam::Orient iOrient)
{
return (iOrient == PcbCam::Orient_Y_0
|| iOrient == PcbCam::Orient_Y_90
|| iOrient == PcbCam::Orient_Y_180
|| iOrient == PcbCam::Orient_Y_270 );
}
bool PcbCamUtil::isFeatMatchFilter(PcbCamFeature *iFeat,
PcbCam::FeatureTypes iTypes,
PcbCam::Polarities iPolarities,
bool iIsFilterProfile,
PcbCam::ProfileRegions iProfileRegion,
const QPainterPath &iProfilePath,
bool iIsFilterIncludeSymbol,
QSet<PcbCamSymbol *> iIncludeSymbols,
bool iIsFilterExcludeSymbol,
QSet<PcbCamSymbol *> iExcludeSymbols,
bool iIsFilterIncludeAttr,
QList<PcbCam::AttrCompareInfo> iIncludeAttrs,
PcbCam::LogicOperator iIncludeAttrLogic,
bool iIsFilterExcludeAttr,
QList<PcbCam::AttrCompareInfo> iExcludeAttrs,
PcbCam::LogicOperator iExcludeAttrLogic)
{
bool feat_match = false;
if ((iTypes & iFeat->type())
&& (iPolarities & iFeat->polarity())
&& (!iIsFilterIncludeSymbol || iIncludeSymbols.contains(iFeat->symbol()))
&& (!iIsFilterExcludeSymbol || iFeat->symbol() == nullptr || !iExcludeSymbols.contains(iFeat->symbol()))
)
{
auto featattr = iFeat->attr();
bool include_attr_match = true;
if (iIsFilterIncludeAttr) {
include_attr_match = (iIncludeAttrLogic == PcbCam::Logic_And);
for (auto attrcmp : iIncludeAttrs) {
bool attrmatch = (featattr.contains(attrcmp.name)
&& ((attrcmp.type == 0)
|| (attrcmp.type == 1 && featattr.value(attrcmp.name).toString() == attrcmp.strValue)
|| (attrcmp.type == 2 && featattr.value(attrcmp.name).toDouble() >= attrcmp.minValue && featattr.value(attrcmp.name).toDouble() <= attrcmp.maxValue)));
if (iIncludeAttrLogic == PcbCam::Logic_And && !attrmatch) {
include_attr_match = false;
break;
}
else if (iIncludeAttrLogic == PcbCam::Logic_Or && attrmatch) {
include_attr_match = true;
break;
}
}
}
bool exclude_attr_match = false;
if (include_attr_match) {
if (iIsFilterExcludeAttr) {
exclude_attr_match = (iExcludeAttrLogic == PcbCam::Logic_And);
for (auto attrcmp : iExcludeAttrs) {
bool attrmatch = (featattr.contains(attrcmp.name)
&& ((attrcmp.type == 0)
|| (attrcmp.type == 1 && featattr.value(attrcmp.name).toString() == attrcmp.strValue)
|| (attrcmp.type == 2 && featattr.value(attrcmp.name).toDouble() >= attrcmp.minValue && featattr.value(attrcmp.name).toDouble() <= attrcmp.maxValue)));
if (iExcludeAttrLogic == PcbCam::Logic_And && !attrmatch) {
exclude_attr_match = false;
break;
}
else if (iExcludeAttrLogic == PcbCam::Logic_Or && attrmatch) {
exclude_attr_match = true;
break;
}
}
}
}
feat_match = (include_attr_match && !exclude_attr_match);
}
if (!feat_match) return false;
if (!iIsFilterProfile) return true;
if (iProfileRegion == PcbCam::AllProfile) {
return true;
}
else if (iProfileRegion == PcbCam::InProfile) {
return iFeat->shape().intersects(iProfilePath);
}
else if (iProfileRegion == PcbCam::OutProfile) {
return !iFeat->shape().intersects(iProfilePath);
}
return true;
}
QPainterPath PcbCamUtil::findClosedPath(const QList<PcbCamFeature *> &iFeatures, double iTol)
{
auto allpaths = findPolyline(iFeatures, iTol);
QPainterPath finalpath;
double max_area = 0.0;
for (auto path : allpaths) {
if (path.elementCount() >= 3
&& qAbs(path.elementAt(0).x - path.elementAt(path.elementCount()-1).x) <= iTol
&& qAbs(path.elementAt(0).y - path.elementAt(path.elementCount()-1).y) <= iTol)
{
auto rect = path.boundingRect();
auto area = rect.width() * rect.height();
if (area > max_area) {
finalpath = path;
max_area = area;
}
}
}
finalpath.closeSubpath();
return finalpath;
}
QList<QPainterPath> PcbCamUtil::findPolyline(const QList<PcbCamFeature *> &iFeatures, double iTol)
{
QList<PcbCamFeature*> feats;
for (auto f: iFeatures) {
if (f->type() == PcbCam::LineFeature || f->type() == PcbCam::ArcFeature) {
feats << f;
}
}
auto appendFeatureToPath = [](QPainterPath *iPath, PcbCamFeature *iFeat, bool iInvert = false){
if (iFeat->type() == PcbCam::LineFeature) {
auto feat = static_cast<PcbCamFeatureLine*>(iFeat);
auto ps = iInvert ? feat->line().p2() : feat->line().p1();
auto pe = iInvert ? feat->line().p1() : feat->line().p2();
if (iPath->isEmpty()) {
iPath->moveTo(ps);
iPath->lineTo(pe);
}
else {
iPath->lineTo(pe);
}
}
else if (iFeat->type() == PcbCam::ArcFeature) {
auto feat = static_cast<PcbCamFeatureArc*>(iFeat);
auto ps = iInvert ? feat->pe() : feat->ps();
auto pe = iInvert ? feat->ps() : feat->pe();
auto pc = feat->pc();
bool cw = iInvert ? !feat->cw() : feat->cw();
double startAngle;
double sweepLength;
auto rect = calcPathArc(ps, pe, pc, cw, &startAngle, &sweepLength);
if (iPath->isEmpty()) {
iPath->arcMoveTo(rect, startAngle);
iPath->arcTo(rect, startAngle, sweepLength);
}
else {
iPath->arcTo(rect, startAngle, sweepLength);
}
}
};
QList<QPainterPath> allpaths;
QPainterPath path;
QPointF lastCoord;
while (feats.count() > 0) {
bool findnext = false;
bool invert = false;
QPointF ps, pe;
for (int n = 0; n < feats.count(); n++) {
auto feat = feats[n];
if (feat->type() == PcbCam::LineFeature) {
auto linefeat = static_cast<PcbCamFeatureLine*>(feat);
ps = linefeat->line().p1();
pe = linefeat->line().p2();
}
else if (feat->type() == PcbCam::ArcFeature) {
auto arcfeat = static_cast<PcbCamFeatureArc*>(feat);
ps = arcfeat->ps();
pe = arcfeat->pe();
}
if (path.isEmpty()) {
findnext = true;
invert = false;
}
else if (qAbs(lastCoord.x() - ps.x()) <= iTol && qAbs(lastCoord.y() - ps.y()) <= iTol) {
findnext = true;
invert = false;
}
else if (qAbs(lastCoord.x() - pe.x()) <= iTol && qAbs(lastCoord.y() - pe.y()) <= iTol) {
findnext = true;
invert = true;
}
if (findnext) {
appendFeatureToPath(&path, feat, invert);
feats.removeAt(n);
lastCoord = invert ? ps : pe;
break;
}
}
if (!findnext) {
if (!path.isEmpty()) {
allpaths.append(path);
}
path = QPainterPath();
}
}
if (!path.isEmpty()) {
allpaths.append(path);
}
return allpaths;
}
TITAN_END_NAMESPACE
#ifndef TITAN_PCBCAM_UTIL_H
#define TITAN_PCBCAM_UTIL_H
#include "../titanpcbcamglobal.h"
#include <QRectF>
#include "./feature.h"
#include "./symbol.h"
#include "./job.h"
#include "./step.h"
#include "./layer.h"
#include "./common.h"
#include <QPainterPath>
#include <QPen>
TITAN_BEGIN_NAMESPACE
class TITAN_PCBCAM_EXPORT PcbCamUtil
{
public:
static QString formatNumber(double iNumber, int iPercision = 6);
static QRectF calcPathArc(const QPointF &iPs, const QPointF &iPe, const QPointF &iPc, bool iCw, double *oStartAngle, double *oSweepLength);
static QPainterPath arc2path(const QPointF &iPs, const QPointF &iPe, const QPointF &iPc, bool iCw);
static QPainterPath line2path(const QLineF &iLine);
static QPen sym2pen(PcbCamSymbol *iSymbol);
static QTransform matrix(const QPointF &iPos, PcbCam::Orient iOrient);
static QTransform matrix(const QPointF &iPos, const QPointF &iDatum, qreal iAngle, bool iMirror);
static void drawFeatures(QPainter *painter,
const QList<PcbCamFeature*> &iFeatures,
PcbCam::Polarity iPolarity,
const QColor &iColor,
const QTransform &iMatrix,
const QRectF &iSceneRect,
PcbCam::DisplayOptions iDispOption = PcbCam::DisplayFill,
PcbCamJob *iJob = nullptr,
PcbCamStep *iStep = nullptr,
PcbCamLayer *iLayer = nullptr);
static int orient2angle(PcbCam::Orient iOrient);
static bool orient2mirror(PcbCam::Orient iOrient);
static bool isFeatMatchFilter(PcbCamFeature *iFeat,
PcbCam::FeatureTypes iTypes,
PcbCam::Polarities iPolarities,
bool iIsFilterProfile,
PcbCam::ProfileRegions iProfileRegion,
const QPainterPath &iProfilePath,
bool iIsFilterIncludeSymbol,
QSet<PcbCamSymbol *> iIncludeSymbols,
bool iIsFilterExcludeSymbol,
QSet<PcbCamSymbol *> iExcludeSymbols,
bool iIsFilterIncludeAttr,
QList<PcbCam::AttrCompareInfo> iIncludeAttrs,
PcbCam::LogicOperator iIncludeAttrLogic,
bool iIsFilterExcludeAttr,
QList<PcbCam::AttrCompareInfo> iExcludeAttrs,
PcbCam::LogicOperator iExcludeAttrLogic);
//点到线段的最短距离
static double point2segDist(double x, double y, double x1, double y1, double x2, double y2);
//点到多段线最短距离
static double point2polylineDist(const QPointF &p, const QPolygonF &polyline);
//查找封闭的painterpath
static QPainterPath findClosedPath(const QList<PcbCamFeature*> &iFeatures, double iTol = 0.0001);
//查找polyline
static QList<QPainterPath> findPolyline(const QList<PcbCamFeature*> &iFeatures, double iTol = 0.0001);
};
TITAN_END_NAMESPACE
#endif // TITAN_PCBCAM_UTIL_H
#----------------项目设置----------------------------------------------------
PROJECT_NAME = titan_pcbcam
ROOT_DIR = $$PWD/../../
HEADER_DIR = titan/pcbcam
DLL_LIBS =
STATIC_LIBS =
VERSION = 2.0.2
#----------------编译设置---------------------------------------------------
TEMPLATE = lib
##CONFIG += staticlib
### Library Export
CONFIG(staticlib) : DEFINES += $$upper($${PROJECT_NAME})_STATIC
else : DEFINES += $$upper($${PROJECT_NAME})_SHARED
TARGET = $$qtLibraryTarget($${PROJECT_NAME})
###添加QT库依赖库
QT += core core-private gui widgets qml
TRANSLATIONS += $${PROJECT_NAME}_en.ts $${PROJECT_NAME}_zhcn.ts $${PROJECT_NAME}_zhtw.ts
QM_LIST = $$PWD/*.qm
#-----------------File List----------------------------------------------
SOURCES +=
HEADERS += \
titanpcbcamglobal.h
OTHER_FILES +=
RESOURCES +=
DISTFILES +=
include(pcbcam.pri)
#----------------其它编译设定----------------------------------------------
SRC_PWD = $$PWD
include($${ROOT_DIR}/shared/shared.pri)
### 导出头文件 ###
equals(TEMPLATE, "lib") {
headerlist = core widget parser
for(hf, headerlist) {
hpath = $$system_path($${DIST_HEADER}/$${hf})
!exists($${hpath}){
mkpath($${hpath})
}
win32 {
system(copy $$system_path($${SRC_PWD}/$${hf}/*.h) $${hpath})
} else {
system(cp $$system_path($${SRC_PWD}/$${hf}/*.h) $${hpath})
}
}
}
# Version
CONFIG += skip_target_version_ext
QMAKE_TARGET_PRODUCT = titan_pcbcam
QMAKE_TARGET_COMPANY = TopLinker Co.,Ltd.
QMAKE_TARGET_COPYRIGHT = Copyright(C) 2020 TopLinker
############################### COPYRIGHT ##################################
# #
# Copyright (c) 2009-2020 TopLinker Co.,Ltd. (http://www.toplinker.net) #
# ALL RIGHTS RESERVED #
# #
# The entire contents of this file is protected by copyright law and #
# international treaties. Unauthorized reproduction, reverse-engineering #
# and distribution of all or any portion of the code contained in this #
# file is strictly prohibited and may result in severe civil and #
# criminal penalties and will be prosecuted to the maximum extent #
# possible under the law. #
# #
# RESTRICTIONS #
# #
# THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED #
# FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE #
# COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE #
# AVAILABLE TO OTHER INDIVIDUALS WITHOUT WRITTEN CONSENT #
# AND PERMISSION FROM DEVELOPER MACHINES #
# #
# CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON #
# ADDITIONAL RESTRICTIONS. #
# #
#############################################################################
#include "drillparser.h"
#include <QFile>
#include <QSet>
#include <QTextStream>
#include <QDebug>
#include <QtMath>
#include <functional>
#include "../core/util.h"
TITAN_BEGIN_NAMESPACE
class PcbCamDrillToolData: public QSharedData
{
public:
PcbCamDrillToolData() {}
PcbCamDrillToolData(const PcbCamDrillToolData &other) : QSharedData(other) {}
~PcbCamDrillToolData() {}
int T {0};
double F {0.0};
double C {0.0};
double S {0.0};
double R {0.0};
double H {0.0};
double Z {0.0};
};
class PcbCamDrillTool
{
public:
PcbCamDrillTool() : d(new PcbCamDrillToolData) {}
PcbCamDrillTool(const PcbCamDrillTool &rhs): d(rhs.d) {}
PcbCamDrillTool &operator=(const PcbCamDrillTool &rhs)
{
if (this != &rhs) d.operator=(rhs.d);
return *this;
}
~PcbCamDrillTool() {}
void setT(int val) {d->T = val;}
int T() const {return d->T;}
void setF(double val) {d->F = val;}
double F() const {return d->F;}
void setC(double val) {d->C = val;}
double C() const {return d->C;}
void setS(double val) {d->S = val;}
double S() const {return d->S;}
void setR(double val) {d->R = val;}
double R() const {return d->R;}
void setH(double val) {d->H = val;}
double H() const {return d->H;}
void setZ(double val) {d->Z = val;}
double Z() const {return d->Z;}
QString symbolName() const {
return QString("r%1").arg(PcbCamUtil::formatNumber(d->C * 1000, 6));
}
private:
QSharedDataPointer<PcbCamDrillToolData> d;
};
class PcbCamDrillParserPrivate
{
Q_DECLARE_PUBLIC(PcbCamDrillParser)
public:
enum class Section {
None,
Head,
Body,
};
enum class Cmd {
UNKNOW = -1,
EMPTY = 0,
INCH_METRIC = 1, // INCH,LZ 或 METRIC,000.000 :单位及省零模式(TZ=Traling, LZ=Leading)
FMAT = 2, // FMAT,2 :格式标准Excellon2格式
VER = 3, // VER,1 :Selection of X and Y Axis Version
TCODE = 4, // T01C0.2 //刀具信息
POSXY = 5, // X0001Y0001 : 坐标
K = 6, // (K) 禁用顺序优化
F = 7, // F07 Worktable feed rate of 70 IPM or 70 mm/s for routing
G70_74 = 1170, // Posalux格式时排版变换指令; G70,G71,G72,G73,G74
M02_EMPTY = 2003, // 每次排版后有一行空白的M02
G00 = 1000, // Route Mode (X#Y#) перемещение.
G01 = 1001, // Linear (Straight Line) Mode
G02 = 1002, // Circular CW Mode
G03 = 1003, // Circular CCW Mode
G04 = 1004, // X# Variable Dwell
G05 = 1005, // Drill Mode (G81)
G07 = 1007, // Override current tool feed or speed
G32 = 1032, // Routed Circle Canned Cycle (X#Y#A#)
G33 = 1033, // CCW G34,#(,#) Select Vision Tool
G34 = 1034, // CW G33X#Y#A# Routed Circle Canned Cycle
G35 = 1035, // Single Point Vision Offset (Relative to Work Zero) (X#Y#)
G36 = 1036, // Multipoint Vision Translation (Relative to Work Zero) (X#Y#)
G37 = 1037, // Cancel Vision Translation or Offset (From G35 or G36)
G38 = 1038, // Vision Corrected Single Hole Drilling (Relative to Work Zero) (X#Y#)
G39 = 1039, // Vision System Autocalibration (X#Y#)
G40 = 1040, // Cutter Compensation Off
G41 = 1041, // Cutter Compensation Left
G42 = 1042, // Cutter Compensation Right
G45 = 1045, // Single Point Vision Offset (Relative to G35 or G36) (X#Y#)
G46 = 1046, // Multipoint Vision Translation (Relative to G35 or G36) (X#Y#)
G47 = 1047, // Cancel Vision Translation or Offset (From G45 or G46)
G48 = 1048, // Vision Corrected Single Hole Drilling (Relative to G35 or G36) (X#Y#)
G82 = 1082, // Dual In Line Package (G81)
G83 = 1083, // Eight Pin L Pack
G84 = 1084, // Circle
G85 = 1085, // Slot
G87 = 1087, // Routed Step Slot Canned Cycle
G90 = 1090, // Absolute Mode
G91 = 1091, // Incremental Input Mode
G93 = 1093, // Zero Set (X#Y#)
M00 = 2000, // End of Program - No Rewind (X#Y#)
M01 = 2001, // End of Pattern
M02 = 2002, // Repeat Pattern Offset ((M02)X#Y#)
// M02 = 2, // Swap Axes ((M02)XYM70)
// M02 = 2, // Mirror Image X Axis ((M02)XYM80)
// M02 = 2, // Mirror Image Y Axis ((M02)XYM90)
M06 = 2006, // Optional Stop (X#Y#)
M08 = 2008, // End of Step and Repeat
M09 = 2009, // Stop for Inspection (X#Y#)
M12 = 2012, // ATS Laser Cutting转换程序里有,暂不知道用途
M14 = 2014, // Z Axis Route Position With Depth Controlled Contouring
M15 = 2015, // Z Axis Route Position
M16 = 2016, // Retract With Clamping - вытянуть с фиксацией.
M17 = 2017, // Retract Without Clamping
M18 = 2018, // Command tool tip check
M19 = 2019, // Binary Map
M25 = 2025, // Beginning of Pattern
M29 = 2029, // Poslaux中有M29,暂时还不知道有何用途
M30 = 2030, // End of Program Rewind (X#Y#)
M45 = 2045, // Long Operator message on multiple\ part program lines (,long message\)
M47 = 2047, // Operator Message (,text)
M48 = 2048, // The beginning of a heade,same as %
M50 = 2050, // Vision Step and Repeat Pattern Start (,#)
M51 = 2051, // Vision Step and Repeat Rewind (,#)
M52 = 2052, // Vision Step and Repeat Offset Counter Control (#)
M60 = 2060, // Reference Scaling enable
M61 = 2061, // Reference Scaling disable
M62 = 2062, // Turn on peck drilling
M63 = 2063, // Turn off peck drilling
M71 = 2071, // Metric Measuring Mode
M72 = 2072, // Inch Measuring Mode
M83 = 2083, // M83,ZOT0.0
M95 = 2095, // % end header
M97 = 2097, // Canned Text (,text)
M98 = 2098, // Canned Text (,text)
M99 = 2099, // User Defined Stored Pattern (,subprogram)
M100 = 2100, //Marco
REMARK = 9000, // ATS laser cutting (remark_1,"X50.51Y277.975")
};
struct RowData {
Section section {PcbCamDrillParserPrivate::Section::None}; //位于哪个区段
QString rawString; //原始字符
int group {0}; //分组
int lineNumber {0}; //行号
PcbCamDrillTool tool; //当前刀号
bool isRepeatBlock {false}; //是否在Repeat区块内
Cmd cmd {PcbCamDrillParserPrivate::Cmd::UNKNOW};
int tcode {-1};
PcbCam::CoordNotation coordMode {PcbCam::CoordAbsoulte};
QPointF origin {0.0, 0.0};
QPointF lastPos {0.0, 0.0};
QPointF pos {0.0, 0.0}; //hole中心,slot起点,G84中心点
QPointF pos2 {0.0, 0.0}; //slot终点
double size {0.0}; //G84 size, G02 G03圆弧半径
QTransform transform; //Repeat时的座标变换
QList<RowData> repeatRows;
RowData transformed(const QTransform &iTransform) const {
RowData res = *this;
res.pos = iTransform.map(this->pos);
res.pos2 = iTransform.map(this->pos2);
res.lastPos = iTransform.map(this->lastPos);
return res;
}
};
PcbCamDrillParserPrivate(PcbCamDrillParser *qptr) : q_ptr(qptr){}
~PcbCamDrillParserPrivate() {}
PcbCamDrillTool parseToolString(const QString &ilinestr)
{
PcbCamDrillTool tool;
//T01C0.41S120.F80R600Z-.13H2000
QRegularExpressionMatch match = QRegularExpression("^T([0-9]{1,2})").match(ilinestr);
if (match.hasMatch()) tool.setT(match.captured(1).toInt());
match = QRegularExpression("C([+-]?[0-9.]+)").match(ilinestr);
if (match.hasMatch()) tool.setC(unitsConvert(match.captured(1).toDouble(), statement.toolUnits, PcbCam::Units_Inch));
match = QRegularExpression("S([+-]?[0-9\\.]+)").match(ilinestr);
if (match.hasMatch()) tool.setS(match.captured(1).toDouble());
match = QRegularExpression("F([+-]?[0-9\\.]+)").match(ilinestr);
if (match.hasMatch()) tool.setF(match.captured(1).toDouble());
match = QRegularExpression("R([+-]?[0-9\\.]+)").match(ilinestr);
if (match.hasMatch()) tool.setR(match.captured(1).toDouble());
match = QRegularExpression("Z([+-]?[0-9\\.]+)").match(ilinestr);
if (match.hasMatch()) tool.setZ(match.captured(1).toDouble());
match = QRegularExpression("H([+-]?[0-9\\.]+)").match(ilinestr);
if (match.hasMatch()) tool.setH(match.captured(1).toDouble());
return tool;
}
double drillStr2Double(const QString &iStr, const PcbCamDrillParser::DrillStatement &iFormat, PcbCam::UnitsType iDestUnits)
{
if (iStr.isEmpty()) return 0.0;
double value {0.0};
if (iFormat.zerosOmit == PcbCam::ZerosOmit_Decimal) {
value = iStr.toDouble();
}
else if (iFormat.zerosOmit == PcbCam::ZerosOmit_Training) {
QString str = iStr;
int i = iFormat.integerDigits;
int d = iFormat.decimalDigits;
int c = i + d;
QString sign;
if (str.startsWith("-") || str.startsWith("+")) {
sign = str.left(1);
str.remove(0, 1);
}
if (str.length() < c) {
str.append(QString("0").repeated(c - str.length()));
}
str.insert(i, ".");
str.prepend(sign);
value = str.toDouble();
}
else {
QString str = iStr;
int i = iFormat.integerDigits;
int d = iFormat.decimalDigits;
int c = i + d;
QString sign;
if (str.startsWith("-") || str.startsWith("+")) {
sign = str.left(1);
str.remove(0, 1);
}
if (str.length() < c) {
str.prepend(QString("0").repeated(c - str.length()));
}
str.insert(str.length() - d, ".");
str.prepend(sign);
value = str.toDouble();
}
if (iFormat.units == PcbCam::Units_Mm && iDestUnits == PcbCam::Units_Inch) {
value /= 25.4;
}
else if (iFormat.units == PcbCam::Units_Inch && iDestUnits == PcbCam::Units_Mm) {
value *= 25.4;
}
return value;
}
QPointF drillCatchXy(const QString &iStr, const PcbCamDrillParser::DrillStatement &iFormat, PcbCam::UnitsType iDestUnits, const QPointF &iDefault)
{
QPointF res = iDefault;
QRegularExpression regx("X([+-]?[0-9.]*)");
QRegularExpression regy("Y([+-]?[0-9.]*)");
auto matchx = regx.match(iStr);
if (matchx.hasMatch()) {
res.setX(drillStr2Double(matchx.captured(1), iFormat, iDestUnits));
}
auto matchy = regy.match(iStr);
if (matchy.hasMatch()) {
res.setY(drillStr2Double(matchy.captured(1), iFormat, iDestUnits));
}
return res;
}
double unitsConvert(double iValue, PcbCam::UnitsType iSrcUnits, PcbCam::UnitsType iDestUnits)
{
if (iSrcUnits == PcbCam::Units_Mm && iDestUnits == PcbCam::Units_Inch) {
return iValue / 25.4;
}
else if (iSrcUnits == PcbCam::Units_Inch && iDestUnits == PcbCam::Units_Mm) {
return iValue * 25.4;
}
return iValue;
}
QPointF calcCircleCenter(QPointF p1, QPointF p2, double dRadius, double clockwise) const
{
double x1 = p1.x();
double y1 = p1.y();
double x2 = p2.x();
double y2 = p2.y();
double mid_x = (x1 + x2) / 2.0;
double mid_y = (y1 + y2) / 2.0;
double mo1 = qSqrt(qAbs(dRadius * dRadius - ((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)) / 4));
double mo2 = qSqrt(qAbs(dRadius * dRadius - ((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)) / 4));
double lx = (x2 - x1) / qSqrt(qAbs((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)));
double ly = (y2 - y1) / qSqrt(qAbs((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)));
double center2_x = mid_x + mo1 * ly;
double center2_y = mid_y + mo1 * (-lx);
double center1_x = mid_x + mo2 * (-ly);
double center1_y = mid_y + mo2 * lx;
QPointF center1(center1_x, center1_y);
QPointF center2(center2_x, center2_y);
if (clockwise) {
return center1;
}
else {
return center2;
}
}
PcbCamOdbFeatureInfo createFeature(const RowData &iRowData) {
PcbCamOdbFeatureInfo feat;
if (iRowData.cmd == PcbCamDrillParserPrivate::Cmd::G85) { //Slot
feat.type = PcbCam::LineFeature;
feat.ps = iRowData.pos;
feat.pe = iRowData.pos2;
feat.symbol = iRowData.tool.symbolName();
}
else if (iRowData.cmd == PcbCamDrillParserPrivate::Cmd::G84) { //扩孔
feat.type = PcbCam::PadFeature;
feat.ps = iRowData.pos;
feat.symbol = QString("r%1").arg(PcbCamUtil::formatNumber(iRowData.size*1000, 6));
}
else if (iRowData.cmd == PcbCamDrillParserPrivate::Cmd::POSXY) {
feat.type = PcbCam::PadFeature;
feat.ps = iRowData.pos;
feat.symbol = iRowData.tool.symbolName();
}
else if (iRowData.cmd == PcbCamDrillParserPrivate::Cmd::G01) {
feat.type = PcbCam::LineFeature;
feat.ps = iRowData.pos;
feat.pe = iRowData.pos2;
feat.symbol = iRowData.tool.symbolName();
}
else if (iRowData.cmd == PcbCamDrillParserPrivate::Cmd::G02) {
feat.type = PcbCam::ArcFeature;
feat.cw = true;
feat.ps = iRowData.pos;
feat.pe = iRowData.pos2;
feat.pc = calcCircleCenter(feat.ps, feat.pe, iRowData.size, feat.cw);
feat.symbol = iRowData.tool.symbolName();
}
else if (iRowData.cmd == PcbCamDrillParserPrivate::Cmd::G03) {
feat.type = PcbCam::ArcFeature;
feat.cw = false;
feat.ps = iRowData.pos;
feat.pe = iRowData.pos2;
feat.pc = calcCircleCenter(feat.ps, feat.pe, iRowData.size, feat.cw);
feat.symbol = iRowData.tool.symbolName();
}
return feat;
}
using WalkCallback = std::function<bool(const RowData &iRowData)>;
bool walkDrillRows(const QStringList &iDrillRows, const PcbCamDrillParser::DrillStatement &iStatement, WalkCallback iCallback) {
auto statement = iStatement;
auto globalUnits = PcbCam::Units_Inch;
QTransform g74Trans = QTransform( 0, 1, 1, 0, 0, 0);
QTransform g71Trans = QTransform(-1, 0, 0, 1, 0, 0);
QTransform g72Trans = QTransform( 1, 0, 0, -1, 0, 0);
QMap<int, PcbCamDrillTool> toolMap;
QSet<int> transSet;
QPointF lastM02Pos {0.0, 0.0};
QList<PcbCamDrillParserPrivate::RowData> repeat_rows;
PcbCamDrillParserPrivate::RowData rowData;
QString linestr;
for (const auto l : iDrillRows) {
linestr = l.trimmed();
rowData.rawString = linestr;
rowData.lineNumber++;
rowData.cmd = PcbCamDrillParserPrivate::Cmd::UNKNOW;
if (linestr.isEmpty()) {
rowData.cmd = PcbCamDrillParserPrivate::Cmd::EMPTY;
}
else if (rowData.section == PcbCamDrillParserPrivate::Section::None) {
if (linestr.startsWith("M48")) {
// M48 :程序头部开始
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M48;
rowData.section = PcbCamDrillParserPrivate::Section::Head;
}
else if (linestr == "%") {
rowData.cmd = PcbCamDrillParserPrivate::Cmd::EMPTY;
}
}
else if (rowData.section == PcbCamDrillParserPrivate::Section::Head) {
if (linestr == "%" || linestr == "M95") {
// % :-头部结束,Body开始
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M95;
rowData.section = PcbCamDrillParserPrivate::Section::Body;
rowData.tcode = -1;
}
else if (linestr.startsWith("T")) {
// T01C0.41S120.F80R600Z-.13H2000 :刀具信息
rowData.cmd = PcbCamDrillParserPrivate::Cmd::TCODE;
auto tool = this->parseToolString(linestr);
toolMap.insert(tool.T(), tool);
rowData.tcode = tool.T();
rowData.tool = tool;
}
else if (linestr.startsWith("METRIC")) {
// METRIC,TZ :公制单位及省零模式(TZ=Traling, LZ=Leading)
// METRIC,000.000
rowData.cmd = PcbCamDrillParserPrivate::Cmd::INCH_METRIC;
}
else if (linestr.startsWith("INCH")) {
// INCH,LZ :英制单位及省零模式(TZ=Traling, LZ=Leading)
rowData.cmd = PcbCamDrillParserPrivate::Cmd::INCH_METRIC;
}
else if (linestr.startsWith("FMAT")) {
//FMAT,2 :格式标准Excellon2格式
rowData.cmd = PcbCamDrillParserPrivate::Cmd::FMAT;
}
else if (linestr.startsWith("VER")) {
//VER,1 :Selection of X and Y Axis Version
rowData.cmd = PcbCamDrillParserPrivate::Cmd::VER;
}
else if (linestr.startsWith("M100")) {
//M100 :宏命令
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M100;
}
}
else if (rowData.section == PcbCamDrillParserPrivate::Section::Body) {
if (linestr.startsWith("X") || linestr.startsWith("Y")) {
if (linestr.contains("G85")) {
//X03Y05G85X03Y047 :slot
rowData.cmd = PcbCamDrillParserPrivate::Cmd::G85;
QPointF p1, p2;
auto tmplist = linestr.split("G85", Qt::SkipEmptyParts);
if (rowData.coordMode == PcbCam::CoordIncremental) {
p1 = this->drillCatchXy(tmplist.value(0), statement, globalUnits, QPointF(0.0, 0.0));
p1 += rowData.lastPos;
p2 = this->drillCatchXy(tmplist.value(1), statement, globalUnits, QPointF(0.0, 0.0));
p2 += p1;
}
else {
p1 = this->drillCatchXy(tmplist.value(0), statement, globalUnits, QPointF(0.0, 0.0));
p2 = this->drillCatchXy(tmplist.value(1), statement, globalUnits, QPointF(0.0, 0.0));
}
rowData.pos = p1;
rowData.pos2 = p2;
}
else if (linestr.contains("G84")) {
//X009Y046G84X005 :扩孔
rowData.cmd = PcbCamDrillParserPrivate::Cmd::G84;
auto tmplist = linestr.split("G84", Qt::SkipEmptyParts);
QPointF p1;
if (rowData.coordMode == PcbCam::CoordIncremental) {
p1 = this->drillCatchXy(tmplist.value(0), statement, globalUnits, QPointF(0.0, 0.0));
p1 += rowData.lastPos;
}
else {
p1 = this->drillCatchXy(tmplist.value(0), statement, globalUnits, QPointF(0.0, 0.0));
}
rowData.pos = p1;
rowData.size = this->drillStr2Double(tmplist.value(1).mid(1), statement, globalUnits);
}
else {
//X13.560Y602.390 :圆孔
rowData.cmd = PcbCamDrillParserPrivate::Cmd::POSXY;
QPointF p1;
if (rowData.coordMode == PcbCam::CoordIncremental) {
p1 = this->drillCatchXy(linestr, statement, globalUnits, QPointF(0.0, 0.0));
p1 += rowData.lastPos;
}
else {
p1 = this->drillCatchXy(linestr, statement, globalUnits, rowData.lastPos);
}
rowData.pos = p1;
}
}
else if (linestr.startsWith("T")) {
//T02 :刀号选择
rowData.cmd = PcbCamDrillParserPrivate::Cmd::TCODE;
QRegularExpressionMatch match = QRegularExpression("^T([0-9]{2})").match(linestr);
rowData.tcode = match.captured(1).toInt();
rowData.tool = toolMap.value(rowData.tcode);
}
else if (linestr.startsWith("G00")) {
//G00X#Y# :快速移动至此点
//G00 turns the routing mode on and the drilling mode off. This command is required before any routing can be performed. An X and Y
//coordinate must be provided to move the worktable to a starting point for routing. When the CNC-7 encounters this command, the
//worktable moves to the X,Y coordinate. The spindles will not plunge into the work until a plunge command (e.g. M15) is given.
//Compensation is automatically turned off during the move and can be turned on again after the move. The G00 command remains in
//effect until another G00 command, or a G01, G02, G03, or G05 command is encountered. Do not use this command when the Z-axis is in
//the rout position. The tool can be damaged by a high speed move.
rowData.cmd = PcbCamDrillParserPrivate::Cmd::G00;
rowData.pos = this->drillCatchXy(linestr.mid(2), statement, globalUnits, rowData.lastPos);
}
else if (linestr.startsWith("G01")) {
//G01(X#)(Y#) :直线插补
//G01 turns on linear interpolation mode. This means that the machine will begin routing in a straight line. If you supply an X and/or Y
//coordinate with the command, the machine will rout a straight line from the current position to the coordinate position. If you do not supply
//coordinates, the CNC-7 will look for coordinates in a succeeding block, and rout to the first coordinate found. Unless a different rate has
//been set, linear movement will occur at a default rate of 100 IPM (42.3 mm/s) at 100% feed rate. This can be overridden with the F#
//command, described in the Tool Commands section of this chapter, or with the FEED RATE buttons on the Touch Screen.
rowData.cmd = PcbCamDrillParserPrivate::Cmd::G01;
rowData.pos = rowData.lastPos;
rowData.pos2 = this->drillCatchXy(linestr.mid(2), statement, globalUnits, rowData.lastPos);
}
else if (linestr.startsWith("G02")) {
//G02(X#)(Y#)(A#) G02(X#)(Y#)(I#J#) :顺圆差补
//G02 turns on circular interpolation mode and sets clockwise direction of travel. If you supply an X and/or Y coordinate with the command,
//the worktable will move to that coordinate position. The move will be made along an arc in a clockwise direction at a controlled velocity. If
//you do not supply coordinates, the CNC-7 will look for coordinates in a succeeding block, and rout to the first coordinate found. The arc
//must be equal to or less than 180 degrees. The arc radius or the arc center offset is specified either by the A# command or the I#J#
//command. These commands are indicated as optional. If they are not included in the G02 command, they must be included in a previous
//block of the program, either alone or with another routing command. The A# and I#J# commands are discussed in the next sections.
//Unless a different rate has been set, movement will occur at a default rate of 100 IPM (42.3 mm/s) at 100% feed rate. This can be
//overridden with the F# command, described in the Tool Commands section of this chapter, or with the FEED RATE switches on the Touch
//Screen.
rowData.cmd = PcbCamDrillParserPrivate::Cmd::G02;
if (linestr.contains("A")) {
auto tmplist = linestr.mid(2).split("A", Qt::SkipEmptyParts);
QPointF p1;
if (rowData.coordMode == PcbCam::CoordIncremental) {
p1 = this->drillCatchXy(tmplist.value(0), statement, globalUnits, QPointF(0.0, 0.0));
p1 += rowData.lastPos;
}
else {
p1 = this->drillCatchXy(tmplist.value(0), statement, globalUnits, rowData.lastPos);
}
rowData.pos = rowData.lastPos;
rowData.pos2 = p1;
rowData.size = this->drillStr2Double(tmplist.value(1), statement, globalUnits);
}
else {
rowData.cmd = PcbCamDrillParserPrivate::Cmd::UNKNOW;
}
}
else if (linestr.startsWith("G03")) {
//G03(X#)(Y#)(A#) G03(X#)(Y#)(I#J#) :逆圆差补
//G03 turns on circular interpolation mode and sets counterclockwise direction of travel. If you supply an X and/or Y coordinate with the
//command, the worktable will move to that coordinate position. The move will be made along an arc in a counterclockwise direction at a
//controlled velocity. If you do not supply coordinates, the CNC-7 will look for coordinates in a succeeding block, and rout to the first
//coordinate found. The arc must be equal to or less than 180 degrees. The arc radius or the arc center offset is specified either by the A#
//command or the I#J# command. If they are not included in the G03 command, they must be included in a previous block of the program,
//either alone or with another routing command. The A# and I#J# commands are discussed in the next sections. Unless a different rate has
//been set, movement will occur at a default rate of 100 IPM (42.3 mm/s) at 100% feed rate. This can be overridden with the F# command,
//described in the Tool Commands section of this chapter, or with the FEED RATE switches on the Touch Screen.
rowData.cmd = PcbCamDrillParserPrivate::Cmd::G03;
if (linestr.contains("A")) {
auto tmplist = linestr.mid(2).split("A", Qt::SkipEmptyParts);
QPointF p1;
if (rowData.coordMode == PcbCam::CoordIncremental) {
p1 = this->drillCatchXy(tmplist.value(0), statement, globalUnits, QPointF(0.0, 0.0));
p1 += rowData.lastPos;
}
else {
p1 = this->drillCatchXy(tmplist.value(0), statement, globalUnits, rowData.lastPos);
}
rowData.pos = rowData.lastPos;
rowData.pos2 = p1;
rowData.size = this->drillStr2Double(tmplist.value(1), statement, globalUnits);
}
else {
rowData.cmd = PcbCamDrillParserPrivate::Cmd::UNKNOW;
}
}
else if (linestr.startsWith("G04")) {
//G04X# :停止一段时间
//G04 Halts the machine for the time you specify in place of #. This command is used, for example, to cool a router bit after a long cut. The
//dwell time is interpreted as 1 millisecond per increment in the current coordinate measurement mode (inch or metric). The dwell time may
//be programmed from 1 to 10 seconds of 1 msec. If you program beyond these limits, or if you do not supply a value, the dwell time
//defaults to 10 seconds.
//Example of usage: G04X001 = 1 second
rowData.cmd = PcbCamDrillParserPrivate::Cmd::G04;
}
else if (linestr.startsWith("G40")) {
//G40 :关闭补偿
//G40 turns cutter compensation off. This command is programmed in a block by itself. Cutter compensation is discussed with the G41 and
//G42 commands below, and with the Cutter Compensation Page.
//THIS COMMAND MUST NOT BE USED WHILE PLUNGED!
//Example of usage:
//G40
rowData.cmd = PcbCamDrillParserPrivate::Cmd::G40;
}
else if (linestr.startsWith("G41")) {
//G41 :左补偿
//G41 turns cutter compensation on for the tool being used to rout. The compensation path is left of the part relative to the direction that the
//tool is moving.
//THIS COMMAND MUST NOT BE USED WHILE PLUNGED! A Compensation Index must be specified on the Cutter Information Page for
//the tool being used. Without an Index there will be no compensation applied to the tool after compensation is turned on. A value must be
//assigned to the index number. Compensation will continue for all routing moves until a G00, G40, or G42 command is encountered, or the
//part program ends. The command must be programmed in a block by itself.
//Example of usage: G41
rowData.cmd = PcbCamDrillParserPrivate::Cmd::G41;
}
else if (linestr.startsWith("G42")) {
//G42 :右补偿
//G42 turns cutter compensation on for the tool being used to rout. The compensation path is right of the part relative to the direction that
//the tool is moving.
//THIS COMMAND MUST NOT BE USED WHILE PLUNGED! A Compensation Index must be specified on the Cutter Information Page for
//the tool being used. Without an index there will be no compensation applied to the tool after compensation is turned on. A value must be
//assigned to the index number. Compensation will continue for all routing moves until a G00, G40, or G41 command is encountered, or the
//part program ends. This command must be programmed in a block by itself.
//Example of usage: G42
rowData.cmd = PcbCamDrillParserPrivate::Cmd::G42;
}
else if (linestr.startsWith("G82")) {
//TODO 暂不支持G82
//rowData.cmd = PcbCamDrillParserPrivate::Cmd::G82;
}
else if (linestr.startsWith("G83")) {
//TODO 暂不支持G83
//rowData.cmd = PcbCamDrillParserPrivate::Cmd::G83;
}
else if (linestr == "G90") {
//G90 :绝对座标
rowData.cmd = PcbCamDrillParserPrivate::Cmd::G90;
rowData.coordMode = PcbCam::CoordAbsoulte;
}
else if (linestr == "G91") {
//G91 :相对对座标
rowData.cmd = PcbCamDrillParserPrivate::Cmd::G91;
rowData.coordMode = PcbCam::CoordIncremental;
}
else if (linestr.startsWith("G93")) {
//G93X0325Y015 :零点设置
rowData.cmd = PcbCamDrillParserPrivate::Cmd::G93;
rowData.origin = this->drillCatchXy(linestr, statement, globalUnits, QPointF(0.0, 0.0));
}
else if (linestr.startsWith("M12")) {
//M12 :ATS Laser Cutting转换程序用,暂不知道用途
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M12;
}
else if (linestr.startsWith("M14")) {
//M14 :Z Axis Rout Position with Depth Controlled Contouring
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M14;
}
else if (linestr.startsWith("M15")) {
//M15 :Z Axis Rout Positiong
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M15;
}
else if (linestr.startsWith("M16")) {
//M16 :Retract with Clamping
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M16;
}
else if (linestr.startsWith("M17")) {
//M17 :Retract without Clamping
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M17;
}
else if (linestr.startsWith("M18")) {
//M18 :Tool tip checkProgrammed tool tip check
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M18;
}
else if (linestr.startsWith("M19")) {
//M19 :<M19,#####>: Binary Map Commands
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M19;
}
else if (linestr == "M25") {
//M25 :图形Step&Repeat块开始标记 后续的M02命令可以重复介于M25与M01之间的部分
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M25;
rowData.isRepeatBlock = true;
repeat_rows.clear();
}
else if (linestr == "M30") {
//M30 :程序结束
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M30;
}
else if (linestr.startsWith("M45")) {
//M45,text\text\text :Operator Lone Message
//TODO 暂不支持M45
//rowData.cmd = PcbCamDrillParserPrivate::Cmd::M45;
}
else if (linestr.startsWith("M47")) {
//M47,text :Operator Message
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M47;
}
else if (linestr.startsWith("M60")) {
//M60 :Reference Scaling enable
//TODO 暂不支持M60
//rowData.cmd = PcbCamDrillParserPrivate::Cmd::M60;
}
else if (linestr.startsWith("M61")) {
//M61 :Reference Scaling disable
//TODO 暂不支持M61
//rowData.cmd = PcbCamDrillParserPrivate::Cmd::M61;
}
else if (linestr.startsWith("M62")) {
//M62 :Turn on peck drilling
//TODO 暂不支持M62
//rowData.cmd = PcbCamDrillParserPrivate::Cmd::M62;
}
else if (linestr.startsWith("M63")) {
//M63 :Turn off peck drilling
//TODO 暂不支持M63
//rowData.cmd = PcbCamDrillParserPrivate::Cmd::M63;
}
else if (linestr.startsWith("M71")) {
//M71 :Metric Measuring Mode
//TODO 暂不支持M71
//rowData.cmd = PcbCamDrillParserPrivate::Cmd::M71;
}
else if (linestr.startsWith("M83")) {
//<M83,ZUT28.3>
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M83;
}
else if (linestr.startsWith("M96")) {
//M96,OFF :Select Spindle Group
//TODO 暂不支持M96
//rowData.cmd = PcbCamDrillParserPrivate::Cmd::M96
}
else if (linestr.startsWith("M97")) {
//M97,0* M97,text :X方向的canned text
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M97;
}
else if (linestr.startsWith("M98")) {
//M98,0* M98,text :Y方向的canned text
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M98;
}
else if (linestr.startsWith("M100")) {
//M100 :宏命令
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M100;
}
else if (linestr.startsWith("(K)")) {
//K :表示不能调整顺序
rowData.cmd = PcbCamDrillParserPrivate::Cmd::K;
}
else if (linestr.startsWith("F")) {
//F :F07 Worktable feed rate of 70 IPM or 70 mm/s for routing
rowData.cmd = PcbCamDrillParserPrivate::Cmd::F;
}
else if (linestr.startsWith("remark", Qt::CaseInsensitive)) {
// remark_1,"X50.51Y277.975"
// remark_2,"X50.51Y558.475"
// ATS的Laser Cutting程序里有,表示排版座标
rowData.cmd = PcbCamDrillParserPrivate::Cmd::REMARK;
}
else if (statement.format == PcbCamDrillParser::DrillFormat_Excellon2) {
/********repeat example
M25
X034193Y010866
Y009055
Y012677
X034626Y013583
Y009961
M01
M02X000000Y025394
M02X000000Y023425
M02X037295Y-195277
M02X000000Y023425
M02
M08
*******************/
if (linestr == "M01") {
//M01 :Repeat块结束 indicates the end of the part program section which is to be repeated. This command is programmed in a block by itself.
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M01;
rowData.isRepeatBlock = false;
rowData.repeatRows = repeat_rows;
lastM02Pos = QPointF(0.0, 0.0);
rowData.lastPos = QPointF(0.0, 0.0);
}
else if (linestr.startsWith("M02")) {
//M02X#Y#M80 :Pattern Repeat
// The M02 command causes a repeat of all the commands between the M25 command and the M01 command. The M02 command is
// incremental. This means that the coordinate X#Y# is the distance from the beginning of the last pattern, not the distance from Work Zero.
// A separate M02 command is required for each repeat of the pattern of set of patterns. After the last M02 repeat command, an extra M02
// command which requires no coordinates, must be added in a block by itself. This will clear a counter built into the system software. The
// M02 command must always occur after the M01 command discussed above, and before the M08 command discussed below.
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M02;
transSet.clear();
if (linestr.toUpper() == "M02" || linestr.toUpper() == "M02XY") {
//空白的M02,一般在M08之前会有一个不带座标的M02
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M02_EMPTY;
}
else if (linestr.contains("M70") || linestr.contains("M80") || linestr.contains("M90")) {
//Repeat时旋转镜像
if (linestr.contains("M70")) {
//Swap AxisM70
//Mirror Image and Swap Axis
//You can make better use of PC board materials and reduce setup time by turning the axis of the boards by 180 degrees, or by reversing
//the axis to create a mirror image, or both. Excellon provides you with three commands which enable you to reverse and/or rotate the axis
//of a pattern, or an entire PC board. These commands are step and repeat commands and must be used in combination with the M25 and
//M01 commands, described earlier in this chapter. The swap rotates the pattern 90 degrees and makes a mirror image by changing the X
//axis to Y, and the Y axis to X. This command is used in a step and repeat offset block only, as shown
transSet.insert(74);
}
if (linestr.contains("M80")) {
//M80 creates a mirror image of a pattern or group of patterns by reversing the sign of the X axis coordinates. All X+ coordinates will be
//changed to X-, and all X- coordinates will be changed to X+. The Y coordinates remain the same. This command is used in a step and
//repeat offset block only.
transSet.insert(72);
}
if (linestr.contains("M90")) {
//M90 creates a mirror image of a pattern or group of patterns by reversing the sign of the Y axis coordinates. All Y+ coordinates will be
//changed to Y-, and all Y- coordinates will be changed to Y+. The X coordinates remain the same.
//This command is used in a step and repeat offset block only.
transSet.insert(71);
}
}
QPointF orgOffset = this->drillCatchXy(linestr.mid(2), statement, globalUnits, QPointF{0.0, 0.0});
QPointF offset = lastM02Pos + orgOffset;
lastM02Pos = offset;
rowData.pos = offset;
rowData.pos2 = orgOffset;
QTransform transform;
if (transSet.contains(74)) transform *= g74Trans;
if (transSet.contains(71)) transform *= g71Trans;
if (transSet.contains(72)) transform *= g72Trans;
QTransform trans(transform.m11(), transform.m12(), transform.m21(), transform.m22(), offset.x(), offset.y());
rowData.transform = trans;
}
else if (linestr.startsWith("M08")) {
//M08 EndofStepandRepeat
//M08indicatestheendofallstepandrepeatcommands.IfallM02commandshavenotbeencompleted,theCNC-7willreturntothelast
//startofpatterncommandandrepeat.Whenallpatternshavebeencompleted,theprogramwillcontinueonpasttheM08,findingeitheran endofprogramcommandormoreprograminformation.AnM30endofprogramcommandmaybecombinedwiththiscommand,
//otherwiseitisprogrammedinablockbyitself.
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M08;
}
else if (linestr.startsWith("G05")) {
//G05 :drill mode = Excellon1<G81>
rowData.cmd = PcbCamDrillParserPrivate::Cmd::G05;
}
else if (linestr.startsWith("M00")) {
//Excellon2 <M00> = Excellon1 <M02> End of Program, no rewind
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M00;
}
else if (linestr.startsWith("M06")) {
//<M06X#Y#> :Optional Stop = Excellon1<M01>
//TODO 暂不支持M06
//rowData.cmd = PcbCamDrillParserPrivate::Cmd::M06;
}
else if (linestr.startsWith("M09")) {
//<M09X#Y#> :Stop for Inspection = Excellon1 <M00>
//TODO 暂不支持M09
//rowData.cmd = PcbCamDrillParserPrivate::Cmd::M09;
}
else if (linestr.startsWith("M72")) {
//M72 :Inch Measuring Mode = Excellon1 <M70>
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M72;
}
} // end of Format_Excellon2
else if (statement.format == PcbCamDrillParser::DrillFormat_Posalux) {
/********repeat example
M25
X104.146Y131.245
X104.146Y131.892
X104.146Y132.540
X104.882Y129.949
X103.409Y129.949
M100,M97F
X103.194Y103.551(K)
M24
M26XY109.100
M26XY218.200
M26XY327.300
M26XY436.400
G74G71
M26X360.285Y22.915
M26X469.385Y22.915
M26X469.385Y290.215
M26X469.385Y379.315
M26X469.385Y468.415
G73
G70
M26X416.400Y
M26X416.400Y109.100
M26X416.400Y218.200
M26X416.400Y327.300
M26X416.400Y436.400
M27
*******************/
if (linestr == "M24") {
//M24 :Repeat块结束 = Excellon2<M01>
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M01;
rowData.isRepeatBlock = false;
rowData.repeatRows = repeat_rows;
}
else if (linestr.contains(QRegularExpression("G7[01234]"))) {
rowData.cmd = PcbCamDrillParserPrivate::Cmd::G70_74;
if (linestr.contains("G74")) transSet.insert(74);
if (linestr.contains("G71")) transSet.insert(71);
if (linestr.contains("G72")) transSet.insert(72);
if (linestr.contains("G73")) transSet.remove(74);
if (linestr.contains("G70")) {
transSet.remove(71);
transSet.remove(72);
}
}
else if (linestr.startsWith("M26")) {
//M26X416.400Y109.100 :Pattern Repeat = Excellon <M02>
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M02;
QPointF offset = this->drillCatchXy(linestr.mid(2), statement, globalUnits, QPointF{0.0, 0.0});
QTransform transform;
if (transSet.contains(74)) transform *= g74Trans;
if (transSet.contains(71)) transform *= g71Trans;
if (transSet.contains(72)) transform *= g72Trans;
QTransform trans(QTransform(transform.m11(), transform.m12(), transform.m21(), transform.m22(), offset.x(), offset.y()));
rowData.pos = offset;
rowData.transform = trans;
}
else if (linestr.startsWith("M27")) {
//M27 = Excellon2 <M08>
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M08;
}
else if (linestr.startsWith("G81")) {
//G81 :drill mode = Excellon2 <G05>
rowData.cmd = PcbCamDrillParserPrivate::Cmd::G05;
}
else if (linestr.startsWith("M00")) {
//<M00><M00X#Y#> = Excellon2 <M09>:Stop for Inspection
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M09;
}
else if (linestr.startsWith("M01")) {
//<M01> = Excellon2 <M06>:Optional Stop
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M06;
}
else if (linestr.startsWith("M02")) {
//<M02> = Excellon2 <M00>: End of Program, no rewind
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M00;
}
else if (linestr.startsWith("M70")) {
//<M70>:Inch Measuring Mode = Excellon2 <M72>
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M72;
}
else if (linestr.startsWith("M29")) {
//M29 :暂不知道用途是什么,ATS的程序里有
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M29;
}
} // end of Format_Poslaux
else if (statement.format == PcbCamDrillParser::DrillFormat_Excellon1) {
if (linestr == "M24") {
//M24 :Repeat块结束 = Excellon2<M01>
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M01;
rowData.isRepeatBlock = false;
rowData.repeatRows = repeat_rows;
lastM02Pos = QPointF(0.0, 0.0);
rowData.lastPos = QPointF(0.0, 0.0);
}
else if (linestr.startsWith("M26")) {
//M26X#Y#M23 :Pattern Repeat = Excellon <M02>
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M02;
transSet.clear();
if (linestr.toUpper() == "M26" || linestr.toUpper() == "M26XY") {
//空白的M02,一般在M08之前会有一个不带座标的M02
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M02_EMPTY;
}
else if (linestr.contains("M23") || linestr.contains("M21") || linestr.contains("M22")) {
//Repeat时旋转镜像
if (linestr.contains("M23")) {
//M23 = Excellon2 <M70>
transSet.insert(74);
}
if (linestr.contains("M21")) {
//M21 = Excellon2 <M80>
transSet.insert(72);
}
if (linestr.contains("M22")) {
//M22 = Excellon2 <M90>
transSet.insert(71);
}
}
QPointF orgOffset = this->drillCatchXy(linestr.mid(2), statement, globalUnits, QPointF{0.0, 0.0});
QPointF offset = lastM02Pos + orgOffset;
lastM02Pos = offset;
rowData.pos = offset;
rowData.pos2 = orgOffset;
QTransform transform;
if (transSet.contains(74)) transform *= g74Trans;
if (transSet.contains(71)) transform *= g71Trans;
if (transSet.contains(72)) transform *= g72Trans;
QTransform trans(transform.m11(), transform.m12(), transform.m21(), transform.m22(), offset.x(), offset.y());
rowData.transform = trans;
}
else if (linestr.startsWith("M27")) {
//M27 = Excellon2 <M08>
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M08;
}
else if (linestr.startsWith("G81")) {
//G81 :drill mode = Excellon2<G05>
rowData.cmd = PcbCamDrillParserPrivate::Cmd::G05;
}
else if (linestr.startsWith("M00")) {
//<M00><M00X#Y#> = Excellon2 <M09>:Stop for Inspection
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M09;
}
else if (linestr.startsWith("M01")) {
//<M01> = Excellon2 <M06>:Optional Stop
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M06;
}
else if (linestr.startsWith("M02")) {
//<M02> = Excellon2 <M00>: End of Program, no rewind
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M00;
}
else if (linestr.startsWith("M70")) {
//<M70>:Inch Measuring Mode = Excellon2 <M72>
rowData.cmd = PcbCamDrillParserPrivate::Cmd::M72;
}
} // end of Format_Excellon1
if (rowData.isRepeatBlock && rowData.cmd != PcbCamDrillParserPrivate::Cmd::M25) {
repeat_rows << rowData;
}
} // end of body
//callback here
bool ok = iCallback(rowData);
if (!ok) return false;
if (rowData.cmd == PcbCamDrillParserPrivate::Cmd::POSXY || rowData.cmd == PcbCamDrillParserPrivate::Cmd::G84 || rowData.cmd == PcbCamDrillParserPrivate::Cmd::G00) {
rowData.lastPos = rowData.pos;
}
else if (rowData.cmd == PcbCamDrillParserPrivate::Cmd::G85 || rowData.cmd == PcbCamDrillParserPrivate::Cmd::G01 || rowData.cmd == PcbCamDrillParserPrivate::Cmd::G02 || rowData.cmd == PcbCamDrillParserPrivate::Cmd::G03 ) {
rowData.lastPos = rowData.pos2;
}
} // end of while
return true;
}
QString filePath;
PcbCamDrillParser::DrillStatement statement;
QMap<int, PcbCamDrillTool> tools;
QList<PcbCamOdbFeatureInfo> features;
QStringList errorList;
protected:
PcbCamDrillParser * const q_ptr;
};
PcbCamDrillParser::PcbCamDrillParser():
d_ptr(new PcbCamDrillParserPrivate(this))
{
}
PcbCamDrillParser::PcbCamDrillParser(const QString &iFilePath, const DrillStatement &iStatement):
d_ptr(new PcbCamDrillParserPrivate(this))
{
Q_D(PcbCamDrillParser);
d->filePath = iFilePath;
d->statement = iStatement;
}
PcbCamDrillParser::~PcbCamDrillParser()
{
}
void PcbCamDrillParser::setFilePath(const QString &iFilePath)
{
Q_D(PcbCamDrillParser);
d->filePath = iFilePath;
}
QString PcbCamDrillParser::filePath() const
{
Q_D(const PcbCamDrillParser);
return d->filePath;
}
void PcbCamDrillParser::setStatement(const DrillStatement &iStatement)
{
Q_D(PcbCamDrillParser);
d->statement = iStatement;
}
PcbCamDrillParser::DrillStatement PcbCamDrillParser::statement() const
{
Q_D(const PcbCamDrillParser);
return d->statement;
}
bool PcbCamDrillParser::parser()
{
Q_D(PcbCamDrillParser);
d->tools.clear();
d->features.clear();
d->errorList.clear();
QFile drlfile(d->filePath);
if (!drlfile.open(QFile::ReadOnly|QFile::Text)) return false;
QStringList drillrows;
QTextStream stream(&drlfile);
QString line;
while (stream.readLineInto(&line)) {
drillrows.append(line);
}
drlfile.close();
d->walkDrillRows(drillrows, d->statement, [this](const PcbCamDrillParserPrivate::RowData &rowdata){
if (rowdata.section == PcbCamDrillParserPrivate::Section::Head ) {
if (rowdata.cmd == PcbCamDrillParserPrivate::Cmd::TCODE) {
auto tool = rowdata.tool;
d_func()->tools.insert(tool.T(), tool);
}
}
else if (rowdata.section == PcbCamDrillParserPrivate::Section::Body) {
if (rowdata.cmd == PcbCamDrillParserPrivate::Cmd::POSXY
|| rowdata.cmd == PcbCamDrillParserPrivate::Cmd::G85
|| rowdata.cmd == PcbCamDrillParserPrivate::Cmd::G84
|| rowdata.cmd == PcbCamDrillParserPrivate::Cmd::G01
|| rowdata.cmd == PcbCamDrillParserPrivate::Cmd::G02
|| rowdata.cmd == PcbCamDrillParserPrivate::Cmd::G03)
{
auto feat = d_func()->createFeature(rowdata);
d_func()->features.append(feat);
}
else if (rowdata.cmd == PcbCamDrillParserPrivate::Cmd::M02) {
for (const auto &r : rowdata.repeatRows) {
auto row = r;
row.pos = rowdata.transform.map(row.pos);
row.pos2 = rowdata.transform.map(row.pos2);
auto feat = d_func()->createFeature(row);
d_func()->features.append(feat);
}
}
}
return true;
});
}
QStringList PcbCamDrillParser::errors() const
{
Q_D(const PcbCamDrillParser);
return d->errorList;
}
QStringList PcbCamDrillParser::symbols() const
{
Q_D(const PcbCamDrillParser);
QSet<QString> res;
for (auto f : d->features) {
res.insert(f.symbol);
}
return res.values();
}
QList<PcbCamOdbFeatureInfo> PcbCamDrillParser::features() const
{
Q_D(const PcbCamDrillParser);
return d->features;
}
PcbCamDrillParser::DrillStatement::DrillStatement(const QVariantMap &iData)
{
if (iData.contains("format")) {
QString formatstr = iData.value("format").toString().toUpper();
if (formatstr == "EXCELLON1") {
this->format = DrillFormat_Excellon1;
}
else if (formatstr == "EXCELLON2") {
this->format = DrillFormat_Excellon2;
}
else if (formatstr == "POSALUX") {
this->format = DrillFormat_Posalux;
}
else {
this->format = DrillFormat_Unknow;
}
}
if (iData.contains("units")) {
QString unitstr = iData.value("units").toString().toUpper();
if (unitstr == "INCH") {
this->units = PcbCam::Units_Inch;
}
else if (unitstr == "MM") {
this->units = PcbCam::Units_Mm;
}
else {
this->units = PcbCam::Units_Unknow;
}
}
if (iData.contains("toolUnits")) {
QString toolunitstr = iData.value("toolUnits").toString().toUpper();
if (toolunitstr == "INCH") {
this->toolUnits = PcbCam::Units_Inch;
}
else if (toolunitstr == "MM") {
this->toolUnits = PcbCam::Units_Mm;
}
else {
this->toolUnits = PcbCam::Units_Unknow;
}
}
if (iData.contains("zerosOmit")) {
QString zerostr = iData.value("zerosOmit").toString().toUpper();
if (zerostr == "DECIMAL") {
this->zerosOmit = PcbCam::ZerosOmit_Decimal;
}
else if (zerostr == "LEADING") {
this->zerosOmit = PcbCam::ZerosOmit_Leading;
}
else if (zerostr == "TRAINING") {
this->zerosOmit = PcbCam::ZerosOmit_Training;
}
else if (zerostr == "NONE") {
this->zerosOmit = PcbCam::ZerosOmit_None;
}
else {
this->zerosOmit = PcbCam::ZerosOmit_Unknow;
}
}
if (iData.contains("coordMode")) {
QString coordmodestr = iData.value("coordMode").toString().toUpper();
if (coordmodestr == "absoulte") {
this->coordMode = PcbCam::CoordAbsoulte;
}
else if (coordmodestr == "incremental") {
this->coordMode = PcbCam::CoordIncremental;
}
else {
this->coordMode = PcbCam::CoordUnknow;
}
}
if (iData.contains("integerDigits")) {
this->integerDigits = iData.value("integerDigits").toInt();
}
if (iData.contains("decimalDigits")) {
this->decimalDigits = iData.value("decimalDigits").toInt();
}
}
QVariantMap PcbCamDrillParser::DrillStatement::toMap() const
{
QString formatStr;
if (this->format == DrillFormat_Excellon1) {
formatStr = "excellon1";
}
else if (this->format == DrillFormat_Excellon2) {
formatStr = "excellon2";
}
else if (this->format == DrillFormat_Posalux) {
formatStr = "posalux";
}
else if (this->format == DrillFormat_Unknow) {
formatStr = "unknow";
}
QString unitsStr;
if (this->units == PcbCam::Units_Inch) {
unitsStr = "inch";
}
else if (this->units == PcbCam::Units_Mm) {
unitsStr = "mm";
}
else if (this->units == PcbCam::Units_Unknow) {
unitsStr = "unknow";
}
QString toolUnitsStr;
if (this->toolUnits == PcbCam::Units_Inch) {
toolUnitsStr = "inch";
}
else if (this->toolUnits == PcbCam::Units_Mm) {
toolUnitsStr = "mm";
}
else if (this->toolUnits == PcbCam::Units_Unknow) {
toolUnitsStr = "unknow";
}
QString zeroStr;
if (this->zerosOmit == PcbCam::ZerosOmit_Decimal) {
zeroStr = "decimal";
}
else if (this->zerosOmit == PcbCam::ZerosOmit_Leading) {
zeroStr = "leading";
}
else if (this->zerosOmit == PcbCam::ZerosOmit_Training) {
zeroStr = "training";
}
else if (this->zerosOmit == PcbCam::ZerosOmit_None) {
zeroStr = "none";
}
else if (this->zerosOmit == PcbCam::ZerosOmit_Unknow) {
zeroStr = "unknow";
}
QString coordModeStr;
if (this->coordMode == PcbCam::CoordAbsoulte) {
coordModeStr = "absoulte";
}
else if (this->coordMode == PcbCam::CoordIncremental) {
coordModeStr = "incremental";
}
else if (this->coordMode == PcbCam::CoordUnknow) {
coordModeStr = "unknow";
}
return QVariantMap {
{"format", formatStr},
{"units", unitsStr},
{"toolUnits", toolUnitsStr},
{"zerosOmit", zeroStr},
{"coordMode", coordModeStr},
{"integerDigits", this->integerDigits},
{"decimalDigits", this->decimalDigits},
};
}
TITAN_END_NAMESPACE
#ifndef TITAN_PCBCAM_DRILLPARSER_H
#define TITAN_PCBCAM_DRILLPARSER_H
#include "../titanpcbcamglobal.h"
#include "odbfeatureparser.h"
TITAN_BEGIN_NAMESPACE
class PcbCamDrillParserPrivate;
class TITAN_PCBCAM_EXPORT PcbCamDrillParser
{
public:
enum DrillFormat {
DrillFormat_Unknow,
DrillFormat_Excellon1,
DrillFormat_Excellon2,
DrillFormat_Posalux,
};
struct DrillStatement {
explicit DrillStatement(){}
explicit DrillStatement(const QVariantMap &iData);
DrillFormat format {DrillFormat_Unknow};
PcbCam::UnitsType units {PcbCam::Units_Unknow};
PcbCam::ZerosOmit zerosOmit {PcbCam::ZerosOmit_Unknow};
PcbCam::CoordNotation coordMode {PcbCam::CoordUnknow};
PcbCam::UnitsType toolUnits {PcbCam::Units_Unknow};
int integerDigits {0};
int decimalDigits {0};
QPointF offsetPos {0.0, 0.0};
QVariantMap toMap() const;
};
explicit PcbCamDrillParser();
explicit PcbCamDrillParser(const QString &iFilePath, const DrillStatement &iStatement);
~PcbCamDrillParser();
void setFilePath(const QString &iFilePath);
QString filePath() const;
void setStatement(const DrillStatement &iStatement);
DrillStatement statement() const;
bool parser();
QStringList errors() const;
QStringList symbols() const;
QList<PcbCamOdbFeatureInfo> features() const;
protected:
const QScopedPointer<PcbCamDrillParserPrivate> d_ptr;
private:
Q_DECLARE_PRIVATE(PcbCamDrillParser)
Q_DISABLE_COPY(PcbCamDrillParser)
};
TITAN_END_NAMESPACE
#endif // TITAN_PCBCAM_DRILLPARSER_H
#include "gerber274xparser.h"
#include <QDebug>
#include <QtMath>
#include <QTextStream>
#include <QJSEngine>
#include <QJSValue>
#include <QPen>
#include <QPainterPath>
#include <QPainterPathStroker>
#include <QIODevice>
#include <QtMath>
#include "../core/util.h"
TITAN_BEGIN_NAMESPACE
class PcbCamGerber274XParserPrivate
{
Q_DECLARE_PUBLIC(PcbCamGerber274XParser)
public:
PcbCamGerber274XParserPrivate(PcbCamGerber274XParser *qptr): q_ptr(qptr){ }
~PcbCamGerber274XParserPrivate() {}
struct RegxMatchResult {
bool hasMatch {false};
QMap<QString, QString> captures;
};
enum InterpolationMode {
LinearMode = 1,
ClockwiseCircularMode = 2,
CounterclockwiseCircularMode = 3,
};
enum QuadrantMode {
SingleQuadrant,
MultiQuadrant,
};
struct GraphicsState {
PcbCam::UnitsType units {PcbCam::Units_Inch};
PcbCam::ZerosOmit zerosOmit {PcbCam::ZerosOmit_Leading};
PcbCam::CoordNotation coordNotation {PcbCam::CoordAbsoulte};
int integerDigits {0};
int decimalDigits {0};
QPointF currentPoint;
int currentAperture;
InterpolationMode interpolationMode {LinearMode};
QuadrantMode quadrantMode {SingleQuadrant};
bool regionMode {false};
PcbCam::Polarity polarity {PcbCam::Positive};
bool mirror {false};
int rotation {0};
int operationMode {2}; //D01 D02 D03
bool srMode {false};
int srRepeatsX {1};
int srRepeatsY {1};
double srStepI {0.0};
double srStepJ {0.0};
};
QStringList errorList;
QList<PcbCamOdbFeatureInfo> featureList;
PcbCamGerber274XParserPrivate::GraphicsState graphicsState;
QPainterPath curRegionPath;
QMap<int, PcbCamGerber274XParser::ApertureInfo> apertures;
QMap<QString, QStringList> apertureMacroDefines;
QJSEngine scriptEngine;
QMap<PcbCamGerber274XParser::Cmd, QRegularExpression> paramRegxs{
{ PcbCamGerber274XParser::Cmd::COORD, QRegularExpression("^(G(?<cmd>0*[123]))?(?<coord>[XYIJ][XYIJ0-9\\+\\-]+)?(D(?<op>0*[123]))?$")},
{ PcbCamGerber274XParser::Cmd::APERTURE_SELECT, QRegularExpression("^(?<cmd>G54|G55)?D(?<dcode>\\d+)$")},
{ PcbCamGerber274XParser::Cmd::FS, QRegularExpression("^(?<cmd>FS)(?<zero>[LTD])?(?<notation>[AI])([NGDM]\\d+)?X(?<wx>[0-7])(?<dx>[0-7])Y(?<wy>[0-7])(?<dy>[0-7])$") },
{ PcbCamGerber274XParser::Cmd::MO, QRegularExpression("^(?<cmd>MO)(?<mo>(MM|IN))$")},
{ PcbCamGerber274XParser::Cmd::LP, QRegularExpression("^(?<cmd>LP)(?<lp>(D|C))$")},
{ PcbCamGerber274XParser::Cmd::AD_CIRCLE, QRegularExpression("^(?<cmd>AD)D(?<dcode>\\d+)(?<shape>C)[,]?(?<modifiers>[^,%]*)$")},
{ PcbCamGerber274XParser::Cmd::AD_RECT, QRegularExpression("^(?<cmd>AD)D(?<dcode>\\d+)(?<shape>R)[,]?(?<modifiers>[^,%]*)$")},
{ PcbCamGerber274XParser::Cmd::AD_OBROUND, QRegularExpression("^(?<cmd>AD)D(?<dcode>\\d+)(?<shape>O)[,]?(?<modifiers>[^,%]*)$")},
{ PcbCamGerber274XParser::Cmd::AD_POLY, QRegularExpression("^(?<cmd>AD)D(?<dcode>\\d+)(?<shape>P)[,]?(?<modifiers>[^,%]*)$")},
{ PcbCamGerber274XParser::Cmd::AD_MACRO, QRegularExpression("^(?<cmd>AD)D(?<dcode>\\d+)(?<name>[a-zA-Z_$\\.][a-zA-Z_$\\.0-9+\\-]+)[,]?(?<modifiers>[^,%]*)$")},
{ PcbCamGerber274XParser::Cmd::AM, QRegularExpression("^(?<cmd>AM)(?<name>[a-zA-Z_$\\.][a-zA-Z_$\\.0-9\\+\\-]+)\\*(?<modifiers>.*)\\*$")},
{ PcbCamGerber274XParser::Cmd::IF, QRegularExpression("^(?<cmd>IF)(?<filename>.*)$")},
{ PcbCamGerber274XParser::Cmd::REGION_MODE, QRegularExpression("^(?<cmd>G3[67])$")},
{ PcbCamGerber274XParser::Cmd::QUAD_MODE, QRegularExpression("^(?<cmd>G7[45])$")},
{ PcbCamGerber274XParser::Cmd::SR, QRegularExpression("^(?<cmd>SR)(?<coord>[XYIJ0-9\\+\\-\\.]+)?")},
// 以下为旧版格式命令
{ PcbCamGerber274XParser::Cmd::IN, QRegularExpression("^(?<cmd>IN)(?<name>.*)")},
{ PcbCamGerber274XParser::Cmd::IP, QRegularExpression("^(?<cmd>IP)(?<mode>(POS|NEG))")},
{ PcbCamGerber274XParser::Cmd::IR, QRegularExpression("^(?<cmd>IR)(?<angle>[\\+\\-]?\\d+>)")},
{ PcbCamGerber274XParser::Cmd::OF, QRegularExpression("^(?<cmd>IO)(A(?<a>[\\+\\-]?\\d+(\\.?\\d+)?))?(B(?<b>[\\+\\-]?\\d+(\\.?\\d+)?))?")},
{ PcbCamGerber274XParser::Cmd::AS, QRegularExpression("^(?<cmd>AS)(?<mode>(AXBY|AYBX))")},
{ PcbCamGerber274XParser::Cmd::MI, QRegularExpression("^(?<cmd>MI)(A(?<a>0|1))?(B(?<b>0|1))?")},
{ PcbCamGerber274XParser::Cmd::OF, QRegularExpression("^(?<cmd>OF)(A(?<a>[\\+\\-]?\\d+(\\.?\\d+)?))?(B(?<b>[\\+\\-]?\\d+(\\.?\\d+)?))?")},
{ PcbCamGerber274XParser::Cmd::SF, QRegularExpression("^(?<cmd>SF)(?<discarded>.*)")},
{ PcbCamGerber274XParser::Cmd::LN, QRegularExpression("^(?<cmd>LN)(?<name>.*)")},
{ PcbCamGerber274XParser::Cmd::DEPRECATED_UNIT, QRegularExpression("^(?<cmd>G7[01])")},
{ PcbCamGerber274XParser::Cmd::DEPRECATED_FORMAT, QRegularExpression("^(?<cmd>G9[01])")},
};
QRegularExpression coordRegx {"([XYIJ])([\\+\\-\\.0-9]+)"};
RegxMatchResult getRegxCaptures(const QRegularExpression iRegx, const QString &iText) {
RegxMatchResult result;
auto match = iRegx.match(iText);
result.hasMatch = match.hasMatch();
if (match.hasMatch()) {
QMap<QString, QString> caps;
for (auto capname: iRegx.namedCaptureGroups()) {
if (!capname.isEmpty()) {
caps.insert(capname, match.captured(capname));
}
}
result.captures = caps;
}
return result;
}
double coord2inch(const QString &iStr) const {
if (iStr.isEmpty()) return 0.0;
double value {0.0};
if (graphicsState.zerosOmit == PcbCam::ZerosOmit_Training) {
QString str = iStr;
int i = graphicsState.integerDigits;
int d = graphicsState.decimalDigits;
int c = i + d;
QString sign;
if (str.startsWith("-") || str.startsWith("+")) {
sign = str.left(1);
str.remove(0, 1);
}
if (str.length() < c) {
str.append(QString("0").repeated(c - str.length()));
}
str.insert(i, ".");
str.prepend(sign);
value = str.toDouble();
}
else {
QString str = iStr;
int i = graphicsState.integerDigits;
int d = graphicsState.decimalDigits;
int c = i + d;
QString sign;
if (str.startsWith("-") || str.startsWith("+")) {
sign = str.left(1);
str.remove(0, 1);
}
if (str.length() < c) {
str.prepend(QString("0").repeated(c - str.length()));
}
str.insert(str.length() - d, ".");
str.prepend(sign);
value = str.toDouble();
}
if (graphicsState.units == PcbCam::Units_Mm) {
value /= 25.4;
}
return value;
}
double val2inch(const QString &iStr) {
auto value = iStr.toDouble();
if (graphicsState.units == PcbCam::Units_Mm) {
value /= 25.4;
}
return value;
}
QPointF calcArcCenter(const QPointF &iPs, const QPointF &iPe, double iOffsetI, double iOffsetJ, bool iCw, QuadrantMode iQuadrantMode) {
if (iQuadrantMode == MultiQuadrant) {
return QPointF(iPs.x() + iOffsetI, iPs.y() + iOffsetJ);
}
else {
QLineF line(iPs, iPe);
QTransform trans;
trans.translate(-iPs.x(), -iPs.y());
line = trans.map(line);
double lineangle = line.angle();
line.setAngle(0);
double radius = qSqrt(iOffsetI*iOffsetI + iOffsetJ*iOffsetJ);
double l = qSqrt(radius*radius - (line.length()/2.0)*(line.length()/2.0));
QPointF c1(line.length()/2.0, l);
QPointF c2(line.length()/2.0, -l);
QLineF linecs1(c1, line.p1());
QLineF linece1(c1, line.p2());
QPointF finalCenter;
if (iCw) {
if (linecs1.angleTo(linece1) <= 180) {
finalCenter = c1;
}
else {
finalCenter = c2;
}
}
else {
if (linecs1.angleTo(linece1) > 180) {
finalCenter = c1;
}
else {
finalCenter = c2;
}
}
trans.reset();
trans.rotate(-lineangle);
finalCenter = trans.map(finalCenter);
trans.reset();
trans.translate(iPs.x(), iPs.y());
finalCenter = trans.map(finalCenter);
return finalCenter;
}
}
QPainterPath rotatePath(const QPainterPath &iPath, double angle, const QPointF &iCenter = QPointF(0.0, 0.0)) {
if (qFuzzyCompare(angle, 0.0)) return iPath;
QTransform mat;
mat.rotate(angle);
return mat.map(iPath);
}
PcbCamGerber274XParser::ApertureInfo createCircleAperture(const QMap<QString, QString> &iParam) {
PcbCamGerber274XParser::ApertureInfo res;
res.dcode = iParam.value("dcode").toInt();
auto sizes = iParam.value("modifiers").split("X", Qt::SkipEmptyParts, Qt::CaseInsensitive);
if (sizes.count() == 1) {
res.name = QString("r%1").arg(val2inch(sizes.value(0))*1000);
res.isStandard = true;
}
else if (sizes.count() == 2) {
res.name = QString("donut_r%1x%2").arg(val2inch(sizes.value(0))*1000).arg(val2inch(sizes.value(1))*1000);
res.isStandard = true;
}
else if (sizes.count() == 3) {
res.isStandard = false;
auto outer_diameter = val2inch(sizes.value(0));
auto inner_width = val2inch(sizes.value(1));
auto inner_height = val2inch(sizes.value(2));
PcbCamOdbFeatureInfo feat;
feat.type = PcbCam::SurfaceFeature;
QPainterPath path;
path.addEllipse(QPointF(0.0, 0.0), outer_diameter, outer_diameter);
path.addRect(-inner_width/2.0, -inner_height/2.0, inner_width, inner_height);
feat.path = path;
res.features << feat;
}
else {
res.name = "r0";
res.isStandard = true;
}
return res;
}
PcbCamGerber274XParser::ApertureInfo createRectAperture(const QMap<QString, QString> &iParam) {
PcbCamGerber274XParser::ApertureInfo res;
res.dcode = iParam.value("dcode").toInt();
auto sizes = iParam.value("modifiers").split("X", Qt::SkipEmptyParts, Qt::CaseInsensitive);
if (sizes.count() == 2) {
res.name = QString("rect%1x%2").arg(val2inch(sizes.value(0))*1000).arg(val2inch(sizes.value(1))*1000);
res.isStandard = true;
}
else if (sizes.count() == 3) {
res.isStandard = false;
auto width = val2inch(sizes.value(0));
auto height = val2inch(sizes.value(1));
auto hole_diam = val2inch(sizes.value(2));
PcbCamOdbFeatureInfo feat;
feat.type = PcbCam::SurfaceFeature;
QPainterPath path;
path.addRect(-width/2.0, -height/2.0, width, height);
path.addEllipse(QPointF(0.0, 0.0), hole_diam, hole_diam);
feat.path = path;
res.features << feat;
}
else if (sizes.count() == 4) {
res.isStandard = false;
auto width = val2inch(sizes.value(0));
auto height = val2inch(sizes.value(1));
auto hole_w = val2inch(sizes.value(2));
auto hole_h = val2inch(sizes.value(3));
PcbCamOdbFeatureInfo feat;
feat.type = PcbCam::SurfaceFeature;
QPainterPath path;
path.addRect(-width/2.0, -height/2.0, width, height);
path.addRect(-hole_w/2.0, -hole_h/2.0, hole_w, hole_h);
feat.path = path;
res.features << feat;
}
else {
res.name = "r0";
res.isStandard = true;
}
return res;
}
PcbCamGerber274XParser::ApertureInfo createObroundAperture(const QMap<QString, QString> &iParam) {
PcbCamGerber274XParser::ApertureInfo res;
res.dcode = iParam.value("dcode").toInt();
auto sizes = iParam.value("modifiers").split("X", Qt::SkipEmptyParts, Qt::CaseInsensitive);
if (sizes.count() == 2) {
res.name = QString("oval%1x%2").arg(val2inch(sizes.value(0))*1000).arg(val2inch(sizes.value(1))*1000);
res.isStandard = true;
}
else if (sizes.count() >= 3) {
res.isStandard = false;
auto w = val2inch(sizes.value(0));
auto h = val2inch(sizes.value(1));
auto hole_w = val2inch(sizes.value(2));
PcbCamOdbFeatureInfo feat;
feat.type = PcbCam::SurfaceFeature;
QPainterPath path;
if (w > h) {
qreal rad = h / 2.0;
path.moveTo(-w/2.0 + rad, -h/2.0);
path.lineTo(w/2.0 - rad, -h/2.0);
path.arcTo(w/2.0 -rad*2.0, -h/2.0, h, h, 90, -180);
path.lineTo(-w/2.0 + rad, h/2.0);
path.arcTo(-w/2.0, -h/2.0, h, h, -90, -180);
path.closeSubpath();
}
else {
qreal rad = w/2.0;
path.moveTo(w/2.0, -h/2.0 + rad);
path.lineTo(w/2.0, h/2.0 - rad);
path.arcTo(-w/2.0, h/2.0 - rad*2.0, w, w, 0, -180);
path.lineTo(-w/2.0,-h/2.0 + rad);
path.arcTo(-w/2.0, -h/2.0, w, w, 180, -180);
path.closeSubpath();
}
if (sizes.count() == 3) {
path.addEllipse(QPointF(0.0, 0.0), hole_w, hole_w);
}
else {
auto hole_h = val2inch(sizes.value(3));
path.addRect(-hole_w/2.0, -hole_h/2.0, hole_w, hole_h);
}
feat.path = path;
res.features << feat;
}
else {
res.name = "r0";
res.isStandard = true;
}
return res;
}
PcbCamGerber274XParser::ApertureInfo createPolyAperture(const QMap<QString, QString> &iParam) {
PcbCamGerber274XParser::ApertureInfo res;
res.dcode = iParam.value("dcode").toInt();
auto sizes = iParam.value("modifiers").split("X", Qt::SkipEmptyParts, Qt::CaseInsensitive);
res.isStandard = false;
auto diam = val2inch(sizes.value(0));
auto edge = sizes.value(1).toInt();
PcbCamOdbFeatureInfo feat;
feat.type = PcbCam::SurfaceFeature;
QPainterPath path;
QPointF first_point(diam/2.0, 0.0);
QTransform mat;
double ra = 360.0/edge;
path.moveTo(first_point);
for (int n = 1; n <= edge; n++) {
mat.reset();
mat.rotate(ra*n);
path.lineTo(mat.map(first_point));
}
path.closeSubpath();
path = rotatePath(path, sizes.value(2, "0").toDouble());
if (sizes.count() > 3) {
auto hole_diam = val2inch(sizes.value(3));
path.addEllipse(QPointF(0.0, 0.0), hole_diam, hole_diam);
}
feat.path = path;
res.features << feat;
return res;
}
PcbCamGerber274XParser::ApertureInfo createSpecialAperture(const QMap<QString, QString> &iParam) {
PcbCamGerber274XParser::ApertureInfo res;
res.dcode = iParam.value("dcode").toInt();
res.isStandard = false;
auto sizes = iParam.value("modifiers").split("X", Qt::SkipEmptyParts, Qt::CaseInsensitive);
auto defstrs = this->apertureMacroDefines.value(iParam.value("name"));
if (!sizes.isEmpty()) {
for (int i = 0; i < sizes.count(); ++i) {
scriptEngine.globalObject().setProperty(QString("$%1").arg(i+1), sizes.value(i).toDouble());
}
}
for (auto line : defstrs) {
if (line.startsWith('$')) {
line.replace("x", "*", Qt::CaseInsensitive);
scriptEngine.evaluate(line);
}
else {
auto items = line.split(',', Qt::SkipEmptyParts);
for (auto &it : items) {
if (it.contains('$')) {
it.replace("x", "*", Qt::CaseInsensitive);
it = QString("%1").arg(scriptEngine.evaluate("(" + it + ")").toNumber());
}
}
int prim_code = items.value(0).toInt();
if (prim_code == 0) {
// comment
}
else if (prim_code == 1) {
auto diam = val2inch(items.value(2));
auto cx = val2inch(items.value(3));
auto cy = val2inch(items.value(4));
PcbCamOdbFeatureInfo feat;
feat.polarity = items.value(1) == "1" ? PcbCam::Positive : PcbCam::Negative;
feat.type = PcbCam::SurfaceFeature;
QPainterPath path;
path.addEllipse(QPointF(cx, cy), diam/2.0, diam/2.0);
path = rotatePath(path, items.value(5, "0").toDouble());
feat.path = path;
res.features << feat;
}
else if (prim_code == 20 || prim_code == 2) {
auto diam = val2inch(items.value(2));
auto xs = val2inch(items.value(3));
auto ys = val2inch(items.value(4));
auto xe = val2inch(items.value(5));
auto ye = val2inch(items.value(6));
PcbCamOdbFeatureInfo feat;
feat.polarity = items.value(1) == "1" ? PcbCam::Positive : PcbCam::Negative;
feat.type = PcbCam::SurfaceFeature;
QPainterPath path;
path.moveTo(xs, ys);
path.lineTo(xe, ye);
QPen pen;
pen.setCapStyle(Qt::FlatCap);
pen.setWidthF(diam);
QPainterPathStroker stroker(pen);
path = stroker.createStroke(path);
path = rotatePath(path, items.value(7, "0").toDouble());
feat.path = path;
res.features << feat;
}
else if (prim_code == 21) {
auto w = val2inch(items.value(2));
auto h = val2inch(items.value(3));
auto xc = val2inch(items.value(4));
auto yc = val2inch(items.value(5));
PcbCamOdbFeatureInfo feat;
feat.polarity = items.value(1) == "1" ? PcbCam::Positive : PcbCam::Negative;
feat.type = PcbCam::SurfaceFeature;
QPainterPath path;
path.addRect(xc-w/2.0, yc-h/2.0, w, h);
path = rotatePath(path, items.value(6, "0").toDouble());
feat.path = path;
res.features << feat;
}
else if (prim_code == 22) {
auto w = val2inch(items.value(2));
auto h = val2inch(items.value(3));
auto x = val2inch(items.value(4));
auto y = val2inch(items.value(5));
PcbCamOdbFeatureInfo feat;
feat.polarity = items.value(1) == "1" ? PcbCam::Positive : PcbCam::Negative;
feat.type = PcbCam::SurfaceFeature;
QPainterPath path;
path.addRect(x, y, w, h);
path = rotatePath(path, items.value(6, "0").toDouble());
feat.path = path;
res.features << feat;
}
else if (prim_code == 4) {
PcbCamOdbFeatureInfo feat;
feat.polarity = items.value(1) == "1" ? PcbCam::Positive : PcbCam::Negative;
feat.type = PcbCam::SurfaceFeature;
int pcount = items.value(2).toInt();
QPainterPath path;
path.moveTo(val2inch(items.value(3)), val2inch(items.value(4)));
for (int n = 1; n <= pcount; n++) {
path.lineTo(val2inch(items.value(3 + 2*n)), val2inch(items.value(4 + 2*n)));
}
path = rotatePath(path, items.value(-1, "0").toDouble());
feat.path = path;
res.features << feat;
}
else if (prim_code == 5) {
int edge = items.value(2).toInt();
double xc = val2inch(items.value(3));
double yc = val2inch(items.value(4));
double diam = val2inch(items.value(5));
PcbCamOdbFeatureInfo feat;
feat.polarity = items.value(1) == "1" ? PcbCam::Positive : PcbCam::Negative;
feat.type = PcbCam::SurfaceFeature;
QPointF first_point(diam/2.0, 0.0);
QPainterPath path;
QTransform mat;
double ra = 360.0/edge;
path.moveTo(first_point);
for (int n = 1; n <= edge; n++) {
mat.reset();
mat.rotate(ra*n);
path.lineTo(mat.map(first_point));
}
path.closeSubpath();
mat.reset();
mat.translate(xc, yc);
path = mat.map(path);
path = rotatePath(path, items.value(6, "0").toDouble());
feat.path = path;
res.features << feat;
}
else if (prim_code == 6) {
double xc = val2inch(items.value(1));
double yc = val2inch(items.value(2));
double diam = val2inch(items.value(3));
double ring_thk = val2inch(items.value(4));
double ring_gap = val2inch(items.value(5));
int ring_count = items.value(6).toInt();
double hair_thk = val2inch(items.value(7));
double hair_length = val2inch(items.value(8));
PcbCamOdbFeatureInfo feat;
feat.type = PcbCam::SurfaceFeature;
QPainterPath path;
for (int n = 0; n < ring_count; ++n) {
double outer_diam = diam - n * (ring_thk + ring_gap) * 2.0;
double inner_diam = outer_diam - 2.0 * ring_thk;
if (outer_diam > 0.0) {
path.addEllipse(-outer_diam/2.0, -outer_diam/2.0, outer_diam, outer_diam);
}
if (inner_diam > 0.0) {
path.addEllipse(-inner_diam/2.0, -inner_diam/2.0, inner_diam, inner_diam);
}
}
if (hair_thk > 0.0 && hair_length > 0.0) {
QPainterPath hairpath1;
hairpath1.addRect(-hair_length/2.0, -hair_thk/2.0, hair_length, hair_thk);
QPainterPath hairpath2;
hairpath2.addRect(-hair_thk/2.0, -hair_length/2.0, hair_thk, hair_length);
auto hairpath = hairpath1.united(hairpath2);
QTransform mat;
mat.scale(1000, 1000);
hairpath = mat.map(hairpath);
path = mat.map(path);
path = path.united(hairpath);
mat.reset();
mat.scale(0.001, 0.001);
path = mat.map(path);
}
QTransform mat;
mat.translate(xc, yc);
path = mat.map(path);
path = rotatePath(path, items.value(9, "0").toDouble());
feat.path = path;
res.features << feat;
}
else if (prim_code == 7) {
auto xc = val2inch(items.value(1));
auto yc = val2inch(items.value(2));
auto outer_diam = val2inch(items.value(3));
auto inner_diam = val2inch(items.value(4));
auto gap = val2inch(items.value(5));
PcbCamOdbFeatureInfo feat;
feat.type = PcbCam::SurfaceFeature;
qreal pie_angle = 360.0/4;
qreal half_inner_gap_angle = (180.0/M_PI) * (qAsin(gap/inner_diam));
qreal half_outer_gap_angle = (180.0/M_PI) * (qAsin(gap/outer_diam));
qreal inner_start_angle = 45.0 + half_inner_gap_angle;
qreal inner_pie_angle = pie_angle - 2 * half_inner_gap_angle;
qreal outer_start_angle = 45.0 + half_outer_gap_angle;
qreal outer_pie_angle = pie_angle - 2 * half_outer_gap_angle;
QPainterPath path;
for (int i = 0; i < 4; ++i) {
path.arcMoveTo(-outer_diam/2.0, -outer_diam/2.0, outer_diam, outer_diam, outer_start_angle);
path.arcTo(-outer_diam/2.0, -outer_diam/2.0, outer_diam, outer_diam, outer_start_angle, outer_pie_angle);
path.arcTo(-inner_diam/2.0, -inner_diam/2.0, inner_diam, inner_diam, inner_start_angle + inner_pie_angle, 0);
path.arcTo(-inner_diam/2.0, -inner_diam/2.0, inner_diam, inner_diam, inner_start_angle + inner_pie_angle, -inner_pie_angle);
path.closeSubpath();
inner_start_angle += pie_angle;
outer_start_angle += pie_angle;
}
QTransform trans;
trans.scale(1, -1);
path = trans.map(path);
QTransform mat;
mat.translate(xc, yc);
path = mat.map(path);
path = rotatePath(path, items.value(9, "0").toDouble());
feat.path = path;
res.features << feat;
}
}
}
return res;
}
QList<PcbCamOdbFeatureInfo> srFeature(const PcbCamOdbFeatureInfo &iFeat) {
QList<PcbCamOdbFeatureInfo> ret;
QTransform mat;
for (int i = 1; i <= graphicsState.srRepeatsX; ++i) {
for (int j = 1; j <= graphicsState.srRepeatsY; ++j) {
mat.reset();
mat.translate((i-1)*graphicsState.srStepI, (j-1)*graphicsState.srStepJ);
auto feat = iFeat;
feat.ps = mat.map(feat.ps);
feat.pe = mat.map(feat.pe);
feat.pc = mat.map(feat.pc);
feat.path = mat.map(feat.path);
ret << feat;
}
}
return ret;
}
protected:
PcbCamGerber274XParser * const q_ptr;
};
PcbCamGerber274XParser::PcbCamGerber274XParser()
:d_ptr(new PcbCamGerber274XParserPrivate(this))
{
}
PcbCamGerber274XParser::~PcbCamGerber274XParser()
{
}
void PcbCamGerber274XParser::parse(QIODevice *iIODevice)
{
Q_D(PcbCamGerber274XParser);
d->apertures.clear();
d->featureList.clear();
d->errorList.clear();
d->curRegionPath = QPainterPath();
d->apertureMacroDefines.clear();
QString line;
char c;
bool inblock = false;
bool lineend = false;
while (iIODevice->getChar(&c)) {
if (c == '\n' || c == '\r') continue;
if (inblock) {
if (c == '%') {
inblock = false;
lineend = true;
}
else if (c == '*' && !line.startsWith("AM")) {
lineend = true;
}
else {
line.append(c);
}
}
else {
if (c == '%') {
inblock = true;
}
else if (c == '*') {
lineend = true;
}
else {
line.append(c);
}
}
if (!lineend) continue;
auto trimline = line.trimmed().toUpper();
trimline.replace(" ", "");
line.clear();
lineend = false;
if (trimline.isEmpty()) continue;
QMapIterator<PcbCamGerber274XParser::Cmd, QRegularExpression> iter(d->paramRegxs);
while (iter.hasNext()) {
iter.next();
auto match = d->getRegxCaptures(iter.value(), trimline);
if (!match.hasMatch) continue;
auto cmd = iter.key();
auto param = match.captures;
if (cmd == Cmd::COORD) {
auto gmode_str = param.value("cmd");
if (!gmode_str.isEmpty()) {
auto gmode = gmode_str.toInt();
if (gmode == 1) {
d->graphicsState.interpolationMode = PcbCamGerber274XParserPrivate::LinearMode;
}
else if (gmode == 2) {
d->graphicsState.interpolationMode = PcbCamGerber274XParserPrivate::ClockwiseCircularMode;
}
else if (gmode == 3) {
d->graphicsState.interpolationMode = PcbCamGerber274XParserPrivate::CounterclockwiseCircularMode;
}
}
auto op_str = param.value("op");
if (!op_str.isEmpty()) {
d->graphicsState.operationMode = op_str.toInt();
}
if (!param.value("coord").isEmpty() || !op_str.isEmpty()) {
QPointF pos = d->graphicsState.currentPoint;
QRegularExpressionMatchIterator matchiter = d->coordRegx.globalMatch(param.value("coord"));
QMap<QString, QString> coordparam;
while (matchiter.hasNext()) {
auto match = matchiter.next();
coordparam.insert(match.captured(1).toLower(), match.captured(2));
}
auto x_str = coordparam.value("x");
auto y_str = coordparam.value("y");
if (!x_str.isEmpty()) {
pos.setX(d->coord2inch(x_str));
}
if (!y_str.isEmpty()) {
pos.setY(d->coord2inch(y_str));
}
if (d->graphicsState.regionMode) {
if (d->graphicsState.operationMode == 1) { //D01
if (d->curRegionPath.isEmpty()) {
d->curRegionPath.moveTo(d->graphicsState.currentPoint);
}
if (d->graphicsState.interpolationMode == PcbCamGerber274XParserPrivate::LinearMode) {
d->curRegionPath.lineTo(pos);
}
else if (d->graphicsState.interpolationMode == PcbCamGerber274XParserPrivate::ClockwiseCircularMode
|| d->graphicsState.interpolationMode == PcbCamGerber274XParserPrivate::CounterclockwiseCircularMode)
{
auto ps = d->graphicsState.currentPoint;
bool cw = d->graphicsState.interpolationMode == PcbCamGerber274XParserPrivate::ClockwiseCircularMode;
auto pc = d->calcArcCenter(ps, pos, d->coord2inch(coordparam.value("i", "0")), d->coord2inch(coordparam.value("j", "0")), cw, d->graphicsState.quadrantMode);
double startAngle;
double sweepLength;
auto arcrect = PcbCamUtil::calcPathArc(ps, pos, pc, cw, &startAngle, &sweepLength);
d->curRegionPath.arcTo(arcrect, startAngle, sweepLength);
}
}
else if (d->graphicsState.operationMode == 2) { //D02
if (!d->curRegionPath.isEmpty()) {
d->curRegionPath.closeSubpath();
}
d->curRegionPath.moveTo(pos);
}
else if (d->graphicsState.operationMode == 3) { //D03
// not allowed
}
}
else {
if (d->graphicsState.operationMode == 1) { //D01
if (d->graphicsState.interpolationMode == PcbCamGerber274XParserPrivate::LinearMode) {
PcbCamOdbFeatureInfo feat;
feat.polarity = d->graphicsState.polarity;
feat.type = PcbCam::LineFeature;
feat.ps = d->graphicsState.currentPoint;
feat.pe = pos;
feat.decode = d->graphicsState.currentAperture;
if (d->graphicsState.srMode) {
d->featureList << d->srFeature(feat);
}
else {
d->featureList << feat;
}
}
else if (d->graphicsState.interpolationMode == PcbCamGerber274XParserPrivate::ClockwiseCircularMode
|| d->graphicsState.interpolationMode == PcbCamGerber274XParserPrivate::CounterclockwiseCircularMode)
{
auto ps = d->graphicsState.currentPoint;
bool cw = d->graphicsState.interpolationMode == PcbCamGerber274XParserPrivate::ClockwiseCircularMode;
auto pc = d->calcArcCenter(ps, pos, d->coord2inch(coordparam.value("i", "0")), d->coord2inch(coordparam.value("j", "0")), cw, d->graphicsState.quadrantMode);
PcbCamOdbFeatureInfo feat;
feat.polarity = d->graphicsState.polarity;
feat.type = PcbCam::ArcFeature;
feat.ps = ps;
feat.pe = pos;
feat.pc = pc;
feat.cw = cw;
feat.decode = d->graphicsState.currentAperture;
if (d->graphicsState.srMode) {
d->featureList << d->srFeature(feat);
}
else {
d->featureList << feat;
}
}
}
else if (d->graphicsState.operationMode == 2) { //D02
// only move point
}
else if (d->graphicsState.operationMode == 3) { //D03
PcbCamOdbFeatureInfo feat;
feat.polarity = d->graphicsState.polarity;
feat.type = PcbCam::PadFeature;
feat.ps = pos;
feat.decode = d->graphicsState.currentAperture;
if (d->graphicsState.srMode) {
d->featureList << d->srFeature(feat);
}
else {
d->featureList << feat;
}
}
}
d->graphicsState.currentPoint = pos;
}
}
else if (cmd == Cmd::APERTURE_SELECT) {
d->graphicsState.currentAperture = param.value("dcode").toInt();
}
else if (cmd == Cmd::REGION_MODE) {
d->graphicsState.regionMode = param.value("cmd") == "G36";
if (!d->graphicsState.regionMode) {
PcbCamOdbFeatureInfo feat;
feat.polarity = d->graphicsState.polarity;
feat.type = PcbCam::SurfaceFeature;
feat.path = d->curRegionPath;
if (d->graphicsState.srMode) {
d->featureList << d->srFeature(feat);
}
else {
d->featureList << feat;
}
d->curRegionPath = QPainterPath();
}
}
else if (cmd == Cmd::QUAD_MODE) {
d->graphicsState.quadrantMode = param.value("cmd") == "G75" ? PcbCamGerber274XParserPrivate::MultiQuadrant : PcbCamGerber274XParserPrivate::SingleQuadrant;
}
else if (cmd == Cmd::DEPRECATED_UNIT) {
d->graphicsState.units = param.value("cmd") == "G70" ? PcbCam::Units_Inch : PcbCam::Units_Mm;
}
else if (cmd == Cmd::DEPRECATED_FORMAT) {
d->graphicsState.coordNotation = param.value("cmd") == "G91" ? PcbCam::CoordIncremental : PcbCam::CoordAbsoulte;
}
else if (cmd == Cmd::FS) {
// Format Sepcification
if (param.value("zero") == "L") {
d->graphicsState.zerosOmit = PcbCam::ZerosOmit_Leading;
}
else if (param.value("zero") == "T") {
d->graphicsState.zerosOmit = PcbCam::ZerosOmit_Training;
}
else {
d->graphicsState.zerosOmit = PcbCam::ZerosOmit_None;
}
d->graphicsState.coordNotation = param.value("notation") == "I" ? PcbCam::CoordIncremental : PcbCam::CoordAbsoulte;
d->graphicsState.integerDigits = param.value("wx").toInt();
d->graphicsState.decimalDigits = param.value("dx").toUInt();
}
else if (cmd == Cmd::MO) {
// Unit Mode
d->graphicsState.units = param.value("mo") == "IN" ? PcbCam::Units_Inch : PcbCam::Units_Mm;
}
else if (cmd == Cmd::LP) {
// Layer Polarity
d->graphicsState.polarity = param.value("lp") == "C" ? PcbCam::Negative : PcbCam::Positive;
}
else if (cmd == Cmd::AD_CIRCLE) {
// Aperture Define
auto ap = d->createCircleAperture(param);
d->apertures.insert(ap.dcode, ap);
}
else if (cmd == Cmd::AD_RECT) {
auto ap = d->createRectAperture(param);
d->apertures.insert(ap.dcode, ap);
}
else if (cmd == Cmd::AD_OBROUND) {
auto ap = d->createObroundAperture(param);
d->apertures.insert(ap.dcode, ap);
}
else if (cmd == Cmd::AD_POLY) {
auto ap = d->createPolyAperture(param);
d->apertures.insert(ap.dcode, ap);
}
else if (cmd == Cmd::AD_MACRO) {
auto ap = d->createSpecialAperture(param);
d->apertures.insert(ap.dcode, ap);
}
else if (cmd == Cmd::AM) {
// Aperture Macro
d->apertureMacroDefines.insert(param.value("name"), param.value("modifiers").split('*', Qt::SkipEmptyParts));
}
else if (cmd == Cmd::SR) {
auto coordstr = param.value("coord");
d->graphicsState.srMode = !coordstr.isEmpty();
if (d->graphicsState.srMode) {
QRegularExpressionMatchIterator matchiter = d->coordRegx.globalMatch(param.value("coord"));
QMap<QString, QString> coordparam;
while (matchiter.hasNext()) {
auto match = matchiter.next();
coordparam.insert(match.captured(1).toLower(), match.captured(2));
}
d->graphicsState.srRepeatsX = coordparam.value("x", "0").toInt();
d->graphicsState.srRepeatsY = coordparam.value("y", "0").toInt();
d->graphicsState.srStepI = coordparam.value("i", "0.0").toDouble();
d->graphicsState.srStepJ = coordparam.value("j", "0.0").toDouble();
}
else {
d->graphicsState.srRepeatsX = 1;
d->graphicsState.srRepeatsY = 1;
d->graphicsState.srStepI = 0.0;
d->graphicsState.srStepJ = 0.0;
}
}
else if (cmd == Cmd::IF) {
// Include File
// TODO
}
else if (cmd == Cmd::IN) {
// Image Name, just a comment
}
else if (cmd == Cmd::LN) {
// Layer Name, just a comment
}
else if (cmd == Cmd::IP) {
// Image Polarity, IPPOS* or IPNEG*
}
else if (cmd == Cmd::AS) {
// Axis assignment, ASAXBY* or ASAYBX*
// TODO
}
else if (cmd == Cmd::IR) {
// Image Rotation, IR0 IR90 IR180 IR270
// TODO
}
else if (cmd == Cmd::MI) {
// Mirror Image %MIA0B0%
// TODO
}
else if (cmd == Cmd::OF) {
// Image Offset
// TODO
}
else if (cmd == Cmd::SF) {
// Scale Factor
// TODO
}
break;
}
}
}
QList<PcbCamOdbFeatureInfo> PcbCamGerber274XParser::features() const
{
Q_D(const PcbCamGerber274XParser);
return d->featureList;
}
QMap<int, PcbCamGerber274XParser::ApertureInfo> PcbCamGerber274XParser::apertures() const
{
Q_D(const PcbCamGerber274XParser);
return d->apertures;
}
TITAN_END_NAMESPACE
#ifndef TITAN_PCBCAM_GERBER274XPARSER_H
#define TITAN_PCBCAM_GERBER274XPARSER_H
#include "../titanpcbcamglobal.h"
#include "odbfeatureparser.h"
TITAN_BEGIN_NAMESPACE
class PcbCamGerber274XParserPrivate;
class TITAN_PCBCAM_EXPORT PcbCamGerber274XParser
{
public:
struct ApertureInfo {
int dcode {0};
QString name;
bool isStandard {true};
QList<PcbCamOdbFeatureInfo> features;
};
enum class Cmd {
COORD = 0,
APERTURE_SELECT = 1,
FS,
MO,
LP,
AD_CIRCLE,
AD_RECT,
AD_OBROUND,
AD_POLY,
AD_MACRO,
AM,
IF,
REGION_MODE,
QUAD_MODE,
SR,
// 以下为旧版格式命令
AS,
IN,
IP,
IR,
IO,
MI,
OF,
SF,
LN,
DEPRECATED_UNIT,
DEPRECATED_FORMAT,
UNKNOW ,
EMPTY,
};
PcbCamGerber274XParser();
~PcbCamGerber274XParser();
void parse(QIODevice *iIODevice);
QStringList errors();
QList<PcbCamOdbFeatureInfo> features() const;
QMap<int, ApertureInfo> apertures() const;
protected:
const QScopedPointer<PcbCamGerber274XParserPrivate> d_ptr;
private:
Q_DECLARE_PRIVATE(PcbCamGerber274XParser)
Q_DISABLE_COPY(PcbCamGerber274XParser)
};
TITAN_END_NAMESPACE
#endif // TITAN_PCBCAM_GERBER274XPARSER_H
#include "odbcomponentparser.h"
#include <QTextStream>
#include <QStringList>
#include <QtMath>
TITAN_BEGIN_NAMESPACE
class PcbCamOdbComponentParserPrivate
{
Q_DECLARE_PUBLIC(PcbCamOdbComponentParser)
public:
PcbCamOdbComponentParserPrivate(PcbCamOdbComponentParser *qptr) : q_ptr(qptr){ }
~PcbCamOdbComponentParserPrivate() { }
QList<PcbCamOdbFeatureInfo> featureList;
QStringList errorList;
QByteArray featData;
QHash<int, QString> symbolsHash;
QHash<int, QString> attrNameHash;
QHash<int, QString> attrTextHash;
protected:
PcbCamOdbComponentParser * const q_ptr;
};
PcbCamOdbComponentParser::PcbCamOdbComponentParser(const QByteArray &iData)
: d_ptr(new PcbCamOdbComponentParserPrivate(this))
{
Q_D(PcbCamOdbComponentParser);
d->featData = iData;
}
PcbCamOdbComponentParser::~PcbCamOdbComponentParser()
{
}
void PcbCamOdbComponentParser::parse()
{
Q_D(PcbCamOdbComponentParser);
d->attrNameHash.clear();
d->attrTextHash.clear();
d->featureList.clear();
d->errorList.clear();
QTextStream stream(&d->featData);
QString line;
while (stream.readLineInto(&line)) {
if (line.startsWith("#") || line.length() == 0) { // comment
continue;
}
if (line.startsWith("@")) { // symbol names
parseAttrName(line);
}
else if (line.startsWith("&")) { // attr text strings
parseAttrText(line);
}
else if (line.startsWith("CMP")) { // component
parseComponent(line);
}
}
}
QList<PcbCamOdbFeatureInfo> PcbCamOdbComponentParser::features()
{
Q_D(const PcbCamOdbComponentParser);
return d->featureList;
}
QStringList PcbCamOdbComponentParser::errors()
{
Q_D(const PcbCamOdbComponentParser);
return d->errorList;
}
void PcbCamOdbComponentParser::parseAttrName(const QString &iLine)
{
Q_D(PcbCamOdbComponentParser);
QStringList tmp = iLine.split(" ", Qt::SkipEmptyParts);
if (tmp.length() == 2) {
d->attrNameHash.insert(tmp[0].mid(1).toInt(), tmp[1]);
}
}
void PcbCamOdbComponentParser::parseAttrText(const QString &iLine)
{
Q_D(PcbCamOdbComponentParser);
QStringList tmp = iLine.split(" ", Qt::SkipEmptyParts);
if (tmp.length() == 2) {
d->attrTextHash.insert(tmp[0].mid(1).toInt(), tmp[1]);
}
}
void PcbCamOdbComponentParser::parseComponent(const QString &iLine)
{
Q_D(PcbCamOdbComponentParser);
QStringList param;
QVariantMap attrmap;
parseAttributes(iLine, &param, &attrmap);
// CMP <pkg_ref> <x> <y> <rot> <mirror> <comp_name> <part_name> ; <attributes>
PcbCamOdbFeatureInfo feat;
feat.type = PcbCam::ComponentFeature;
feat.ps = QPointF(param.value(2).toDouble(), param.value(3).toDouble());
feat.symbol = param.value(1);
feat.widthFactor = param.value(4).toDouble(); // 为了节省内层空间,角度<rot>放在widthFactor里
feat.cw = (param.value(5) == "Y"); // 为了节省内层空间,是否镜像<mirror>放在cw里
feat.text = param.value(6); // comp_name
feat.font = param.value(7); // part_name
feat.attributes = attrmap;
d->featureList.append(feat);
}
void PcbCamOdbComponentParser::parseAttributes(const QString &iLine, QStringList *oParams, QVariantMap *oAttrMap) const
{
Q_D(const PcbCamOdbComponentParser);
//拆分属性
//CMP 9 3.7385827 5.1106299 180.0 N J7002 998-6533 ;0=2,1=0.166142
int loc = iLine.lastIndexOf(";");
QString record = iLine.left(loc).trimmed();
QString attr;
if (loc != -1) {
attr = iLine.right(iLine.length() - loc - 1).trimmed();
}
//拆分文字的单引号
//CMP 9 3.7385827 5.1106299 180.0 N 'J7002 1' 998-6533 1;0
if (record.indexOf("'") != -1) {
int loc = record.indexOf("'");
int loc2 = record.indexOf("'", loc + 1);
QString left = record.left(loc);
QString middle = record.mid(loc + 1, loc2 - loc - 1);
QString right = record.right(record.length() - loc2 - 1);
*oParams = left.split(" ", Qt::SkipEmptyParts);
*oParams << middle;
*oParams += right.split(" ", Qt::SkipEmptyParts);
} else {
*oParams = record.split(" ", Qt::SkipEmptyParts);
}
if (!attr.isEmpty()) {
QStringList terms = attr.split(',');
for (int i = 0; i < terms.size(); ++i) {
QStringList v = terms[i].split('=');
QString key = d->attrNameHash.value(v[0].toInt());
if (v.size() == 1) {
oAttrMap->insert(key, QVariant(true));
} else {
oAttrMap->insert(key, d->attrTextHash.value(v[1].toInt()));
}
}
}
}
TITAN_END_NAMESPACE
#ifndef TITAN_PCBCAM_ODBCOMPONENTPARSER_H
#define TITAN_PCBCAM_ODBCOMPONENTPARSER_H
#include "../titanpcbcamglobal.h"
#include "odbfeatureparser.h"
TITAN_BEGIN_NAMESPACE
class PcbCamOdbComponentParserPrivate;
class TITAN_PCBCAM_EXPORT PcbCamOdbComponentParser
{
public:
PcbCamOdbComponentParser(const QByteArray &iData);
~PcbCamOdbComponentParser();
void parse();
QList<PcbCamOdbFeatureInfo> features();
QStringList errors();
private:
void parseAttrName(const QString &iLine);
void parseAttrText(const QString &iLine);
void parseComponent(const QString &iLine);
void parseAttributes(const QString &iLine, QStringList *oParams, QVariantMap *oAttrMap) const;
protected:
const QScopedPointer<PcbCamOdbComponentParserPrivate> d_ptr;
private:
Q_DECLARE_PRIVATE(PcbCamOdbComponentParser)
Q_DISABLE_COPY(PcbCamOdbComponentParser)
};
TITAN_END_NAMESPACE
#endif // TITAN_PCBCAM_ODBCOMPONENTPARSER_H
#include "odbedadataparser.h"
#include <QTextStream>
#include <QtMath>
TITAN_BEGIN_NAMESPACE
class PcbCamOdbEdaDataParserPrivate
{
Q_DECLARE_PUBLIC(PcbCamOdbEdaDataParser)
public:
PcbCamOdbEdaDataParserPrivate(PcbCamOdbEdaDataParser *qptr) : q_ptr(qptr) { }
~PcbCamOdbEdaDataParserPrivate() { }
QByteArray edaData;
QList<QList<PcbCamOdbFeatureInfo>> packageList;
QStringList errorList;
QList<PcbCamOdbFeatureInfo> tmpFeatureList;
PcbCamOdbFeatureInfo lastSurfaceInfo;
QPainterPath lastPath;
qreal lastSurfacePx {0.0};
qreal lastSurfacePy {0.0};
protected:
PcbCamOdbEdaDataParser * const q_ptr;
};
PcbCamOdbEdaDataParser::PcbCamOdbEdaDataParser(const QByteArray &iEdaData)
: d_ptr(new PcbCamOdbEdaDataParserPrivate(this))
{
Q_D(PcbCamOdbEdaDataParser);
d->edaData = iEdaData;
}
PcbCamOdbEdaDataParser::~PcbCamOdbEdaDataParser()
{
}
void PcbCamOdbEdaDataParser::parse()
{
Q_D(PcbCamOdbEdaDataParser);
d->packageList.clear();
d->errorList.clear();
d->tmpFeatureList.clear();
bool isInSurface = false;
QTextStream stream(&d->edaData);
QString line;
int sectionFlag = 0; // 0:未知 1:PKG(Package Record) 2:PIN(Pin Record) 3:FGR(Feature Group Record) 4:FID(Feature ID Record) 5:PRP(Property Record)
while (stream.readLineInto(&line)) {
if (line.startsWith("#") || line.length() == 0) { // comment
continue;
}
if (line.startsWith("PKG ")) {
if (!d->tmpFeatureList.isEmpty()) {
d->packageList.append(d->tmpFeatureList);
}
d->tmpFeatureList.clear();
sectionFlag = 1;
}
else if (line.startsWith("PIN ")) {
sectionFlag = 2;
}
else if (line.startsWith("FGR ")) {
sectionFlag = 3;
}
else if (line.startsWith("FID ")) {
sectionFlag = 4;
}
else if (line.startsWith("PRP ")) {
sectionFlag = 5;
}
if (sectionFlag >= 1 && sectionFlag <= 4) {
if (isInSurface) {
if (line.startsWith("CE")) {
isInSurface = false;
PcbCamOdbFeatureInfo feat;
feat.type = PcbCam::PathFeature;
feat.path = d->lastPath;
feat.widthFactor = sectionFlag == 1 ? 2 : 1;
d->tmpFeatureList.append(feat);
d->lastPath = QPainterPath();
}
else {
parseSurfaceLine(line);
}
continue;
}
if (line.startsWith("CR")) { // circle record
QStringList params = line.split(" ", Qt::SkipEmptyParts);
PcbCamOdbFeatureInfo feat;
feat.type = PcbCam::PathFeature;
QPainterPath path;
double xc = params.value(1).toDouble();
double yc = params.value(2).toDouble();
double r = params.value(3).toDouble();
path.addEllipse(QPointF(xc, yc), r*2.0, r*2.0);
feat.path = path;
feat.widthFactor = sectionFlag == 1 ? 2 : 1;
d->tmpFeatureList.append(feat);
}
else if (line.startsWith("SQ")) { // square record
QStringList params = line.split(" ", Qt::SkipEmptyParts);
PcbCamOdbFeatureInfo feat;
feat.type = PcbCam::PathFeature;
QPainterPath path;
double xc = params.value(1).toDouble();
double yc = params.value(2).toDouble();
double r = params.value(3).toDouble();
path.addRect(xc-r, yc-r, r*2.0, r*2.0);
feat.path = path;
feat.widthFactor = sectionFlag == 1 ? 2 : 1;
d->tmpFeatureList.append(feat);
}
else if (line.startsWith("RC")) { // rectangle record
QStringList params = line.split(" ", Qt::SkipEmptyParts);
PcbCamOdbFeatureInfo feat;
feat.type = PcbCam::PathFeature;
QPainterPath path;
double xs = params.value(1).toDouble();
double ys = params.value(2).toDouble();
double w = params.value(3).toDouble();
double h = params.value(4).toDouble();
path.addRect(xs, ys, w, h);
feat.path = path;
feat.widthFactor = sectionFlag == 1 ? 2 : 1;
d->tmpFeatureList.append(feat);
}
else if (line.startsWith("CT")) { // start contour record
d->lastPath = QPainterPath();
isInSurface = true;
}
}
}
if (!d->tmpFeatureList.isEmpty()) {
d->packageList.append(d->tmpFeatureList);
}
}
QList<QList<PcbCamOdbFeatureInfo> > PcbCamOdbEdaDataParser::packageFeatures()
{
Q_D(const PcbCamOdbEdaDataParser);
return d->packageList;
}
QStringList PcbCamOdbEdaDataParser::errors()
{
Q_D(const PcbCamOdbEdaDataParser);
return d->errorList;
}
void PcbCamOdbEdaDataParser::parseSurfaceLine(const QString &iLine)
{
Q_D(PcbCamOdbEdaDataParser);
QStringList param = iLine.split(" ", Qt::SkipEmptyParts);
if (param.value(0) == "OB") {
d->lastSurfacePx = param.value(1).toDouble();
d->lastSurfacePy = param.value(2).toDouble();
d->lastPath.moveTo(d->lastSurfacePx, d->lastSurfacePy);
}
else if (param.value(0) == "OS") {
d->lastSurfacePx = param.value(1).toDouble();
d->lastSurfacePy = param.value(2).toDouble();
d->lastPath.lineTo(d->lastSurfacePx, d->lastSurfacePy);
}
else if (param.value(0) == "OC") {
qreal sx = d->lastSurfacePx, sy = d->lastSurfacePy;
qreal ex = param.value(1).toDouble(), ey = param.value(2).toDouble();
qreal cx = param.value(3).toDouble(), cy = param.value(4).toDouble();
bool cw = param.value(5) == "Y" ? true : false;
qreal sax = sx - cx, say = sy - cy;
qreal eax = ex - cx, eay = ey - cy;
qreal r = qSqrt(sax * sax + say * say);
qreal sa = qAtan2(-say, sax);
qreal ea = qAtan2(-eay, eax);
if (cw) {
if (ea <= sa) {
ea += 2.0 * M_PI;
}
}
else {
if (sa <= ea) {
sa += 2.0 * M_PI;
}
}
d->lastPath.arcTo(QRectF(cx -r, cy -r, r *2, r *2), sa * (180.0 / M_PI), (ea - sa) * (180.0 / M_PI));
d->lastSurfacePx = ex;
d->lastSurfacePy = ey;
}
else if (param.value(0) == "OE") {
d->lastPath.closeSubpath();
}
}
TITAN_END_NAMESPACE
#ifndef TITAN_PCBCAM_ODBEDAPACKAGEPARSER_H
#define TITAN_PCBCAM_ODBEDAPACKAGEPARSER_H
#include "../titanpcbcamglobal.h"
#include "odbfeatureparser.h"
TITAN_BEGIN_NAMESPACE
class PcbCamOdbEdaDataParserPrivate;
class TITAN_PCBCAM_EXPORT PcbCamOdbEdaDataParser
{
public:
PcbCamOdbEdaDataParser(const QByteArray &iEdaData);
~PcbCamOdbEdaDataParser();
void parse();
QList<QList<PcbCamOdbFeatureInfo>> packageFeatures();
QStringList errors();
private:
void parseSurfaceLine(const QString &iLine);
protected:
const QScopedPointer<PcbCamOdbEdaDataParserPrivate> d_ptr;
private:
Q_DECLARE_PRIVATE(PcbCamOdbEdaDataParser)
Q_DISABLE_COPY(PcbCamOdbEdaDataParser)
};
TITAN_END_NAMESPACE
#endif // TITAN_PCBCAM_ODBEDAPACKAGEPARSER_H
#include "odbfeatureparser.h"
#include <QTextStream>
#include <QStringList>
#include <QtMath>
#include "../core/util.h"
TITAN_BEGIN_NAMESPACE
class PcbCamOdbFeatureParserPrivate
{
Q_DECLARE_PUBLIC(PcbCamOdbFeatureParser)
public:
PcbCamOdbFeatureParserPrivate(PcbCamOdbFeatureParser *qptr) : q_ptr(qptr) { }
~PcbCamOdbFeatureParserPrivate() { }
QList<PcbCamOdbFeatureInfo> featureList;
PcbCamOdbFeatureInfo lastSurfaceInfo;
QStringList errorList;
QByteArray featData;
QPainterPath lastPath;
qreal lastSurfacePx {0.0};
qreal lastSurfacePy {0.0};
QHash<int, QString> symbolsHash;
QHash<int, QString> attrNameHash;
QHash<int, QString> attrTextHash;
protected:
PcbCamOdbFeatureParser * const q_ptr;
};
PcbCamOdbFeatureParser::PcbCamOdbFeatureParser(const QByteArray &iFeatData)
: d_ptr(new PcbCamOdbFeatureParserPrivate(this))
{
Q_D(PcbCamOdbFeatureParser);
d->featData = iFeatData;
}
PcbCamOdbFeatureParser::~PcbCamOdbFeatureParser()
{
}
void PcbCamOdbFeatureParser::parse()
{
Q_D(PcbCamOdbFeatureParser);
d->symbolsHash.clear();
d->attrNameHash.clear();
d->attrTextHash.clear();
d->featureList.clear();
d->errorList.clear();
bool isInSurface = false;
QTextStream stream(&d->featData);
QString line;
while (stream.readLineInto(&line)) {
if (line.startsWith("#") || line.length() == 0) { // comment
continue;
}
if (isInSurface) {
if (line.startsWith("SE")) {
isInSurface = false;
parseSurfaceEnd();
} else {
parseSurfaceLine(line);
}
continue;
}
if (line.startsWith("$")) { // symbol names
parseSymbolName(line);
} else if (line.startsWith("@")) { // attrib names
parseAttrName(line);
} else if (line.startsWith("&")) { // attrib text strings
parseAttrText(line);
} else if (line.startsWith("L")) { // line
parseLine(line);
} else if (line.startsWith("P")) { // pad
parsePad(line);
} else if (line.startsWith("A")) { // arc
parseArc(line);
} else if (line.startsWith("T")) { // text
parseText(line);
} else if (line.startsWith("B")) { // barcode
parseBarcode(line);
} else if (line.startsWith("S")) { // surface
parseSurfaceStart(line);
isInSurface = true;
}
}
}
QList<PcbCamOdbFeatureInfo> PcbCamOdbFeatureParser::features()
{
Q_D(const PcbCamOdbFeatureParser);
return d->featureList;
}
QStringList PcbCamOdbFeatureParser::errors()
{
Q_D(const PcbCamOdbFeatureParser);
return d->errorList;
}
QStringList PcbCamOdbFeatureParser::symbols()
{
Q_D(const PcbCamOdbFeatureParser);
return d->symbolsHash.values();
}
void PcbCamOdbFeatureParser::parseSymbolName(const QString &iLine)
{
Q_D(PcbCamOdbFeatureParser);
QStringList tmp = iLine.split(" ", Qt::SkipEmptyParts);
if (tmp.length() == 2) {
d->symbolsHash.insert(tmp[0].mid(1).toInt(), tmp[1]);
}
}
void PcbCamOdbFeatureParser::parseAttrName(const QString &iLine)
{
Q_D(PcbCamOdbFeatureParser);
QStringList tmp = iLine.split(" ", Qt::SkipEmptyParts);
if (tmp.length() == 2) {
d->attrNameHash.insert(tmp[0].mid(1).toInt(), tmp[1]);
}
}
void PcbCamOdbFeatureParser::parseAttrText(const QString &iLine)
{
Q_D(PcbCamOdbFeatureParser);
QStringList tmp = iLine.split(" ", Qt::SkipEmptyParts);
if (tmp.length() == 2) {
d->attrTextHash.insert(tmp[0].mid(1).toInt(), tmp[1]);
}
}
void PcbCamOdbFeatureParser::parseLine(const QString &iLine)
{
Q_D(PcbCamOdbFeatureParser);
QStringList param;
QVariantMap attrmap;
parseAttributes(iLine, &param, &attrmap);
PcbCamOdbFeatureInfo feat;
feat.type = PcbCam::LineFeature;
feat.ps = QPointF(param.value(1).toDouble(), param.value(2).toDouble());
feat.pe = QPointF(param.value(3).toDouble(), param.value(4).toDouble());
feat.symbol = d->symbolsHash.value(param.value(5).toInt());
feat.polarity = param.value(6) == "P" ? PcbCam::Positive : PcbCam::Negative;
feat.decode = param.value(7).toInt();
feat.attributes = attrmap;
d->featureList.append(feat);
}
void PcbCamOdbFeatureParser::parsePad(const QString &iLine)
{
Q_D(PcbCamOdbFeatureParser);
QStringList param;
QVariantMap attrmap;
parseAttributes(iLine, &param, &attrmap);
PcbCamOdbFeatureInfo feat;
feat.type = PcbCam::PadFeature;
feat.ps = QPointF(param.value(1).toDouble(), param.value(2).toDouble());
feat.symbol = d->symbolsHash.value(param.value(3).toInt());
feat.polarity = param.value(4) == "P" ? PcbCam::Positive : PcbCam::Negative;
feat.decode = param.value(5).toInt();
feat.orient = (PcbCam::Orient)param.value(6).toInt();
feat.attributes = attrmap;
d->featureList.append(feat);
}
void PcbCamOdbFeatureParser::parseArc(const QString &iLine)
{
Q_D(PcbCamOdbFeatureParser);
QStringList param;
QVariantMap attrmap;
parseAttributes(iLine, &param, &attrmap);
PcbCamOdbFeatureInfo feat;
feat.type = PcbCam::ArcFeature;
feat.ps = QPointF(param.value(1).toDouble(), param.value(2).toDouble());
feat.pe = QPointF(param.value(3).toDouble(), param.value(4).toDouble());
feat.pc = QPointF(param.value(5).toDouble(), param.value(6).toDouble());
feat.cw = param.value(10) == "Y" ? true : false;
feat.symbol = d->symbolsHash.value(param.value(7).toInt());
feat.polarity = param.value(8) == "P" ? PcbCam::Positive : PcbCam::Negative;
feat.decode = param.value(9).toInt();
feat.attributes = attrmap;
d->featureList.append(feat);
}
void PcbCamOdbFeatureParser::parseText(const QString &iLine)
{
Q_D(PcbCamOdbFeatureParser);
QStringList param;
QVariantMap attrmap;
parseAttributes(iLine, &param, &attrmap);
PcbCamOdbFeatureInfo feat;
feat.type = PcbCam::TextFeature;
feat.ps = QPointF(param.value(1).toDouble(), param.value(2).toDouble());
feat.font = param.value(3);
feat.polarity = param.value(4) == "P" ? PcbCam::Positive : PcbCam::Negative;
feat.orient = (PcbCam::Orient)param.value(5).toInt();
feat.size = QSizeF(param.value(6).toDouble(), param.value(7).toDouble());
feat.widthFactor = param.value(8).toDouble();
feat.text = param.value(9);
feat.version = param.value(10).toInt();
feat.attributes = attrmap;
d->featureList.append(feat);
}
void PcbCamOdbFeatureParser::parseBarcode(const QString &iLine)
{
Q_D(PcbCamOdbFeatureParser);
QStringList param;
QVariantMap attrmap;
parseAttributes(iLine, &param, &attrmap);
PcbCamOdbFeatureInfo feat;
feat.type = PcbCam::BarcodeFeature;
feat.ps = QPointF(param.value(1).toDouble(), param.value(2).toDouble());
feat.barcode = param.value(3);
feat.font = param.value(4);
feat.polarity = param.value(5) == "P" ? PcbCam::Positive : PcbCam::Negative;
feat.orient = (PcbCam::Orient)param.value(6).toInt();
feat.size = QSize(param.value(8).toDouble(), param.value(9).toDouble());
feat.fullAscii = param.value(10) == "Y" ? true : false;
feat.checkSum = param.value(11) == "Y" ? true : false;
feat.background = param.value(12) == "Y" ? true : false;
feat.additionStr = param.value(13) == "Y" ? true : false;
feat.additionStrPos = param.value(14) == "T" ? PcbCam::BarcodeTextPos_Top : PcbCam::BarcodeTextPos_Bot;
feat.text = param.value(15);
feat.attributes = attrmap;
d->featureList.append(feat);
}
void PcbCamOdbFeatureParser::parseSurfaceStart(const QString &iLine)
{
Q_D(PcbCamOdbFeatureParser);
QStringList param;
QVariantMap attrmap;
parseAttributes(iLine, &param, &attrmap);
d->lastSurfaceInfo = PcbCamOdbFeatureInfo();
d->lastSurfaceInfo.type = PcbCam::SurfaceFeature;
d->lastPath = QPainterPath();
d->lastSurfaceInfo.polarity = param.value(1) == "P" ? PcbCam::Positive : PcbCam::Negative;
d->lastSurfaceInfo.decode = param.value(2).toInt();
d->lastSurfaceInfo.attributes = attrmap;
}
void PcbCamOdbFeatureParser::parseSurfaceLine(const QString &iLine)
{
Q_D(PcbCamOdbFeatureParser);
QStringList param = iLine.split(" ", Qt::SkipEmptyParts);
if (param.value(0) == "OB") {
d->lastSurfacePx = param.value(1).toDouble();
d->lastSurfacePy = param.value(2).toDouble();
d->lastPath.moveTo(d->lastSurfacePx, d->lastSurfacePy);
}
else if (param.value(0) == "OS") {
d->lastSurfacePx = param.value(1).toDouble();
d->lastSurfacePy = param.value(2).toDouble();
d->lastPath.lineTo(d->lastSurfacePx, d->lastSurfacePy);
}
else if (param.value(0) == "OC") {
qreal sx = d->lastSurfacePx, sy = d->lastSurfacePy;
qreal ex = param.value(1).toDouble(), ey = param.value(2).toDouble();
qreal cx = param.value(3).toDouble(), cy = param.value(4).toDouble();
bool cw = param.value(5) == "Y" ? true : false;
double startAngle;
double sweepLength;
auto arcrect = PcbCamUtil::calcPathArc(QPointF(sx, sy), QPointF(ex, ey), QPointF(cx, cy), cw, &startAngle, &sweepLength);
d->lastPath.arcTo(arcrect, startAngle, sweepLength);
d->lastSurfacePx = ex;
d->lastSurfacePy = ey;
}
else if (param.value(0) == "OE") {
d->lastPath.closeSubpath();
}
}
void PcbCamOdbFeatureParser::parseSurfaceEnd()
{
Q_D(PcbCamOdbFeatureParser);
d->lastSurfaceInfo.path = d->lastPath;
d->featureList.append(d->lastSurfaceInfo);
}
void PcbCamOdbFeatureParser::parseAttributes(const QString &iLine, QStringList *oParams, QVariantMap *oAttrMap) const
{
Q_D(const PcbCamOdbFeatureParser);
//拆分属性
//P 20.31496063 4.86220472 11 N 0 0;2=62
int loc = iLine.lastIndexOf(";");
QString record = iLine.left(loc).trimmed();
QString attr;
if (loc != -1) {
attr = iLine.right(iLine.length() - loc - 1).trimmed();
}
//拆分文字的单引号
//T -1.1023622 1.10629921 standard P 3 0.08661417 0.10031496 0.82021 'X=0.000 Y=545.900 D=545.900' 1;0
if (record.indexOf("'") != -1) {
int loc = record.indexOf("'");
int loc2 = record.indexOf("'", loc + 1);
QString left = record.left(loc);
QString middle = record.mid(loc + 1, loc2 - loc - 1);
QString right = record.right(record.length() - loc2 - 1);
*oParams = left.split(" ", Qt::SkipEmptyParts);
*oParams << middle;
*oParams += right.split(" ", Qt::SkipEmptyParts);
} else {
*oParams = record.split(" ", Qt::SkipEmptyParts);
}
if (!attr.isEmpty()) {
QStringList terms = attr.split(',');
for (int i = 0; i < terms.size(); ++i) {
QStringList v = terms[i].split('=');
QString key = d->attrNameHash.value(v[0].toInt());
if (v.size() == 1) {
oAttrMap->insert(key, QVariant(true));
} else {
oAttrMap->insert(key, d->attrTextHash.value(v[1].toInt()));
}
}
}
}
TITAN_END_NAMESPACE
#ifndef TITAN_PCBCAM_ODBFEATUREPARSERV2_H
#define TITAN_PCBCAM_ODBFEATUREPARSERV2_H
#include "../titanpcbcamglobal.h"
#include <QVariantList>
#include <QVariantMap>
#include <QPainterPath>
#include <QPointF>
#include <QSizeF>
#include "../core/common.h"
TITAN_BEGIN_NAMESPACE
struct PcbCamOdbFeatureInfo {
PcbCam::FeatureType type {PcbCam::PadFeature};
PcbCam::Polarity polarity {PcbCam::Positive};
QVariantMap attributes;
int index {0};
int decode {0};
QString symbol;
QPointF ps;
QPointF pe;
QPointF pc;
bool cw {false};
PcbCam::Orient orient {PcbCam::Orient_N_0};
QString font {"standard"};
QSizeF size;
qreal widthFactor {1.0};
QString text;
int version {1};
QString barcode;
bool fullAscii {false};
bool checkSum {false};
bool background {false};
bool additionStr {false};
PcbCam::BarcodeTextPos additionStrPos {PcbCam::BarcodeTextPos_Top};
QPainterPath path;
};
class PcbCamOdbFeatureParserPrivate;
class TITAN_PCBCAM_EXPORT PcbCamOdbFeatureParser
{
public:
PcbCamOdbFeatureParser(const QByteArray &iFeatData);
~PcbCamOdbFeatureParser();
void parse();
QList<PcbCamOdbFeatureInfo> features();
QStringList errors();
QStringList symbols();
private:
void parseSymbolName(const QString &iLine);
void parseAttrName(const QString &iLine);
void parseAttrText(const QString &iLine);
void parseLine(const QString &iLine);
void parsePad(const QString &iLine);
void parseArc(const QString &iLine);
void parseText(const QString &iLine);
void parseBarcode(const QString &iLine);
void parseSurfaceStart(const QString &iLine);
void parseSurfaceLine(const QString &iLine);
void parseSurfaceEnd();
void parseAttributes(const QString &iLine, QStringList *oParams, QVariantMap *oAttrMap) const;
protected:
const QScopedPointer<PcbCamOdbFeatureParserPrivate> d_ptr;
private:
Q_DECLARE_PRIVATE(PcbCamOdbFeatureParser)
Q_DISABLE_COPY(PcbCamOdbFeatureParser)
};
TITAN_END_NAMESPACE
#endif // TITAN_PCBCAM_ODBFEATUREPARSERV2_H
#include "odbmatrixparser.h"
#include <QFile>
#include <QTextStream>
TITAN_BEGIN_NAMESPACE
class PcbCamOdbMatrixParserPrivate
{
Q_DECLARE_PUBLIC(PcbCamOdbMatrixParser)
public:
PcbCamOdbMatrixParserPrivate(PcbCamOdbMatrixParser *qptr):q_ptr(qptr){}
~PcbCamOdbMatrixParserPrivate(){}
QByteArray data;
QMap<QString, int> steps;
QList<PcbCamMatrixLayer> layers;
QStringList errors;
protected:
PcbCamOdbMatrixParser * const q_ptr;
};
PcbCamOdbMatrixParser::PcbCamOdbMatrixParser(QObject *parent) : QObject(parent),
d_ptr(new PcbCamOdbMatrixParserPrivate(this))
{
}
PcbCamOdbMatrixParser::PcbCamOdbMatrixParser(const QByteArray &iData, QObject *parent) : QObject(parent),
d_ptr(new PcbCamOdbMatrixParserPrivate(this))
{
Q_D(PcbCamOdbMatrixParser);
d->data = iData;
}
PcbCamOdbMatrixParser::~PcbCamOdbMatrixParser()
{
}
void PcbCamOdbMatrixParser::setData(const QByteArray &iData)
{
Q_D(PcbCamOdbMatrixParser);
d->data = iData;
}
void PcbCamOdbMatrixParser::parse()
{
Q_D(PcbCamOdbMatrixParser);
d->errors.clear();
d->layers.clear();
d->steps.clear();
int block = 0; //1:step, 2:layer, 0:other
int tmpStepCol {0};
QString tmpStepName;
PcbCamMatrixLayer tmpLayer;
QTextStream stream(d->data);
QString line;
while (stream.readLineInto(&line)) {
line = line.trimmed();
if (line.length() == 0) continue;
if (line.startsWith("STEP") && line.endsWith(" {")) {
block = 1;
}
else if (line.startsWith("LAYER") && line.endsWith(" {")) {
block = 2;
}
else if (line.startsWith("}")) {
if (block == 1) {
d->steps.insert(tmpStepName, tmpStepCol);
}
else if (block == 2) {
d->layers.append(tmpLayer);
}
block = 0;
}
else {
if (block == 1) {
int loc = line.indexOf('=');
QString k = line.left(loc).trimmed();
QString v = line.mid(loc+1).trimmed();
if (k == "COL") {
tmpStepCol = v.toInt();
}
else if (k == "NAME") {
tmpStepName = v.toLower();
}
}
else if (block == 2 ) {
int loc = line.indexOf('=');
QString k = line.left(loc).trimmed();
QString v = line.mid(loc+1).trimmed();
if (k == "ROW") {
tmpLayer.setRow(v.toInt());
}
else if (k == "CONTEXT") {
if (v == "BOARD") {
tmpLayer.setContext(PcbCam::BoardContext);
}
else {
tmpLayer.setContext(PcbCam::MiscContext);
}
}
else if (k == "TYPE") {
tmpLayer.setType(v.toLower());
}
else if (k == "NAME") {
tmpLayer.setName(v.toLower());
}
else if (k == "POLARITY") {
if (v == "NEGATIVE") {
tmpLayer.setPolarity(PcbCam::Negative);
}
else {
tmpLayer.setPolarity(PcbCam::Positive);
}
}
else if (k == "OLD_NAME") {
tmpLayer.setOldName(v);
}
else if (k == "START_NAME") {
tmpLayer.setStartName(v);
}
else if (k == "END_NAME") {
tmpLayer.setEndName(v);
}
}
}
}
}
QMap<QString, int> PcbCamOdbMatrixParser::steps() const
{
Q_D(const PcbCamOdbMatrixParser);
return d->steps;
}
QList<PcbCamMatrixLayer> PcbCamOdbMatrixParser::layers() const
{
Q_D(const PcbCamOdbMatrixParser);
return d->layers;
}
QStringList PcbCamOdbMatrixParser::errors() const
{
Q_D(const PcbCamOdbMatrixParser);
return d->errors;
}
TITAN_END_NAMESPACE
#ifndef TITAN_PCBCAM_ODBMATRIXPARSER_H
#define TITAN_PCBCAM_ODBMATRIXPARSER_H
#include "../titanpcbcamglobal.h"
#include <QObject>
#include <QMap>
#include "../core/matrixlayer.h"
TITAN_BEGIN_NAMESPACE
class PcbCamOdbMatrixParserPrivate;
class TITAN_PCBCAM_EXPORT PcbCamOdbMatrixParser : public QObject
{
Q_OBJECT
public:
PcbCamOdbMatrixParser(QObject *parent = nullptr);
PcbCamOdbMatrixParser(const QByteArray &iData, QObject *parent = nullptr);
~PcbCamOdbMatrixParser();
void setData(const QByteArray &iData);
void parse();
QMap<QString, int> steps() const;
QList<PcbCamMatrixLayer> layers() const;
QStringList errors() const;
protected:
const QScopedPointer<PcbCamOdbMatrixParserPrivate> d_ptr;
private:
Q_DECLARE_PRIVATE(PcbCamOdbMatrixParser)
Q_DISABLE_COPY(PcbCamOdbMatrixParser)
};
TITAN_END_NAMESPACE
#endif // TITAN_PCBCAM_ODBMATRIXPARSER_H
#include "parserhelper.h"
#include <QFile>
#include <QTextStream>
#include <QVariantMap>
#include <QtMath>
#include <QDebug>
#include "../core/font.h"
TITAN_BEGIN_NAMESPACE
QVariantMap PcbCamParserHelper::parseOdbStructuredText(const QByteArray &iData, QString *oErrStr)
{
if (oErrStr != nullptr) oErrStr->clear();
QByteArray data = iData;
QVariantMap res;
QTextStream stream(&data);
QString line;
QMap<QString, QVariantList> subMaps;
bool inSubBlock = false;
QString subKey;
QVariantMap subValue;
while (stream.readLineInto(&line)) {
if (line.length() == 0 || line.startsWith("#")) continue;
if (line.endsWith(" {")) {
line.chop(2);
subKey = line;
if (!subMaps.contains(subKey)) {
subMaps.insert(subKey, QVariantList());
}
inSubBlock = true;
}
else if (line.startsWith("}")) {
subMaps[subKey].append(subValue);
inSubBlock = false;
subKey = "";
subValue.clear();
}
else {
int loc = line.indexOf('=');
QString k = line.left(loc).trimmed();
QString v = line.mid(loc+1).trimmed();
if (inSubBlock) {
subValue.insert(k, v);
}
else {
res.insert(k, v);
}
}
}
QMapIterator<QString, QVariantList> it(subMaps);
while (it.hasNext()) {
it.next();
res.insert(it.key(), it.value());
}
return res;
}
QPainterPath PcbCamParserHelper::parseOdbProfile(const QByteArray &iData, QString *oErrStr)
{
if (oErrStr != nullptr) oErrStr->clear();
QByteArray data = iData;
QTextStream stream(&data);
QString line;
QPainterPath res;
qreal lastx {0.0};
qreal lasty {0.0};
while (stream.readLineInto(&line)) {
if (line.startsWith("#") || line.length() == 0) { // comment
continue;
}
QStringList param = line.split(" ", Qt::SkipEmptyParts);
if (param.value(0) == "OB") {
lastx = param.value(1).toDouble();
lasty = param.value(2).toDouble();
res.moveTo(lastx, lasty);
}
else if (param.value(0) == "OS") {
lastx = param.value(1).toDouble();
lasty = param.value(2).toDouble();
res.lineTo(lastx, lasty);
}
else if (param.value(0) == "OC") {
qreal sx = lastx, sy = lasty;
qreal ex = param.value(1).toDouble(), ey = param.value(2).toDouble();
qreal cx = param.value(3).toDouble(), cy = param.value(4).toDouble();
bool cw = param.value(5) == "Y" ? true : false;
qreal sax = sx - cx, say = sy - cy;
qreal eax = ex - cx, eay = ey - cy;
qreal r = qSqrt(sax * sax + say * say);
qreal sa = qAtan2(-say, sax);
qreal ea = qAtan2(-eay, eax);
if (cw) {
if (ea <= sa) {
ea += 2.0 * M_PI;
}
}
else {
if (sa <= ea) {
sa += 2.0 * M_PI;
}
}
res.arcTo(QRectF(cx -r, cy -r, r *2, r *2), sa * (180.0 / M_PI), (ea - sa) * (180.0 / M_PI));
//res.lineTo(ex, ey);
lastx = ex;
lasty = ey;
}
else if (param.value(0) == "OE") {
res.closeSubpath();
}
}
return res;
}
bool PcbCamParserHelper::parseOdbFont(const QByteArray &iData, PcbCamFont *oFont, QString *oErrStr)
{
if (oFont == nullptr) return false;
if (oErrStr != nullptr) oErrStr->clear();
QList<PcbCamFontCharLine> currentCharLines;
QChar currentChar;
bool inblock = false;
QTextStream stream(iData);
QString line;
while (stream.readLineInto(&line)) {
line = line.trimmed();
if (line.startsWith("#") || line.length() == 0) { //comment
continue;
}
QStringList param = line.split(" ", Qt::SkipEmptyParts);
if (inblock) {
if (line.startsWith("ECHAR")) {
oFont->setCharLines(currentChar, currentCharLines);
currentCharLines.clear();
inblock = false;
}
else if (line.startsWith("LINE")) {
PcbCamFontCharLine charline;
double xs = param.value(1, "0.0").toDouble();
double ys = param.value(2, "0.0").toDouble();
double xe = param.value(3, "0.0").toDouble();
double ye = param.value(4, "0.0").toDouble();
charline.setLine(QLineF(xs, ys, xe, ye));
charline.setPolarity(param.value(5) == "N" ? PcbCam::Negative : PcbCam::Positive);
charline.setShape(param.value(6) == "S" ? PcbCamFontCharLine::LineShape_S : PcbCamFontCharLine::LineShape_R);
charline.setWidth(param.value(7, "0.0").toDouble());
currentCharLines.append(charline);
}
continue;
}
if (line.startsWith("XSIZE")) {
oFont->setSizeX(param.value(1).toDouble());
}
else if (line.startsWith("YSIZE")) {
oFont->setSizeY(param.value(1).toDouble());
}
else if (line.startsWith("OFFSET")) {
oFont->setOffset(param.value(1).toDouble());
}
else if (line.startsWith("CHAR")) {
currentChar = param.value(1, " ").at(0);
inblock = true;
}
}
return true;
}
PcbCamParserHelper::PcbCamParserHelper()
{
}
TITAN_END_NAMESPACE
#ifndef TITAN_PCBCAM_PARSERHELPER_H
#define TITAN_PCBCAM_PARSERHELPER_H
#include "../titanpcbcamglobal.h"
#include <QVariantMap>
#include <QPainterPath>
TITAN_BEGIN_NAMESPACE
class PcbCamFont;
class TITAN_PCBCAM_EXPORT PcbCamParserHelper
{
public:
static QVariantMap parseOdbStructuredText(const QByteArray &iData, QString *oErrStr = nullptr);
static QPainterPath parseOdbProfile(const QByteArray &iData, QString *oErrStr = nullptr);
static bool parseOdbFont(const QByteArray &iData, PcbCamFont *oFont, QString *oErrStr = nullptr);
private:
PcbCamParserHelper();
};
TITAN_END_NAMESPACE
#endif // TITAN_PCBCAM_PARSERHELPER_H
INCLUDEPATH += $$PWD
SOURCES += \
$$PWD/core/job.cpp \
$$PWD/core/math.cpp \
$$PWD/core/symbolfactory.cpp \
$$PWD/core/util.cpp \
$$PWD/core/attrdefine.cpp \
$$PWD/core/feature.cpp \
$$PWD/core/font.cpp \
$$PWD/core/fontcharline.cpp \
$$PWD/core/layer.cpp \
$$PWD/core/matrixlayer.cpp \
$$PWD/core/step.cpp \
$$PWD/core/steprepeat.cpp \
$$PWD/core/symbol.cpp \
$$PWD/parser/drillparser.cpp \
$$PWD/parser/gerber274xparser.cpp \
$$PWD/parser/odbcomponentparser.cpp \
$$PWD/parser/odbedadataparser.cpp \
$$PWD/widget/canvas.cpp \
$$PWD/parser/odbfeatureparser.cpp \
$$PWD/parser/odbmatrixparser.cpp \
$$PWD/parser/parserhelper.cpp \
$$PWD/core/core.cpp \
$$PWD/core/config.cpp \
$$PWD/widget/popviewwindow.cpp
HEADERS += \
$$PWD/core/math.h \
$$PWD/parser/drillparser.h \
$$PWD/parser/gerber274xparser.h \
$$PWD/parser/odbcomponentparser.h \
$$PWD/parser/odbedadataparser.h \
$$PWD/core/job.h \
$$PWD/core/symbolfactory.h \
$$PWD/core/util.h \
$$PWD/core/attrdefine.h \
$$PWD/core/feature.h \
$$PWD/core/font.h \
$$PWD/core/fontcharline.h \
$$PWD/core/layer.h \
$$PWD/core/matrixlayer.h \
$$PWD/core/step.h \
$$PWD/core/steprepeat.h \
$$PWD/core/symbol.h \
$$PWD/widget/canvas.h \
$$PWD/parser/odbfeatureparser.h \
$$PWD/parser/odbmatrixparser.h \
$$PWD/parser/parserhelper.h \
$$PWD/core/common.h \
$$PWD/core/core.h \
$$PWD/core/abstractdataio.h \
$$PWD/core/config.h \
$$PWD/widget/popviewwindow.h
OTHER_FILES +=
RESOURCES +=
DISTFILES +=
#ifndef TITAN_PCBCAM_GLOBAL_H
#define TITAN_PCBCAM_GLOBAL_H
#include <QtCore/qglobal.h>
#if !defined(TITAN_PCBCAM_STATIC)
# if defined(TITAN_PCBCAM_SHARED)
# define TITAN_PCBCAM_EXPORT Q_DECL_EXPORT
# else
# define TITAN_PCBCAM_EXPORT Q_DECL_IMPORT
# endif
#else
# define TITAN_PCBCAM_EXPORT
#endif
#define TITAN_BEGIN_NAMESPACE namespace titan {
#define TITAN_END_NAMESPACE }
#endif // TITAN_PCBCAM_GLOBAL_H
#include "./canvas.h"
#include <QMouseEvent>
#include <QPainter>
#include <QDebug>
#include <QElapsedTimer>
#include <QWheelEvent>
#include <QMenu>
#include <QStack>
#include "../core/arcpainterinfo.h"
#include "../core/util.h"
#include "../core/math.h"
#include "../core/symbol.h"
#include "../core/feature.h"
#include "./popviewwindow.h"
TITAN_BEGIN_NAMESPACE
struct PopViewInfo {
QRectF canvasRect;
QRect popviewRect;
};
class PcbCamCanvasPrivate
{
Q_DECLARE_PUBLIC(PcbCamCanvas)
public:
explicit PcbCamCanvasPrivate(PcbCamCanvas *qptr)
: q_ptr(qptr){}
~PcbCamCanvasPrivate(){}
QRectF scaleRect(const QRectF &iRect, qreal iScale) {
QPointF pc = iRect.center();
qreal w = iRect.width() * iScale;
qreal h = iRect.height() * iScale;
return QRectF(pc.x()-w/2.0, pc.y()-h/2.0, w, h);
}
void pushDisplayHist(const QRectF &iRect) {
if (!displayRectHist.isEmpty() && displayRectHist.last() == iRect) {
return;
}
displayRectHist.push(iRect);
if (displayRectHist.count() > 100) {
displayRectHist.pop_front();
}
}
PcbCamJob *jobData {nullptr};
QMenu *contextMenu {nullptr};
PcbCamCanvas::MouseMode mouseMode {PcbCamCanvas::ZoomAreaMode};
PcbCam::UnitsType unitsType {PcbCam::Units_Inch};
QRectF rubberBandRect;
QRectF tmpRubberBandRect;
QPolygonF polygonBand;
int mouseClickTimes {0};
QString currentStep;
QMap<QString, QString> dispLayer;
QRectF currentDisplayRect {0, 0, 20, 20};
QTransform currentMatrix;
QTransform orientMatrix;
QColor bgColor {Qt::black};
QColor rubberColor {Qt::white};
QColor highlightColor {Qt::white};
QColor selectionColor {Qt::white};
QColor profileColor {Qt::white};
QColor snapColor {"#CBCB41"};
//QPixmap bufferPixmap;
QMap<QString, QPixmap> pixBuffers;
QStack<QRectF> displayRectHist;
PcbCam::DisplayOptions displayOptions {PcbCam::DisplayFill|PcbCam::DisplayProfile|PcbCam::DisplayDatumn|PcbCam::DisplayTextValue};
PcbCam::FeatureSelectionMode curFeatSelMode {PcbCam::ContainsFeatureShape};
PcbCam::FeatureSelectionOperation curFeatSelOp {PcbCam::ReplaceFeatureSelection};
bool panviewDrag {false};
QPoint panviewStartPos;
QRectF panviewStartRect;
//绝对座标原点
QPointF origPoint {0.0, 0.0};
//相对坐标原点
QPointF lastCoordPoint {0.0, 0.0};
//鼠标坐标
QPoint curMousePos;
//是否绘制相对坐标
bool drawRelativeOrig {false};
//距离量测值
QLineF measureLine;
//CheckList高亮对象
QVariantList checkMeasList;
//PopView对象列表
QList<PcbCamPopViewWindow*> popviewList;
PcbCamPopViewWindow *currentMovePopView {nullptr};
QRect currentMovePopViewOrigRect;
// 高亮缓存
QMap<qlonglong, PcbCamCanvas::FeatureInfo> highlightBuffer;
qlonglong highlightIndex {0};
// 间距测量对象缓存
QList<PcbCamCanvas::FeatureInfo> spacingFeatBuffer;
//单选缓存数据
QMap<QString, QList<int> > lastSingleSelectMap;
QMap<QString, int> lastSingleSelectIndex;
//捕捉对象时的Key
QString snapFeatRequestKey;
// 上次鼠标指针样式
QCursor lastCursor;
// Feature过滤器
PcbCam::FeatureSelectionFilter currentFeatureFilter;
// 捕捉模式
PcbCam::SnapModes snapMode {PcbCam::SnapOff};
// 捕捉对象
PcbCam::FeatureTypes snapFeatureType {PcbCam::AllFeatures};
// 捕捉层
QStringList snapLayers;
// 捕捉点
QPointF snapPoint;
bool isSnapPointValid {false};
protected:
PcbCamCanvas * const q_ptr;
};
PcbCamCanvas::PcbCamCanvas(QWidget *parent) : QWidget(parent),
d_ptr(new PcbCamCanvasPrivate(this))
{
this->setMouseTracking(true);
this->setFocusPolicy(Qt::StrongFocus);
}
PcbCamCanvas::~PcbCamCanvas()
{
}
void PcbCamCanvas::fitInView(const QRectF &iRect, bool iSaveHist)
{
Q_D(PcbCamCanvas);
if (iSaveHist) {
d->pushDisplayHist(d->currentDisplayRect);
}
d->currentDisplayRect = iRect;
QRect wgtRect = this->rect();
auto disprect = d->orientMatrix.mapRect(d->currentDisplayRect.normalized()).normalized();
qreal scale = qMin(double(wgtRect.width())/disprect.width(),
double(wgtRect.height())/disprect.height());
QTransform mat = d->orientMatrix * QTransform(scale, 0, 0, -scale, 0, 0);
disprect = mat.mapRect(d->currentDisplayRect.normalized());
d->currentMatrix = mat * QTransform(1, 0, 0, 1, wgtRect.center().x() - disprect.center().x(), wgtRect.center().y() - disprect.center().y());
d->pixBuffers.clear();
update();
}
void PcbCamCanvas::setCurrentStep(const QString &iStep)
{
Q_D(PcbCamCanvas);
d->currentStep = iStep;
zoomHome();
}
QString PcbCamCanvas::currentStep() const
{
Q_D(const PcbCamCanvas);
return d->currentStep;
}
void PcbCamCanvas::zoomHome()
{
Q_D(PcbCamCanvas);
if (d->jobData == nullptr || !d->jobData->isStepExists(d->currentStep)) return;
QRectF dispRect;
for (const QString &layername : d->dispLayer.keys()) {
if (!d->jobData->isStepLayerExists(d->currentStep, layername)) continue;
PcbCamLayer *layer = d->jobData->layer(d->currentStep, layername);
dispRect = dispRect.united(layer->boundingRect());
}
dispRect = dispRect.united(d->jobData->step(d->currentStep)->profile().boundingRect());
if (dispRect.width() < 0.00001 || dispRect.height() < 0.00001) {
dispRect = QRectF(0, 0, 10, 10);
}
fitInView(d->scaleRect(dispRect, 1.1));
}
void PcbCamCanvas::zoomIn()
{
Q_D(PcbCamCanvas);
fitInView(d->scaleRect(d->currentDisplayRect, 1.0/1.2));
}
void PcbCamCanvas::zoomOut()
{
Q_D(PcbCamCanvas);
fitInView(d->scaleRect(d->currentDisplayRect, 1.2));
}
void PcbCamCanvas::zoomPrevious()
{
Q_D(PcbCamCanvas);
if (!d->displayRectHist.isEmpty()) {
fitInView(d->displayRectHist.pop(), false);
}
}
void PcbCamCanvas::viewLeft(qreal iRate)
{
Q_D(PcbCamCanvas);
QRectF rect = d->orientMatrix.mapRect(d->currentDisplayRect).normalized();
rect.moveLeft(rect.left() - rect.width()*iRate);
rect = d->orientMatrix.inverted().mapRect(rect).normalized();
fitInView(rect);
}
void PcbCamCanvas::viewRight(qreal iRate)
{
Q_D(PcbCamCanvas);
QRectF rect = d->orientMatrix.mapRect(d->currentDisplayRect).normalized();
rect.moveRight(rect.right() + rect.width()*iRate);
rect = d->orientMatrix.inverted().mapRect(rect).normalized();
fitInView(rect);
}
void PcbCamCanvas::viewUp(qreal iRate)
{
Q_D(PcbCamCanvas);
QRectF rect = d->orientMatrix.mapRect(d->currentDisplayRect).normalized();
rect.moveBottom(rect.bottom() - rect.height()*iRate);
rect = d->orientMatrix.inverted().mapRect(rect).normalized();
fitInView(rect);
}
void PcbCamCanvas::viewDown(qreal iRate)
{
Q_D(PcbCamCanvas);
QRectF rect = d->orientMatrix.mapRect(d->currentDisplayRect).normalized();
rect.moveTop(rect.top() + rect.height()*iRate);
rect = d->orientMatrix.inverted().mapRect(rect).normalized();
fitInView(rect);
}
void PcbCamCanvas::setOrientMatrix(const QTransform &iMatrix)
{
Q_D(PcbCamCanvas);
d->orientMatrix = iMatrix;
auto rect = d->currentDisplayRect.normalized();
qreal size = qMin(rect.width(), rect.height());
this->fitInView(QRectF(rect.center().x() - size/2.0, rect.center().y() - size/2.0, size, size), false);
}
QTransform PcbCamCanvas::orientMatrix() const
{
Q_D(const PcbCamCanvas);
return d->orientMatrix;
}
QTransform PcbCamCanvas::currentMatrix() const
{
Q_D(const PcbCamCanvas);
return d->currentMatrix;
}
void PcbCamCanvas::setUnitsType(PcbCam::UnitsType iUnits)
{
Q_D(PcbCamCanvas);
d->unitsType = iUnits;
}
PcbCam::UnitsType PcbCamCanvas::unitsType() const
{
Q_D(const PcbCamCanvas);
return d->unitsType;
}
void PcbCamCanvas::display(const QString &iLayer, const QString &iColor)
{
Q_D(PcbCamCanvas);
if (iColor.isEmpty()) {
d->dispLayer.remove(iLayer);
}
else {
d->dispLayer.insert(iLayer, iColor);
if (d->jobData != nullptr) d->jobData->loadStepLayer(d->currentStep, iLayer);
}
d->pixBuffers.remove(d->currentStep +"/SELECTION");
d->pixBuffers.remove("ALL");
update();
}
void PcbCamCanvas::resetDisplayLayers(const QMap<QString, QString> &iDispInfo)
{
Q_D(PcbCamCanvas);
d->dispLayer.clear();
if (d->jobData != nullptr) {
d->jobData->clearStepDisplayLayer(d->currentStep);
}
for (auto layer : iDispInfo.keys()) {
auto color = iDispInfo.value(layer);
if (!color.isEmpty()) {
d->dispLayer.insert(layer, color);
if (d->jobData != nullptr) {
d->jobData->loadStepLayer(d->currentStep, layer);
auto joblayer = d->jobData->layer(d->currentStep, layer);
if (joblayer != nullptr) {
joblayer->setDisplayColor(color);
}
}
}
}
d->pixBuffers.remove(d->currentStep +"/SELECTION");
d->pixBuffers.remove("ALL");
update();
}
void PcbCamCanvas::clearDisplay()
{
Q_D(PcbCamCanvas);
d->dispLayer.clear();
d->pixBuffers.remove("ALL");
d->highlightBuffer.clear();
d->displayRectHist.clear();
d->checkMeasList.clear();
d->currentStep.clear();
d->mouseClickTimes = 0;
d->rubberBandRect = QRect();
d->tmpRubberBandRect = QRect();
update();
}
void PcbCamCanvas::refresh()
{
Q_D(PcbCamCanvas);
d->pixBuffers.clear();
update();
}
void PcbCamCanvas::setBgColor(const QString &iBgColor)
{
Q_D(PcbCamCanvas);
d->bgColor = QColor(iBgColor);
}
QString PcbCamCanvas::bgColor() const
{
Q_D(const PcbCamCanvas);
return d->bgColor.name();
}
void PcbCamCanvas::setRubberColor(const QString &iColor)
{
Q_D(PcbCamCanvas);
d->rubberColor = QColor(iColor);
}
QString PcbCamCanvas::rubberColor() const
{
Q_D(const PcbCamCanvas);
return d->rubberColor.name();
}
void PcbCamCanvas::setHighlightColor(const QString &iColor)
{
Q_D(PcbCamCanvas);
d->highlightColor = QColor(iColor);
}
QString PcbCamCanvas::highlightColor() const
{
Q_D(const PcbCamCanvas);
return d->highlightColor.name();
}
void PcbCamCanvas::setSelectionColor(const QString &iColor)
{
Q_D(PcbCamCanvas);
d->selectionColor = QColor(iColor);
}
QString PcbCamCanvas::selectionColor() const
{
Q_D(const PcbCamCanvas);
return d->selectionColor.name();
}
void PcbCamCanvas::setProfileColor(const QString &iColor)
{
Q_D(PcbCamCanvas);
d->profileColor = QColor(iColor);
}
QString PcbCamCanvas::profileColor() const
{
Q_D(const PcbCamCanvas);
return d->profileColor.name();
}
QPointF PcbCamCanvas::mapToScene(const QPoint &iPoint) const
{
Q_D(const PcbCamCanvas);
return d->currentMatrix.inverted().map(QPointF(iPoint));
}
QRectF PcbCamCanvas::mapToScene(const QRect &iRect) const
{
Q_D(const PcbCamCanvas);
return d->currentMatrix.inverted().mapRect(QRectF(iRect));
}
void PcbCamCanvas::setMouseMode(const PcbCamCanvas::MouseMode iMouseMode)
{
Q_D(PcbCamCanvas);
d->mouseMode = iMouseMode;
if (d->mouseMode == PcbCamCanvas::PanViewMode) {
this->setCursor(QCursor(Qt::OpenHandCursor));
}
else if (d->mouseMode == PcbCamCanvas::SnapFeatMode) {
this->setCursor(QCursor(Qt::PointingHandCursor));
}
else {
this->setCursor(QCursor(Qt::ArrowCursor));
}
d->mouseClickTimes = 0;
d->rubberBandRect = QRect();
d->tmpRubberBandRect = QRect();
d->polygonBand.clear();
//d->spacingFeatBuffer.clear();
//d->measureLine = QLineF(0.0, 0.0, 0.0, 0.0);
update();
}
PcbCamCanvas::MouseMode PcbCamCanvas::mouseMode() const
{
Q_D(const PcbCamCanvas);
return d->mouseMode;
}
QList<PcbCamCanvas::FeatureInfo> PcbCamCanvas::getFeaturesAt(const QPoint &iPoint, LayerScope iLayerScope, int iTolPix) const
{
Q_D(const PcbCamCanvas);
QList<PcbCamCanvas::FeatureInfo> res;
if (d->jobData == nullptr || d->currentStep.isEmpty()) return res;
QList<PcbCamLayer*> layers;
if (iLayerScope & WorkLayer) {
auto layer = d->jobData->stepWorkLayer(d->currentStep);
if (layer != nullptr) layers << layer;
}
if (iLayerScope & AffectedLayer) {
for (auto layer : d->jobData->stepAffectedLayer(d->currentStep)) {
if (!layers.contains(layer)) layers << layer;
}
}
if (iLayerScope & DisplayLayer) {
for (auto layer: d->jobData->stepDispalyLayer(d->currentStep)) {
if (!layers.contains(layer)) layers << layer;
}
}
auto step = d->jobData->step(d->currentStep);
QRectF rect = mapToScene(QRect(iPoint.x() - iTolPix, iPoint.y() - iTolPix, 2 * iTolPix, 2 * iTolPix));
QPainterPath rectpath;
rectpath.addRect(rect);
for (auto layer: layers) {
for (auto feat : layer->selectFeature(rectpath, PcbCam::FeatureSelectionFilter(), PcbCam::NoFeatureSelection, PcbCam::IntersectsFeatureShape)) {
FeatureInfo featinfo;
featinfo.feature = feat;
featinfo.layer = layer;
featinfo.step = step;
res << featinfo;
}
}
return res;
}
PcbCamCanvas::FeatureInfo PcbCamCanvas::getFirstFeatureAt(const QPoint &iPoint, PcbCamCanvas::LayerScope iLayerScope, int iTolPix) const
{
Q_D(const PcbCamCanvas);
PcbCamCanvas::FeatureInfo res;
if (d->jobData == nullptr || d->currentStep.isEmpty()) return res;
QList<PcbCamLayer*> layers;
if (iLayerScope & WorkLayer) {
auto layer = d->jobData->stepWorkLayer(d->currentStep);
if (layer != nullptr) layers << layer;
}
if (iLayerScope & AffectedLayer) {
for (auto layer : d->jobData->stepAffectedLayer(d->currentStep)) {
if (!layers.contains(layer)) layers << layer;
}
}
if (iLayerScope & DisplayLayer) {
for (auto layer: d->jobData->stepDispalyLayer(d->currentStep)) {
if (!layers.contains(layer)) layers << layer;
}
}
auto step = d->jobData->step(d->currentStep);
QRectF rect = mapToScene(QRect(iPoint.x() - iTolPix, iPoint.y() - iTolPix, 2 * iTolPix, 2 * iTolPix));
QPainterPath rectpath;
rectpath.addRect(rect);
for (auto layer: layers) {
auto feats = layer->selectFeature(rectpath, PcbCam::FeatureSelectionFilter(), PcbCam::NoFeatureSelection, PcbCam::IntersectsFeatureShape);
if (!feats.isEmpty()) {
res.feature = feats.first();
res.step = step;
res.layer = layer;
}
}
return res;
}
QVariantMap PcbCamCanvas::snapFeatInfo(const QPoint &iPoint, int iTolPix)
{
Q_D(const PcbCamCanvas);
if (d->jobData == nullptr) return QVariantMap();
QVariantMap res;
auto curfeatinfo = getFirstFeatureAt(iPoint, DisplayLayer, iTolPix);
if (curfeatinfo.feature != nullptr) {
auto curfeat = curfeatinfo.feature;
res.insert("request_key", d->snapFeatRequestKey);
res.insert("polarity", curfeat->polarity() == PcbCam::Negative ? "NEG" : "POS");
res.insert("attrs", curfeat->attr());
res.insert("step", curfeatinfo.step->name());
res.insert("layer", curfeatinfo.layer->name());
res.insert("index", curfeat->index());
if (curfeat->type() == PcbCam::PadFeature) {
const auto feat = static_cast<const PcbCamFeaturePad *>(curfeat);
res.insert("type", "Pad");
res.insert("x", feat->pos().x());
res.insert("y", feat->pos().y());
res.insert("symbol", feat->symbol()->name());
res.insert("angle", PcbCamUtil::orient2angle(feat->orient()));
res.insert("mirror", PcbCamUtil::orient2mirror(feat->orient()));
}
else if (curfeat->type() == PcbCam::LineFeature) {
const auto feat = static_cast<const PcbCamFeatureLine *>(curfeat);
res.insert("type", "Line");
res.insert("xs", feat->line().x1());
res.insert("ys", feat->line().y1());
res.insert("xe", feat->line().x2());
res.insert("ye", feat->line().y2());
res.insert("symbol", feat->symbol()->name());
}
else if (curfeat->type() == PcbCam::ArcFeature) {
const auto feat = static_cast<const PcbCamFeatureArc *>(curfeat);
res.insert("type", "Arc");
res.insert("xc", feat->pc().x());
res.insert("yc", feat->pc().y());
res.insert("xs", feat->ps().x());
res.insert("ys", feat->ps().y());
res.insert("xe", feat->pe().x());
res.insert("ye", feat->pe().y());
res.insert("cw", feat->cw());
res.insert("symbol", feat->symbol()->name());
}
else if (curfeat->type() == PcbCam::SurfaceFeature) {
const auto feat = static_cast<const PcbCamFeatureSurface *>(curfeat);
res.insert("type", "Surface");
auto pc = feat->boundingRect().center();
res.insert("xc", pc.x());
res.insert("yc", pc.y());
}
else if (curfeat->type() == PcbCam::TextFeature) {
const auto feat = static_cast<const PcbCamFeatureText *>(curfeat);
res.insert("type", "Text");
res.insert("x", feat->pos().x());
res.insert("y", feat->pos().y());
res.insert("font", feat->font()->name());
res.insert("text", feat->text());
res.insert("angle", PcbCamUtil::orient2angle(feat->orient()));
res.insert("mirror", PcbCamUtil::orient2mirror(feat->orient()));
}
emit snapFeatChanged(res);
}
return res;
}
void PcbCamCanvas::setSnapFeatRequestKey(const QString &iKey)
{
Q_D(PcbCamCanvas);
d->snapFeatRequestKey = iKey;
}
void PcbCamCanvas::singleClickSelection(const QPoint &iPoint, PcbCam::FeatureSelectionOperation iSelOp)
{
Q_D(PcbCamCanvas);
if (d->jobData == nullptr || d->currentStep.isEmpty()) return;
int tol = 2;
QRectF rect = mapToScene(QRect(iPoint.x() - tol, iPoint.y() - tol, 2 * tol, 2 * tol));
QPainterPath rectpath;
rectpath.addRect(rect);
QList<PcbCamLayer *> affected_layers = d->jobData->stepAffectedLayer(d->currentStep);
PcbCamLayer *worklayer = d->jobData->stepWorkLayer(d->currentStep);
if (worklayer != nullptr) affected_layers.prepend(worklayer);
PcbCamFeature *curfeat {nullptr};
QString curfeat_layer;
int selfeat_count {0};
if (iSelOp == PcbCam::RemoveFeatureSelection) {
for (PcbCamLayer *layer : affected_layers) {
auto feats = layer->selectFeature(rectpath, PcbCam::FeatureSelectionFilter(), PcbCam::NoFeatureSelection, PcbCam::IntersectsFeatureShape);
for (auto feat : feats) {
if (feat->isSelected()) {
feat->setSelected(false);
break;
}
}
}
}
else {
for (PcbCamLayer *layer : affected_layers) {
if (iSelOp == PcbCam::ReplaceFeatureSelection) {
layer->clearSelection();
}
auto feats = layer->selectFeature(rectpath, PcbCam::FeatureSelectionFilter(), PcbCam::NoFeatureSelection, PcbCam::IntersectsFeatureShape);
if (feats.isEmpty()) continue;
QList<int> selindex;
for (auto feat : feats) {
selindex.append(feat->index());
}
QList<int> lastindex = d->lastSingleSelectMap.value(layer->name());
int curindex;
if (selindex == lastindex) {
curindex = (d->lastSingleSelectIndex.value(layer->name(), -1) + 1) % selindex.count();
}
else {
d->lastSingleSelectMap.insert(layer->name(), selindex);
curindex = 0;
}
d->lastSingleSelectIndex.insert(layer->name(), curindex);
feats[curindex]->setSelected(true);
curfeat = feats[curindex];
curfeat_layer = layer->name();
selfeat_count++;
}
}
if (selfeat_count == 1) {
QVariantMap msginfo;
msginfo.insert("INFO_TYPE", "FEATURE");
msginfo.insert("polarity", curfeat->polarity() == PcbCam::Negative ? "NEG" : "POS");
msginfo.insert("attrs", curfeat->attr());
msginfo.insert("layer", curfeat_layer);
msginfo.insert("index", curfeat->index());
if (curfeat->type() == PcbCam::PadFeature) {
const auto feat = static_cast<const PcbCamFeaturePad *>(curfeat);
msginfo.insert("type", "Pad");
msginfo.insert("x", feat->pos().x());
msginfo.insert("y", feat->pos().y());
msginfo.insert("symbol", feat->symbol()->name());
msginfo.insert("angle", PcbCamUtil::orient2angle(feat->orient()));
msginfo.insert("mirror", PcbCamUtil::orient2mirror(feat->orient()));
}
else if (curfeat->type() == PcbCam::LineFeature) {
const auto feat = static_cast<const PcbCamFeatureLine *>(curfeat);
msginfo.insert("type", "Line");
msginfo.insert("xs", feat->line().x1());
msginfo.insert("ys", feat->line().y1());
msginfo.insert("xe", feat->line().x2());
msginfo.insert("ye", feat->line().y2());
msginfo.insert("symbol", feat->symbol()->name());
}
else if (curfeat->type() == PcbCam::ArcFeature) {
const auto feat = static_cast<const PcbCamFeatureArc *>(curfeat);
msginfo.insert("type", "Arc");
msginfo.insert("xc", feat->pc().x());
msginfo.insert("yc", feat->pc().y());
msginfo.insert("xs", feat->ps().x());
msginfo.insert("ys", feat->ps().y());
msginfo.insert("xe", feat->pe().x());
msginfo.insert("ye", feat->pe().y());
msginfo.insert("cw", feat->cw());
msginfo.insert("symbol", feat->symbol()->name());
}
else if (curfeat->type() == PcbCam::SurfaceFeature) {
const auto feat = static_cast<const PcbCamFeatureSurface *>(curfeat);
msginfo.insert("type", "Surface");
auto pc = feat->boundingRect().center();
msginfo.insert("xc", pc.x());
msginfo.insert("yc", pc.y());
}
else if (curfeat->type() == PcbCam::TextFeature) {
const auto feat = static_cast<const PcbCamFeatureText *>(curfeat);
msginfo.insert("type", "Text");
msginfo.insert("x", feat->pos().x());
msginfo.insert("y", feat->pos().y());
msginfo.insert("font", feat->font()->name());
msginfo.insert("text", feat->text());
msginfo.insert("angle", PcbCamUtil::orient2angle(feat->orient()));
msginfo.insert("mirror", PcbCamUtil::orient2mirror(feat->orient()));
}
emit messageNotified(msginfo);
}
d->pixBuffers.remove(d->currentStep +"/SELECTION");
d->pixBuffers.remove("ALL");
emit selectionChanged();
update();
}
void PcbCamCanvas::doubleClickSelection(const QPoint &iPoint, PcbCam::FeatureSelectionOperation iSelOp)
{
Q_D(PcbCamCanvas);
if (d->jobData == nullptr || d->currentStep.isEmpty()) return;
int tol = 2;
QRectF rect = mapToScene(QRect(iPoint.x() - tol, iPoint.y() - tol, 2 * tol, 2 * tol));
QPainterPath rectpath;
rectpath.addRect(rect);
QList<PcbCamLayer *> affected_layers = d->jobData->stepAffectedLayer(d->currentStep);
PcbCamLayer *worklayer = d->jobData->stepWorkLayer(d->currentStep);
if (worklayer != nullptr) affected_layers.prepend(worklayer);
PcbCamFeature *curfeat {nullptr};
PcbCamFeature *firstfeat {nullptr};
for (PcbCamLayer *layer : affected_layers) {
auto feats = layer->selectFeature(rectpath, PcbCam::FeatureSelectionFilter(), PcbCam::NoFeatureSelection, PcbCam::IntersectsFeatureShape);
if (!feats.isEmpty()) {
if (firstfeat == nullptr) firstfeat = feats.first();
for (auto f : feats) {
if (f->isSelected()) {
curfeat = f;
break;
}
}
if (curfeat != nullptr) break;
}
}
if (curfeat == nullptr) curfeat = firstfeat;
//清除之前的选择
if (iSelOp == PcbCam::ReplaceFeatureSelection) {
for (PcbCamLayer *layer : affected_layers) {
layer->clearSelection();
}
}
if (curfeat != nullptr) {
auto curtype = curfeat->type();
auto cursym = curfeat->symbol();
int count = 0;
for (auto layer : affected_layers) {
for (auto feat : layer->features()) {
if (feat->type() != curtype) continue;
if ((feat->type() == PcbCam::LineFeature || feat->type() == PcbCam::PadFeature || feat->type() == PcbCam::ArcFeature)
&& feat->symbol() != cursym) continue;
feat->setSelected(true);
count++;
}
}
QVariantMap msginfo;
msginfo.insert("INFO_TYPE", "DBCLICK_SELECT");
msginfo.insert("count", count);
if (curtype == PcbCam::LineFeature) {
msginfo.insert("type", "Line");
msginfo.insert("symbol", cursym->name());
}
else if (curtype == PcbCam::PadFeature) {
msginfo.insert("type", "Pad");
msginfo.insert("symbol", cursym->name());
}
else if (curtype == PcbCam::ArcFeature) {
msginfo.insert("type", "Arc");
msginfo.insert("symbol", cursym->name());
}
else if (curtype == PcbCam::SurfaceFeature) {
msginfo.insert("type", "Surface");
}
else if (curtype == PcbCam::TextFeature) {
msginfo.insert("type", "Text");
}
emit messageNotified(msginfo);
}
d->pixBuffers.remove(d->currentStep +"/SELECTION");
d->pixBuffers.remove("ALL");
emit selectionChanged();
update();
}
QList<PcbCamFeature *> PcbCamCanvas::selectFeature(const QStringList &iLayers,
const QPainterPath &iPath,
const PcbCam::FeatureSelectionFilter &iFilter,
PcbCam::FeatureSelectionOperation iSelOp,
PcbCam::FeatureSelectionMode iMode)
{
Q_D(PcbCamCanvas);
QList<PcbCamFeature *> res;
if (d->jobData == nullptr || d->currentStep.isEmpty()) return res;
auto affected_layers = d->jobData->stepAffectedLayer(d->currentStep);
auto worklayer = d->jobData->stepWorkLayer(d->currentStep);
if (worklayer != nullptr) affected_layers.prepend(worklayer);
for (auto layer : affected_layers) {
if (iSelOp == PcbCam::ReplaceFeatureSelection) {
layer->clearSelection();
}
if (iLayers.isEmpty() || iLayers.contains(layer->name())) {
res.append(layer->selectFeature(iPath, iFilter, iSelOp, iMode));
}
}
if (iSelOp != PcbCam::NoFeatureSelection && iSelOp != PcbCam::RemoveFeatureSelection) {
QVariantMap msginfo;
msginfo.insert("INFO_TYPE", "REGION_SELECT");
msginfo.insert("count", res.count());
emit messageNotified(msginfo);
}
d->pixBuffers.remove(d->currentStep +"/SELECTION");
d->pixBuffers.remove("ALL");
emit selectionChanged();
update();
return res;
}
QList<PcbCamFeature *> PcbCamCanvas::selectedFeatures() const
{
Q_D(const PcbCamCanvas);
QList<PcbCamFeature *> ret;
QList<PcbCamLayer *> affected_layers = d->jobData->stepAffectedLayer(d->currentStep);
PcbCamLayer *worklayer = d->jobData->stepWorkLayer(d->currentStep);
if (worklayer != nullptr) affected_layers.prepend(worklayer);
for (auto layer: affected_layers) {
ret << layer->selectedFeatures();
}
return ret;
}
void PcbCamCanvas::layerNetSelection(const QStringList &iLayers, const QPoint &iPoint, PcbCam::FeatureSelectionOperation iSelOp, const PcbCam::FeatureSelectionFilter &iFilter)
{
Q_D(PcbCamCanvas);
if (d->jobData == nullptr || d->currentStep.isEmpty()) return;
int tol = 4;
QRectF rect = mapToScene(QRect(iPoint.x() - tol, iPoint.y() - tol, 2 * tol, 2 * tol));
QPainterPath selpath;
selpath.addRect(rect);
QList<PcbCamLayer *> affected_layers = d->jobData->stepAffectedLayer(d->currentStep);
PcbCamLayer *worklayer = d->jobData->stepWorkLayer(d->currentStep);
if (worklayer != nullptr) affected_layers.prepend(worklayer);
auto filter = iFilter;
//filter.polarity = PcbCam::Positive;
for (auto layer: affected_layers) {
if (iSelOp == PcbCam::ReplaceFeatureSelection) {
layer->clearSelection();
}
if (!iLayers.isEmpty() && !iLayers.contains(layer->name())) {
continue;
}
QSet<PcbCamFeature*> selectedFeatures;
while (!selpath.isEmpty()) {
QList<PcbCamFeature*> selfeats;
QPainterPath tmppath;
for (auto f : layer->selectFeature(selpath, filter, PcbCam::NoFeatureSelection, PcbCam::IntersectsFeatureShape)){
if (!selectedFeatures.contains(f)) {
if (f->polarity() == PcbCam::Positive) {
tmppath = tmppath.united(f->shape());
}
else {
tmppath = tmppath.subtracted(f->shape());
}
if (iSelOp == PcbCam::RemoveFeatureSelection) {
f->setSelected(false);
}
else if (f->polarity() == PcbCam::Positive) {
f->setSelected(true);
}
selectedFeatures.insert(f);
// 第一个对象只能是鼠标下的一个Feature,不然会同时选中多个net
if (selectedFeatures.count() == 1) {
break;
}
}
}
selpath = tmppath;
}
}
d->pixBuffers.remove(d->currentStep +"/SELECTION");
d->pixBuffers.remove("ALL");
emit selectionChanged();
update();
}
void PcbCamCanvas::highlightFeature(const QString &iStep,
const QStringList &iLayers,
const PcbCam::FeatureSelectionFilter &iFilter,
PcbCam::FeatureSelectionOperation iSelOp,
const QTransform &iMatrix,
bool iStepRepeat)
{
Q_D(PcbCamCanvas);
if (d->jobData == nullptr) return;
auto step = d->jobData->step(iStep);
if (step == nullptr) return;
auto affected_layers = d->jobData->stepAffectedLayer(iStep);
auto worklayer = d->jobData->stepWorkLayer(iStep);
if (worklayer != nullptr) affected_layers.prepend(worklayer);
QMap<QString, PcbCamLayer*> layerMap;
if (!iLayers.isEmpty()) {
for (auto ln : iLayers) {
auto layer = d->jobData->layer(iStep, ln);
if (layer != nullptr) layerMap.insert(ln, layer);
}
}
else {
for (auto layer : affected_layers) {
layerMap.insert(layer->name(), layer);
}
}
if (iSelOp == PcbCam::ReplaceFeatureSelection) {
d->highlightBuffer.clear();
}
auto stepProfile = step->profile();
bool isFilterProfile = (iFilter.profile != PcbCam::AllProfile && !stepProfile.isEmpty());
bool isFilterInclueSym = !iFilter.includeSymbols.isEmpty();
bool isFilterExcludeSym = !iFilter.excludeSymbols.isEmpty();
bool isFilterIncludeAttr = !iFilter.includeAttributes.isEmpty();
bool isFilterExcludeAttr = !iFilter.excludeAttributes.isEmpty();
QSet<PcbCamSymbol*> includeSymbols;
for (auto symname : iFilter.includeSymbols) {
auto symbol = d->jobData->symbol(symname);
if (symbol != nullptr) {
includeSymbols.insert(symbol);
}
}
QSet<PcbCamSymbol*> excludeSymbols;
for (auto symname : iFilter.excludeSymbols) {
auto symbol = d->jobData->symbol(symname);
if (symbol != nullptr) {
excludeSymbols.insert(symbol);
}
}
QList<PcbCam::AttrCompareInfo> includeAttrs;
for (auto attr : iFilter.includeAttributes) {
includeAttrs.append(PcbCam::AttrCompareInfo(attr));
}
QList<PcbCam::AttrCompareInfo> excludeAttrs;
for (auto attr : iFilter.excludeAttributes) {
excludeAttrs.append(PcbCam::AttrCompareInfo(attr));
}
if (iSelOp == PcbCam::RemoveFeatureSelection) {
for (auto k : d->highlightBuffer.keys()) {
auto hinfo = d->highlightBuffer[k];
if (layerMap.contains(hinfo.layer->name())) {
bool match = PcbCamUtil::isFeatMatchFilter(hinfo.feature,
iFilter.type,
iFilter.polarity,
isFilterProfile,
iFilter.profile,
stepProfile,
isFilterInclueSym,
includeSymbols,
isFilterExcludeSym,
excludeSymbols,
isFilterIncludeAttr,
includeAttrs,
iFilter.includeAttributesLogic,
isFilterExcludeAttr,
excludeAttrs,
iFilter.excludeAttributesLogic
);
if (match) d->highlightBuffer.remove(k);
}
}
}
else {
for (auto layer : layerMap.values()) {
for (auto feat : layer->features()) {
bool match = PcbCamUtil::isFeatMatchFilter(feat,
iFilter.type,
iFilter.polarity,
isFilterProfile,
iFilter.profile,
stepProfile,
isFilterInclueSym,
includeSymbols,
isFilterExcludeSym,
excludeSymbols,
isFilterIncludeAttr,
includeAttrs,
iFilter.includeAttributesLogic,
isFilterExcludeAttr,
excludeAttrs,
iFilter.excludeAttributesLogic
);
if (match) {
FeatureInfo hinfo;
hinfo.layer = layer;
hinfo.step = step;
hinfo.feature = feat;
hinfo.matrix = iMatrix;
d->highlightBuffer.insert(d->highlightIndex++, hinfo);
}
}
}
if (iStepRepeat) {
for (auto sr : step->getBreakedRepeats()) {
auto srstep = d->jobData->step(sr.step());
QTransform srmat = PcbCamUtil::matrix(QPointF(sr.x(), sr.y()), srstep->datum(), sr.angle(), sr.mirror()) * iMatrix;
highlightFeature(srstep->name(), iLayers, iFilter, iSelOp, srmat, iStepRepeat);
}
}
}
d->pixBuffers.remove(d->currentStep +"/HIGHLIGHT");
d->pixBuffers.remove("ALL");
update();
}
void PcbCamCanvas::clearSelection()
{
Q_D(PcbCamCanvas);
if (d->jobData == nullptr) return;
QList<PcbCamLayer *> affected_layers = d->jobData->stepAffectedLayer(d->currentStep);
PcbCamLayer *worklayer = d->jobData->stepWorkLayer(d->currentStep);
if (worklayer != nullptr) affected_layers.prepend(worklayer);
for (PcbCamLayer *layer : affected_layers) {
layer->clearSelection();
}
d->pixBuffers.remove(d->currentStep + "/SELECTION");
d->pixBuffers.remove("ALL");
update();
}
void PcbCamCanvas::clearHighlight()
{
Q_D(PcbCamCanvas);
d->highlightBuffer.clear();
d->spacingFeatBuffer.clear();
d->measureLine = QLineF(0.0, 0.0, 0.0, 0.0);
d->pixBuffers.remove(d->currentStep + "/HIGHLIGHT");
d->pixBuffers.remove("ALL");
update();
}
void PcbCamCanvas::setCheckMeasList(const QVariantList &iData)
{
Q_D(PcbCamCanvas);
d->checkMeasList = iData;
d->pixBuffers.remove(d->currentStep+"/CHECKMEAS");
d->pixBuffers.remove("ALL");
update();
}
void PcbCamCanvas::clearPopView()
{
Q_D(PcbCamCanvas);
for (auto popview : d->popviewList) {
popview->deleteLater();
}
d->popviewList.clear();
}
void PcbCamCanvas::onPopViewClosed()
{
Q_D(PcbCamCanvas);
PcbCamPopViewWindow *popview = qobject_cast<PcbCamPopViewWindow*>(sender());
auto idx = d->popviewList.indexOf(popview);
if (idx != -1) {
d->popviewList.removeAt(idx);
}
popview->deleteLater();
update();
}
void PcbCamCanvas::doSpacingMeasure()
{
Q_D(PcbCamCanvas);
if (d->spacingFeatBuffer.count() < 2) return;
auto feat1 = d->spacingFeatBuffer.value(0).feature;
auto feat2 = d->spacingFeatBuffer.value(1).feature;
auto shape1 = feat1->shape();
auto shape2 = feat2->shape();
if (shape1.intersects(shape2)) {
d->measureLine = QLineF(0.0, 0.0, 0.0, 0.0);
}
else {
QTransform mat;
mat.scale(10000, 10000);
double dist = LONG_MAX;
auto polys1 = mat.map(shape1).toSubpathPolygons();
auto polys2 = mat.map(shape2).toSubpathPolygons();
double tmpdist;
QLineF spacingLine;
QPointF tmpSnapPoint;
for (auto poly1 : polys1) {
for (auto poly2 : polys2) {
for (auto pt : poly2) {
tmpdist = PcbCamMath::point2polylineDist(pt, poly1, tmpSnapPoint);
if (tmpdist < dist) {
dist = tmpdist;
spacingLine.setP1(pt);
spacingLine.setP2(tmpSnapPoint);
}
}
}
}
for (auto poly2 : polys2) {
for (auto poly1 : polys1) {
for (auto pt : poly1) {
tmpdist = PcbCamMath::point2polylineDist(pt, poly2, tmpSnapPoint);
if (tmpdist < dist) {
dist = tmpdist;
spacingLine.setP1(pt);
spacingLine.setP2(tmpSnapPoint);
}
}
}
}
d->measureLine = mat.inverted().map(spacingLine);
}
QVariantMap msginfo;
msginfo.insert("INFO_TYPE", "MEASURE_SPACING");
msginfo.insert("line", d->measureLine);
emit messageNotified(msginfo);
}
void PcbCamCanvas::doDistMeasure()
{
Q_D(PcbCamCanvas);
QVariantMap msginfo;
msginfo.insert("INFO_TYPE", "MEASURE_DIST");
msginfo.insert("line", d->measureLine);
emit messageNotified(msginfo);
}
void PcbCamCanvas::createPopView(const QRectF &iSourceRect, const QRect &iTargetRect)
{
Q_D(PcbCamCanvas);
auto popview = new PcbCamPopViewWindow(iSourceRect, iTargetRect, this);
popview->setStyleSheet(".PcbCamPopViewWindow{background-color:#E9EEF1;}");
connect(this, &PcbCamCanvas::displayUpdated, popview, &PcbCamPopViewWindow::refresh);
connect(popview, &PcbCamPopViewWindow::aboutToClose, this, &PcbCamCanvas::onPopViewClosed);
connect(popview, &PcbCamPopViewWindow::geometryChanged, [this](){this->update();});
popview->show();
d->popviewList.append(popview);
}
void PcbCamCanvas::drawStepLayer(QPainter *painter,
const QString &iStep,
const QString &iLayer,
const QColor &iColor,
bool iStepRepeat,
const QTransform &iMatrix,
const QRectF &iSceneRect,
PcbCam::DisplayOptions iDispOption) const
{
Q_D(const PcbCamCanvas);
if (d->jobData == nullptr
|| !d->jobData->isStepExists(d->currentStep) ||
!d->jobData->isStepLayerExists(iStep, iLayer))
{
return ;
}
PcbCamStep *step = d->jobData->step(iStep);
PcbCamLayer *layer = d->jobData->layer(iStep, iLayer);
if (iStepRepeat) {
for (const PcbCamStepRepeat &sr : step->getBreakedRepeats()) {
PcbCamStep *srstep = d->jobData->step(sr.step());
QTransform srmat = PcbCamUtil::matrix(QPointF(sr.x(), sr.y()), srstep->datum(), sr.angle(), sr.mirror()) * iMatrix;
drawStepLayer(painter, sr.step(), iLayer, iColor, iStepRepeat, srmat,
srmat.inverted().mapRect(iMatrix.mapRect(iSceneRect)),iDispOption);
}
}
PcbCamUtil::drawFeatures(painter,
layer->features(),
PcbCam::Positive,
iColor,
iMatrix,
iSceneRect,
iDispOption,
d->jobData,
step,
layer);
}
void PcbCamCanvas::drawStepProfile(QPainter *painter, const QString &iStep, const QColor &iColor, const QTransform &iMatrix, bool iSelected) const
{
Q_D(const PcbCamCanvas);
if (d->jobData == nullptr || !d->jobData->isStepExists(iStep)) return ;
painter->save();
PcbCamStep *step = d->jobData->step(iStep);
for (const PcbCamStepRepeat &sr : step->getBreakedRepeats()) {
PcbCamStep *srstep = d->jobData->step(sr.step());
QTransform srmat = PcbCamUtil::matrix(QPointF(sr.x(), sr.y()), srstep->datum(), sr.angle(), sr.mirror()) * iMatrix;
drawStepProfile(painter, sr.step(), iColor, srmat, sr.isSelected());
}
QPen pen(iColor);
if (iSelected) {
pen.setColor(d->snapColor);
}
pen.setWidth(1);
pen.setCosmetic(true);
painter->setPen(pen);
painter->setBrush(Qt::NoBrush);
painter->setTransform(iMatrix);
painter->drawPath(step->profile());
painter->restore();
}
QPixmap PcbCamCanvas::render(const QTransform &iMatrix, const QSize &iSize)
{
Q_D(PcbCamCanvas);
QPainter painter;
QRect renderrect(QPoint(0, 0), iSize);
QPixmap retpix(renderrect.size());
painter.begin(&retpix);
painter.fillRect(renderrect, d->bgColor);
painter.end();
if (d->jobData == nullptr || !d->jobData->isStepExists(d->currentStep)) return retpix;
PcbCamStep *step = d->jobData->step(d->currentStep);
QRectF sceneRect = iMatrix.inverted().mapRect(QRectF(renderrect));
QList<QPixmap> layerpixmaps;
for (const QString &layername : d->dispLayer.keys()) {
QPixmap pixmap(renderrect.size());
pixmap.fill(Qt::transparent);
painter.begin(&pixmap);
drawStepLayer(&painter, step->name(), layername,
QColor(d->dispLayer.value(layername)),
true, iMatrix, sceneRect,
d->displayOptions);
painter.end();
layerpixmaps.append(pixmap);
}
//绘制selection
QList<PcbCamLayer *> affected_layers = d->jobData->stepAffectedLayer(d->currentStep);
PcbCamLayer *worklayer = d->jobData->stepWorkLayer(d->currentStep);
if (worklayer != nullptr) affected_layers.prepend(worklayer);
QPixmap selpixmap(renderrect.size());
selpixmap.fill(Qt::transparent);
painter.begin(&selpixmap);
for (auto layer : affected_layers) {
auto selfeats = layer->selectedFeatures();
if (selfeats.isEmpty()) continue;
PcbCamUtil::drawFeatures(&painter,
selfeats,
PcbCam::Positive,
d->selectionColor,
iMatrix,
sceneRect,
d->displayOptions,
d->jobData,
step,
layer);
}
painter.end();
//绘制highlight
QPixmap highlightpixmap(renderrect.size());
highlightpixmap.fill(Qt::transparent);
painter.begin(&highlightpixmap);
auto dispopt = d->displayOptions;
dispopt |= PcbCam::DisplayNegative;
QRectF srect;
for (auto hinfo : d->highlightBuffer) {
auto mat = hinfo.matrix * iMatrix;
srect = mat.inverted().mapRect(QRectF(renderrect));
PcbCamUtil::drawFeatures(&painter,
QList<PcbCamFeature*>{hinfo.feature},
PcbCam::Positive,
d->highlightColor,
mat ,
srect,
dispopt,
d->jobData,
hinfo.step,
hinfo.layer
);
}
painter.end();
//绘制checklist高亮项
QPixmap chkpixmap = renderChkMeans(iMatrix, renderrect.size());
QPixmap allpix(renderrect.size());
allpix.fill(Qt::transparent);
painter.begin(&allpix);
painter.setCompositionMode(QPainter::CompositionMode_Screen);
for (const QPixmap &pix: layerpixmaps) {
painter.drawPixmap(0, 0, pix);
}
if (!chkpixmap.isNull()) {
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
painter.drawPixmap(0, 0, chkpixmap);
}
if (!highlightpixmap.isNull()) {
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
painter.drawPixmap(0, 0, highlightpixmap);
}
if (!selpixmap.isNull()) {
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
painter.drawPixmap(0, 0, selpixmap);
}
if (d->displayOptions & PcbCam::DisplayProfile) {
drawStepProfile(&painter, d->currentStep, d->profileColor, iMatrix);
}
painter.end();
painter.begin(&retpix);
painter.drawPixmap(0, 0, allpix);
painter.end();
return retpix;
}
QPixmap PcbCamCanvas::renderChkMeans(const QTransform &iMatrix, const QSize &iSize)
{
Q_D(PcbCamCanvas);
QPainter painter;
QPixmap pixmap(iSize);
pixmap.fill(Qt::transparent);
painter.begin(&pixmap);
painter.save();
painter.setTransform(iMatrix);
QColor meascolor(255, 255, 255, 200);
QPen pen(meascolor);
pen.setWidthF(0.005);
pen.setCapStyle(Qt::RoundCap);
pen.setJoinStyle(Qt::RoundJoin);
painter.setPen(pen);
painter.setBrush(Qt::NoBrush);
for (auto meas : d->checkMeasList) {
auto measinfo = meas.toMap();
auto shape = measinfo.value("shape").toString();
auto prop = measinfo.value("shapeprop").toMap();
if (shape == "PT") {
QRectF rectf(prop.value("x").toDouble() - 0.015, prop.value("y").toDouble() - 0.015, 0.03, 0.03);
painter.drawLine(rectf.topLeft(), rectf.bottomRight());
painter.drawLine(rectf.bottomLeft(), rectf.topRight());
}
else if (shape == "SG") {
painter.drawLine(QPointF(prop.value("xs").toDouble(), prop.value("ys").toDouble()),
QPointF(prop.value("xe").toDouble(), prop.value("ye").toDouble()));
}
else if (shape == "CU") {
double r = QLineF(prop.value("xs").toDouble(), prop.value("ys").toDouble(), prop.value("xc").toDouble(), prop.value("yc").toDouble()).length();
QRectF rect(prop.value("xc").toDouble() - r, prop.value("yc").toDouble() -r , r*2, r*2);
painter.drawRect(rect);
}
else if (shape == "LN") {
QPen newpen = pen;
newpen.setWidthF(prop.value("size").toDouble() * 2.0);
//newpen.setCapStyle(prop.value("cap").toString() == "S" ? Qt::SquareCap : Qt::RoundCap);
painter.setPen(newpen);
painter.drawLine(QPointF(prop.value("xs").toDouble(), prop.value("ys").toDouble()),
QPointF(prop.value("xe").toDouble(), prop.value("ye").toDouble()));
painter.setPen(pen);
}
else if (shape == "CR") {
double sz = prop.value("size").toDouble()/2.0;
QRectF rect(prop.value("x").toDouble(), prop.value("y").toDouble(), sz , sz);
painter.drawEllipse(rect);
}
else if (shape == "SQ") {
double sz = prop.value("size").toDouble()/2.0;
QRectF rect(prop.value("x").toDouble(), prop.value("y").toDouble(), sz , sz);
painter.drawRect(rect);
}
else if (shape == "RC") {
QRectF rect(prop.value("xll").toDouble(), prop.value("yll").toDouble(), prop.value("xur").toDouble() , prop.value("yur").toDouble());
painter.drawRect(rect);
}
else if (shape == "AR") {
double r = QLineF(prop.value("xs").toDouble(), prop.value("ys").toDouble(), prop.value("xc").toDouble(), prop.value("yc").toDouble()).length();
QRectF rect(prop.value("xc").toDouble() - r, prop.value("yc").toDouble() -r , r*2, r*2);
double sz = prop.value("size").toDouble()/2.0;
rect = rect.marginsAdded(QMarginsF(sz, sz, sz, sz));
painter.drawRect(rect);
}
}
painter.restore();
painter.end();
return pixmap;
}
QPointF PcbCamCanvas::getSnapPoint(const QPoint &iCursorPos, int iSnapRange, bool *oSnaped)
{
Q_D(PcbCamCanvas);
d->isSnapPointValid = false;
if (oSnaped != nullptr) *oSnaped = false;
if (d->jobData == nullptr) return QPointF();
QPointF curpos = mapToScene(iCursorPos);
if (d->snapMode == PcbCam::SnapOff) return curpos;
QRectF range = mapToScene(QRect(iCursorPos.x() - iSnapRange, iCursorPos.y() - iSnapRange, iSnapRange*2, iSnapRange *2));
QPainterPath snapFeatPaths;
QPolygonF snapFeatPoints;
bool disp_sr = (d->displayOptions & PcbCam::DisplayStepRepeat);
getSnapPathsInRect(d->currentStep, range, disp_sr, QTransform(), snapFeatPaths, snapFeatPoints);
QTransform mat;
mat.scale(10000, 10000);
QPointF scaledCurPos = mat.map(curpos);
QRectF scaledRange = mat.mapRect(range);
bool snapExists = false;
double dist = LONG_MAX;
double tmpdist;
QPointF snapPoint;
QPointF tmpSnapPoint;
snapFeatPaths = mat.map(snapFeatPaths);
for (auto polyline: snapFeatPaths.toSubpathPolygons()) {
tmpdist = PcbCamMath::point2polylineDist(scaledCurPos, polyline, tmpSnapPoint);
if (tmpdist < dist) {
dist = tmpdist;
snapPoint = tmpSnapPoint;
snapExists = true;
}
}
snapFeatPoints = mat.map(snapFeatPoints);
for (auto point : snapFeatPoints) {
tmpdist = PcbCamMath::point2pointDist(scaledCurPos, point);
if (tmpdist < dist) {
dist = tmpdist;
snapPoint = point;
snapExists = true;
}
}
if (snapExists && scaledRange.contains(snapPoint)) {
if (oSnaped != nullptr) *oSnaped = true;
d->isSnapPointValid = true;
d->snapPoint = mat.inverted().map(snapPoint);
return d->snapPoint;
}
else {
return curpos;
}
}
void PcbCamCanvas::getSnapPathsInRect(const QString &iStep, const QRectF &iRange, bool iIncludeStepRepeat, const QTransform &iMatrix, QPainterPath &oSnapFeatPaths, QPolygonF &oSnapFeatPoints) const
{
Q_D(const PcbCamCanvas);
if (d->jobData == nullptr) return ;
auto step = d->jobData->step(iStep);
if (step == nullptr) return;
QPainterPath rectpath;
rectpath.addRect(iRange);
PcbCam::FeatureSelectionFilter snapfilter;
snapfilter.type = d->snapFeatureType;
for (const auto &layername : d->snapLayers) {
auto layer = d->jobData->layer(iStep, layername);
if (layer == nullptr) continue;
for (auto feat : layer->selectFeature(rectpath, snapfilter , PcbCam::NoFeatureSelection, PcbCam::IntersectsFeatureShape)) {
//捕捉边缘
if (d->snapMode & PcbCam::SnapEdge) {
oSnapFeatPaths.addPath(iMatrix.map(feat->shape()));
}
if (feat->type() == PcbCam::PadFeature) {
auto pad = static_cast<PcbCamFeaturePad*>(feat);
if (d->snapMode & PcbCam::SnapCenter || d->snapMode & PcbCam::SnapMidPoint || d->snapMode & PcbCam::SnapSkeleton) {
oSnapFeatPoints << iMatrix.map(pad->pos());
}
}
else if (feat->type() == PcbCam::LineFeature) {
auto line = static_cast<PcbCamFeatureLine*>(feat);
if (d->snapMode & PcbCam::SnapMidPoint || d->snapMode & PcbCam::SnapCenter) {
oSnapFeatPoints << iMatrix.map(line->line().p1()) << iMatrix.map(line->line().p2());
if (d->snapMode & PcbCam::SnapMidPoint) {
oSnapFeatPoints << iMatrix.map(line->line().center());
}
}
if (d->snapMode & PcbCam::SnapSkeleton) {
oSnapFeatPaths.moveTo(iMatrix.map(line->line().p1()));
oSnapFeatPaths.lineTo(iMatrix.map(line->line().p2()));
}
}
else if (feat->type() == PcbCam::ArcFeature) {
auto arc = static_cast<PcbCamFeatureArc*>(feat);
if (d->snapMode & PcbCam::SnapCenter || d->snapMode & PcbCam::SnapMidPoint) {
oSnapFeatPoints << iMatrix.map(arc->ps()) << iMatrix.map(arc->pe()) << iMatrix.map(arc->pc());
}
if (d->snapMode & PcbCam::SnapSkeleton) {
oSnapFeatPaths.addPath(iMatrix.map(PcbCamUtil::arc2path(arc->ps(), arc->pe(), arc->pc(), arc->cw())));
}
}
else if (feat->type() == PcbCam::SurfaceFeature) {
if (d->snapMode & PcbCam::SnapMidPoint) {
oSnapFeatPoints << iMatrix.map(feat->boundingRect().center());
}
}
}
}
if (d->snapMode & PcbCam::SnapProfile) {
auto step = d->jobData->step(iStep);
if (step != nullptr) {
oSnapFeatPaths.addPath(iMatrix.map(step->profile()));
}
}
if (iIncludeStepRepeat) {
for (const auto &sr : step->getBreakedRepeats()) {
auto srstep = d->jobData->step(sr.step());
QTransform srmat = PcbCamUtil::matrix(QPointF(sr.x(), sr.y()), srstep->datum(), sr.angle(), sr.mirror());// * iMatrix;
auto srprofile = srstep->profile();
if (!srmat.map(srprofile).intersects(iRange)) continue;
auto srrange = srmat.inverted().mapRect(iRange);
getSnapPathsInRect(srstep->name(), srrange, iIncludeStepRepeat, srmat*iMatrix, oSnapFeatPaths, oSnapFeatPoints);
}
}
}
void PcbCamCanvas::setDisplayOption(PcbCam::DisplayOptions iDispOption)
{
Q_D(PcbCamCanvas);
d->displayOptions = iDispOption;
d->pixBuffers.clear();
update();
}
PcbCam::DisplayOptions PcbCamCanvas::displayOption() const
{
Q_D(const PcbCamCanvas);
return d->displayOptions;
}
void PcbCamCanvas::setContextMenu(QMenu *iMenu)
{
Q_D(PcbCamCanvas);
d->contextMenu = iMenu;
}
QMenu *PcbCamCanvas::contextMenu() const
{
Q_D(const PcbCamCanvas);
return d->contextMenu;
}
void PcbCamCanvas::setCurrentFeatureFilter(const PcbCam::FeatureSelectionFilter &iFilter)
{
Q_D(PcbCamCanvas);
d->currentFeatureFilter = iFilter;
}
PcbCam::FeatureSelectionFilter PcbCamCanvas::currentFeatureFilter() const
{
Q_D(const PcbCamCanvas);
return d->currentFeatureFilter;
}
void PcbCamCanvas::setSnapLayers(const QStringList &iSnapLayers)
{
Q_D(PcbCamCanvas);
d->snapLayers = iSnapLayers;
}
QStringList PcbCamCanvas::snapLayers() const
{
Q_D(const PcbCamCanvas);
return d->snapLayers;
}
void PcbCamCanvas::setSnapMode(PcbCam::SnapModes iMode)
{
Q_D(PcbCamCanvas);
d->snapMode = iMode;
}
PcbCam::SnapModes PcbCamCanvas::snapMode() const
{
Q_D(const PcbCamCanvas);
return d->snapMode;
}
void PcbCamCanvas::setSnapFeatureType(PcbCam::FeatureTypes iType)
{
Q_D(PcbCamCanvas);
d->snapFeatureType = iType;
}
PcbCam::FeatureTypes PcbCamCanvas::snapFeatureType() const
{
Q_D(const PcbCamCanvas);
return d->snapFeatureType;
}
void PcbCamCanvas::showContextMenu(const QPoint &iPos)
{
Q_D(PcbCamCanvas);
Q_UNUSED(iPos);
if (d->contextMenu != nullptr) {
d->contextMenu->exec(QCursor::pos());
}
}
void PcbCamCanvas::setMousePoint(const QPointF &iPos)
{
Q_D(PcbCamCanvas);
if (d->mouseMode == PcbCamCanvas::ZoomAreaMode || d->mouseMode == PcbCamCanvas::RectangleSelectionMode) {
//区域放大点选第一点
if (d->mouseClickTimes == 0) {
d->rubberBandRect.setTopLeft(iPos);
d->rubberBandRect.setBottomRight(iPos);
d->lastCoordPoint = iPos;
d->mouseClickTimes = 1;
}
else if (d->mouseClickTimes == 1) {
d->rubberBandRect.setBottomRight(iPos);
d->lastCoordPoint = iPos;
d->mouseClickTimes = 0;
if (d->mouseMode == PcbCamCanvas::ZoomAreaMode) {
this->fitInView(d->rubberBandRect);
}
else if (d->mouseMode == PcbCamCanvas::RectangleSelectionMode) {
QPainterPath rectpath; rectpath.addRect(d->rubberBandRect);
selectFeature(QStringList(), rectpath, d->currentFeatureFilter, d->curFeatSelOp, d->curFeatSelMode);
}
d->rubberBandRect = QRectF();
update();
}
else if (d->mouseMode == PcbCamCanvas::SingleSelectionMode) {
singleClickSelection(d->currentMatrix.map(iPos).toPoint(), d->curFeatSelOp);
}
else if (d->mouseMode == PcbCamCanvas::MeasurePointsMode) {
if (d->mouseClickTimes == 0) {
d->measureLine.setP1(iPos);
d->measureLine.setP2(d->measureLine.p1());
d->rubberBandRect.setTopLeft(iPos);
d->rubberBandRect.setBottomRight(iPos);
d->lastCoordPoint = iPos;
d->mouseClickTimes = 1;
}
else if (d->mouseClickTimes == 1) {
d->measureLine.setP2(iPos);
d->rubberBandRect.setBottomRight(iPos);
d->mouseClickTimes = 0;
d->lastCoordPoint = iPos;
d->rubberBandRect = QRectF();
//TODO 抛出量测值
update();
}
}
else if (d->mouseMode == PcbCamCanvas::PopViewMode) {
if (d->mouseClickTimes == 0 || d->mouseClickTimes == 2) {
if (d->currentMovePopView == nullptr) {
d->rubberBandRect.setTopLeft(iPos);
d->rubberBandRect.setBottomRight(iPos);
d->lastCoordPoint = iPos;
d->mouseClickTimes += 1;
}
}
else if (d->mouseClickTimes == 1 || d->mouseClickTimes == 3) {
d->rubberBandRect.setBottomRight(iPos);
d->lastCoordPoint = iPos;
if (d->mouseClickTimes == 1) {
d->tmpRubberBandRect = d->rubberBandRect;
d->rubberBandRect = QRectF();
d->mouseClickTimes++;
}
else if (d->mouseClickTimes == 3) {
QRect poprect = d->currentMatrix.mapRect(d->rubberBandRect.normalized()).toRect();
poprect.moveTo(this->mapToGlobal(poprect.topLeft()));
this->createPopView(d->tmpRubberBandRect.normalized(), poprect);
d->rubberBandRect = QRect();
d->tmpRubberBandRect = QRect();
d->mouseClickTimes = 0;
}
update();
}
}
}
}
void PcbCamCanvas::setDrawRelativeOrig(bool iY)
{
Q_D(PcbCamCanvas);
d->drawRelativeOrig = iY;
}
void PcbCamCanvas::setOriginalPoint(double x, double y)
{
Q_D(PcbCamCanvas);
d->origPoint.setX(x);
d->origPoint.setY(y);
}
QPointF PcbCamCanvas::originalPoint() const
{
Q_D(const PcbCamCanvas);
return d->origPoint;
}
QPointF PcbCamCanvas::relativeOriginalPoint() const
{
Q_D(const PcbCamCanvas);
return d->lastCoordPoint;
}
void PcbCamCanvas::setJobData(PcbCamJob *iJob)
{
Q_D(PcbCamCanvas);
d->jobData = iJob;
}
bool PcbCamCanvas::event(QEvent *iEvent)
{
Q_D(PcbCamCanvas);
if (iEvent->type() == QEvent::MouseMove) {
QMouseEvent *evt = static_cast<QMouseEvent*>(iEvent);
if (d->displayOptions & PcbCam::DisplayFullCursor) {
d->curMousePos = evt->pos();
update();
}
emit mousePositionChanged(d->currentMatrix.inverted().map(QPointF(evt->pos())));
}
if (d->mouseMode == PcbCamCanvas::PanViewMode
|| d->panviewDrag
|| (static_cast<QMouseEvent*>(iEvent) != nullptr && (static_cast<QMouseEvent*>(iEvent)->modifiers() & Qt::AltModifier) && static_cast<QMouseEvent*>(iEvent)->button() == Qt::LeftButton))
{
if (iEvent->type() == QEvent::MouseButtonDblClick) {
this->zoomHome();
}
else {
if (iEvent->type() == QEvent::MouseButtonPress) {
QMouseEvent *evt = static_cast<QMouseEvent*>(iEvent);
d->panviewDrag = true;
d->panviewStartPos = evt->pos();
d->panviewStartRect = d->currentDisplayRect;
d->lastCursor = this->cursor();
this->setCursor(QCursor(Qt::ClosedHandCursor));
}
else if (d->panviewDrag && iEvent->type() == QEvent::MouseMove) {
QMouseEvent *evt = static_cast<QMouseEvent*>(iEvent);
QPointF dist = mapToScene(d->panviewStartPos) - mapToScene(evt->pos());
this->fitInView(d->panviewStartRect.translated(dist), false);
}
else if (iEvent->type() == QEvent::MouseButtonRelease) {
d->panviewDrag = false;
this->setCursor(QCursor(d->mouseMode == PcbCamCanvas::PanViewMode ? Qt::OpenHandCursor : d->lastCursor));
}
}
}
else if (d->mouseMode == PcbCamCanvas::ZoomAreaMode || d->mouseMode == PcbCamCanvas::RectangleSelectionMode) {
//区域放大点选第一点
if (d->mouseClickTimes == 0 && iEvent->type() == QEvent::MouseButtonPress ) {
QMouseEvent *evt = static_cast<QMouseEvent*>(iEvent);
if (evt->button() == Qt::LeftButton) {
d->rubberBandRect.setTopLeft(mapToScene(evt->pos()));
d->rubberBandRect.setBottomRight(mapToScene(evt->pos()));
d->lastCoordPoint = mapToScene(evt->pos());
d->mouseClickTimes = 1;
}
}
else if (d->mouseClickTimes == 1 && iEvent->type() == QEvent::MouseMove) {
QMouseEvent *evt = static_cast<QMouseEvent*>(iEvent);
d->rubberBandRect.setBottomRight(mapToScene(evt->pos()));
update();
}
else if (d->mouseClickTimes == 1 && iEvent->type() == QEvent::MouseButtonPress) {
QMouseEvent *evt = static_cast<QMouseEvent*>(iEvent);
if (evt->button() == Qt::LeftButton) {
d->rubberBandRect.setBottomRight(mapToScene(evt->pos()));
d->lastCoordPoint = mapToScene(evt->pos());
d->mouseClickTimes = 0;
if (d->mouseMode == PcbCamCanvas::ZoomAreaMode) {
this->fitInView(d->rubberBandRect);
}
else if (d->mouseMode == PcbCamCanvas::RectangleSelectionMode) {
PcbCam::FeatureSelectionMode mode = (evt->modifiers() & Qt::ControlModifier) ? PcbCam::IntersectsFeatureShape : PcbCam::ContainsFeatureShape;
PcbCam::FeatureSelectionOperation op = (evt->modifiers() & Qt::ShiftModifier) ? PcbCam::AppendFeatureSelection : PcbCam::ReplaceFeatureSelection;
QPainterPath rectpath; rectpath.addRect(d->rubberBandRect);
selectFeature(QStringList(), rectpath, d->currentFeatureFilter, op, mode);
}
d->rubberBandRect = QRectF();
update();
}
else if (evt->button() == Qt::MiddleButton) {
d->mouseClickTimes = 0;
d->rubberBandRect = QRectF();
update();
}
}
}
else if (d->mouseMode == PcbCamCanvas::PolygonSelectionMode) {
if (d->mouseClickTimes == 0 && iEvent->type() == QEvent::MouseButtonPress ) {
QMouseEvent *evt = static_cast<QMouseEvent*>(iEvent);
if (evt->button() == Qt::LeftButton) {
d->lastCoordPoint = mapToScene(evt->pos());
d->curMousePos = evt->pos();
d->polygonBand.clear();
d->polygonBand << mapToScene(evt->pos());
d->mouseClickTimes = 1;
}
}
else if (d->mouseClickTimes == 1 && iEvent->type() == QEvent::MouseMove) {
QMouseEvent *evt = static_cast<QMouseEvent*>(iEvent);
d->curMousePos = evt->pos();
update();
}
else if (d->mouseClickTimes == 1 && iEvent->type() == QEvent::MouseButtonPress) {
QMouseEvent *evt = static_cast<QMouseEvent*>(iEvent);
if (evt->button() == Qt::LeftButton) {
d->lastCoordPoint = mapToScene(evt->pos());
d->polygonBand << mapToScene(evt->pos());
update();
}
else if (evt->button() == Qt::MiddleButton) {
if (!d->polygonBand.isEmpty()) d->polygonBand.pop_back();
update();
}
}
else if (d->mouseClickTimes == 1 && iEvent->type() == QEvent::MouseButtonDblClick) {
QMouseEvent *evt = static_cast<QMouseEvent*>(iEvent);
if (evt->button() == Qt::LeftButton) {
d->polygonBand << mapToScene(evt->pos());
d->lastCoordPoint = mapToScene(evt->pos());
d->mouseClickTimes = 0;
if (d->polygonBand.count() > 2) {
PcbCam::FeatureSelectionMode mode = (evt->modifiers() & Qt::ControlModifier) ? PcbCam::IntersectsFeatureShape : PcbCam::ContainsFeatureShape;
PcbCam::FeatureSelectionOperation op = (evt->modifiers() & Qt::ShiftModifier) ? PcbCam::AppendFeatureSelection : PcbCam::ReplaceFeatureSelection;
QPainterPath polypath;
polypath.addPolygon(d->polygonBand);
polypath.closeSubpath();
selectFeature(QStringList(), polypath, d->currentFeatureFilter, op, mode);
}
d->polygonBand.clear();
update();
}
}
}
else if (d->mouseMode == PcbCamCanvas::SingleSelectionMode) {
d->mouseClickTimes = 0;
d->rubberBandRect = QRect();
if (iEvent->type() == QEvent::MouseButtonDblClick) {
QMouseEvent *evt = static_cast<QMouseEvent*>(iEvent);
if (evt->button() == Qt::LeftButton) {
PcbCam::FeatureSelectionOperation op = (evt->modifiers() & Qt::ShiftModifier)
? PcbCam::AppendFeatureSelection
: PcbCam::ReplaceFeatureSelection;
doubleClickSelection(evt->pos(), op);
}
}
else if (iEvent->type() == QEvent::MouseButtonPress) {
QMouseEvent *evt = static_cast<QMouseEvent*>(iEvent);
if (evt->button() == Qt::LeftButton) {
PcbCam::FeatureSelectionOperation op = (evt->modifiers() & Qt::ShiftModifier)
? PcbCam::AppendFeatureSelection
: PcbCam::ReplaceFeatureSelection;
d->lastCoordPoint = mapToScene(evt->pos());
singleClickSelection(evt->pos(), op);
}
else if (evt->button() == Qt::MiddleButton) {
singleClickSelection(evt->pos(), PcbCam::RemoveFeatureSelection);
}
}
}
else if (d->mouseMode == PcbCamCanvas::LayerNetSelectionMode) {
d->mouseClickTimes = 0;
d->rubberBandRect = QRect();
if (iEvent->type() == QEvent::MouseButtonPress) {
PcbCam::FeatureSelectionFilter filter;
QMouseEvent *evt = static_cast<QMouseEvent*>(iEvent);
if (evt->button() == Qt::LeftButton) {
PcbCam::FeatureSelectionOperation op = (evt->modifiers() & Qt::ShiftModifier)
? PcbCam::AppendFeatureSelection
: PcbCam::ReplaceFeatureSelection;
d->lastCoordPoint = mapToScene(evt->pos());
layerNetSelection(QStringList(), evt->pos(), op, filter);
}
else if (evt->button() == Qt::MiddleButton) {
layerNetSelection(QStringList(), evt->pos(), PcbCam::RemoveFeatureSelection, filter);
}
}
}
else if (d->mouseMode == PcbCamCanvas::LayerPolylineSelectionMode) {
d->mouseClickTimes = 0;
d->rubberBandRect = QRect();
if (iEvent->type() == QEvent::MouseButtonPress && d->jobData != nullptr && !d->currentStep.isEmpty()) {
QMouseEvent *evt = static_cast<QMouseEvent*>(iEvent);
PcbCam::FeatureSelectionFilter filter;
filter.type = PcbCam::LineFeature;
filter.type |= PcbCam::ArcFeature;
filter.polarity = PcbCam::Positive;
// 获取鼠标下的symbolname
auto pos = evt->pos();
int tol = 4;
QRectF rect = mapToScene(QRect(pos.x() - tol, pos.y() - tol, 2 * tol, 2 * tol));
QPainterPath rectpath;
rectpath.addRect(rect);
PcbCamLayer *worklayer = d->jobData->stepWorkLayer(d->currentStep);
if (worklayer != nullptr) {
PcbCamFeature *firstfeat = worklayer->selectFeature(rectpath, filter, PcbCam::NoFeatureSelection, PcbCam::IntersectsFeatureShape).value(0, nullptr);
if (firstfeat != nullptr) {
filter.includeSymbols.append(firstfeat->symbol()->name());
}
}
if (evt->button() == Qt::LeftButton) {
PcbCam::FeatureSelectionOperation op = (evt->modifiers() & Qt::ShiftModifier)
? PcbCam::AppendFeatureSelection
: PcbCam::ReplaceFeatureSelection;
d->lastCoordPoint = mapToScene(evt->pos());
layerNetSelection(QStringList() << worklayer->name(), evt->pos(), op, filter);
}
else if (evt->button() == Qt::MiddleButton) {
d->lastCoordPoint = mapToScene(evt->pos());
layerNetSelection(QStringList() << worklayer->name(), evt->pos(), PcbCam::RemoveFeatureSelection, filter);
}
}
}
else if (d->mouseMode == PcbCamCanvas::SnapFeatMode) {
d->mouseClickTimes = 0;
d->rubberBandRect = QRect();
if (iEvent->type() == QEvent::MouseButtonPress) {
QMouseEvent *evt = static_cast<QMouseEvent*>(iEvent);
if (evt->button() == Qt::LeftButton) {
snapFeatInfo(evt->pos());
}
}
}
else if (d->mouseMode == PcbCamCanvas::MeasurePointsMode) {
//测量点选第一点
if (d->mouseClickTimes == 0 && iEvent->type() == QEvent::MouseButtonPress ) {
QMouseEvent *evt = static_cast<QMouseEvent*>(iEvent);
if (evt->button() == Qt::LeftButton) {
QPointF sp = getSnapPoint(evt->pos());
d->measureLine.setP1(sp);
d->measureLine.setP2(d->measureLine.p1());
d->rubberBandRect.setTopLeft(sp);
d->rubberBandRect.setBottomRight(sp);
d->lastCoordPoint = sp;
d->mouseClickTimes = 1;
}
}
else if (d->mouseClickTimes == 0 && iEvent->type() == QEvent::MouseMove) {
QMouseEvent *evt = static_cast<QMouseEvent*>(iEvent);
getSnapPoint(evt->pos());
update();
}
else if (d->mouseClickTimes == 1 && iEvent->type() == QEvent::MouseMove) {
QMouseEvent *evt = static_cast<QMouseEvent*>(iEvent);
QPointF sp = getSnapPoint(evt->pos());
d->measureLine.setP2(sp);
d->rubberBandRect.setBottomRight(sp);
update();
}
else if (d->mouseClickTimes == 1 && iEvent->type() == QEvent::MouseButtonPress) {
QMouseEvent *evt = static_cast<QMouseEvent*>(iEvent);
if (evt->button() == Qt::LeftButton) {
d->lastCoordPoint = d->rubberBandRect.bottomRight();
d->mouseClickTimes = 0;
d->isSnapPointValid = false;
d->rubberBandRect = QRectF();
doDistMeasure();
update();
}
else if (evt->button() == Qt::MiddleButton) {
d->mouseClickTimes = 0;
d->isSnapPointValid = false;
d->rubberBandRect = QRectF();
update();
}
}
}
else if (d->mouseMode == PcbCamCanvas::MeasureSpacingMode) {
// 间距测量
if (iEvent->type() == QEvent::MouseButtonPress) {
QMouseEvent *evt = static_cast<QMouseEvent*>(iEvent);
if (evt->button() == Qt::LeftButton) {
auto featinfo = getFirstFeatureAt(evt->pos(), DisplayLayer);
if (featinfo.feature != nullptr) {
d->spacingFeatBuffer << featinfo;
}
if (d->spacingFeatBuffer.count() == 2) {
doSpacingMeasure();
}
else if (d->spacingFeatBuffer.count() > 2) {
d->spacingFeatBuffer.pop_front();
d->spacingFeatBuffer.pop_front();
d->measureLine = QLineF(0.0, 0.0, 0.0, 0.0);
}
update();
}
else if (evt->button() == Qt::MiddleButton) {
if (!d->spacingFeatBuffer.isEmpty()) d->spacingFeatBuffer.pop_back();
update();
}
}
}
else if (d->mouseMode == PcbCamCanvas::PopViewMode) {
if ((d->mouseClickTimes == 0 || d->mouseClickTimes == 2 ) && iEvent->type() == QEvent::MouseButtonPress ) {
QMouseEvent *evt = static_cast<QMouseEvent*>(iEvent);
if (evt->button() == Qt::LeftButton) {
//判断是否为移动PopView范围
if (d->mouseClickTimes == 0) {
for (auto popview : d->popviewList) {
if (d->currentMatrix.mapRect(popview->sourceRect()).contains(evt->pos())) {
d->currentMovePopView = popview;
d->currentMovePopViewOrigRect = d->currentMatrix.mapRect(popview->sourceRect()).toRect();
d->panviewStartPos = evt->pos();
this->setCursor(QCursor(Qt::ClosedHandCursor));
break;
}
}
}
if (d->currentMovePopView == nullptr) {
d->rubberBandRect.setTopLeft(mapToScene(evt->pos()));
d->rubberBandRect.setBottomRight(mapToScene(evt->pos()));
d->lastCoordPoint = mapToScene(evt->pos());
d->mouseClickTimes += 1;
}
}
}
else if (d->currentMovePopView && d->mouseClickTimes == 0 && iEvent->type() == QEvent::MouseMove) {
//移动PopView范围
QMouseEvent *evt = static_cast<QMouseEvent*>(iEvent);
QPoint dist(evt->pos().x() - d->panviewStartPos.x() , evt->pos().y() - d->panviewStartPos.y());
d->currentMovePopView->setSourceRect(mapToScene(d->currentMovePopViewOrigRect.translated(dist)));
this->update();
}
else if (d->currentMovePopView && d->mouseClickTimes == 0 && iEvent->type() == QEvent::MouseButtonRelease) {
//移动PopView范围完成
d->currentMovePopView->refresh();
this->setCursor(QCursor(Qt::ArrowCursor));
d->currentMovePopView = nullptr;
}
else if ((d->mouseClickTimes == 1 || d->mouseClickTimes == 3) && iEvent->type() == QEvent::MouseMove) {
QMouseEvent *evt = static_cast<QMouseEvent*>(iEvent);
d->rubberBandRect.setBottomRight(mapToScene(evt->pos()));
update();
}
else if ((d->mouseClickTimes == 1 || d->mouseClickTimes == 3) && iEvent->type() == QEvent::MouseButtonPress) {
QMouseEvent *evt = static_cast<QMouseEvent*>(iEvent);
if (evt->button() == Qt::LeftButton) {
d->rubberBandRect.setBottomRight(mapToScene(evt->pos()));
d->lastCoordPoint = mapToScene(evt->pos());
if (d->mouseClickTimes == 1) {
d->tmpRubberBandRect = d->rubberBandRect;
d->rubberBandRect = QRectF();
d->mouseClickTimes++;
}
else if (d->mouseClickTimes == 3) {
QRect poprect = d->currentMatrix.mapRect(d->rubberBandRect.normalized()).toRect();
poprect.moveTo(this->mapToGlobal(poprect.topLeft()));
this->createPopView(d->tmpRubberBandRect.normalized(), poprect);
d->rubberBandRect = QRect();
d->tmpRubberBandRect = QRect();
d->mouseClickTimes = 0;
}
update();
}
}
if (iEvent->type() == QEvent::MouseButtonPress && static_cast<QMouseEvent*>(iEvent)->button() == Qt::MiddleButton) {
d->mouseClickTimes = 0;
d->rubberBandRect = QRectF();
d->tmpRubberBandRect = QRectF();
update();
}
}
if (iEvent->type() == QEvent::KeyPress) {
QKeyEvent *keyevt = static_cast<QKeyEvent*>(iEvent);
if (keyevt->modifiers() == Qt::NoModifier) {
emit keyPressed(keyevt->text());
}
}
return QWidget::event(iEvent);
}
void PcbCamCanvas::paintEvent(QPaintEvent */*iEvent*/)
{
Q_D(PcbCamCanvas);
QPainter painter;
painter.begin(this);
painter.fillRect(this->rect(), d->bgColor);
painter.end();
if (d->jobData == nullptr) return;
if (!d->jobData->isStepExists(d->currentStep)) return;
PcbCamStep *curstep = d->jobData->step(d->currentStep);
QRectF sceneRect = d->currentMatrix.inverted().mapRect(QRectF(this->rect()));
if (d->pixBuffers.value("ALL").isNull()) {
QList<QPixmap> pixmaps;
for (const QString &layername: d->dispLayer.keys()) {
QString bfkey = curstep->name() + "/" + layername + "/" + d->dispLayer.value(layername);
if (!d->pixBuffers.contains(bfkey)) {
QPixmap pixmap(this->rect().size());
pixmap.fill(Qt::transparent);
painter.begin(&pixmap);
drawStepLayer(&painter, curstep->name(), layername,
QColor(d->dispLayer.value(layername)),
(d->displayOptions & PcbCam::DisplayStepRepeat),
d->currentMatrix, sceneRect,d->displayOptions);
painter.end();
d->pixBuffers.insert(bfkey, pixmap);
}
pixmaps.append(d->pixBuffers.value(bfkey));
}
//绘制selection
QPixmap selpixmap;
{
QList<PcbCamLayer *> affected_layers = d->jobData->stepAffectedLayer(d->currentStep);
PcbCamLayer *worklayer = d->jobData->stepWorkLayer(d->currentStep);
if (worklayer != nullptr) affected_layers.prepend(worklayer);
QString bfkey = curstep->name() + "/SELECTION";
if (!d->pixBuffers.contains(bfkey)) {
QPixmap pixmap(this->rect().size());
pixmap.fill(Qt::transparent);
painter.begin(&pixmap);
auto dispopt = d->displayOptions;
dispopt |= PcbCam::DisplayNegative;
for (auto layer : affected_layers) {
auto selfeats = layer->selectedFeatures();
if (selfeats.isEmpty()) continue;
PcbCamUtil::drawFeatures(&painter,
selfeats,
PcbCam::Positive,
d->selectionColor,
d->currentMatrix,
sceneRect,
dispopt,
d->jobData,
curstep,
layer);
}
painter.end();
d->pixBuffers.insert(bfkey, pixmap);
}
selpixmap = d->pixBuffers.value(bfkey);
}
//绘制highlight
QPixmap highlightpixmap;
{
QString bfkey = curstep->name() + "/HIGHLIGHT";
if (!d->pixBuffers.contains(bfkey)) {
QPixmap pixmap(this->rect().size());
pixmap.fill(Qt::transparent);
painter.begin(&pixmap);
auto dispopt = d->displayOptions;
dispopt |= PcbCam::DisplayNegative;
QRectF srect;
for (auto hinfo : d->highlightBuffer) {
auto mat = hinfo.matrix * d->currentMatrix;
srect = mat.inverted().mapRect(QRectF(this->rect()));
PcbCamUtil::drawFeatures(&painter,
QList<PcbCamFeature*>{hinfo.feature},
PcbCam::Positive,
d->highlightColor,
mat ,
srect,
dispopt,
d->jobData,
hinfo.step,
hinfo.layer
);
}
painter.end();
d->pixBuffers.insert(bfkey, pixmap);
}
highlightpixmap = d->pixBuffers.value(bfkey);
}
//绘制checklist高亮项
QPixmap chkpixmap;
{
QString bfkey = curstep->name() + "/CHECKMEAS";
if (!d->pixBuffers.contains(bfkey) && !d->checkMeasList.isEmpty()) {
d->pixBuffers.insert(bfkey, renderChkMeans(d->currentMatrix, this->rect().size()));
}
chkpixmap = d->pixBuffers.value(bfkey);
}
QPixmap allpix(this->rect().size());
allpix.fill(Qt::transparent);
painter.begin(&allpix);
painter.setCompositionMode(QPainter::CompositionMode_Screen);
for (const QPixmap &pix : pixmaps) {
painter.drawPixmap(0, 0, pix);
}
if (!chkpixmap.isNull()) {
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
painter.drawPixmap(0, 0, chkpixmap);
}
if (!highlightpixmap.isNull()) {
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
painter.drawPixmap(0, 0, highlightpixmap);
}
if (!selpixmap.isNull()) {
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
painter.drawPixmap(0, 0, selpixmap);
}
if (d->displayOptions & PcbCam::DisplayProfile) {
drawStepProfile(&painter, d->currentStep, d->profileColor, d->currentMatrix);
}
painter.end();
d->pixBuffers.insert("ALL", allpix);
emit displayUpdated();
}
painter.begin(this);
painter.drawPixmap(0, 0, d->pixBuffers.value("ALL"));
//绘制座标原点
QPen pen(d->profileColor);
pen.setWidth(1);
pen.setCosmetic(true);
painter.setPen(pen);
painter.setBrush(Qt::NoBrush);
QPoint origPos = d->currentMatrix.map(d->origPoint).toPoint();
int origSize = 10;
QRect origrect (origPos.x() - origSize/2.0, origPos.y() - origSize/2.0, origSize, origSize);
if (d->displayOptions & PcbCam::DisplayDatumn) {
painter.drawEllipse(origrect);
painter.drawLine(QLine(origPos.x(), origPos.y() - origSize/2 - 2, origPos.x(), origPos.y() + origSize/2 + 2));
painter.drawLine(QLine(origPos.x() - origSize/2 - 2, origPos.y(), origPos.x() + origSize/2 + 2, origPos.y()));
}
//绘制相对座标原点
if (d->drawRelativeOrig) {
QPoint relOrigPos = d->currentMatrix.map(d->lastCoordPoint).toPoint();
painter.drawPoint(relOrigPos);
painter.drawLine(relOrigPos.x() - origSize/2.0, relOrigPos.y(), relOrigPos.x(), relOrigPos.y() + origSize/2);
painter.drawLine(relOrigPos.x(), relOrigPos.y() + origSize/2, relOrigPos.x() + origSize/2.0, relOrigPos.y());
painter.drawLine(relOrigPos.x() + origSize/2.0, relOrigPos.y(), relOrigPos.x(), relOrigPos.y() - origSize/2);
painter.drawLine(relOrigPos.x(), relOrigPos.y() - origSize/2, relOrigPos.x() - origSize/2.0, relOrigPos.y());
}
//绘制Rubber
pen.setColor(d->rubberColor);
pen.setWidth(1);
pen.setCosmetic(true);
painter.setPen(pen);
QColor color(Qt::blue);
color.setAlphaF(0.2);
painter.setBrush(QBrush(color));
if (!d->tmpRubberBandRect.normalized().isEmpty()) {
painter.drawRect(d->currentMatrix.mapRect(d->tmpRubberBandRect).normalized());
}
if (!d->rubberBandRect.normalized().isEmpty()) {
painter.drawRect(d->currentMatrix.mapRect(d->rubberBandRect).normalized());
}
if (d->polygonBand.count() == 1) {
painter.drawLine(d->currentMatrix.map(d->polygonBand.first()).toPoint(), d->curMousePos);
}
else if (d->polygonBand.count() >= 2) {
auto poly = d->polygonBand;
poly << mapToScene(d->curMousePos);
QPainterPath path;
path.addPolygon(poly);
path.closeSubpath();
painter.drawPath(d->currentMatrix.map(path));
}
//绘制全屏Cursor
if (d->displayOptions & PcbCam::DisplayFullCursor) {
auto rect = this->rect();
painter.drawLine(d->curMousePos.x(), rect.top(), d->curMousePos.x(), rect.bottom());
painter.drawLine(rect.left(), d->curMousePos.y(), rect.right(), d->curMousePos.y());
}
// 绘制捕捉点
if (d->isSnapPointValid) {
painter.setPen(d->snapColor);
auto snapcolor = d->snapColor;
snapcolor.setAlphaF(0.2);
painter.setBrush(QBrush(color));
double snapsize = 8;
auto snappos = d->currentMatrix.map(d->snapPoint);
QPainterPath snappath;
snappath.moveTo(snappos.x() - snapsize, snappos.y());
snappath.lineTo(snappos.x(), snappos.y() + snapsize);
snappath.lineTo(snappos.x() + snapsize, snappos.y());
snappath.lineTo(snappos.x(), snappos.y() - snapsize);
snappath.closeSubpath();
painter.drawPath(snappath);
painter.drawPoint(snappos);
}
//绘制PopView框
painter.setPen(d->highlightColor);
for (const PcbCamPopViewWindow *popview: d->popviewList) {
auto srcRect = d->currentMatrix.mapRect(popview->sourceRect()).normalized();
auto popRect = popview->viewRect();
popRect.moveTo(this->mapFromGlobal(popRect.topLeft()));
popRect = popRect.normalized();
painter.drawRect(srcRect);
painter.drawLine(QLineF(srcRect.topLeft(), popRect.topLeft()));
painter.drawLine(QLineF(srcRect.topRight(), popRect.topRight()));
painter.drawLine(QLineF(srcRect.bottomLeft(), popRect.bottomLeft()));
painter.drawLine(QLineF(srcRect.bottomRight(), popRect.bottomRight()));
}
//绘制间距量测
if (!d->spacingFeatBuffer.isEmpty()) {
if (d->measureLine.length() > 0) {
painter.setPen(d->highlightColor);
painter.drawLine(d->currentMatrix.map(d->measureLine));
}
auto dispopt = d->displayOptions;
dispopt |= PcbCam::DisplayNegative;
for (auto hinfo : d->spacingFeatBuffer) {
auto mat = hinfo.matrix * d->currentMatrix;
QRectF srect = mat.inverted().mapRect(QRectF(this->rect()));
PcbCamUtil::drawFeatures(&painter,
QList<PcbCamFeature*>{hinfo.feature},
PcbCam::Positive,
d->highlightColor,
mat ,
srect,
dispopt,
d->jobData,
hinfo.step,
hinfo.layer
);
}
}
//绘制距离量测
if (d->mouseMode == PcbCamCanvas::MeasurePointsMode && d->mouseClickTimes == 1) {
painter.setPen(d->rubberColor);
QRectF rubberrect = d->currentMatrix.mapRect(d->rubberBandRect);
rubberrect = rubberrect.normalized();
QFont font = painter.font();
font.setPixelSize(16);
painter.setFont(font);
QFontMetrics fm(font);
double dx = d->unitsType == PcbCam::Units_Mm ? d->measureLine.dx() * 25.4 : d->measureLine.dx();
double dy = d->unitsType == PcbCam::Units_Mm ? d->measureLine.dy() * 25.4 : d->measureLine.dy();
double len = d->unitsType == PcbCam::Units_Mm ? d->measureLine.length() * 25.4 : d->measureLine.length();
if ((dx > 0 && dy >0 ) || (dx < 0 && dy < 0)) {
painter.drawLine(rubberrect.bottomLeft(), rubberrect.topRight());
}
else {
painter.drawLine(rubberrect.topLeft(), rubberrect.bottomRight());
}
QString mtext = QString("DX=%1, DY=%2, D=%3").arg(dx).arg(dy).arg(len);
int textwidth = fm.horizontalAdvance(mtext);
int textheight = fm.height();
QRect textrect;
if (dy > 0) {
textrect.setTop(rubberrect.top() - textheight);
textrect.setBottom(rubberrect.top());
}
else {
textrect.setTop(rubberrect.bottom());
textrect.setBottom(rubberrect.bottom() + textheight);
}
if (dx > 0) {
textrect.setLeft(rubberrect.right() - textwidth);
textrect.setRight(rubberrect.right());
}
else {
textrect.setLeft(rubberrect.left());
textrect.setRight(rubberrect.left() + textwidth);
}
if (textrect.left() < 0) {
textrect.moveLeft(0);
}
if (textrect.right() > this->contentsRect().right()) {
textrect.moveRight(this->contentsRect().right());
}
painter.setPen(d->highlightColor);
painter.drawText(textrect, mtext);
}
painter.end();
}
void PcbCamCanvas::resizeEvent(QResizeEvent *)
{
Q_D(PcbCamCanvas);
fitInView(d->currentDisplayRect, false);
}
void PcbCamCanvas::wheelEvent(QWheelEvent *event)
{
Q_D(PcbCamCanvas);
QPoint numDegrees = event->angleDelta() / 8;
QPointF pos = event->position();
int steps = numDegrees.y()/15;
if (steps == 0) {
event->accept();
return;
}
bool isZoomIn = steps < 0;
steps = qMin(2, abs(steps));
qreal scale = isZoomIn ? 1.2*steps : 1.0/(1.2*steps);
QTransform mat;
mat.scale(scale, scale);
auto newpos = mat.map(pos);
auto newrect = mat.mapRect(QRectF(this->rect()));
newrect.translate(pos.x() - newpos.x(), pos.y() - newpos.y());
this->fitInView( d->currentMatrix.inverted().mapRect(QRectF(newrect)), false);
event->accept();
update();
}
void PcbCamCanvas::contextMenuEvent(QContextMenuEvent *event)
{
Q_D(PcbCamCanvas);
// if (event->modifiers() & Qt::ControlModifier || event->modifiers() &Qt::AltModifier || event->modifiers() & Qt::ShiftModifier) {
// event->ignore();
// }
// else {
if (d->contextMenu != nullptr) {
d->contextMenu->exec(event->globalPos());
}
event->accept();
// }
}
TITAN_END_NAMESPACE
#ifndef TITAN_PCBCAM_GRAPHVIEW_H
#define TITAN_PCBCAM_GRAPHVIEW_H
#include "../titanpcbcamglobal.h"
#include <QWidget>
#include <QMenu>
#include <QRectF>
#include <QEvent>
#include "../core/job.h"
TITAN_BEGIN_NAMESPACE
class PcbCamPopViewWindow;
class PcbCamCanvasPrivate;
class TITAN_PCBCAM_EXPORT PcbCamCanvas : public QWidget
{
Q_OBJECT
friend class PcbCamPopViewWindow;
public:
enum MouseMode {
ZoomAreaMode,
SingleSelectionMode,
RectangleSelectionMode,
PolygonSelectionMode,
LayerNetSelectionMode,
LayerPolylineSelectionMode,
PanViewMode,
MeasurePointsMode,
MeasureSpacingMode,
PopViewMode,
SnapFeatMode,
};
enum LayerScope {
WorkLayer = 0x01,
AffectedLayer = 0x02,
DisplayLayer = 0x04,
};
Q_ENUM(LayerScope)
Q_DECLARE_FLAGS(LayerScopes, LayerScope)
Q_FLAGS(LayerScopes)
struct FeatureInfo {
PcbCamLayer *layer {nullptr};
PcbCamFeature *feature {nullptr};
PcbCamStep *step {nullptr};
QTransform matrix;
};
explicit PcbCamCanvas(QWidget *parent = 0);
~PcbCamCanvas();
signals:
void mousePositionChanged(const QPointF &iPos);
void messageNotified(const QVariant &iInfo);
void displayUpdated();
void selectionChanged();
void keyPressed(const QString &iKey);
void snapFeatChanged(const QVariantMap &iInfo);
public slots:
void setJobData(PcbCamJob *iJob);
void fitInView(const QRectF &iRect, bool iSaveHist = true);
void setCurrentStep(const QString &iStep);
QString currentStep() const;
void zoomHome();
void zoomIn();
void zoomOut();
void zoomPrevious();
void viewLeft(qreal iRate = 0.9);
void viewRight(qreal iRate = 0.9);
void viewUp(qreal iRate = 0.9);
void viewDown(qreal iRate = 0.9);
void setOrientMatrix(const QTransform &iMatrix);
QTransform orientMatrix() const;
QTransform currentMatrix() const;
void setUnitsType(PcbCam::UnitsType iUnits);
PcbCam::UnitsType unitsType() const;
void display(const QString &iLayer, const QString &iColor);
void resetDisplayLayers(const QMap<QString, QString> &iDispInfo);
void clearDisplay();
void refresh();
void setBgColor(const QString &iBgColor);
QString bgColor() const;
void setRubberColor(const QString &iColor);
QString rubberColor() const;
void setHighlightColor(const QString &iColor);
QString highlightColor() const;
void setSelectionColor(const QString &iColor);
QString selectionColor() const;
void setProfileColor(const QString &iColor);
QString profileColor() const;
QPointF mapToScene(const QPoint &iPoint) const;
QRectF mapToScene(const QRect &iRect) const;
void setMouseMode(const PcbCamCanvas::MouseMode iMouseMode);
PcbCamCanvas::MouseMode mouseMode() const;
QList<PcbCamCanvas::FeatureInfo> getFeaturesAt(const QPoint &iPoint, LayerScope iLayerScope, int iTolPix=2) const;
PcbCamCanvas::FeatureInfo getFirstFeatureAt(const QPoint &iPoint, LayerScope iLayerScope, int iTolPix=2) const;
QVariantMap snapFeatInfo(const QPoint &iPoint, int iTolPix=2);
void setSnapFeatRequestKey(const QString &iKey);
void singleClickSelection(const QPoint &iPoint, PcbCam::FeatureSelectionOperation iSelOp);
void doubleClickSelection(const QPoint &iPoint, PcbCam::FeatureSelectionOperation iSelOp);
QList<PcbCamFeature *> selectFeature(const QStringList &iLayers, const QPainterPath &iPath,
const PcbCam::FeatureSelectionFilter &iFilter,
PcbCam::FeatureSelectionOperation iSelOp,
PcbCam::FeatureSelectionMode iMode
);
QList<PcbCamFeature *> selectedFeatures() const;
void layerNetSelection(const QStringList &iLayers, const QPoint &iPoint, PcbCam::FeatureSelectionOperation iSelOp, const PcbCam::FeatureSelectionFilter &iFilter);
void highlightFeature(const QString &iStep,
const QStringList &iLayers,
const PcbCam::FeatureSelectionFilter &iFilter,
PcbCam::FeatureSelectionOperation iSelOp,
const QTransform &iMatrix,
bool iStepRepeat);
void clearSelection();
void clearHighlight();
void setCheckMeasList(const QVariantList &iData);
void clearPopView();
void setMousePoint(const QPointF &iPos);
void setDrawRelativeOrig(bool iY);
void setOriginalPoint(double x, double y);
QPointF originalPoint() const;
QPointF relativeOriginalPoint() const;
void setContextMenu(QMenu *iMenu);
QMenu *contextMenu() const;
void setCurrentFeatureFilter(const PcbCam::FeatureSelectionFilter &iFilter);
PcbCam::FeatureSelectionFilter currentFeatureFilter() const;
void setSnapLayers(const QStringList &iSnapLayers);
QStringList snapLayers() const;
void setSnapMode(PcbCam::SnapModes iMode);
PcbCam::SnapModes snapMode() const;
void setSnapFeatureType(PcbCam::FeatureTypes iType);
PcbCam::FeatureTypes snapFeatureType() const;
QPointF getSnapPoint(const QPoint &iCursorPos, int iSnapRange = 20, bool *oSnaped = nullptr);
void getSnapPathsInRect(const QString &iStep, const QRectF &iRange, bool iIncludeStepRepeat, const QTransform &iMatrix, QPainterPath &oSnapFeatPaths, QPolygonF &oSnapFeatPoints) const;
void setDisplayOption(PcbCam::DisplayOptions iDispOption);
PcbCam::DisplayOptions displayOption() const;
private slots:
void onPopViewClosed();
private:
void doSpacingMeasure();
void doDistMeasure();
void createPopView(const QRectF &iSourceRect, const QRect &iTargetRect);
void drawStepLayer(QPainter *painter,
const QString &iStep,
const QString &iLayer,
const QColor &iColor,
bool iStepRepeat,
const QTransform &iMatrix,
const QRectF &iSceneRect,
PcbCam::DisplayOptions iDispOption) const;
void drawStepProfile(QPainter *painter,
const QString &iStep,
const QColor &iColor,
const QTransform &iMatrix,
bool iSelected = false) const;
QPixmap render(const QTransform &iMatrix, const QSize &iSize);
QPixmap renderChkMeans(const QTransform &iMatrix, const QSize &iSize);
void showContextMenu(const QPoint &iPos);
protected:
bool event(QEvent *iEvent) override;
void paintEvent(QPaintEvent *iEvent) override;
void resizeEvent(QResizeEvent *) override;
void wheelEvent(QWheelEvent *event) override;
void contextMenuEvent(QContextMenuEvent *event) override;
protected:
const QScopedPointer<PcbCamCanvasPrivate> d_ptr;
private:
Q_DECLARE_PRIVATE(PcbCamCanvas)
Q_DISABLE_COPY(PcbCamCanvas)
};
TITAN_END_NAMESPACE
#endif // TITAN_PCBCAM_GRAPHVIEW_H
#include "popviewwindow.h"
#include <QLabel>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QToolBar>
#include <QPushButton>
#include <QCloseEvent>
#include <QGraphicsDropShadowEffect>
#include <QPainter>
#include <QApplication>
#include "canvas.h"
#include <QDebug>
TITAN_BEGIN_NAMESPACE
static QIcon coloredIcon(const QIcon &iIcon, const QColor &iColor)
{
QPixmap pixmap = iIcon.pixmap(128, 128);
if (!pixmap.isNull()){
QPainter painter(&pixmap);
painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
painter.fillRect(pixmap.rect(), iColor);
painter.end();
}
return QIcon(pixmap);
}
class PcbCamPopViewWindowPrivate
{
Q_DECLARE_PUBLIC(PcbCamPopViewWindow)
public:
explicit PcbCamPopViewWindowPrivate(PcbCamPopViewWindow *qptr) : q_ptr(qptr){}
~PcbCamPopViewWindowPrivate(){}
enum MouseRegion {
NONE = 0, UP=1, DOWN=2, LEFT, RIGHT, LEFTTOP, LEFTBOTTOM, RIGHTBOTTOM, RIGHTTOP
};
QLabel *imageLabel {nullptr};
PcbCamCanvas *canvas;
QRectF sourceRect;
bool isLeftPressDown {false};
QPoint dragPosition;
MouseRegion mouseRegion = {NONE};
int borderPadding = 4;
void region(const QPoint &cursorGlobalPoint) {
Q_Q(PcbCamPopViewWindow);
auto rect = q->rect();
auto tl = q->mapToGlobal(rect.topLeft());
auto rb = q->mapToGlobal(rect.bottomRight());
int x = cursorGlobalPoint.x();
int y = cursorGlobalPoint.y();
if(tl.x() + borderPadding >= x && tl.x() <= x && tl.y() + borderPadding >= y && tl.y() <= y) {
// 左上角
mouseRegion = LEFTTOP;
q->setCursor(QCursor(Qt::SizeFDiagCursor)); // 设置鼠标形状
} else if(x >= rb.x() - borderPadding && x <= rb.x() && y >= rb.y() - borderPadding && y <= rb.y()) {
// 右下角
mouseRegion = RIGHTBOTTOM;
q->setCursor(QCursor(Qt::SizeFDiagCursor));
} else if(x <= tl.x() + borderPadding && x >= tl.x() && y >= rb.y() - borderPadding && y <= rb.y()) {
//左下角
mouseRegion = LEFTBOTTOM;
q->setCursor(QCursor(Qt::SizeBDiagCursor));
} else if(x <= rb.x() && x >= rb.x() - borderPadding && y >= tl.y() && y <= tl.y() + borderPadding) {
// 右上角
mouseRegion = RIGHTTOP;
q->setCursor(QCursor(Qt::SizeBDiagCursor));
} else if(x <= tl.x() + borderPadding && x >= tl.x()) {
// 左边
mouseRegion = LEFT;
q->setCursor(QCursor(Qt::SizeHorCursor));
} else if( x <= rb.x() && x >= rb.x() - borderPadding) {
// 右边
mouseRegion = RIGHT;
q->setCursor(QCursor(Qt::SizeHorCursor));
}else if(y >= tl.y() && y <= tl.y() + borderPadding){
// 上边
mouseRegion = UP;
q->setCursor(QCursor(Qt::SizeVerCursor));
} else if(y <= rb.y() && y >= rb.y() - borderPadding) {
// 下边
mouseRegion = DOWN;
q->setCursor(QCursor(Qt::SizeVerCursor));
}else {
// 默认
mouseRegion = NONE;
q->setCursor(QCursor(Qt::ArrowCursor));
}
}
protected:
PcbCamPopViewWindow * const q_ptr;
};
PcbCamPopViewWindow::PcbCamPopViewWindow(const QRectF &iSourceRect, const QRect &iTargetRect, titan::PcbCamCanvas *iCanvas): QFrame(iCanvas),
d_ptr(new PcbCamPopViewWindowPrivate(this))
{
Q_D(PcbCamPopViewWindow);
this->setWindowTitle(" ");
d->canvas = iCanvas;
d->sourceRect = iSourceRect;
this->setWindowFlags(Qt::FramelessWindowHint|Qt::Tool);
this->setMouseTracking(true);
auto vlayout = new QVBoxLayout(this);
vlayout->setContentsMargins(0, 0, 0, 0);
vlayout->setSpacing(0);
auto tbframe = new QFrame(this);
tbframe->setMouseTracking(true);
tbframe->setStyleSheet(".QFrame{background-color:#2F3E4E;}");
auto tbshadow = new QGraphicsDropShadowEffect(tbframe);
tbshadow->setBlurRadius(5.0);
tbshadow->setOffset(1.0, 1.0);
tbframe->setGraphicsEffect(tbshadow);
auto tblayout = new QHBoxLayout(tbframe);
tblayout->setContentsMargins(2, 2, 2, 2);
tblayout->setSpacing(4);
vlayout->addWidget(tbframe, 0);
auto imagelayout = new QVBoxLayout;
imagelayout->setContentsMargins(2, 2, 2, 2);
imagelayout->setSpacing(0);
d->imageLabel = new QLabel(this);
d->imageLabel->setMouseTracking(true);
d->imageLabel->setMinimumSize(100, 100);
imagelayout->addWidget(d->imageLabel, 1);
vlayout->addLayout(imagelayout, 1);
QColor iconColor = Qt::white;
auto viewUpBtn = new QPushButton(coloredIcon(QIcon(":/res/icon/view_up.svg"), iconColor), "", this);
viewUpBtn->setToolTip(tr("Pan Up"));
viewUpBtn->setProperty("SS_TYPE", "DARKTOOL");
viewUpBtn->setProperty("SS_SIZE", "SMALL");
auto viewDownBtn = new QPushButton(coloredIcon(QIcon(":/res/icon/view_down.svg"), iconColor) ,"", this);
viewDownBtn->setToolTip(tr("Pan Down"));
viewDownBtn->setProperty("SS_TYPE", "DARKTOOL");
viewDownBtn->setProperty("SS_SIZE", "SMALL");
auto viewLeftBtn = new QPushButton(coloredIcon(QIcon(":/res/icon/view_left.svg"), iconColor),"", this);
viewLeftBtn->setProperty("SS_TYPE", "DARKTOOL");
viewLeftBtn->setProperty("SS_SIZE", "SMALL");
viewLeftBtn->setToolTip(tr("Pan Left"));
auto viewRightBtn = new QPushButton(coloredIcon(QIcon(":/res/icon/view_right.svg"), iconColor) ,"", this);
viewRightBtn->setToolTip(tr("Pan Down"));
viewRightBtn->setProperty("SS_TYPE", "DARKTOOL");
viewRightBtn->setProperty("SS_SIZE", "SMALL");
auto zoomInBtn = new QPushButton(coloredIcon(QIcon(":/res/icon/zoom_in.svg"), iconColor),"", this);
zoomInBtn->setToolTip(tr("Zoom In"));
zoomInBtn->setProperty("SS_TYPE", "DARKTOOL");
zoomInBtn->setProperty("SS_SIZE", "SMALL");
auto zoomOutBtn = new QPushButton(coloredIcon(QIcon(":/res/icon/zoom_out.svg"), iconColor),"", this);
zoomOutBtn->setToolTip(tr("Zoom Out"));
zoomOutBtn->setProperty("SS_TYPE", "DARKTOOL");
zoomOutBtn->setProperty("SS_SIZE", "SMALL");
auto closeBtn = new QPushButton(coloredIcon(QIcon(":/res/icon/close.svg"), iconColor), "", this);
closeBtn->setToolTip(tr("Close"));
closeBtn->setProperty("SS_TYPE", "DARKTOOL");
closeBtn->setProperty("SS_SIZE", "SMALL");
tblayout->addSpacing(2);
tblayout->addWidget(viewUpBtn, 0);
tblayout->addWidget(viewDownBtn, 0);
tblayout->addWidget(viewLeftBtn, 0);
tblayout->addWidget(viewRightBtn, 0);
tblayout->addWidget(zoomInBtn, 0);
tblayout->addWidget(zoomOutBtn, 0);
tblayout->addStretch(1);
tblayout->addWidget(closeBtn, 0);
this->adjustSize();
QSize imgsize = d->imageLabel->size();
QSize winsize = this->size();
QPoint imgpos = this->mapToGlobal(d->imageLabel->rect().topLeft());
int sx = winsize.width() - imgsize.width();
int sy = winsize.height() - imgsize.height();
this->setGeometry(QRect(iTargetRect.topLeft() - imgpos, QSize(iTargetRect.size().width() + sx, iTargetRect.size().height() + sy)));
tbframe->raise();
connect(closeBtn, &QPushButton::clicked, this, &PcbCamPopViewWindow::close);
connect(viewUpBtn, &QPushButton::clicked, this, &PcbCamPopViewWindow::onPanUpClicked);
connect(viewDownBtn, &QPushButton::clicked, this, &PcbCamPopViewWindow::onPanDownClicked);
connect(viewLeftBtn, &QPushButton::clicked, this, &PcbCamPopViewWindow::onPanLeftClicked);
connect(viewRightBtn, &QPushButton::clicked, this, &PcbCamPopViewWindow::onPanRightClicked);
connect(zoomInBtn, &QPushButton::clicked, this, &PcbCamPopViewWindow::onZoomInClicked);
connect(zoomOutBtn, &QPushButton::clicked, this, &PcbCamPopViewWindow::onZoomOutClicked);
}
PcbCamPopViewWindow::~PcbCamPopViewWindow()
{
}
void PcbCamPopViewWindow::setSourceRect(const QRectF &iSourceRect)
{
Q_D(PcbCamPopViewWindow);
d->sourceRect = iSourceRect;
}
QRectF PcbCamPopViewWindow::sourceRect() const
{
Q_D(const PcbCamPopViewWindow);
return d->sourceRect;
}
QRect PcbCamPopViewWindow::viewRect() const
{
Q_D(const PcbCamPopViewWindow);
QRect rect = d->imageLabel->rect();
rect.moveTo(d->imageLabel->mapToGlobal(rect.topLeft()));
return rect;
}
void PcbCamPopViewWindow::refresh()
{
Q_D(PcbCamPopViewWindow);
QRectF sceneRect = d->sourceRect;
QRect imgRect(QPoint(0, 0), d->imageLabel->size());
auto disprect = d->canvas->orientMatrix().mapRect(sceneRect.normalized()).normalized();
qreal scale = qMin(double(imgRect.width())/disprect.width(),
double(imgRect.height())/disprect.height());
QTransform mat = d->canvas->orientMatrix() * QTransform(scale, 0, 0, -scale, 0, 0);
disprect = mat.mapRect(sceneRect.normalized());
mat = mat * QTransform(1, 0, 0, 1, imgRect.center().x() - disprect.center().x(), imgRect.center().y() - disprect.center().y());
QPixmap pix = d->canvas->render(mat, d->imageLabel->rect().size());
d->imageLabel->setPixmap(pix);
}
void PcbCamPopViewWindow::resizeEvent(QResizeEvent *event)
{
emit geometryChanged();
this->refresh();
}
void PcbCamPopViewWindow::closeEvent(QCloseEvent *event)
{
emit aboutToClose();
QWidget::closeEvent(event);
}
void PcbCamPopViewWindow::mouseReleaseEvent(QMouseEvent *event)
{
Q_D(PcbCamPopViewWindow);
QApplication::restoreOverrideCursor();
event->ignore();
d->isLeftPressDown = false;
}
void PcbCamPopViewWindow::mousePressEvent(QMouseEvent *event)
{
Q_D(PcbCamPopViewWindow);
switch(event->button()) {
case Qt::LeftButton:
d->isLeftPressDown = true;
if(d->mouseRegion != PcbCamPopViewWindowPrivate::NONE) {
this->mouseGrabber();
} else {
d->dragPosition = event->globalPos() - this->frameGeometry().topLeft();
}
break;
default:
QFrame::mousePressEvent(event);
}
}
void PcbCamPopViewWindow::mouseMoveEvent(QMouseEvent *event)
{
Q_D(PcbCamPopViewWindow);
QPoint gloPoint = event->globalPos();
QRect rect = this->rect();
QPoint tl = mapToGlobal(rect.topLeft());
QPoint rb = mapToGlobal(rect.bottomRight());
if(!d->isLeftPressDown) {
d->region(gloPoint);
} else {
if(d->mouseRegion != PcbCamPopViewWindowPrivate::NONE) {
QRect rMove(tl, rb);
switch(d->mouseRegion) {
case PcbCamPopViewWindowPrivate::LEFT:
if(rb.x() - gloPoint.x() <= this->minimumWidth())
rMove.setX(tl.x());
else
rMove.setX(gloPoint.x());
break;
case PcbCamPopViewWindowPrivate::RIGHT:
rMove.setWidth(gloPoint.x() - tl.x());
break;
case PcbCamPopViewWindowPrivate::UP:
if(rb.y() - gloPoint.y() <= this->minimumHeight())
rMove.setY(tl.y());
else
rMove.setY(gloPoint.y());
break;
case PcbCamPopViewWindowPrivate::DOWN:
rMove.setHeight(gloPoint.y() - tl.y());
break;
case PcbCamPopViewWindowPrivate::LEFTTOP:
if(rb.x() - gloPoint.x() <= this->minimumWidth())
rMove.setX(tl.x());
else
rMove.setX(gloPoint.x());
if(rb.y() - gloPoint.y() <= this->minimumHeight())
rMove.setY(tl.y());
else
rMove.setY(gloPoint.y());
break;
case PcbCamPopViewWindowPrivate::RIGHTTOP:
rMove.setWidth(gloPoint.x() - tl.x());
rMove.setY(gloPoint.y());
break;
case PcbCamPopViewWindowPrivate::LEFTBOTTOM:
rMove.setX(gloPoint.x());
rMove.setHeight(gloPoint.y() - tl.y());
break;
case PcbCamPopViewWindowPrivate::RIGHTBOTTOM:
rMove.setWidth(gloPoint.x() - tl.x());
rMove.setHeight(gloPoint.y() - tl.y());
break;
default:
break;
}
this->setGeometry(rMove);
} else {
move(event->globalPos() - d->dragPosition);
event->accept();
}
}
QFrame::mouseMoveEvent(event);
}
void PcbCamPopViewWindow::moveEvent(QMoveEvent *event)
{
emit geometryChanged();
QWidget::moveEvent(event);
}
void PcbCamPopViewWindow::onPanUpClicked()
{
Q_D(PcbCamPopViewWindow);
d->sourceRect.translate(0, (double(d->sourceRect.height()) * 0.1));
emit geometryChanged();
this->refresh();
}
void PcbCamPopViewWindow::onPanDownClicked()
{
Q_D(PcbCamPopViewWindow);
d->sourceRect.translate(0, (-double(d->sourceRect.height()) * 0.1));
emit geometryChanged();
this->refresh();
}
void PcbCamPopViewWindow::onPanLeftClicked()
{
Q_D(PcbCamPopViewWindow);
d->sourceRect.translate((-double(d->sourceRect.width()) * 0.1), 0);
emit geometryChanged();
this->refresh();
}
void PcbCamPopViewWindow::onPanRightClicked()
{
Q_D(PcbCamPopViewWindow);
d->sourceRect.translate((double(d->sourceRect.width()) * 0.1), 0);
emit geometryChanged();
this->refresh();
}
void PcbCamPopViewWindow::onZoomInClicked()
{
Q_D(PcbCamPopViewWindow);
QPointF pc = d->sourceRect.center();
qreal scale = 1.0/1.2;
qreal w = double(d->sourceRect.width()) * scale;
qreal h = double(d->sourceRect.height()) * scale;
d->sourceRect = QRectF(pc.x() - w/2.0, pc.y()-h/2.0, w, h);
emit geometryChanged();
this->refresh();
}
void PcbCamPopViewWindow::onZoomOutClicked()
{
Q_D(PcbCamPopViewWindow);
QPointF pc = d->sourceRect.center();
qreal scale = 1.2;
qreal w = double(d->sourceRect.width()) * scale;
qreal h = double(d->sourceRect.height()) * scale;
d->sourceRect = QRectF(pc.x() - w/2.0, pc.y()-h/2.0, w, h);
emit geometryChanged();
this->refresh();
}
TITAN_END_NAMESPACE
#ifndef TITAN_PCBCAM_POPVIEWWINDOW_H
#define TITAN_PCBCAM_POPVIEWWINDOW_H
#include "../titanpcbcamglobal.h"
#include <QFrame>
TITAN_BEGIN_NAMESPACE
class PcbCamCanvas;
class PcbCamPopViewWindowPrivate;
class PcbCamPopViewWindow : public QFrame
{
Q_OBJECT
friend class PcbCamCanvas;
public:
explicit PcbCamPopViewWindow(const QRectF &iSourceRect, const QRect &iTargetRect, titan::PcbCamCanvas *iCanvas);
~PcbCamPopViewWindow();
void setSourceRect(const QRectF &iSourceRect);
QRectF sourceRect() const;
QRect viewRect() const;
public slots:
void refresh();
signals:
void aboutToClose();
void geometryChanged();
protected:
void resizeEvent(QResizeEvent *event) override;
void closeEvent(QCloseEvent *event) override;
void moveEvent(QMoveEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
private slots:
void onPanUpClicked();
void onPanDownClicked();
void onPanLeftClicked();
void onPanRightClicked();
void onZoomInClicked();
void onZoomOutClicked();
private:
void resizeWidget(const QPoint &globalMousePos, int direction);
protected:
const QScopedPointer<PcbCamPopViewWindowPrivate> d_ptr;
private:
Q_DECLARE_PRIVATE(PcbCamPopViewWindow)
Q_DISABLE_COPY(PcbCamPopViewWindow)
};
TITAN_END_NAMESPACE
#endif // TITAN_PCBCAM_POPVIEWWINDOW_H
#############################################################################
##
## Copyright (C) 2019 The Qt Company Ltd.
## Contact: http://www.qt.io/licensing/
##
## This file is part of the Qt for Python examples of the Qt Toolkit.
##
## $QT_BEGIN_LICENSE:BSD$
## You may use this file under the terms of the BSD license as follows:
##
## "Redistribution and use in source and binary forms, with or without
## modification, are permitted provided that the following conditions are
## met:
## * Redistributions of source code must retain the above copyright
## notice, this list of conditions and the following disclaimer.
## * Redistributions in binary form must reproduce the above copyright
## notice, this list of conditions and the following disclaimer in
## the documentation and/or other materials provided with the
## distribution.
## * Neither the name of The Qt Company Ltd nor the names of its
## contributors may be used to endorse or promote products derived
## from this software without specific prior written permission.
##
##
## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
##
## $QT_END_LICENSE$
##
#############################################################################
import os, glob, re, sys
from distutils import sysconfig
generic_error = (' Did you forget to activate your virtualenv? Or perhaps'
' you forgot to build / install PySide2 into your currently active Python'
' environment?')
pyside2_error = 'Unable to locate PySide2.' + generic_error
shiboken2_module_error = 'Unable to locate shiboken2-module.' + generic_error
shiboken2_generator_error = 'Unable to locate shiboken2-generator.' + generic_error
pyside2_libs_error = 'Unable to locate the PySide2 shared libraries.' + generic_error
python_link_error = 'Unable to locate the Python library for linking.'
python_include_error = 'Unable to locate the Python include headers directory.'
options = []
# option, function, error, description
options.append(("--shiboken2-module-path",
lambda: find_shiboken2_module(),
shiboken2_module_error,
"Print shiboken2 module location"))
options.append(("--shiboken2-generator-path",
lambda: find_shiboken2_generator(),
shiboken2_generator_error,
"Print shiboken2 generator location"))
options.append(("--pyside2-path", lambda: find_pyside2(), pyside2_error,
"Print PySide2 location"))
options.append(("--python-include-path",
lambda: get_python_include_path(),
python_include_error,
"Print Python include path"))
options.append(("--shiboken2-generator-include-path",
lambda: get_package_include_path(Package.shiboken2_generator),
pyside2_error,
"Print shiboken2 generator include paths"))
options.append(("--pyside2-include-path",
lambda: get_package_include_path(Package.pyside2),
pyside2_error,
"Print PySide2 include paths"))
options.append(("--python-link-flags-qmake", lambda: python_link_flags_qmake(), python_link_error,
"Print python link flags for qmake"))
options.append(("--python-link-flags-cmake", lambda: python_link_flags_cmake(), python_link_error,
"Print python link flags for cmake"))
options.append(("--shiboken2-module-qmake-lflags",
lambda: get_package_qmake_lflags(Package.shiboken2_module), pyside2_error,
"Print shiboken2 shared library link flags for qmake"))
options.append(("--pyside2-qmake-lflags",
lambda: get_package_qmake_lflags(Package.pyside2), pyside2_error,
"Print PySide2 shared library link flags for qmake"))
options.append(("--shiboken2-module-shared-libraries-qmake",
lambda: get_shared_libraries_qmake(Package.shiboken2_module), pyside2_libs_error,
"Print paths of shiboken2 shared libraries (.so's, .dylib's, .dll's) for qmake"))
options.append(("--shiboken2-module-shared-libraries-cmake",
lambda: get_shared_libraries_cmake(Package.shiboken2_module), pyside2_libs_error,
"Print paths of shiboken2 shared libraries (.so's, .dylib's, .dll's) for cmake"))
options.append(("--pyside2-shared-libraries-qmake",
lambda: get_shared_libraries_qmake(Package.pyside2), pyside2_libs_error,
"Print paths of PySide2 shared libraries (.so's, .dylib's, .dll's) for qmake"))
options.append(("--pyside2-shared-libraries-cmake",
lambda: get_shared_libraries_cmake(Package.pyside2), pyside2_libs_error,
"Print paths of PySide2 shared libraries (.so's, .dylib's, .dll's) for cmake"))
options_usage = ''
for i, (flag, _, _, description) in enumerate(options):
options_usage += ' {:<45} {}'.format(flag, description)
if i < len(options) - 1:
options_usage += '\n'
usage = """
Utility to determine include/link options of shiboken2/PySide2 and Python for qmake/CMake projects
that would like to embed or build custom shiboken2/PySide2 bindings.
Usage: pyside2_config.py [option]
Options:
{}
-a Print all options and their values
--help/-h Print this help
""".format(options_usage)
option = sys.argv[1] if len(sys.argv) == 2 else '-a'
if option == '-h' or option == '--help':
print(usage)
sys.exit(0)
class Package(object):
shiboken2_module = 1
shiboken2_generator = 2
pyside2 = 3
def clean_path(path):
return path if sys.platform != 'win32' else path.replace('\\', '/')
def shared_library_suffix():
if sys.platform == 'win32':
return 'lib'
elif sys.platform == 'darwin':
return 'dylib'
# Linux
else:
return 'so.*'
def import_suffixes():
if (sys.version_info >= (3, 4)):
import importlib.machinery
return importlib.machinery.EXTENSION_SUFFIXES
else:
import imp
result = []
for t in imp.get_suffixes():
result.append(t[0])
return result
def is_debug():
debug_suffix = '_d.pyd' if sys.platform == 'win32' else '_d.so'
return any([s.endswith(debug_suffix) for s in import_suffixes()])
def shared_library_glob_pattern():
glob = '*.' + shared_library_suffix()
return glob if sys.platform == 'win32' else 'lib' + glob
def filter_shared_libraries(libs_list):
def predicate(lib_name):
basename = os.path.basename(lib_name)
if 'shiboken' in basename or 'pyside2' in basename:
return True
return False
result = [lib for lib in libs_list if predicate(lib)]
return result
# Return qmake link option for a library file name
def link_option(lib):
# On Linux:
# Since we cannot include symlinks with wheel packages
# we are using an absolute path for the libpyside and libshiboken
# libraries when compiling the project
baseName = os.path.basename(lib)
link = ' -l'
if sys.platform in ['linux', 'linux2']: # Linux: 'libfoo.so' -> '/absolute/path/libfoo.so'
link = lib
elif sys.platform in ['darwin']: # Darwin: 'libfoo.so' -> '-lfoo'
link += os.path.splitext(baseName[3:])[0]
else: # Windows: 'libfoo.dll' -> 'libfoo.dll'
link += os.path.splitext(baseName)[0]
return link
# Locate PySide2 via sys.path package path.
def find_pyside2():
return find_package_path("PySide2")
def find_shiboken2_module():
return find_package_path("shiboken2")
def find_shiboken2_generator():
return find_package_path("shiboken2_generator")
def find_package(which_package):
if which_package == Package.shiboken2_module:
return find_shiboken2_module()
if which_package == Package.shiboken2_generator:
return find_shiboken2_generator()
if which_package == Package.pyside2:
return find_pyside2()
return None
def find_package_path(dir_name):
for p in sys.path:
if 'site-' in p:
package = os.path.join(p, dir_name)
if os.path.exists(package):
return clean_path(os.path.realpath(package))
return None
# Return version as "3.5"
def python_version():
return str(sys.version_info[0]) + '.' + str(sys.version_info[1])
def get_python_include_path():
return sysconfig.get_python_inc()
def python_link_flags_qmake():
flags = python_link_data()
if sys.platform == 'win32':
libdir = flags['libdir']
# This will add the "~1" shortcut for directories that
# contain white spaces
# e.g.: "Program Files" to "Progra~1"
for d in libdir.split("\\"):
if " " in d:
libdir = libdir.replace(d, d.split(" ")[0][:-1]+"~1")
return '-L{} -l{}'.format(libdir, flags['lib'])
elif sys.platform == 'darwin':
return '-L{} -l{}'.format(flags['libdir'], flags['lib'])
else:
# Linux and anything else
return '-L{} -l{}'.format(flags['libdir'], flags['lib'])
def python_link_flags_cmake():
flags = python_link_data()
libdir = flags['libdir']
lib = re.sub(r'.dll$', '.lib', flags['lib'])
return '{};{}'.format(libdir, lib)
def python_link_data():
# @TODO Fix to work with static builds of Python
libdir = sysconfig.get_config_var('LIBDIR')
if libdir is None:
libdir = os.path.abspath(os.path.join(
sysconfig.get_config_var('LIBDEST'), "..", "libs"))
version = python_version()
version_no_dots = version.replace('.', '')
flags = {}
flags['libdir'] = libdir
if sys.platform == 'win32':
suffix = '_d' if is_debug() else ''
flags['lib'] = 'python{}{}'.format(version_no_dots, suffix)
elif sys.platform == 'darwin':
flags['lib'] = 'python{}'.format(version)
# Linux and anything else
else:
if sys.version_info[0] < 3:
suffix = '_d' if is_debug() else ''
flags['lib'] = 'python{}{}'.format(version, suffix)
else:
flags['lib'] = 'python{}{}'.format(version, sys.abiflags)
return flags
def get_package_include_path(which_package):
package_path = find_package(which_package)
if package_path is None:
return None
includes = "{0}/include".format(package_path)
return includes
def get_package_qmake_lflags(which_package):
package_path = find_package(which_package)
if package_path is None:
return None
link = "-L{}".format(package_path)
glob_result = glob.glob(os.path.join(package_path, shared_library_glob_pattern()))
for lib in filter_shared_libraries(glob_result):
link += ' '
link += link_option(lib)
return link
def get_shared_libraries_data(which_package):
package_path = find_package(which_package)
if package_path is None:
return None
glob_result = glob.glob(os.path.join(package_path, shared_library_glob_pattern()))
filtered_libs = filter_shared_libraries(glob_result)
libs = []
if sys.platform == 'win32':
for lib in filtered_libs:
libs.append(os.path.realpath(lib))
else:
for lib in filtered_libs:
libs.append(lib)
return libs
def get_shared_libraries_qmake(which_package):
libs = get_shared_libraries_data(which_package)
if libs is None:
return None
if sys.platform == 'win32':
if not libs:
return ''
dlls = ''
for lib in libs:
dll = os.path.splitext(lib)[0] + '.dll'
dlls += dll + ' '
return dlls
else:
libs_string = ''
for lib in libs:
libs_string += lib + ' '
return libs_string
def get_shared_libraries_cmake(which_package):
libs = get_shared_libraries_data(which_package)
result = ';'.join(libs)
return result
print_all = option == "-a"
for argument, handler, error, _ in options:
if option == argument or print_all:
handler_result = handler()
if handler_result is None:
sys.exit(error)
line = handler_result
if print_all:
line = "{:<40}: ".format(argument) + line
print(line)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment