init
This commit is contained in:
BIN
lib/R_detection/RMS_Dll.dll
Normal file
BIN
lib/R_detection/RMS_Dll.dll
Normal file
Binary file not shown.
12
lib/R_detection/RMS_Dll_global.h
Normal file
12
lib/R_detection/RMS_Dll_global.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef RMS_DLL_GLOBAL_H
|
||||
#define RMS_DLL_GLOBAL_H
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#if defined(RMS_DLL_LIBRARY)
|
||||
# define RMS_DLL_EXPORT Q_DECL_EXPORT
|
||||
#else
|
||||
# define RMS_DLL_EXPORT Q_DECL_IMPORT
|
||||
#endif
|
||||
|
||||
#endif // RMS_DLL_GLOBAL_H
|
||||
75
lib/R_detection/rms_dll.h
Normal file
75
lib/R_detection/rms_dll.h
Normal file
@@ -0,0 +1,75 @@
|
||||
#ifndef RMS_DLL_H
|
||||
#define RMS_DLL_H
|
||||
#include"qtcpserver.h"
|
||||
#include"qtcpsocket.h"
|
||||
#include "RMS_Dll_global.h"
|
||||
#include <QImage>
|
||||
|
||||
class RMS_DLL_EXPORT RMS_Dll
|
||||
{
|
||||
public:
|
||||
RMS_Dll();
|
||||
int add(int a,int b);
|
||||
|
||||
QVector<double> x;//存储电阻率值
|
||||
|
||||
int isshow = 0;
|
||||
QTcpSocket* _Socket;
|
||||
|
||||
//连接探头
|
||||
bool RMS_Connect(QString IP, quint16 Port);
|
||||
|
||||
//取消连接
|
||||
void RMS_Disconnect();
|
||||
|
||||
//RMS_Read_Empty()调用即空采
|
||||
bool RMS_Read_Empty();
|
||||
|
||||
//正常采集,传入x坐标,y坐标
|
||||
bool RMS_Read(int cx,int cy);
|
||||
double RMS_Read_Single();
|
||||
|
||||
//所有点采集完成后,获取四个值
|
||||
void RMS_ACQ(double *max,double *min,double *med,double *mode);//返回最大值,最小值,中位数,众数
|
||||
|
||||
//传入mode、Pm和Po,获取Pt和Ps
|
||||
void RMS_P(double mode,double *Pt,double *Ps,double Pm,double Po);
|
||||
|
||||
//传入晶锭尺寸size,40、60、80,分别为四英寸、六英寸和八英寸,返回QImage
|
||||
QImage RMS_Image(int size);
|
||||
|
||||
|
||||
//之前tcp传输的点,这回直接用就行
|
||||
QString StrPlotSixInch = "(0,-60)(-30,-50)(-20,-50)(-10,-50)(0,-50)(10,-50)(20,-50)(30,-50)(-40,-40)(-30,-40)(-20,-40)(-10,-40)(0,-40)(10,-40)"
|
||||
"(20,-40)(30,-40)(40,-40)(-50,-30)(-40,-30)(-30,-30)(-20,-30)(-10,-30)(0,-30)(10,-30)(20,-30)(30,-30)(40,-30)(50,-30)"
|
||||
"(-50,-20)(-40,-20)(-30,-20)(-20,-20)(-10,-20)(0,-20)(10,-20)(20,-20)(30,-20)(40,-20)(50,-20)(-50,-10)(-40,-10)(-30,-10)"
|
||||
"(-20,-10)(-10,-10)(0,-10)(10,-10)(20,-10)(30,-10)(40,-10)(50,-10)(-60,0)(-50,0)(-40,0)(-30,0)(-20,0)(-10,0)(0,0)(10,0)"
|
||||
"(20,0)(30,0)(40,0)(50,0)(60,0)(-50,10)(-40,10)(-30,10)(-20,10)(-10,10)(0,10)(10,10)(20,10)(30,10)(40,10)(50,10)(-50,20)"
|
||||
"(-40,20)(-30,20)(-20,20)(-10,20)(0,20)(10,20)(20,20)(30,20)(40,20)(50,20)(-50,30)(-40,30)(-30,30)(-20,30)(-10,30)(0,30)"
|
||||
"(10,30)(20,30)(30,30)(40,30)(50,30)(-40,40)(-30,40)(-20,40)(-10,40)(0,40)(10,40)(20,40)(30,40)(40,40)(-30,50)(-20,50)"
|
||||
"(-10,50)(0,50)(10,50)(20,50)(30,50)(0,60)";
|
||||
QString StrPlotEightInch = "(-44,-72)(-30,-72)(-16,-72)(-2,-72)(12,-72)(26,-72)(40,-72)(-58,-58)"
|
||||
"(-44,-58)(-30,-58)(-16,-58)(-2,-58)(12,-58)(26,-58)(40,-58)(54,-58)"
|
||||
"(-72,-44)(-58,-44)(-44,-44)(-30,-44)(-16,-44)(-2,-44)(12,-44)(26,-44)"
|
||||
"(40,-44)(54,-44)(68,-44)(-72,-30)(-58,-30)(-44,-30)(-30,-30)(-16,-30)"
|
||||
"(-2,-30)(12,-30)(26,-30)(40,-30)(54,-30)(68,-30)(-72,-16)(-58,-16)"
|
||||
"(-44,-16)(-30,-16)(-16,-16)(-2,-16)(12,-16)(26,-16)(40,-16)(54,-16)"
|
||||
"(68,-16)(82,-16)(-72,-2)(-58,-2)(-44,-2)(-30,-2)(-16,-2)(-2,-2)"
|
||||
"(12,-2)(26,-2)(40,-2)(54,-2)(68,-2)(82,-2)(-72,12)(-58,12)(-44,12)"
|
||||
"(-30,12)(-16,12)(-2,12)(12,12)(26,12)(40,12)(54,12)(68,12)(82,12)"
|
||||
"(-72,26)(-58,26)(-44,26)(-30,26)(-16,26)(-2,26)(12,26)(26,26)(40,26)"
|
||||
"(54,26)(68,26)(-72,40)(-58,40)(-44,40)(-30,40)(-16,40)(-2,40)(12,40)"
|
||||
"(26,40)(40,40)(54,40)(68,40)(-58,54)(-44,54)(-30,54)(-16,54)(-2,54)"
|
||||
"(12,54)(26,54)(40,54)(54,54)(-44,68)(-30,68)(-16,68)(-2,68)(12,68)"
|
||||
"(26,68)(40,68)(-16,82)(-2,82)(12,82)";
|
||||
QString StrPlotFourInch = "(-2,-44)(-30,-30)(-16,-30)(-2,-30)(12,-30)(26,-30)(-30,-16)(-16,-16)"
|
||||
"(-2,-16)(12,-16)(26,-16)(40,-16)(-44,-2)(-30,-2)(-16,-2)(-2,-2)(12,-2)"
|
||||
"(26,-2)(40,-2)(-30,12)(-16,12)(-2,12)(12,12)(26,12)(40,12)(-30,26)(-16,26)"
|
||||
"(-2,26)(12,26)(26,26)(-16,40)(-2,40)(12,40)";
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // RMS_DLL_H
|
||||
BIN
lib/acs/ACSCL_x64.LIB
Normal file
BIN
lib/acs/ACSCL_x64.LIB
Normal file
Binary file not shown.
BIN
lib/acs/ACSCL_x86.LIB
Normal file
BIN
lib/acs/ACSCL_x86.LIB
Normal file
Binary file not shown.
326
lib/actions/rs_actioninterface.cpp
Normal file
326
lib/actions/rs_actioninterface.cpp
Normal file
@@ -0,0 +1,326 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
#include <QKeyEvent>
|
||||
#include "rs_actioninterface.h"
|
||||
#include "rs_graphicview.h"
|
||||
#include "rs_commands.h"
|
||||
#include "rs_dialogfactory.h"
|
||||
#include "rs_coordinateevent.h"
|
||||
#include "rs_debug.h"
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* Sets the entity container on which the action class inherited
|
||||
* from this interface operates.
|
||||
*
|
||||
* @param name Action name. This can be used internally for
|
||||
* debugging mainly.
|
||||
* @param container Entity container this action operates on.
|
||||
* @param graphicView Graphic view instance this action operates on.
|
||||
* Please note that an action belongs to this
|
||||
* view.
|
||||
* @param cursor Default mouse cursor for this action. If the action
|
||||
* is suspended and resumed again the cursor will always
|
||||
* be reset to the one given here.
|
||||
*/
|
||||
RS_ActionInterface::RS_ActionInterface(const char* name,
|
||||
RS_EntityContainer& container,
|
||||
RS_GraphicView& graphicView) :
|
||||
RS_Snapper(container, graphicView) {
|
||||
|
||||
RS_DEBUG->print("RS_ActionInterface::RS_ActionInterface: Setting up action: \"%s\"", name);
|
||||
|
||||
this->name = name;
|
||||
status = 0;
|
||||
finished = false;
|
||||
//triggerOnResume = false;
|
||||
|
||||
// graphic provides a pointer to the graphic if the
|
||||
// entity container is a graphic (i.e. can also hold
|
||||
// layers).
|
||||
graphic = container.getGraphic();
|
||||
|
||||
// document pointer will be used for undo / redo
|
||||
document = container.getDocument();
|
||||
|
||||
//this->cursor = cursor;
|
||||
//setSnapMode(graphicView.getDefaultSnapMode());
|
||||
actionType=RS2::ActionNone;
|
||||
|
||||
RS_DEBUG->print("RS_ActionInterface::RS_ActionInterface: Setting up action: \"%s\": OK", name);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Must be implemented to return the ID of this action.
|
||||
*
|
||||
* @todo no default implementation
|
||||
*/
|
||||
RS2::ActionType RS_ActionInterface::rtti() const{
|
||||
return actionType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return name of this action
|
||||
*/
|
||||
QString RS_ActionInterface::getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
void RS_ActionInterface::setName(const char* _name) {
|
||||
this->name=_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to initiate an action. This funtcion is often
|
||||
* overwritten by the implementing action.
|
||||
*
|
||||
* @param status The status on which to initiate this action.
|
||||
* default is 0 to begin the action.
|
||||
*/
|
||||
void RS_ActionInterface::init(int status)
|
||||
{
|
||||
setStatus(status);
|
||||
if (status>=0) {
|
||||
RS_Snapper::init();
|
||||
updateMouseButtonHints();
|
||||
updateMouseCursor();
|
||||
}else{
|
||||
//delete snapper when finished, bug#3416878
|
||||
deleteSnapper();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Called when the mouse moves and this is the current action.
|
||||
* This function can be overwritten by the implementing action.
|
||||
* The default implementation keeps track of the mouse position.
|
||||
*/
|
||||
void RS_ActionInterface::mouseMoveEvent(QMouseEvent*) {}
|
||||
|
||||
/**
|
||||
* Called when the left mouse button is pressed and this is the
|
||||
* current action.
|
||||
* This function can be overwritten by the implementing action.
|
||||
* The default implementation does nothing.
|
||||
*/
|
||||
void RS_ActionInterface::mousePressEvent(QMouseEvent*) {}
|
||||
|
||||
/**
|
||||
* Called when the left mouse button is released and this is
|
||||
* the current action.
|
||||
* This function can be overwritten by the implementing action.
|
||||
* The default implementation does nothing.
|
||||
*/
|
||||
void RS_ActionInterface::mouseReleaseEvent(QMouseEvent*) {}
|
||||
|
||||
/**
|
||||
* Called when a key is pressed and this is the current action.
|
||||
* This function can be overwritten by the implementing action.
|
||||
* The default implementation does nothing.
|
||||
*/
|
||||
void RS_ActionInterface::keyPressEvent(QKeyEvent* e) {
|
||||
e->ignore();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a key is released and this is the current action.
|
||||
* This function can be overwritten by the implementing action.
|
||||
* The default implementation does nothing.
|
||||
*/
|
||||
void RS_ActionInterface::keyReleaseEvent(QKeyEvent* e) {
|
||||
e->ignore();
|
||||
}
|
||||
|
||||
/**
|
||||
* Coordinate event. Triggered usually from a command line.
|
||||
* This function can be overwritten by the implementing action.
|
||||
* The default implementation does nothing.
|
||||
*/
|
||||
void RS_ActionInterface::coordinateEvent(RS_CoordinateEvent*) {}
|
||||
|
||||
/**
|
||||
* Called when a command from the command line is launched.
|
||||
* and this is the current action.
|
||||
* This function can be overwritten by the implementing action.
|
||||
* The default implementation does nothing.
|
||||
*/
|
||||
void RS_ActionInterface::commandEvent(RS_CommandEvent*) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Must be implemented to return the currently available commands
|
||||
* for the command line.
|
||||
*/
|
||||
QStringList RS_ActionInterface::getAvailableCommands() {
|
||||
return QStringList{};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current status (progress) of this action.
|
||||
* The default implementation sets the class variable 'status' to the
|
||||
* given value and finishes the action if 'status' is negative.
|
||||
*
|
||||
* @param status Status number. It's up to the action implementor
|
||||
* what the action uses the status for. However, a
|
||||
* negative status number finishes the action. Usually
|
||||
* the status of an action increases for every step
|
||||
* of progress and decreases when the user goes one
|
||||
* step back (i.e. presses the right mouse button).
|
||||
*/
|
||||
void RS_ActionInterface::setStatus(int status) {
|
||||
this->status = status;
|
||||
updateMouseButtonHints();
|
||||
updateMouseCursor();
|
||||
if(status<0) finish();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Current status of this action.
|
||||
*/
|
||||
int RS_ActionInterface::getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers this action. This should be called after all
|
||||
* data needed for this action was collected / set.
|
||||
* The default implementation does nothing.
|
||||
*/
|
||||
void RS_ActionInterface::trigger() {}
|
||||
|
||||
/**
|
||||
* Should be overwritten to update the mouse button hints
|
||||
* wherever they might needed.
|
||||
*/
|
||||
void RS_ActionInterface::updateMouseButtonHints() {}
|
||||
|
||||
/**
|
||||
* Should be overwritten to set the mouse cursor for this action.
|
||||
*/
|
||||
void RS_ActionInterface::updateMouseCursor() {}
|
||||
|
||||
/**
|
||||
* @return true, if the action is finished and can be deleted.
|
||||
*/
|
||||
bool RS_ActionInterface::isFinished() {
|
||||
return finished;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Forces a termination of the action without any cleanup.
|
||||
*/
|
||||
void RS_ActionInterface::setFinished() {
|
||||
status = -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finishes this action.
|
||||
*/
|
||||
void RS_ActionInterface::finish(bool /*updateTB*/)
|
||||
{
|
||||
RS_DEBUG->print("RS_ActionInterface::finish");
|
||||
//refuse to quit the default action
|
||||
if(rtti() != RS2::ActionDefault) {
|
||||
status = -1;
|
||||
finished = true;
|
||||
hideOptions();
|
||||
RS_Snapper::finish();
|
||||
}
|
||||
RS_DEBUG->print("RS_ActionInterface::finish: OK");
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the event handler to give this action a chance to
|
||||
* communicate with its predecessor.
|
||||
*/
|
||||
void RS_ActionInterface::setPredecessor(RS_ActionInterface* pre) {
|
||||
predecessor = pre;
|
||||
}
|
||||
|
||||
/**
|
||||
* Suspends this action while another action takes place.
|
||||
*/
|
||||
void RS_ActionInterface::suspend() {
|
||||
RS_Snapper::suspend();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resumes an action after it was suspended.
|
||||
*/
|
||||
void RS_ActionInterface::resume() {
|
||||
updateMouseCursor();
|
||||
updateMouseButtonHints();
|
||||
RS_Snapper::resume();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides the tool options. Default implementation does nothing.
|
||||
*/
|
||||
void RS_ActionInterface::hideOptions() {
|
||||
RS_Snapper::hideOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the tool options. Default implementation does nothing.
|
||||
*/
|
||||
void RS_ActionInterface::showOptions() {
|
||||
RS_Snapper::showOptions();
|
||||
}
|
||||
|
||||
void RS_ActionInterface::setActionType(RS2::ActionType actionType){
|
||||
this->actionType=actionType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls checkCommand() from the RS_COMMANDS module.
|
||||
*/
|
||||
bool RS_ActionInterface::checkCommand(const QString& cmd, const QString& str,
|
||||
RS2::ActionType action) {
|
||||
return RS_COMMANDS->checkCommand(cmd, str, action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls command() from the RS_COMMANDS module.
|
||||
*/
|
||||
QString RS_ActionInterface::command(const QString& cmd) {
|
||||
return RS_COMMANDS->command(cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls msgAvailableCommands() from the RS_COMMANDS module.
|
||||
*/
|
||||
QString RS_ActionInterface::msgAvailableCommands() {
|
||||
return RS_COMMANDS->msgAvailableCommands();
|
||||
}
|
||||
|
||||
161
lib/actions/rs_actioninterface.h
Normal file
161
lib/actions/rs_actioninterface.h
Normal file
@@ -0,0 +1,161 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_ACTIONINTERFACE_H
|
||||
#define RS_ACTIONINTERFACE_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "rs_snapper.h"
|
||||
|
||||
class QKeyEvent;
|
||||
class RS_CommandEvent;
|
||||
class RS_CoordinateEvent;
|
||||
class RS_Graphic;
|
||||
class RS_Document;
|
||||
class QAction;
|
||||
|
||||
/**
|
||||
* This is the interface that must be implemented for all
|
||||
* action classes. Action classes handle actions such
|
||||
* as drawing lines, moving entities or zooming in.
|
||||
*
|
||||
* Inherited from QObject for Qt translation features.
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_ActionInterface : public QObject, public RS_Snapper {
|
||||
Q_OBJECT
|
||||
public:
|
||||
RS_ActionInterface(const char* name,
|
||||
RS_EntityContainer& container,
|
||||
RS_GraphicView& graphicView);
|
||||
virtual ~RS_ActionInterface() = default;
|
||||
|
||||
virtual RS2::ActionType rtti() const;
|
||||
|
||||
void setName(const char* _name);
|
||||
QString getName();
|
||||
|
||||
virtual void init(int status=0);
|
||||
virtual void mouseMoveEvent(QMouseEvent*);
|
||||
virtual void mousePressEvent(QMouseEvent*);
|
||||
|
||||
virtual void mouseReleaseEvent(QMouseEvent*);
|
||||
virtual void keyPressEvent(QKeyEvent* e);
|
||||
virtual void keyReleaseEvent(QKeyEvent* e);
|
||||
virtual void coordinateEvent(RS_CoordinateEvent*);
|
||||
virtual void commandEvent(RS_CommandEvent*);
|
||||
virtual QStringList getAvailableCommands();
|
||||
virtual void setStatus(int status);
|
||||
virtual int getStatus();
|
||||
virtual void trigger();
|
||||
virtual void updateMouseButtonHints();
|
||||
virtual void updateMouseCursor();
|
||||
virtual bool isFinished();
|
||||
virtual void setFinished();
|
||||
virtual void finish(bool updateTB = true );
|
||||
virtual void setPredecessor(RS_ActionInterface* pre);
|
||||
virtual void suspend();
|
||||
virtual void resume();
|
||||
virtual void hideOptions();
|
||||
virtual void showOptions();
|
||||
virtual void setActionType(RS2::ActionType actionType);
|
||||
bool checkCommand(const QString& cmd, const QString& str,
|
||||
RS2::ActionType action=RS2::ActionNone);
|
||||
QString command(const QString& cmd);
|
||||
QString msgAvailableCommands();
|
||||
|
||||
private:
|
||||
/**
|
||||
* Current status of the action. After an action has
|
||||
* been created the action status is set to 0. Actions
|
||||
* that are terminated have a stats of -1. Other status
|
||||
* numbers can be used to describe the stage this action
|
||||
* is in. E.g. a window zoom consists of selecting the
|
||||
* first corner (status 0), and selecting the second
|
||||
* corner (status 1).
|
||||
*/
|
||||
int status;
|
||||
|
||||
protected:
|
||||
/** Action name. Used internally for debugging */
|
||||
QString name;
|
||||
|
||||
/**
|
||||
* This flag is set when the action has terminated and
|
||||
* can be deleted.
|
||||
*/
|
||||
bool finished;
|
||||
|
||||
/**
|
||||
* Pointer to the graphic is this container is a graphic.
|
||||
* NULL otherwise
|
||||
*/
|
||||
RS_Graphic* graphic;
|
||||
|
||||
/**
|
||||
* Pointer to the document (graphic or block) or NULL.
|
||||
*/
|
||||
RS_Document* document;
|
||||
|
||||
/**
|
||||
* Pointer to the default mouse cursor for this action or NULL.
|
||||
*/
|
||||
//RS2::CursorType cursor;
|
||||
|
||||
/**
|
||||
* Predecessor of this action or NULL.
|
||||
*/
|
||||
RS_ActionInterface* predecessor;
|
||||
|
||||
/**
|
||||
* String prepended to the help text for currently available commands.
|
||||
*/
|
||||
//static QString msgAvailableCommands;
|
||||
|
||||
/**
|
||||
* Command used for showing help for every action.
|
||||
*/
|
||||
//static QString cmdHelp;
|
||||
|
||||
/**
|
||||
* Command for answering yes to a question.
|
||||
*/
|
||||
//static QString cmdYes;
|
||||
//static QString cmdYes2;
|
||||
|
||||
/**
|
||||
* Command for answering no to a question.
|
||||
*/
|
||||
//static QString cmdNo;
|
||||
//static QString cmdNo2;
|
||||
RS2::ActionType actionType;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
190
lib/actions/rs_preview.cpp
Normal file
190
lib/actions/rs_preview.cpp
Normal file
@@ -0,0 +1,190 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
#include "rs_preview.h"
|
||||
#include "rs_entitycontainer.h"
|
||||
#include "rs_line.h"
|
||||
#include "rs_graphicview.h"
|
||||
#include "rs_information.h"
|
||||
#include "rs_settings.h"
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
RS_Preview::RS_Preview(RS_EntityContainer* parent)
|
||||
: RS_EntityContainer(parent, true) {
|
||||
|
||||
RS_SETTINGS->beginGroup("/Appearance");
|
||||
maxEntities = RS_SETTINGS->readNumEntry("/MaxPreview", 100);
|
||||
RS_SETTINGS->endGroup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an entity to this preview and removes any attributes / layer
|
||||
* connections before that.
|
||||
*/
|
||||
void RS_Preview::addEntity(RS_Entity* entity) {
|
||||
if (!entity || entity->isUndone()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// only border preview for complex entities:
|
||||
//if ((entity->count() > maxEntities-count()) &&
|
||||
|
||||
bool addBorder = false;
|
||||
|
||||
if (entity->rtti()==RS2::EntityImage || entity->rtti()==RS2::EntityHatch ||
|
||||
entity->rtti()==RS2::EntityInsert) {
|
||||
|
||||
addBorder = true;
|
||||
} else {
|
||||
if (entity->isContainer() && entity->rtti()!=RS2::EntitySpline) {
|
||||
if (entity->countDeep() > maxEntities-countDeep()) {
|
||||
addBorder = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (addBorder) {
|
||||
RS_Vector min = entity->getMin();
|
||||
RS_Vector max = entity->getMax();
|
||||
|
||||
RS_Line* l1 =
|
||||
new RS_Line(this, {min.x, min.y}, {max.x, min.y});
|
||||
RS_Line* l2 =
|
||||
new RS_Line(this, {max.x, min.y}, {max.x, max.y});
|
||||
RS_Line* l3 =
|
||||
new RS_Line(this, {max.x, max.y}, {min.x, max.y});
|
||||
RS_Line* l4 =
|
||||
new RS_Line(this, {min.x, max.y}, {min.x, min.y});
|
||||
|
||||
RS_EntityContainer::addEntity(l1);
|
||||
RS_EntityContainer::addEntity(l2);
|
||||
RS_EntityContainer::addEntity(l3);
|
||||
RS_EntityContainer::addEntity(l4);
|
||||
|
||||
delete entity;
|
||||
entity = nullptr;
|
||||
} else {
|
||||
entity->setLayer(nullptr);
|
||||
entity->setSelected(false);
|
||||
entity->reparent(this);
|
||||
// Don't set this pen, let drawing routines decide entity->setPenToActive();
|
||||
RS_EntityContainer::addEntity(entity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones the given entity and adds the clone to the preview.
|
||||
*/
|
||||
void RS_Preview::addCloneOf(RS_Entity* entity) {
|
||||
if (!entity) {
|
||||
return;
|
||||
}
|
||||
|
||||
RS_Entity* clone = entity->clone();
|
||||
clone->reparent(this);
|
||||
addEntity(clone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all entities from 'container' to the preview (unselected).
|
||||
*/
|
||||
void RS_Preview::addAllFrom(RS_EntityContainer& container) {
|
||||
int c=0;
|
||||
for(auto e: container){
|
||||
|
||||
if (c<maxEntities) {
|
||||
RS_Entity* clone = e->clone();
|
||||
clone->setSelected(false);
|
||||
clone->reparent(this);
|
||||
|
||||
c+=clone->countDeep();
|
||||
addEntity(clone);
|
||||
// clone might be nullptr after this point
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all selected entities from 'container' to the preview (unselected).
|
||||
*/
|
||||
void RS_Preview::addSelectionFrom(RS_EntityContainer& container) {
|
||||
int c=0;
|
||||
for(auto e: container){
|
||||
|
||||
if (e->isSelected() && c<maxEntities) {
|
||||
RS_Entity* clone = e->clone();
|
||||
clone->setSelected(false);
|
||||
clone->reparent(this);
|
||||
|
||||
c+=clone->countDeep();
|
||||
addEntity(clone);
|
||||
// clone might be nullptr after this point
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all entities in the given range and those which have endpoints
|
||||
* in the given range to the preview.
|
||||
*/
|
||||
void RS_Preview::addStretchablesFrom(RS_EntityContainer& container,
|
||||
const RS_Vector& v1, const RS_Vector& v2) {
|
||||
int c=0;
|
||||
|
||||
for(auto e: container){
|
||||
|
||||
if (e->isVisible() &&
|
||||
e->rtti()!=RS2::EntityHatch &&
|
||||
((e->isInWindow(v1, v2)) ||
|
||||
e->hasEndpointsWithinWindow(v1, v2)) &&
|
||||
|
||||
c<maxEntities) {
|
||||
|
||||
RS_Entity* clone = e->clone();
|
||||
//clone->setSelected(false);
|
||||
clone->reparent(this);
|
||||
|
||||
c+=clone->countDeep();
|
||||
addEntity(clone);
|
||||
// clone might be nullptr after this point
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RS_Preview::draw(RS_Painter* painter, RS_GraphicView* view,
|
||||
double& patternOffset) {
|
||||
|
||||
if (!(painter && view)) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (auto e, entities)
|
||||
{
|
||||
e->draw(painter, view, patternOffset);
|
||||
}
|
||||
}
|
||||
60
lib/actions/rs_preview.h
Normal file
60
lib/actions/rs_preview.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_PREVIEW_H
|
||||
#define RS_PREVIEW_H
|
||||
|
||||
#include "rs_entitycontainer.h"
|
||||
|
||||
/**
|
||||
* This class supports previewing. The RS_Snapper class uses
|
||||
* an instance of RS_Preview to preview entities, ranges,
|
||||
* lines, arcs, ... on the fly.
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_Preview : public RS_EntityContainer {
|
||||
public:
|
||||
RS_Preview(RS_EntityContainer* parent=nullptr);
|
||||
~RS_Preview() = default;
|
||||
virtual RS2::EntityType rtti() const override{
|
||||
return RS2::EntityPreview;
|
||||
}
|
||||
virtual void addEntity(RS_Entity* entity) override;
|
||||
void addCloneOf(RS_Entity* entity);
|
||||
virtual void addSelectionFrom(RS_EntityContainer& container);
|
||||
virtual void addAllFrom(RS_EntityContainer& container);
|
||||
virtual void addStretchablesFrom(RS_EntityContainer& container,
|
||||
const RS_Vector& v1, const RS_Vector& v2);
|
||||
|
||||
void draw(RS_Painter* painter, RS_GraphicView* view, double& patternOffset) override;
|
||||
|
||||
private:
|
||||
int maxEntities;
|
||||
};
|
||||
|
||||
#endif
|
||||
130
lib/actions/rs_previewactioninterface.cpp
Normal file
130
lib/actions/rs_previewactioninterface.cpp
Normal file
@@ -0,0 +1,130 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#include "rs_previewactioninterface.h"
|
||||
|
||||
#include "rs_graphicview.h"
|
||||
#include "rs_preview.h"
|
||||
#include "rs_debug.h"
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* Sets the entity container on which the action class inherited
|
||||
* from this interface operates.
|
||||
*/
|
||||
RS_PreviewActionInterface::RS_PreviewActionInterface(const char* name,
|
||||
RS_EntityContainer& container,
|
||||
RS_GraphicView& graphicView) :
|
||||
RS_ActionInterface(name, container, graphicView)
|
||||
,preview(new RS_Preview(&container))
|
||||
// ,offset(new RS_Vector{})
|
||||
{
|
||||
|
||||
RS_DEBUG->print("RS_PreviewActionInterface::RS_PreviewActionInterface: Setting up action with preview: \"%s\"", name);
|
||||
|
||||
// preview is linked to the container for getting access to
|
||||
// document settings / dictionary variables
|
||||
|
||||
preview->setLayer(NULL);
|
||||
hasPreview = true;
|
||||
|
||||
RS_DEBUG->print("RS_PreviewActionInterface::RS_PreviewActionInterface: Setting up action with preview: \"%s\": OK", name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Destructor */
|
||||
RS_PreviewActionInterface::~RS_PreviewActionInterface() {
|
||||
deletePreview();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_PreviewActionInterface::init(int status) {
|
||||
deletePreview();
|
||||
RS_ActionInterface::init(status);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_PreviewActionInterface::finish(bool updateTB) {
|
||||
deletePreview();
|
||||
RS_ActionInterface::finish(updateTB);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_PreviewActionInterface::suspend() {
|
||||
RS_ActionInterface::suspend();
|
||||
deletePreview();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_PreviewActionInterface::resume() {
|
||||
RS_ActionInterface::resume();
|
||||
drawPreview();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_PreviewActionInterface::trigger() {
|
||||
RS_ActionInterface::trigger();
|
||||
deletePreview();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deletes the preview from the screen.
|
||||
*/
|
||||
void RS_PreviewActionInterface::deletePreview() {
|
||||
if (hasPreview){
|
||||
//avoid deleting NULL or empty preview
|
||||
preview->clear();
|
||||
hasPreview=false;
|
||||
}
|
||||
if(!graphicView->isCleanUp()){
|
||||
graphicView->getOverlayContainer(RS2::ActionPreviewEntity)->clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Draws / deletes the current preview.
|
||||
*/
|
||||
void RS_PreviewActionInterface::drawPreview() {
|
||||
// RVT_PORT How does offset work?? painter->setOffset(offset);
|
||||
RS_EntityContainer *container=graphicView->getOverlayContainer(RS2::ActionPreviewEntity);
|
||||
container->clear();
|
||||
container->setOwner(false); // Little hack for now so we don't delete the preview twice
|
||||
container->addEntity(preview.get());
|
||||
graphicView->redraw(RS2::RedrawOverlay);
|
||||
hasPreview=true;
|
||||
}
|
||||
|
||||
69
lib/actions/rs_previewactioninterface.h
Normal file
69
lib/actions/rs_previewactioninterface.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_PREVIEWACTIONINTERFACE_H
|
||||
#define RS_PREVIEWACTIONINTERFACE_H
|
||||
|
||||
#include <memory>
|
||||
#include "rs_actioninterface.h"
|
||||
|
||||
/**
|
||||
* This is the interface that must be implemented for all
|
||||
* action classes which need a preview.
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_PreviewActionInterface : public RS_ActionInterface {
|
||||
public:
|
||||
RS_PreviewActionInterface(const char* name,
|
||||
RS_EntityContainer& container,
|
||||
RS_GraphicView& graphicView);
|
||||
~RS_PreviewActionInterface() override;
|
||||
|
||||
void init(int status=0) override;
|
||||
void finish(bool updateTB=true) override;
|
||||
void suspend() override;
|
||||
void resume() override;
|
||||
void trigger() override;
|
||||
void drawPreview();
|
||||
void deletePreview();
|
||||
|
||||
private:
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Preview that holds the entities to be previewed.
|
||||
*/
|
||||
std::unique_ptr<RS_Preview> preview;
|
||||
bool hasPreview;//whether preview is in use
|
||||
// /**
|
||||
// * Current offset of the preview.
|
||||
// */
|
||||
// std::unique_ptr<RS_Vector> offset;
|
||||
};
|
||||
|
||||
#endif
|
||||
1016
lib/actions/rs_snapper.cpp
Normal file
1016
lib/actions/rs_snapper.cpp
Normal file
File diff suppressed because it is too large
Load Diff
237
lib/actions/rs_snapper.h
Normal file
237
lib/actions/rs_snapper.h
Normal file
@@ -0,0 +1,237 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2015 Dongxu Li (dongxuli2011@gmail.com)
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef RS_SNAPPER_H
|
||||
#define RS_SNAPPER_H
|
||||
|
||||
#include<memory>
|
||||
#include "rs.h"
|
||||
|
||||
class RS_Entity;
|
||||
class RS_GraphicView;
|
||||
class RS_Vector;
|
||||
class RS_Preview;
|
||||
class QMouseEvent;
|
||||
class RS_EntityContainer;
|
||||
|
||||
/**
|
||||
* This class holds information on how to snap the mouse.
|
||||
*
|
||||
* @author Kevin Cox
|
||||
*/
|
||||
struct RS_SnapMode {
|
||||
/* SnapModes for RS_SnapMode to Int conversion and vice versa
|
||||
*
|
||||
* The conversion is only used for save/restore of active snap modes in application settings.
|
||||
* Don't change existing mode order, because this will mess up settings on upgrades
|
||||
*
|
||||
* When adding new values, take care for correct implementation in \p toInt() and \p fromInt()
|
||||
*/
|
||||
enum SnapModes {
|
||||
SnapIntersection = 1 << 0,
|
||||
SnapOnEntity = 1 << 1,
|
||||
SnapCenter = 1 << 2,
|
||||
SnapDistance = 1 << 3,
|
||||
SnapMiddle = 1 << 4,
|
||||
SnapEndpoint = 1 << 5,
|
||||
SnapGrid = 1 << 6,
|
||||
SnapFree = 1 << 7,
|
||||
RestrictHorizontal = 1 << 8,
|
||||
RestrictVertical = 1 << 9,
|
||||
RestrictOrthogonal = RestrictHorizontal | RestrictVertical,
|
||||
SnapAngle = 1 << 10
|
||||
};
|
||||
|
||||
bool snapIntersection {false}; //< Whether to snap to intersections or not.
|
||||
bool snapOnEntity {false}; //< Whether to snap to entities or not.
|
||||
bool snapCenter {false}; //< Whether to snap to centers or not.
|
||||
bool snapDistance {false}; //< Whether to snap to distance from endpoints or not.
|
||||
bool snapMiddle {false}; //< Whether to snap to midpoints or not.
|
||||
bool snapEndpoint {false}; //< Whether to snap to endpoints or not.
|
||||
bool snapGrid {false}; //< Whether to snap to grid or not.
|
||||
bool snapFree {false}; //< Whether to snap freely
|
||||
bool snapAngle {false}; //< Whether to snap along line under certain angle
|
||||
|
||||
RS2::SnapRestriction restriction {RS2::RestrictNothing}; /// The restriction on the free snap.
|
||||
|
||||
double distance {5.0}; //< The distance to snap before defaulting to free snapping.
|
||||
|
||||
/**
|
||||
* Disable all snapping.
|
||||
*
|
||||
* This effectively puts the object into free snap mode.
|
||||
*
|
||||
* @returns A reference to itself.
|
||||
*/
|
||||
RS_SnapMode const & clear(void);
|
||||
bool operator == (RS_SnapMode const& rhs) const;
|
||||
|
||||
static uint toInt(const RS_SnapMode& s); //< convert to int, to save settings
|
||||
static RS_SnapMode fromInt(unsigned int); //< convert from int, to restore settings
|
||||
};
|
||||
|
||||
typedef std::initializer_list<RS2::EntityType> EntityTypeList;
|
||||
|
||||
/**
|
||||
* This class is used for snapping functions in a graphic view.
|
||||
* Actions are usually derived from this base class if they need
|
||||
* to catch entities or snap to coordinates. Use the methods to
|
||||
* retrieve a graphic coordinate from a mouse coordinate.
|
||||
*
|
||||
* Possible snapping functions are described in RS_SnapMode.
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_Snapper {
|
||||
public:
|
||||
RS_Snapper() = delete;
|
||||
RS_Snapper(RS_EntityContainer& container, RS_GraphicView& graphicView);
|
||||
virtual ~RS_Snapper();
|
||||
|
||||
void init();
|
||||
//!
|
||||
//! \brief finish stop using snapper
|
||||
//!
|
||||
void finish();
|
||||
|
||||
/**
|
||||
* @return Pointer to the entity which was the key entity for the
|
||||
* last successful snapping action. If the snap mode is "end point"
|
||||
* the key entity is the entity whose end point was caught.
|
||||
* If the snap mode didn't require an entity (e.g. free, grid) this
|
||||
* method will return NULL.
|
||||
*/
|
||||
RS_Entity* getKeyEntity() const {
|
||||
return keyEntity;
|
||||
}
|
||||
|
||||
/** Sets a new snap mode. */
|
||||
void setSnapMode(const RS_SnapMode& snapMode);
|
||||
|
||||
RS_SnapMode const* getSnapMode() const;
|
||||
RS_SnapMode* getSnapMode();
|
||||
|
||||
/** Sets a new snap restriction. */
|
||||
void setSnapRestriction(RS2::SnapRestriction /*snapRes*/) {
|
||||
//this->snapRes = snapRes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the snap range in pixels for catchEntity().
|
||||
*
|
||||
* @see catchEntity()
|
||||
*/
|
||||
void setSnapRange(int r) {
|
||||
snapRange = r;
|
||||
}
|
||||
|
||||
/**manually set snapPoint*/
|
||||
RS_Vector snapPoint(const RS_Vector& coord, bool setSpot = false);
|
||||
RS_Vector snapPoint(QMouseEvent* e);
|
||||
RS_Vector snapFree(QMouseEvent* e);
|
||||
|
||||
RS_Vector snapFree(const RS_Vector& coord);
|
||||
RS_Vector snapGrid(const RS_Vector& coord);
|
||||
RS_Vector snapEndpoint(const RS_Vector& coord);
|
||||
RS_Vector snapOnEntity(const RS_Vector& coord);
|
||||
RS_Vector snapCenter(const RS_Vector& coord);
|
||||
RS_Vector snapMiddle(const RS_Vector& coord);
|
||||
RS_Vector snapDist(const RS_Vector& coord);
|
||||
RS_Vector snapIntersection(const RS_Vector& coord);
|
||||
//RS_Vector snapDirect(RS_Vector coord, bool abs);
|
||||
RS_Vector snapToAngle(const RS_Vector &coord, const RS_Vector &ref_coord, const double ang_res);
|
||||
|
||||
RS_Vector restrictOrthogonal(const RS_Vector& coord);
|
||||
RS_Vector restrictHorizontal(const RS_Vector& coord);
|
||||
RS_Vector restrictVertical(const RS_Vector& coord);
|
||||
|
||||
|
||||
//RS_Entity* catchLeafEntity(const RS_Vector& pos);
|
||||
//RS_Entity* catchLeafEntity(QMouseEvent* e);
|
||||
RS_Entity* catchEntity(const RS_Vector& pos,
|
||||
RS2::ResolveLevel level=RS2::ResolveNone);
|
||||
RS_Entity* catchEntity(QMouseEvent* e,
|
||||
RS2::ResolveLevel level=RS2::ResolveNone);
|
||||
// catch Entity closest to pos and of the given entity type of enType, only search for a particular entity type
|
||||
RS_Entity* catchEntity(const RS_Vector& pos, RS2::EntityType enType,
|
||||
RS2::ResolveLevel level=RS2::ResolveNone);
|
||||
RS_Entity* catchEntity(QMouseEvent* e, RS2::EntityType enType,
|
||||
RS2::ResolveLevel level=RS2::ResolveNone);
|
||||
RS_Entity* catchEntity(QMouseEvent* e, const EntityTypeList& enTypeList,
|
||||
RS2::ResolveLevel level=RS2::ResolveNone);
|
||||
|
||||
/**
|
||||
* Suspends this snapper while another action takes place.
|
||||
*/
|
||||
virtual void suspend();
|
||||
|
||||
/**
|
||||
* Resumes this snapper after it has been suspended.
|
||||
*/
|
||||
virtual void resume() {
|
||||
drawSnapper();
|
||||
}
|
||||
|
||||
virtual void hideOptions();
|
||||
virtual void showOptions();
|
||||
|
||||
void drawSnapper();
|
||||
|
||||
protected:
|
||||
void deleteSnapper();
|
||||
double getSnapRange() const;
|
||||
RS_EntityContainer* container;
|
||||
RS_GraphicView* graphicView;
|
||||
RS_Entity* keyEntity;
|
||||
RS_SnapMode snapMode;
|
||||
//RS2::SnapRestriction snapRes;
|
||||
/**
|
||||
* Snap distance for snapping to points with a
|
||||
* given distance from endpoints.
|
||||
*/
|
||||
double m_SnapDistance;
|
||||
/**
|
||||
* Snap to equidistant middle points
|
||||
* default to 1, i.e., equidistant to start/end points
|
||||
*/
|
||||
int middlePoints;
|
||||
/**
|
||||
* Snap range for catching entities.
|
||||
*/
|
||||
int snapRange;
|
||||
bool finished{false};
|
||||
|
||||
private:
|
||||
struct ImpData;
|
||||
std::unique_ptr<ImpData> pImpData;
|
||||
|
||||
struct Indicator;
|
||||
Indicator* snap_indicator{nullptr};
|
||||
};
|
||||
|
||||
#endif
|
||||
//EOF
|
||||
BIN
lib/coordinate/coordinate.dll
Normal file
BIN
lib/coordinate/coordinate.dll
Normal file
Binary file not shown.
24
lib/coordinate/coordinate.h
Normal file
24
lib/coordinate/coordinate.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef COORDINATE_H
|
||||
#define COORDINATE_H
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#if defined(COORDINATE_LIBRARY)
|
||||
# define COORDINATESHARED_EXPORT Q_DECL_EXPORT
|
||||
#else
|
||||
# define COORDINATESHARED_EXPORT Q_DECL_IMPORT
|
||||
#endif
|
||||
|
||||
class COORDINATESHARED_EXPORT Coordinate
|
||||
{
|
||||
|
||||
public:
|
||||
Coordinate();
|
||||
|
||||
int add(int a,int b);
|
||||
void getCoordinate(QVector<QVector<int>> **vec,int *row,int *col);
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // COORDINATE_H
|
||||
1119
lib/creation/rs_creation.cpp
Normal file
1119
lib/creation/rs_creation.cpp
Normal file
File diff suppressed because it is too large
Load Diff
164
lib/creation/rs_creation.h
Normal file
164
lib/creation/rs_creation.h
Normal file
@@ -0,0 +1,164 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_CREATION_H
|
||||
#define RS_CREATION_H
|
||||
|
||||
#include "rs_vector.h"
|
||||
|
||||
class RS_Document;
|
||||
class RS_EntityContainer;
|
||||
class RS_GraphicView;
|
||||
class RS_Graphic;
|
||||
class RS_Entity;
|
||||
class RS_Arc;
|
||||
class RS_Circle;
|
||||
class RS_Ellipse;
|
||||
class RS_Line;
|
||||
class LC_SplinePoints;
|
||||
struct RS_BlockData;
|
||||
struct RS_ImageData;
|
||||
class RS_Image;
|
||||
struct RS_InsertData;
|
||||
class RS_Insert;
|
||||
class RS_Block;
|
||||
class QString;
|
||||
|
||||
/**
|
||||
* Data needed to insert library items.
|
||||
*/
|
||||
struct RS_LibraryInsertData {
|
||||
QString file;
|
||||
RS_Vector insertionPoint;
|
||||
double factor;
|
||||
double angle;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Class for the creation of new entities.
|
||||
* This class is bound to an entity container in which the
|
||||
* entities are stored.
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_Creation {
|
||||
public:
|
||||
RS_Creation(RS_EntityContainer* container,
|
||||
RS_GraphicView* graphicView=nullptr,
|
||||
bool handleUndo=true);
|
||||
~RS_Creation()=default;
|
||||
|
||||
RS_Entity* createParallelThrough(const RS_Vector& coord,
|
||||
int number,
|
||||
RS_Entity* e);
|
||||
|
||||
RS_Entity* createParallel(const RS_Vector& coord,
|
||||
double distance,
|
||||
int number,
|
||||
RS_Entity* e);
|
||||
|
||||
RS_Line* createParallelLine(const RS_Vector& coord,
|
||||
double distance, int number,
|
||||
RS_Line* e);
|
||||
|
||||
RS_Arc* createParallelArc(const RS_Vector& coord,
|
||||
double distance, int number,
|
||||
RS_Arc* e);
|
||||
|
||||
RS_Circle* createParallelCircle(const RS_Vector& coord,
|
||||
double distance, int number,
|
||||
RS_Circle* e);
|
||||
|
||||
LC_SplinePoints* createParallelSplinePoints(const RS_Vector& coord,
|
||||
double distance, int number,
|
||||
LC_SplinePoints* e);
|
||||
|
||||
RS_Line* createBisector(const RS_Vector& coord1,
|
||||
const RS_Vector& coord2,
|
||||
double length,
|
||||
int num,
|
||||
RS_Line* l1,
|
||||
RS_Line* l2);
|
||||
|
||||
RS_Line* createTangent1(const RS_Vector& coord,
|
||||
const RS_Vector& point,
|
||||
RS_Entity* circle);
|
||||
/**
|
||||
* create a tangent line which is orthogonal to the given RS_Line(normal)
|
||||
*/
|
||||
RS_Line* createLineOrthTan(const RS_Vector& coord,
|
||||
RS_Line* normal,
|
||||
RS_Entity* circle);
|
||||
RS_Line* createTangent2(const RS_Vector& coord,
|
||||
RS_Entity* circle1,
|
||||
RS_Entity* circle2);
|
||||
/**
|
||||
* create the path of centers of common tangent circles of the two given circles
|
||||
*@ return nullptr, if failed
|
||||
*@ at success return either an ellipse or hyperbola
|
||||
*/
|
||||
std::vector<RS_Entity*> createCircleTangent2( RS_Entity* circle1,RS_Entity* circle2);
|
||||
|
||||
RS_Line* createLineRelAngle(const RS_Vector& coord,
|
||||
RS_Entity* entity,
|
||||
double angle,
|
||||
double length);
|
||||
|
||||
RS_Line* createPolygon(const RS_Vector& center,
|
||||
const RS_Vector& corner,
|
||||
int number);
|
||||
|
||||
RS_Line* createPolygon2(const RS_Vector& corner1,
|
||||
const RS_Vector& corner2,
|
||||
int number);
|
||||
|
||||
RS_Line* createPolygon3(const RS_Vector& center,
|
||||
const RS_Vector& tangent,
|
||||
int number);
|
||||
|
||||
RS_Insert* createInsert(const RS_InsertData* pdata);
|
||||
|
||||
RS_Image* createImage(const RS_ImageData* pdata);
|
||||
|
||||
RS_Block* createBlock(const RS_BlockData* data,
|
||||
const RS_Vector& referencePoint,
|
||||
const bool remove);
|
||||
|
||||
RS_Insert* createLibraryInsert(RS_LibraryInsertData& data);
|
||||
|
||||
protected:
|
||||
RS_EntityContainer* container;
|
||||
RS_Graphic* graphic;
|
||||
RS_Document* document;
|
||||
RS_GraphicView* graphicView;
|
||||
bool handleUndo;
|
||||
private:
|
||||
void setEntity(RS_Entity* en) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
180
lib/debug/rs_debug.cpp
Normal file
180
lib/debug/rs_debug.cpp
Normal file
@@ -0,0 +1,180 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#include "rs_debug.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
#include <QString>
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
|
||||
RS_Debug* RS_Debug::uniqueInstance = nullptr;
|
||||
void debugHeader(char const* file, char const* func, int line)
|
||||
{
|
||||
std::cout<<file<<" : "<<func<<" : line "<<line<<std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the one and only RS_Debug instance
|
||||
* (creates a new one on first call only)
|
||||
*
|
||||
* @return Pointer to the single instance of this
|
||||
* singleton class
|
||||
*/
|
||||
RS_Debug* RS_Debug::instance() {
|
||||
if(!uniqueInstance) {
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
QString nowStr;
|
||||
nowStr = now.toString("yyyyMMdd_hhmmss");
|
||||
|
||||
//QString fName = QString("%1/debug_%2.log")
|
||||
// .arg(RS_SYSTEM->getHomeDir())
|
||||
// .arg(nowStr);
|
||||
// 定义打印日志名称
|
||||
QString fName = QString("debug_%1.log").arg(nowStr);
|
||||
|
||||
uniqueInstance = new RS_Debug;
|
||||
// 获取日志文件句柄
|
||||
//uniqueInstance->stream = fopen(fName.latin1(), "wt");
|
||||
uniqueInstance->stream = stderr;
|
||||
}
|
||||
return uniqueInstance;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deletes the one and only RS_Debug instance.
|
||||
*/
|
||||
void
|
||||
RS_Debug::deleteInstance() {
|
||||
if (uniqueInstance) {
|
||||
fclose(uniqueInstance->stream);
|
||||
delete uniqueInstance;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor setting the default debug level.
|
||||
*/
|
||||
RS_Debug::RS_Debug()
|
||||
{
|
||||
debugLevel = D_DEBUGGING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the debugging level.
|
||||
*/
|
||||
void RS_Debug::setLevel(RS_DebugLevel level) {
|
||||
if(debugLevel==level) return;
|
||||
debugLevel = level;
|
||||
print( D_NOTHING, "RS_DEBUG::setLevel(%d)", level);
|
||||
print( D_CRITICAL, "RS_DEBUG: Critical");
|
||||
print( D_ERROR, "RS_DEBUG: Errors");
|
||||
print( D_WARNING, "RS_DEBUG: Warnings");
|
||||
print( D_NOTICE, "RS_DEBUG: Notice");
|
||||
print( D_INFORMATIONAL, "RS_DEBUG: Informational");
|
||||
print( D_DEBUGGING, "RS_DEBUG: Debugging");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the current debugging level.
|
||||
*/
|
||||
RS_Debug::RS_DebugLevel RS_Debug::getLevel() {
|
||||
return debugLevel;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prints the given message to stdout.
|
||||
* 实现把文本字符串写入文件,并且文本字符可以带多个格式参数
|
||||
*/
|
||||
void RS_Debug::print(const char* format ...) {
|
||||
if(debugLevel==D_DEBUGGING) {
|
||||
// 定义可变参数指针
|
||||
va_list ap;
|
||||
// 初始化可变参数指针,指向第一个可变参数
|
||||
va_start(ap, format);
|
||||
// 使用参数列表发送格式化输出到流 stream 中
|
||||
// 参数1:这是指向 FILE 对象的指针,该 FILE 对象标识了流
|
||||
// 参数2:这是 C 字符串,包含了要被写入到流 stream 中的文本。它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。
|
||||
// 参数3:可变参数指针
|
||||
vfprintf(stream, format, ap);
|
||||
fprintf(stream, "\n");
|
||||
va_end(ap);
|
||||
fflush(stream);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the given message to stdout if the current debug level
|
||||
* is lower then the given level
|
||||
*
|
||||
* @param level Debug level.
|
||||
*/
|
||||
void RS_Debug::print(RS_DebugLevel level, const char* format ...) {
|
||||
|
||||
if(debugLevel>=level) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vfprintf(stream, format, ap);
|
||||
fprintf(stream, "\n");
|
||||
va_end(ap);
|
||||
fflush(stream);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prints a time stamp in the format yyyyMMdd_hhmmss.
|
||||
*/
|
||||
void RS_Debug::timestamp() {
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
QString nowStr;
|
||||
|
||||
nowStr = now.toString("yyyyMMdd_hh:mm:ss:zzz ");
|
||||
fprintf(stream, "%s", nowStr.toLatin1().data());
|
||||
fprintf(stream, "\n");
|
||||
fflush(stream);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prints the unicode for every character in the given string.
|
||||
*/
|
||||
void RS_Debug::printUnicode(const QString& text) {
|
||||
for(auto const& v: text){
|
||||
print("[%X] %c", v.unicode(), v.toLatin1());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// EOF
|
||||
109
lib/debug/rs_debug.h
Normal file
109
lib/debug/rs_debug.h
Normal file
@@ -0,0 +1,109 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_DEBUG_H
|
||||
#define RS_DEBUG_H
|
||||
|
||||
#include <iosfwd>
|
||||
#ifdef __hpux
|
||||
#include <sys/_size_t.h>
|
||||
#endif
|
||||
#include<QObject>
|
||||
|
||||
class QString;
|
||||
|
||||
/** print out a debug header*/
|
||||
#define DEBUG_HEADER debugHeader(__FILE__, __func__, __LINE__);
|
||||
void debugHeader(char const* file, char const* func, int line);
|
||||
#define RS_DEBUG RS_Debug::instance()
|
||||
#define RS_DEBUG_VERBOSE DEBUG_HEADER \
|
||||
RS_Debug::instance()
|
||||
|
||||
/**
|
||||
* Debugging facilities.
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_Debug:public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Enum for debug levels. Only messages of the current
|
||||
* or a higher level are printed.
|
||||
* <ul>
|
||||
* <li>D_NOTHING: nothing
|
||||
* <li>D_CRITICAL: critical messages
|
||||
* <li>D_ERROR: errors
|
||||
* <li>D_WARNING: warnings
|
||||
* <li>D_NOTICE: notes
|
||||
* <li>D_INFORMATIONAL: infos
|
||||
* <li>D_DEBUGGING: very verbose
|
||||
* </ul>
|
||||
*/
|
||||
enum RS_DebugLevel { D_NOTHING,
|
||||
D_CRITICAL,
|
||||
D_ERROR,
|
||||
D_WARNING,
|
||||
D_NOTICE,
|
||||
D_INFORMATIONAL,
|
||||
D_DEBUGGING };
|
||||
|
||||
private:
|
||||
RS_Debug();
|
||||
RS_Debug(const RS_Debug&)=delete;
|
||||
RS_Debug& operator = (const RS_Debug&)=delete;
|
||||
RS_Debug(RS_Debug&&)=delete;
|
||||
RS_Debug& operator = (RS_Debug&&)=delete;
|
||||
|
||||
|
||||
|
||||
public:
|
||||
static RS_Debug* instance();
|
||||
|
||||
static void deleteInstance();
|
||||
void setLevel(RS_DebugLevel level);
|
||||
RS_DebugLevel getLevel();
|
||||
void print(RS_DebugLevel level, const char* format ...);
|
||||
void print(const char* format ...);
|
||||
|
||||
|
||||
void printUnicode(const QString& text);
|
||||
void timestamp();
|
||||
void setStream(FILE* s) {
|
||||
stream = s;
|
||||
}
|
||||
|
||||
private:
|
||||
static RS_Debug* uniqueInstance;
|
||||
|
||||
RS_DebugLevel debugLevel;
|
||||
FILE* stream;
|
||||
};
|
||||
|
||||
#endif
|
||||
// EOF
|
||||
202
lib/engine/lc_hyperbola.cpp
Normal file
202
lib/engine/lc_hyperbola.cpp
Normal file
@@ -0,0 +1,202 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
#include "lc_hyperbola.h"
|
||||
|
||||
#include "rs_graphic.h"
|
||||
#include "rs_graphicview.h"
|
||||
#include "rs_painter.h"
|
||||
#include "rs_information.h"
|
||||
#include "rs_linetypepattern.h"
|
||||
#include "lc_quadratic.h"
|
||||
|
||||
LC_HyperbolaData::LC_HyperbolaData(const RS_Vector& _center,
|
||||
const RS_Vector& _majorP,
|
||||
double _ratio,
|
||||
double _angle1, double _angle2,
|
||||
bool _reversed):
|
||||
center(_center)
|
||||
,majorP(_majorP)
|
||||
,ratio(_ratio)
|
||||
,angle1(_angle1)
|
||||
,angle2(_angle2)
|
||||
,reversed(_reversed)
|
||||
{
|
||||
}
|
||||
|
||||
std::ostream& operator << (std::ostream& os, const LC_HyperbolaData& ed) {
|
||||
os << "(" << ed.center <<
|
||||
"/" << ed.majorP <<
|
||||
" " << ed.ratio <<
|
||||
" " << ed.angle1 <<
|
||||
"," << ed.angle2 <<
|
||||
")";
|
||||
return os;
|
||||
}
|
||||
|
||||
#ifdef EMU_C99
|
||||
#include "emu_c99.h" /* C99 math */
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
LC_Hyperbola::LC_Hyperbola(RS_EntityContainer* parent,
|
||||
const LC_HyperbolaData& d)
|
||||
:RS_AtomicEntity(parent)
|
||||
,data(d)
|
||||
,m_bValid(true)
|
||||
{
|
||||
if(data.majorP.squared()<RS_TOLERANCE2) {
|
||||
m_bValid=false;
|
||||
return;
|
||||
}
|
||||
//calculateEndpoints();
|
||||
calculateBorders();
|
||||
}
|
||||
|
||||
/** create data based on foci and a point on hyperbola */
|
||||
LC_HyperbolaData::LC_HyperbolaData(const RS_Vector& focus0,
|
||||
const RS_Vector& focus1,
|
||||
const RS_Vector& point):
|
||||
center((focus0+focus1)*0.5)
|
||||
{
|
||||
double ds0=focus0.distanceTo(point);
|
||||
ds0 -= focus1.distanceTo(point);
|
||||
|
||||
majorP= (ds0>0.)?focus0-center:focus1-center;
|
||||
double dc=focus0.distanceTo(focus1);
|
||||
double dd=fabs(ds0);
|
||||
//no hyperbola for middle equidistant
|
||||
if(dc<RS_TOLERANCE||dd<RS_TOLERANCE) {
|
||||
majorP.set(0.,0.);
|
||||
return;
|
||||
}
|
||||
ratio= dc/dd;
|
||||
majorP /= ratio;
|
||||
ratio=sqrt(ratio*ratio - 1.);
|
||||
|
||||
}
|
||||
|
||||
///** create data based on foci and a point on hyperbola */
|
||||
//LC_Hyperbola::LC_Hyperbola(const RS_Vector& focus0,
|
||||
// const RS_Vector& focus1,
|
||||
// const RS_Vector& point):
|
||||
// data(focus0,focus1,point)
|
||||
//{
|
||||
// m_bValid = data.majorP.squared()> RS_TOLERANCE2;
|
||||
//}
|
||||
/**
|
||||
* Recalculates the endpoints using the angles and the radius.
|
||||
*/
|
||||
/*
|
||||
void LC_Hyperbola::calculateEndpoints() {
|
||||
double angle = data.majorP.angle();
|
||||
double radius1 = getMajorRadius();
|
||||
double radius2 = getMinorRadius();
|
||||
|
||||
startpoint.set(data.center.x + cos(data.angle1) * radius1,
|
||||
data.center.y + sin(data.angle1) * radius2);
|
||||
startpoint.rotate(data.center, angle);
|
||||
endpoint.set(data.center.x + cos(data.angle2) * radius1,
|
||||
data.center.y + sin(data.angle2) * radius2);
|
||||
endpoint.rotate(data.center, angle);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the boundary box of this ellipse.
|
||||
*/
|
||||
|
||||
|
||||
RS_Entity* LC_Hyperbola::clone() const {
|
||||
LC_Hyperbola* e = new LC_Hyperbola(*this);
|
||||
e->initId();
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* return the foci of ellipse
|
||||
*
|
||||
*@Author: Dongxu Li
|
||||
*/
|
||||
|
||||
RS_VectorSolutions LC_Hyperbola::getFoci() const {
|
||||
RS_Vector vp(getMajorP()*sqrt(1.-getRatio()*getRatio()));
|
||||
return RS_VectorSolutions({getCenter()+vp, getCenter()-vp});
|
||||
}
|
||||
|
||||
RS_VectorSolutions LC_Hyperbola::getRefPoints() const{
|
||||
RS_VectorSolutions ret({data.center});
|
||||
ret.push_back(getFoci());
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool LC_Hyperbola::isPointOnEntity(const RS_Vector& coord,
|
||||
double tolerance) const
|
||||
{
|
||||
double a=data.majorP.magnitude();
|
||||
double b=a*data.ratio;
|
||||
if(fabs(a)<tolerance || fabs(b)<tolerance) return false;
|
||||
RS_Vector vp(coord - data.center);
|
||||
vp=vp.rotate(-data.majorP.angle());
|
||||
return fabs( vp.x*vp.x/(a*a)- vp.y*vp.y/(b*b) -1.)<tolerance;
|
||||
}
|
||||
|
||||
|
||||
LC_Quadratic LC_Hyperbola::getQuadratic() const
|
||||
{
|
||||
std::vector<double> ce(6,0.);
|
||||
ce[0]=data.majorP.squared();
|
||||
ce[2]=-data.ratio*data.ratio*ce[0];
|
||||
if(ce[0]>RS_TOLERANCE2) ce[0]=1./ce[0];
|
||||
if(fabs(ce[2])>RS_TOLERANCE2) ce[2]=1./ce[2];
|
||||
ce[5]=-1.;
|
||||
LC_Quadratic ret(ce);
|
||||
if(ce[0]<RS_TOLERANCE2 || fabs(ce[2])<RS_TOLERANCE2) {
|
||||
ret.setValid(false);
|
||||
return ret;
|
||||
}
|
||||
ret.rotate(data.majorP.angle());
|
||||
ret.move(data.center);
|
||||
return ret;
|
||||
}
|
||||
|
||||
//RS_Vector LC_Hyperbola::getNearestEndpoint(const RS_Vector& /*coord*/,
|
||||
// double* /*dist*/ = NULL) const
|
||||
//{
|
||||
//}
|
||||
|
||||
/**
|
||||
* Dumps the point's data to stdout.
|
||||
*/
|
||||
std::ostream& operator << (std::ostream& os, const LC_Hyperbola& a) {
|
||||
os << " Hyperbola: " << a.data << "\n";
|
||||
return os;
|
||||
}
|
||||
|
||||
262
lib/engine/lc_hyperbola.h
Normal file
262
lib/engine/lc_hyperbola.h
Normal file
@@ -0,0 +1,262 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2011-2012 Dongxu Li (dongxuli2011@gmail.com)
|
||||
|
||||
Copyright (C) 2012 Dongxu Li (dongxuli2011@gmail.com)
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef LC_HYPERBOLA_H
|
||||
#define LC_HYPERBOLA_H
|
||||
|
||||
#include "rs_atomicentity.h"
|
||||
|
||||
class RS_Circle;
|
||||
class LC_Quadratic;
|
||||
|
||||
/**
|
||||
* Holds the data that defines one branch of a hyperbola.
|
||||
* majorP is the vector from center to the vertex
|
||||
* ratio is the ratio between semi-major and semi-minor axis
|
||||
|
||||
*/
|
||||
struct LC_HyperbolaData {
|
||||
LC_HyperbolaData() = default;
|
||||
LC_HyperbolaData(const RS_Vector& center,
|
||||
const RS_Vector& majorP,
|
||||
double ratio,
|
||||
double angle1, double angle2,
|
||||
bool reversed);
|
||||
~LC_HyperbolaData() = default;
|
||||
/** create data based on foci and a point on hyperbola */
|
||||
LC_HyperbolaData(const RS_Vector& focus0,
|
||||
const RS_Vector& focus1,
|
||||
const RS_Vector& point);
|
||||
|
||||
//! Hyperbola center
|
||||
RS_Vector center;
|
||||
//! Endpoint of major axis relative to center.
|
||||
RS_Vector majorP;
|
||||
//! Ratio of minor axis to major axis.
|
||||
double ratio;
|
||||
//! Start angle
|
||||
double angle1;
|
||||
//! End angle
|
||||
double angle2;
|
||||
//! Reversed (cw) flag
|
||||
bool reversed;
|
||||
};
|
||||
|
||||
std::ostream& operator << (std::ostream& os, const LC_HyperbolaData& ed);
|
||||
|
||||
|
||||
/**
|
||||
* Class for an hyperbola entity.
|
||||
*
|
||||
* @author Dongxu Li
|
||||
*/
|
||||
class LC_Hyperbola : public RS_AtomicEntity {
|
||||
public:
|
||||
LC_Hyperbola() = default;
|
||||
LC_Hyperbola(RS_EntityContainer* parent,
|
||||
const LC_HyperbolaData& d);
|
||||
|
||||
/** create data based on foci and a point on hyperbola */
|
||||
LC_Hyperbola(const RS_Vector& focus0,
|
||||
const RS_Vector& focus1,
|
||||
const RS_Vector& point);
|
||||
|
||||
RS_Entity* clone() const override;
|
||||
|
||||
/** @return RS2::EntityHyperbola */
|
||||
RS2::EntityType rtti() const override{
|
||||
return RS2::EntityHyperbola;
|
||||
}
|
||||
bool isValid() const{
|
||||
return m_bValid;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// double getLength() const;
|
||||
|
||||
// /**
|
||||
// //Hyperbola must have ratio<1, and not reversed
|
||||
// *@ x1, hyperbola angle
|
||||
// *@ x2, hyperbola angle
|
||||
// //@return the arc length between hyperbola angle x1, x2
|
||||
// **/
|
||||
// double getHyperbolaLength(double a1, double a2) const;
|
||||
// double getHyperbolaLength(double a2) const;
|
||||
|
||||
|
||||
/** @return Copy of data that defines the hyperbola. **/
|
||||
LC_HyperbolaData getData() const {
|
||||
return data;
|
||||
}
|
||||
RS_VectorSolutions getFoci() const;
|
||||
RS_VectorSolutions getRefPoints() const override;
|
||||
|
||||
/**
|
||||
* @retval true if the arc is reversed (clockwise),
|
||||
* @retval false otherwise
|
||||
*/
|
||||
bool isReversed() const{
|
||||
return data.reversed;
|
||||
}
|
||||
/** sets the reversed status. */
|
||||
void setReversed(bool r){
|
||||
data.reversed = r;
|
||||
}
|
||||
|
||||
/** @return The rotation angle of this hyperbola */
|
||||
double getAngle() const {
|
||||
return data.majorP.angle();
|
||||
}
|
||||
|
||||
/** @return The start angle of this arc */
|
||||
double getAngle1() const {
|
||||
return data.angle1;
|
||||
}
|
||||
/** Sets new start angle. */
|
||||
void setAngle1(double a1) {
|
||||
data.angle1 = a1;
|
||||
}
|
||||
/** @return The end angle of this arc */
|
||||
double getAngle2() const {
|
||||
return data.angle2;
|
||||
}
|
||||
/** Sets new end angle. */
|
||||
void setAngle2(double a2) {
|
||||
data.angle2 = a2;
|
||||
}
|
||||
|
||||
|
||||
/** @return The center point (x) of this arc */
|
||||
RS_Vector getCenter() const override{
|
||||
return data.center;
|
||||
}
|
||||
/** Sets new center. */
|
||||
void setCenter(const RS_Vector& c) {
|
||||
data.center = c;
|
||||
}
|
||||
|
||||
/** @return The endpoint of the major axis (relative to center). */
|
||||
RS_Vector getMajorP() const {
|
||||
return data.majorP;
|
||||
}
|
||||
/** Sets new major point (relative to center). */
|
||||
void setMajorP(const RS_Vector& p) {
|
||||
data.majorP = p;
|
||||
}
|
||||
|
||||
/** @return The ratio of minor to major axis */
|
||||
double getRatio() const {
|
||||
return data.ratio;
|
||||
}
|
||||
/** Sets new ratio. */
|
||||
void setRatio(double r) {
|
||||
data.ratio = r;
|
||||
}
|
||||
|
||||
|
||||
/** @return The major radius of this hyperbola. Same as getRadius() */
|
||||
double getMajorRadius() const {
|
||||
return data.majorP.magnitude();
|
||||
}
|
||||
|
||||
/** @return The minor radius of this hyperbola */
|
||||
double getMinorRadius() const {
|
||||
return data.majorP.magnitude()*data.ratio;
|
||||
}
|
||||
|
||||
void calculateBorders() override{}
|
||||
|
||||
RS_Vector getMiddlePoint(void)const override{return RS_Vector(false);}
|
||||
RS_Vector getNearestEndpoint(const RS_Vector& /*coord*/,
|
||||
double*/* dist = NULL*/) const override
|
||||
{return RS_Vector(false);}
|
||||
RS_Vector getNearestPointOnEntity(const RS_Vector& /*coord*/,
|
||||
bool /*onEntity = true*/, double*/* dist = NULL*/, RS_Entity**/* entity=NULL*/) const override
|
||||
{return RS_Vector(false);}
|
||||
RS_Vector getNearestCenter(const RS_Vector& /*coord*/,
|
||||
double*/* dist = NULL*/) const override
|
||||
{return RS_Vector(false);}
|
||||
RS_Vector getNearestMiddle(const RS_Vector& /*coord*/,
|
||||
double*/* dist = NULL*/,
|
||||
int/* middlePoints = 1*/
|
||||
)const override
|
||||
{return RS_Vector(false);}
|
||||
RS_Vector getNearestDist(double /*distance*/,
|
||||
const RS_Vector&/* coord*/,
|
||||
double*/* dist = NULL*/) const override
|
||||
{return RS_Vector(false);}
|
||||
RS_Vector getNearestOrthTan(const RS_Vector& /*coord*/,
|
||||
const RS_Line& /*normal*/,
|
||||
bool /*onEntity = false*/) const override
|
||||
{return RS_Vector(false);}
|
||||
double getDistanceToPoint(const RS_Vector& /*coord*/,
|
||||
RS_Entity** /*entity=NULL*/,
|
||||
RS2::ResolveLevel/* level=RS2::ResolveNone*/,
|
||||
double /*solidDist = RS_MAXDOUBLE*/) const override
|
||||
{return RS_MAXDOUBLE;}
|
||||
bool isPointOnEntity(const RS_Vector& /*coord*/,
|
||||
double /*tolerance=RS_TOLERANCE*/) const override;
|
||||
|
||||
void move(const RS_Vector& /*offset*/) override{}
|
||||
void rotate(const double& /*angle*/) {}
|
||||
void rotate(const RS_Vector& /*angleVector*/){}
|
||||
void rotate(const RS_Vector& /*center*/, const double& /*angle*/) override{}
|
||||
void rotate(const RS_Vector& /*center*/, const RS_Vector& /*angle*/)override{}
|
||||
void scale(const RS_Vector& /*center*/, const RS_Vector& /*factor*/)override{}
|
||||
void mirror(const RS_Vector& /*axisPoint1*/, const RS_Vector& /*axisPoint2*/)override{}
|
||||
void moveRef(const RS_Vector& /*ref*/, const RS_Vector& /*offset*/)override{}
|
||||
|
||||
void draw(RS_Painter* /*painter*/, RS_GraphicView* /*view*/, double& /*patternOffset*/)override{}
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os, const LC_Hyperbola& a);
|
||||
|
||||
//void calculateEndpoints();
|
||||
// void calculateBorders();
|
||||
|
||||
//direction of tangent at endpoints
|
||||
double getDirection1() const override{return 0.;}
|
||||
double getDirection2() const override{return 0.;}
|
||||
/** return the equation of the entity
|
||||
for quadratic,
|
||||
|
||||
return a vector contains:
|
||||
m0 x^2 + m1 xy + m2 y^2 + m3 x + m4 y + m5 =0
|
||||
|
||||
for linear:
|
||||
m0 x + m1 y + m2 =0
|
||||
**/
|
||||
LC_Quadratic getQuadratic() const override;
|
||||
|
||||
protected:
|
||||
LC_HyperbolaData data;
|
||||
bool m_bValid;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
//EOF
|
||||
309
lib/engine/lc_rect.cpp
Normal file
309
lib/engine/lc_rect.cpp
Normal file
@@ -0,0 +1,309 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2015 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2015 Dongxu Li (dongxuli2011@gmail.com)
|
||||
** Copyright (C) 2015 librecad.org (www.librecad.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
**********************************************************************/
|
||||
#include<iostream>
|
||||
#include <QDebug>
|
||||
#include <cassert>
|
||||
#include "lc_rect.h"
|
||||
|
||||
#define INTERT_TEST(s) qDebug()<<"\ntesting " #s; \
|
||||
assert(s); \
|
||||
qDebug()<<"Passed";
|
||||
|
||||
using namespace lc::geo;
|
||||
|
||||
Coordinate LC_Rect::Vector(Coordinate const& p, Coordinate const& q) {
|
||||
return {q.x - p.x, q.y - p.y};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Area. The coordinates coordA and coordB will be ordered so that minP will always be < maxP
|
||||
* The coordinates are not allowed to describe a volume
|
||||
*
|
||||
* @param CoordA First coordinate of an area
|
||||
* @param CoordB Second coordinate of an area
|
||||
*/
|
||||
LC_Rect::Area(const Coordinate& coordA, const Coordinate& coordB) :
|
||||
_minP{std::min(coordA.x, coordB.x), std::min(coordA.y, coordB.y)},
|
||||
_maxP{std::max(coordA.x, coordB.x), std::max(coordA.y, coordB.y)}
|
||||
{
|
||||
}
|
||||
|
||||
LC_Rect::Area() : _minP{0., 0.}, _maxP{0., 0.} {}
|
||||
|
||||
/**
|
||||
* @brief Area
|
||||
* given at a coordinate with a given width and height
|
||||
* @param coordA
|
||||
* @param width
|
||||
* @param height
|
||||
*/
|
||||
LC_Rect::Area(const Coordinate& coord, double width, double height):
|
||||
Area(coord, {coord.x + width, coord.y + height})
|
||||
{}
|
||||
|
||||
/**
|
||||
* Return the smallest corner (closest to (0,0,0) )
|
||||
*/
|
||||
const Coordinate& LC_Rect::minP() const {
|
||||
return _minP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the highest corner
|
||||
*/
|
||||
const Coordinate& LC_Rect::maxP() const {
|
||||
return _maxP;
|
||||
}
|
||||
/**
|
||||
* @brief topLeftCorner return the upperLeftCorner coordinates
|
||||
* _minP is considered lowerLeft, _maxP is the upperRight
|
||||
* @return {_minP.x, _maxP.y}
|
||||
*/
|
||||
Coordinate LC_Rect::upperLeftCorner() const {
|
||||
return {_minP.x, _maxP.y};
|
||||
}
|
||||
Coordinate LC_Rect::upperRightCorner() const {
|
||||
return _maxP;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief lowerRightCorner return the lowerRight coordinates
|
||||
* _minP is considered lowerLeft, _maxP is the upperRight
|
||||
* @return {_maxP.x, _minP.y}
|
||||
*/
|
||||
Coordinate LC_Rect::lowerRightCorner() const {
|
||||
return {_maxP.x, _minP.y};
|
||||
}
|
||||
|
||||
Coordinate LC_Rect::lowerLeftCorner() const {
|
||||
return _minP;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief width
|
||||
* Returns the wid th of this area
|
||||
* @return
|
||||
*/
|
||||
double LC_Rect::width() const {
|
||||
return _maxP.x - _minP.x;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief height
|
||||
* Returns the height f this area
|
||||
* @return
|
||||
*/
|
||||
double LC_Rect::height() const {
|
||||
return _maxP.y - _minP.y;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test of a specific point lies within an area
|
||||
* @param point Point to test against
|
||||
* @return boolean true of the point is within the area
|
||||
*/
|
||||
bool LC_Rect::inArea(const Coordinate& point, double tolerance) const {
|
||||
return (point.x >= _minP.x - tolerance && point.x <= _maxP.x + tolerance && point.y >= _minP.y - tolerance && point.y <= _maxP.y + tolerance);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief inArea
|
||||
* test if this object's fit's fully in area
|
||||
* @param area
|
||||
* @return
|
||||
*/
|
||||
bool LC_Rect::inArea(const Area& area) const {
|
||||
return _minP.x >= area._minP.x && _minP.y >= area._minP.y && _maxP.x <= area._maxP.x && _maxP.y <= area._maxP.y;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief overlaps
|
||||
* returns true if any overlap is happening between the two area's, even if otherArea fit's within this area
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
bool LC_Rect::overlaps(const Area& otherArea) const {
|
||||
return intersects(otherArea);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief numCornersInside
|
||||
* count the number of corners this object has in otherArea
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
short LC_Rect::numCornersInside(const Area& otherArea) const {
|
||||
short pointsInside = 0;
|
||||
|
||||
if (otherArea.inArea(_minP)) {
|
||||
pointsInside++;
|
||||
}
|
||||
|
||||
if (otherArea.inArea(_maxP)) {
|
||||
pointsInside++;
|
||||
}
|
||||
|
||||
if (otherArea.inArea(upperLeftCorner())) {
|
||||
pointsInside++;
|
||||
}
|
||||
|
||||
if (otherArea.inArea(lowerRightCorner())) {
|
||||
pointsInside++;
|
||||
}
|
||||
|
||||
return pointsInside;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief merge
|
||||
* two area's and expand if required to largest containing area
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
Area LC_Rect::merge(const Area& other) const {
|
||||
return {
|
||||
{std::min(other.minP().x, this->minP().x), std::min(other.minP().y, this->minP().y)},
|
||||
{std::max(other.maxP().x, this->maxP().x), std::max(other.maxP().y, this->maxP().y)}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief merge
|
||||
* two area's and expand if required to largest containing area
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
Area LC_Rect::merge(const Coordinate& other) const {
|
||||
return {
|
||||
{std::min(other.x, this->minP().x), std::min(other.y, this->minP().y)},
|
||||
{std::max(other.x, this->maxP().x), std::max(other.y, this->maxP().y)}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief merge
|
||||
* two area's and expand if required to largest containing area
|
||||
* @param other
|
||||
* @param tolerance, tolerance to detect zero size intersection
|
||||
* @return
|
||||
*/
|
||||
Area LC_Rect::intersection(const Area& other, double tolerance) const {
|
||||
|
||||
Area const ret{
|
||||
{std::max(other.minP().x, this->minP().x), std::max(other.minP().y, this->minP().y)},
|
||||
{std::min(other.maxP().x, this->maxP().x), std::min(other.maxP().y, this->maxP().y)}
|
||||
};
|
||||
if (ret.width() < tolerance || ret.height() < tolerance) {
|
||||
return {};
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool LC_Rect::intersects(Area const& rhs, double tolerance) const {
|
||||
return maxP().x + tolerance >= rhs.minP().x &&
|
||||
maxP().y + tolerance >= rhs.minP().y &&
|
||||
rhs.maxP().x + tolerance >= minP().x &&
|
||||
rhs.maxP().y + tolerance >= minP().y;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief top
|
||||
* vector of this area
|
||||
* @return
|
||||
*/
|
||||
Coordinate LC_Rect::top() const {
|
||||
return Vector(upperLeftCorner(), _maxP);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief bottom
|
||||
* vector of this area
|
||||
* @return
|
||||
*/
|
||||
Coordinate LC_Rect::bottom() const {
|
||||
return Vector(_minP, lowerRightCorner());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief left
|
||||
* vector for this area
|
||||
* @return
|
||||
*/
|
||||
Coordinate LC_Rect::left() const {
|
||||
return Vector(_minP, upperLeftCorner());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief right
|
||||
* vector of this area
|
||||
* @return
|
||||
*/
|
||||
Coordinate LC_Rect::right() const {
|
||||
return Vector(lowerRightCorner(), _maxP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increase the area on each side by increaseBy
|
||||
*/
|
||||
Area LC_Rect::increaseBy(double increaseBy) const {
|
||||
return {_minP - increaseBy, _maxP + increaseBy};
|
||||
}
|
||||
|
||||
std::array<Coordinate, 4> LC_Rect::vertices() const
|
||||
{
|
||||
return {{lowerLeftCorner(), lowerRightCorner(),
|
||||
upperRightCorner(), upperLeftCorner()}};
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const Area& area) {
|
||||
os << "Area(" << area.minP() << " " << area.maxP() << ")";
|
||||
return os;
|
||||
}
|
||||
|
||||
void LC_Rect::unitTest() {
|
||||
LC_Rect const rect0{{0., 0.}, {1., 1.}};
|
||||
LC_Rect const rect1{{0.5, 0.5}, {1.5, 1.5}};
|
||||
LC_Rect const rect2{{1.5, 1.5}, {2.5, 2.5}};
|
||||
LC_Rect const rect3{{0.0, 1.}, {1.5, 1.5}};
|
||||
|
||||
//intersects() tests
|
||||
INTERT_TEST(rect0.intersects(rect1))
|
||||
INTERT_TEST(rect1.intersects(rect0))
|
||||
INTERT_TEST(rect1.intersects(rect2))
|
||||
INTERT_TEST(rect2.intersects(rect1))
|
||||
|
||||
INTERT_TEST(!rect0.intersects(rect2))
|
||||
INTERT_TEST(!rect2.intersects(rect0))
|
||||
|
||||
INTERT_TEST(rect2.intersects(rect3))
|
||||
INTERT_TEST(rect3.intersects(rect2))
|
||||
|
||||
// inArea() tests
|
||||
INTERT_TEST(rect0.inArea({0.1, 0.1}))
|
||||
INTERT_TEST(rect0.inArea({0.5, 0.5}))
|
||||
|
||||
INTERT_TEST(!rect0.inArea({1.1, 1.1}))
|
||||
INTERT_TEST(!rect0.inArea({-1.1, -1.1}))
|
||||
|
||||
}
|
||||
|
||||
217
lib/engine/lc_rect.h
Normal file
217
lib/engine/lc_rect.h
Normal file
@@ -0,0 +1,217 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2015 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2015 Dongxu Li (dongxuli2011@gmail.com)
|
||||
** Copyright (C) 2015 librecad.org (www.librecad.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef LC_RECT_H
|
||||
#define LC_RECT_H
|
||||
#include "rs_vector.h"
|
||||
#include <array>
|
||||
|
||||
//ported from LibreCAD V3
|
||||
namespace lc {
|
||||
namespace geo {
|
||||
|
||||
typedef RS_Vector Coordinate;
|
||||
|
||||
/**
|
||||
* Class that describes an area or window.
|
||||
*/
|
||||
class Area {
|
||||
|
||||
public:
|
||||
Area();
|
||||
/**
|
||||
* Create a new Area. The coordinates coordA and coordB will be ordered so that minP will always be < maxP
|
||||
* The coordinates are not allowed to describe a volume
|
||||
*
|
||||
* @param CoordA First coordinate of an area
|
||||
* @param CoordB Second coordinate of an area
|
||||
*/
|
||||
Area(const Coordinate& coordA, const Coordinate& coordB);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Area
|
||||
* given at a coordinate with a given width and height
|
||||
* @param coordA
|
||||
* @param width
|
||||
* @param height
|
||||
*/
|
||||
explicit Area(const Coordinate& coord, double width, double height);
|
||||
|
||||
/**
|
||||
* Return the smallest corner (closest to (0,0,0) )
|
||||
*/
|
||||
const Coordinate& minP() const;
|
||||
|
||||
/**
|
||||
* Return the highest corner
|
||||
*/
|
||||
const Coordinate& maxP() const;
|
||||
/**
|
||||
* @brief topLeftCorner return the upperLeftCorner coordinates
|
||||
* _minP is considered lowerLeft, _maxP is the upperRight
|
||||
* @return {_minP.x, _maxP.y}
|
||||
*/
|
||||
Coordinate upperLeftCorner() const;
|
||||
Coordinate upperRightCorner() const;
|
||||
/**
|
||||
* @brief lowerRightCorner return the lowerRight coordinates
|
||||
* _minP is considered lowerLeft, _maxP is the upperRight
|
||||
* @return {_maxP.x, _minP.y}
|
||||
*/
|
||||
Coordinate lowerLeftCorner() const;
|
||||
Coordinate lowerRightCorner() const;
|
||||
|
||||
/**
|
||||
* @brief width
|
||||
* Returns the width of this area
|
||||
* @return
|
||||
*/
|
||||
double width() const;
|
||||
|
||||
/**
|
||||
* @brief height
|
||||
* Returns the height of this area
|
||||
* @return
|
||||
*/
|
||||
double height() const;
|
||||
|
||||
/**
|
||||
* @brief Test of a specific point lies within an area
|
||||
* @param point Point to test against
|
||||
* @return boolean true of the point is within the area
|
||||
*/
|
||||
bool inArea(const Coordinate& point, double tolerance = 0.) const;
|
||||
|
||||
/**
|
||||
* @brief inArea
|
||||
* test if this object's fit's fully in area
|
||||
* @param area
|
||||
* @return
|
||||
*/
|
||||
bool inArea(const Area& area) const;
|
||||
|
||||
/**
|
||||
* @brief overlaps
|
||||
* returns true if any overlap is happening between the two area's, even if otherArea fit's within this area
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
bool overlaps(const Area& otherArea) const;
|
||||
|
||||
/**
|
||||
* @brief numCornersInside
|
||||
* count the number of corners this object has in otherArea
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
short numCornersInside(const Area& otherArea) const;
|
||||
|
||||
/**
|
||||
* @brief merge
|
||||
* two area's and expand if required to largest containing area
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
Area merge(const Area& other) const;
|
||||
|
||||
/**
|
||||
* @brief merge
|
||||
* two area's and expand if required to largest containing area
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
Area merge(const Coordinate& other) const;
|
||||
|
||||
/**
|
||||
* @brief merge
|
||||
* two area's and expand if required to largest containing area
|
||||
* @param other
|
||||
* @param tolerance, tolerance to detect zero size intersection
|
||||
* @return
|
||||
*/
|
||||
Area intersection(const Area& other, double tolerance = 0.) const;
|
||||
|
||||
/**
|
||||
* @brief intersects whether two rectangular area
|
||||
* if the closest distance between two Areas is smaller than tolerance, they
|
||||
* are considered to have intersection
|
||||
* @param rhs the other rect
|
||||
* @return true if closest distance is smaller than or equal to tolerance
|
||||
*/
|
||||
bool intersects(Area const& rhs, double tolerance = 0.) const;
|
||||
|
||||
/**
|
||||
* @brief top
|
||||
* vector of this area
|
||||
* @return
|
||||
*/
|
||||
Coordinate top() const;
|
||||
|
||||
/**
|
||||
* @brief bottom
|
||||
* vector of this area
|
||||
* @return
|
||||
*/
|
||||
Coordinate bottom() const;
|
||||
|
||||
/**
|
||||
* @brief left
|
||||
* vector for this area
|
||||
* @return
|
||||
*/
|
||||
Coordinate left() const;
|
||||
|
||||
/**
|
||||
* @brief right
|
||||
* vector of this area
|
||||
* @return
|
||||
*/
|
||||
Coordinate right() const;
|
||||
|
||||
/**
|
||||
* Increase the area on each side by increaseBy
|
||||
*/
|
||||
Area increaseBy (double increaseBy) const;
|
||||
/**
|
||||
* @brief vertices generate vertices of the rectangular area
|
||||
* @return array of vertices by the order {ll, lr, ur, rl} starting with
|
||||
* lower-left corner, i.e. _minP
|
||||
*/
|
||||
std::array<Coordinate, 4> vertices() const;
|
||||
|
||||
static void unitTest();
|
||||
|
||||
private:
|
||||
static Coordinate Vector(Coordinate const& p, Coordinate const& q);
|
||||
friend std::ostream& operator<<(std::ostream& os, const Area& area);
|
||||
|
||||
private:
|
||||
Coordinate _minP;
|
||||
Coordinate _maxP;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
using LC_Rect = lc::geo::Area;
|
||||
#endif // LC_RECT_H
|
||||
3756
lib/engine/lc_splinepoints.cpp
Normal file
3756
lib/engine/lc_splinepoints.cpp
Normal file
File diff suppressed because it is too large
Load Diff
245
lib/engine/lc_splinepoints.h
Normal file
245
lib/engine/lc_splinepoints.h
Normal file
@@ -0,0 +1,245 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2014 Dongxu Li (dongxuli2011@gmail.com)
|
||||
** Copyright (C) 2014 Pavel Krejcir (pavel@pamsoft.cz)
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef LC_SPLINEPOINTS_H
|
||||
#define LC_SPLINEPOINTS_H
|
||||
|
||||
#include <vector>
|
||||
#include "rs_atomicentity.h"
|
||||
|
||||
class QPolygonF;
|
||||
struct RS_LineTypePattern;
|
||||
|
||||
/**
|
||||
* Holds the data that defines a line.
|
||||
* Few notes about implementation:
|
||||
* When drawing, the spline is defined via splinePoints collection.
|
||||
* However, since we want to allow trimming/cutting the spline,
|
||||
* we cannot guarantee that the shape would stay unchanged after
|
||||
* a part of the spline would be cut off. This would espetially be
|
||||
* obvious after cutting closed splines. So we introduce the "cut"
|
||||
* state. After that, all splinePoints will be deleted except start
|
||||
* and end points, and the controlPoints become the reference points
|
||||
* of that shape. It will be further possible to modify the spline,
|
||||
* but the control points will serve as handles then.
|
||||
*/
|
||||
struct LC_SplinePointsData
|
||||
{
|
||||
/**
|
||||
* Default constructor. Leaves the data object uninitialized.
|
||||
*/
|
||||
LC_SplinePointsData() = default;
|
||||
~LC_SplinePointsData() = default;
|
||||
|
||||
LC_SplinePointsData(bool closed, bool cut);
|
||||
|
||||
bool closed;
|
||||
bool cut;
|
||||
/** points on the spline. */
|
||||
std::vector<RS_Vector> splinePoints;
|
||||
std::vector<RS_Vector> controlPoints;
|
||||
};
|
||||
|
||||
std::ostream& operator << (std::ostream& os, const LC_SplinePointsData& ld);
|
||||
|
||||
/**
|
||||
* Class for a spline entity.
|
||||
*
|
||||
* @author Pavel Krejcir
|
||||
*/
|
||||
class LC_SplinePoints : public RS_AtomicEntity // RS_EntityContainer
|
||||
{
|
||||
private:
|
||||
void drawPattern(RS_Painter* painter, RS_GraphicView* view,
|
||||
double& patternOffset, const RS_LineTypePattern* pat);
|
||||
void drawSimple(RS_Painter* painter, RS_GraphicView* view);
|
||||
void UpdateControlPoints();
|
||||
void UpdateQuadExtent(const RS_Vector& x1, const RS_Vector& c1, const RS_Vector& x2);
|
||||
int GetNearestQuad(const RS_Vector& coord, double* dist, double* dt) const;
|
||||
RS_Vector GetSplinePointAtDist(double dDist, int iStartSeg, double dStartT,
|
||||
int *piSeg, double *pdt) const;
|
||||
int GetQuadPoints(int iSeg, RS_Vector *pvStart, RS_Vector *pvControl,
|
||||
RS_Vector *pvEnd) const;
|
||||
|
||||
bool offsetCut(const RS_Vector& coord, const double& distance);
|
||||
bool offsetSpline(const RS_Vector& coord, const double& distance);
|
||||
std::vector<RS_Entity*> offsetTwoSidesSpline(const double& distance) const;
|
||||
std::vector<RS_Entity*> offsetTwoSidesCut(const double& distance) const;
|
||||
LC_SplinePointsData data;
|
||||
|
||||
public:
|
||||
LC_SplinePoints(RS_EntityContainer* parent, const LC_SplinePointsData& d);
|
||||
RS_Entity* clone() const override;
|
||||
|
||||
/** @return RS2::EntitySpline */
|
||||
RS2::EntityType rtti() const override;
|
||||
|
||||
/** @return false */
|
||||
bool isEdge() const override;
|
||||
|
||||
/** @return Copy of data that defines the spline. */
|
||||
LC_SplinePointsData const& getData() const;
|
||||
LC_SplinePointsData& getData();
|
||||
|
||||
/** @return Number of control points. */
|
||||
size_t getNumberOfControlPoints() const;
|
||||
|
||||
/**
|
||||
* @retval true if the spline is closed.
|
||||
* @retval false otherwise.
|
||||
*/
|
||||
bool isClosed() const;
|
||||
|
||||
/**
|
||||
* Sets the closed flag of this spline.
|
||||
*/
|
||||
void setClosed(bool c);
|
||||
|
||||
void update() override;
|
||||
|
||||
RS_VectorSolutions getRefPoints() const override;
|
||||
|
||||
/** @return Start point of the entity */
|
||||
RS_Vector getStartpoint() const override;
|
||||
|
||||
/** @return End point of the entity */
|
||||
RS_Vector getEndpoint() const override;
|
||||
|
||||
/** Sets the startpoint */
|
||||
//void setStartpoint(RS_Vector s) {
|
||||
// data.startpoint = s;
|
||||
// calculateBorders();
|
||||
//}
|
||||
/** Sets the endpoint */
|
||||
//void setEndpoint(RS_Vector e) {
|
||||
// data.endpoint = e;
|
||||
// calculateBorders();
|
||||
//}
|
||||
|
||||
double getDirection1() const override;
|
||||
double getDirection2() const override;
|
||||
|
||||
//void moveStartpoint(const RS_Vector& pos) override;
|
||||
//void moveEndpoint(const RS_Vector& pos) override;
|
||||
//RS2::Ending getTrimPoint(const RS_Vector& coord,
|
||||
// const RS_Vector& trimPoint);
|
||||
//void reverse() override;
|
||||
/** @return the center point of the line. */
|
||||
//RS_Vector getMiddlePoint() {
|
||||
// return (data.startpoint + data.endpoint)/2.0;
|
||||
//}
|
||||
//bool hasEndpointsWithinWindow(RS_Vector v1, RS_Vector v2) override;
|
||||
|
||||
/**
|
||||
* @return The length of the line.
|
||||
*/
|
||||
double getLength() const override;
|
||||
|
||||
/**
|
||||
* @return The angle of the line (from start to endpoint).
|
||||
*/
|
||||
//double getAngle1() {
|
||||
// return data.startpoint.angleTo(data.endpoint);
|
||||
//}
|
||||
|
||||
/**
|
||||
* @return The angle of the line (from end to startpoint).
|
||||
*/
|
||||
//double getAngle2() {
|
||||
// return data.endpoint.angleTo(data.startpoint);
|
||||
//}
|
||||
|
||||
RS_VectorSolutions getTangentPoint(const RS_Vector& point) const override;
|
||||
RS_Vector getTangentDirection(const RS_Vector& point) const override;
|
||||
|
||||
RS_Vector getNearestEndpoint(const RS_Vector& coord,
|
||||
double* dist = nullptr) const override;
|
||||
/**
|
||||
* @brief getNearestPointOnEntity
|
||||
* @param coord
|
||||
* @param onEntity, unused, because current implementation finds the nearest point on the spline
|
||||
* @param dist
|
||||
* @param entity
|
||||
* @return
|
||||
*/
|
||||
RS_Vector getNearestPointOnEntity(const RS_Vector& coord,
|
||||
bool onEntity = true, double* dist = nullptr, RS_Entity** entity = nullptr) const override;
|
||||
// RS_Vector getNearestCenter(const RS_Vector& coord,
|
||||
// double* dist = nullptr) const;
|
||||
RS_Vector getNearestMiddle(const RS_Vector& coord,
|
||||
double* dist = nullptr, int middlePoints = 1) const override;
|
||||
RS_Vector getNearestDist(double distance,
|
||||
const RS_Vector& coord, double* dist = nullptr) const override;
|
||||
//RS_Vector getNearestRef(const RS_Vector& coord,
|
||||
// double* dist = nullptr);
|
||||
double getDistanceToPoint(const RS_Vector& coord,
|
||||
RS_Entity** entity = nullptr, RS2::ResolveLevel level = RS2::ResolveNone,
|
||||
double solidDist = RS_MAXDOUBLE) const override;
|
||||
|
||||
bool addPoint(const RS_Vector& v);
|
||||
void removeLastPoint();
|
||||
void addControlPoint(const RS_Vector& v);
|
||||
|
||||
void move(const RS_Vector& offset) override;
|
||||
void rotate(const RS_Vector& center, const double& angle) override;
|
||||
void rotate(const RS_Vector& center, const RS_Vector& angleVector) override;
|
||||
void scale(const RS_Vector& center, const RS_Vector& factor) override;
|
||||
void mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) override;
|
||||
|
||||
void moveRef(const RS_Vector& ref, const RS_Vector& offset) override;
|
||||
void revertDirection() override;
|
||||
|
||||
void draw(RS_Painter* painter, RS_GraphicView* view, double& patternOffset) override;
|
||||
std::vector<RS_Vector> const& getPoints() const;
|
||||
std::vector<RS_Vector> const& getControlPoints() const;
|
||||
std::vector<RS_Vector> getStrokePoints() const;
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os, const LC_SplinePoints& l);
|
||||
|
||||
void calculateBorders() override;
|
||||
|
||||
bool offset(const RS_Vector& coord, const double& distance) override;
|
||||
std::vector<RS_Entity*> offsetTwoSides(const double& distance) const override;
|
||||
|
||||
static RS_VectorSolutions getIntersection(RS_Entity const* e1, RS_Entity const* e2);
|
||||
RS_VectorSolutions getLineIntersect(const RS_Vector& x1, const RS_Vector& x2);
|
||||
void addQuadIntersect(RS_VectorSolutions *pVS, const RS_Vector& x1,
|
||||
const RS_Vector& c1, const RS_Vector& x2);
|
||||
RS_VectorSolutions getSplinePointsIntersect(LC_SplinePoints* l1);
|
||||
RS_VectorSolutions getQuadraticIntersect(RS_Entity const* e1);
|
||||
|
||||
// we will not enable trimming, maybe in the future
|
||||
//void trimStartpoint(const RS_Vector& pos) override;
|
||||
//void trimEndpoint(const RS_Vector& pos) override;
|
||||
|
||||
LC_SplinePoints* cut(const RS_Vector& pos);
|
||||
//! \{ getBoundingRect find bounding rectangle for the bezier segment
|
||||
//! \param x1,c1,x2 first/center/last control points
|
||||
//! \return rectangle as a polygon
|
||||
static QPolygonF getBoundingRect(const RS_Vector& x1, const RS_Vector& c1, const RS_Vector& x2);
|
||||
//! \}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
50
lib/engine/lc_undosection.cpp
Normal file
50
lib/engine/lc_undosection.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2018 A. Stebich (librecad@mail.lordofbikes.de)
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
#include "lc_undosection.h"
|
||||
#include "rs_document.h"
|
||||
|
||||
LC_UndoSection::LC_UndoSection(RS_Document *doc, const bool handleUndo /*= true*/) :
|
||||
document( doc),
|
||||
valid( handleUndo && nullptr != doc)
|
||||
{
|
||||
if (valid) {
|
||||
document->startUndoCycle();
|
||||
}
|
||||
}
|
||||
|
||||
LC_UndoSection::~LC_UndoSection()
|
||||
{
|
||||
if (valid) {
|
||||
document->endUndoCycle();
|
||||
}
|
||||
}
|
||||
|
||||
void LC_UndoSection::addUndoable(RS_Undoable *undoable)
|
||||
{
|
||||
if (valid) {
|
||||
document->addUndoable( undoable);
|
||||
}
|
||||
}
|
||||
56
lib/engine/lc_undosection.h
Normal file
56
lib/engine/lc_undosection.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2018 A. Stebich (librecad@mail.lordofbikes.de)
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef LC_UNDOSECTION_H
|
||||
#define LC_UNDOSECTION_H
|
||||
|
||||
class RS_Document;
|
||||
class RS_Undoable;
|
||||
|
||||
/** \brief This class is a wrapper for RS_Undo methods
|
||||
*
|
||||
* It's important that calls to RS_Undo::startUndoCycle() and
|
||||
* RS_Undo::endUndoCycle() are balanced.
|
||||
* On instantiation the constructor calls startUndoCycle().
|
||||
* The class handles also validation of the RS_Document pointer.
|
||||
* When the instance is leaving the scope, the destructor
|
||||
* calls endUndoCycle().
|
||||
* This way the balance is guaranteed.
|
||||
* It simplifies undo handling specially in RS_Creation and RS_Modification classes
|
||||
*/
|
||||
class LC_UndoSection
|
||||
{
|
||||
public:
|
||||
LC_UndoSection(RS_Document * doc, const bool handleUndo = true);
|
||||
~LC_UndoSection();
|
||||
|
||||
void addUndoable(RS_Undoable * undoable);
|
||||
|
||||
private:
|
||||
RS_Document *document {nullptr};
|
||||
bool valid {true};
|
||||
};
|
||||
|
||||
#endif // LC_UNDOSECTION_H
|
||||
51
lib/engine/rs.cpp
Normal file
51
lib/engine/rs.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
#include<iostream>
|
||||
#include<vector>
|
||||
#include<utility>
|
||||
#include<climits>
|
||||
#include "rs.h"
|
||||
|
||||
RS2::LineWidth RS2::intToLineWidth(int w) {
|
||||
std::vector<std::pair<int, LineWidth>> const table{
|
||||
{-2, WidthDefault}, //for w = -3
|
||||
{-1, WidthByBlock}, //for w = -2
|
||||
{0, WidthByLayer}, //for w = -1
|
||||
// for w < 3, return Width00
|
||||
{3, Width00},
|
||||
{8, Width01},
|
||||
{12, Width02},
|
||||
{14, Width03},
|
||||
{17, Width04},
|
||||
{19, Width05},
|
||||
{23, Width06},
|
||||
{28, Width07},
|
||||
{33, Width08},
|
||||
{38, Width09},
|
||||
{46, Width10},
|
||||
{52, Width11},
|
||||
{57, Width12},
|
||||
{66, Width13},
|
||||
{76, Width14},
|
||||
{86, Width15},
|
||||
{96, Width16},
|
||||
{104, Width17},
|
||||
{114, Width18},
|
||||
{131, Width19},
|
||||
{150, Width20},
|
||||
{180, Width21},
|
||||
{206, Width22},
|
||||
{INT_MAX, Width23}
|
||||
};
|
||||
|
||||
//binary search
|
||||
//assume table size is at least 2
|
||||
size_t low = -1;
|
||||
size_t high = table.size() - 1;
|
||||
while (low + 1 < high) {
|
||||
size_t const mid = low + (high - low)/2;
|
||||
if (w >= table.at(mid).first)
|
||||
low = mid;
|
||||
else
|
||||
high = mid;
|
||||
}
|
||||
return table.at(high).second;
|
||||
}
|
||||
945
lib/engine/rs.h
Normal file
945
lib/engine/rs.h
Normal file
@@ -0,0 +1,945 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef RS_H
|
||||
#define RS_H
|
||||
|
||||
//#define RS_TEST
|
||||
|
||||
// Windoze XP can't handle the original MAX/MINDOUBLE's
|
||||
#define RS_MAXDOUBLE 1.0E+10
|
||||
#define RS_MINDOUBLE -1.0E+10
|
||||
//tolerance
|
||||
#define RS_TOLERANCE 1.0e-10
|
||||
//squared tolerance
|
||||
#define RS_TOLERANCE15 1.5e-15
|
||||
#define RS_TOLERANCE2 1.0e-20
|
||||
#define RS_TOLERANCE_ANGLE 1.0e-8
|
||||
|
||||
/**
|
||||
* Class namespace for various enums along with some simple
|
||||
* wrapper methods for converting the enums to the Qt
|
||||
* counterparts.
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS2 {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Flags.
|
||||
*/
|
||||
enum Flags {
|
||||
/** Flag for Undoables. */
|
||||
FlagUndone = 1<<0,
|
||||
/** Entity Visibility. */
|
||||
FlagVisible = 1<<1,
|
||||
/** Entity attribute (e.g. color) is defined by layer. */
|
||||
FlagByLayer = 1<<2,
|
||||
/** Entity attribute (e.g. color) defined by block. */
|
||||
FlagByBlock = 1<<3,
|
||||
/** Layer frozen. */
|
||||
FlagFrozen = 1<<4,
|
||||
/** Layer frozen by default. */
|
||||
FlagDefFrozen = 1<<5,
|
||||
/** Layer locked. */
|
||||
FlagLocked = 1<<6,
|
||||
/** Used for invalid pens. */
|
||||
FlagInvalid = 1<<7,
|
||||
/** Entity in current selection. */
|
||||
FlagSelected = 1<<8,
|
||||
/** Polyline closed? */
|
||||
FlagClosed = 1<<9,
|
||||
/** Flag for temporary entities (e.g. hatch) */
|
||||
FlagTemp = 1<<10,
|
||||
/** Flag for processed entities (optcontour) */
|
||||
FlagProcessed = 1<<11,
|
||||
/** Startpoint selected */
|
||||
FlagSelected1 = 1<<12,
|
||||
/** Endpoint selected */
|
||||
FlagSelected2 = 1<<13,
|
||||
/** Entity is highlighted temporarily (as a user action feedback) */
|
||||
FlagHighlighted = 1<<14
|
||||
};
|
||||
|
||||
/**
|
||||
* Variable types used by RS_VariableDict and RS_Variable.
|
||||
*/
|
||||
enum VariableType {
|
||||
VariableString,
|
||||
VariableInt,
|
||||
VariableDouble,
|
||||
VariableVector,
|
||||
VariableVoid
|
||||
};
|
||||
|
||||
/**
|
||||
* File types. Used by file dialogs. Note: the extension might not
|
||||
* be enough to distinguish file types.
|
||||
*/
|
||||
enum FormatType {
|
||||
FormatUnknown, /**< Unknown / unsupported format. */
|
||||
FormatDXF1, /**< QCad 1 compatibility DXF format. */
|
||||
FormatDXFRW, /**< DXF format. v2007. */
|
||||
FormatDXFRW2004, /**< DXF format. v2004. */
|
||||
FormatDXFRW2000, /**< DXF format. v2000. */
|
||||
FormatDXFRW14, /**< DXF format. v14. */
|
||||
FormatDXFRW12, /**< DXF format. v12. */
|
||||
#ifdef DWGSUPPORT
|
||||
FormatDWG, /**< DWG format. */
|
||||
#endif
|
||||
FormatLFF, /**< LibreCAD Font File format. */
|
||||
FormatCXF, /**< CAM Expert Font format. */
|
||||
FormatJWW, /**< JWW Format type */
|
||||
FormatJWC /**< JWC Format type */
|
||||
};
|
||||
|
||||
/**
|
||||
* Entity types returned by the rtti() method
|
||||
*/
|
||||
enum EntityType {
|
||||
EntityUnknown, /**< Unknown */
|
||||
EntityContainer, /**< Container */
|
||||
EntityBlock, /**< Block (Group definition) */
|
||||
EntityFontChar, /**< Font character */
|
||||
EntityInsert, /**< Insert (Group instance) */
|
||||
EntityGraphic, /**< Graphic with layers */
|
||||
EntityPoint, /**< Point */
|
||||
EntityLine, /**< Line */
|
||||
EntityPolyline, /**< Polyline */
|
||||
EntityVertex, /**< Vertex (part of a polyline) */
|
||||
EntityArc, /**< Arc */
|
||||
EntityCircle, /**< Circle */
|
||||
EntityEllipse, /**< Ellipse */
|
||||
EntityHyperbola, /**< Hyperbola */
|
||||
EntitySolid, /**< Solid */
|
||||
EntityConstructionLine, /**< Construction line */
|
||||
EntityMText, /**< Multi-line Text */
|
||||
EntityText, /**< Single-line Text */
|
||||
EntityDimAligned, /**< Aligned Dimension */
|
||||
EntityDimLinear, /**< Linear Dimension */
|
||||
EntityDimRadial, /**< Radial Dimension */
|
||||
EntityDimDiametric, /**< Diametric Dimension */
|
||||
EntityDimAngular, /**< Angular Dimension */
|
||||
EntityDimLeader, /**< Leader Dimension */
|
||||
EntityHatch, /**< Hatch */
|
||||
EntityImage, /**< Image */
|
||||
EntitySpline, /**< Spline */
|
||||
EntitySplinePoints, /**< SplinePoints */
|
||||
EntityOverlayBox, /**< OverlayBox */
|
||||
EntityPreview, /**< Preview Container */
|
||||
EntityPattern,
|
||||
EntityOverlayLine
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Action types used by action factories.
|
||||
*/
|
||||
enum ActionType {
|
||||
ActionNone, /**< Invalid action id. */
|
||||
|
||||
ActionDefault,
|
||||
|
||||
ActionFileNew,
|
||||
ActionFileNewTemplate,
|
||||
ActionFileOpen,
|
||||
ActionFileSave,
|
||||
ActionFileSaveAs,
|
||||
ActionFileExport,
|
||||
ActionFileClose,
|
||||
ActionFilePrint,
|
||||
ActionFilePrintPDF,
|
||||
ActionFilePrintPreview,
|
||||
ActionFileExportMakerCam,
|
||||
ActionFileQuit,
|
||||
|
||||
ActionEditKillAllActions,
|
||||
ActionEditUndo,
|
||||
ActionEditRedo,
|
||||
ActionEditCut,
|
||||
ActionEditCutNoSelect,
|
||||
ActionEditCopy,
|
||||
ActionEditCopyNoSelect,
|
||||
ActionEditPaste,
|
||||
ActionOrderNoSelect,
|
||||
ActionOrderBottom,
|
||||
ActionOrderLower,
|
||||
ActionOrderRaise,
|
||||
ActionOrderTop,
|
||||
|
||||
ActionViewStatusBar,
|
||||
ActionViewLayerList,
|
||||
ActionViewBlockList,
|
||||
ActionViewCommandLine,
|
||||
ActionViewLibrary,
|
||||
|
||||
ActionViewPenToolbar,
|
||||
ActionViewOptionToolbar,
|
||||
ActionViewCadToolbar,
|
||||
ActionViewFileToolbar,
|
||||
ActionViewEditToolbar,
|
||||
ActionViewSnapToolbar,
|
||||
|
||||
ActionViewGrid,
|
||||
ActionViewDraft,
|
||||
|
||||
ActionZoomIn,
|
||||
ActionZoomOut,
|
||||
ActionZoomAuto,
|
||||
ActionZoomWindow,
|
||||
ActionZoomPan,
|
||||
ActionZoomRedraw,
|
||||
ActionZoomPrevious,
|
||||
|
||||
ActionSelect,
|
||||
ActionSelectSingle,
|
||||
ActionSelectContour,
|
||||
ActionSelectWindow,
|
||||
ActionDeselectWindow,
|
||||
ActionSelectAll,
|
||||
ActionDeselectAll,
|
||||
ActionSelectIntersected,
|
||||
ActionDeselectIntersected,
|
||||
ActionSelectInvert,
|
||||
ActionSelectLayer,
|
||||
ActionSelectDouble,
|
||||
ActionGetSelect,
|
||||
|
||||
ActionDrawArc,
|
||||
ActionDrawArc3P,
|
||||
ActionDrawArcParallel,
|
||||
ActionDrawArcTangential,
|
||||
ActionDrawCircle,
|
||||
ActionDrawCircle2P,
|
||||
ActionDrawCircle2PR,
|
||||
ActionDrawCircle3P,
|
||||
ActionDrawCircleCR,
|
||||
ActionDrawCircleParallel,
|
||||
ActionDrawCircleInscribe,
|
||||
ActionDrawCircleTan2_1P,
|
||||
ActionDrawCircleTan1_2P,
|
||||
ActionDrawCircleTan2,
|
||||
ActionDrawCircleTan3,
|
||||
|
||||
ActionDrawEllipseArcAxis,
|
||||
ActionDrawEllipseAxis,
|
||||
ActionDrawEllipseFociPoint,
|
||||
ActionDrawEllipse4Points,
|
||||
ActionDrawEllipseCenter3Points,
|
||||
ActionDrawEllipseInscribe,
|
||||
|
||||
ActionDrawHatch,
|
||||
ActionDrawHatchNoSelect,
|
||||
ActionDrawImage,
|
||||
ActionDrawLine,
|
||||
ActionDrawLineAngle,
|
||||
ActionDrawLineBisector,
|
||||
ActionDrawLineFree,
|
||||
ActionDrawLineHorVert,
|
||||
ActionDrawLineHorizontal,
|
||||
ActionDrawLineOrthogonal,
|
||||
ActionDrawLineOrthTan,
|
||||
ActionDrawLineParallel,
|
||||
ActionDrawLineParallelThrough,
|
||||
ActionDrawLinePolygonCenCor,
|
||||
ActionDrawLinePolygonCenTan,//add by txmy
|
||||
ActionDrawLinePolygonCorCor,
|
||||
ActionDrawLineRectangle,
|
||||
ActionDrawLineRelAngle,
|
||||
ActionDrawLineTangent1,
|
||||
ActionDrawLineTangent2,
|
||||
ActionDrawLineVertical,
|
||||
ActionDrawMText,
|
||||
ActionDrawPoint,
|
||||
ActionDrawSpline,
|
||||
ActionDrawSplinePoints, //interpolation spline
|
||||
ActionDrawPolyline,
|
||||
ActionDrawText,
|
||||
|
||||
ActionPolylineAdd,
|
||||
ActionPolylineAppend,
|
||||
ActionPolylineDel,
|
||||
ActionPolylineDelBetween,
|
||||
ActionPolylineTrim,
|
||||
ActionPolylineEquidistant,
|
||||
ActionPolylineSegment,
|
||||
|
||||
ActionDimAligned,
|
||||
ActionDimLinear,
|
||||
ActionDimLinearVer,
|
||||
ActionDimLinearHor,
|
||||
ActionDimRadial,
|
||||
ActionDimDiametric,
|
||||
ActionDimAngular,
|
||||
ActionDimLeader,
|
||||
|
||||
ActionModifyAttributes,
|
||||
ActionModifyAttributesNoSelect,
|
||||
ActionModifyDelete,
|
||||
ActionModifyDeleteNoSelect,
|
||||
ActionModifyDeleteQuick,
|
||||
ActionModifyDeleteFree,
|
||||
ActionModifyMove,
|
||||
ActionModifyMoveNoSelect,
|
||||
ActionModifyRotate,
|
||||
ActionModifyRotateNoSelect,
|
||||
ActionModifyScale,
|
||||
ActionModifyScaleNoSelect,
|
||||
ActionModifyMirror,
|
||||
ActionModifyMirrorNoSelect,
|
||||
ActionModifyMoveRotate,
|
||||
ActionModifyMoveRotateNoSelect,
|
||||
ActionModifyRevertDirection,
|
||||
ActionModifyRevertDirectionNoSelect,
|
||||
ActionModifyRotate2,
|
||||
ActionModifyRotate2NoSelect,
|
||||
ActionModifyEntity,
|
||||
ActionModifyTrim,
|
||||
ActionModifyTrim2,
|
||||
ActionModifyTrimAmount,
|
||||
ActionModifyCut,
|
||||
ActionModifyStretch,
|
||||
ActionModifyBevel,
|
||||
ActionModifyRound,
|
||||
ActionModifyOffset,
|
||||
ActionModifyOffsetNoSelect,
|
||||
|
||||
ActionSnapFree,
|
||||
ActionSnapGrid,
|
||||
ActionSnapEndpoint,
|
||||
ActionSnapOnEntity,
|
||||
ActionSnapCenter,
|
||||
ActionSnapMiddle,
|
||||
ActionSnapDist,
|
||||
ActionSnapIntersection,
|
||||
ActionSnapIntersectionManual,
|
||||
|
||||
ActionRestrictNothing,
|
||||
ActionRestrictOrthogonal,
|
||||
ActionRestrictHorizontal,
|
||||
ActionRestrictVertical,
|
||||
|
||||
ActionSetRelativeZero,
|
||||
ActionLockRelativeZero,
|
||||
ActionUnlockRelativeZero,
|
||||
|
||||
ActionInfoInside,
|
||||
ActionInfoDist,
|
||||
ActionInfoDist2,
|
||||
ActionInfoAngle,
|
||||
ActionInfoTotalLength,
|
||||
ActionInfoTotalLengthNoSelect,
|
||||
ActionInfoArea,
|
||||
|
||||
ActionLayersDefreezeAll,
|
||||
ActionLayersFreezeAll,
|
||||
ActionLayersUnlockAll,
|
||||
ActionLayersLockAll,
|
||||
ActionLayersAdd,
|
||||
ActionLayersRemove,
|
||||
ActionLayersEdit,
|
||||
ActionLayersToggleView,
|
||||
ActionLayersToggleLock,
|
||||
ActionLayersTogglePrint,
|
||||
ActionLayersToggleConstruction,
|
||||
|
||||
ActionBlocksDefreezeAll,
|
||||
ActionBlocksFreezeAll,
|
||||
ActionBlocksAdd,
|
||||
ActionBlocksRemove,
|
||||
ActionBlocksAttributes,
|
||||
ActionBlocksEdit,
|
||||
ActionBlocksSave,
|
||||
ActionBlocksInsert,
|
||||
ActionBlocksToggleView,
|
||||
ActionBlocksCreate,
|
||||
ActionBlocksCreateNoSelect,
|
||||
ActionBlocksExplode,
|
||||
ActionBlocksExplodeNoSelect,
|
||||
ActionBlocksImport,
|
||||
|
||||
ActionModifyExplodeText,
|
||||
ActionModifyExplodeTextNoSelect,
|
||||
|
||||
ActionLibraryInsert,
|
||||
|
||||
ActionOptionsGeneral,
|
||||
ActionOptionsDrawing,
|
||||
|
||||
ActionToolRegenerateDimensions,
|
||||
|
||||
ActionScriptOpenIDE,
|
||||
ActionScriptRun,
|
||||
|
||||
/** Needed to loop through all actions */
|
||||
ActionLast
|
||||
};
|
||||
|
||||
/**
|
||||
* Entity ending. Used for returning which end of an entity is meant.
|
||||
*/
|
||||
enum Ending {
|
||||
EndingStart, /**< Start point. */
|
||||
EndingEnd, /**< End point. */
|
||||
EndingNone /**< Neither. */
|
||||
};
|
||||
|
||||
/**
|
||||
* Update mode for non-atomic entities that need to be updated when
|
||||
* they change. e.g. texts, inserts, ...
|
||||
*/
|
||||
enum UpdateMode {
|
||||
NoUpdate, /**< No automatic updates. */
|
||||
Update, /**< Always update automatically when modified. */
|
||||
PreviewUpdate /**< Update automatically but only for previews (quick update) */
|
||||
};
|
||||
|
||||
/**
|
||||
* Drawing mode.
|
||||
*/
|
||||
enum DrawingMode {
|
||||
ModeFull, /**< Draw everything always detailed (default) */
|
||||
ModeAuto, /**< Draw details when reasonable */
|
||||
ModePreview, /**< Draw only in black/white without styles */
|
||||
ModeBW, /**< Black/white. Can be used for printing. */
|
||||
ModeWB, /**< White/black, used for export */
|
||||
};
|
||||
|
||||
/**
|
||||
* Undoable rtti.
|
||||
*/
|
||||
enum UndoableType {
|
||||
UndoableUnknown, /**< Unknown undoable */
|
||||
UndoableEntity, /**< Entity */
|
||||
UndoableLayer /**< Layer */
|
||||
};
|
||||
|
||||
/**
|
||||
* Units.
|
||||
*/
|
||||
enum Unit {
|
||||
None = 0, /**< No unit (unit from parent) */
|
||||
Inch = 1, /**< Inch */
|
||||
Foot = 2, /**< Foot: 12 Inches */
|
||||
Mile = 3, /**< Mile: 1760 Yards = 1609 m */
|
||||
Millimeter = 4, /**< Millimeter: 0.001m */
|
||||
Centimeter = 5, /**< Centimeter: 0.01m */
|
||||
Meter = 6, /**< Meter */
|
||||
Kilometer = 7, /**< Kilometer: 1000m */
|
||||
Microinch = 8, /**< Microinch: 0.000001 */
|
||||
Mil = 9, /**< Mil = 0.001 Inch*/
|
||||
Yard = 10, /**< Yard: 3 Feet */
|
||||
Angstrom = 11, /**< Angstrom: 10^-10m */
|
||||
Nanometer = 12, /**< Nanometer: 10^-9m */
|
||||
Micron = 13, /**< Micron: 10^-6m */
|
||||
Decimeter = 14, /**< Decimeter: 0.1m */
|
||||
Decameter = 15, /**< Decameter: 10m */
|
||||
Hectometer = 16, /**< Hectometer: 100m */
|
||||
Gigameter = 17, /**< Gigameter: 1000000m */
|
||||
Astro = 18, /**< Astro: 149.6 x 10^9m */
|
||||
Lightyear = 19, /**< Lightyear: 9460731798 x 10^6m */
|
||||
Parsec = 20, /**< Parsec: 30857 x 10^12 */
|
||||
|
||||
LastUnit = 21 /**< Used to iterate through units */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Format for length values.
|
||||
*/
|
||||
enum LinearFormat {
|
||||
/** Scientific (e.g. 2.5E+05) */
|
||||
Scientific,
|
||||
/** Decimal (e.g. 9.5)*/
|
||||
Decimal,
|
||||
/** Engineering (e.g. 7' 11.5")*/
|
||||
Engineering,
|
||||
/** Architectural (e.g. 7'-9 1/8")*/
|
||||
Architectural,
|
||||
/** Fractional (e.g. 7 9 1/8) */
|
||||
Fractional,
|
||||
/** Metric Architectural using DIN 406 (e.g. 1.12⁵)*/
|
||||
ArchitecturalMetric
|
||||
};
|
||||
|
||||
/**
|
||||
* Angle Units.
|
||||
*/
|
||||
enum AngleUnit {
|
||||
Deg, /**< Degrees */
|
||||
Rad, /**< Radians */
|
||||
Gra /**< Gradians */
|
||||
};
|
||||
|
||||
/**
|
||||
* Display formats for angles.
|
||||
*/
|
||||
enum AngleFormat {
|
||||
/** Degrees with decimal point (e.g. 24.5<EFBFBD>) */
|
||||
DegreesDecimal,
|
||||
/** Degrees, Minutes and Seconds (e.g. 24<32>30'5'') */
|
||||
DegreesMinutesSeconds,
|
||||
/** Gradians with decimal point (e.g. 390.5)*/
|
||||
Gradians,
|
||||
/** Radians with decimal point (e.g. 1.57)*/
|
||||
Radians,
|
||||
/** Surveyor's units */
|
||||
Surveyors
|
||||
};
|
||||
|
||||
/**
|
||||
* Enum of levels of resolving when iterating through an entity tree.
|
||||
*/
|
||||
enum ResolveLevel {
|
||||
/** Groups are not resolved */
|
||||
ResolveNone,
|
||||
/**
|
||||
* Resolve all but not Inserts.
|
||||
*/
|
||||
ResolveAllButInserts,
|
||||
/**
|
||||
* Resolve all but not Text or MText.
|
||||
*/
|
||||
ResolveAllButTexts,
|
||||
/**
|
||||
* Resolve no text or images, added as a quick fix for bug#422
|
||||
*/
|
||||
ResolveAllButTextImage,
|
||||
/**
|
||||
* all Entity Containers are resolved
|
||||
* (including Texts, Polylines, ...)
|
||||
*/
|
||||
ResolveAll
|
||||
};
|
||||
|
||||
/**
|
||||
* Direction used for scrolling actions.
|
||||
*/
|
||||
enum Direction {
|
||||
Up, Left, Right, Down
|
||||
};
|
||||
|
||||
enum SubWindowMode {
|
||||
CurrentMode = -1, Maximized, Cascade, Tile, TileVertical, TileHorizontal
|
||||
};
|
||||
|
||||
enum TabShape {
|
||||
AnyShape = -1, Rounded, Triangular
|
||||
};
|
||||
|
||||
enum TabPosition {
|
||||
AnyPosition = -1, North, South, West, East
|
||||
};
|
||||
|
||||
/**
|
||||
* Vertical alignments.
|
||||
*/
|
||||
// enum VAlign {
|
||||
// VAlignTop, /**< Top. */
|
||||
// VAlignMiddle, /**< Middle */
|
||||
// VAlignBottom /**< Bottom */
|
||||
// };
|
||||
|
||||
/**
|
||||
* Horizontal alignments.
|
||||
*/
|
||||
// enum HAlign {
|
||||
// HAlignLeft, /**< Left */
|
||||
// HAlignCenter, /**< Centered */
|
||||
// HAlignRight /**< Right */
|
||||
// };
|
||||
|
||||
/**
|
||||
* Text drawing direction.
|
||||
*/
|
||||
// enum TextDrawingDirection {
|
||||
// LeftToRight, /**< Left to right */
|
||||
// TopToBottom, /**< Top to bottom */
|
||||
// ByStyle /**< Inherited from associated text style */
|
||||
// };
|
||||
|
||||
/**
|
||||
* Line spacing style for texts.
|
||||
*/
|
||||
// enum TextLineSpacingStyle {
|
||||
// AtLeast, /**< Taller characters will override */
|
||||
// Exact /**< Taller characters will not override */
|
||||
// };
|
||||
|
||||
/**
|
||||
* Leader path type.
|
||||
*/
|
||||
enum LeaderPathType {
|
||||
Straight, /**< Straight line segments */
|
||||
Spline /**< Splines */
|
||||
};
|
||||
|
||||
/**
|
||||
* Direction for zooming actions.
|
||||
*/
|
||||
enum ZoomDirection {
|
||||
In, Out
|
||||
};
|
||||
|
||||
/**
|
||||
* Axis specification for zooming actions.
|
||||
*/
|
||||
enum Axis {
|
||||
OnlyX, OnlyY, Both
|
||||
};
|
||||
|
||||
/**
|
||||
* Crosshair type
|
||||
*/
|
||||
enum CrosshairType {
|
||||
LeftCrosshair, /**< Left type isometric Crosshair */
|
||||
TopCrosshair, /**< Top type isometric Crosshair */
|
||||
RightCrosshair, /**< Right type isometric Crosshair */
|
||||
OrthogonalCrosshair /**< Orthogonal Crosshair */
|
||||
};
|
||||
|
||||
/**
|
||||
* Snapping modes
|
||||
*/
|
||||
enum SnapMode {
|
||||
SnapFree, /**< Free positioning */
|
||||
SnapGrid, /**< Snap to grid points */
|
||||
SnapEndpoint, /**< Snap to endpoints */
|
||||
SnapMiddle, /**< Snap to middle points */
|
||||
SnapCenter, /**< Snap to centers */
|
||||
SnapOnEntity, /**< Snap to the next point on an entity */
|
||||
SnapDist, /**< Snap to points with a distance to an endpoint */
|
||||
SnapIntersection, /**< Snap to intersection */
|
||||
SnapIntersectionManual /**< Snap to intersection manually */
|
||||
};
|
||||
|
||||
/**
|
||||
* Snap restrictions
|
||||
*/
|
||||
enum SnapRestriction {
|
||||
RestrictNothing, /**< No restriction to snap mode */
|
||||
RestrictHorizontal, /**< Restrict to 0,180 degrees */
|
||||
RestrictVertical, /**< Restrict to 90,270 degrees */
|
||||
RestrictOrthogonal /**< Restrict to 90,180,270,0 degrees */
|
||||
};
|
||||
|
||||
/**
|
||||
* Enum of line styles:
|
||||
*/
|
||||
enum LineType {
|
||||
LineByBlock = -2, /**< Line type defined by block not entity */
|
||||
LineByLayer = -1, /**< Line type defined by layer not entity */
|
||||
NoPen = 0, /**< No line at all. */
|
||||
SolidLine = 1, /**< Normal line. */
|
||||
|
||||
DotLine = 2, /**< Dotted line. */
|
||||
DotLineTiny = 3, /**< Dotted line tiny */
|
||||
DotLine2 = 4, /**< Dotted line small. */
|
||||
DotLineX2 = 5, /**< Dotted line large. */
|
||||
|
||||
DashLine = 6, /**< Dashed line. */
|
||||
DashLineTiny=7, /**< Dashed line tiny */
|
||||
DashLine2 = 8, /**< Dashed line small. */
|
||||
DashLineX2 = 9, /**< Dashed line large. */
|
||||
|
||||
DashDotLine = 10, /**< Alternate dots and dashes. */
|
||||
DashDotLineTiny = 11, /**< Alternate dots and dashes tiny. */
|
||||
DashDotLine2 = 12, /**< Alternate dots and dashes small. */
|
||||
DashDotLineX2 = 13, /**< Alternate dots and dashes large. */
|
||||
|
||||
DivideLine = 14, /**< dash, dot, dot. */
|
||||
DivideLineTiny = 15, /**< dash, dot, dot, tiny */
|
||||
DivideLine2 = 16, /**< dash, dot, dot small. */
|
||||
DivideLineX2 = 17, /**< dash, dot, dot large. */
|
||||
|
||||
CenterLine = 18, /**< dash, small dash. */
|
||||
CenterLineTiny = 19, /**< dash, small dash tiny */
|
||||
CenterLine2 = 20, /**< dash, small dash small. */
|
||||
CenterLineX2 = 21, /**< dash, small dash large. */
|
||||
|
||||
BorderLine = 22, /**< dash, dash, dot. */
|
||||
BorderLineTiny = 23, /**< dash, dash, dot tiny */
|
||||
BorderLine2 = 24, /**< dash, dash, dot small. */
|
||||
BorderLineX2 = 25, /**< dash, dash, dot large. */
|
||||
|
||||
LineTypeUnchanged=26 /**< Line type defined by block not entity */
|
||||
};
|
||||
|
||||
/**
|
||||
* Enum of line widths:
|
||||
*/
|
||||
enum LineWidth {
|
||||
Width00 = 0, /**< Width 1. (0.00mm) */
|
||||
Width01 = 5, /**< Width 2. (0.05mm) */
|
||||
Width02 = 9, /**< Width 3. (0.09mm) */
|
||||
Width03 = 13, /**< Width 4. (0.13mm) */
|
||||
Width04 = 15, /**< Width 5. (0.15mm) */
|
||||
Width05 = 18, /**< Width 6. (0.18mm) */
|
||||
Width06 = 20, /**< Width 7. (0.20mm) */
|
||||
Width07 = 25, /**< Width 8. (0.25mm) */
|
||||
Width08 = 30, /**< Width 9. (0.30mm) */
|
||||
Width09 = 35, /**< Width 10. (0.35mm) */
|
||||
Width10 = 40, /**< Width 11. (0.40mm) */
|
||||
Width11 = 50, /**< Width 12. (0.50mm) */
|
||||
Width12 = 53, /**< Width 13. (0.53mm) */
|
||||
Width13 = 60, /**< Width 14. (0.60mm) */
|
||||
Width14 = 70, /**< Width 15. (0.70mm) */
|
||||
Width15 = 80, /**< Width 16. (0.80mm) */
|
||||
Width16 = 90, /**< Width 17. (0.90mm) */
|
||||
Width17 = 100, /**< Width 18. (1.00mm) */
|
||||
Width18 = 106, /**< Width 19. (1.06mm) */
|
||||
Width19 = 120, /**< Width 20. (1.20mm) */
|
||||
Width20 = 140, /**< Width 21. (1.40mm) */
|
||||
Width21 = 158, /**< Width 22. (1.58mm) */
|
||||
Width22 = 200, /**< Width 23. (2.00mm) */
|
||||
Width23 = 211, /**< Width 24. (2.11mm) */
|
||||
WidthByLayer = -1, /**< Line width defined by layer not entity. */
|
||||
WidthByBlock = -2, /**< Line width defined by block not entity. */
|
||||
WidthDefault = -3 /**< Line width defaults to the predefined line width. */
|
||||
};
|
||||
|
||||
/**
|
||||
* Wrapper for Qt
|
||||
*/
|
||||
/*
|
||||
static int qw(RS2::LineWidth w) {
|
||||
switch (w) {
|
||||
case Width00:
|
||||
return 1; // 0 is more accurate but quite slow
|
||||
break;
|
||||
case WidthByLayer:
|
||||
case WidthByBlock:
|
||||
case WidthDefault:
|
||||
return 1;
|
||||
break;
|
||||
case Width01:
|
||||
case Width02:
|
||||
case Width03:
|
||||
case Width04:
|
||||
case Width05:
|
||||
case Width06:
|
||||
case Width07:
|
||||
case Width08:
|
||||
return 1;
|
||||
break;
|
||||
case Width09:
|
||||
case Width10:
|
||||
return 3;
|
||||
break;
|
||||
case Width11:
|
||||
return 4;
|
||||
break;
|
||||
case Width12:
|
||||
case Width13:
|
||||
return 5;
|
||||
break;
|
||||
case Width14:
|
||||
return 6;
|
||||
break;
|
||||
case Width15:
|
||||
return 7;
|
||||
break;
|
||||
case Width16:
|
||||
return 8;
|
||||
break;
|
||||
case Width17:
|
||||
return 9;
|
||||
break;
|
||||
case Width18:
|
||||
case Width19:
|
||||
return 10;
|
||||
break;
|
||||
case Width20:
|
||||
return 12;
|
||||
break;
|
||||
case Width21:
|
||||
case Width22:
|
||||
case Width23:
|
||||
//case Width24:
|
||||
return 14;
|
||||
break;
|
||||
default:
|
||||
return (int)w;
|
||||
break;
|
||||
}
|
||||
return (int)w;
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Wrapper for Qt
|
||||
*/
|
||||
static LineWidth intToLineWidth(int w);
|
||||
|
||||
/**
|
||||
* Enum of cursor types.
|
||||
*/
|
||||
enum CursorType {
|
||||
ArrowCursor, /**< ArrowCursor - standard arrow cursor. */
|
||||
UpArrowCursor, /**< UpArrowCursor - upwards arrow. */
|
||||
CrossCursor, /**< CrossCursor - crosshair. */
|
||||
WaitCursor, /**< WaitCursor - hourglass/watch. */
|
||||
IbeamCursor, /**< IbeamCursor - ibeam/text entry. */
|
||||
SizeVerCursor, /**< SizeVerCursor - vertical resize. */
|
||||
SizeHorCursor, /**< SizeHorCursor - horizontal resize. */
|
||||
SizeBDiagCursor, /**< SizeBDiagCursor - diagonal resize (/). */
|
||||
SizeFDiagCursor, /**< SizeFDiagCursor - diagonal resize (\). */
|
||||
SizeAllCursor, /**< SizeAllCursor - all directions resize. */
|
||||
BlankCursor, /**< BlankCursor - blank/invisible cursor. */
|
||||
SplitVCursor, /**< SplitVCursor - vertical splitting. */
|
||||
SplitHCursor, /**< SplitHCursor - horizontal splitting. */
|
||||
PointingHandCursor, /**< PointingHandCursor - a pointing hand. */
|
||||
ForbiddenCursor, /**< ForbiddenCursor - a slashed circle. */
|
||||
WhatsThisCursor, /**< WhatsThisCursor - an arrow with a ?. */
|
||||
OpenHandCursor, /**< Qt OpenHandCursor */
|
||||
ClosedHandCursor, /**< Qt ClosedHandCursor */
|
||||
CadCursor, /**< CadCursor - a bigger cross. */
|
||||
DelCursor, /**< DelCursor - cursor for choosing entities */
|
||||
SelectCursor, /**< SelectCursor - for selecting single entities */
|
||||
MagnifierCursor, /**< MagnifierCursor - a magnifying glass. */
|
||||
MovingHandCursor /**< Moving hand - a little flat hand. */
|
||||
};
|
||||
|
||||
/**
|
||||
* Wrapper for Qt.
|
||||
*/
|
||||
/*
|
||||
static Qt::CursorShape rsToQtCursorType(RS2::CursorType t) {
|
||||
switch (t) {
|
||||
case ArrowCursor:
|
||||
return Qt::ArrowCursor;
|
||||
case UpArrowCursor:
|
||||
return Qt::UpArrowCursor;
|
||||
case CrossCursor:
|
||||
return Qt::CrossCursor;
|
||||
case WaitCursor:
|
||||
return Qt::WaitCursor;
|
||||
case IbeamCursor:
|
||||
return Qt::IBeamCursor;
|
||||
case SizeVerCursor:
|
||||
return Qt::SizeVerCursor;
|
||||
case SizeHorCursor:
|
||||
return Qt::SizeHorCursor;
|
||||
case SizeBDiagCursor:
|
||||
return Qt::SizeBDiagCursor;
|
||||
case SizeFDiagCursor:
|
||||
return Qt::SizeFDiagCursor;
|
||||
case SizeAllCursor:
|
||||
return Qt::SizeAllCursor;
|
||||
case BlankCursor:
|
||||
return Qt::BlankCursor;
|
||||
case SplitVCursor:
|
||||
return Qt::SplitVCursor;
|
||||
case SplitHCursor:
|
||||
return Qt::SplitHCursor;
|
||||
case PointingHandCursor:
|
||||
return Qt::PointingHandCursor;
|
||||
case OpenHandCursor:
|
||||
return Qt::OpenHandCursor;
|
||||
case ClosedHandCursor:
|
||||
return Qt::ClosedHandCursor;
|
||||
case ForbiddenCursor:
|
||||
return Qt::ForbiddenCursor;
|
||||
case WhatsThisCursor:
|
||||
return Qt::WhatsThisCursor;
|
||||
default:
|
||||
return Qt::ArrowCursor;
|
||||
}
|
||||
}
|
||||
*/
|
||||
/**
|
||||
* Paper formats.
|
||||
*/
|
||||
enum PaperFormat {
|
||||
FirstPaperFormat,
|
||||
Custom = FirstPaperFormat,
|
||||
|
||||
/* ISO "A" Series */
|
||||
A0, /* 841 x 1189 mm 33.1 x 46.8 in */
|
||||
A1, /* 594 x 841 mm 23.4 x 33.1 in */
|
||||
A2, /* 420 x 594 mm 16.5 x 23.4 in */
|
||||
A3, /* 297 x 420 mm 11.7 x 16.5 in */
|
||||
A4, /* 210 x 297 mm 8.3 x 11.7 in */
|
||||
|
||||
/* Removed ISO "B" and "C" series, C5E, Comm10E, DLE, (envelope sizes) */
|
||||
|
||||
/* US "Office" */
|
||||
Letter, /* 216 x 279 mm 8.5 x 11.0 in */
|
||||
Legal, /* 216 x 356 mm 8.5 x 14.0 in */
|
||||
Tabloid, /* 279 x 432 mm 11.0 x 17.0 in */
|
||||
/* Tabloid = Ledger = ANSI B. Although, technically, both ANSI B and
|
||||
Ledger are defined in the qt library as 431.8 mm x 279.4 mm / 17
|
||||
x 11", while Tabloid is 279 x 432 mm / 11.0 x 17.0 in . Using either
|
||||
"Ledger" or "AnsiB" will result in the wrong page orientation when
|
||||
printing or exporting to PDF.) */
|
||||
|
||||
/* ANSI */
|
||||
//Ansi_A, /* 216 x 279 mm 8.5 x 11.0 in */
|
||||
//Ansi_B, /* 279 x 432 mm 11.0 x 17.0 in */
|
||||
Ansi_C, /* 432 x 559 mm 17.0 x 22.0 in */
|
||||
Ansi_D, /* 559 x 864 mm 22.0 x 34.0 in */
|
||||
Ansi_E, /* 864 x 1118 mm 34.0 x 44.0 in */
|
||||
|
||||
/* Architectural */
|
||||
Arch_A, /* 229 x 305 mm 9.0 x 12.0 in */
|
||||
Arch_B, /* 305 x 457 mm 12.0 x 18.0 in */
|
||||
Arch_C, /* 457 x 610 mm 18.0 x 24.0 in */
|
||||
Arch_D, /* 610 x 914 mm 24.0 x 36.0 in */
|
||||
Arch_E, /* 914 x 1219 mm 36.0 x 48.0 in */
|
||||
|
||||
NPageFormat
|
||||
};
|
||||
|
||||
/**
|
||||
* Items that can be put on a overlay, the items are rendered in this order. Best is to leave snapper as last so
|
||||
* it always shows up
|
||||
*/
|
||||
enum OverlayGraphics {
|
||||
ActionPreviewEntity, // Action Entities
|
||||
Snapper // Snapper
|
||||
};
|
||||
|
||||
//Different re-draw methods to speed up rendering of the screen
|
||||
enum RedrawMethod {
|
||||
RedrawNone = 0,
|
||||
RedrawGrid = 1,
|
||||
RedrawOverlay = 2,
|
||||
RedrawDrawing = 4,
|
||||
RedrawAll = 0xffff
|
||||
};
|
||||
|
||||
/**
|
||||
* Text drawing direction.
|
||||
*/
|
||||
enum TextLocaleDirection {
|
||||
locLeftToRight, /** Left to right **/
|
||||
locRightToLeft /** Right to Left **/
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
1169
lib/engine/rs_arc.cpp
Normal file
1169
lib/engine/rs_arc.cpp
Normal file
File diff suppressed because it is too large
Load Diff
257
lib/engine/rs_arc.h
Normal file
257
lib/engine/rs_arc.h
Normal file
@@ -0,0 +1,257 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef RS_ARC_H
|
||||
#define RS_ARC_H
|
||||
|
||||
#include "rs_atomicentity.h"
|
||||
class LC_Quadratic;
|
||||
|
||||
|
||||
/**
|
||||
* Holds the data that defines an arc.
|
||||
*/
|
||||
struct RS_ArcData {
|
||||
RS_ArcData() = default;
|
||||
~RS_ArcData() = default;
|
||||
|
||||
RS_ArcData(const RS_Vector& center,
|
||||
double radius,
|
||||
double angle1, double angle2,
|
||||
bool reversed);
|
||||
|
||||
void reset();
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
RS_Vector center;
|
||||
double radius;
|
||||
double angle1;
|
||||
double angle2;
|
||||
bool reversed;
|
||||
};
|
||||
|
||||
std::ostream& operator << (std::ostream& os, const RS_ArcData& ad);
|
||||
|
||||
|
||||
/**
|
||||
* Class for an arc entity. All angles are in Rad.
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_Arc : public RS_AtomicEntity {
|
||||
public:
|
||||
RS_Arc()=default;
|
||||
RS_Arc(RS_EntityContainer* parent,
|
||||
const RS_ArcData& d);
|
||||
|
||||
RS_Entity* clone() const override;
|
||||
|
||||
/** @return RS2::EntityArc */
|
||||
RS2::EntityType rtti() const override
|
||||
{
|
||||
return RS2::EntityArc;
|
||||
}
|
||||
/** @return true */
|
||||
bool isEdge() const override {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @return Copy of data that defines the arc. **/
|
||||
RS_ArcData getData() const {
|
||||
return data;
|
||||
}
|
||||
|
||||
RS_VectorSolutions getRefPoints() const override;
|
||||
|
||||
/** Sets new arc parameters. **/
|
||||
void setData(RS_ArcData d) {
|
||||
data = d;
|
||||
}
|
||||
|
||||
/** @return The center point (x) of this arc */
|
||||
RS_Vector getCenter() const override {
|
||||
return data.center;
|
||||
}
|
||||
/** Sets new center. */
|
||||
void setCenter(const RS_Vector& c) {
|
||||
data.center = c;
|
||||
}
|
||||
|
||||
/** @return The radius of this arc */
|
||||
double getRadius() const override {
|
||||
return data.radius;
|
||||
}
|
||||
/** Sets new radius. */
|
||||
void setRadius(double r) {
|
||||
data.radius = r;
|
||||
}
|
||||
|
||||
/** @return The start angle of this arc */
|
||||
double getAngle1() const {
|
||||
return data.angle1;
|
||||
}
|
||||
/** Sets new start angle. */
|
||||
void setAngle1(double a1) {
|
||||
data.angle1 = a1;
|
||||
}
|
||||
/** @return The end angle of this arc */
|
||||
double getAngle2() const {
|
||||
return data.angle2;
|
||||
}
|
||||
/** Sets new end angle. */
|
||||
void setAngle2(double a2) {
|
||||
data.angle2 = a2;
|
||||
}
|
||||
/** get angle relative arc center*/
|
||||
double getArcAngle(const RS_Vector& vp) {
|
||||
return (vp - data.center).angle();
|
||||
}
|
||||
/**
|
||||
* @return Direction 1. The angle at which the arc starts at
|
||||
* the startpoint.
|
||||
*/
|
||||
double getDirection1() const override;
|
||||
/**
|
||||
* @return Direction 2. The angle at which the arc starts at
|
||||
* the endpoint.
|
||||
*/
|
||||
double getDirection2() const override;
|
||||
|
||||
/**
|
||||
* @retval true if the arc is reversed (clockwise),
|
||||
* @retval false otherwise
|
||||
*/
|
||||
bool isReversed() const {
|
||||
return data.reversed;
|
||||
}
|
||||
/** sets the reversed status. */
|
||||
void setReversed(bool r) {
|
||||
data.reversed = r;
|
||||
}
|
||||
|
||||
/** @return Start point of the entity. */
|
||||
RS_Vector getStartpoint() const override;
|
||||
/** @return End point of the entity. */
|
||||
RS_Vector getEndpoint() const override;
|
||||
std::vector<RS_Entity* > offsetTwoSides(const double& distance) const override;
|
||||
/**
|
||||
* implementations must revert the direction of an atomic entity
|
||||
*/
|
||||
void revertDirection() override;
|
||||
void correctAngles();//make sure angleLength() is not more than 2*M_PI
|
||||
void moveStartpoint(const RS_Vector& pos) override;
|
||||
void moveEndpoint(const RS_Vector& pos) override;
|
||||
bool offset(const RS_Vector& position, const double& distance) override;
|
||||
|
||||
void trimStartpoint(const RS_Vector& pos) override;
|
||||
void trimEndpoint(const RS_Vector& pos) override;
|
||||
|
||||
RS2::Ending getTrimPoint(const RS_Vector& coord,
|
||||
const RS_Vector& trimPoint) override;
|
||||
/** choose an intersection to trim to based on mouse point */
|
||||
RS_Vector prepareTrim(const RS_Vector& mousePoint,
|
||||
const RS_VectorSolutions& trimSol)override;
|
||||
|
||||
void reverse() override;
|
||||
|
||||
RS_Vector getMiddlePoint() const override;
|
||||
double getAngleLength() const;
|
||||
double getLength() const override;
|
||||
double getBulge() const;
|
||||
|
||||
bool createFrom3P(const RS_Vector& p1, const RS_Vector& p2,
|
||||
const RS_Vector& p3);
|
||||
bool createFrom2PDirectionRadius(const RS_Vector& startPoint, const RS_Vector& endPoint,
|
||||
double direction1, double radius);
|
||||
bool createFrom2PDirectionAngle(const RS_Vector& startPoint, const RS_Vector& endPoint,
|
||||
double direction1, double angleLength);
|
||||
bool createFrom2PBulge(const RS_Vector& startPoint, const RS_Vector& endPoint,
|
||||
double bulge);
|
||||
|
||||
RS_Vector getNearestEndpoint(const RS_Vector& coord,
|
||||
double* dist = nullptr) const override;
|
||||
RS_Vector getNearestPointOnEntity(const RS_Vector& coord,
|
||||
bool onEntity = true,
|
||||
double* dist = nullptr,
|
||||
RS_Entity** entity=nullptr) const override;
|
||||
RS_Vector getNearestCenter(const RS_Vector& coord,
|
||||
double* dist = nullptr) const override;
|
||||
RS_Vector getNearestMiddle(const RS_Vector& coord,
|
||||
double* dist = nullptr,
|
||||
int middlePoints = 1
|
||||
) const override;
|
||||
RS_Vector getNearestDist(double distance,
|
||||
const RS_Vector& coord,
|
||||
double* dist = nullptr) const override;
|
||||
RS_Vector getNearestDist(double distance,
|
||||
bool startp) const override;
|
||||
RS_Vector getNearestOrthTan(const RS_Vector& coord,
|
||||
const RS_Line& normal,
|
||||
bool onEntity = false) const override;
|
||||
RS_VectorSolutions getTangentPoint(const RS_Vector& point) const override;//find the tangential points seeing from given point
|
||||
RS_Vector getTangentDirection(const RS_Vector& point) const override;
|
||||
void move(const RS_Vector& offset) override;
|
||||
void rotate(const RS_Vector& center, const double& angle) override;
|
||||
void rotate(const RS_Vector& center, const RS_Vector& angleVector) override;
|
||||
void scale(const RS_Vector& center, const RS_Vector& factor) override;
|
||||
void mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) override;
|
||||
void moveRef(const RS_Vector& ref, const RS_Vector& offset) override;
|
||||
void stretch(const RS_Vector& firstCorner,
|
||||
const RS_Vector& secondCorner,
|
||||
const RS_Vector& offset) override;
|
||||
|
||||
/** find the visible part of the arc, and call drawVisible() to draw */
|
||||
void draw(RS_Painter* painter, RS_GraphicView* view, double& patternOffset) override;
|
||||
/** directly draw the arc, assuming the whole arc is within visible window */
|
||||
void drawVisible(RS_Painter* painter, RS_GraphicView* view, double& patternOffset);
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os, const RS_Arc& a);
|
||||
|
||||
virtual void calculateBorders() override;
|
||||
/** return the equation of the entity
|
||||
for quadratic,
|
||||
|
||||
return a vector contains:
|
||||
m0 x^2 + m1 xy + m2 y^2 + m3 x + m4 y + m5 =0
|
||||
|
||||
for linear:
|
||||
m0 x + m1 y + m2 =0
|
||||
**/
|
||||
virtual LC_Quadratic getQuadratic() const override;
|
||||
/**
|
||||
* @brief areaLineIntegral, line integral for contour area calculation by Green's Theorem
|
||||
* Contour Area =\oint x dy
|
||||
* @return line integral \oint x dy along the entity
|
||||
* \oint x dy = c_x r \sin t + \frac{1}{4}r^2\sin 2t + \frac{1}{2}r^2 t
|
||||
*/
|
||||
virtual double areaLineIntegral() const override;
|
||||
|
||||
protected:
|
||||
RS_ArcData data;
|
||||
};
|
||||
|
||||
#endif
|
||||
206
lib/engine/rs_atomicentity.cpp
Normal file
206
lib/engine/rs_atomicentity.cpp
Normal file
@@ -0,0 +1,206 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
|
||||
Copyright (C) 2012-2015 Dongxu Li (dongxuli2011@gmail.com)
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#include "rs_atomicentity.h"
|
||||
RS_AtomicEntity::RS_AtomicEntity(RS_EntityContainer* parent) : RS_Entity(parent) {}
|
||||
|
||||
bool RS_AtomicEntity::isContainer() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true because entities made from subclasses are
|
||||
* atomic entities.
|
||||
*/
|
||||
bool RS_AtomicEntity::isAtomic() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Always 1 for atomic entities.
|
||||
*/
|
||||
unsigned int RS_AtomicEntity::count() const{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Always 1 for atomic entities.
|
||||
*/
|
||||
unsigned int RS_AtomicEntity::countDeep() const{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation must return the endpoint of the entity or
|
||||
* an invalid vector if the entity has no endpoint.
|
||||
*/
|
||||
RS_Vector RS_AtomicEntity::getEndpoint() const {
|
||||
return RS_Vector(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation must return the startpoint of the entity or
|
||||
* an invalid vector if the entity has no startpoint.
|
||||
*/
|
||||
RS_Vector RS_AtomicEntity::getStartpoint() const {
|
||||
return RS_Vector(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation must return the angle in which direction the entity starts.
|
||||
*/
|
||||
double RS_AtomicEntity::getDirection1() const {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation must return the angle in which direction the entity starts the opposite way.
|
||||
*/
|
||||
double RS_AtomicEntity::getDirection2() const {
|
||||
return 0.0;
|
||||
}
|
||||
RS_Vector RS_AtomicEntity::getCenter() const {
|
||||
return RS_Vector(false);
|
||||
}
|
||||
double RS_AtomicEntity::getRadius() const {
|
||||
return 0.;
|
||||
}
|
||||
/**
|
||||
* return the nearest center for snapping
|
||||
* @param coord Coordinate (typically a mouse coordinate)
|
||||
* @param dist Pointer to a value which will contain the measured
|
||||
* distance between 'coord' and the closest center point. The passed
|
||||
* pointer can also be NULL in which case the distance will be
|
||||
* lost.
|
||||
*
|
||||
* @return The closest center point.
|
||||
*/
|
||||
RS_Vector RS_AtomicEntity::getNearestCenter(const RS_Vector& /*coord*/,
|
||||
double* /*dist*/) const{
|
||||
return RS_Vector(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* (De-)selects startpoint.
|
||||
*/
|
||||
void RS_AtomicEntity::setStartpointSelected(bool select) {
|
||||
if (select) {
|
||||
setFlag(RS2::FlagSelected1);
|
||||
} else {
|
||||
delFlag(RS2::FlagSelected1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* (De-)selects endpoint.
|
||||
*/
|
||||
void RS_AtomicEntity::setEndpointSelected(bool select) {
|
||||
if (select) {
|
||||
setFlag(RS2::FlagSelected2);
|
||||
} else {
|
||||
delFlag(RS2::FlagSelected2);
|
||||
}
|
||||
}
|
||||
bool RS_AtomicEntity::isTangent(const RS_CircleData& /* circleData */) const{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if the entities startpoint is selected.
|
||||
*/
|
||||
bool RS_AtomicEntity::isStartpointSelected() const {
|
||||
return getFlag(RS2::FlagSelected1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if the entities endpoint is selected.
|
||||
*/
|
||||
bool RS_AtomicEntity::isEndpointSelected() const {
|
||||
return getFlag(RS2::FlagSelected2);
|
||||
}
|
||||
|
||||
void RS_AtomicEntity::revertDirection(){}
|
||||
|
||||
/**
|
||||
* Implementation must create offset of the entity to
|
||||
* the given direction and distance
|
||||
*/
|
||||
bool RS_AtomicEntity::offset(const RS_Vector& /*position*/, const double& /*distance*/) {return false;}
|
||||
|
||||
/**
|
||||
* Implementation must move the startpoint of the entity to
|
||||
* the given position.
|
||||
*/
|
||||
void RS_AtomicEntity::moveStartpoint(const RS_Vector& /*pos*/) {}
|
||||
|
||||
/**
|
||||
* Implementation must move the endpoint of the entity to
|
||||
* the given position.
|
||||
*/
|
||||
void RS_AtomicEntity::moveEndpoint(const RS_Vector& /*pos*/) {}
|
||||
|
||||
/**
|
||||
* Implementation must trim the startpoint of the entity to
|
||||
* the given position.
|
||||
*/
|
||||
void RS_AtomicEntity::trimStartpoint(const RS_Vector& pos) {
|
||||
moveStartpoint(pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation must trim the endpoint of the entity to
|
||||
* the given position.
|
||||
*/
|
||||
void RS_AtomicEntity::trimEndpoint(const RS_Vector& pos) {
|
||||
moveEndpoint(pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation must return which ending of the entity will
|
||||
* be trimmed if 'coord' is the coordinate chosen to indicate the
|
||||
* trim entity and 'trimPoint' is the point to which the entity will
|
||||
* be trimmed.
|
||||
*/
|
||||
RS2::Ending RS_AtomicEntity::getTrimPoint(const RS_Vector& /*coord*/,
|
||||
const RS_Vector& /*trimPoint*/) {
|
||||
return RS2::EndingNone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation must trim the entity in the case of multiple
|
||||
* intersections and return the trimPoint
|
||||
* trimCoord indicts the trigger trim position
|
||||
* trimSol contains intersections
|
||||
* */
|
||||
RS_Vector RS_AtomicEntity::prepareTrim(const RS_Vector& /*trimCoord*/,
|
||||
const RS_VectorSolutions& /*trimSol*/) {
|
||||
return RS_Vector(false);
|
||||
}
|
||||
|
||||
void RS_AtomicEntity::reverse() {}
|
||||
|
||||
void RS_AtomicEntity::moveSelectedRef(const RS_Vector& ref, const RS_Vector& offset) {
|
||||
if (isSelected()) {
|
||||
moveRef(ref, offset);
|
||||
}
|
||||
}
|
||||
185
lib/engine/rs_atomicentity.h
Normal file
185
lib/engine/rs_atomicentity.h
Normal file
@@ -0,0 +1,185 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_ATOMICENTITY_H
|
||||
#define RS_ATOMICENTITY_H
|
||||
|
||||
#include "rs_entity.h"
|
||||
|
||||
struct RS_CircleData;
|
||||
|
||||
/**
|
||||
* Class representing an atomic entity
|
||||
* Typical atomic entities: RS_Line, RS_Arc, RS_Circle, RS_Ellipse
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_AtomicEntity : public RS_Entity {
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
RS_AtomicEntity(RS_EntityContainer* parent=nullptr);
|
||||
|
||||
/**
|
||||
* @return false because entities made from subclasses are
|
||||
* atomic entities.
|
||||
*/
|
||||
bool isContainer() const override;
|
||||
|
||||
/**
|
||||
* @return true because entities made from subclasses are
|
||||
* atomic entities.
|
||||
*/
|
||||
bool isAtomic() const override;
|
||||
|
||||
/**
|
||||
* @return Always 1 for atomic entities.
|
||||
*/
|
||||
unsigned count() const override;
|
||||
|
||||
/**
|
||||
* @return Always 1 for atomic entities.
|
||||
*/
|
||||
unsigned countDeep() const override;
|
||||
|
||||
/**
|
||||
* Implementation must return the endpoint of the entity or
|
||||
* an invalid vector if the entity has no endpoint.
|
||||
*/
|
||||
RS_Vector getEndpoint() const override;
|
||||
|
||||
/**
|
||||
* Implementation must return the startpoint of the entity or
|
||||
* an invalid vector if the entity has no startpoint.
|
||||
*/
|
||||
RS_Vector getStartpoint() const override;
|
||||
|
||||
/**
|
||||
* Implementation must return the angle in which direction the entity starts.
|
||||
*/
|
||||
double getDirection1() const override;
|
||||
|
||||
/**
|
||||
* Implementation must return the angle in which direction the entity starts the opposite way.
|
||||
*/
|
||||
double getDirection2() const override;
|
||||
|
||||
RS_Vector getCenter() const override;
|
||||
double getRadius() const override;
|
||||
/**
|
||||
* return the nearest center for snapping
|
||||
* @param coord Coordinate (typically a mouse coordinate)
|
||||
* @param dist Pointer to a value which will contain the measured
|
||||
* distance between 'coord' and the closest center point. The passed
|
||||
* pointer can also be NULL in which case the distance will be
|
||||
* lost.
|
||||
*
|
||||
* @return The closest center point.
|
||||
*/
|
||||
RS_Vector getNearestCenter(const RS_Vector& /*coord*/,
|
||||
double* /*dist*/) const override;
|
||||
|
||||
/**
|
||||
* (De-)selects startpoint.
|
||||
*/
|
||||
virtual void setStartpointSelected(bool select);
|
||||
|
||||
/**
|
||||
* (De-)selects endpoint.
|
||||
*/
|
||||
virtual void setEndpointSelected(bool select);
|
||||
virtual bool isTangent(const RS_CircleData& /* circleData */) const;
|
||||
|
||||
/**
|
||||
* @return True if the entities startpoint is selected.
|
||||
*/
|
||||
bool isStartpointSelected() const;
|
||||
|
||||
/**
|
||||
* @return True if the entities endpoint is selected.
|
||||
*/
|
||||
bool isEndpointSelected() const;
|
||||
|
||||
void revertDirection() override;
|
||||
|
||||
/**
|
||||
* Implementation must create offset of the entity to
|
||||
* the given direction and distance
|
||||
*/
|
||||
bool offset(const RS_Vector& /*position*/, const double& /*distance*/) override;
|
||||
|
||||
/**
|
||||
* Implementation must move the startpoint of the entity to
|
||||
* the given position.
|
||||
*/
|
||||
virtual void moveStartpoint(const RS_Vector& /*pos*/);
|
||||
|
||||
/**
|
||||
* Implementation must move the endpoint of the entity to
|
||||
* the given position.
|
||||
*/
|
||||
virtual void moveEndpoint(const RS_Vector& /*pos*/);
|
||||
|
||||
/**
|
||||
* Implementation must trim the startpoint of the entity to
|
||||
* the given position.
|
||||
*/
|
||||
virtual void trimStartpoint(const RS_Vector& pos);
|
||||
|
||||
/**
|
||||
* Implementation must trim the endpoint of the entity to
|
||||
* the given position.
|
||||
*/
|
||||
virtual void trimEndpoint(const RS_Vector& pos);
|
||||
|
||||
/**
|
||||
* Implementation must return which ending of the entity will
|
||||
* be trimmed if 'coord' is the coordinate chosen to indicate the
|
||||
* trim entity and 'trimPoint' is the point to which the entity will
|
||||
* be trimmed.
|
||||
*/
|
||||
virtual RS2::Ending getTrimPoint(const RS_Vector& /*coord*/,
|
||||
const RS_Vector& /*trimPoint*/);
|
||||
|
||||
/**
|
||||
* Implementation must trim the entity in the case of multiple
|
||||
* intersections and return the trimPoint
|
||||
* trimCoord indicts the trigger trim position
|
||||
* trimSol contains intersections
|
||||
* */
|
||||
virtual RS_Vector prepareTrim(const RS_Vector& /*trimCoord*/,
|
||||
const RS_VectorSolutions& /*trimSol*/);
|
||||
|
||||
virtual void reverse();
|
||||
|
||||
void moveSelectedRef(const RS_Vector& ref, const RS_Vector& offset) override;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
202
lib/engine/rs_block.cpp
Normal file
202
lib/engine/rs_block.cpp
Normal file
@@ -0,0 +1,202 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
#include<iostream>
|
||||
#include "rs_block.h"
|
||||
|
||||
#include "rs_graphic.h"
|
||||
#include "rs_insert.h"
|
||||
|
||||
RS_BlockData::RS_BlockData(const QString& _name,
|
||||
const RS_Vector& _basePoint,
|
||||
bool _frozen):
|
||||
name(_name)
|
||||
,basePoint(_basePoint)
|
||||
,frozen(_frozen)
|
||||
{
|
||||
}
|
||||
|
||||
bool RS_BlockData::isValid() const{
|
||||
return (!name.isEmpty() && basePoint.valid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param parent The graphic this block belongs to.
|
||||
* @param name The name of the block used as an identifier.
|
||||
* @param basePoint Base point (offset) of the block.
|
||||
*/
|
||||
RS_Block::RS_Block(RS_EntityContainer* parent,
|
||||
const RS_BlockData& d)
|
||||
: RS_Document(parent), data(d) {
|
||||
|
||||
pen = RS_Pen(RS_Color(128,128,128), RS2::Width01, RS2::SolidLine);
|
||||
}
|
||||
|
||||
|
||||
RS_Entity* RS_Block::clone() const {
|
||||
RS_Block* blk = new RS_Block(*this);
|
||||
blk->setOwner(isOwner());
|
||||
blk->detach();
|
||||
blk->initId();
|
||||
return blk;
|
||||
}
|
||||
|
||||
|
||||
|
||||
RS_LayerList* RS_Block::getLayerList() {
|
||||
RS_Graphic* g = getGraphic();
|
||||
if (g) {
|
||||
return g->getLayerList();
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
RS_BlockList* RS_Block::getBlockList() {
|
||||
RS_Graphic* g = getGraphic();
|
||||
if (g) {
|
||||
return g->getBlockList();
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool RS_Block::save(bool isAutoSave) {
|
||||
RS_Graphic* g = getGraphic();
|
||||
if (g) {
|
||||
return g->save(isAutoSave);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool RS_Block::saveAs(const QString& filename, RS2::FormatType type, bool force) {
|
||||
RS_Graphic* g = getGraphic();
|
||||
if (g) {
|
||||
return g->saveAs(filename, type, force);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Sets the parent documents modified status to 'm'.
|
||||
*/
|
||||
void RS_Block::setModified(bool m) {
|
||||
RS_Graphic* p = getGraphic();
|
||||
if (p) {
|
||||
p->setModified(m);
|
||||
}
|
||||
modified = m;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the visibility of the Block in block list
|
||||
*
|
||||
* @param v true: visible, false: invisible
|
||||
*/
|
||||
void RS_Block::visibleInBlockList(bool v) {
|
||||
data.visibleInBlockList = v;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the visibility of the Block in block list
|
||||
*/
|
||||
bool RS_Block::isVisibleInBlockList() const {
|
||||
return data.visibleInBlockList;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets selection state of the block in block list
|
||||
*
|
||||
* @param v true: selected, false: deselected
|
||||
*/
|
||||
void RS_Block::selectedInBlockList(bool v) {
|
||||
data.selectedInBlockList = v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns selection state of the block in block list
|
||||
*/
|
||||
bool RS_Block::isSelectedInBlockList() const {
|
||||
return data.selectedInBlockList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Block may contain inserts of other blocks.
|
||||
* Find name of the nested block that contain the insert
|
||||
* of specified block.
|
||||
*
|
||||
* @param bName name of the block the nested insert references to
|
||||
*
|
||||
* @return block name chain to the block that contain searched insert
|
||||
*/
|
||||
QStringList RS_Block::findNestedInsert(const QString& bName) {
|
||||
|
||||
QStringList bnChain;
|
||||
|
||||
for (RS_Entity* e: entities) {
|
||||
if (e->rtti()==RS2::EntityInsert) {
|
||||
RS_Insert* i = ((RS_Insert*)e);
|
||||
QString iName = i->getName();
|
||||
if (iName == bName) {
|
||||
bnChain << data.name;
|
||||
break;
|
||||
} else {
|
||||
RS_BlockList* bList = getBlockList();
|
||||
if (bList) {
|
||||
RS_Block* nestedBlock = bList->find(iName);
|
||||
if (nestedBlock) {
|
||||
QStringList nestedChain;
|
||||
nestedChain = nestedBlock->findNestedInsert(bName);
|
||||
if (!nestedChain.empty()) {
|
||||
bnChain << data.name;
|
||||
bnChain << nestedChain;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bnChain;
|
||||
}
|
||||
|
||||
std::ostream& operator << (std::ostream& os, const RS_Block& b) {
|
||||
os << " name: " << b.getName().toLatin1().data() << "\n";
|
||||
os << " entities: " << (RS_EntityContainer&)b << "\n";
|
||||
return os;
|
||||
}
|
||||
228
lib/engine/rs_block.h
Normal file
228
lib/engine/rs_block.h
Normal file
@@ -0,0 +1,228 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_BLOCK_H
|
||||
#define RS_BLOCK_H
|
||||
|
||||
#include "rs_document.h"
|
||||
|
||||
/**
|
||||
* Holds the data that defines a block.
|
||||
*/
|
||||
struct RS_BlockData {
|
||||
RS_BlockData() = default;
|
||||
|
||||
RS_BlockData(const QString& name,
|
||||
const RS_Vector& basePoint,
|
||||
bool frozen);
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
/**
|
||||
* Block name. Acts as an id.
|
||||
*/
|
||||
QString name;
|
||||
/**
|
||||
* Base point of the Block. Usually 0/0 since blocks can be moved around
|
||||
* using the insertion point of Insert entities.
|
||||
*/
|
||||
RS_Vector basePoint;
|
||||
|
||||
bool frozen {false}; //!< Frozen flag
|
||||
bool visibleInBlockList {true}; //!< Visible in block list
|
||||
bool selectedInBlockList {false}; //!< selected in block list
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A block is a group of entities. A block unlike an other entity
|
||||
* container has a base point which defines the offset of the
|
||||
* block. Note that although technically possible, a block should
|
||||
* never be part of the entity tree of a graphic. Blocks are
|
||||
* stored in a separate list inside the graphic document (a block list).
|
||||
* The graphic can contain RS_Insert entities that refer to such
|
||||
* blocks.
|
||||
*
|
||||
* blocks are documents and can therefore be handled by graphic views.
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_Block : public RS_Document {
|
||||
|
||||
friend class RS_BlockList;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @param parent The graphic this block belongs to.
|
||||
* @param blockData defining data of the block.
|
||||
*/
|
||||
RS_Block(RS_EntityContainer* parent, const RS_BlockData& d);
|
||||
|
||||
virtual ~RS_Block() = default;
|
||||
|
||||
virtual RS_Entity* clone() const;
|
||||
|
||||
/** @return RS2::EntityBlock */
|
||||
virtual RS2::EntityType rtti() const {
|
||||
return RS2::EntityBlock;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Name of this block (the name is an Id for this block).
|
||||
*/
|
||||
QString getName() const {
|
||||
return data.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return base point of this block.
|
||||
*/
|
||||
RS_Vector getBasePoint() const {
|
||||
return data.basePoint;
|
||||
}
|
||||
|
||||
virtual RS_LayerList* getLayerList();
|
||||
virtual RS_BlockList* getBlockList();
|
||||
|
||||
/**
|
||||
* Reimplementation from RS_Document. Does nothing.
|
||||
*/
|
||||
virtual void newDoc() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Reimplementation from RS_Document. Saves the parent graphic document.
|
||||
*/
|
||||
virtual bool save(bool isAutoSave = false);
|
||||
|
||||
/**
|
||||
* Reimplementation from RS_Document. Does nothing.
|
||||
*/
|
||||
virtual bool saveAs(const QString& filename, RS2::FormatType type, bool force = false);
|
||||
|
||||
/**
|
||||
* Reimplementation from RS_Document. Does nothing.
|
||||
*/
|
||||
virtual bool open(const QString& , RS2::FormatType) {
|
||||
// do nothing
|
||||
return false;
|
||||
}
|
||||
virtual bool loadTemplate(const QString& , RS2::FormatType) {
|
||||
// do nothing
|
||||
return false;
|
||||
}
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os, const RS_Block& b);
|
||||
|
||||
/**
|
||||
* sets a new name for the block. Only called by blocklist to
|
||||
* assure that block names stay unique.
|
||||
*/
|
||||
void setName(const QString& n) {
|
||||
data.name = n;
|
||||
}
|
||||
|
||||
/**
|
||||
* @retval true if this block is frozen (invisible)
|
||||
* @retval false if this block isn't frozen (visible)
|
||||
*/
|
||||
bool isFrozen() const {
|
||||
return data.frozen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the visibility of this block.
|
||||
* Freezes the block if it's not frozen, thaws the block otherwise
|
||||
*/
|
||||
void toggle() {
|
||||
data.frozen = !data.frozen;
|
||||
}
|
||||
|
||||
/**
|
||||
* (De-)freezes this block.
|
||||
*
|
||||
* @param freeze true: freeze, false: defreeze
|
||||
*/
|
||||
void freeze(bool freeze) {
|
||||
data.frozen = freeze;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the parent documents modified status to 'm'.
|
||||
*/
|
||||
virtual void setModified(bool m);
|
||||
|
||||
/**
|
||||
* Sets only this block modified status to 'm'
|
||||
* without touching parent document.
|
||||
*/
|
||||
void setModifiedFlag(bool m) { modified = m; }
|
||||
|
||||
/**
|
||||
* Sets the visibility of the Block in block list
|
||||
*
|
||||
* @param v true: visible, false: invisible
|
||||
*/
|
||||
void visibleInBlockList(bool v);
|
||||
|
||||
/**
|
||||
* Returns the visibility of the Block in block list
|
||||
*/
|
||||
bool isVisibleInBlockList() const;
|
||||
|
||||
/**
|
||||
* Sets selection state of the block in block list
|
||||
*
|
||||
* @param v true: selected, false: deselected
|
||||
*/
|
||||
void selectedInBlockList(bool v);
|
||||
|
||||
/**
|
||||
* Returns selection state of the block in block list
|
||||
*/
|
||||
bool isSelectedInBlockList() const;
|
||||
|
||||
/**
|
||||
* Block may contain inserts of other blocks.
|
||||
* Find name of the nested block that contain the insert
|
||||
* of specified block.
|
||||
*
|
||||
* @param bName name of the block the nested insert references to
|
||||
*
|
||||
* @return block name chain to the block that contain searched insert
|
||||
*/
|
||||
QStringList findNestedInsert(const QString& bName);
|
||||
|
||||
protected:
|
||||
//! Block data
|
||||
RS_BlockData data;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
426
lib/engine/rs_blocklist.cpp
Normal file
426
lib/engine/rs_blocklist.cpp
Normal file
@@ -0,0 +1,426 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
#include <set>
|
||||
#include <iostream>
|
||||
#include <QString>
|
||||
#include <QRegExp>
|
||||
#include "rs_debug.h"
|
||||
#include "rs_blocklist.h"
|
||||
#include "rs_block.h"
|
||||
#include "rs_blocklistlistener.h"
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param owner true if this is the owner of the blocks added.
|
||||
* If so, the blocks will be deleted when the block
|
||||
* list is deleted.
|
||||
*/
|
||||
RS_BlockList::RS_BlockList(bool owner) {
|
||||
this->owner = owner;
|
||||
//blocks.setAutoDelete(owner);
|
||||
activeBlock = nullptr;
|
||||
setModified(false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes all blocks in the blocklist.
|
||||
*/
|
||||
void RS_BlockList::clear() {
|
||||
blocks.clear();
|
||||
activeBlock = nullptr;
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Activates the given block.
|
||||
* Listeners are notified.
|
||||
*/
|
||||
void RS_BlockList::activate(const QString& name) {
|
||||
RS_DEBUG->print("RS_BlockList::activateBlock");
|
||||
|
||||
activate(find(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates the given block.
|
||||
* Listeners are notified.
|
||||
*/
|
||||
void RS_BlockList::activate(RS_Block* block) {
|
||||
RS_DEBUG->print("RS_BlockList::activateBlock");
|
||||
activeBlock = block;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds a block to the block list. If a block with the same name
|
||||
* exists already, the given block will be deleted if the blocklist
|
||||
* owns the blocks.
|
||||
*
|
||||
* @param notify true if you want listeners to be notified.
|
||||
*
|
||||
* @return false: block already existed and was deleted.
|
||||
*/
|
||||
bool RS_BlockList::add(RS_Block* block, bool notify) {
|
||||
RS_DEBUG->print("RS_BlockList::add()");
|
||||
|
||||
if (!block) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if block already exists:
|
||||
RS_Block* b = find(block->getName());
|
||||
if (!b) {
|
||||
blocks.append(block);
|
||||
|
||||
if (notify) {
|
||||
addNotification();
|
||||
}
|
||||
setModified(true);
|
||||
|
||||
return true;
|
||||
} else {
|
||||
if (owner) {
|
||||
delete block;
|
||||
block = nullptr;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Notifies the listeners about blocks that were added. This can be
|
||||
* used after adding a lot of blocks without auto-update or simply
|
||||
* to force an update of GUI blocklists.
|
||||
*/
|
||||
void RS_BlockList::addNotification() {
|
||||
for(auto l: blockListListeners){
|
||||
l->blockAdded(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Removes a block from the list.
|
||||
* Listeners are notified after the block was removed from
|
||||
* the list but before it gets deleted.
|
||||
*/
|
||||
void RS_BlockList::remove(RS_Block* block) {
|
||||
RS_DEBUG->print("RS_BlockList::removeBlock()");
|
||||
|
||||
// here the block is removed from the list but not deleted
|
||||
blocks.removeOne(block);
|
||||
|
||||
for(auto l: blockListListeners){
|
||||
l->blockRemoved(block);
|
||||
}
|
||||
|
||||
setModified(true);
|
||||
|
||||
// / *
|
||||
// activate an other block if necessary:
|
||||
if (activeBlock==block) {
|
||||
//activate(blocks.first());
|
||||
activeBlock = nullptr;
|
||||
}
|
||||
// * /
|
||||
|
||||
// now it's save to delete the block
|
||||
if (owner) {
|
||||
delete block;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Tries to rename the given block to 'name'. Block names are unique in the
|
||||
* block list.
|
||||
*
|
||||
* @retval true block was successfully renamed.
|
||||
* @retval false block couldn't be renamed.
|
||||
*/
|
||||
bool RS_BlockList::rename(RS_Block* block, const QString& name) {
|
||||
if (block) {
|
||||
if (!find(name)) {
|
||||
QString oldName = block->getName();
|
||||
block->setName(name);
|
||||
setModified(true);
|
||||
|
||||
// when the renamed block is nested within other block, we need to rename its inserts as well
|
||||
for(RS_Block* b: blocks) {
|
||||
b->renameInserts(oldName, name);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Changes a block's attributes. The attributes of block 'block'
|
||||
* are copied from block 'source'.
|
||||
* Listeners are notified.
|
||||
*/
|
||||
/*
|
||||
void RS_BlockList::editBlock(RS_Block* block, const RS_Block& source) {
|
||||
*block = source;
|
||||
|
||||
for (unsigned i=0; i<blockListListeners.count(); ++i) {
|
||||
RS_BlockListListener* l = blockListListeners.at(i);
|
||||
|
||||
l->blockEdited(block);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @return Pointer to the block with the given name or
|
||||
* \p nullptr if no such block was found.
|
||||
*/
|
||||
RS_Block* RS_BlockList::find(const QString& name) {
|
||||
try {
|
||||
RS_DEBUG->print(RS_Debug::D_DEBUGGING, "RS_BlockList::find(): %s", name.toLatin1().constData());
|
||||
}
|
||||
catch(...) {
|
||||
RS_DEBUG->print(RS_Debug::D_DEBUGGING, "RS_BlockList::find(): wrong name to find");
|
||||
return nullptr;
|
||||
}
|
||||
// Todo : reduce this from O(N) to O(log(N)) complexity based on sorted list or hash
|
||||
//DFS
|
||||
for(RS_Block* b: blocks) {
|
||||
if (b->getName()==name) {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
RS_DEBUG->print(RS_Debug::D_DEBUGGING, "RS_BlockList::find(): bad");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a new unique block name.
|
||||
*
|
||||
* @param suggestion Suggested name the new name will be based on.
|
||||
*/
|
||||
QString RS_BlockList::newName(const QString& suggestion) {
|
||||
// qDebug()<<"begin: suggestion: "<<suggestion;
|
||||
if(!find(suggestion))
|
||||
return suggestion;
|
||||
|
||||
QString name=suggestion;
|
||||
QRegExp const rx(R"(-\d+$)");
|
||||
int index=name.lastIndexOf(rx);
|
||||
int i=-1;
|
||||
if(index>0){
|
||||
i=name.mid(index+1).toInt();
|
||||
name=name.mid(0, index);
|
||||
}
|
||||
for(RS_Block* b: blocks){
|
||||
index=b->getName().lastIndexOf(rx);
|
||||
if(index<0) continue;
|
||||
QString const part1= b->getName().mid(0, index);
|
||||
if(part1 != name) continue;
|
||||
i=std::max(b->getName().mid(index+1).toInt(),i);
|
||||
}
|
||||
// qDebug()<<QString("%1-%2").arg(name).arg(i+1);
|
||||
return QString("%1-%2").arg(name).arg(i+1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches on / off the given block.
|
||||
* Listeners are notified.
|
||||
*/
|
||||
void RS_BlockList::toggle(const QString& name) {
|
||||
toggle(find(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches on / off the given block.
|
||||
* Listeners are notified.
|
||||
*/
|
||||
void RS_BlockList::toggle(RS_Block* block) {
|
||||
if (!block) {
|
||||
return;
|
||||
}
|
||||
|
||||
block->toggle();
|
||||
// TODO LordOfBikes: when block attributes are saved, activate this
|
||||
//setModified(true);
|
||||
|
||||
// Notify listeners:
|
||||
for(auto l: blockListListeners){
|
||||
l->blockToggled(block);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Freezes or defreezes all blocks.
|
||||
*
|
||||
* @param freeze true: freeze, false: defreeze
|
||||
*/
|
||||
void RS_BlockList::freezeAll(bool freeze) {
|
||||
|
||||
for (int l=0; l<count(); l++) {
|
||||
if (at(l)->isVisibleInBlockList()) {
|
||||
at(l)->freeze(freeze);
|
||||
}
|
||||
}
|
||||
// TODO LordOfBikes: when block attributes are saved, activate this
|
||||
//setModified(true);
|
||||
|
||||
for(auto l: blockListListeners){
|
||||
l->blockToggled(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Switches on / off the given block.
|
||||
* Listeners are notified.
|
||||
*/
|
||||
/*
|
||||
void RS_BlockList::toggleBlock(const QString& name) {
|
||||
RS_Block* block = findBlock(name);
|
||||
block->toggle();
|
||||
|
||||
// Notify listeners:
|
||||
for (unsigned i=0; i<blockListListeners.count(); ++i) {
|
||||
RS_BlockListListener* l = blockListListeners.at(i);
|
||||
|
||||
l->blockToggled(block);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* adds a BlockListListener to the list of listeners. Listeners
|
||||
* are notified when the block list changes.
|
||||
*/
|
||||
void RS_BlockList::addListener(RS_BlockListListener* listener) {
|
||||
blockListListeners.append(listener);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* removes a BlockListListener from the list of listeners.
|
||||
*/
|
||||
void RS_BlockList::removeListener(RS_BlockListListener* listener) {
|
||||
blockListListeners.removeOne(listener);
|
||||
}
|
||||
|
||||
int RS_BlockList::count() const{
|
||||
return blocks.count();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Block at given position or nullptr if i is out of range.
|
||||
*/
|
||||
RS_Block* RS_BlockList::at(int i) {
|
||||
return blocks.at(i);
|
||||
}
|
||||
RS_Block* RS_BlockList::at(int i) const{
|
||||
return blocks.at(i);
|
||||
}
|
||||
QList<RS_Block*>::iterator RS_BlockList::begin()
|
||||
{
|
||||
return blocks.begin();
|
||||
}
|
||||
|
||||
QList<RS_Block*>::iterator RS_BlockList::end()
|
||||
{
|
||||
return blocks.end();
|
||||
}
|
||||
|
||||
QList<RS_Block*>::const_iterator RS_BlockList::begin()const
|
||||
{
|
||||
return blocks.begin();
|
||||
}
|
||||
|
||||
QList<RS_Block*>::const_iterator RS_BlockList::end()const
|
||||
{
|
||||
return blocks.end();
|
||||
}
|
||||
|
||||
//! @return The active block of nullptr if no block is activated.
|
||||
RS_Block* RS_BlockList::getActive() {
|
||||
return activeBlock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the block list modified status to 'm'.
|
||||
*/
|
||||
void RS_BlockList::setModified(bool m) {
|
||||
modified = m;
|
||||
|
||||
// Update each block modified status,
|
||||
// but only when the status is set to false.
|
||||
if (m == false) {
|
||||
for (auto b: blocks) {
|
||||
b->setModifiedFlag(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Notify listeners
|
||||
for (auto l: blockListListeners) {
|
||||
l->blockListModified(m);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @retval true The block list has been modified.
|
||||
* @retval false The block list has not been modified.
|
||||
*/
|
||||
bool RS_BlockList::isModified() const {
|
||||
return modified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps the blocks to stdout.
|
||||
*/
|
||||
std::ostream& operator << (std::ostream& os, RS_BlockList& b) {
|
||||
|
||||
os << "Blocklist: \n";
|
||||
for (int i=0; i<b.count(); ++i) {
|
||||
RS_Block* blk = b.at(i);
|
||||
|
||||
os << *blk << "\n";
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
116
lib/engine/rs_blocklist.h
Normal file
116
lib/engine/rs_blocklist.h
Normal file
@@ -0,0 +1,116 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_BLOCKLIST_H
|
||||
#define RS_BLOCKLIST_H
|
||||
|
||||
|
||||
#include <QList>
|
||||
|
||||
class QString;
|
||||
class RS_Block;
|
||||
class RS_BlockListListener;
|
||||
|
||||
/**
|
||||
* List of blocks.
|
||||
*
|
||||
* @see RS_Block
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_BlockList {
|
||||
public:
|
||||
RS_BlockList(bool owner=false);
|
||||
virtual ~RS_BlockList() = default;
|
||||
|
||||
void clear();
|
||||
/**
|
||||
* @return Number of blocks available.
|
||||
*/
|
||||
int count() const;
|
||||
|
||||
/**
|
||||
* @return Block at given position or NULL if i is out of range.
|
||||
*/
|
||||
RS_Block* at(int i);
|
||||
RS_Block* at(int i) const;
|
||||
//! \{ \brief range based loop
|
||||
QList<RS_Block*>::iterator begin();
|
||||
QList<RS_Block*>::iterator end();
|
||||
QList<RS_Block*>::const_iterator begin()const;
|
||||
QList<RS_Block*>::const_iterator end()const;
|
||||
//! \}
|
||||
|
||||
void activate(const QString& name);
|
||||
void activate(RS_Block* block);
|
||||
//! @return The active block of NULL if no block is activated.
|
||||
RS_Block* getActive();
|
||||
|
||||
virtual bool add(RS_Block* block, bool notify=true);
|
||||
virtual void addNotification();
|
||||
virtual void remove(RS_Block* block);
|
||||
virtual bool rename(RS_Block* block, const QString& name);
|
||||
//virtual void editBlock(RS_Block* block, const RS_Block& source);
|
||||
RS_Block* find(const QString& name);
|
||||
QString newName(const QString& suggestion = "");
|
||||
void toggle(const QString& name);
|
||||
void toggle(RS_Block* block);
|
||||
void freezeAll(bool freeze);
|
||||
|
||||
void addListener(RS_BlockListListener* listener);
|
||||
void removeListener(RS_BlockListListener* listener);
|
||||
|
||||
bool isOwner() const {return owner;}
|
||||
void setOwner(bool ow) {owner = ow;}
|
||||
|
||||
/**
|
||||
* Sets the block list modified status to 'm'.
|
||||
*/
|
||||
void setModified(bool m);
|
||||
|
||||
/**
|
||||
* @retval true The block list has been modified.
|
||||
* @retval false The block list has not been modified.
|
||||
*/
|
||||
bool isModified() const;
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os, RS_BlockList& b);
|
||||
|
||||
private:
|
||||
//! Is the list owning the blocks?
|
||||
bool owner;
|
||||
//! Blocks in the graphic
|
||||
QList<RS_Block*> blocks;
|
||||
//! List of registered BlockListListeners
|
||||
QList<RS_BlockListListener*> blockListListeners;
|
||||
//! Currently active block
|
||||
RS_Block* activeBlock;
|
||||
/** Flag set if the block list was modified and not yet saved. */
|
||||
bool modified;
|
||||
};
|
||||
|
||||
#endif
|
||||
74
lib/engine/rs_blocklistlistener.h
Normal file
74
lib/engine/rs_blocklistlistener.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_BLOCKLISTLISTENER_H
|
||||
#define RS_BLOCKLISTLISTENER_H
|
||||
|
||||
#include "rs_block.h"
|
||||
|
||||
/**
|
||||
* This class is an interface for classes that are interested in
|
||||
* knowing about changes in the block list.
|
||||
*/
|
||||
class RS_BlockListListener {
|
||||
public:
|
||||
RS_BlockListListener() {}
|
||||
virtual ~RS_BlockListListener() {}
|
||||
|
||||
/**
|
||||
* Called when the active block changes.
|
||||
*/
|
||||
virtual void blockActivated(RS_Block*) {}
|
||||
|
||||
/**
|
||||
* Called when a new block is added to the list.
|
||||
*/
|
||||
virtual void blockAdded(RS_Block*) {}
|
||||
|
||||
/**
|
||||
* Called when a block is removed from the list.
|
||||
*/
|
||||
virtual void blockRemoved(RS_Block*) {}
|
||||
|
||||
/**
|
||||
* Called when a block's attributes are modified.
|
||||
*/
|
||||
virtual void blockEdited(RS_Block*) {}
|
||||
|
||||
/**
|
||||
* Called when a block's visibility is toggled.
|
||||
*/
|
||||
virtual void blockToggled(RS_Block*) {}
|
||||
|
||||
/**
|
||||
* Called when block list is modified.
|
||||
*/
|
||||
virtual void blockListModified(bool) {}
|
||||
}
|
||||
;
|
||||
|
||||
#endif
|
||||
841
lib/engine/rs_circle.cpp
Normal file
841
lib/engine/rs_circle.cpp
Normal file
@@ -0,0 +1,841 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2015 A. Stebich (librecad@mail.lordofbikes.de)
|
||||
** Copyright (C) 2011-2012 Dongxu Li (dongxuli2011@gmail.com)
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
#include <cfloat>
|
||||
#include <QPolygonF>
|
||||
#include "rs_circle.h"
|
||||
|
||||
#include "rs_arc.h"
|
||||
#include "rs_line.h"
|
||||
#include "rs_constructionline.h"
|
||||
#include "rs_information.h"
|
||||
#include "rs_graphicview.h"
|
||||
#include "rs_painter.h"
|
||||
#include "rs_linetypepattern.h"
|
||||
#include "rs_math.h"
|
||||
#include "lc_hyperbola.h"
|
||||
#include "lc_quadratic.h"
|
||||
#include "rs_debug.h"
|
||||
|
||||
RS_CircleData::RS_CircleData(RS_Vector const& center, double radius):
|
||||
center(center)
|
||||
, radius(radius)
|
||||
{
|
||||
}
|
||||
|
||||
bool RS_CircleData::isValid() const {
|
||||
return (center.valid && radius>RS_TOLERANCE);
|
||||
}
|
||||
|
||||
bool RS_CircleData::operator == (RS_CircleData const& rhs) const
|
||||
{
|
||||
if(! (center.valid && rhs.center.valid)) return false;
|
||||
if( center.squaredTo(rhs.center) > RS_TOLERANCE2) return false;
|
||||
return fabs(radius - rhs.radius)< RS_TOLERANCE;
|
||||
}
|
||||
|
||||
std::ostream& operator << (std::ostream& os, const RS_CircleData& ad)
|
||||
{
|
||||
os << "(" << ad.center <<
|
||||
"/" << ad.radius <<
|
||||
")";
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* constructor.
|
||||
*/
|
||||
RS_Circle::RS_Circle(RS_EntityContainer* parent,
|
||||
const RS_CircleData& d)
|
||||
:RS_AtomicEntity(parent), data(d) {
|
||||
calculateBorders();
|
||||
}
|
||||
|
||||
RS_Entity* RS_Circle::clone() const {
|
||||
RS_Circle* c = new RS_Circle(*this);
|
||||
c->initId();
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
void RS_Circle::calculateBorders() {
|
||||
RS_Vector r(data.radius,data.radius);
|
||||
minV = data.center - r;
|
||||
maxV = data.center + r;
|
||||
}
|
||||
|
||||
|
||||
/** @return The center point (x) of this arc */
|
||||
RS_Vector RS_Circle::getCenter() const {
|
||||
return data.center;
|
||||
}
|
||||
/** Sets new center. */
|
||||
void RS_Circle::setCenter(const RS_Vector& c) {
|
||||
data.center = c;
|
||||
}
|
||||
/** @return The radius of this arc */
|
||||
double RS_Circle::getRadius() const {
|
||||
return data.radius;
|
||||
}
|
||||
/** Sets new radius. */
|
||||
void RS_Circle::setRadius(double r) {
|
||||
data.radius = r;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Angle length in rad.
|
||||
*/
|
||||
double RS_Circle::getAngleLength() const {
|
||||
return 2*M_PI;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return Length of the circle which is the circumference.
|
||||
*/
|
||||
double RS_Circle::getLength() const {
|
||||
return 2*M_PI*data.radius;
|
||||
}
|
||||
|
||||
bool RS_Circle::isTangent(const RS_CircleData& circleData) const{
|
||||
const double d=circleData.center.distanceTo(data.center);
|
||||
// DEBUG_HEADER
|
||||
const double r0=fabs(circleData.radius);
|
||||
const double r1=fabs(data.radius);
|
||||
// std::cout<<fabs(d-fabs(r0-r1))<<" : "<<fabs(d-fabs(r0+r1))<<std::endl;
|
||||
if( fabs(d-fabs(r0-r1))<20.*RS_TOLERANCE ||
|
||||
fabs(d-fabs(r0+r1))<20.*RS_TOLERANCE ) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates this circle from a center point and a radius.
|
||||
*
|
||||
* @param c Center.
|
||||
* @param r Radius
|
||||
*/
|
||||
bool RS_Circle::createFromCR(const RS_Vector& c, double r) {
|
||||
if (fabs(r)>RS_TOLERANCE && c.valid ) {
|
||||
data.radius = fabs(r);
|
||||
data.center = c;
|
||||
return true;
|
||||
} else {
|
||||
RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Circle::createFromCR(): "
|
||||
"Cannot create a circle with radius 0.0.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates this circle from two opposite points.
|
||||
*
|
||||
* @param p1 1st point.
|
||||
* @param p2 2nd point.
|
||||
*/
|
||||
bool RS_Circle::createFrom2P(const RS_Vector& p1, const RS_Vector& p2) {
|
||||
double r=0.5*p1.distanceTo(p2);
|
||||
if (r>RS_TOLERANCE) {
|
||||
data.radius = r;
|
||||
data.center = (p1+p2)*0.5;
|
||||
return true;
|
||||
} else {
|
||||
// RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Circle::createFrom2P(): "
|
||||
// "Cannot create a circle with radius 0.0.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates this circle from 3 given points which define the circle line.
|
||||
*
|
||||
* @param p1 1st point.
|
||||
* @param p2 2nd point.
|
||||
* @param p3 3rd point.
|
||||
*/
|
||||
bool RS_Circle::createFrom3P(const RS_Vector& p1, const RS_Vector& p2,
|
||||
const RS_Vector& p3) {
|
||||
RS_Vector vra=p2 - p1;
|
||||
RS_Vector vrb=p3 - p1;
|
||||
double ra2=vra.squared()*0.5;
|
||||
double rb2=vrb.squared()*0.5;
|
||||
double crossp=vra.x * vrb.y - vra.y * vrb.x;
|
||||
if (fabs(crossp)< RS_TOLERANCE2) {
|
||||
RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Circle::createFrom3P(): "
|
||||
"Cannot create a circle with radius 0.0.");
|
||||
return false;
|
||||
}
|
||||
crossp=1./crossp;
|
||||
data.center.set((ra2*vrb.y - rb2*vra.y)*crossp,(rb2*vra.x - ra2*vrb.x)*crossp);
|
||||
data.radius=data.center.magnitude();
|
||||
data.center += p1;
|
||||
return true;
|
||||
}
|
||||
//*create Circle from 3 points
|
||||
//Author: Dongxu Li
|
||||
bool RS_Circle::createFrom3P(const RS_VectorSolutions& sol) {
|
||||
if(sol.getNumber() < 2) return false;
|
||||
if(sol.getNumber() == 2) return createFrom2P(sol.get(0),sol.get(1));
|
||||
if((sol.get(1)-sol.get(2)).squared() < RS_TOLERANCE2)
|
||||
return createFrom2P(sol.get(0),sol.get(1));
|
||||
RS_Vector vra(sol.get(1) - sol.get(0));
|
||||
RS_Vector vrb(sol.get(2) - sol.get(0));
|
||||
double ra2=vra.squared()*0.5;
|
||||
double rb2=vrb.squared()*0.5;
|
||||
double crossp=vra.x * vrb.y - vra.y * vrb.x;
|
||||
if (fabs(crossp)< RS_TOLERANCE2) {
|
||||
RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Circle::createFrom3P(): "
|
||||
"Cannot create a circle with radius 0.0.");
|
||||
return false;
|
||||
}
|
||||
crossp=1./crossp;
|
||||
data.center.set((ra2*vrb.y - rb2*vra.y)*crossp,(rb2*vra.x - ra2*vrb.x)*crossp);
|
||||
data.radius=data.center.magnitude();
|
||||
data.center += sol.get(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*create circle inscribled in a triangle
|
||||
*
|
||||
*Author: Dongxu Li
|
||||
*/
|
||||
bool RS_Circle::createInscribe(const RS_Vector& coord, const std::vector<RS_Line*>& lines){
|
||||
if(lines.size()<3) return false;
|
||||
std::vector<RS_Line*> tri(lines);
|
||||
RS_VectorSolutions sol=RS_Information::getIntersectionLineLine(tri[0],tri[1]);
|
||||
if(sol.getNumber() == 0 ) {//move parallel to opposite
|
||||
std::swap(tri[1],tri[2]);
|
||||
sol=RS_Information::getIntersectionLineLine(tri[0],tri[1]);
|
||||
}
|
||||
if(sol.getNumber() == 0 ) return false;
|
||||
RS_Vector vp0(sol.get(0));
|
||||
sol=RS_Information::getIntersectionLineLine(tri[2],tri[1]);
|
||||
if(sol.getNumber() == 0 ) return false;
|
||||
RS_Vector vp1(sol.get(0));
|
||||
RS_Vector dvp(vp1-vp0);
|
||||
double a(dvp.squared());
|
||||
if( a< RS_TOLERANCE2) return false; //three lines share a common intersecting point
|
||||
RS_Vector vp(coord - vp0);
|
||||
vp -= dvp*(RS_Vector::dotP(dvp,vp)/a); //normal component
|
||||
RS_Vector vl0(tri[0]->getEndpoint() - tri[0]->getStartpoint());
|
||||
a=dvp.angle();
|
||||
double angle0(0.5*(vl0.angle() + a));
|
||||
if( RS_Vector::dotP(vp,vl0) <0.) {
|
||||
angle0 += 0.5*M_PI;
|
||||
}
|
||||
|
||||
RS_Line line0(vp0, vp0+RS_Vector(angle0));//first bisecting line
|
||||
vl0=(tri[2]->getEndpoint() - tri[2]->getStartpoint());
|
||||
angle0=0.5*(vl0.angle() + a+M_PI);
|
||||
if( RS_Vector::dotP(vp,vl0) <0.) {
|
||||
angle0 += 0.5*M_PI;
|
||||
}
|
||||
RS_Line line1(vp1, vp1+RS_Vector(angle0));//second bisection line
|
||||
sol=RS_Information::getIntersectionLineLine(&line0,&line1);
|
||||
if(sol.getNumber() == 0 ) return false;
|
||||
|
||||
bool ret=createFromCR(sol.get(0),tri[1]->getDistanceToPoint(sol.get(0)));
|
||||
if(!ret) return false;
|
||||
for(auto p: lines){
|
||||
if(! p->isTangent(data)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<RS_Entity* > RS_Circle::offsetTwoSides(const double& distance) const
|
||||
{
|
||||
std::vector<RS_Entity*> ret(0,nullptr);
|
||||
ret.push_back(new RS_Circle(nullptr, {getCenter(),getRadius()+distance}));
|
||||
if(fabs(getRadius()-distance)>RS_TOLERANCE)
|
||||
ret.push_back(new RS_Circle(nullptr, {getCenter(),fabs(getRadius()-distance)}));
|
||||
return ret;
|
||||
}
|
||||
|
||||
RS_VectorSolutions RS_Circle::createTan1_2P(const RS_AtomicEntity* circle, const std::vector<RS_Vector>& points)
|
||||
{
|
||||
RS_VectorSolutions ret;
|
||||
if (!circle||points.size()<2) return ret;
|
||||
return LC_Quadratic::getIntersection(
|
||||
LC_Quadratic(circle,points[0]),
|
||||
LC_Quadratic(circle,points[1])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* create a circle of radius r and tangential to two given entities
|
||||
*/
|
||||
RS_VectorSolutions RS_Circle::createTan2(const std::vector<RS_AtomicEntity*>& circles, const double& r)
|
||||
{
|
||||
if(circles.size()<2) return false;
|
||||
auto e0=circles[0]->offsetTwoSides(r);
|
||||
auto e1=circles[1]->offsetTwoSides(r);
|
||||
RS_VectorSolutions centers;
|
||||
if(e0.size() && e1.size()) {
|
||||
for(auto it0=e0.begin();it0!=e0.end();it0++){
|
||||
for(auto it1=e1.begin();it1!=e1.end();it1++){
|
||||
centers.push_back(RS_Information::getIntersection(*it0,*it1));
|
||||
}
|
||||
}
|
||||
}
|
||||
for(auto it0=e0.begin();it0!=e0.end();it0++){
|
||||
delete *it0;
|
||||
}
|
||||
for(auto it0=e1.begin();it0!=e1.end();it0++){
|
||||
delete *it0;
|
||||
}
|
||||
return centers;
|
||||
|
||||
}
|
||||
|
||||
std::vector<RS_Circle> RS_Circle::createTan3(const std::vector<RS_AtomicEntity*>& circles)
|
||||
{
|
||||
std::vector<RS_Circle> ret;
|
||||
if(circles.size()!=3) return ret;
|
||||
std::vector<RS_Circle> cs;
|
||||
for(auto c: circles){
|
||||
cs.emplace_back(RS_Circle(nullptr, {c->getCenter(),c->getRadius()}));
|
||||
}
|
||||
unsigned short flags=0;
|
||||
do{
|
||||
for(unsigned short j=0u;j<3u;++j){
|
||||
if(flags & (1u<<j)) {
|
||||
cs[j].setRadius( - fabs(cs[j].getRadius()));
|
||||
}else{
|
||||
cs[j].setRadius( fabs(cs[j].getRadius()));
|
||||
}
|
||||
}
|
||||
// RS_DEBUG->print(RS_Debug::D_ERROR, "flags=%d\n",flags);
|
||||
auto list=solveAppolloniusSingle(cs);
|
||||
if(list.size()>=1){
|
||||
for(RS_Circle& c0: list){
|
||||
bool addNew=true;
|
||||
for(RS_Circle& c: ret){
|
||||
if((c0.getCenter()-c.getCenter()).squared()<RS_TOLERANCE15 && fabs(c0.getRadius() - c.getRadius())<RS_TOLERANCE){
|
||||
addNew=false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(addNew) ret.push_back(c0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}while(++flags<8u);
|
||||
// std::cout<<__FILE__<<" : "<<__func__<<" : line "<<__LINE__<<std::endl;
|
||||
// std::cout<<"before testing, ret.size()="<<ret.size()<<std::endl;
|
||||
for(size_t i=0;i<ret.size();){
|
||||
if(ret[i].testTan3(circles) == false) {
|
||||
ret.erase(ret.begin()+i);
|
||||
}else{
|
||||
++i;
|
||||
}
|
||||
}
|
||||
// DEBUG_HEADER
|
||||
// std::cout<<"after testing, ret.size()="<<ret.size()<<std::endl;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool RS_Circle::testTan3(const std::vector<RS_AtomicEntity*>& circles)
|
||||
{
|
||||
|
||||
if(circles.size()!=3) return false;
|
||||
|
||||
// std::cout<<__FILE__<<" : "<<__func__<<" : line "<<__LINE__<<std::endl;
|
||||
// std::cout<<"to verify Center = ( "<<data.center.x<<" , "<<data.center.y<<" ), r= "<<data.radius<<std::endl;
|
||||
for(auto const& c: circles){
|
||||
const double r0 = fabs(data.radius);
|
||||
const double r1 = fabs(c->getRadius());
|
||||
|
||||
const double dist=fabs((data.center - c->getCenter()).magnitude());
|
||||
// DEBUG_HEADER
|
||||
// std::cout<<"testing: "<<getCenter()<<" r="<<getRadius()<<". \twith Center = ( "<<(*it)->getCenter().x<<" , "<<(*it)->getCenter().y<<" ), r= "<<(*it)->getRadius()<<std::endl;
|
||||
// std::cout<<"r0="<<r0<<"\tr1="<<r1<<"\tdist="<<dist<<"\tdelta0="<<fabs(dist - fabs(r0 - r1)) <<"\tdelta1="<<fabs(dist - fabs(r0 + r1))
|
||||
// <<"\t"<<sqrt(DBL_EPSILON)*qMax(r0,r1)<<std::endl;
|
||||
|
||||
double const rmax=std::max(r0,r1);
|
||||
if( dist < rmax )
|
||||
return fabs(dist - fabs(r0 - r1)) <= sqrt(DBL_EPSILON)*rmax;
|
||||
else
|
||||
return fabs(dist - fabs(r0 + r1)) <= sqrt(DBL_EPSILON)*rmax;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** solve one of the eight Appollonius Equations
|
||||
| Cx - Ci|^2=(Rx+Ri)^2
|
||||
with Cx the center of the common tangent circle, Rx the radius. Ci and Ri are the Center and radius of the i-th existing circle
|
||||
**/
|
||||
std::vector<RS_Circle> RS_Circle::solveAppolloniusSingle(const std::vector<RS_Circle>& circles)
|
||||
{
|
||||
// std::cout<<__FILE__<<" : "<<__func__<<" : line "<<__LINE__<<std::endl;
|
||||
// for(int i=0;i<circles.size();i++){
|
||||
//std::cout<<"i="<<i<<"\t center="<<circles[i].getCenter()<<"\tr="<<circles[i].getRadius()<<std::endl;
|
||||
// }
|
||||
std::vector<RS_Circle> ret;
|
||||
|
||||
std::vector<RS_Vector> centers;
|
||||
std::vector<double> radii;
|
||||
|
||||
for(auto c: circles){
|
||||
if(c.getCenter().valid==false) return ret;
|
||||
centers.push_back(c.getCenter());
|
||||
radii.push_back(c.getRadius());
|
||||
}
|
||||
// for(int i=0;i<circles.size();i++){
|
||||
// std::cout<<"i="<<i<<"\t center="<<circles[i].getCenter()<<"\tr="<<radii.at(i)<<std::endl;
|
||||
// }
|
||||
/** form the linear equation to solve center in radius **/
|
||||
std::vector<std::vector<double> > mat(2,std::vector<double>(3,0.));
|
||||
mat[0][0]=centers[2].x - centers[0].x;
|
||||
mat[0][1]=centers[2].y - centers[0].y;
|
||||
mat[1][0]=centers[2].x - centers[1].x;
|
||||
mat[1][1]=centers[2].y - centers[1].y;
|
||||
if(fabs(mat[0][0]*mat[1][1] - mat[0][1]*mat[1][0])<RS_TOLERANCE2){
|
||||
// DEBUG_HEADER
|
||||
// std::cout<<"The provided circles are in a line, not common tangent circle"<<std::endl;
|
||||
size_t i0=0;
|
||||
if( centers[0].distanceTo(centers[1]) <= RS_TOLERANCE || centers[0].distanceTo(centers[2]) <= RS_TOLERANCE) i0 = 1;
|
||||
LC_Quadratic lc0(& (circles[i0]), & (circles[(i0+1)%3]));
|
||||
LC_Quadratic lc1(& (circles[i0]), & (circles[(i0+2)%3]));
|
||||
auto c0 = LC_Quadratic::getIntersection(lc0, lc1);
|
||||
// qDebug()<<"c0.size()="<<c0.size();
|
||||
for(size_t i=0; i<c0.size(); i++){
|
||||
const double dc = c0[i].distanceTo(centers[i0]);
|
||||
ret.push_back(RS_Circle(nullptr, {c0[i], fabs(dc - radii[i0])}));
|
||||
if( dc > radii[i0]) {
|
||||
ret.push_back(RS_Circle(nullptr, {c0[i], dc + radii[i0]}));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
// r^0 term
|
||||
mat[0][2]=0.5*(centers[2].squared()-centers[0].squared()+radii[0]*radii[0]-radii[2]*radii[2]);
|
||||
mat[1][2]=0.5*(centers[2].squared()-centers[1].squared()+radii[1]*radii[1]-radii[2]*radii[2]);
|
||||
// std::cout<<__FILE__<<" : "<<__func__<<" : line "<<__LINE__<<std::endl;
|
||||
// for(unsigned short i=0;i<=1;i++){
|
||||
// std::cout<<"eqs P:"<<i<<" : "<<mat[i][0]<<"*x + "<<mat[i][1]<<"*y = "<<mat[i][2]<<std::endl;
|
||||
// }
|
||||
// std::vector<std::vector<double> > sm(2,std::vector<double>(2,0.));
|
||||
std::vector<double> sm(2,0.);
|
||||
if(RS_Math::linearSolver(mat,sm)==false){
|
||||
return ret;
|
||||
}
|
||||
|
||||
RS_Vector vp(sm[0],sm[1]);
|
||||
// std::cout<<__FILE__<<" : "<<__func__<<" : line "<<__LINE__<<std::endl;
|
||||
// std::cout<<"vp="<<vp<<std::endl;
|
||||
|
||||
// r term
|
||||
mat[0][2]= radii[0]-radii[2];
|
||||
mat[1][2]= radii[1]-radii[2];
|
||||
// for(unsigned short i=0;i<=1;i++){
|
||||
// std::cout<<"eqs Q:"<<i<<" : "<<mat[i][0]<<"*x + "<<mat[i][1]<<"*y = "<<mat[i][2]<<std::endl;
|
||||
// }
|
||||
if(RS_Math::linearSolver(mat,sm)==false){
|
||||
return ret;
|
||||
}
|
||||
RS_Vector vq(sm[0],sm[1]);
|
||||
// std::cout<<"vq="<<vq<<std::endl;
|
||||
//form quadratic equation for r
|
||||
RS_Vector dcp=vp-centers[0];
|
||||
double a=vq.squared()-1.;
|
||||
if(fabs(a)<RS_TOLERANCE*1e-4) {
|
||||
return ret;
|
||||
}
|
||||
std::vector<double> ce(0,0.);
|
||||
ce.push_back(2.*(dcp.dotP(vq)-radii[0])/a);
|
||||
ce.push_back((dcp.squared()-radii[0]*radii[0])/a);
|
||||
std::vector<double>&& vr=RS_Math::quadraticSolver(ce);
|
||||
for(size_t i=0; i < vr.size();i++){
|
||||
if(vr.at(i)<RS_TOLERANCE) continue;
|
||||
ret.emplace_back(RS_Circle(nullptr, {vp+vq*vr.at(i),fabs(vr.at(i))}));
|
||||
}
|
||||
// std::cout<<__FILE__<<" : "<<__func__<<" : line "<<__LINE__<<std::endl;
|
||||
// std::cout<<"Found "<<ret.size()<<" solutions"<<std::endl;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
RS_VectorSolutions RS_Circle::getRefPoints() const
|
||||
{
|
||||
RS_Vector v1(data.radius, 0.0);
|
||||
RS_Vector v2(0.0, data.radius);
|
||||
|
||||
return RS_VectorSolutions ({data.center,
|
||||
data.center+v1, data.center+v2,
|
||||
data.center-v1, data.center-v2});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief compute nearest endpoint, intersection with X/Y axis at 0, 90, 180 and 270 degree
|
||||
*
|
||||
* Use getNearestMiddle() method to compute the nearest circle quadrant endpoints
|
||||
*
|
||||
* @param coord coordinates to compute, e.g. mouse cursor position
|
||||
* @param dist double pointer to return distance between mouse pointer and nearest entity point
|
||||
* @return the nearest intersection of the circle with X/Y axis.
|
||||
*/
|
||||
RS_Vector RS_Circle::getNearestEndpoint(const RS_Vector& coord, double* dist /*= nullptr*/) const
|
||||
{
|
||||
return getNearestMiddle( coord, dist, 0);
|
||||
}
|
||||
|
||||
|
||||
RS_Vector RS_Circle::getNearestPointOnEntity(const RS_Vector& coord,
|
||||
bool /*onEntity*/, double* dist, RS_Entity** entity)const {
|
||||
|
||||
if (entity) {
|
||||
*entity = const_cast<RS_Circle*>(this);
|
||||
}
|
||||
RS_Vector vp(coord - data.center);
|
||||
double d(vp.magnitude());
|
||||
if( d < RS_TOLERANCE ) return RS_Vector(false);
|
||||
vp =data.center+vp*(data.radius/d);
|
||||
// RS_DEBUG->print(RS_Debug::D_ERROR, "circle(%g, %g), r=%g: distance to point (%g, %g)\n",data.center.x,data.center.y,coord.x,coord.y);
|
||||
|
||||
if(dist){
|
||||
*dist=coord.distanceTo(vp);
|
||||
// RS_DEBUG->print(RS_Debug::D_ERROR, "circle(%g, %g), r=%g: distance to point (%g, %g)=%g\n",data.center.x,data.center.y,coord.x,coord.y,*dist);
|
||||
}
|
||||
return vp;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*find the tangential points from a given point, i.e., the tangent lines should pass
|
||||
* the given point and tangential points
|
||||
*
|
||||
*Author: Dongxu Li
|
||||
*/
|
||||
RS_VectorSolutions RS_Circle::getTangentPoint(const RS_Vector& point) const {
|
||||
RS_VectorSolutions ret;
|
||||
double r2(getRadius()*getRadius());
|
||||
if(r2<RS_TOLERANCE2) return ret; //circle too small
|
||||
RS_Vector vp(point-getCenter());
|
||||
double c2(vp.squared());
|
||||
if(c2<r2-getRadius()*2.*RS_TOLERANCE) {
|
||||
//inside point, no tangential point
|
||||
return ret;
|
||||
}
|
||||
if(c2>r2+getRadius()*2.*RS_TOLERANCE) {
|
||||
//external point
|
||||
RS_Vector vp1(-vp.y,vp.x);
|
||||
vp1*=getRadius()*sqrt(c2-r2)/c2;
|
||||
vp *= r2/c2;
|
||||
vp += getCenter();
|
||||
if(vp1.squared()>RS_TOLERANCE2) {
|
||||
ret.push_back(vp+vp1);
|
||||
ret.push_back(vp-vp1);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
ret.push_back(point);
|
||||
return ret;
|
||||
}
|
||||
RS_Vector RS_Circle::getTangentDirection(const RS_Vector& point) const {
|
||||
RS_Vector vp(point-getCenter());
|
||||
// double c2(vp.squared());
|
||||
// if(c2<r2-getRadius()*2.*RS_TOLERANCE) {
|
||||
// //inside point, no tangential point
|
||||
// return RS_Vector(false);
|
||||
// }
|
||||
return RS_Vector(-vp.y,vp.x);
|
||||
|
||||
}
|
||||
|
||||
RS_Vector RS_Circle::getNearestCenter(const RS_Vector& coord,
|
||||
double* dist) const{
|
||||
if (dist) {
|
||||
*dist = coord.distanceTo(data.center);
|
||||
}
|
||||
return data.center;
|
||||
}
|
||||
|
||||
|
||||
|
||||
RS_Vector RS_Circle::getMiddlePoint(void)const
|
||||
{
|
||||
return RS_Vector(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief compute middlePoints for each quadrant of a circle
|
||||
*
|
||||
* 0 middlePoints snaps to axis intersection at 0, 90, 180 and 270 degree (getNearestEndpoint) \n
|
||||
* 1 middlePoints snaps to 45, 135, 225 and 315 degree \n
|
||||
* 2 middlePoints snaps to 30, 60, 120, 150, 210, 240, 300 and 330 degree \n
|
||||
* and so on
|
||||
*
|
||||
* @param coord coordinates to compute, e.g. mouse cursor position
|
||||
* @param dist double pointer to return distance between mouse pointer and nearest entity point
|
||||
* @param middlePoints number of middle points to compute per quadrant (0 for endpoints)
|
||||
* @return the nearest of equidistant middle points of the circles quadrants.
|
||||
*/
|
||||
RS_Vector RS_Circle::getNearestMiddle(const RS_Vector& coord,
|
||||
double* dist /*= nullptr*/,
|
||||
const int middlePoints /*= 1*/) const
|
||||
{
|
||||
if( data.radius <= RS_TOLERANCE) {
|
||||
//circle too short
|
||||
if ( nullptr != dist) {
|
||||
*dist = RS_MAXDOUBLE;
|
||||
}
|
||||
return RS_Vector(false);
|
||||
}
|
||||
|
||||
RS_Vector vPoint( getNearestPointOnEntity( coord, true, dist));
|
||||
int iCounts = middlePoints + 1;
|
||||
double dAngleSteps = M_PI_2 / iCounts;
|
||||
double dAngleToPoint = data.center.angleTo(vPoint);
|
||||
int iStepCount = static_cast<int>((dAngleToPoint + 0.5 * dAngleSteps) / dAngleSteps);
|
||||
if( 0 < middlePoints) {
|
||||
// for nearest middle eliminate start/endpoints
|
||||
int iQuadrant = static_cast<int>(dAngleToPoint / 0.5 / M_PI);
|
||||
int iQuadrantStep = iStepCount - iQuadrant * iCounts;
|
||||
if( 0 == iQuadrantStep) {
|
||||
++iStepCount;
|
||||
}
|
||||
else if( iCounts == iQuadrantStep) {
|
||||
--iStepCount;
|
||||
}
|
||||
}
|
||||
|
||||
vPoint.setPolar( data.radius, dAngleSteps * iStepCount);
|
||||
vPoint.move( data.center);
|
||||
|
||||
if(dist) {
|
||||
*dist = vPoint.distanceTo( coord);
|
||||
}
|
||||
|
||||
return vPoint;
|
||||
}
|
||||
|
||||
|
||||
RS_Vector RS_Circle::getNearestDist(double /*distance*/,
|
||||
const RS_Vector& /*coord*/,
|
||||
double* dist) const{
|
||||
|
||||
if (dist) {
|
||||
*dist = RS_MAXDOUBLE;
|
||||
}
|
||||
return RS_Vector(false);
|
||||
}
|
||||
|
||||
RS_Vector RS_Circle::getNearestDist(double /*distance*/,
|
||||
bool /*startp*/) const{
|
||||
|
||||
return RS_Vector(false);
|
||||
}
|
||||
|
||||
|
||||
RS_Vector RS_Circle::getNearestOrthTan(const RS_Vector& coord,
|
||||
const RS_Line& normal,
|
||||
bool /*onEntity = false*/) const
|
||||
{
|
||||
if ( !coord.valid) {
|
||||
return RS_Vector(false);
|
||||
}
|
||||
RS_Vector vp0(coord-getCenter());
|
||||
RS_Vector vp1(normal.getAngle1());
|
||||
double d=RS_Vector::dotP(vp0,vp1);
|
||||
if(d >= 0. ) {
|
||||
return getCenter() + vp1*getRadius();
|
||||
}else{
|
||||
return getCenter() - vp1*getRadius();
|
||||
}
|
||||
}
|
||||
|
||||
void RS_Circle::move(const RS_Vector& offset) {
|
||||
data.center.move(offset);
|
||||
moveBorders(offset);
|
||||
// calculateBorders();
|
||||
}
|
||||
|
||||
/**
|
||||
* this function creates offset
|
||||
*@coord, position indicates the direction of offset
|
||||
*@distance, distance of offset
|
||||
* return true, if success, otherwise, false
|
||||
*
|
||||
*Author: Dongxu Li
|
||||
*/
|
||||
bool RS_Circle::offset(const RS_Vector& coord, const double& distance) {
|
||||
double r0(coord.distanceTo(getCenter()));
|
||||
if(r0 > getRadius()){
|
||||
//external
|
||||
r0 = getRadius()+ fabs(distance);
|
||||
}else{
|
||||
r0 = getRadius()- fabs(distance);
|
||||
if(r0<RS_TOLERANCE) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
setRadius(r0);
|
||||
calculateBorders();
|
||||
return true;
|
||||
}
|
||||
|
||||
void RS_Circle::rotate(const RS_Vector& center, const double& angle) {
|
||||
data.center.rotate(center, angle);
|
||||
calculateBorders();
|
||||
}
|
||||
|
||||
void RS_Circle::rotate(const RS_Vector& center, const RS_Vector& angleVector) {
|
||||
data.center.rotate(center, angleVector);
|
||||
calculateBorders();
|
||||
}
|
||||
|
||||
void RS_Circle::scale(const RS_Vector& center, const RS_Vector& factor) {
|
||||
data.center.scale(center, factor);
|
||||
//radius always is positive
|
||||
data.radius *= fabs(factor.x);
|
||||
scaleBorders(center,factor);
|
||||
// calculateBorders();
|
||||
}
|
||||
|
||||
double RS_Circle::getDirection1() const{
|
||||
return M_PI_2;
|
||||
}
|
||||
|
||||
double RS_Circle::getDirection2() const{
|
||||
return M_PI_2*3.0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_Circle::mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) {
|
||||
data.center.mirror(axisPoint1, axisPoint2);
|
||||
calculateBorders();
|
||||
}
|
||||
|
||||
|
||||
/** whether the entity's bounding box intersects with visible portion of graphic view
|
||||
//fix me, need to handle overlay container separately
|
||||
*/
|
||||
bool RS_Circle::isVisibleInWindow(RS_GraphicView* view) const
|
||||
{
|
||||
|
||||
RS_Vector vpMin(view->toGraph(0,view->getHeight()));
|
||||
RS_Vector vpMax(view->toGraph(view->getWidth(),0));
|
||||
QPolygonF visualBox(QRectF(vpMin.x,vpMin.y,vpMax.x-vpMin.x, vpMax.y-vpMin.y));
|
||||
std::vector<RS_Vector> vps;
|
||||
for(unsigned short i=0;i<4;i++){
|
||||
const QPointF& vp(visualBox.at(i));
|
||||
vps.emplace_back(vp.x(),vp.y());
|
||||
}
|
||||
for(unsigned short i=0;i<4;i++){
|
||||
RS_Line line{nullptr, {vps.at(i),vps.at((i+1)%4)}};
|
||||
RS_Circle c0{nullptr, getData()};
|
||||
if( RS_Information::getIntersection(&c0, &line, true).size()>0) return true;
|
||||
}
|
||||
if( getCenter().isInWindowOrdered(vpMin,vpMax)==false) return false;
|
||||
return (vpMin-getCenter()).squared() > getRadius()*getRadius();
|
||||
}
|
||||
|
||||
|
||||
void RS_Circle::draw(RS_Painter* painter, RS_GraphicView* view, double& /*patternOffset*/) {
|
||||
// // draw circle as a 2 pi arc
|
||||
// RS_Arc arc(getParent(), RS_ArcData(getCenter(),getRadius(),0.,2.*M_PI, false));
|
||||
// arc.setSelected(isSelected());
|
||||
// arc.setPen(getPen());
|
||||
// arc.draw(painter,view,patternOffset);
|
||||
|
||||
painter->drawCircle(view->toGui(getCenter()), view->toGuiDX(getRadius()));
|
||||
}
|
||||
|
||||
|
||||
void RS_Circle::moveRef(const RS_Vector& ref, const RS_Vector& offset) {
|
||||
if(ref.distanceTo(data.center)<1.0e-4){
|
||||
data.center += offset;
|
||||
return;
|
||||
}
|
||||
RS_Vector v1(data.radius, 0.0);
|
||||
RS_VectorSolutions sol;
|
||||
sol.push_back(data.center + v1);
|
||||
sol.push_back(data.center - v1);
|
||||
v1.set(0., data.radius);
|
||||
sol.push_back(data.center + v1);
|
||||
sol.push_back(data.center - v1);
|
||||
double dist;
|
||||
v1=sol.getClosest(ref,&dist);
|
||||
if(dist>1.0e-4) return;
|
||||
data.radius = data.center.distanceTo(v1 + offset);
|
||||
}
|
||||
|
||||
|
||||
/** return the equation of the entity
|
||||
for quadratic,
|
||||
|
||||
return a vector contains:
|
||||
m0 x^2 + m1 xy + m2 y^2 + m3 x + m4 y + m5 =0
|
||||
|
||||
for linear:
|
||||
m0 x + m1 y + m2 =0
|
||||
**/
|
||||
LC_Quadratic RS_Circle::getQuadratic() const
|
||||
{
|
||||
std::vector<double> ce(6,0.);
|
||||
ce[0]=1.;
|
||||
ce[2]=1.;
|
||||
ce[5]=-data.radius*data.radius;
|
||||
LC_Quadratic ret(ce);
|
||||
ret.move(data.center);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Returns area of full circle
|
||||
* Note: Circular arcs are handled separately by RS_Arc (areaLIneIntegral)
|
||||
* However, full ellipses and ellipse arcs are handled by RS_Ellipse
|
||||
* @return \pi r^2
|
||||
*/
|
||||
double RS_Circle::areaLineIntegral() const
|
||||
{
|
||||
const double r = getRadius();
|
||||
|
||||
return M_PI*r*r;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Dumps the circle's data to stdout.
|
||||
*/
|
||||
std::ostream& operator << (std::ostream& os, const RS_Circle& a) {
|
||||
os << " Circle: " << a.data << "\n";
|
||||
return os;
|
||||
}
|
||||
|
||||
186
lib/engine/rs_circle.h
Normal file
186
lib/engine/rs_circle.h
Normal file
@@ -0,0 +1,186 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2015 A. Stebich (librecad@mail.lordofbikes.de)
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_CIRCLE_H
|
||||
#define RS_CIRCLE_H
|
||||
|
||||
#include <vector>
|
||||
#include "rs_atomicentity.h"
|
||||
|
||||
class LC_Quadratic;
|
||||
|
||||
/**
|
||||
* Holds the data that defines a circle.
|
||||
*/
|
||||
struct RS_CircleData {
|
||||
RS_CircleData() = default;
|
||||
RS_CircleData(RS_Vector const& center, double radius);
|
||||
bool isValid() const;
|
||||
bool operator == (RS_CircleData const&) const;
|
||||
RS_Vector center;
|
||||
double radius;
|
||||
};
|
||||
|
||||
std::ostream& operator << (std::ostream& os, const RS_CircleData& ad);
|
||||
|
||||
/**
|
||||
* Class for a circle entity.
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_Circle : public RS_AtomicEntity {
|
||||
public:
|
||||
RS_Circle()=default;
|
||||
RS_Circle (RS_EntityContainer* parent,
|
||||
const RS_CircleData& d);
|
||||
~RS_Circle() = default;
|
||||
|
||||
RS_Entity* clone() const override;
|
||||
|
||||
/** @return RS2::EntityCircle */
|
||||
RS2::EntityType rtti() const override{
|
||||
return RS2::EntityCircle;
|
||||
}
|
||||
/** @return true */
|
||||
bool isEdge() const override{
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @return Copy of data that defines the circle. **/
|
||||
const RS_CircleData& getData() const {
|
||||
return data;
|
||||
}
|
||||
|
||||
RS_VectorSolutions getRefPoints() const override;
|
||||
|
||||
//no start/end point for whole circle
|
||||
// RS_Vector getStartpoint() const {
|
||||
// return data.center + RS_Vector(data.radius, 0.0);
|
||||
// }
|
||||
// RS_Vector getEndpoint() const {
|
||||
// return data.center + RS_Vector(data.radius, 0.0);
|
||||
// }
|
||||
/**
|
||||
* @return Direction 1. The angle at which the arc starts at
|
||||
* the startpoint.
|
||||
*/
|
||||
double getDirection1() const override;
|
||||
/**
|
||||
* @return Direction 2. The angle at which the arc starts at
|
||||
* the endpoint.
|
||||
*/
|
||||
double getDirection2() const override;
|
||||
|
||||
/** @return The center point (x) of this arc */
|
||||
RS_Vector getCenter() const override;
|
||||
/** Sets new center. */
|
||||
void setCenter(const RS_Vector& c);
|
||||
/** @return The radius of this arc */
|
||||
double getRadius() const override;
|
||||
/** Sets new radius. */
|
||||
void setRadius(double r);
|
||||
double getAngleLength() const;
|
||||
double getLength() const override;
|
||||
bool isTangent(const RS_CircleData& circleData) const override;
|
||||
|
||||
bool createFromCR(const RS_Vector& c, double r);
|
||||
bool createFrom2P(const RS_Vector& p1, const RS_Vector& p2);
|
||||
bool createFrom3P(const RS_Vector& p1, const RS_Vector& p2,
|
||||
const RS_Vector& p3);
|
||||
bool createFrom3P(const RS_VectorSolutions& sol);
|
||||
bool createInscribe(const RS_Vector& coord, const std::vector<RS_Line*>& lines);
|
||||
std::vector<RS_Entity* > offsetTwoSides(const double& distance) const override;
|
||||
RS_VectorSolutions createTan1_2P(const RS_AtomicEntity* circle, const std::vector<RS_Vector>& points);
|
||||
static RS_VectorSolutions createTan2(const std::vector<RS_AtomicEntity*>& circles, const double& r);
|
||||
/** solve one of the eight Appollonius Equations
|
||||
| Cx - Ci|^2=(Rx+Ri)^2
|
||||
with Cx the center of the common tangent circle, Rx the radius. Ci and Ri are the Center and radius of the i-th existing circle
|
||||
**/
|
||||
static std::vector<RS_Circle> solveAppolloniusSingle(const std::vector<RS_Circle>& circles);
|
||||
|
||||
std::vector<RS_Circle> createTan3(const std::vector<RS_AtomicEntity*>& circles);
|
||||
bool testTan3(const std::vector<RS_AtomicEntity*>& circles);
|
||||
RS_Vector getMiddlePoint(void)const override;
|
||||
RS_Vector getNearestEndpoint(const RS_Vector& coord,
|
||||
double* dist = nullptr) const override;
|
||||
RS_Vector getNearestPointOnEntity(const RS_Vector& coord,
|
||||
bool onEntity = true, double* dist = NULL, RS_Entity** entity=NULL)const override;
|
||||
RS_Vector getNearestCenter(const RS_Vector& coord,
|
||||
double* dist = NULL)const override;
|
||||
RS_Vector getNearestMiddle(const RS_Vector& coord,
|
||||
double* dist = nullptr,
|
||||
int middlePoints = 1 ) const override;
|
||||
RS_Vector getNearestDist(double distance,
|
||||
const RS_Vector& coord,
|
||||
double* dist = NULL)const override;
|
||||
RS_Vector getNearestDist(double distance,
|
||||
bool startp)const override;
|
||||
RS_Vector getNearestOrthTan(const RS_Vector& coord,
|
||||
const RS_Line& normal,
|
||||
bool onEntity = false) const override;
|
||||
|
||||
bool offset(const RS_Vector& coord, const double& distance) override;
|
||||
RS_VectorSolutions getTangentPoint(const RS_Vector& point) const override;//find the tangential points seeing from given point
|
||||
RS_Vector getTangentDirection(const RS_Vector& point)const override;
|
||||
void move(const RS_Vector& offset) override;
|
||||
void rotate(const RS_Vector& center, const double& angle) override;
|
||||
void rotate(const RS_Vector& center, const RS_Vector& angleVector) override;
|
||||
void scale(const RS_Vector& center, const RS_Vector& factor) override;
|
||||
void mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) override;
|
||||
void moveRef(const RS_Vector& ref, const RS_Vector& offset) override;
|
||||
/** whether the entity's bounding box intersects with visible portion of graphic view */
|
||||
bool isVisibleInWindow(RS_GraphicView* view) const override;
|
||||
void draw(RS_Painter* painter, RS_GraphicView* view, double& patternOffset) override;
|
||||
/** return the equation of the entity
|
||||
for quadratic,
|
||||
|
||||
return a vector contains:
|
||||
m0 x^2 + m1 xy + m2 y^2 + m3 x + m4 y + m5 =0
|
||||
|
||||
for linear:
|
||||
m0 x + m1 y + m2 =0
|
||||
**/
|
||||
LC_Quadratic getQuadratic() const override;
|
||||
|
||||
/**
|
||||
* @brief Returns area of full circle
|
||||
* Note: Circular arcs are handled separately by RS_Arc (areaLIneIntegral)
|
||||
* However, full ellipses and ellipse arcs are handled by RS_Ellipse
|
||||
* @return \pi r^2
|
||||
*/
|
||||
double areaLineIntegral() const override;
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os, const RS_Circle& a);
|
||||
|
||||
void calculateBorders() override;
|
||||
|
||||
protected:
|
||||
RS_CircleData data;
|
||||
};
|
||||
|
||||
#endif
|
||||
91
lib/engine/rs_clipboard.cpp
Normal file
91
lib/engine/rs_clipboard.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
#include "rs_clipboard.h"
|
||||
#include "rs_block.h"
|
||||
#include "rs_layer.h"
|
||||
#include "rs_entity.h"
|
||||
|
||||
RS_Clipboard* RS_Clipboard::uniqueInstance = NULL;
|
||||
|
||||
|
||||
|
||||
void RS_Clipboard::clear() {
|
||||
graphic.clear();
|
||||
graphic.clearBlocks();
|
||||
graphic.clearLayers();
|
||||
graphic.clearVariables();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void RS_Clipboard::addBlock(RS_Block* b) {
|
||||
if (b) {
|
||||
graphic.addBlock(b, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool RS_Clipboard::hasBlock(const QString& name) {
|
||||
return (graphic.findBlock(name));
|
||||
}
|
||||
|
||||
|
||||
void RS_Clipboard::addLayer(RS_Layer* l) {
|
||||
if (l) {
|
||||
//graphic.addLayer(l->clone());
|
||||
graphic.addLayer(l);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool RS_Clipboard::hasLayer(const QString& name) {
|
||||
return (graphic.findLayer(name));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_Clipboard::addEntity(RS_Entity* e) {
|
||||
if (e) {
|
||||
//graphic.addEntity(e->clone());
|
||||
graphic.addEntity(e);
|
||||
e->reparent(&graphic);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps the clipboard contents to stdout.
|
||||
*/
|
||||
std::ostream& operator << (std::ostream& os, RS_Clipboard& cb) {
|
||||
os << "Clipboard: " << cb.graphic << "\n";
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
112
lib/engine/rs_clipboard.h
Normal file
112
lib/engine/rs_clipboard.h
Normal file
@@ -0,0 +1,112 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_CLIPBOARD_H
|
||||
#define RS_CLIPBOARD_H
|
||||
|
||||
#include <iosfwd>
|
||||
#include "rs_graphic.h"
|
||||
|
||||
#define RS_CLIPBOARD RS_Clipboard::instance()
|
||||
|
||||
class RS_Block;
|
||||
class RS_Layer;
|
||||
class RS_Entity;
|
||||
|
||||
/**
|
||||
* LibreCAD internal clipboard. We don't use the system clipboard for
|
||||
* better portaility.
|
||||
* Implemented as singleton.
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_Clipboard {
|
||||
protected:
|
||||
RS_Clipboard() {
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* @return Instance to the unique clipboard object.
|
||||
*/
|
||||
static RS_Clipboard* instance() {
|
||||
if (uniqueInstance==NULL) {
|
||||
uniqueInstance = new RS_Clipboard();
|
||||
}
|
||||
return uniqueInstance;
|
||||
}
|
||||
|
||||
void clear();
|
||||
|
||||
void addBlock(RS_Block* b);
|
||||
bool hasBlock(const QString& name);
|
||||
int countBlocks() {
|
||||
return graphic.countBlocks();
|
||||
}
|
||||
RS_Block* blockAt(int i) {
|
||||
return graphic.blockAt(i);
|
||||
}
|
||||
|
||||
void addLayer(RS_Layer* l);
|
||||
bool hasLayer(const QString& name);
|
||||
int countLayers() {
|
||||
return graphic.countLayers();
|
||||
}
|
||||
RS_Layer* layerAt(int i) {
|
||||
return graphic.layerAt(i);
|
||||
}
|
||||
|
||||
void addEntity(RS_Entity* e);
|
||||
|
||||
unsigned count() {
|
||||
return graphic.count();
|
||||
}
|
||||
RS_Entity* entityAt(unsigned i) {
|
||||
return graphic.entityAt(i);
|
||||
}
|
||||
RS_Entity* firstEntity() {
|
||||
return graphic.firstEntity();
|
||||
}
|
||||
|
||||
RS_Entity* nextEntity() {
|
||||
return graphic.nextEntity();
|
||||
}
|
||||
|
||||
RS_Graphic* getGraphic() {
|
||||
return &graphic;
|
||||
}
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os, RS_Clipboard& cb);
|
||||
|
||||
protected:
|
||||
static RS_Clipboard* uniqueInstance;
|
||||
|
||||
RS_Graphic graphic;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
94
lib/engine/rs_color.cpp
Normal file
94
lib/engine/rs_color.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2020 A. Stebich (librecad@mail.lordofbikes.de)
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
#include "rs_color.h"
|
||||
|
||||
//This method is used for plugins
|
||||
int RS_Color::toIntColor(void) const {
|
||||
if (isByLayer())
|
||||
return -1;
|
||||
if (isByBlock())
|
||||
return -2;
|
||||
// int tmp1 = red() << 16;
|
||||
// int tmp2 = green() << 8;
|
||||
// int tmp3 = tmp1+tmp2+blue();
|
||||
int cd = (red() << 16) + (green() << 8) + blue();
|
||||
return cd;
|
||||
|
||||
}
|
||||
|
||||
//This method is used for plugins
|
||||
void RS_Color::fromIntColor(int co) {
|
||||
if (co == -1)
|
||||
setFlags(RS2::FlagByLayer);
|
||||
else if (co == -2)
|
||||
setFlags(RS2::FlagByBlock);
|
||||
else {
|
||||
setRed((co >> 16) & 0xFF);
|
||||
setGreen((co >> 8) & 0xFF);
|
||||
setBlue(co & 0xFF);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Color distance
|
||||
*
|
||||
* Calculate distance between two RGB colors using low-cost approximation of
|
||||
* human eye response by Thiadmer Riemersma. Formula explanation found here:
|
||||
* https://www.compuphase.com/cmetric.htm
|
||||
*
|
||||
* @author Thiadmer Riemersma
|
||||
* @author Jeremy Ruhland
|
||||
*
|
||||
* @param c Color to perform comparison against
|
||||
*
|
||||
* @return Distance between colors in percent, value ranging from 0 (identical)
|
||||
* to 100 (maximum difference)
|
||||
*/
|
||||
int RS_Color::colorDistance(const RS_Color& c) const {
|
||||
|
||||
int myRed {red()};
|
||||
int otherRed {c.red()};
|
||||
int redMean {(myRed + otherRed) / 2};
|
||||
|
||||
// Convert difference value to percentage using maximum color difference (764.834 / 100)
|
||||
return std::lround( std::sqrt( std::pow(otherRed - myRed, 2) * (512 + redMean) / 256
|
||||
+ std::pow(c.green() - green(), 2) * 4
|
||||
+ std::pow(c.blue() - blue(), 2) * (767 - redMean) / 256)
|
||||
/ 7.64834);
|
||||
}
|
||||
|
||||
std::ostream& operator << (std::ostream& os, const RS_Color& c) {
|
||||
os << " color: " << c.name().toLatin1().data()
|
||||
<< " flags: " << (c.getFlag(RS2::FlagByLayer) ? "RS2::FlagByLayer " : "")
|
||||
<< (c.getFlag(RS2::FlagByBlock) ? "RS2::FlagByBlock " : "");
|
||||
return os;
|
||||
}
|
||||
114
lib/engine/rs_color.h
Normal file
114
lib/engine/rs_color.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2020 A. Stebich (librecad@mail.lordofbikes.de)
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_COLOR_H
|
||||
#define RS_COLOR_H
|
||||
|
||||
#include <QColor>
|
||||
|
||||
#include "rs.h"
|
||||
#include "rs_flags.h"
|
||||
|
||||
//! Color defined by layer not entity
|
||||
//#define C_BY_LAYER 0x00000001
|
||||
//! Color defined by block not entity
|
||||
//#define C_BY_BLOCK 0x00000002
|
||||
|
||||
/**
|
||||
* Color class.
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_Color: public QColor, public RS_Flags {
|
||||
public:
|
||||
RS_Color() : QColor(), RS_Flags() {}
|
||||
RS_Color(int r, int g, int b) : QColor(r, g, b), RS_Flags() {}
|
||||
RS_Color(int r, int g, int b, int a) : QColor(r, g, b, a), RS_Flags() {}
|
||||
RS_Color(const QColor& c) : QColor(c), RS_Flags() {}
|
||||
RS_Color(const Qt::GlobalColor color) : QColor(color), RS_Flags() {}
|
||||
RS_Color(const RS_Color& c) : QColor(c), RS_Flags() {
|
||||
setFlags(c.getFlags());
|
||||
}
|
||||
RS_Color(unsigned int f) : QColor(), RS_Flags(f) {}
|
||||
RS_Color(QString name) : QColor(name), RS_Flags() {}
|
||||
|
||||
|
||||
/** @return A copy of this color without flags. */
|
||||
RS_Color stripFlags() const {
|
||||
return RS_Color(red(), green(), blue());
|
||||
}
|
||||
|
||||
/** @return true if the color is defined by layer. */
|
||||
bool isByLayer() const {
|
||||
return getFlag(RS2::FlagByLayer);
|
||||
}
|
||||
|
||||
/** @return true if the color is defined by block. */
|
||||
bool isByBlock() const {
|
||||
return getFlag(RS2::FlagByBlock);
|
||||
}
|
||||
|
||||
QColor toQColor(void) const {
|
||||
QColor c0;
|
||||
c0.setRgb(red(),green(),blue());
|
||||
return c0;
|
||||
}
|
||||
|
||||
//These 3 methods are used for plugins
|
||||
int toIntColor(void) const;
|
||||
void fromIntColor(int co);
|
||||
int colorDistance(const RS_Color& c) const;
|
||||
|
||||
enum {
|
||||
Black = 0,
|
||||
/**
|
||||
* Minimum acceptable distance between two colors before visibility
|
||||
* enhancement is required. Determined empirically.
|
||||
*/
|
||||
MinColorDistance = 20, //< in %
|
||||
};
|
||||
|
||||
RS_Color& operator = (const RS_Color& c) {
|
||||
setRgb(c.red(), c.green(), c.blue());
|
||||
setFlags(c.getFlags());
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator == (const RS_Color& c) const {
|
||||
return (red()==c.red() &&
|
||||
green()==c.green() &&
|
||||
blue()==c.blue() &&
|
||||
getFlags()==c.getFlags());
|
||||
}
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os, const RS_Color& c);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
286
lib/engine/rs_constructionline.cpp
Normal file
286
lib/engine/rs_constructionline.cpp
Normal file
@@ -0,0 +1,286 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#include "rs_constructionline.h"
|
||||
|
||||
#include "rs_debug.h"
|
||||
#include "lc_quadratic.h"
|
||||
#include "rs_math.h"
|
||||
|
||||
RS_ConstructionLineData::RS_ConstructionLineData():
|
||||
point1(false),
|
||||
point2(false)
|
||||
{}
|
||||
|
||||
RS_ConstructionLineData::RS_ConstructionLineData(const RS_Vector& point1,
|
||||
const RS_Vector& point2):
|
||||
point1(point1)
|
||||
,point2(point2)
|
||||
{
|
||||
}
|
||||
|
||||
std::ostream& operator << (std::ostream& os,
|
||||
const RS_ConstructionLineData& ld)
|
||||
{
|
||||
os << "(" << ld.point1 <<
|
||||
"/" << ld.point2 <<
|
||||
")";
|
||||
return os;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
RS_ConstructionLine::RS_ConstructionLine(RS_EntityContainer* parent,
|
||||
const RS_ConstructionLineData& d)
|
||||
:RS_AtomicEntity(parent), data(d) {
|
||||
|
||||
calculateBorders();
|
||||
}
|
||||
|
||||
RS_Entity* RS_ConstructionLine::clone() const {
|
||||
RS_ConstructionLine* c = new RS_ConstructionLine(*this);
|
||||
c->initId();
|
||||
return c;
|
||||
}
|
||||
|
||||
void RS_ConstructionLine::calculateBorders() {
|
||||
minV = RS_Vector::minimum(data.point1, data.point2);
|
||||
maxV = RS_Vector::maximum(data.point1, data.point2);
|
||||
}
|
||||
|
||||
RS_Vector RS_ConstructionLine::getNearestEndpoint(const RS_Vector& coord,
|
||||
double* dist) const{
|
||||
double dist1, dist2;
|
||||
|
||||
dist1 = (data.point1-coord).squared();
|
||||
dist2 = (data.point2-coord).squared();
|
||||
|
||||
if (dist2<dist1) {
|
||||
if (dist) {
|
||||
*dist = sqrt(dist2);
|
||||
}
|
||||
return data.point2;
|
||||
} else {
|
||||
if (dist) {
|
||||
*dist = sqrt(dist1);
|
||||
}
|
||||
return data.point1;
|
||||
}
|
||||
}
|
||||
|
||||
RS_Vector RS_ConstructionLine::getNearestPointOnEntity(const RS_Vector& coord,
|
||||
bool /*onEntity*/, double* /*dist*/, RS_Entity** entity) const{
|
||||
|
||||
if (entity) {
|
||||
*entity = const_cast<RS_ConstructionLine*>(this);
|
||||
}
|
||||
|
||||
RS_Vector ae = data.point2-data.point1;
|
||||
RS_Vector ea = data.point1-data.point2;
|
||||
RS_Vector ap = coord-data.point1;
|
||||
// RS_Vector ep = coord-data.point2;
|
||||
|
||||
if (ae.magnitude()<1.0e-6 || ea.magnitude()<1.0e-6) {
|
||||
return RS_Vector(false);
|
||||
}
|
||||
|
||||
// Orthogonal projection from both sides:
|
||||
RS_Vector ba = ae * RS_Vector::dotP(ae, ap)
|
||||
/ (ae.magnitude()*ae.magnitude());
|
||||
// RS_Vector be = ea * RS_Vector::dotP(ea, ep)
|
||||
// / (ea.magnitude()*ea.magnitude());
|
||||
|
||||
return data.point1+ba;
|
||||
}
|
||||
|
||||
RS_Vector RS_ConstructionLine::getNearestCenter(const RS_Vector& /*coord*/,
|
||||
double* dist) const{
|
||||
|
||||
if (dist) {
|
||||
*dist = RS_MAXDOUBLE;
|
||||
}
|
||||
|
||||
return RS_Vector(false);
|
||||
}
|
||||
|
||||
/** @return Copy of data that defines the line. */
|
||||
RS_ConstructionLineData const& RS_ConstructionLine::getData() const {
|
||||
return data;
|
||||
}
|
||||
|
||||
/** @return First definition point. */
|
||||
RS_Vector const& RS_ConstructionLine::getPoint1() const {
|
||||
return data.point1;
|
||||
}
|
||||
/** @return Second definition point. */
|
||||
RS_Vector const& RS_ConstructionLine::getPoint2() const {
|
||||
return data.point2;
|
||||
}
|
||||
|
||||
/** @return Start point of the entity */
|
||||
RS_Vector RS_ConstructionLine::getStartpoint() const
|
||||
{
|
||||
return data.point1;
|
||||
}
|
||||
|
||||
/** @return End point of the entity */
|
||||
RS_Vector RS_ConstructionLine::getEndpoint() const
|
||||
{
|
||||
return data.point2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Direction 1. The angle at which the arc starts at
|
||||
* the startpoint.
|
||||
*/
|
||||
double RS_ConstructionLine::getDirection1(void) const
|
||||
{
|
||||
return RS_Math::correctAngle( data.point1.angleTo( data.point2));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Direction 2. The angle at which the arc starts at
|
||||
* the endpoint.
|
||||
*/
|
||||
double RS_ConstructionLine::getDirection2(void) const
|
||||
{
|
||||
return RS_Math::correctAngle( data.point2.angleTo( data.point1));
|
||||
}
|
||||
|
||||
/** return the equation of the entity
|
||||
for quadratic,
|
||||
|
||||
return a vector contains:
|
||||
m0 x^2 + m1 xy + m2 y^2 + m3 x + m4 y + m5 =0
|
||||
|
||||
for linear:
|
||||
m0 x + m1 y + m2 =0
|
||||
**/
|
||||
LC_Quadratic RS_ConstructionLine::getQuadratic() const
|
||||
{
|
||||
std::vector<double> ce(3,0.);
|
||||
auto dvp=data.point2 - data.point1;
|
||||
RS_Vector normal(-dvp.y,dvp.x);
|
||||
ce[0]=normal.x;
|
||||
ce[1]=normal.y;
|
||||
ce[2]= -normal.dotP(data.point2);
|
||||
return LC_Quadratic(ce);
|
||||
}
|
||||
|
||||
RS_Vector RS_ConstructionLine::getMiddlePoint() const{
|
||||
return RS_Vector(false);
|
||||
}
|
||||
RS_Vector RS_ConstructionLine::getNearestMiddle(const RS_Vector& /*coord*/,
|
||||
double* dist, const int /*middlePoints*/)const {
|
||||
if (dist) {
|
||||
*dist = RS_MAXDOUBLE;
|
||||
}
|
||||
return RS_Vector(false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
RS_Vector RS_ConstructionLine::getNearestDist(double /*distance*/,
|
||||
const RS_Vector& /*coord*/,
|
||||
double* dist) const{
|
||||
if (dist) {
|
||||
*dist = RS_MAXDOUBLE;
|
||||
}
|
||||
return RS_Vector(false);
|
||||
}
|
||||
|
||||
|
||||
double RS_ConstructionLine::getDistanceToPoint(const RS_Vector& coord,
|
||||
RS_Entity** entity,
|
||||
RS2::ResolveLevel /*level*/, double /*solidDist*/) const {
|
||||
|
||||
RS_DEBUG->print("RS_ConstructionLine::getDistanceToPoint");
|
||||
|
||||
if (entity) {
|
||||
*entity = const_cast<RS_ConstructionLine*>(this);
|
||||
}
|
||||
//double dist = RS_MAXDOUBLE;
|
||||
RS_Vector se = data.point2-data.point1;
|
||||
double d(se.magnitude());
|
||||
if(d<RS_TOLERANCE) {
|
||||
//line too short
|
||||
return RS_MAXDOUBLE;
|
||||
}
|
||||
se.set( se.x/d,-se.y/d); //normalized
|
||||
RS_Vector vpc= coord - data.point1;
|
||||
vpc.rotate(se); // rotate to use the line as x-axis, and the distance is fabs(y)
|
||||
return ( fabs(vpc.y) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_ConstructionLine::move(const RS_Vector& offset) {
|
||||
data.point1.move(offset);
|
||||
data.point2.move(offset);
|
||||
//calculateBorders();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_ConstructionLine::rotate(const RS_Vector& center, const double& angle) {
|
||||
RS_Vector angleVector(angle);
|
||||
data.point1.rotate(center, angleVector);
|
||||
data.point2.rotate(center, angleVector);
|
||||
//calculateBorders();
|
||||
}
|
||||
|
||||
void RS_ConstructionLine::rotate(const RS_Vector& center, const RS_Vector& angleVector) {
|
||||
data.point1.rotate(center, angleVector);
|
||||
data.point2.rotate(center, angleVector);
|
||||
//calculateBorders();
|
||||
}
|
||||
|
||||
void RS_ConstructionLine::scale(const RS_Vector& center, const RS_Vector& factor) {
|
||||
data.point1.scale(center, factor);
|
||||
data.point2.scale(center, factor);
|
||||
//calculateBorders();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_ConstructionLine::mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) {
|
||||
data.point1.mirror(axisPoint1, axisPoint2);
|
||||
data.point2.mirror(axisPoint1, axisPoint2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Dumps the point's data to stdout.
|
||||
*/
|
||||
std::ostream& operator << (std::ostream& os, const RS_ConstructionLine& l) {
|
||||
os << " ConstructionLine: " << l.getData() << "\n";
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
140
lib/engine/rs_constructionline.h
Normal file
140
lib/engine/rs_constructionline.h
Normal file
@@ -0,0 +1,140 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_CONSTRUCTIONLINE_H
|
||||
#define RS_CONSTRUCTIONLINE_H
|
||||
|
||||
#include "rs_atomicentity.h"
|
||||
#include "rs_vector.h"
|
||||
|
||||
/**
|
||||
* Holds the data that defines a construction line (a line
|
||||
* which is not limited to both directions).
|
||||
*/
|
||||
class RS_ConstructionLineData {
|
||||
public:
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
RS_ConstructionLineData();
|
||||
|
||||
RS_ConstructionLineData(const RS_Vector& point1,
|
||||
const RS_Vector& point2);
|
||||
|
||||
friend class RS_ConstructionLine;
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os,
|
||||
const RS_ConstructionLineData& ld);
|
||||
|
||||
private:
|
||||
RS_Vector point1;
|
||||
RS_Vector point2;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Class for a construction line entity.
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_ConstructionLine : public RS_AtomicEntity {
|
||||
public:
|
||||
RS_ConstructionLine()=default;
|
||||
RS_ConstructionLine(RS_EntityContainer* parent,
|
||||
const RS_ConstructionLineData& d);
|
||||
|
||||
virtual RS_Entity* clone() const;
|
||||
|
||||
virtual ~RS_ConstructionLine()=default;
|
||||
|
||||
/** @return RS2::EntityConstructionLine */
|
||||
virtual RS2::EntityType rtti() const {
|
||||
return RS2::EntityConstructionLine;
|
||||
}
|
||||
|
||||
/** @return Copy of data that defines the line. */
|
||||
RS_ConstructionLineData const& getData() const;
|
||||
|
||||
/** @return First definition point. */
|
||||
RS_Vector const& getPoint1() const;
|
||||
/** @return Second definition point. */
|
||||
RS_Vector const& getPoint2() const;
|
||||
|
||||
/** @return Start point of the entity */
|
||||
RS_Vector getStartpoint() const override;
|
||||
/** @return End point of the entity */
|
||||
RS_Vector getEndpoint() const override;
|
||||
double getDirection1(void) const override;
|
||||
double getDirection2(void) const override;
|
||||
|
||||
/** return the equation of the entity
|
||||
for quadratic,
|
||||
|
||||
return a vector contains:
|
||||
m0 x^2 + m1 xy + m2 y^2 + m3 x + m4 y + m5 =0
|
||||
|
||||
for linear:
|
||||
m0 x + m1 y + m2 =0
|
||||
**/
|
||||
virtual LC_Quadratic getQuadratic() const;
|
||||
virtual RS_Vector getMiddlePoint(void) const;
|
||||
virtual RS_Vector getNearestEndpoint(const RS_Vector& coord,
|
||||
double* dist = NULL)const;
|
||||
virtual RS_Vector getNearestPointOnEntity(const RS_Vector& coord,
|
||||
bool onEntity = true, double* dist = NULL, RS_Entity** entity=NULL)const;
|
||||
virtual RS_Vector getNearestCenter(const RS_Vector& coord,
|
||||
double* dist = NULL)const;
|
||||
virtual RS_Vector getNearestMiddle(const RS_Vector& coord,
|
||||
double* dist = NULL,
|
||||
int middlePoints = 1)const;
|
||||
virtual RS_Vector getNearestDist(double distance,
|
||||
const RS_Vector& coord,
|
||||
double* dist = NULL)const;
|
||||
virtual double getDistanceToPoint(const RS_Vector& coord,
|
||||
RS_Entity** entity=NULL,
|
||||
RS2::ResolveLevel level=RS2::ResolveNone,
|
||||
double solidDist = RS_MAXDOUBLE) const;
|
||||
|
||||
virtual void move(const RS_Vector& offset);
|
||||
virtual void rotate(const RS_Vector& center, const double& angle);
|
||||
virtual void rotate(const RS_Vector& center, const RS_Vector& angleVector);
|
||||
virtual void scale(const RS_Vector& center, const RS_Vector& factor);
|
||||
virtual void mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2);
|
||||
|
||||
virtual void draw(RS_Painter* /*painter*/, RS_GraphicView* /*view*/,
|
||||
double& /*patternOffset*/) {}
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os,
|
||||
const RS_ConstructionLine& l);
|
||||
|
||||
virtual void calculateBorders();
|
||||
|
||||
protected:
|
||||
RS_ConstructionLineData data;
|
||||
};
|
||||
|
||||
#endif
|
||||
380
lib/engine/rs_dimaligned.cpp
Normal file
380
lib/engine/rs_dimaligned.cpp
Normal file
@@ -0,0 +1,380 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
#include "rs_dimaligned.h"
|
||||
#include "rs_line.h"
|
||||
|
||||
#include "rs_graphic.h"
|
||||
#include "rs_units.h"
|
||||
#include "rs_constructionline.h"
|
||||
#include "rs_math.h"
|
||||
#include "rs_debug.h"
|
||||
|
||||
RS_DimAlignedData::RS_DimAlignedData():
|
||||
extensionPoint1(false),
|
||||
extensionPoint2(false)
|
||||
{}
|
||||
|
||||
/**
|
||||
* Constructor with initialisation.
|
||||
*
|
||||
* @para extensionPoint1 Definition point. Startpoint of the
|
||||
* first extension line.
|
||||
* @para extensionPoint2 Definition point. Startpoint of the
|
||||
* second extension line.
|
||||
*/
|
||||
RS_DimAlignedData::RS_DimAlignedData(const RS_Vector& _extensionPoint1,
|
||||
const RS_Vector& _extensionPoint2):
|
||||
extensionPoint1(_extensionPoint1)
|
||||
,extensionPoint2(_extensionPoint2)
|
||||
{
|
||||
}
|
||||
|
||||
std::ostream& operator << (std::ostream& os,
|
||||
const RS_DimAlignedData& dd) {
|
||||
os << "(" << dd.extensionPoint1 << "/" << dd.extensionPoint1 << ")";
|
||||
return os;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @para parent Parent Entity Container.
|
||||
* @para d Common dimension geometrical data.
|
||||
* @para ed Extended geometrical data for aligned dimension.
|
||||
*/
|
||||
RS_DimAligned::RS_DimAligned(RS_EntityContainer* parent,
|
||||
const RS_DimensionData& d,
|
||||
const RS_DimAlignedData& ed)
|
||||
: RS_Dimension(parent, d), edata(ed) {
|
||||
|
||||
calculateBorders();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Sets a new text. The entities representing the
|
||||
* text are updated.
|
||||
*/
|
||||
//void RS_DimAligned::setText(const QString& t) {
|
||||
// data.text = t;
|
||||
// update();
|
||||
//}
|
||||
|
||||
RS_Entity* RS_DimAligned::clone() const{
|
||||
RS_DimAligned* d = new RS_DimAligned(*this);
|
||||
d->setOwner(isOwner());
|
||||
d->initId();
|
||||
d->detach();
|
||||
return d;
|
||||
}
|
||||
|
||||
RS_VectorSolutions RS_DimAligned::getRefPoints() const
|
||||
{
|
||||
return RS_VectorSolutions({edata.extensionPoint1, edata.extensionPoint2,
|
||||
data.definitionPoint, data.middleOfText});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Automatically created label for the default
|
||||
* measurement of this dimension.
|
||||
*/
|
||||
QString RS_DimAligned::getMeasuredLabel() {
|
||||
double dist = edata.extensionPoint1.distanceTo(edata.extensionPoint2) * getGeneralFactor();
|
||||
|
||||
RS_Graphic* graphic = getGraphic();
|
||||
QString ret;
|
||||
if (graphic) {
|
||||
int dimlunit = getGraphicVariableInt("$DIMLUNIT", 2);
|
||||
int dimdec = getGraphicVariableInt("$DIMDEC", 4);
|
||||
int dimzin = getGraphicVariableInt("$DIMZIN", 1);
|
||||
RS2::LinearFormat format = graphic->getLinearFormat(dimlunit);
|
||||
|
||||
ret = RS_Units::formatLinear(dist, RS2::None, format, dimdec);
|
||||
if (format == RS2::Decimal)
|
||||
ret = stripZerosLinear(ret, dimzin);
|
||||
//verify if units are decimal and comma separator
|
||||
if (format == RS2::Decimal || format == RS2::ArchitecturalMetric){
|
||||
if (getGraphicVariableInt("$DIMDSEP", 0) == 44)
|
||||
ret.replace(QChar('.'), QChar(','));
|
||||
}
|
||||
}
|
||||
else {
|
||||
ret = QString("%1").arg(dist);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
RS_DimAlignedData const& RS_DimAligned::getEData() const {
|
||||
return edata;
|
||||
}
|
||||
|
||||
RS_Vector const& RS_DimAligned::getExtensionPoint1() const {
|
||||
return edata.extensionPoint1;
|
||||
}
|
||||
|
||||
RS_Vector const& RS_DimAligned::getExtensionPoint2() const {
|
||||
return edata.extensionPoint2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the sub entities of this dimension. Called when the
|
||||
* text or the position, alignment, .. changes.
|
||||
*
|
||||
* @param autoText Automatically reposition the text label
|
||||
*/
|
||||
void RS_DimAligned::updateDim(bool autoText) {
|
||||
|
||||
RS_DEBUG->print("RS_DimAligned::update");
|
||||
|
||||
clear();
|
||||
|
||||
if (isUndone()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// general scale (DIMSCALE)
|
||||
double dimscale = getGeneralScale();
|
||||
// distance from entities (DIMEXO)
|
||||
double dimexo = getExtensionLineOffset()*dimscale;
|
||||
// definition line definition (DIMEXE)
|
||||
double dimexe = getExtensionLineExtension()*dimscale;
|
||||
// text height (DIMTXT)
|
||||
//double dimtxt = getTextHeight();
|
||||
// text distance to line (DIMGAP)
|
||||
//double dimgap = getDimensionLineGap();
|
||||
|
||||
// Angle from extension endpoints towards dimension line
|
||||
double extAngle = edata.extensionPoint2.angleTo(data.definitionPoint);
|
||||
// extension lines length
|
||||
double extLength = edata.extensionPoint2.distanceTo(data.definitionPoint);
|
||||
|
||||
if (getFixedLengthOn()){
|
||||
double dimfxl = getFixedLength()*dimscale;
|
||||
if (extLength-dimexo > dimfxl)
|
||||
dimexo = extLength - dimfxl;
|
||||
}
|
||||
|
||||
RS_Vector v1 = RS_Vector::polar(dimexo, extAngle);
|
||||
RS_Vector v2 = RS_Vector::polar(dimexe, extAngle);
|
||||
RS_Vector e1 = RS_Vector::polar(1.0, extAngle);
|
||||
|
||||
RS_Pen pen(getExtensionLineColor(),
|
||||
getExtensionLineWidth(),
|
||||
RS2::LineByBlock);
|
||||
|
||||
// Extension line 1:
|
||||
RS_Line* line = new RS_Line{this,
|
||||
edata.extensionPoint1 + v1,
|
||||
edata.extensionPoint1 + e1*extLength + v2};
|
||||
//line->setLayerToActive();
|
||||
//line->setPenToActive();
|
||||
// line->setPen(RS_Pen(RS2::FlagInvalid));
|
||||
line->setPen(pen);
|
||||
line->setLayer(nullptr);
|
||||
addEntity(line);
|
||||
|
||||
// Extension line 2:
|
||||
line = new RS_Line{this,
|
||||
edata.extensionPoint2 + v1,
|
||||
edata.extensionPoint2 + e1*extLength + v2};
|
||||
//line->setLayerToActive();
|
||||
//line->setPenToActive();
|
||||
// line->setPen(RS_Pen(RS2::FlagInvalid));
|
||||
line->setPen(pen);
|
||||
line->setLayer(nullptr);
|
||||
addEntity(line);
|
||||
|
||||
// Dimension line:
|
||||
updateCreateDimensionLine(edata.extensionPoint1 + e1*extLength,
|
||||
edata.extensionPoint2 + e1*extLength,
|
||||
true, true, autoText);
|
||||
|
||||
calculateBorders();
|
||||
}
|
||||
|
||||
|
||||
void RS_DimAligned::updateDimPoint(){
|
||||
// temporary construction line
|
||||
RS_ConstructionLine tmpLine( nullptr,
|
||||
RS_ConstructionLineData(edata.extensionPoint1, edata.extensionPoint2));
|
||||
|
||||
RS_Vector tmpP1 = tmpLine.getNearestPointOnEntity(data.definitionPoint);
|
||||
data.definitionPoint += edata.extensionPoint2 - tmpP1;
|
||||
}
|
||||
|
||||
|
||||
bool RS_DimAligned::hasEndpointsWithinWindow(const RS_Vector& v1, const RS_Vector& v2) {
|
||||
return (edata.extensionPoint1.isInWindow(v1, v2) ||
|
||||
edata.extensionPoint2.isInWindow(v1, v2));
|
||||
}
|
||||
|
||||
|
||||
void RS_DimAligned::move(const RS_Vector& offset) {
|
||||
RS_Dimension::move(offset);
|
||||
|
||||
edata.extensionPoint1.move(offset);
|
||||
edata.extensionPoint2.move(offset);
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_DimAligned::rotate(const RS_Vector& center, const double& angle) {
|
||||
rotate(center,RS_Vector(angle));
|
||||
}
|
||||
|
||||
|
||||
void RS_DimAligned::rotate(const RS_Vector& center, const RS_Vector& angleVector) {
|
||||
RS_Dimension::rotate(center, angleVector);
|
||||
edata.extensionPoint1.rotate(center, angleVector);
|
||||
edata.extensionPoint2.rotate(center, angleVector);
|
||||
update();
|
||||
}
|
||||
|
||||
void RS_DimAligned::scale(const RS_Vector& center, const RS_Vector& factor) {
|
||||
RS_Dimension::scale(center, factor);
|
||||
|
||||
edata.extensionPoint1.scale(center, factor);
|
||||
edata.extensionPoint2.scale(center, factor);
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
void RS_DimAligned::mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) {
|
||||
RS_Dimension::mirror(axisPoint1, axisPoint2);
|
||||
|
||||
edata.extensionPoint1.mirror(axisPoint1, axisPoint2);
|
||||
edata.extensionPoint2.mirror(axisPoint1, axisPoint2);
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
void RS_DimAligned::stretch(const RS_Vector& firstCorner,
|
||||
const RS_Vector& secondCorner,
|
||||
const RS_Vector& offset) {
|
||||
|
||||
//e->calculateBorders();
|
||||
if (getMin().isInWindow(firstCorner, secondCorner) &&
|
||||
getMax().isInWindow(firstCorner, secondCorner)) {
|
||||
|
||||
move(offset);
|
||||
}
|
||||
else {
|
||||
//RS_Vector v = data.definitionPoint - edata.extensionPoint2;
|
||||
double len = edata.extensionPoint2.distanceTo(data.definitionPoint);
|
||||
double ang1 = edata.extensionPoint1.angleTo(edata.extensionPoint2)
|
||||
+ M_PI_2;
|
||||
|
||||
if (edata.extensionPoint1.isInWindow(firstCorner,
|
||||
secondCorner)) {
|
||||
edata.extensionPoint1.move(offset);
|
||||
}
|
||||
if (edata.extensionPoint2.isInWindow(firstCorner,
|
||||
secondCorner)) {
|
||||
edata.extensionPoint2.move(offset);
|
||||
}
|
||||
|
||||
double ang2 = edata.extensionPoint1.angleTo(edata.extensionPoint2)
|
||||
+ M_PI_2;
|
||||
|
||||
double diff = RS_Math::getAngleDifference(ang1, ang2);
|
||||
if (diff>M_PI) {
|
||||
diff-=2*M_PI;
|
||||
}
|
||||
|
||||
if (fabs(diff)>M_PI_2) {
|
||||
ang2 = RS_Math::correctAngle(ang2+M_PI);
|
||||
}
|
||||
|
||||
RS_Vector v = RS_Vector::polar(len, ang2);
|
||||
data.definitionPoint = edata.extensionPoint2 + v;
|
||||
}
|
||||
updateDim(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_DimAligned::moveRef(const RS_Vector& ref, const RS_Vector& offset) {
|
||||
|
||||
if (ref.distanceTo(data.definitionPoint)<1.0e-4) {
|
||||
RS_ConstructionLine l(nullptr,
|
||||
RS_ConstructionLineData(edata.extensionPoint1,
|
||||
edata.extensionPoint2));
|
||||
double d = l.getDistanceToPoint(data.definitionPoint+offset);
|
||||
double a = edata.extensionPoint2.angleTo(data.definitionPoint);
|
||||
double ad = RS_Math::getAngleDifference(a,
|
||||
edata.extensionPoint2.angleTo(data.definitionPoint+offset));
|
||||
|
||||
if (fabs(ad)>M_PI_2 && fabs(ad)<3.0/2.0*M_PI) {
|
||||
a = RS_Math::correctAngle(a+M_PI);
|
||||
}
|
||||
|
||||
RS_Vector v = RS_Vector::polar(d, a);
|
||||
data.definitionPoint = edata.extensionPoint2 + v;
|
||||
updateDim(true);
|
||||
}
|
||||
else if (ref.distanceTo(data.middleOfText)<1.0e-4) {
|
||||
data.middleOfText.move(offset);
|
||||
updateDim(false);
|
||||
}
|
||||
else if (ref.distanceTo(edata.extensionPoint1)<1.0e-4) {
|
||||
double a1 = edata.extensionPoint2.angleTo(edata.extensionPoint1);
|
||||
double a2 = edata.extensionPoint2.angleTo(edata.extensionPoint1+offset);
|
||||
double d1 = edata.extensionPoint2.distanceTo(edata.extensionPoint1);
|
||||
double d2 = edata.extensionPoint2.distanceTo(edata.extensionPoint1+offset);
|
||||
rotate(edata.extensionPoint2, a2-a1);
|
||||
if (fabs(d1)>1.0e-4) {
|
||||
scale(edata.extensionPoint2, RS_Vector(d2/d1, d2/d1));
|
||||
}
|
||||
updateDim(true);
|
||||
}
|
||||
else if (ref.distanceTo(edata.extensionPoint2)<1.0e-4) {
|
||||
double a1 = edata.extensionPoint1.angleTo(edata.extensionPoint2);
|
||||
double a2 = edata.extensionPoint1.angleTo(edata.extensionPoint2+offset);
|
||||
double d1 = edata.extensionPoint1.distanceTo(edata.extensionPoint2);
|
||||
double d2 = edata.extensionPoint1.distanceTo(edata.extensionPoint2+offset);
|
||||
rotate(edata.extensionPoint1, a2-a1);
|
||||
if (fabs(d1)>1.0e-4) {
|
||||
scale(edata.extensionPoint1, RS_Vector(d2/d1, d2/d1));
|
||||
}
|
||||
updateDim(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Dumps the point's data to stdout.
|
||||
*/
|
||||
std::ostream& operator << (std::ostream& os, const RS_DimAligned& d) {
|
||||
os << " DimAligned: " << d.getData() << "\n" << d.getEData() << "\n";
|
||||
return os;
|
||||
}
|
||||
119
lib/engine/rs_dimaligned.h
Normal file
119
lib/engine/rs_dimaligned.h
Normal file
@@ -0,0 +1,119 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_DIMALIGNED_H
|
||||
#define RS_DIMALIGNED_H
|
||||
|
||||
#include "rs_dimension.h"
|
||||
|
||||
/**
|
||||
* Holds the data that defines an aligned dimension entity.
|
||||
*/
|
||||
struct RS_DimAlignedData {
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
RS_DimAlignedData();
|
||||
/**
|
||||
* Constructor with initialisation.
|
||||
*
|
||||
* @para extensionPoint1 Definition point. Startpoint of the
|
||||
* first extension line.
|
||||
* @para extensionPoint2 Definition point. Startpoint of the
|
||||
* second extension line.
|
||||
*/
|
||||
RS_DimAlignedData(const RS_Vector& extensionPoint1,
|
||||
const RS_Vector& extensionPoint2);
|
||||
|
||||
/** Definition point. Startpoint of the first extension line. */
|
||||
RS_Vector extensionPoint1;
|
||||
/** Definition point. Startpoint of the second extension line. */
|
||||
RS_Vector extensionPoint2;
|
||||
};
|
||||
|
||||
std::ostream& operator << (std::ostream& os, const RS_DimAlignedData& dd);
|
||||
|
||||
/**
|
||||
* Class for aligned dimension entities.
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_DimAligned : public RS_Dimension {
|
||||
public:
|
||||
RS_DimAligned(RS_EntityContainer* parent,
|
||||
const RS_DimensionData& d,
|
||||
const RS_DimAlignedData& ed);
|
||||
|
||||
RS_Entity* clone() const override;
|
||||
|
||||
/** @return RS2::EntityDimAligned */
|
||||
RS2::EntityType rtti() const override{
|
||||
return RS2::EntityDimAligned;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Copy of data that defines the aligned dimension.
|
||||
* @see getData()
|
||||
*/
|
||||
RS_DimAlignedData const& getEData() const;
|
||||
|
||||
RS_VectorSolutions getRefPoints() const override;
|
||||
|
||||
QString getMeasuredLabel() override;
|
||||
|
||||
void updateDim(bool autoText=false) override;
|
||||
|
||||
RS_Vector const& getExtensionPoint1() const;
|
||||
|
||||
RS_Vector const& getExtensionPoint2() const;
|
||||
|
||||
/**
|
||||
* Recalculate the original Dimension Point to remove Dim oblique angle.
|
||||
* @author Rallaz
|
||||
*/
|
||||
void updateDimPoint();
|
||||
|
||||
void move(const RS_Vector& offset) override;
|
||||
void rotate(const RS_Vector& center, const double& angle) override;
|
||||
void rotate(const RS_Vector& center, const RS_Vector& angleVector) override;
|
||||
void scale(const RS_Vector& center, const RS_Vector& factor) override;
|
||||
void mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) override;
|
||||
bool hasEndpointsWithinWindow(const RS_Vector& v1, const RS_Vector& v2) override;
|
||||
void stretch(const RS_Vector& firstCorner,
|
||||
const RS_Vector& secondCorner,
|
||||
const RS_Vector& offset) override;
|
||||
void moveRef(const RS_Vector& ref, const RS_Vector& offset) override;
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os,
|
||||
const RS_DimAligned& d);
|
||||
|
||||
protected:
|
||||
/** Extended data. */
|
||||
RS_DimAlignedData edata;
|
||||
};
|
||||
|
||||
#endif
|
||||
580
lib/engine/rs_dimangular.cpp
Normal file
580
lib/engine/rs_dimangular.cpp
Normal file
@@ -0,0 +1,580 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2018 A. Stebich (librecad@mail.lordofbikes.de)
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
#include<iostream>
|
||||
#include<cmath>
|
||||
#include "rs_dimangular.h"
|
||||
#include "rs_math.h"
|
||||
|
||||
#include "rs_constructionline.h"
|
||||
#include "rs_arc.h"
|
||||
#include "rs_line.h"
|
||||
#include "rs_graphic.h"
|
||||
#include "rs_information.h"
|
||||
#include "rs_solid.h"
|
||||
#include "rs_mtext.h"
|
||||
#include "rs_debug.h"
|
||||
|
||||
RS_DimAngularData::RS_DimAngularData():
|
||||
definitionPoint1( false),
|
||||
definitionPoint2( false),
|
||||
definitionPoint3( false),
|
||||
definitionPoint4( false)
|
||||
{
|
||||
}
|
||||
|
||||
RS_DimAngularData::RS_DimAngularData(const RS_DimAngularData &ed):
|
||||
definitionPoint1( ed.definitionPoint1),
|
||||
definitionPoint2( ed.definitionPoint2),
|
||||
definitionPoint3( ed.definitionPoint3),
|
||||
definitionPoint4( ed.definitionPoint4)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor with initialisation.
|
||||
*
|
||||
* @param definitionPoint Definition point of the angular dimension.
|
||||
* @param leader Leader length.
|
||||
*/
|
||||
RS_DimAngularData::RS_DimAngularData(const RS_Vector& _definitionPoint1,
|
||||
const RS_Vector& _definitionPoint2,
|
||||
const RS_Vector& _definitionPoint3,
|
||||
const RS_Vector& _definitionPoint4):
|
||||
definitionPoint1( _definitionPoint1),
|
||||
definitionPoint2( _definitionPoint2),
|
||||
definitionPoint3( _definitionPoint3),
|
||||
definitionPoint4( _definitionPoint4)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor with initialisation.
|
||||
*
|
||||
* @param dimscale general scale (DIMSCALE)
|
||||
* @param dimexo distance from entities (DIMEXO)
|
||||
* @param dimexe extension line extension (DIMEXE)
|
||||
* @param dimtxt text height (DIMTXT)
|
||||
* @param dimgap text distance to line (DIMGAP)
|
||||
* @param arrowSize arrow length
|
||||
*/
|
||||
LC_DimAngularVars::LC_DimAngularVars(const double _dimscale,
|
||||
const double _dimexo,
|
||||
const double _dimexe,
|
||||
const double _dimtxt,
|
||||
const double _dimgap,
|
||||
const double _arrowSize) :
|
||||
dimscale( _dimscale),
|
||||
dimexo( _dimexo * _dimscale),
|
||||
dimexe( _dimexe * _dimscale),
|
||||
dimtxt( _dimtxt * _dimscale),
|
||||
dimgap( _dimgap * _dimscale),
|
||||
arrowSize( _arrowSize * _dimscale)
|
||||
{
|
||||
}
|
||||
|
||||
LC_DimAngularVars::LC_DimAngularVars(const LC_DimAngularVars& av) :
|
||||
dimscale( av.dimscale),
|
||||
dimexo( av.dimexo),
|
||||
dimexe( av.dimexe),
|
||||
dimtxt( av.dimtxt),
|
||||
dimgap( av.dimgap),
|
||||
arrowSize( av.arrowSize)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @para parent Parent Entity Container.
|
||||
* @para d Common dimension geometrical data.
|
||||
* @para ed Extended geometrical data for angular dimension.
|
||||
*/
|
||||
RS_DimAngular::RS_DimAngular(RS_EntityContainer* parent,
|
||||
const RS_DimensionData& d,
|
||||
const RS_DimAngularData& ed) :
|
||||
RS_Dimension( parent, d),
|
||||
edata( ed)
|
||||
{
|
||||
calcDimension();
|
||||
calculateBorders();
|
||||
}
|
||||
|
||||
RS_Entity* RS_DimAngular::clone() const
|
||||
{
|
||||
RS_DimAngular *d {new RS_DimAngular(*this)};
|
||||
|
||||
d->setOwner( isOwner());
|
||||
d->initId();
|
||||
d->detach();
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Automatically created label for the default
|
||||
* measurement of this dimension.
|
||||
*/
|
||||
QString RS_DimAngular::getMeasuredLabel()
|
||||
{
|
||||
int dimaunit {getGraphicVariableInt( QStringLiteral( "$DIMAUNIT"), 0)};
|
||||
int dimadec {getGraphicVariableInt( QStringLiteral( "$DIMADEC"), 0)};
|
||||
int dimazin {getGraphicVariableInt( QStringLiteral( "$DIMAZIN"), 0)};
|
||||
RS2::AngleFormat format {RS_Units::numberToAngleFormat( dimaunit)};
|
||||
QString strLabel( RS_Units::formatAngle( dimAngle, format, dimadec));
|
||||
|
||||
if (RS2::DegreesMinutesSeconds != format
|
||||
&& RS2::Surveyors != format) {
|
||||
strLabel = stripZerosAngle( strLabel, dimazin);
|
||||
}
|
||||
|
||||
//verify if units are decimal and comma separator
|
||||
if (RS2::DegreesMinutesSeconds != dimaunit) {
|
||||
if (',' == getGraphicVariableInt( QStringLiteral( "$DIMDSEP"), 0)) {
|
||||
strLabel.replace( QChar('.'), QChar(','));
|
||||
}
|
||||
}
|
||||
|
||||
return strLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Center of the measured dimension.
|
||||
*/
|
||||
RS_Vector RS_DimAngular::getCenter() const
|
||||
{
|
||||
return dimCenter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Add an extension line if necessary
|
||||
*
|
||||
* @param dimLine dimension definition line including extension offset
|
||||
* @param dimPoint point where the arc meets the definition line
|
||||
* @param dirStart unit vector defining the lines starting point direction
|
||||
* @param dirEnd unit vector defining the lines ending point direction
|
||||
* @param av DXF variables with offset and extension line length
|
||||
* @param pen pen to draw the extension line
|
||||
*/
|
||||
void RS_DimAngular::extensionLine(const RS_ConstructionLine& dimLine,
|
||||
const RS_Vector& dimPoint,
|
||||
const RS_Vector& dirStart,
|
||||
const RS_Vector& dirEnd,
|
||||
const LC_DimAngularVars& av,
|
||||
const RS_Pen& pen)
|
||||
{
|
||||
double diffLine {RS_Vector::posInLine( dimLine.getStartpoint(), dimLine.getEndpoint(), dimPoint)};
|
||||
double diffCenter {RS_Vector::posInLine( dimLine.getStartpoint(), dimCenter, dimPoint)};
|
||||
|
||||
if( 0.0 <= diffLine && 1.0 >= diffLine) {
|
||||
// dimension ends on entity, nothing to extend
|
||||
return;
|
||||
}
|
||||
|
||||
if( 0.0 > diffLine && 0.0 > diffCenter) {
|
||||
RS_Line* line {new RS_Line( this,
|
||||
dimLine.getStartpoint(),
|
||||
dimPoint - dirStart * av.exe())};
|
||||
|
||||
line->setPen( pen);
|
||||
line->setLayer( nullptr);
|
||||
addEntity( line);
|
||||
}
|
||||
else if( 1.0 < diffLine && 0.0 < diffCenter) {
|
||||
RS_Line* line {new RS_Line( this,
|
||||
dimLine.getEndpoint(),
|
||||
dimPoint - dirEnd * av.exe())};
|
||||
|
||||
line->setPen( pen);
|
||||
line->setLayer( nullptr);
|
||||
addEntity( line);
|
||||
}
|
||||
else if( 0.0 > diffLine && 1.0 < diffCenter) {
|
||||
RS_Line* line {new RS_Line( this,
|
||||
dimCenter - dirStart * av.exo(),
|
||||
dimPoint + dirEnd * av.exe())};
|
||||
|
||||
line->setPen( pen);
|
||||
line->setLayer( nullptr);
|
||||
addEntity( line);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Add an arrow to the dimension arc
|
||||
*
|
||||
* @param point arc endpoint, the arrow tip
|
||||
* @param angle the angle from center to the arc endpoint
|
||||
* @param direction this holds the sign for the arrow endpoint direction
|
||||
* @param outsideArrow when the arc becomes too small, arrows are placed outside
|
||||
* @param av DXF variables with offset and extension line length
|
||||
* @param pen pen to draw the extension line
|
||||
*/
|
||||
void RS_DimAngular::arrow(const RS_Vector& point,
|
||||
const double angle,
|
||||
const double direction,
|
||||
const bool outsideArrows,
|
||||
const LC_DimAngularVars& av,
|
||||
const RS_Pen& pen)
|
||||
{
|
||||
if (RS_TOLERANCE_ANGLE >= av.arrow()) {
|
||||
// arrow size is 0, no need to add an arrow
|
||||
return;
|
||||
}
|
||||
|
||||
double arrowAngle {0.0};
|
||||
|
||||
if (outsideArrows) {
|
||||
// for outside arrows use tangent angle on endpoints
|
||||
// because for small radius the arrows looked inclined
|
||||
arrowAngle = angle + std::copysign( M_PI_2, direction);
|
||||
}
|
||||
else {
|
||||
// compute the angle from center to the endpoint of the arrow on the arc
|
||||
double endAngle {0.0};
|
||||
if (RS_TOLERANCE_ANGLE < dimRadius) {
|
||||
endAngle = av.arrow() / dimRadius;
|
||||
}
|
||||
|
||||
// compute the endpoint of the arrow on the arc
|
||||
RS_Vector arrowEnd;
|
||||
arrowEnd.setPolar( dimRadius, angle + std::copysign( endAngle, direction));
|
||||
arrowEnd += dimCenter;
|
||||
arrowAngle = arrowEnd.angleTo( point);
|
||||
}
|
||||
|
||||
RS_SolidData sd;
|
||||
RS_Solid* arrow;
|
||||
|
||||
arrow = new RS_Solid( this, sd);
|
||||
arrow->shapeArrow( point, arrowAngle, av.arrow());
|
||||
arrow->setPen( pen);
|
||||
arrow->setLayer( nullptr);
|
||||
addEntity( arrow);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the sub entities of this dimension. Called when the
|
||||
* dimension or the position, alignment, .. changes.
|
||||
*
|
||||
* @param autoText Automatically reposition the text label
|
||||
*/
|
||||
void RS_DimAngular::updateDim(bool autoText /*= false*/)
|
||||
{
|
||||
Q_UNUSED( autoText)
|
||||
RS_DEBUG->print("RS_DimAngular::update");
|
||||
|
||||
clear();
|
||||
|
||||
if (isUndone()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! dimCenter.valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
LC_DimAngularVars av( getGeneralScale(),
|
||||
getExtensionLineOffset(),
|
||||
getExtensionLineExtension(),
|
||||
getTextHeight(),
|
||||
getDimensionLineGap(),
|
||||
getArrowSize());
|
||||
|
||||
// create new lines with offsets for extension lines
|
||||
RS_ConstructionLine line1( nullptr,
|
||||
RS_ConstructionLineData( dimLine1.getStartpoint() - dimDir1s * av.exo(),
|
||||
dimLine1.getEndpoint() - dimDir1e * av.exo()));
|
||||
RS_ConstructionLine line2( nullptr,
|
||||
RS_ConstructionLineData( dimLine2.getStartpoint() - dimDir2s * av.exo(),
|
||||
dimLine2.getEndpoint() - dimDir2e * av.exo()));
|
||||
|
||||
RS_Vector p1 {dimCenter + dimDir1e * dimRadius};
|
||||
RS_Vector p2 {dimCenter + dimDir2e * dimRadius};
|
||||
RS_Pen pen( getExtensionLineColor(), getExtensionLineWidth(), RS2::LineByBlock);
|
||||
|
||||
extensionLine( line1, p1, dimDir1s, dimDir1e, av, pen);
|
||||
extensionLine( line2, p2, dimDir2s, dimDir2e, av, pen);
|
||||
|
||||
// Create dimension line (arc)
|
||||
RS_Arc* arc {new RS_Arc( this, RS_ArcData( dimCenter, dimRadius, dimAngleL1, dimAngleL2, false))};
|
||||
pen.setWidth( getDimensionLineWidth());
|
||||
pen.setColor( getDimensionLineColor());
|
||||
arc->setPen( pen);
|
||||
arc->setLayer( nullptr);
|
||||
addEntity( arc);
|
||||
|
||||
// do we have to put the arrows outside of the arc?
|
||||
bool outsideArrows {arc->getLength() < 3.0 * av.arrow()};
|
||||
|
||||
arrow( p1, dimAngleL1, +1.0, outsideArrows, av, pen);
|
||||
arrow( p2, dimAngleL2, -1.0, outsideArrows, av, pen);
|
||||
|
||||
// text label
|
||||
RS_MTextData textData;
|
||||
RS_Vector textPos {arc->getMiddlePoint()};
|
||||
|
||||
RS_Vector distV;
|
||||
double textAngle {0.0};
|
||||
double angle1 {textPos.angleTo( dimCenter) - M_PI_2};
|
||||
|
||||
// rotate text so it's readable from the bottom or right (ISO)
|
||||
// quadrant 1 & 4
|
||||
if (angle1 > M_PI_2 * 3.0 + 0.001
|
||||
|| angle1 < M_PI_2 + 0.001) {
|
||||
distV.setPolar( av.gap(), angle1 + M_PI_2);
|
||||
textAngle = angle1;
|
||||
}
|
||||
// quadrant 2 & 3
|
||||
else {
|
||||
distV.setPolar( av.gap(), angle1 - M_PI_2);
|
||||
textAngle = angle1 + M_PI;
|
||||
}
|
||||
|
||||
// move text away from dimension line:
|
||||
textPos += distV;
|
||||
|
||||
textData = RS_MTextData( textPos,
|
||||
av.txt(), 30.0,
|
||||
RS_MTextData::VABottom,
|
||||
RS_MTextData::HACenter,
|
||||
RS_MTextData::LeftToRight,
|
||||
RS_MTextData::Exact,
|
||||
1.0,
|
||||
getLabel(),
|
||||
getTextStyle(),
|
||||
textAngle);
|
||||
|
||||
RS_MText* text {new RS_MText( this, textData)};
|
||||
|
||||
// move text to the side:
|
||||
text->setPen( RS_Pen( getTextColor(), RS2::WidthByBlock, RS2::SolidLine));
|
||||
text->setLayer( nullptr);
|
||||
addEntity( text);
|
||||
|
||||
calculateBorders();
|
||||
}
|
||||
|
||||
void RS_DimAngular::update()
|
||||
{
|
||||
calcDimension();
|
||||
RS_Dimension::update();
|
||||
}
|
||||
|
||||
void RS_DimAngular::move(const RS_Vector& offset)
|
||||
{
|
||||
RS_Dimension::move( offset);
|
||||
|
||||
edata.definitionPoint1.move( offset);
|
||||
edata.definitionPoint2.move( offset);
|
||||
edata.definitionPoint3.move( offset);
|
||||
edata.definitionPoint4.move( offset);
|
||||
update();
|
||||
}
|
||||
|
||||
void RS_DimAngular::rotate(const RS_Vector& center, const double& angle)
|
||||
{
|
||||
rotate( center, RS_Vector( angle));
|
||||
}
|
||||
|
||||
void RS_DimAngular::rotate(const RS_Vector& center, const RS_Vector& angleVector)
|
||||
{
|
||||
RS_Dimension::rotate( center, angleVector);
|
||||
|
||||
edata.definitionPoint1.rotate( center, angleVector);
|
||||
edata.definitionPoint2.rotate( center, angleVector);
|
||||
edata.definitionPoint3.rotate( center, angleVector);
|
||||
edata.definitionPoint4.rotate( center, angleVector);
|
||||
update();
|
||||
}
|
||||
|
||||
void RS_DimAngular::scale(const RS_Vector& center, const RS_Vector& factor)
|
||||
{
|
||||
RS_Dimension::scale( center, factor);
|
||||
|
||||
edata.definitionPoint1.scale( center, factor);
|
||||
edata.definitionPoint2.scale( center, factor);
|
||||
edata.definitionPoint3.scale( center, factor);
|
||||
edata.definitionPoint4.scale( center, factor);
|
||||
update();
|
||||
}
|
||||
|
||||
void RS_DimAngular::mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2)
|
||||
{
|
||||
RS_Dimension::mirror( axisPoint1, axisPoint2);
|
||||
|
||||
edata.definitionPoint1.mirror( axisPoint1, axisPoint2);
|
||||
edata.definitionPoint2.mirror( axisPoint1, axisPoint2);
|
||||
edata.definitionPoint3.mirror( axisPoint1, axisPoint2);
|
||||
edata.definitionPoint4.mirror( axisPoint1, axisPoint2);
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compute all static values for dimension.
|
||||
*
|
||||
* From DXF reference the lines are P2-P1 and P-P3.
|
||||
* The dimension is drawn from line1 (P2-P1) to line2 (P-P3) in CCW direction.
|
||||
*/
|
||||
void RS_DimAngular::calcDimension(void)
|
||||
{
|
||||
// get unit vectors for definition points
|
||||
dimDir1s = RS_Vector::polar( 1.0, RS_Math::correctAngle( edata.definitionPoint2.angleTo( edata.definitionPoint1)));
|
||||
dimDir1e = RS_Vector::polar( 1.0, RS_Math::correctAngle( edata.definitionPoint1.angleTo( edata.definitionPoint2)));
|
||||
dimDir2s = RS_Vector::polar( 1.0, RS_Math::correctAngle( data.definitionPoint.angleTo( edata.definitionPoint3)));
|
||||
dimDir2e = RS_Vector::polar( 1.0, RS_Math::correctAngle( edata.definitionPoint3.angleTo( data.definitionPoint)));
|
||||
|
||||
// create the two dimension definition lines
|
||||
dimLine1 = RS_ConstructionLine( nullptr,
|
||||
RS_ConstructionLineData( edata.definitionPoint2,
|
||||
edata.definitionPoint1));
|
||||
dimLine2 = RS_ConstructionLine( nullptr,
|
||||
RS_ConstructionLineData( data.definitionPoint,
|
||||
edata.definitionPoint3));
|
||||
|
||||
RS_VectorSolutions vs {RS_Information::getIntersection( &dimLine1, &dimLine2, false)};
|
||||
dimCenter = vs.get(0);
|
||||
dimRadius = dimCenter.distanceTo( edata.definitionPoint4);
|
||||
dimDirRad = RS_Vector::polar( 1.0, RS_Math::correctAngle( dimCenter.angleTo( edata.definitionPoint4)));
|
||||
|
||||
fixDimension();
|
||||
|
||||
dimAngleL1 = dimLine1.getDirection2();
|
||||
dimAngleL2 = dimLine2.getDirection2();
|
||||
|
||||
dimAngle = RS_Math::correctAngle( dimLine2.getDirection1() - dimLine1.getDirection1());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief check the dimension and fix non conform values from foreign CAD systems
|
||||
*
|
||||
* check if the radius definition point is on the arc,
|
||||
* from line1 to line2 in counter clockwise direction
|
||||
* LibreCAD takes care on correct orientation and line order in RS_ActionDimAngular
|
||||
* but angular dimensions, created in other CAD software, may fail and must be fixed here
|
||||
*/
|
||||
void RS_DimAngular::fixDimension(void)
|
||||
{
|
||||
if( ! RS_Math::isAngleBetween( dimDirRad.angle(), dimDir2s.angle(), dimDir1s.angle(), false)) {
|
||||
double distance0 {data.definitionPoint.distanceTo( dimCenter)};
|
||||
double distance1 {edata.definitionPoint1.distanceTo( dimCenter)};
|
||||
double distance2 {edata.definitionPoint2.distanceTo( dimCenter)};
|
||||
double distance3 {edata.definitionPoint3.distanceTo( dimCenter)};
|
||||
double angle0 {0.0};
|
||||
double angle1 {0.0};
|
||||
double angle2 {0.0};
|
||||
double angle3 {0.0};
|
||||
if( RS_TOLERANCE >= distance0) {
|
||||
angle3 = (edata.definitionPoint3 - dimCenter).angle();
|
||||
angle0 = angle3;
|
||||
}
|
||||
else if( RS_TOLERANCE >= distance3) {
|
||||
angle0 = (data.definitionPoint - dimCenter).angle();
|
||||
angle3 = angle0;
|
||||
}
|
||||
else {
|
||||
angle0 = (data.definitionPoint - dimCenter).angle();
|
||||
angle3 = (edata.definitionPoint3 - dimCenter).angle();
|
||||
}
|
||||
|
||||
if( RS_TOLERANCE >= distance1) {
|
||||
angle2 = (edata.definitionPoint2- dimCenter).angle();
|
||||
angle1 = angle2;
|
||||
}
|
||||
else if( RS_TOLERANCE >= distance2) {
|
||||
angle1 = (edata.definitionPoint1 - dimCenter).angle();
|
||||
angle2 = angle1;
|
||||
}
|
||||
else {
|
||||
angle1 = (edata.definitionPoint1 - dimCenter).angle();
|
||||
angle2 = (edata.definitionPoint2 - dimCenter).angle();
|
||||
}
|
||||
|
||||
if( angle2 == angle1
|
||||
&& distance2 < distance1
|
||||
&& angle0 == angle3
|
||||
&& distance0 < distance3) {
|
||||
// revert both lines
|
||||
dimLine1 = RS_ConstructionLine( nullptr,
|
||||
RS_ConstructionLineData( dimLine1.getEndpoint(),
|
||||
dimLine1.getStartpoint()));
|
||||
dimLine2 = RS_ConstructionLine( nullptr,
|
||||
RS_ConstructionLineData( dimLine2.getEndpoint(),
|
||||
dimLine2.getStartpoint()));
|
||||
|
||||
// and their unit vectors
|
||||
RS_Vector swapDir {dimDir1s};
|
||||
dimDir1s = dimDir1e;
|
||||
dimDir1e = swapDir;
|
||||
|
||||
swapDir = dimDir2s;
|
||||
dimDir2s = dimDir2e;
|
||||
dimDir2e = swapDir;
|
||||
}
|
||||
|
||||
// check again, as the previous revert may have made this condition false
|
||||
if( ! RS_Math::isAngleBetween( dimDirRad.angle(), dimDir2s.angle(), dimDir1s.angle(), false)) {
|
||||
// swap the lines
|
||||
RS_ConstructionLine swapLine {dimLine1};
|
||||
dimLine1 = dimLine2;
|
||||
dimLine2 = swapLine;
|
||||
|
||||
// and their unit vectors
|
||||
RS_Vector swapDir {dimDir1s};
|
||||
dimDir1s = dimDir2s;
|
||||
dimDir2s = swapDir;
|
||||
|
||||
swapDir = dimDir1e;
|
||||
dimDir1e = dimDir2e;
|
||||
dimDir2e = swapDir;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps the point's data to stdout.
|
||||
*/
|
||||
std::ostream& operator << (std::ostream& os, const RS_DimAngular& d)
|
||||
{
|
||||
os << " DimAngular: "
|
||||
<< d.getData() << std::endl
|
||||
<< d.getEData() << std::endl;
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream& operator << (std::ostream& os, const RS_DimAngularData& dd)
|
||||
{
|
||||
os << "(" << dd.definitionPoint1
|
||||
<< "," << dd.definitionPoint2
|
||||
<< "," << dd.definitionPoint3
|
||||
<< "," << dd.definitionPoint3
|
||||
<< ")";
|
||||
|
||||
return os;
|
||||
}
|
||||
193
lib/engine/rs_dimangular.h
Normal file
193
lib/engine/rs_dimangular.h
Normal file
@@ -0,0 +1,193 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2018 A. Stebich (librecad@mail.lordofbikes.de)
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef RS_DIMANGULAR_H
|
||||
#define RS_DIMANGULAR_H
|
||||
|
||||
#include "rs_dimension.h"
|
||||
#include "rs_constructionline.h"
|
||||
|
||||
/**
|
||||
* Holds the data that defines a angular dimension entity.
|
||||
*/
|
||||
struct RS_DimAngularData
|
||||
{
|
||||
RS_DimAngularData();
|
||||
RS_DimAngularData(const RS_DimAngularData& ed);
|
||||
|
||||
/**
|
||||
* Constructor with initialisation.
|
||||
*
|
||||
* @param definitionPoint Definition point of the angular dimension.
|
||||
* @param leader Leader length.
|
||||
*/
|
||||
RS_DimAngularData(const RS_Vector& definitionPoint1,
|
||||
const RS_Vector& definitionPoint2,
|
||||
const RS_Vector& definitionPoint3,
|
||||
const RS_Vector& definitionPoint4);
|
||||
|
||||
RS_Vector definitionPoint1; ///< 1st line start point, DXF codes 13,23,33
|
||||
RS_Vector definitionPoint2; ///< 1st line end point, DXF codes 14,24,34
|
||||
RS_Vector definitionPoint3; ///< 2nd line start point, DXF codes 15,25,35
|
||||
///< 2nd line end point is in common dim data, DXF codes 10,20,30
|
||||
RS_Vector definitionPoint4; ///< dim arc radius point, DXF codes 16,26,36
|
||||
};
|
||||
|
||||
std::ostream& operator << (std::ostream& os, const RS_DimAngularData& dd);
|
||||
|
||||
/**
|
||||
* Holds the DXF variables that defines a angular dimension entity.
|
||||
*/
|
||||
struct LC_DimAngularVars
|
||||
{
|
||||
explicit LC_DimAngularVars(const double _dimscale,
|
||||
const double _dimexo,
|
||||
const double _dimexe,
|
||||
const double _dimtxt,
|
||||
const double _dimgap,
|
||||
const double _arrowSize);
|
||||
explicit LC_DimAngularVars(const LC_DimAngularVars& av);
|
||||
|
||||
double scale(void) const {
|
||||
return dimscale;
|
||||
}
|
||||
double exo(void) const {
|
||||
return dimexo;
|
||||
}
|
||||
double exe(void) const {
|
||||
return dimexe;
|
||||
}
|
||||
double txt(void) const {
|
||||
return dimtxt;
|
||||
}
|
||||
double gap(void) const {
|
||||
return dimgap;
|
||||
}
|
||||
double arrow(void) const {
|
||||
return arrowSize;
|
||||
}
|
||||
|
||||
private:
|
||||
double dimscale {1.0}; ///< general scale (DIMSCALE)
|
||||
double dimexo {0.0}; ///< distance from entities (DIMEXO)
|
||||
double dimexe {0.0}; ///< extension line extension (DIMEXE)
|
||||
double dimtxt {0.0}; ///< text height (DIMTXT)
|
||||
double dimgap {0.0}; ///< text distance to line (DIMGAP)
|
||||
double arrowSize {0.0}; ///< arrow length
|
||||
};
|
||||
|
||||
std::ostream& operator << (std::ostream& os, const LC_DimAngularVars& dd);
|
||||
|
||||
/**
|
||||
* Class for angular dimension entities.
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_DimAngular : public RS_Dimension
|
||||
{
|
||||
friend std::ostream& operator << (std::ostream& os, const RS_DimAngular& d);
|
||||
|
||||
public:
|
||||
RS_DimAngular(RS_EntityContainer* parent,
|
||||
const RS_DimensionData& d,
|
||||
const RS_DimAngularData& ed);
|
||||
|
||||
RS_Entity* clone() const override;
|
||||
|
||||
/** @return RS2::EntityDimAngular */
|
||||
RS2::EntityType rtti() const override {
|
||||
return RS2::EntityDimAngular;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Copy of data that defines the angular dimension.
|
||||
* @see getData()
|
||||
*/
|
||||
RS_DimAngularData getEData() const {
|
||||
return edata;
|
||||
}
|
||||
|
||||
QString getMeasuredLabel() override;
|
||||
RS_Vector getCenter() const override;
|
||||
|
||||
void updateDim(bool autoText = false) override;
|
||||
|
||||
RS_Vector getDefinitionPoint1() {
|
||||
return edata.definitionPoint1;
|
||||
}
|
||||
RS_Vector getDefinitionPoint2() {
|
||||
return edata.definitionPoint2;
|
||||
}
|
||||
RS_Vector getDefinitionPoint3() {
|
||||
return edata.definitionPoint3;
|
||||
}
|
||||
RS_Vector getDefinitionPoint4() {
|
||||
return edata.definitionPoint4;
|
||||
}
|
||||
|
||||
void update() override;
|
||||
void move(const RS_Vector& offset) override;
|
||||
void rotate(const RS_Vector& center, const double& angle) override;
|
||||
void rotate(const RS_Vector& center, const RS_Vector& angleVector) override;
|
||||
void scale(const RS_Vector& center, const RS_Vector& factor) override;
|
||||
void mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) override;
|
||||
|
||||
protected:
|
||||
/** Extended data. */
|
||||
RS_DimAngularData edata;
|
||||
|
||||
private:
|
||||
void calcDimension(void);
|
||||
void fixDimension(void);
|
||||
void extensionLine(const RS_ConstructionLine& dimLine,
|
||||
const RS_Vector& dimPoint,
|
||||
const RS_Vector& dirStart,
|
||||
const RS_Vector& dirEnd,
|
||||
const LC_DimAngularVars& av,
|
||||
const RS_Pen& pen);
|
||||
void arrow(const RS_Vector& point,
|
||||
const double angle,
|
||||
const double direction,
|
||||
const bool outsideArrows,
|
||||
const LC_DimAngularVars& av,
|
||||
const RS_Pen& pen);
|
||||
|
||||
RS_Vector dimDir1s;
|
||||
RS_Vector dimDir1e;
|
||||
RS_Vector dimDir2s;
|
||||
RS_Vector dimDir2e;
|
||||
RS_Vector dimDirRad;
|
||||
RS_ConstructionLine dimLine1;
|
||||
RS_ConstructionLine dimLine2;
|
||||
double dimRadius {0.0};
|
||||
double dimAngleL1 {0.0};
|
||||
double dimAngleL2 {0.0};
|
||||
double dimAngle {0.0}; ///< angle to dimension in rad
|
||||
RS_Vector dimCenter; ///< intersection point of the dimension lines
|
||||
};
|
||||
|
||||
#endif
|
||||
225
lib/engine/rs_dimdiametric.cpp
Normal file
225
lib/engine/rs_dimdiametric.cpp
Normal file
@@ -0,0 +1,225 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
#include<iostream>
|
||||
#include "rs_dimdiametric.h"
|
||||
#include "rs_mtext.h"
|
||||
#include "rs_solid.h"
|
||||
#include "rs_graphic.h"
|
||||
#include "rs_units.h"
|
||||
#include "rs_debug.h"
|
||||
|
||||
RS_DimDiametricData::RS_DimDiametricData():
|
||||
definitionPoint(false),
|
||||
leader(0.0)
|
||||
{}
|
||||
|
||||
/**
|
||||
* Constructor with initialisation.
|
||||
*
|
||||
* @param definitionPoint Definition point of the diametric dimension.
|
||||
* @param leader Leader length.
|
||||
*/
|
||||
RS_DimDiametricData::RS_DimDiametricData(const RS_Vector& _definitionPoint,
|
||||
double _leader):
|
||||
definitionPoint(_definitionPoint)
|
||||
,leader(_leader)
|
||||
{
|
||||
}
|
||||
|
||||
std::ostream& operator << (std::ostream& os,
|
||||
const RS_DimDiametricData& dd) {
|
||||
os << "(" << dd.definitionPoint << "," << dd.leader << ")";
|
||||
return os;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @para parent Parent Entity Container.
|
||||
* @para d Common dimension geometrical data.
|
||||
* @para ed Extended geometrical data for diametric dimension.
|
||||
*/
|
||||
RS_DimDiametric::RS_DimDiametric(RS_EntityContainer* parent,
|
||||
const RS_DimensionData& d,
|
||||
const RS_DimDiametricData& ed)
|
||||
: RS_Dimension(parent, d), edata(ed) {
|
||||
|
||||
calculateBorders();
|
||||
}
|
||||
|
||||
RS_Entity* RS_DimDiametric::clone() const {
|
||||
RS_DimDiametric* d = new RS_DimDiametric(*this);
|
||||
d->setOwner(isOwner());
|
||||
d->initId();
|
||||
d->detach();
|
||||
return d;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Automatically created label for the default
|
||||
* measurement of this dimension.
|
||||
*/
|
||||
QString RS_DimDiametric::getMeasuredLabel() {
|
||||
|
||||
// Definitive dimension line:
|
||||
double dist = data.definitionPoint.distanceTo(edata.definitionPoint) * getGeneralFactor();
|
||||
|
||||
RS_Graphic* graphic = getGraphic();
|
||||
|
||||
QString ret;
|
||||
if (graphic) {
|
||||
int dimlunit = getGraphicVariableInt("$DIMLUNIT", 2);
|
||||
int dimdec = getGraphicVariableInt("$DIMDEC", 4);
|
||||
int dimzin = getGraphicVariableInt("$DIMZIN", 1);
|
||||
RS2::LinearFormat format = graphic->getLinearFormat(dimlunit);
|
||||
ret = RS_Units::formatLinear(dist, RS2::None, format, dimdec);
|
||||
if (format == RS2::Decimal)
|
||||
ret = stripZerosLinear(ret, dimzin);
|
||||
//verify if units are decimal and comma separator
|
||||
if (format == RS2::Decimal || format == RS2::ArchitecturalMetric){
|
||||
if (getGraphicVariableInt("$DIMDSEP", 0) == 44)
|
||||
ret.replace(QChar('.'), QChar(','));
|
||||
}
|
||||
}
|
||||
else {
|
||||
ret = QString("%1").arg(dist);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
RS_VectorSolutions RS_DimDiametric::getRefPoints() const
|
||||
{
|
||||
return RS_VectorSolutions({edata.definitionPoint,
|
||||
data.definitionPoint, data.middleOfText});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Updates the sub entities of this dimension. Called when the
|
||||
* dimension or the position, alignment, .. changes.
|
||||
*
|
||||
* @param autoText Automatically reposition the text label
|
||||
*/
|
||||
void RS_DimDiametric::updateDim(bool autoText) {
|
||||
|
||||
RS_DEBUG->print("RS_DimDiametric::update");
|
||||
|
||||
clear();
|
||||
|
||||
if (isUndone()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// dimension line:
|
||||
updateCreateDimensionLine(data.definitionPoint, edata.definitionPoint,
|
||||
true, true, autoText);
|
||||
|
||||
calculateBorders();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_DimDiametric::move(const RS_Vector& offset) {
|
||||
RS_Dimension::move(offset);
|
||||
|
||||
edata.definitionPoint.move(offset);
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_DimDiametric::rotate(const RS_Vector& center, const double& angle) {
|
||||
rotate(center,RS_Vector(angle));
|
||||
}
|
||||
|
||||
void RS_DimDiametric::rotate(const RS_Vector& center, const RS_Vector& angleVector) {
|
||||
RS_Dimension::rotate(center, angleVector);
|
||||
|
||||
edata.definitionPoint.rotate(center, angleVector);
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
void RS_DimDiametric::scale(const RS_Vector& center, const RS_Vector& factor) {
|
||||
RS_Dimension::scale(center, factor);
|
||||
|
||||
edata.definitionPoint.scale(center, factor);
|
||||
edata.leader*=factor.x;
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_DimDiametric::mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) {
|
||||
RS_Dimension::mirror(axisPoint1, axisPoint2);
|
||||
|
||||
edata.definitionPoint.mirror(axisPoint1, axisPoint2);
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_DimDiametric::moveRef(const RS_Vector& ref, const RS_Vector& offset) {
|
||||
|
||||
if (ref.distanceTo(edata.definitionPoint)<1.0e-4) {
|
||||
RS_Vector c = (edata.definitionPoint + data.definitionPoint)/2.0;
|
||||
double d = c.distanceTo(edata.definitionPoint);
|
||||
double a = c.angleTo(edata.definitionPoint + offset);
|
||||
|
||||
RS_Vector v = RS_Vector::polar(d, a);
|
||||
edata.definitionPoint = c + v;
|
||||
data.definitionPoint = c - v;
|
||||
updateDim(true);
|
||||
}
|
||||
else if (ref.distanceTo(data.definitionPoint)<1.0e-4) {
|
||||
RS_Vector c = (edata.definitionPoint + data.definitionPoint)/2.0;
|
||||
double d = c.distanceTo(data.definitionPoint);
|
||||
double a = c.angleTo(data.definitionPoint + offset);
|
||||
|
||||
RS_Vector v = RS_Vector::polar(d, a);
|
||||
data.definitionPoint = c + v;
|
||||
edata.definitionPoint = c - v;
|
||||
updateDim(true);
|
||||
}
|
||||
else if (ref.distanceTo(data.middleOfText)<1.0e-4) {
|
||||
data.middleOfText.move(offset);
|
||||
updateDim(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Dumps the point's data to stdout.
|
||||
*/
|
||||
std::ostream& operator << (std::ostream& os, const RS_DimDiametric& d) {
|
||||
os << " DimDiametric: " << d.getData() << "\n" << d.getEData() << "\n";
|
||||
return os;
|
||||
}
|
||||
114
lib/engine/rs_dimdiametric.h
Normal file
114
lib/engine/rs_dimdiametric.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_DIMDIAMETER_H
|
||||
#define RS_DIMDIAMETER_H
|
||||
|
||||
#include "rs_dimension.h"
|
||||
|
||||
/**
|
||||
* Holds the data that defines a diametric dimension entity.
|
||||
*/
|
||||
struct RS_DimDiametricData {
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
RS_DimDiametricData();
|
||||
|
||||
/**
|
||||
* Constructor with initialisation.
|
||||
*
|
||||
* @param definitionPoint Definition point of the diametric dimension.
|
||||
* @param leader Leader length.
|
||||
*/
|
||||
RS_DimDiametricData(const RS_Vector& definitionPoint,
|
||||
double leader);
|
||||
|
||||
|
||||
/** Definition point. */
|
||||
RS_Vector definitionPoint;
|
||||
/** Leader length. */
|
||||
double leader;
|
||||
};
|
||||
|
||||
std::ostream& operator << (std::ostream& os, const RS_DimDiametricData& dd);
|
||||
|
||||
/**
|
||||
* Class for diametric dimension entities.
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_DimDiametric : public RS_Dimension {
|
||||
public:
|
||||
RS_DimDiametric(RS_EntityContainer* parent,
|
||||
const RS_DimensionData& d,
|
||||
const RS_DimDiametricData& ed);
|
||||
|
||||
RS_Entity* clone() const override;
|
||||
|
||||
/** @return RS2::EntityDimDiametric */
|
||||
RS2::EntityType rtti() const override{
|
||||
return RS2::EntityDimDiametric;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Copy of data that defines the diametric dimension.
|
||||
* @see getData()
|
||||
*/
|
||||
RS_DimDiametricData getEData() const {
|
||||
return edata;
|
||||
}
|
||||
|
||||
RS_VectorSolutions getRefPoints() const override;
|
||||
|
||||
QString getMeasuredLabel() override;
|
||||
|
||||
void updateDim(bool autoText=false) override;
|
||||
|
||||
RS_Vector getDefinitionPoint() {
|
||||
return edata.definitionPoint;
|
||||
}
|
||||
double getLeader() {
|
||||
return edata.leader;
|
||||
}
|
||||
void move(const RS_Vector& offset) override;
|
||||
void rotate(const RS_Vector& center, const double& angle) override;
|
||||
void rotate(const RS_Vector& center, const RS_Vector& angleVector) override;
|
||||
void scale(const RS_Vector& center, const RS_Vector& factor) override;
|
||||
void mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) override;
|
||||
|
||||
void moveRef(const RS_Vector& ref, const RS_Vector& offset) override;
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os,
|
||||
const RS_DimDiametric& d);
|
||||
|
||||
protected:
|
||||
/** Extended data. */
|
||||
RS_DimDiametricData edata;
|
||||
};
|
||||
|
||||
#endif
|
||||
892
lib/engine/rs_dimension.cpp
Normal file
892
lib/engine/rs_dimension.cpp
Normal file
@@ -0,0 +1,892 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
#include<iostream>
|
||||
#include<cmath>
|
||||
#include<string>
|
||||
#include "rs_information.h"
|
||||
#include "rs_line.h"
|
||||
#include "rs_dimension.h"
|
||||
#include "rs_solid.h"
|
||||
#include "rs_units.h"
|
||||
#include "rs_math.h"
|
||||
#include "rs_filterdxfrw.h" //for int <-> rs_color conversion
|
||||
#include "rs_debug.h"
|
||||
|
||||
RS_DimensionData::RS_DimensionData():
|
||||
definitionPoint(false),
|
||||
middleOfText(false),
|
||||
valign(RS_MTextData::VABottom),
|
||||
halign(RS_MTextData::HALeft),
|
||||
lineSpacingStyle(RS_MTextData::Exact),
|
||||
lineSpacingFactor(0.0),
|
||||
text(""),
|
||||
style(""),
|
||||
angle(0.0)
|
||||
{}
|
||||
|
||||
/**
|
||||
* Constructor with initialisation.
|
||||
*
|
||||
* @param definitionPoint Definition point.
|
||||
* @param middleOfText Middle point of dimension text.
|
||||
* @param valign Vertical alignment.
|
||||
* @param halign Horizontal alignment.
|
||||
* @param lineSpacingStyle Line spacing style.
|
||||
* @param lineSpacingFactor Line spacing factor.
|
||||
* @param text Text string entered explicitly by user or null
|
||||
* or "<>" for the actual measurement or " " (one blank space).
|
||||
* for suppressing the text.
|
||||
* @param style Dimension style name.
|
||||
* @param angle Rotation angle of dimension text away from
|
||||
* default orientation.
|
||||
*/
|
||||
RS_DimensionData::RS_DimensionData(const RS_Vector& _definitionPoint,
|
||||
const RS_Vector& _middleOfText,
|
||||
RS_MTextData::VAlign _valign,
|
||||
RS_MTextData::HAlign _halign,
|
||||
RS_MTextData::MTextLineSpacingStyle _lineSpacingStyle,
|
||||
double _lineSpacingFactor,
|
||||
QString _text,
|
||||
QString _style,
|
||||
double _angle):
|
||||
definitionPoint(_definitionPoint)
|
||||
,middleOfText(_middleOfText)
|
||||
,valign(_valign)
|
||||
,halign(_halign)
|
||||
,lineSpacingStyle(_lineSpacingStyle)
|
||||
,lineSpacingFactor(_lineSpacingFactor)
|
||||
,text(_text)
|
||||
,style(_style)
|
||||
,angle(_angle)
|
||||
{
|
||||
}
|
||||
|
||||
std::ostream& operator << (std::ostream& os,
|
||||
const RS_DimensionData& dd) {
|
||||
os << "("
|
||||
<< dd.definitionPoint<<','
|
||||
<<dd.middleOfText<<','
|
||||
<<dd.valign<<','
|
||||
<<dd.halign<<','
|
||||
<<dd.lineSpacingStyle<<','
|
||||
<<dd.lineSpacingFactor<<','
|
||||
<<dd.text.toLatin1().data() <<','
|
||||
<<dd.style.toLatin1().data()<<','
|
||||
<<dd.angle
|
||||
<< ")";
|
||||
return os;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
RS_Dimension::RS_Dimension(RS_EntityContainer* parent,
|
||||
const RS_DimensionData& d)
|
||||
: RS_EntityContainer(parent), data(d) {
|
||||
}
|
||||
|
||||
RS_Vector RS_Dimension::getNearestRef( const RS_Vector& coord,
|
||||
double* dist /*= nullptr*/) const
|
||||
{
|
||||
// override the RS_EntityContainer method
|
||||
// use RS_Entity instead for refpoint dragging
|
||||
return RS_Entity::getNearestRef( coord, dist);
|
||||
}
|
||||
|
||||
RS_Vector RS_Dimension::getNearestSelectedRef( const RS_Vector& coord,
|
||||
double* dist /*= nullptr*/) const
|
||||
{
|
||||
// override the RS_EntityContainer method
|
||||
// use RS_Entity instead for refpoint dragging
|
||||
return RS_Entity::getNearestSelectedRef( coord, dist);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Dimension text. Either a text the user defined or
|
||||
* the measured text.
|
||||
*
|
||||
* @param resolve false: return plain value. true: return measured
|
||||
* label if appropriate.
|
||||
* @see getMeasuredLabel
|
||||
*/
|
||||
QString RS_Dimension::getLabel(bool resolve) {
|
||||
if (!resolve) {
|
||||
return data.text;
|
||||
}
|
||||
|
||||
QString ret="";
|
||||
|
||||
// One space suppresses the text:
|
||||
if (data.text==" ") {
|
||||
ret = "";
|
||||
}
|
||||
|
||||
// No text prints actual measurement:
|
||||
else if (data.text=="") {
|
||||
ret = getMeasuredLabel();
|
||||
}
|
||||
|
||||
// Others print the text (<> is replaced by the measurement)
|
||||
else {
|
||||
ret = data.text;
|
||||
ret = ret.replace(QString("<>"), getMeasuredLabel());
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets a new text for the label.
|
||||
*/
|
||||
void RS_Dimension::setLabel(const QString& l) {
|
||||
data.text = l;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find intersections between a line and an EntityContainer. Solutions are
|
||||
* sorted along the line before returning.
|
||||
*
|
||||
* @param infiniteLine Treat the line as infinitely long in both directions.
|
||||
*/
|
||||
RS_VectorSolutions RS_Dimension::getIntersectionsLineContainer(
|
||||
const RS_Line* l, const RS_EntityContainer* c, bool infiniteLine)
|
||||
{
|
||||
RS_VectorSolutions solutions_initial;
|
||||
RS_VectorSolutions solutions_filtered;
|
||||
const double tol = 1.0e-4;
|
||||
|
||||
// Find all intersections, including those beyond limits of container
|
||||
// entities.
|
||||
for(RS_Entity* e: *c) {
|
||||
solutions_initial.push_back(
|
||||
RS_Information::getIntersection(l, e, false)
|
||||
);
|
||||
}
|
||||
|
||||
// Filter solutions based on whether they are actually on any entities.
|
||||
for(const RS_Vector& vp: solutions_initial){
|
||||
for(RS_Entity* e: *c) {
|
||||
if (e->isConstruction(true) || e->isPointOnEntity(vp, tol)) {
|
||||
// the intersection is at least on the container, now check the line:
|
||||
if (infiniteLine) {
|
||||
// The line is treated as infinitely long so we don't need to
|
||||
// check if the intersection is on the line.
|
||||
solutions_filtered.push_back(vp);
|
||||
break;
|
||||
} else if (l->isConstruction(true) || l->isPointOnEntity(vp, tol)) {
|
||||
solutions_filtered.push_back(vp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We cannot sort the solutions in place because getVector() returns a
|
||||
* const vector, so first construct a copy:
|
||||
*/
|
||||
std::vector<RS_Vector> solutions_sorted(solutions_filtered.getVector());
|
||||
std::sort(solutions_sorted.begin(), solutions_sorted.end(),
|
||||
[l](const RS_Vector& lhs, const RS_Vector& rhs)
|
||||
{
|
||||
return l->getProjectionValueAlongLine(lhs)
|
||||
< l->getProjectionValueAlongLine(rhs);
|
||||
});
|
||||
|
||||
return RS_VectorSolutions(solutions_sorted);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a horizontal-text dimensioning line (line with one, two or no arrows
|
||||
* and "inside horizontal" text).
|
||||
*
|
||||
* @param forceAutoText Automatically reposition the text label.
|
||||
*/
|
||||
void RS_Dimension::updateCreateHorizontalTextDimensionLine(const RS_Vector& p1,
|
||||
const RS_Vector& p2, bool arrow1, bool arrow2, bool forceAutoText) {
|
||||
// general scale (DIMSCALE)
|
||||
double dimscale = getGeneralScale();
|
||||
// text height (DIMTXT)
|
||||
double dimtxt = getTextHeight()*dimscale;
|
||||
// text distance to line (DIMGAP)
|
||||
double dimgap = getDimensionLineGap()*dimscale;
|
||||
|
||||
// length of dimension line:
|
||||
double distance = p1.distanceTo(p2);
|
||||
// arrow size:
|
||||
double arrowSize = getArrowSize()*dimscale;
|
||||
|
||||
// arrow angles:
|
||||
double arrowAngle1, arrowAngle2;
|
||||
|
||||
RS_Pen pen(getDimensionLineColor(),
|
||||
getDimensionLineWidth(),
|
||||
RS2::LineByBlock);
|
||||
|
||||
// Create dimension line:
|
||||
RS_Line* dimensionLine {new RS_Line{this, p1, p2}};
|
||||
RS_Line* dimensionLineInside1 {nullptr};
|
||||
RS_Line* dimensionLineInside2 {nullptr};
|
||||
RS_Line* dimensionLineOutside1 {nullptr};
|
||||
RS_Line* dimensionLineOutside2 {nullptr};
|
||||
dimensionLine->setPen(pen);
|
||||
dimensionLine->setLayer(nullptr);
|
||||
|
||||
// Text label:
|
||||
RS_MTextData textData;
|
||||
RS_Vector textPos;
|
||||
double textAngle = 0.0;
|
||||
bool autoText = !data.middleOfText.valid || forceAutoText;
|
||||
|
||||
if (autoText) {
|
||||
textPos = dimensionLine->getMiddlePoint();
|
||||
|
||||
//// the next update should still be able to adjust this
|
||||
//// auto text position. leave it invalid
|
||||
data.middleOfText = textPos;
|
||||
} else {
|
||||
textPos = data.middleOfText;
|
||||
}
|
||||
|
||||
textData = RS_MTextData(textPos,
|
||||
dimtxt, 30.0,
|
||||
RS_MTextData::VAMiddle,
|
||||
RS_MTextData::HACenter,
|
||||
RS_MTextData::LeftToRight,
|
||||
RS_MTextData::Exact,
|
||||
1.0,
|
||||
getLabel(),
|
||||
getTextStyle(),
|
||||
textAngle);
|
||||
|
||||
RS_MText* text = new RS_MText(this, textData);
|
||||
text->setPen(RS_Pen(getTextColor(), RS2::WidthByBlock, RS2::SolidLine));
|
||||
text->setLayer(nullptr);
|
||||
|
||||
// evaluate intersection between dim line and text
|
||||
double textIntersectionLength = 0.0;
|
||||
double w = text->getUsedTextWidth()/2+dimgap;
|
||||
double h = text->getUsedTextHeight()/2+dimgap;
|
||||
// textCorner variables correspond to the corners of the text bounding box
|
||||
// if the text were to be positioned in the center of the dimensionLine.
|
||||
RS_Vector textCorner1 = dimensionLine->getMiddlePoint() - RS_Vector{w, h};
|
||||
RS_Vector textCorner2 = dimensionLine->getMiddlePoint() + RS_Vector{w, h};
|
||||
RS_EntityContainer c;
|
||||
c.addRectangle(textCorner1, textCorner2);
|
||||
RS_VectorSolutions sol1 = getIntersectionsLineContainer(
|
||||
dimensionLine, &c,
|
||||
true // treat line as infinitely long in both directions
|
||||
);
|
||||
textIntersectionLength = sol1.get(0).distanceTo(sol1.get(1));
|
||||
|
||||
// determine if we should use outside arrows
|
||||
bool outsideArrows = (textIntersectionLength+3*arrowSize) > distance;
|
||||
|
||||
// add arrows
|
||||
if (outsideArrows==false) {
|
||||
arrowAngle1 = dimensionLine->getAngle2();
|
||||
arrowAngle2 = dimensionLine->getAngle1();
|
||||
} else {
|
||||
arrowAngle1 = dimensionLine->getAngle1();
|
||||
arrowAngle2 = dimensionLine->getAngle2();
|
||||
|
||||
// extend dimension line outside arrows
|
||||
RS_Vector dir = RS_Vector::polar(arrowSize*2, dimensionLine->getAngle1());
|
||||
dimensionLineOutside1 = new RS_Line{this, p1 - dir, p1};
|
||||
dimensionLineOutside2 = new RS_Line{this, p2 + dir, p2};
|
||||
|
||||
// move text to the side if it won't fit either
|
||||
RS_Vector distH;
|
||||
if (textIntersectionLength>distance && autoText) {
|
||||
distH.setPolar(textIntersectionLength/2.0+arrowSize*2+distance/2.0,
|
||||
arrowAngle1);
|
||||
text->move(distH);
|
||||
textPos = text->getInsertionPoint();
|
||||
data.middleOfText = textPos;
|
||||
}
|
||||
}
|
||||
double dimtsz=getTickSize()*dimscale;
|
||||
bool displayArrows = dimtsz < 0.01;
|
||||
if(displayArrows) {
|
||||
//display arrow
|
||||
// Arrows:
|
||||
RS_SolidData sd;
|
||||
RS_Solid* arrow;
|
||||
|
||||
if (arrow1) {
|
||||
// arrow 1
|
||||
arrow = new RS_Solid(this, sd);
|
||||
arrow->shapeArrow(p1,
|
||||
arrowAngle1,
|
||||
arrowSize);
|
||||
arrow->setPen(pen);
|
||||
arrow->setLayer(nullptr);
|
||||
addEntity(arrow);
|
||||
}
|
||||
|
||||
if (arrow2) {
|
||||
// arrow 2:
|
||||
arrow = new RS_Solid(this, sd);
|
||||
arrow->shapeArrow(p2,
|
||||
arrowAngle2,
|
||||
arrowSize);
|
||||
arrow->setPen(pen);
|
||||
arrow->setLayer(nullptr);
|
||||
addEntity(arrow);
|
||||
}
|
||||
} else {
|
||||
//display ticks
|
||||
// Arrows:
|
||||
|
||||
RS_Line* tick;
|
||||
RS_Vector tickVector = RS_Vector::polar(dimtsz,arrowAngle1 + M_PI*0.25); //tick is 45 degree away
|
||||
|
||||
if (arrow1) {
|
||||
// tick 1
|
||||
tick = new RS_Line(this, p1-tickVector, p1+tickVector);
|
||||
tick->setPen(pen);
|
||||
tick->setLayer(nullptr);
|
||||
addEntity(tick);
|
||||
}
|
||||
|
||||
if (arrow2) {
|
||||
// tick 2:
|
||||
tick = new RS_Line(this, p2-tickVector, p2+tickVector);
|
||||
tick->setPen(pen);
|
||||
tick->setLayer(nullptr);
|
||||
addEntity(tick);
|
||||
}
|
||||
}
|
||||
|
||||
// calculate split dimension lines
|
||||
bool splitDimensionLine = false;
|
||||
if (!outsideArrows) {
|
||||
w = text->getUsedTextWidth()/2+dimgap;
|
||||
h = text->getUsedTextHeight()/2+dimgap;
|
||||
RS_Vector s1 = text->getInsertionPoint() - RS_Vector{w, h};
|
||||
RS_Vector s2 = text->getInsertionPoint() + RS_Vector{w, h};
|
||||
c = RS_EntityContainer();
|
||||
c.addRectangle(s1, s2);
|
||||
sol1 = getIntersectionsLineContainer(dimensionLine, &c);
|
||||
if (sol1.size()>1) {
|
||||
// the text bounding box intersects dimensionLine on two sides
|
||||
splitDimensionLine = true;
|
||||
s1 = sol1.get(0);
|
||||
s2 = sol1.get(1);
|
||||
} else if (sol1.size()==1) {
|
||||
// the text bounding box intersects dimensionLine on one side
|
||||
splitDimensionLine = true;
|
||||
if (RS_Information::isPointInsideContour(p1, &c)) {
|
||||
// the dimension line begins inside the text bounds
|
||||
s1 = p1;
|
||||
s2 = sol1.get(0);
|
||||
} else {
|
||||
// the dimension line ends inside the text bounds
|
||||
s1 = sol1.get(0);
|
||||
s2 = p2;
|
||||
}
|
||||
} else {
|
||||
// the text bounding box does not intersect with dimensionLine, but we
|
||||
// should still check if dimensionLine endpoints are completely inside
|
||||
// the bounding box.
|
||||
if (RS_Information::isPointInsideContour(p1, &c)) {
|
||||
splitDimensionLine = true;
|
||||
s1 = p1;
|
||||
s2 = p2;
|
||||
}
|
||||
}
|
||||
|
||||
if (splitDimensionLine) {
|
||||
dimensionLineInside1 = new RS_Line{this, p1, s1};
|
||||
dimensionLineInside2 = new RS_Line{this, s2, p2};
|
||||
}
|
||||
}
|
||||
|
||||
// finally, add the dimension line(s) and text to the drawing
|
||||
if (outsideArrows && dimensionLineOutside1) {
|
||||
addEntity(dimensionLineOutside1);
|
||||
addEntity(dimensionLineOutside2);
|
||||
} else if (splitDimensionLine && dimensionLineInside1) {
|
||||
addEntity(dimensionLineInside1);
|
||||
addEntity(dimensionLineInside2);
|
||||
} else {
|
||||
addEntity(dimensionLine);
|
||||
}
|
||||
|
||||
addEntity(text);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates an aligned-text dimensioning line (line with one, two or no arrows
|
||||
* and aligned text).
|
||||
*
|
||||
* @param forceAutoText Automatically reposition the text label.
|
||||
*/
|
||||
void RS_Dimension::updateCreateAlignedTextDimensionLine(const RS_Vector& p1,
|
||||
const RS_Vector& p2, bool arrow1, bool arrow2, bool forceAutoText) {
|
||||
// general scale (DIMSCALE)
|
||||
double dimscale = getGeneralScale();
|
||||
// text height (DIMTXT)
|
||||
double dimtxt = getTextHeight()*dimscale;
|
||||
// text distance to line (DIMGAP)
|
||||
double dimgap = getDimensionLineGap()*dimscale;
|
||||
|
||||
// length of dimension line:
|
||||
double distance = p1.distanceTo(p2);
|
||||
// arrow size:
|
||||
double arrowSize = getArrowSize()*dimscale;
|
||||
|
||||
// do we have to put the arrows outside of the line?
|
||||
bool outsideArrows = (distance<arrowSize*2.5);
|
||||
|
||||
// arrow angles:
|
||||
double arrowAngle1, arrowAngle2;
|
||||
|
||||
RS_Pen pen(getDimensionLineColor(),
|
||||
getDimensionLineWidth(),
|
||||
RS2::LineByBlock);
|
||||
|
||||
// Create dimension line:
|
||||
RS_Line* dimensionLine = new RS_Line{this, p1, p2};
|
||||
dimensionLine->setPen(pen);
|
||||
dimensionLine->setLayer(nullptr);
|
||||
addEntity(dimensionLine);
|
||||
|
||||
// Text label:
|
||||
RS_MTextData textData;
|
||||
RS_Vector textPos;
|
||||
double dimAngle1 = dimensionLine->getAngle1();
|
||||
bool corrected = false;
|
||||
double textAngle = RS_Math::makeAngleReadable(dimAngle1, true, &corrected);
|
||||
|
||||
if (data.middleOfText.valid && !forceAutoText) {
|
||||
textPos = data.middleOfText;
|
||||
} else {
|
||||
textPos = dimensionLine->getMiddlePoint();
|
||||
|
||||
// rotate text so it's readable from the bottom or right (ISO)
|
||||
// quadrant 1 & 4
|
||||
double const a = corrected?-M_PI_2:M_PI_2;
|
||||
RS_Vector distV = RS_Vector::polar(dimgap + dimtxt/2.0, dimAngle1+a);
|
||||
|
||||
// move text away from dimension line:
|
||||
textPos+=distV;
|
||||
|
||||
//// the next update should still be able to adjust this
|
||||
//// auto text position. leave it invalid
|
||||
data.middleOfText = textPos;
|
||||
}
|
||||
|
||||
textData = RS_MTextData(textPos,
|
||||
dimtxt, 30.0,
|
||||
RS_MTextData::VAMiddle,
|
||||
RS_MTextData::HACenter,
|
||||
RS_MTextData::LeftToRight,
|
||||
RS_MTextData::Exact,
|
||||
1.0,
|
||||
getLabel(),
|
||||
getTextStyle(),
|
||||
textAngle);
|
||||
|
||||
RS_MText* text = new RS_MText(this, textData);
|
||||
text->setPen(RS_Pen(getTextColor(), RS2::WidthByBlock, RS2::SolidLine));
|
||||
text->setLayer(nullptr);
|
||||
|
||||
// move text to the side:
|
||||
RS_Vector distH;
|
||||
if (text->getUsedTextWidth()>distance) {
|
||||
distH.setPolar(text->getUsedTextWidth()/2.0
|
||||
+distance/2.0+dimgap, textAngle);
|
||||
text->move(distH);
|
||||
}
|
||||
|
||||
addEntity(text);
|
||||
|
||||
// add arrows
|
||||
if (outsideArrows==false) {
|
||||
arrowAngle1 = dimensionLine->getAngle2();
|
||||
arrowAngle2 = dimensionLine->getAngle1();
|
||||
} else {
|
||||
arrowAngle1 = dimensionLine->getAngle1();
|
||||
arrowAngle2 = dimensionLine->getAngle2();
|
||||
|
||||
// extend dimension line outside arrows
|
||||
RS_Vector dir = RS_Vector::polar(arrowSize*2, arrowAngle2);
|
||||
dimensionLine->setStartpoint(p1 + dir);
|
||||
dimensionLine->setEndpoint(p2 - dir);
|
||||
}
|
||||
double dimtsz=getTickSize()*dimscale;
|
||||
if(dimtsz < 0.01) {
|
||||
//display arrow
|
||||
// Arrows:
|
||||
RS_SolidData sd;
|
||||
RS_Solid* arrow;
|
||||
|
||||
if (arrow1) {
|
||||
// arrow 1
|
||||
arrow = new RS_Solid(this, sd);
|
||||
arrow->shapeArrow(p1,
|
||||
arrowAngle1,
|
||||
arrowSize);
|
||||
arrow->setPen(pen);
|
||||
arrow->setLayer(nullptr);
|
||||
addEntity(arrow);
|
||||
}
|
||||
|
||||
if (arrow2) {
|
||||
// arrow 2:
|
||||
arrow = new RS_Solid(this, sd);
|
||||
arrow->shapeArrow(p2,
|
||||
arrowAngle2,
|
||||
arrowSize);
|
||||
arrow->setPen(pen);
|
||||
arrow->setLayer(nullptr);
|
||||
addEntity(arrow);
|
||||
}
|
||||
}else{
|
||||
//display ticks
|
||||
// Arrows:
|
||||
|
||||
RS_Line* tick;
|
||||
RS_Vector tickVector = RS_Vector::polar(dimtsz,arrowAngle1 + M_PI*0.25); //tick is 45 degree away
|
||||
|
||||
if (arrow1) {
|
||||
// tick 1
|
||||
tick = new RS_Line(this, p1-tickVector, p1+tickVector);
|
||||
tick->setPen(pen);
|
||||
tick->setLayer(nullptr);
|
||||
addEntity(tick);
|
||||
}
|
||||
|
||||
if (arrow2) {
|
||||
// tick 2:
|
||||
tick = new RS_Line(this, p2-tickVector, p2+tickVector);
|
||||
tick->setPen(pen);
|
||||
tick->setLayer(nullptr);
|
||||
addEntity(tick);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a dimensioning line (line with one, two or no arrows and a text).
|
||||
*
|
||||
* @param forceAutoText Automatically reposition the text label.
|
||||
*/
|
||||
void RS_Dimension::updateCreateDimensionLine(const RS_Vector& p1,
|
||||
const RS_Vector& p2, bool arrow1, bool arrow2, bool forceAutoText) {
|
||||
if (getInsideHorizontalText())
|
||||
updateCreateHorizontalTextDimensionLine(p1, p2, arrow1, arrow2, forceAutoText);
|
||||
else
|
||||
updateCreateAlignedTextDimensionLine(p1, p2, arrow1, arrow2, forceAutoText);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return general factor for linear dimensions.
|
||||
*/
|
||||
double RS_Dimension::getGeneralFactor() {
|
||||
return getGraphicVariable("$DIMLFAC", 1.0, 40);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return general scale for dimensions.
|
||||
*/
|
||||
double RS_Dimension::getGeneralScale() {
|
||||
return getGraphicVariable("$DIMSCALE", 1.0, 40);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return arrow size in drawing units.
|
||||
*/
|
||||
double RS_Dimension::getArrowSize() {
|
||||
return getGraphicVariable("$DIMASZ", 2.5, 40);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return tick size in drawing units.
|
||||
*/
|
||||
double RS_Dimension::getTickSize() {
|
||||
return getGraphicVariable("$DIMTSZ", 0., 40);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return extension line overlength in drawing units.
|
||||
*/
|
||||
double RS_Dimension::getExtensionLineExtension() {
|
||||
return getGraphicVariable("$DIMEXE", 1.25, 40);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return extension line offset from entities in drawing units.
|
||||
*/
|
||||
double RS_Dimension::getExtensionLineOffset() {
|
||||
return getGraphicVariable("$DIMEXO", 0.625, 40);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return extension line gap to text in drawing units.
|
||||
*/
|
||||
double RS_Dimension::getDimensionLineGap() {
|
||||
return getGraphicVariable("$DIMGAP", 0.625, 40);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return Dimension labels text height.
|
||||
*/
|
||||
double RS_Dimension::getTextHeight() {
|
||||
return getGraphicVariable("$DIMTXT", 2.5, 40);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Dimension labels alignment text true= horizontal, false= aligned.
|
||||
*/
|
||||
bool RS_Dimension::getInsideHorizontalText() {
|
||||
int v = getGraphicVariableInt("$DIMTIH", 1);
|
||||
if (v>0) {
|
||||
addGraphicVariable("$DIMTIH", 1, 70);
|
||||
getGraphicVariableInt("$DIMTIH", 1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Dimension fixed length for extension lines true= fixed, false= not fixed.
|
||||
*/
|
||||
bool RS_Dimension::getFixedLengthOn() {
|
||||
int v = getGraphicVariableInt("$DIMFXLON", 0);
|
||||
if (v == 1) {
|
||||
addGraphicVariable("$DIMFXLON", 1, 70);
|
||||
getGraphicVariableInt("$DIMFXLON", 0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Dimension fixed length for extension lines.
|
||||
*/
|
||||
double RS_Dimension::getFixedLength() {
|
||||
return getGraphicVariable("$DIMFXL", 1.0, 40);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return extension line Width.
|
||||
*/
|
||||
RS2::LineWidth RS_Dimension::getExtensionLineWidth() {
|
||||
return RS2::intToLineWidth( getGraphicVariableInt("$DIMLWE", -2) ); //default -2 (RS2::WidthByBlock)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return dimension line Width.
|
||||
*/
|
||||
RS2::LineWidth RS_Dimension::getDimensionLineWidth() {
|
||||
return RS2::intToLineWidth( getGraphicVariableInt("$DIMLWD", -2) ); //default -2 (RS2::WidthByBlock)
|
||||
}
|
||||
|
||||
/**
|
||||
* @return dimension line Color.
|
||||
*/
|
||||
RS_Color RS_Dimension::getDimensionLineColor() {
|
||||
return RS_FilterDXFRW::numberToColor(getGraphicVariableInt("$DIMCLRD", 0));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return extension line Color.
|
||||
*/
|
||||
RS_Color RS_Dimension::getExtensionLineColor() {
|
||||
return RS_FilterDXFRW::numberToColor(getGraphicVariableInt("$DIMCLRE", 0));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return dimension text Color.
|
||||
*/
|
||||
RS_Color RS_Dimension::getTextColor() {
|
||||
return RS_FilterDXFRW::numberToColor(getGraphicVariableInt("$DIMCLRT", 0));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return text style for dimensions.
|
||||
*/
|
||||
QString RS_Dimension::getTextStyle() {
|
||||
return getGraphicVariableString("$DIMTXSTY", "standard");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the given graphic variable or the default value given in mm
|
||||
* converted to the graphic unit.
|
||||
* If the variable is not found it is added with the given default
|
||||
* value converted to the local unit.
|
||||
*/
|
||||
double RS_Dimension::getGraphicVariable(const QString& key, double defMM,
|
||||
int code) {
|
||||
|
||||
double v = getGraphicVariableDouble(key, RS_MINDOUBLE);
|
||||
if (v<=RS_MINDOUBLE) {
|
||||
addGraphicVariable(
|
||||
key,
|
||||
RS_Units::convert(defMM, RS2::Millimeter, getGraphicUnit()),
|
||||
code);
|
||||
v = getGraphicVariableDouble(key, 1.0);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes zeros from angle string.
|
||||
*
|
||||
* @param angle The string representing angle.
|
||||
* @param zeros Zeros suppression (0 none, 1 suppress leading, 2 suppress trailing, 3 both)
|
||||
* Decimal separator are '.'
|
||||
*
|
||||
* @ret String with the formatted angle.
|
||||
*/
|
||||
|
||||
QString RS_Dimension::stripZerosAngle(QString angle, int zeros){
|
||||
if (zeros == 0) //do nothing
|
||||
return angle;
|
||||
if (zeros & 2 && (angle.contains(QString('.')) || angle.contains(QString(',')))) {
|
||||
int end = angle.size() - 1;
|
||||
QChar format = angle[end--]; //stores & skip format char
|
||||
while (end > 0 && angle[end] == QChar('0')) // locate first 0 from end
|
||||
end--;
|
||||
if (angle[end] == QChar('.'))
|
||||
end--;
|
||||
angle.truncate(end+1);
|
||||
angle.append(format);
|
||||
}
|
||||
if (zeros & 1){
|
||||
if (angle[0] == QChar('0') && angle[1] == QChar('.'))
|
||||
angle = angle.remove(0, 1);
|
||||
}
|
||||
return angle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes zeros from linear string.
|
||||
*
|
||||
* @param linear The string representing linear measure.
|
||||
* @param zeros Zeros suppression (see dimzin)
|
||||
*
|
||||
* @ret String with the formatted linear measure.
|
||||
*/
|
||||
|
||||
QString RS_Dimension::stripZerosLinear(QString linear, int zeros){
|
||||
|
||||
//do nothing
|
||||
if (zeros == 1)
|
||||
return linear;
|
||||
|
||||
// return at least 1 character in string
|
||||
int ls = linear.size();
|
||||
if (ls <= 1) {
|
||||
return linear;
|
||||
}
|
||||
|
||||
// if removing of trailing zeroes is needed
|
||||
if (zeros & 8 && (linear.contains(QString('.')) || linear.contains(QString(',')))) {
|
||||
// search index
|
||||
int i = ls - 1;
|
||||
// locate first 0 in row from right
|
||||
while (i > 0 && linear[i] == QChar('0')) {
|
||||
i--;
|
||||
}
|
||||
// strip decimal point
|
||||
if ((linear[i] == QChar('.') || linear[i] == QChar(',')) && i > 0)
|
||||
i--;
|
||||
// strip zeros. Leave at least one character at the beginning
|
||||
linear = linear.remove(i+1, ls-i);
|
||||
}
|
||||
// if removing of initial zeroes is needed
|
||||
if (zeros & 4) {
|
||||
int i = 0;
|
||||
// locate last 0 in row from left
|
||||
while (i < ls-1 && linear[i] == QChar('0')) {
|
||||
i++;
|
||||
}
|
||||
linear = linear.remove(0, i);
|
||||
}
|
||||
return linear;
|
||||
}
|
||||
|
||||
|
||||
void RS_Dimension::move(const RS_Vector& offset) {
|
||||
data.definitionPoint.move(offset);
|
||||
data.middleOfText.move(offset);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_Dimension::rotate(const RS_Vector& center, const double& angle) {
|
||||
RS_Vector angleVector(angle);
|
||||
data.definitionPoint.rotate(center, angleVector);
|
||||
data.middleOfText.rotate(center, angleVector);
|
||||
data.angle = RS_Math::correctAngle(data.angle+angle);
|
||||
}
|
||||
|
||||
void RS_Dimension::rotate(const RS_Vector& center, const RS_Vector& angleVector) {
|
||||
data.definitionPoint.rotate(center, angleVector);
|
||||
data.middleOfText.rotate(center, angleVector);
|
||||
data.angle = RS_Math::correctAngle(data.angle+angleVector.angle());
|
||||
}
|
||||
|
||||
|
||||
void RS_Dimension::scale(const RS_Vector& center, const RS_Vector& factor) {
|
||||
data.definitionPoint.scale(center, factor);
|
||||
data.middleOfText.scale(center, factor);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_Dimension::mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) {
|
||||
data.definitionPoint.mirror(axisPoint1, axisPoint2);
|
||||
data.middleOfText.mirror(axisPoint1, axisPoint2);
|
||||
}
|
||||
|
||||
// EOF
|
||||
219
lib/engine/rs_dimension.h
Normal file
219
lib/engine/rs_dimension.h
Normal file
@@ -0,0 +1,219 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_DIMENSION_H
|
||||
#define RS_DIMENSION_H
|
||||
|
||||
#include "rs_entitycontainer.h"
|
||||
#include "rs_mtext.h"
|
||||
|
||||
/**
|
||||
* Holds the data that is common to all dimension entities.
|
||||
*/
|
||||
struct RS_DimensionData : public RS_Flags {
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
RS_DimensionData();
|
||||
|
||||
/**
|
||||
* Constructor with initialisation.
|
||||
*
|
||||
* @param definitionPoint Definition point.
|
||||
* @param middleOfText Middle point of dimension text.
|
||||
* @param valign Vertical alignment.
|
||||
* @param halign Horizontal alignment.
|
||||
* @param lineSpacingStyle Line spacing style.
|
||||
* @param lineSpacingFactor Line spacing factor.
|
||||
* @param text Text string entered explicitly by user or null
|
||||
* or "<>" for the actual measurement or " " (one blank space).
|
||||
* for suppressing the text.
|
||||
* @param style Dimension style name.
|
||||
* @param angle Rotation angle of dimension text away from
|
||||
* default orientation.
|
||||
*/
|
||||
RS_DimensionData(const RS_Vector& definitionPoint,
|
||||
const RS_Vector& middleOfText,
|
||||
RS_MTextData::VAlign valign,
|
||||
RS_MTextData::HAlign halign,
|
||||
RS_MTextData::MTextLineSpacingStyle lineSpacingStyle,
|
||||
double lineSpacingFactor,
|
||||
QString text,
|
||||
QString style,
|
||||
double angle);
|
||||
|
||||
/** Definition point */
|
||||
RS_Vector definitionPoint;
|
||||
/** Middle point of dimension text */
|
||||
RS_Vector middleOfText;
|
||||
/** Vertical alignment */
|
||||
RS_MTextData::VAlign valign;
|
||||
/** Horizontal alignment */
|
||||
RS_MTextData::HAlign halign;
|
||||
/** Line spacing style */
|
||||
RS_MTextData::MTextLineSpacingStyle lineSpacingStyle;
|
||||
/** Line spacing factor */
|
||||
double lineSpacingFactor;
|
||||
/**
|
||||
* Text string entered explicitly by user or null
|
||||
* or "<>" for the actual measurement or " " (one blank space)
|
||||
* for suppressing the text.
|
||||
*/
|
||||
QString text;
|
||||
/** Dimension style name */
|
||||
QString style;
|
||||
/** Rotation angle of dimension text away from default orientation */
|
||||
double angle;
|
||||
};
|
||||
|
||||
std::ostream& operator << (std::ostream& os,
|
||||
const RS_DimensionData& dd);
|
||||
|
||||
/**
|
||||
* Abstract base class for dimension entity classes.
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_Dimension : public RS_EntityContainer {
|
||||
public:
|
||||
RS_Dimension(RS_EntityContainer* parent,
|
||||
const RS_DimensionData& d);
|
||||
|
||||
RS_Vector getNearestRef( const RS_Vector& coord, double* dist = nullptr) const override;
|
||||
RS_Vector getNearestSelectedRef( const RS_Vector& coord, double* dist = nullptr) const override;
|
||||
|
||||
/** @return Copy of data that defines the dimension. */
|
||||
RS_DimensionData getData() const {
|
||||
return data;
|
||||
}
|
||||
|
||||
QString getLabel(bool resolve=true);
|
||||
void setLabel(const QString& l);
|
||||
|
||||
/**
|
||||
* Needs to be implemented by the dimension class to return the
|
||||
* measurement of the dimension (e.g. 10.5 or 15'14").
|
||||
*/
|
||||
virtual QString getMeasuredLabel() = 0;
|
||||
|
||||
/**
|
||||
* Must be overwritten by implementing dimension entity class
|
||||
* to update the subentities which make up the dimension entity.
|
||||
*/
|
||||
void update() override{
|
||||
updateDim();
|
||||
}
|
||||
|
||||
virtual void updateDim(bool autoText=false) = 0;
|
||||
|
||||
void updateCreateDimensionLine(const RS_Vector& p1, const RS_Vector& p2,
|
||||
bool arrow1=true, bool arrow2=true, bool autoText=false);
|
||||
|
||||
RS_Vector getDefinitionPoint() {
|
||||
return data.definitionPoint;
|
||||
}
|
||||
|
||||
RS_Vector getMiddleOfText() {
|
||||
return data.middleOfText;
|
||||
}
|
||||
|
||||
RS_MTextData::VAlign getVAlign() {
|
||||
return data.valign;
|
||||
}
|
||||
|
||||
RS_MTextData::HAlign getHAlign() {
|
||||
return data.halign;
|
||||
}
|
||||
|
||||
RS_MTextData::MTextLineSpacingStyle getLineSpacingStyle() {
|
||||
return data.lineSpacingStyle;
|
||||
}
|
||||
|
||||
double getLineSpacingFactor() {
|
||||
return data.lineSpacingFactor;
|
||||
}
|
||||
|
||||
QString getText() {
|
||||
return data.text;
|
||||
}
|
||||
|
||||
QString getStyle() {
|
||||
return data.style;
|
||||
}
|
||||
|
||||
double getAngle() {
|
||||
return data.angle;
|
||||
}
|
||||
|
||||
double getGeneralFactor();
|
||||
double getGeneralScale();
|
||||
double getArrowSize();
|
||||
double getTickSize();
|
||||
double getExtensionLineExtension();
|
||||
double getExtensionLineOffset();
|
||||
double getDimensionLineGap();
|
||||
double getTextHeight();
|
||||
bool getInsideHorizontalText();
|
||||
bool getFixedLengthOn();
|
||||
double getFixedLength();
|
||||
RS2::LineWidth getExtensionLineWidth();
|
||||
RS2::LineWidth getDimensionLineWidth();
|
||||
RS_Color getDimensionLineColor();
|
||||
RS_Color getExtensionLineColor();
|
||||
RS_Color getTextColor();
|
||||
QString getTextStyle();
|
||||
|
||||
double getGraphicVariable(const QString& key, double defMM, int code);
|
||||
static QString stripZerosAngle(QString angle, int zeros=0);
|
||||
static QString stripZerosLinear(QString linear, int zeros=1);
|
||||
|
||||
// virtual double getLength() {
|
||||
// return -1.0;
|
||||
// }
|
||||
|
||||
void move(const RS_Vector& offset) override;
|
||||
void rotate(const RS_Vector& center, const double& angle) override;
|
||||
void rotate(const RS_Vector& center, const RS_Vector& angleVector) override;
|
||||
void scale(const RS_Vector& center, const RS_Vector& factor) override;
|
||||
void mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) override;
|
||||
|
||||
private:
|
||||
static RS_VectorSolutions getIntersectionsLineContainer(
|
||||
const RS_Line* l, const RS_EntityContainer* c, bool infiniteLine=false);
|
||||
void updateCreateHorizontalTextDimensionLine(
|
||||
const RS_Vector& p1, const RS_Vector& p2,
|
||||
bool arrow1=true, bool arrow2=true, bool autoText=false);
|
||||
void updateCreateAlignedTextDimensionLine(
|
||||
const RS_Vector& p1, const RS_Vector& p2,
|
||||
bool arrow1=true, bool arrow2=true, bool autoText=false);
|
||||
|
||||
protected:
|
||||
/** Data common to all dimension entities. */
|
||||
RS_DimensionData data;
|
||||
};
|
||||
|
||||
#endif
|
||||
384
lib/engine/rs_dimlinear.cpp
Normal file
384
lib/engine/rs_dimlinear.cpp
Normal file
@@ -0,0 +1,384 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
#include<iostream>
|
||||
#include<cmath>
|
||||
#include "rs_dimlinear.h"
|
||||
#include "rs_line.h"
|
||||
#include "rs_constructionline.h"
|
||||
#include "rs_mtext.h"
|
||||
#include "rs_solid.h"
|
||||
#include "rs_graphic.h"
|
||||
#include "rs_math.h"
|
||||
#include "rs_debug.h"
|
||||
|
||||
|
||||
RS_DimLinearData::RS_DimLinearData():
|
||||
extensionPoint1(false),
|
||||
extensionPoint2(false),
|
||||
angle(0.0),
|
||||
oblique(0.0)
|
||||
{}
|
||||
|
||||
RS_DimLinearData::RS_DimLinearData(const RS_Vector& _extensionPoint1,
|
||||
const RS_Vector& _extensionPoint2,
|
||||
double _angle, double _oblique):
|
||||
extensionPoint1(_extensionPoint1)
|
||||
,extensionPoint2(_extensionPoint2)
|
||||
,angle(_angle)
|
||||
,oblique(_oblique)
|
||||
{
|
||||
}
|
||||
|
||||
std::ostream& operator << (std::ostream& os,
|
||||
const RS_DimLinearData& dd) {
|
||||
os << "(" << dd.extensionPoint1 << ","
|
||||
<< dd.extensionPoint1 <<','
|
||||
<< dd.angle <<','
|
||||
<< dd.oblique <<','
|
||||
<<")";
|
||||
return os;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @para parent Parent Entity Container.
|
||||
* @para d Common dimension geometrical data.
|
||||
* @para ed Extended geometrical data for linear dimension.
|
||||
*/
|
||||
RS_DimLinear::RS_DimLinear(RS_EntityContainer* parent,
|
||||
const RS_DimensionData& d,
|
||||
const RS_DimLinearData& ed)
|
||||
: RS_Dimension(parent, d), edata(ed) {
|
||||
|
||||
calculateBorders();
|
||||
}
|
||||
|
||||
RS_Entity* RS_DimLinear::clone() const {
|
||||
RS_DimLinear* d = new RS_DimLinear(*this);
|
||||
d->setOwner(isOwner());
|
||||
d->initId();
|
||||
d->detach();
|
||||
return d;
|
||||
}
|
||||
|
||||
RS_VectorSolutions RS_DimLinear::getRefPoints() const
|
||||
{
|
||||
return RS_VectorSolutions({edata.extensionPoint1, edata.extensionPoint2,
|
||||
data.definitionPoint, data.middleOfText});
|
||||
}
|
||||
void RS_DimLinear::setAngle(double a) {
|
||||
edata.angle = RS_Math::correctAngle(a);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Automatically created label for the default
|
||||
* measurement of this dimension.
|
||||
*/
|
||||
QString RS_DimLinear::getMeasuredLabel() {
|
||||
// direction of dimension line
|
||||
RS_Vector dirDim = RS_Vector::polar(100.0, edata.angle);
|
||||
|
||||
// construction line for dimension line
|
||||
RS_ConstructionLine dimLine(nullptr,
|
||||
RS_ConstructionLineData(data.definitionPoint,
|
||||
data.definitionPoint + dirDim));
|
||||
|
||||
RS_Vector dimP1 = dimLine.getNearestPointOnEntity(edata.extensionPoint1);
|
||||
RS_Vector dimP2 = dimLine.getNearestPointOnEntity(edata.extensionPoint2);
|
||||
|
||||
// Definitive dimension line:
|
||||
double dist = dimP1.distanceTo(dimP2) * getGeneralFactor();
|
||||
|
||||
RS_Graphic* graphic = getGraphic();
|
||||
|
||||
QString ret;
|
||||
if (graphic) {
|
||||
int dimlunit = getGraphicVariableInt("$DIMLUNIT", 2);
|
||||
int dimdec = getGraphicVariableInt("$DIMDEC", 4);
|
||||
int dimzin = getGraphicVariableInt("$DIMZIN", 1);
|
||||
RS2::LinearFormat format = graphic->getLinearFormat(dimlunit);
|
||||
ret = RS_Units::formatLinear(dist, RS2::None, format, dimdec);
|
||||
if (format == RS2::Decimal)
|
||||
ret = stripZerosLinear(ret, dimzin);
|
||||
//verify if units are decimal and comma separator
|
||||
if (format == RS2::Decimal || format == RS2::ArchitecturalMetric){
|
||||
if (getGraphicVariableInt("$DIMDSEP", 0) == 44)
|
||||
ret.replace(QChar('.'), QChar(','));
|
||||
}
|
||||
}
|
||||
else {
|
||||
ret = QString("%1").arg(dist);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool RS_DimLinear::hasEndpointsWithinWindow(const RS_Vector& v1, const RS_Vector& v2) {
|
||||
return (edata.extensionPoint1.isInWindow(v1, v2) ||
|
||||
edata.extensionPoint2.isInWindow(v1, v2));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Updates the sub entities of this dimension. Called when the
|
||||
* text or the position, alignment, .. changes.
|
||||
*
|
||||
* @param autoText Automatically reposition the text label
|
||||
*/
|
||||
void RS_DimLinear::updateDim(bool autoText) {
|
||||
|
||||
RS_DEBUG->print("RS_DimLinear::update");
|
||||
|
||||
clear();
|
||||
|
||||
if (isUndone()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// general scale (DIMSCALE)
|
||||
double dimscale = getGeneralScale();
|
||||
// distance from entities (DIMEXO)
|
||||
double dimexo = getExtensionLineOffset()*dimscale;
|
||||
// extension line extension (DIMEXE)
|
||||
double dimexe = getExtensionLineExtension()*dimscale;
|
||||
|
||||
// direction of dimension line
|
||||
RS_Vector dirDim = RS_Vector::polar(100.0, edata.angle);
|
||||
|
||||
// construction line for dimension line
|
||||
RS_ConstructionLine dimLine(
|
||||
nullptr,
|
||||
RS_ConstructionLineData(data.definitionPoint,
|
||||
data.definitionPoint + dirDim));
|
||||
|
||||
RS_Vector dimP1 = dimLine.getNearestPointOnEntity(edata.extensionPoint1);
|
||||
RS_Vector dimP2 = dimLine.getNearestPointOnEntity(edata.extensionPoint2);
|
||||
|
||||
// Definitive dimension line:
|
||||
updateCreateDimensionLine(dimP1, dimP2, true, true, autoText);
|
||||
/*
|
||||
ld = RS_LineData(data.definitionPoint, dimP1);
|
||||
RS_Line* dimensionLine = new RS_Line(this, ld);
|
||||
addEntity(dimensionLine);
|
||||
*/
|
||||
|
||||
double extAngle1, extAngle2;
|
||||
|
||||
if ((edata.extensionPoint1-dimP1).magnitude()<1e-6) {
|
||||
if ((edata.extensionPoint2-dimP2).magnitude()<1e-6) {
|
||||
//boot extension points are in dimension line only rotate 90
|
||||
extAngle2 = edata.angle + (M_PI_2);
|
||||
} else {
|
||||
//first extension point are in dimension line use second
|
||||
extAngle2 = edata.extensionPoint2.angleTo(dimP2);
|
||||
}
|
||||
extAngle1 = extAngle2;
|
||||
} else {
|
||||
//first extension point not are in dimension line use it
|
||||
extAngle1 = edata.extensionPoint1.angleTo(dimP1);
|
||||
if ((edata.extensionPoint2-dimP2).magnitude()<1e-6)
|
||||
extAngle2 = extAngle1;
|
||||
else
|
||||
extAngle2 = edata.extensionPoint2.angleTo(dimP2);
|
||||
}
|
||||
|
||||
RS_Vector vDimexe1 = RS_Vector::polar(dimexe, extAngle1);
|
||||
RS_Vector vDimexe2 = RS_Vector::polar(dimexe, extAngle2);
|
||||
|
||||
RS_Vector vDimexo1, vDimexo2;
|
||||
if (getFixedLengthOn()){
|
||||
double dimfxl = getFixedLength()*dimscale;
|
||||
double extLength = (edata.extensionPoint1-dimP1).magnitude();
|
||||
if (extLength-dimexo > dimfxl)
|
||||
vDimexo1.setPolar(extLength - dimfxl, extAngle1);
|
||||
extLength = (edata.extensionPoint2-dimP2).magnitude();
|
||||
if (extLength-dimexo > dimfxl)
|
||||
vDimexo2.setPolar(extLength - dimfxl, extAngle2);
|
||||
} else {
|
||||
vDimexo1.setPolar(dimexo, extAngle1);
|
||||
vDimexo2.setPolar(dimexo, extAngle2);
|
||||
}
|
||||
|
||||
RS_Pen pen(getExtensionLineColor(),
|
||||
getExtensionLineWidth(),
|
||||
RS2::LineByBlock);
|
||||
|
||||
// extension lines:
|
||||
RS_Line* line = new RS_Line{this,
|
||||
edata.extensionPoint1+vDimexo1, dimP1+vDimexe1};
|
||||
line->setPen(pen);
|
||||
// line->setPen(RS_Pen(RS2::FlagInvalid));
|
||||
line->setLayer(nullptr);
|
||||
addEntity(line);
|
||||
//data.definitionPoint+vDimexe2);
|
||||
line = new RS_Line{this,
|
||||
edata.extensionPoint2+vDimexo2, dimP2+vDimexe2};
|
||||
line->setPen(pen);
|
||||
// line->setPen(RS_Pen(RS2::FlagInvalid));
|
||||
line->setLayer(nullptr);
|
||||
addEntity(line);
|
||||
|
||||
calculateBorders();
|
||||
}
|
||||
|
||||
void RS_DimLinear::move(const RS_Vector& offset) {
|
||||
RS_Dimension::move(offset);
|
||||
|
||||
edata.extensionPoint1.move(offset);
|
||||
edata.extensionPoint2.move(offset);
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_DimLinear::rotate(const RS_Vector& center, const double& angle) {
|
||||
RS_Vector angleVector(angle);
|
||||
RS_Dimension::rotate(center, angleVector);
|
||||
|
||||
edata.extensionPoint1.rotate(center, angleVector);
|
||||
edata.extensionPoint2.rotate(center, angleVector);
|
||||
edata.angle = RS_Math::correctAngle(edata.angle+angle);
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
void RS_DimLinear::rotate(const RS_Vector& center, const RS_Vector& angleVector) {
|
||||
RS_Dimension::rotate(center, angleVector);
|
||||
|
||||
edata.extensionPoint1.rotate(center, angleVector);
|
||||
edata.extensionPoint2.rotate(center, angleVector);
|
||||
edata.angle = RS_Math::correctAngle(edata.angle+angleVector.angle());
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_DimLinear::scale(const RS_Vector& center, const RS_Vector& factor) {
|
||||
RS_Dimension::scale(center, factor);
|
||||
|
||||
edata.extensionPoint1.scale(center, factor);
|
||||
edata.extensionPoint2.scale(center, factor);
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_DimLinear::mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) {
|
||||
RS_Dimension::mirror(axisPoint1, axisPoint2);
|
||||
|
||||
edata.extensionPoint1.mirror(axisPoint1, axisPoint2);
|
||||
edata.extensionPoint2.mirror(axisPoint1, axisPoint2);
|
||||
|
||||
RS_Vector vec;
|
||||
vec.setPolar(1.0, edata.angle);
|
||||
vec.mirror(RS_Vector(0.0,0.0), axisPoint2-axisPoint1);
|
||||
edata.angle = vec.angle();
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_DimLinear::stretch(const RS_Vector& firstCorner,
|
||||
const RS_Vector& secondCorner,
|
||||
const RS_Vector& offset) {
|
||||
|
||||
//e->calculateBorders();
|
||||
if (getMin().isInWindow(firstCorner, secondCorner) &&
|
||||
getMax().isInWindow(firstCorner, secondCorner)) {
|
||||
|
||||
move(offset);
|
||||
} else {
|
||||
//RS_Vector v = data.definitionPoint - edata.extensionPoint2;
|
||||
//double len = edata.extensionPoint2.distanceTo(data.definitionPoint);
|
||||
//double ang1 = edata.extensionPoint1.angleTo(edata.extensionPoint2)
|
||||
// + M_PI_2;
|
||||
|
||||
if (edata.extensionPoint1.isInWindow(firstCorner,
|
||||
secondCorner)) {
|
||||
edata.extensionPoint1.move(offset);
|
||||
}
|
||||
if (edata.extensionPoint2.isInWindow(firstCorner,
|
||||
secondCorner)) {
|
||||
edata.extensionPoint2.move(offset);
|
||||
}
|
||||
|
||||
/*
|
||||
double ang2 = edata.extensionPoint1.angleTo(edata.extensionPoint2)
|
||||
+ M_PI_2;
|
||||
|
||||
double diff = RS_Math::getAngleDifference(ang1, ang2);
|
||||
if (diff>M_PI) {
|
||||
diff-=2*M_PI;
|
||||
}
|
||||
|
||||
if (fabs(diff)>M_PI_2) {
|
||||
ang2 = RS_Math::correctAngle(ang2+M_PI);
|
||||
}
|
||||
|
||||
RS_Vector v;
|
||||
v.setPolar(len, ang2);
|
||||
data.definitionPoint = edata.extensionPoint2 + v;
|
||||
*/
|
||||
}
|
||||
updateDim(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_DimLinear::moveRef(const RS_Vector& ref, const RS_Vector& offset) {
|
||||
|
||||
if (ref.distanceTo(data.definitionPoint)<1.0e-4) {
|
||||
data.definitionPoint += offset;
|
||||
updateDim(true);
|
||||
}
|
||||
else if (ref.distanceTo(data.middleOfText)<1.0e-4) {
|
||||
data.middleOfText += offset;
|
||||
updateDim(false);
|
||||
}
|
||||
else if (ref.distanceTo(edata.extensionPoint1)<1.0e-4) {
|
||||
edata.extensionPoint1 += offset;
|
||||
updateDim(true);
|
||||
}
|
||||
else if (ref.distanceTo(edata.extensionPoint2)<1.0e-4) {
|
||||
edata.extensionPoint2 += offset;
|
||||
updateDim(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps the point's data to stdout.
|
||||
*/
|
||||
std::ostream& operator << (std::ostream& os, const RS_DimLinear& d) {
|
||||
os << " DimLinear: " << d.getData() << "\n" << d.getEData() << "\n";
|
||||
return os;
|
||||
}
|
||||
137
lib/engine/rs_dimlinear.h
Normal file
137
lib/engine/rs_dimlinear.h
Normal file
@@ -0,0 +1,137 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_DIMLINEAR_H
|
||||
#define RS_DIMLINEAR_H
|
||||
|
||||
#include "rs_dimension.h"
|
||||
|
||||
/**
|
||||
* Holds the data that defines a linear dimension entity.
|
||||
*/
|
||||
struct RS_DimLinearData {
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
RS_DimLinearData();
|
||||
|
||||
/**
|
||||
* Constructor with initialisation.
|
||||
*
|
||||
* @para extensionPoint1 Startpoint of the first extension line.
|
||||
* @para extensionPoint2 Startpoint of the second extension line.
|
||||
* @param angle Rotation angle in rad.
|
||||
* @param oblique Oblique angle in rad.
|
||||
*/
|
||||
RS_DimLinearData(const RS_Vector& extensionPoint1,
|
||||
const RS_Vector& extensionPoint2,
|
||||
double angle, double oblique);
|
||||
|
||||
/** Definition point. Startpoint of the first definition line. */
|
||||
RS_Vector extensionPoint1;
|
||||
/** Definition point. Startpoint of the second definition line. */
|
||||
RS_Vector extensionPoint2;
|
||||
/** Rotation angle in rad. */
|
||||
double angle;
|
||||
/** Oblique angle in rad. */
|
||||
double oblique;
|
||||
};
|
||||
|
||||
std::ostream& operator << (std::ostream& os,
|
||||
const RS_DimLinearData& dd);
|
||||
|
||||
/**
|
||||
* Class for aligned dimension entities.
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_DimLinear : public RS_Dimension {
|
||||
public:
|
||||
RS_DimLinear(RS_EntityContainer* parent,
|
||||
const RS_DimensionData& d,
|
||||
const RS_DimLinearData& ed);
|
||||
virtual ~RS_DimLinear() = default;
|
||||
|
||||
virtual RS_Entity* clone() const;
|
||||
|
||||
/** @return RS2::EntityDimLinear */
|
||||
virtual RS2::EntityType rtti() const {
|
||||
return RS2::EntityDimLinear;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Copy of data that defines the linear dimension.
|
||||
* @see getData()
|
||||
*/
|
||||
RS_DimLinearData getEData() const {
|
||||
return edata;
|
||||
}
|
||||
|
||||
virtual RS_VectorSolutions getRefPoints() const;
|
||||
|
||||
virtual QString getMeasuredLabel();
|
||||
|
||||
virtual void updateDim(bool autoText=false);
|
||||
|
||||
RS_Vector getExtensionPoint1() const{
|
||||
return edata.extensionPoint1;
|
||||
}
|
||||
|
||||
RS_Vector getExtensionPoint2() const{
|
||||
return edata.extensionPoint2;
|
||||
}
|
||||
|
||||
double getAngle() const{
|
||||
return edata.angle;
|
||||
}
|
||||
|
||||
void setAngle(double a);
|
||||
|
||||
double getOblique() const{
|
||||
return edata.oblique;
|
||||
}
|
||||
|
||||
virtual void move(const RS_Vector& offset);
|
||||
virtual void rotate(const RS_Vector& center, const double& angle);
|
||||
virtual void rotate(const RS_Vector& center, const RS_Vector& angleVector);
|
||||
virtual void scale(const RS_Vector& center, const RS_Vector& factor);
|
||||
virtual void mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2);
|
||||
virtual bool hasEndpointsWithinWindow(const RS_Vector& v1, const RS_Vector& v2);
|
||||
virtual void stretch(const RS_Vector& firstCorner,
|
||||
const RS_Vector& secondCorner,
|
||||
const RS_Vector& offset);
|
||||
virtual void moveRef(const RS_Vector& ref, const RS_Vector& offset);
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os,
|
||||
const RS_DimLinear& d);
|
||||
|
||||
protected:
|
||||
/** Extended data. */
|
||||
RS_DimLinearData edata;
|
||||
};
|
||||
|
||||
#endif
|
||||
318
lib/engine/rs_dimradial.cpp
Normal file
318
lib/engine/rs_dimradial.cpp
Normal file
@@ -0,0 +1,318 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
#include "rs_dimradial.h"
|
||||
#include "rs_line.h"
|
||||
#include "rs_mtext.h"
|
||||
#include "rs_solid.h"
|
||||
#include "rs_graphic.h"
|
||||
#include "rs_debug.h"
|
||||
|
||||
RS_DimRadialData::RS_DimRadialData():
|
||||
definitionPoint(false),
|
||||
leader(0.0)
|
||||
{}
|
||||
|
||||
/**
|
||||
* Constructor with initialisation.
|
||||
*
|
||||
* @param definitionPoint Definition point of the radial dimension.
|
||||
* @param leader Leader length.
|
||||
*/
|
||||
RS_DimRadialData::RS_DimRadialData(const RS_Vector& _definitionPoint,
|
||||
double _leader):
|
||||
definitionPoint(_definitionPoint)
|
||||
,leader(_leader)
|
||||
{
|
||||
}
|
||||
|
||||
std::ostream& operator << (std::ostream& os,
|
||||
const RS_DimRadialData& dd) {
|
||||
os << "(" << dd.definitionPoint << "/" << dd.leader << ")";
|
||||
return os;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @para parent Parent Entity Container.
|
||||
* @para d Common dimension geometrical data.
|
||||
* @para ed Extended geometrical data for radial dimension.
|
||||
*/
|
||||
RS_DimRadial::RS_DimRadial(RS_EntityContainer* parent,
|
||||
const RS_DimensionData& d,
|
||||
const RS_DimRadialData& ed)
|
||||
: RS_Dimension(parent, d), edata(ed) {}
|
||||
|
||||
RS_Entity* RS_DimRadial::clone() const {
|
||||
RS_DimRadial* d = new RS_DimRadial(*this);
|
||||
d->setOwner(isOwner());
|
||||
d->initId();
|
||||
d->detach();
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Automatically created label for the default
|
||||
* measurement of this dimension.
|
||||
*/
|
||||
QString RS_DimRadial::getMeasuredLabel() {
|
||||
|
||||
// Definitive dimension line:
|
||||
double dist = data.definitionPoint.distanceTo(edata.definitionPoint) * getGeneralFactor();
|
||||
|
||||
RS_Graphic* graphic = getGraphic();
|
||||
|
||||
QString ret;
|
||||
if (graphic) {
|
||||
int dimlunit = getGraphicVariableInt("$DIMLUNIT", 2);
|
||||
int dimdec = getGraphicVariableInt("$DIMDEC", 4);
|
||||
int dimzin = getGraphicVariableInt("$DIMZIN", 1);
|
||||
RS2::LinearFormat format = graphic->getLinearFormat(dimlunit);
|
||||
ret = RS_Units::formatLinear(dist, RS2::None, format, dimdec);
|
||||
if (format == RS2::Decimal)
|
||||
ret = stripZerosLinear(ret, dimzin);
|
||||
//verify if units are decimal and comma separator
|
||||
if (format == RS2::Decimal || format == RS2::ArchitecturalMetric){
|
||||
if (getGraphicVariableInt("$DIMDSEP", 0) == 44)
|
||||
ret.replace(QChar('.'), QChar(','));
|
||||
}
|
||||
} else {
|
||||
ret = QString("%1").arg(dist);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
RS_VectorSolutions RS_DimRadial::getRefPoints() const
|
||||
{
|
||||
return RS_VectorSolutions({edata.definitionPoint,
|
||||
data.definitionPoint, data.middleOfText});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Updates the sub entities of this dimension. Called when the
|
||||
* dimension or the position, alignment, .. changes.
|
||||
*
|
||||
* @param autoText Automatically reposition the text label
|
||||
*/
|
||||
void RS_DimRadial::updateDim(bool autoText) {
|
||||
|
||||
RS_DEBUG->print("RS_DimRadial::update");
|
||||
|
||||
clear();
|
||||
|
||||
if (isUndone()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// general scale (DIMSCALE)
|
||||
double dimscale = getGeneralScale();
|
||||
|
||||
RS_Vector p1 = data.definitionPoint;
|
||||
RS_Vector p2 = edata.definitionPoint;
|
||||
double angle = p1.angleTo(p2);
|
||||
|
||||
// text height (DIMTXT)
|
||||
double dimtxt = getTextHeight()*dimscale;
|
||||
|
||||
RS_Pen pen(getDimensionLineColor(),
|
||||
getDimensionLineWidth(),
|
||||
RS2::LineByBlock);
|
||||
|
||||
RS_MTextData textData;
|
||||
|
||||
textData = RS_MTextData(RS_Vector(0.0,0.0),
|
||||
dimtxt, 30.0,
|
||||
RS_MTextData::VAMiddle,
|
||||
RS_MTextData::HACenter,
|
||||
RS_MTextData::LeftToRight,
|
||||
RS_MTextData::Exact,
|
||||
1.0,
|
||||
getLabel(),
|
||||
getTextStyle(),
|
||||
0.0);
|
||||
|
||||
RS_MText* text = new RS_MText(this, textData);
|
||||
double textWidth = text->getSize().x;
|
||||
|
||||
double tick_size = getTickSize()*dimscale;
|
||||
double arrow_size = getArrowSize()*dimscale;
|
||||
double length = p1.distanceTo(p2); // line length
|
||||
|
||||
bool outsideArrow = false;
|
||||
|
||||
if (tick_size == 0 && arrow_size != 0)
|
||||
{
|
||||
// do we have to put the arrow / text outside of the arc?
|
||||
outsideArrow = (length < arrow_size*2+textWidth);
|
||||
double arrowAngle;
|
||||
|
||||
if (outsideArrow) {
|
||||
length += arrow_size*2 + textWidth;
|
||||
arrowAngle = angle+M_PI;
|
||||
} else {
|
||||
arrowAngle = angle;
|
||||
}
|
||||
|
||||
// create arrow:
|
||||
RS_SolidData sd;
|
||||
RS_Solid* arrow;
|
||||
|
||||
arrow = new RS_Solid(this, sd);
|
||||
arrow->shapeArrow(p2, arrowAngle, arrow_size);
|
||||
arrow->setPen(pen);
|
||||
arrow->setLayer(nullptr);
|
||||
addEntity(arrow);
|
||||
}
|
||||
|
||||
RS_Vector p3 = RS_Vector::polar(length, angle);
|
||||
p3 += p1;
|
||||
|
||||
// Create dimension line:
|
||||
RS_Line* dimensionLine = new RS_Line{this, p1, p3};
|
||||
dimensionLine->setPen(pen);
|
||||
dimensionLine->setLayer(nullptr);
|
||||
addEntity(dimensionLine);
|
||||
|
||||
RS_Vector distV;
|
||||
double textAngle;
|
||||
|
||||
// text distance to line (DIMGAP)
|
||||
double dimgap = getDimensionLineGap()*dimscale;
|
||||
|
||||
// rotate text so it's readable from the bottom or right (ISO)
|
||||
// quadrant 1 & 4
|
||||
if (angle > M_PI_2*3.0+0.001 || angle < M_PI_2+0.001)
|
||||
{
|
||||
distV.setPolar(dimgap + dimtxt/2.0, angle+M_PI_2);
|
||||
textAngle = angle;
|
||||
}
|
||||
// quadrant 2 & 3
|
||||
else
|
||||
{
|
||||
distV.setPolar(dimgap + dimtxt/2.0, angle-M_PI_2);
|
||||
textAngle = angle+M_PI;
|
||||
}
|
||||
|
||||
// move text label:
|
||||
RS_Vector textPos;
|
||||
|
||||
if (data.middleOfText.valid && !autoText) {
|
||||
textPos = data.middleOfText;
|
||||
} else {
|
||||
if (outsideArrow) {
|
||||
textPos.setPolar(length-textWidth/2.0-arrow_size, angle);
|
||||
} else {
|
||||
textPos.setPolar(length/2.0, angle);
|
||||
}
|
||||
textPos += p1;
|
||||
// move text away from dimension line:
|
||||
textPos += distV;
|
||||
data.middleOfText = textPos;
|
||||
}
|
||||
|
||||
text->rotate({0., 0.}, textAngle);
|
||||
text->move(textPos);
|
||||
|
||||
text->setPen(RS_Pen(getTextColor(), RS2::WidthByBlock, RS2::SolidLine));
|
||||
text->setLayer(nullptr);
|
||||
addEntity(text);
|
||||
|
||||
calculateBorders();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_DimRadial::move(const RS_Vector& offset) {
|
||||
RS_Dimension::move(offset);
|
||||
|
||||
edata.definitionPoint.move(offset);
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_DimRadial::rotate(const RS_Vector& center, const double& angle) {
|
||||
rotate(center,RS_Vector(angle));
|
||||
}
|
||||
|
||||
|
||||
void RS_DimRadial::rotate(const RS_Vector& center, const RS_Vector& angleVector) {
|
||||
RS_Dimension::rotate(center, angleVector);
|
||||
|
||||
edata.definitionPoint.rotate(center, angleVector);
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_DimRadial::scale(const RS_Vector& center, const RS_Vector& factor) {
|
||||
RS_Dimension::scale(center, factor);
|
||||
|
||||
edata.definitionPoint.scale(center, factor);
|
||||
edata.leader*=factor.x;
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_DimRadial::mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) {
|
||||
RS_Dimension::mirror(axisPoint1, axisPoint2);
|
||||
|
||||
edata.definitionPoint.mirror(axisPoint1, axisPoint2);
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
void RS_DimRadial::moveRef(const RS_Vector& ref, const RS_Vector& offset) {
|
||||
|
||||
if (ref.distanceTo(edata.definitionPoint)<1.0e-4) {
|
||||
double d = data.definitionPoint.distanceTo(edata.definitionPoint);
|
||||
double a = data.definitionPoint.angleTo(edata.definitionPoint + offset);
|
||||
|
||||
RS_Vector v = RS_Vector::polar(d, a);
|
||||
edata.definitionPoint = data.definitionPoint + v;
|
||||
updateDim(true);
|
||||
}
|
||||
else if (ref.distanceTo(data.middleOfText)<1.0e-4) {
|
||||
data.middleOfText.move(offset);
|
||||
updateDim(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps the point's data to stdout.
|
||||
*/
|
||||
std::ostream& operator << (std::ostream& os, const RS_DimRadial& d) {
|
||||
os << " DimRadial: " << d.getData() << "\n" << d.getEData() << "\n";
|
||||
return os;
|
||||
}
|
||||
114
lib/engine/rs_dimradial.h
Normal file
114
lib/engine/rs_dimradial.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_DIMRADIAL_H
|
||||
#define RS_DIMRADIAL_H
|
||||
|
||||
#include "rs_dimension.h"
|
||||
|
||||
/**
|
||||
* Holds the data that defines a radial dimension entity.
|
||||
*/
|
||||
struct RS_DimRadialData {
|
||||
/**
|
||||
* Default constructor. Leaves the data object uninitialized.
|
||||
*/
|
||||
RS_DimRadialData();
|
||||
|
||||
/**
|
||||
* Constructor with initialisation.
|
||||
*
|
||||
* @param definitionPoint Definition point of the radial dimension.
|
||||
* @param leader Leader length.
|
||||
*/
|
||||
RS_DimRadialData(const RS_Vector& definitionPoint,
|
||||
double leader);
|
||||
|
||||
/** Definition point. */
|
||||
RS_Vector definitionPoint;
|
||||
/** Leader length. */
|
||||
double leader;
|
||||
};
|
||||
|
||||
std::ostream& operator << (std::ostream& os,
|
||||
const RS_DimRadialData& dd);
|
||||
|
||||
/**
|
||||
* Class for radial dimension entities.
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_DimRadial : public RS_Dimension {
|
||||
public:
|
||||
RS_DimRadial(RS_EntityContainer* parent,
|
||||
const RS_DimensionData& d,
|
||||
const RS_DimRadialData& ed);
|
||||
|
||||
RS_Entity* clone() const override;
|
||||
|
||||
/** @return RS2::EntityDimRadial */
|
||||
RS2::EntityType rtti() const override{
|
||||
return RS2::EntityDimRadial;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Copy of data that defines the radial dimension.
|
||||
* @see getData()
|
||||
*/
|
||||
RS_DimRadialData getEData() const {
|
||||
return edata;
|
||||
}
|
||||
|
||||
RS_VectorSolutions getRefPoints() const override;
|
||||
|
||||
QString getMeasuredLabel() override;
|
||||
|
||||
void updateDim(bool autoText=false) override;
|
||||
|
||||
RS_Vector getDefinitionPoint() {
|
||||
return edata.definitionPoint;
|
||||
}
|
||||
double getLeader() {
|
||||
return edata.leader;
|
||||
}
|
||||
|
||||
void move(const RS_Vector& offset) override;
|
||||
void rotate(const RS_Vector& center, const double& angle) override;
|
||||
void rotate(const RS_Vector& center, const RS_Vector& angleVector) override;
|
||||
void scale(const RS_Vector& center, const RS_Vector& factor) override;
|
||||
void mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) override;
|
||||
void moveRef(const RS_Vector& ref, const RS_Vector& offset) override;
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os,
|
||||
const RS_DimRadial& d);
|
||||
|
||||
protected:
|
||||
/** Extended data. */
|
||||
RS_DimRadialData edata;
|
||||
};
|
||||
|
||||
#endif
|
||||
65
lib/engine/rs_document.cpp
Normal file
65
lib/engine/rs_document.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2018 A. Stebich (librecad@mail.lordofbikes.de)
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#include "rs_document.h"
|
||||
#include "rs_debug.h"
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param parent Parent of the document. Often that's NULL but
|
||||
* for blocks it's the blocklist.
|
||||
*/
|
||||
RS_Document::RS_Document(RS_EntityContainer* parent)
|
||||
: RS_EntityContainer(parent), RS_Undo() {
|
||||
|
||||
RS_DEBUG->print("RS_Document::RS_Document() ");
|
||||
|
||||
filename = "";
|
||||
autosaveFilename = "Unnamed";
|
||||
formatType = RS2::FormatUnknown;
|
||||
setModified(false);
|
||||
RS_Color col(RS2::FlagByLayer);
|
||||
activePen = RS_Pen(col, RS2::WidthByLayer, RS2::LineByLayer);
|
||||
|
||||
gv = NULL;//used to read/save current view
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwritten to set modified flag when undo cycle finished with undoable(s).
|
||||
*/
|
||||
void RS_Document::endUndoCycle()
|
||||
{
|
||||
if (hasUndoable()) {
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
RS_Undo::endUndoCycle();
|
||||
}
|
||||
|
||||
155
lib/engine/rs_document.h
Normal file
155
lib/engine/rs_document.h
Normal file
@@ -0,0 +1,155 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2018 A. Stebich (librecad@mail.lordofbikes.de)
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_DOCUMENT_H
|
||||
#define RS_DOCUMENT_H
|
||||
|
||||
#include "rs_layerlist.h"
|
||||
#include "rs_entitycontainer.h"
|
||||
#include "rs_undo.h"
|
||||
|
||||
class RS_BlockList;
|
||||
|
||||
/**
|
||||
* Base class for documents. Documents can be either graphics or
|
||||
* blocks and are typically shown in graphic views. Documents hold
|
||||
* an active pen for drawing in the Document, a file name and they
|
||||
* know whether they have been modified or not.
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_Document : public RS_EntityContainer,
|
||||
public RS_Undo {
|
||||
public:
|
||||
RS_Document(RS_EntityContainer* parent=nullptr);
|
||||
virtual ~RS_Document() = default;
|
||||
|
||||
virtual RS_LayerList* getLayerList() = 0;
|
||||
virtual RS_BlockList* getBlockList() = 0;
|
||||
|
||||
virtual void newDoc() = 0;
|
||||
virtual bool save(bool isAutoSave = false) = 0;
|
||||
virtual bool saveAs(const QString &filename, RS2::FormatType type, bool force) = 0;
|
||||
virtual bool open(const QString &filename, RS2::FormatType type) = 0;
|
||||
virtual bool loadTemplate(const QString &filename, RS2::FormatType type) = 0;
|
||||
|
||||
|
||||
/**
|
||||
* @return true for all document entities (e.g. Graphics or Blocks).
|
||||
*/
|
||||
virtual bool isDocument() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an entity from the entity container. Implementation
|
||||
* from RS_Undo.
|
||||
*/
|
||||
virtual void removeUndoable(RS_Undoable* u) {
|
||||
if (u && u->undoRtti()==RS2::UndoableEntity && u->isUndone()) {
|
||||
removeEntity(static_cast<RS_Entity*>(u));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Currently active drawing pen.
|
||||
*/
|
||||
RS_Pen getActivePen() const {
|
||||
return activePen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the currently active drawing pen to p.
|
||||
*/
|
||||
void setActivePen(RS_Pen p) {
|
||||
activePen = p;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return File name of the document currently loaded.
|
||||
* Note, that the default file name is empty.
|
||||
*/
|
||||
QString getFilename() const {
|
||||
return filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Auto-save file name of the document currently loaded.
|
||||
*/
|
||||
QString getAutoSaveFilename() const {
|
||||
return autosaveFilename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets file name for the document currently loaded.
|
||||
*/
|
||||
void setFilename(const QString& fn) {
|
||||
filename = fn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the documents modified status to 'm'.
|
||||
*/
|
||||
virtual void setModified(bool m) {
|
||||
//std::cout << "RS_Document::setModified: %d" << (int)m << std::endl;
|
||||
modified = m;
|
||||
}
|
||||
|
||||
/**
|
||||
* @retval true The document has been modified since it was last saved.
|
||||
* @retval false The document has not been modified since it was last saved.
|
||||
*/
|
||||
virtual bool isModified() const {
|
||||
return modified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwritten to set modified flag when undo cycle finished with undoable(s).
|
||||
*/
|
||||
virtual void endUndoCycle() override;
|
||||
|
||||
void setGraphicView(RS_GraphicView * g) {gv = g;}
|
||||
RS_GraphicView* getGraphicView() {return gv;}
|
||||
|
||||
protected:
|
||||
/** Flag set if the document was modified and not yet saved. */
|
||||
bool modified;
|
||||
/** Active pen. */
|
||||
RS_Pen activePen;
|
||||
/** File name of the document or empty for a new document. */
|
||||
QString filename;
|
||||
/** Auto-save file name of document. */
|
||||
QString autosaveFilename;
|
||||
/** Format type */
|
||||
RS2::FormatType formatType;
|
||||
RS_GraphicView * gv;//used to read/save current view
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
1866
lib/engine/rs_ellipse.cpp
Normal file
1866
lib/engine/rs_ellipse.cpp
Normal file
File diff suppressed because it is too large
Load Diff
247
lib/engine/rs_ellipse.h
Normal file
247
lib/engine/rs_ellipse.h
Normal file
@@ -0,0 +1,247 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2011-2015 Dongxu Li (dongxuli2011@gmail.com)
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_ELLIPSE_H
|
||||
#define RS_ELLIPSE_H
|
||||
|
||||
#include "rs_atomicentity.h"
|
||||
|
||||
class LC_Quadratic;
|
||||
|
||||
/**
|
||||
* Holds the data that defines an ellipse.
|
||||
* angle1=angle2=0.0 is reserved for whole ellipses
|
||||
* add 2*M_PI to angle1 or angle2 to make whole range ellipse arcs
|
||||
*/
|
||||
struct RS_EllipseData {
|
||||
//! Ellipse center
|
||||
RS_Vector center;
|
||||
//! Endpoint of major axis relative to center.
|
||||
RS_Vector majorP;
|
||||
//! Ratio of minor axis to major axis.
|
||||
double ratio;
|
||||
//! Start angle
|
||||
double angle1;
|
||||
//! End angle
|
||||
double angle2;
|
||||
//! Reversed (cw) flag
|
||||
bool reversed;
|
||||
};
|
||||
|
||||
std::ostream& operator << (std::ostream& os, const RS_EllipseData& ed);
|
||||
|
||||
/**
|
||||
* Class for an ellipse entity. All angles are in Rad.
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_Ellipse : public RS_AtomicEntity {
|
||||
public:
|
||||
RS_Ellipse()=default;
|
||||
RS_Ellipse(RS_EntityContainer* parent, const RS_EllipseData& d);
|
||||
|
||||
RS_Entity* clone() const override;
|
||||
|
||||
/** @return RS2::EntityEllipse */
|
||||
RS2::EntityType rtti() const override{
|
||||
return RS2::EntityEllipse;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Start point of the entity.
|
||||
*/
|
||||
RS_Vector getStartpoint() const override;
|
||||
RS_VectorSolutions getFoci() const;
|
||||
|
||||
/**
|
||||
* @return End point of the entity.
|
||||
*/
|
||||
RS_Vector getEndpoint() const override;
|
||||
RS_Vector getEllipsePoint(const double& a) const; //find the point according to ellipse angle
|
||||
|
||||
void moveStartpoint(const RS_Vector& pos) override;
|
||||
void moveEndpoint(const RS_Vector& pos) override;
|
||||
double getLength() const override;
|
||||
|
||||
/**
|
||||
//Ellipse must have ratio<1, and not reversed
|
||||
*@ x1, ellipse angle
|
||||
*@ x2, ellipse angle
|
||||
//@return the arc length between ellipse angle x1, x2
|
||||
**/
|
||||
double getEllipseLength(double a1, double a2) const;
|
||||
double getEllipseLength(double a2) const;
|
||||
RS_VectorSolutions getTangentPoint(const RS_Vector& point) const override;//find the tangential points seeing from given point
|
||||
RS_Vector getTangentDirection(const RS_Vector& point)const override;
|
||||
RS2::Ending getTrimPoint(const RS_Vector& trimCoord,
|
||||
const RS_Vector& trimPoint) override;
|
||||
|
||||
RS_Vector prepareTrim(const RS_Vector& trimCoord,
|
||||
const RS_VectorSolutions& trimSol) override;
|
||||
|
||||
double getEllipseAngle (const RS_Vector& pos) const;
|
||||
|
||||
/** @return Copy of data that defines the ellipse. **/
|
||||
const RS_EllipseData& getData() const;
|
||||
|
||||
RS_VectorSolutions getRefPoints() const override;
|
||||
|
||||
/**
|
||||
* @retval true if the arc is reversed (clockwise),
|
||||
* @retval false otherwise
|
||||
*/
|
||||
bool isReversed() const;
|
||||
/** sets the reversed status. */
|
||||
void setReversed(bool r);
|
||||
|
||||
/** @return The rotation angle of this ellipse */
|
||||
double getAngle() const;
|
||||
|
||||
/** @return The start angle of this arc */
|
||||
double getAngle1() const;
|
||||
/** Sets new start angle. */
|
||||
void setAngle1(double a1);
|
||||
/** @return The end angle of this arc */
|
||||
double getAngle2() const;
|
||||
/** Sets new end angle. */
|
||||
void setAngle2(double a2);
|
||||
|
||||
|
||||
/** @return The center point (x) of this arc */
|
||||
RS_Vector getCenter() const override;
|
||||
/** Sets new center. */
|
||||
void setCenter(const RS_Vector& c);
|
||||
|
||||
/** @return The endpoint of the major axis (relative to center). */
|
||||
const RS_Vector& getMajorP() const;
|
||||
/** Sets new major point (relative to center). */
|
||||
void setMajorP(const RS_Vector& p);
|
||||
|
||||
/** @return The ratio of minor to major axis */
|
||||
double getRatio() const;
|
||||
/** Sets new ratio. */
|
||||
void setRatio(double r);
|
||||
|
||||
/**
|
||||
* @return Angle length in rad.
|
||||
*/
|
||||
double getAngleLength() const;
|
||||
|
||||
/** @return The major radius of this ellipse. Same as getRadius() */
|
||||
double getMajorRadius() const;
|
||||
|
||||
/** @return the point by major minor radius directions */
|
||||
RS_Vector getMajorPoint() const;
|
||||
RS_Vector getMinorPoint() const;
|
||||
|
||||
/** @return The minor radius of this ellipse */
|
||||
double getMinorRadius() const;
|
||||
//! \brief isEllipticArc the ellipse an Arc, if angle1/angle2 are not both 0
|
||||
bool isEllipticArc() const;
|
||||
bool isEdge() const override{
|
||||
return true;
|
||||
}
|
||||
bool createFrom4P(const RS_VectorSolutions& sol);
|
||||
bool createFromCenter3Points(const RS_VectorSolutions& sol);
|
||||
//! \{ \brief from quadratic form
|
||||
/** : dn[0] x^2 + dn[1] xy + dn[2] y^2 =1 */
|
||||
bool createFromQuadratic(const std::vector<double>& dn);
|
||||
/** : generic quadratic: A x^2 + C xy + B y^2 + D x + E y + F =0 */
|
||||
bool createFromQuadratic(const LC_Quadratic& q);
|
||||
//! \}
|
||||
bool createInscribeQuadrilateral(const std::vector<RS_Line*>& lines);
|
||||
RS_Vector getMiddlePoint(void)const override;
|
||||
RS_Vector getNearestEndpoint(const RS_Vector& coord,
|
||||
double* dist = nullptr) const override;
|
||||
RS_Vector getNearestPointOnEntity(const RS_Vector& coord,
|
||||
bool onEntity = true, double* dist = nullptr, RS_Entity** entity=nullptr) const override;
|
||||
RS_Vector getNearestCenter(const RS_Vector& coord,
|
||||
double* dist = nullptr)const override;
|
||||
RS_Vector getNearestMiddle(const RS_Vector& coord,
|
||||
double* dist = nullptr,
|
||||
int middlePoints = 1
|
||||
)const override;
|
||||
RS_Vector getNearestDist(double distance,
|
||||
const RS_Vector& coord,
|
||||
double* dist = nullptr)const override;
|
||||
RS_Vector getNearestOrthTan(const RS_Vector& coord,
|
||||
const RS_Line& normal,
|
||||
bool onEntity = false) const override;
|
||||
bool switchMajorMinor(void); //switch major minor axes to keep major the longer ellipse radius
|
||||
void correctAngles();//make sure angleLength() is not more than 2*M_PI
|
||||
bool isPointOnEntity(const RS_Vector& coord,
|
||||
double tolerance=RS_TOLERANCE) const override;
|
||||
|
||||
void move(const RS_Vector& offset) override;
|
||||
void rotate(const double& angle);
|
||||
void rotate(const RS_Vector& angleVector);
|
||||
void rotate(const RS_Vector& center, const double& angle) override;
|
||||
void rotate(const RS_Vector& center, const RS_Vector& angle) override;
|
||||
void scale(const RS_Vector& center, const RS_Vector& factor) override;
|
||||
void mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) override;
|
||||
void moveRef(const RS_Vector& ref, const RS_Vector& offset) override;
|
||||
|
||||
/** whether the entity's bounding box intersects with visible portion of graphic view
|
||||
*/
|
||||
bool isVisibleInWindow(RS_GraphicView* view) const override;
|
||||
//! \{ \brief find visible segments of entity and draw only those visible portion
|
||||
void draw(RS_Painter* painter, RS_GraphicView* view, double& patternOffset) override;
|
||||
void drawVisible(RS_Painter* painter, RS_GraphicView* view, double& patternOffset);
|
||||
//! \}
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os, const RS_Ellipse& a);
|
||||
|
||||
//void calculateEndpoints() override;
|
||||
void calculateBorders() override;
|
||||
|
||||
//direction of tangent at endpoints
|
||||
double getDirection1() const override;
|
||||
double getDirection2() const override;
|
||||
|
||||
/** \brief return the equation of the entity
|
||||
a quadratic contains coefficients for quadratic:
|
||||
m0 x^2 + m1 xy + m2 y^2 + m3 x + m4 y + m5 =0
|
||||
|
||||
for linear:
|
||||
m0 x + m1 y + m2 =0
|
||||
**/
|
||||
LC_Quadratic getQuadratic() const override;
|
||||
/**
|
||||
* @brief areaLineIntegral, line integral for contour area calculation by Green's Theorem
|
||||
* Contour Area =\oint x dy
|
||||
* @return line integral \oint x dy along the entity
|
||||
* \oint x dy = Cx y + \frac{1}{4}((a^{2}+b^{2})sin(2a)cos^{2}(t)-ab(2sin^{2}(a)sin(2t)-2t-sin(2t)))
|
||||
*/
|
||||
double areaLineIntegral() const override;
|
||||
|
||||
protected:
|
||||
RS_EllipseData data;
|
||||
};
|
||||
|
||||
#endif
|
||||
//EOF
|
||||
1129
lib/engine/rs_entity.cpp
Normal file
1129
lib/engine/rs_entity.cpp
Normal file
File diff suppressed because it is too large
Load Diff
585
lib/engine/rs_entity.h
Normal file
585
lib/engine/rs_entity.h
Normal file
@@ -0,0 +1,585 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2015 A. Stebich (librecad@mail.lordofbikes.de)
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_ENTITY_H
|
||||
#define RS_ENTITY_H
|
||||
|
||||
#include <map>
|
||||
#include "rs_vector.h"
|
||||
#include "rs_pen.h"
|
||||
#include "rs_undoable.h"
|
||||
|
||||
class RS_Arc;
|
||||
class RS_Block;
|
||||
class RS_Circle;
|
||||
class RS_Document;
|
||||
class RS_EntityContainer;
|
||||
class RS_Graphic;
|
||||
class RS_GraphicView;
|
||||
class RS_Insert;
|
||||
class RS_Line;
|
||||
class RS_Painter;
|
||||
class RS_Point;
|
||||
class RS_Polyline;
|
||||
class RS_Text;
|
||||
class RS_Layer;
|
||||
class LC_Quadratic;
|
||||
class RS_Vector;
|
||||
class RS_VectorSolutions;
|
||||
class QString;
|
||||
|
||||
/**
|
||||
* Base class for an entity (line, arc, circle, ...)
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_Entity : public RS_Undoable {
|
||||
public:
|
||||
RS_Entity(RS_EntityContainer* parent=nullptr);
|
||||
virtual ~RS_Entity() = default;
|
||||
|
||||
void init();
|
||||
virtual void initId();
|
||||
|
||||
virtual RS_Entity* clone() const = 0;
|
||||
|
||||
virtual void reparent(RS_EntityContainer* parent) {
|
||||
this->parent = parent;
|
||||
}
|
||||
|
||||
void resetBorders();
|
||||
void moveBorders(const RS_Vector& offset);
|
||||
void scaleBorders(const RS_Vector& center, const RS_Vector& factor);
|
||||
/**
|
||||
* Must be overwritten to return the rtti of this entity
|
||||
* (e.g. RS2::EntityArc).
|
||||
*/
|
||||
virtual RS2::EntityType rtti() const{
|
||||
return RS2::EntityUnknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Identify all entities as undoable entities.
|
||||
* @return RS2::UndoableEntity
|
||||
*/
|
||||
virtual RS2::UndoableType undoRtti() const override {
|
||||
return RS2::UndoableEntity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Unique Id of this entity.
|
||||
*/
|
||||
unsigned long int getId() const {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method must be overwritten in subclasses and return the
|
||||
* number of <b>atomic</b> entities in this entity.
|
||||
*/
|
||||
virtual unsigned int count() const= 0;
|
||||
|
||||
/**
|
||||
* This method must be overwritten in subclasses and return the
|
||||
* number of <b>atomic</b> entities in this entity including sub containers.
|
||||
*/
|
||||
virtual unsigned int countDeep() const= 0;
|
||||
|
||||
|
||||
/**
|
||||
* Implementations must return the total length of the entity
|
||||
* or a negative number if the entity has no length (e.g. a text or hatch).
|
||||
*/
|
||||
virtual double getLength() const {
|
||||
return -1.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Parent of this entity or nullptr if this is a root entity.
|
||||
*/
|
||||
RS_EntityContainer* getParent() const {
|
||||
return parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reparents this entity.
|
||||
*/
|
||||
void setParent(RS_EntityContainer* p) {
|
||||
parent = p;
|
||||
}
|
||||
/** @return The center point (x) of this arc */
|
||||
//get center for entities: arc, circle and ellipse
|
||||
virtual RS_Vector getCenter() const;
|
||||
virtual double getRadius() const;
|
||||
RS_Graphic* getGraphic() const;
|
||||
RS_Block* getBlock() const;
|
||||
RS_Insert* getInsert() const;
|
||||
RS_Entity* getBlockOrInsert() const;
|
||||
RS_Document* getDocument() const;
|
||||
|
||||
void setLayer(const QString& name);
|
||||
void setLayer(RS_Layer* l);
|
||||
void setLayerToActive();
|
||||
RS_Layer* getLayer(bool resolve = true) const;
|
||||
|
||||
/**
|
||||
* Sets the explicit pen for this entity or a pen with special
|
||||
* attributes such as BY_LAYER, ..
|
||||
*/
|
||||
void setPen(const RS_Pen& pen) {
|
||||
this->pen = pen;
|
||||
}
|
||||
|
||||
|
||||
void setPenToActive();
|
||||
RS_Pen getPen(bool resolve = true) const;
|
||||
|
||||
/**
|
||||
* Must be overwritten to return true if an entity type
|
||||
* is a container for other entities (e.g. polyline, group, ...).
|
||||
*/
|
||||
virtual bool isContainer() const = 0;
|
||||
|
||||
/**
|
||||
* Must be overwritten to return true if an entity type
|
||||
* is an atomic entity.
|
||||
*/
|
||||
virtual bool isAtomic() const = 0;
|
||||
|
||||
/**
|
||||
* Must be overwritten to return true if an entity type
|
||||
* is a potential edge entity of a contour. By default
|
||||
* this returns false.
|
||||
*/
|
||||
virtual bool isEdge() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true for all document entities (e.g. Graphics or Blocks).
|
||||
* false otherwise.
|
||||
*/
|
||||
virtual bool isDocument() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool setSelected(bool select);
|
||||
virtual bool toggleSelected();
|
||||
virtual bool isSelected() const;
|
||||
bool isParentSelected() const;
|
||||
virtual bool isProcessed() const;
|
||||
virtual void setProcessed(bool on);
|
||||
bool isInWindow(RS_Vector v1, RS_Vector v2) const;
|
||||
virtual bool hasEndpointsWithinWindow(const RS_Vector& /*v1*/, const RS_Vector& /*v2*/) {
|
||||
return false;
|
||||
}
|
||||
virtual bool isVisible() const;
|
||||
virtual void setVisible(bool v);
|
||||
virtual void setHighlighted(bool on);
|
||||
virtual bool isHighlighted() const;
|
||||
|
||||
bool isLocked() const;
|
||||
|
||||
void undoStateChanged(bool undone) override;
|
||||
virtual bool isUndone() const;
|
||||
|
||||
/**
|
||||
* Can be implemented by child classes to update the entities
|
||||
* temporary subentities. update() is called if the entity's
|
||||
* parameters or undo state changed.
|
||||
*/
|
||||
virtual void update() {}
|
||||
|
||||
virtual void setUpdateEnabled(bool on) {
|
||||
updateEnabled = on;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method doesn't do any calculations.
|
||||
* @return minimum coordinate of the entity.
|
||||
* @see calculateBorders()
|
||||
*/
|
||||
RS_Vector getMin() const {
|
||||
return minV;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method doesn't do any calculations.
|
||||
* @return minimum coordinate of the entity.
|
||||
* @see calculateBorders()
|
||||
*/
|
||||
RS_Vector getMax() const {
|
||||
return maxV;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the difference of max and min returned
|
||||
* by the above functions.
|
||||
* @return size of the entity.
|
||||
* @see calculateBorders()
|
||||
* @see getMin()
|
||||
* @see getMax()
|
||||
*/
|
||||
RS_Vector getSize() const;
|
||||
|
||||
void addGraphicVariable(const QString& key, double val, int code);
|
||||
void addGraphicVariable(const QString& key, int val, int code);
|
||||
void addGraphicVariable(const QString& key, const QString& val, int code);
|
||||
|
||||
double getGraphicVariableDouble(const QString& key, double def);
|
||||
int getGraphicVariableInt(const QString& key, int def) const;
|
||||
QString getGraphicVariableString(const QString& key,
|
||||
const QString& def) const;
|
||||
virtual RS_Vector getStartpoint() const;
|
||||
virtual RS_Vector getEndpoint() const;
|
||||
//find the local direction at end points, derived entities
|
||||
// must implement this if direction is supported by the entity type
|
||||
virtual double getDirection1() const {
|
||||
return 0.;
|
||||
}
|
||||
virtual double getDirection2() const {
|
||||
return 0.;
|
||||
}
|
||||
|
||||
//find the tangential points seeing from given point
|
||||
virtual RS_VectorSolutions getTangentPoint(const RS_Vector& /*point*/) const;
|
||||
virtual RS_Vector getTangentDirection(const RS_Vector& /*point*/)const;
|
||||
RS2::Unit getGraphicUnit() const;
|
||||
|
||||
/**
|
||||
* Must be overwritten to get all reference points of the entity.
|
||||
*/
|
||||
virtual RS_VectorSolutions getRefPoints() const;
|
||||
|
||||
/**
|
||||
* Must be overwritten to get the closest endpoint to the
|
||||
* given coordinate for this entity.
|
||||
*
|
||||
* @param coord Coordinate (typically a mouse coordinate)
|
||||
* @param dist Pointer to a value which will contain the measured
|
||||
* distance between 'coord' and the closest endpoint. The passed
|
||||
* pointer can also be nullptr in which case the distance will be
|
||||
* lost.
|
||||
*
|
||||
* @return The closest endpoint.
|
||||
*/
|
||||
virtual RS_Vector getNearestEndpoint(const RS_Vector& coord,
|
||||
double* dist = nullptr)const = 0;
|
||||
|
||||
/**
|
||||
* Must be overwritten to get the closest coordinate to the
|
||||
* given coordinate which is on this entity.
|
||||
*
|
||||
* @param coord Coordinate (typically a mouse coordinate)
|
||||
* @param dist Pointer to a value which will contain the measured
|
||||
* distance between \p coord and the point. The passed pointer can
|
||||
* also be \p nullptr in which case the distance will be lost.
|
||||
*
|
||||
* @return The closest coordinate.
|
||||
*/
|
||||
virtual RS_Vector getNearestPointOnEntity(const RS_Vector& /*coord*/,
|
||||
bool onEntity = true, double* dist = nullptr,
|
||||
RS_Entity** entity = nullptr) const = 0;
|
||||
|
||||
/**
|
||||
* Must be overwritten to get the (nearest) center point to the
|
||||
* given coordinate for this entity.
|
||||
*
|
||||
* @param coord Coordinate (typically a mouse coordinate)
|
||||
* @param dist Pointer to a value which will contain the measured
|
||||
* distance between 'coord' and the closest center point. The passed
|
||||
* pointer can also be nullptr in which case the distance will be
|
||||
* lost.
|
||||
*
|
||||
* @return The closest center point.
|
||||
*/
|
||||
virtual RS_Vector getNearestCenter(const RS_Vector& coord,
|
||||
double* dist = nullptr) const= 0;
|
||||
|
||||
/**
|
||||
* Must be overwritten to get the (nearest) middle point to the
|
||||
* given coordinate for this entity.
|
||||
*
|
||||
* @param coord Coordinate (typically a mouse coordinate)
|
||||
* @param dist Pointer to a value which will contain the measured
|
||||
* distance between 'coord' and the closest middle point. The passed
|
||||
* pointer can also be nullptr in which case the distance will be
|
||||
* lost.
|
||||
*
|
||||
* @return The closest middle point.
|
||||
*/
|
||||
virtual RS_Vector getMiddlePoint(void)const{
|
||||
return RS_Vector(false);
|
||||
}
|
||||
virtual RS_Vector getNearestMiddle(const RS_Vector& coord,
|
||||
double* dist = nullptr,
|
||||
int middlePoints = 1
|
||||
) const= 0;
|
||||
|
||||
/**
|
||||
* Must be overwritten to get the nearest point with a given
|
||||
* distance to the endpoint to the given coordinate for this entity.
|
||||
*
|
||||
* @param distance Distance to endpoint.
|
||||
* @param coord Coordinate (typically a mouse coordinate)
|
||||
* @param dist Pointer to a value which will contain the measured
|
||||
* distance between 'coord' and the closest point. The passed
|
||||
* pointer can also be nullptr in which case the distance will be
|
||||
* lost.
|
||||
*
|
||||
* @return The closest point with the given distance to the endpoint.
|
||||
*/
|
||||
virtual RS_Vector getNearestDist(double distance,
|
||||
const RS_Vector& coord,
|
||||
double* dist = nullptr) const= 0;
|
||||
|
||||
/**
|
||||
* Must be overwritten to get the point with a given
|
||||
* distance to the start- or endpoint to the given coordinate for this entity.
|
||||
*
|
||||
* @param distance Distance to endpoint.
|
||||
* @param startp true = measured from Startpoint, false = measured from Endpoint
|
||||
*
|
||||
* @return The point with the given distance to the start- or endpoint.
|
||||
*/
|
||||
virtual RS_Vector getNearestDist(double /*distance*/,
|
||||
bool /*startp*/) const{
|
||||
return RS_Vector(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Must be overwritten to get the nearest reference point for this entity.
|
||||
*
|
||||
* @param coord Coordinate (typically a mouse coordinate)
|
||||
* @param dist Pointer to a value which will contain the measured
|
||||
* distance between 'coord' and the closest point. The passed
|
||||
* pointer can also be nullptr in which case the distance will be
|
||||
* lost.
|
||||
*
|
||||
* @return The closest point with the given distance to the endpoint.
|
||||
*/
|
||||
virtual RS_Vector getNearestRef(const RS_Vector& coord,
|
||||
double* dist = nullptr) const;
|
||||
|
||||
/**
|
||||
* Gets the nearest reference point of this entity if it is selected.
|
||||
* Containers re-implement this method to return the nearest reference
|
||||
* point of a selected sub entity.
|
||||
*
|
||||
* @param coord Coordinate (typically a mouse coordinate)
|
||||
* @param dist Pointer to a value which will contain the measured
|
||||
* distance between 'coord' and the closest point. The passed
|
||||
* pointer can also be nullptr in which case the distance will be
|
||||
* lost.
|
||||
*
|
||||
* @return The closest point with the given distance to the endpoint.
|
||||
*/
|
||||
virtual RS_Vector getNearestSelectedRef(const RS_Vector& coord,
|
||||
double* dist = nullptr) const;
|
||||
|
||||
/**
|
||||
* Must be overwritten to get the shortest distance between this
|
||||
* entity and a coordinate.
|
||||
*
|
||||
* @param coord Coordinate (typically a mouse coordinate)
|
||||
* @param entity Pointer which will contain the (sub-)entity which is
|
||||
* closest to the given point or nullptr if the caller is not
|
||||
* interested in this information.
|
||||
* @param level The resolve level.
|
||||
*
|
||||
* @sa RS2::ResolveLevel
|
||||
*
|
||||
* @return The measured distance between \p coord and the entity.
|
||||
*/
|
||||
virtual RS_Vector getNearestOrthTan(const RS_Vector& /*coord*/,
|
||||
const RS_Line& /*normal*/,
|
||||
bool onEntity = false) const;
|
||||
virtual double getDistanceToPoint(const RS_Vector& coord,
|
||||
RS_Entity** entity = nullptr,
|
||||
RS2::ResolveLevel level = RS2::ResolveNone,
|
||||
double solidDist = RS_MAXDOUBLE) const;
|
||||
|
||||
virtual bool isPointOnEntity(const RS_Vector& coord,
|
||||
double tolerance=20.*RS_TOLERANCE) const;
|
||||
|
||||
/**
|
||||
* Implementations must offset the entity by the given direction and distance.
|
||||
*/
|
||||
virtual bool offset(const RS_Vector& /*coord*/, const double& /*distance*/) {return false;}
|
||||
|
||||
/**
|
||||
* Implementations must offset the entity by the distance at both directions
|
||||
* used to generate tangential circles
|
||||
*/
|
||||
virtual std::vector<RS_Entity* > offsetTwoSides(const double& /*distance*/) const
|
||||
{
|
||||
return std::vector<RS_Entity* >();
|
||||
}
|
||||
/**
|
||||
* implementations must revert the direction of an atomic entity
|
||||
*/
|
||||
virtual void revertDirection(){}
|
||||
/**
|
||||
* Implementations must move the entity by the given vector.
|
||||
*/
|
||||
virtual void move(const RS_Vector& offset) = 0;
|
||||
|
||||
/**
|
||||
* Implementations must rotate the entity by the given angle around
|
||||
* the given center.
|
||||
*/
|
||||
virtual void rotate(const RS_Vector& center, const double& angle) = 0;
|
||||
virtual void rotate(const RS_Vector& center, const RS_Vector& angleVector) = 0;
|
||||
|
||||
/**
|
||||
* Implementations must scale the entity by the given factors.
|
||||
*/
|
||||
virtual void scale(const RS_Vector& center, const RS_Vector& factor) = 0;
|
||||
|
||||
/**
|
||||
* Acts like scale(RS_Vector) but with equal factors.
|
||||
* Equal to scale(center, RS_Vector(factor, factor)).
|
||||
*/
|
||||
virtual void scale(const RS_Vector& center, const double& factor) {
|
||||
scale(center, RS_Vector(factor, factor));
|
||||
}
|
||||
virtual void scale(const RS_Vector& factor) {
|
||||
scale(RS_Vector(0.,0.), factor);
|
||||
}
|
||||
/**
|
||||
* Implementations must mirror the entity by the given axis.
|
||||
*/
|
||||
virtual void mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) = 0;
|
||||
|
||||
virtual void stretch(const RS_Vector& firstCorner,
|
||||
const RS_Vector& secondCorner,
|
||||
const RS_Vector& offset);
|
||||
|
||||
/**
|
||||
* Implementations must drag the reference point(s) of all
|
||||
* (sub-)entities that are very close to ref by offset.
|
||||
*/
|
||||
virtual void moveRef(const RS_Vector& /*ref*/,
|
||||
const RS_Vector& /*offset*/) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementations must drag the reference point(s) of selected
|
||||
* (sub-)entities that are very close to ref by offset.
|
||||
*/
|
||||
virtual void moveSelectedRef(const RS_Vector& /*ref*/,
|
||||
const RS_Vector& /*offset*/) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/** whether the entity's bounding box intersects with visible portion of graphic view */
|
||||
virtual bool isVisibleInWindow(RS_GraphicView* view) const;
|
||||
/**
|
||||
* Implementations must draw the entity on the given device.
|
||||
*/
|
||||
virtual void draw(RS_Painter* painter, RS_GraphicView* view,
|
||||
double& patternOffset ) = 0;
|
||||
|
||||
double getStyleFactor(RS_GraphicView* view);
|
||||
|
||||
QString getUserDefVar(const QString& key) const;
|
||||
std::vector<QString> getAllKeys() const;
|
||||
void setUserDefVar(QString key, QString val);
|
||||
void delUserDefVar(QString key);
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os, RS_Entity& e);
|
||||
|
||||
/** Recalculates the borders of this entity. */
|
||||
virtual void calculateBorders() = 0;
|
||||
/** whether the entity is on a constructionLayer */
|
||||
//! constructionLayer contains entities of infinite length, constructionLayer doesn't show up in print
|
||||
bool isConstruction(bool typeCheck = false) const; // ignore certain entity types for constructionLayer check
|
||||
//! whether printing is enabled or disabled for the entity's layer
|
||||
bool isPrint(void) const;
|
||||
/** return the equation of the entity
|
||||
for quadratic,
|
||||
|
||||
return a vector contains:
|
||||
m0 x^2 + m1 xy + m2 y^2 + m3 x + m4 y + m5 =0
|
||||
|
||||
for linear:
|
||||
m0 x + m1 y + m2 =0
|
||||
**/
|
||||
virtual LC_Quadratic getQuadratic() const;
|
||||
/**
|
||||
* @brief areaLineIntegral, line integral for contour area calculation by Green's Theorem
|
||||
* Contour Area =\oint x dy
|
||||
* @return line integral \oint x dy along the entity
|
||||
*/
|
||||
virtual double areaLineIntegral() const;
|
||||
|
||||
/**
|
||||
* @brief trimmable, whether the entity type can be trimmed
|
||||
* @return true, for trimmable entity types
|
||||
* currently, trimmable types are: RS_Line, RS_Circle, RS_Arc, RS_Ellipse
|
||||
*/
|
||||
bool trimmable() const;
|
||||
|
||||
/**
|
||||
* @brief isArc is the entity of type Arc, Circle, or Ellipse
|
||||
* @return true for Arc, Circle, or Ellipse
|
||||
*/
|
||||
virtual bool isArc() const;
|
||||
/**
|
||||
* @brief isArcLine determine the entity is either Arc, Circle, or Line
|
||||
* @return true if entity is Arc, Circle, or Line
|
||||
*/
|
||||
virtual bool isArcCircleLine() const;
|
||||
|
||||
protected:
|
||||
//! Entity's parent entity or nullptr is this entity has no parent.
|
||||
RS_EntityContainer* parent = nullptr;
|
||||
//! minimum coordinates
|
||||
RS_Vector minV;
|
||||
//! maximum coordinates
|
||||
RS_Vector maxV;
|
||||
|
||||
//! Pointer to layer
|
||||
RS_Layer* layer;
|
||||
|
||||
//! Entity id
|
||||
unsigned long int id;
|
||||
|
||||
//! pen (attributes) for this entity
|
||||
RS_Pen pen;
|
||||
|
||||
//! auto updating enabled?
|
||||
bool updateEnabled;
|
||||
|
||||
private:
|
||||
std::map<QString, QString> varList;
|
||||
};
|
||||
|
||||
#endif
|
||||
1976
lib/engine/rs_entitycontainer.cpp
Normal file
1976
lib/engine/rs_entitycontainer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
259
lib/engine/rs_entitycontainer.h
Normal file
259
lib/engine/rs_entitycontainer.h
Normal file
@@ -0,0 +1,259 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_ENTITYCONTAINER_H
|
||||
#define RS_ENTITYCONTAINER_H
|
||||
|
||||
#include <vector>
|
||||
#include "rs_entity.h"
|
||||
|
||||
/**
|
||||
* Class representing a tree of entities.
|
||||
* Typical entity containers are graphics, polylines, groups, texts, ...)
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_EntityContainer : public RS_Entity {
|
||||
typedef RS_Entity * value_type;
|
||||
|
||||
public:
|
||||
|
||||
RS_EntityContainer(RS_EntityContainer* parent=nullptr, bool owner=true);
|
||||
//RS_EntityContainer(const RS_EntityContainer& ec);
|
||||
~RS_EntityContainer() override;
|
||||
|
||||
RS_Entity* clone() const override;
|
||||
virtual void detach();
|
||||
|
||||
/** @return RS2::EntityContainer */
|
||||
RS2::EntityType rtti() const override{
|
||||
return RS2::EntityContainer;
|
||||
}
|
||||
|
||||
void reparent(RS_EntityContainer* parent) override;
|
||||
|
||||
/**
|
||||
* @return true: because entities made from this class
|
||||
* and subclasses are containers for other entities.
|
||||
*/
|
||||
bool isContainer() const override{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return false: because entities made from this class
|
||||
* and subclasses are containers for other entities.
|
||||
*/
|
||||
bool isAtomic() const override{
|
||||
return false;
|
||||
}
|
||||
|
||||
double getLength() const override;
|
||||
|
||||
void setVisible(bool v) override;
|
||||
|
||||
bool setSelected(bool select=true) override;
|
||||
bool toggleSelected() override;
|
||||
|
||||
virtual void selectWindow(RS_Vector v1, RS_Vector v2,
|
||||
bool select=true, bool cross=false);
|
||||
|
||||
virtual void addEntity(RS_Entity* entity);
|
||||
virtual void appendEntity(RS_Entity* entity);
|
||||
virtual void prependEntity(RS_Entity* entity);
|
||||
virtual void moveEntity(int index, QList<RS_Entity *>& entList);
|
||||
virtual void insertEntity(int index, RS_Entity* entity);
|
||||
virtual bool removeEntity(RS_Entity* entity);
|
||||
|
||||
//!
|
||||
//! \brief addRectangle add four lines to form a rectangle by
|
||||
//! the diagonal vertices v0,v1
|
||||
//! \param v0,v1 diagonal vertices of the rectangle
|
||||
//!
|
||||
void addRectangle(RS_Vector const& v0, RS_Vector const& v1);
|
||||
|
||||
virtual RS_Entity* firstEntity(RS2::ResolveLevel level=RS2::ResolveNone);
|
||||
virtual RS_Entity* lastEntity(RS2::ResolveLevel level=RS2::ResolveNone);
|
||||
virtual RS_Entity* nextEntity(RS2::ResolveLevel level=RS2::ResolveNone);
|
||||
virtual RS_Entity* prevEntity(RS2::ResolveLevel level=RS2::ResolveNone);
|
||||
virtual RS_Entity* entityAt(int index);
|
||||
virtual void setEntityAt(int index,RS_Entity* en);
|
||||
//RLZ unused virtual int entityAt();
|
||||
virtual int findEntity(RS_Entity const* const entity);
|
||||
virtual void clear();
|
||||
|
||||
//virtual unsigned long int count() {
|
||||
// return count(false);
|
||||
//}
|
||||
virtual bool isEmpty() const{
|
||||
return count()==0;
|
||||
}
|
||||
unsigned count() const override;
|
||||
unsigned countDeep() const override;
|
||||
//virtual unsigned long int countLayerEntities(RS_Layer* layer);
|
||||
/** \brief countSelected number of selected
|
||||
* @param deep count sub-containers, if true
|
||||
* @param types if is not empty, only counts by types listed
|
||||
*/
|
||||
virtual unsigned countSelected(bool deep=true, std::initializer_list<RS2::EntityType> const& types = {});
|
||||
virtual double totalSelectedLength();
|
||||
|
||||
/**
|
||||
* Enables / disables automatic update of borders on entity removals
|
||||
* and additions. By default this is turned on.
|
||||
*/
|
||||
virtual void setAutoUpdateBorders(bool enable) {
|
||||
autoUpdateBorders = enable;
|
||||
}
|
||||
virtual void adjustBorders(RS_Entity* entity);
|
||||
void calculateBorders() override;
|
||||
void forcedCalculateBorders();
|
||||
void updateDimensions( bool autoText=true);
|
||||
virtual void updateInserts();
|
||||
virtual void updateSplines();
|
||||
void update() override;
|
||||
virtual void renameInserts(const QString& oldName,
|
||||
const QString& newName);
|
||||
|
||||
RS_Vector getNearestEndpoint(const RS_Vector& coord,
|
||||
double* dist = nullptr)const override;
|
||||
RS_Vector getNearestEndpoint(const RS_Vector& coord,
|
||||
double* dist, RS_Entity** pEntity ) const;
|
||||
|
||||
RS_Entity* getNearestEntity(const RS_Vector& point,
|
||||
double* dist = nullptr,
|
||||
RS2::ResolveLevel level=RS2::ResolveAll) const;
|
||||
|
||||
RS_Vector getNearestPointOnEntity(const RS_Vector& coord,
|
||||
bool onEntity = true,
|
||||
double* dist = nullptr,
|
||||
RS_Entity** entity=nullptr)const override;
|
||||
|
||||
RS_Vector getNearestCenter(const RS_Vector& coord,
|
||||
double* dist = nullptr)const override;
|
||||
RS_Vector getNearestMiddle(const RS_Vector& coord,
|
||||
double* dist = nullptr,
|
||||
int middlePoints = 1
|
||||
)const override;
|
||||
RS_Vector getNearestDist(double distance,
|
||||
const RS_Vector& coord,
|
||||
double* dist = nullptr) const override;
|
||||
RS_Vector getNearestIntersection(const RS_Vector& coord,
|
||||
double* dist = nullptr);
|
||||
RS_Vector getNearestVirtualIntersection(const RS_Vector& coord,
|
||||
const double& angle,
|
||||
double* dist);
|
||||
RS_Vector getNearestRef(const RS_Vector& coord,
|
||||
double* dist = nullptr) const override;
|
||||
RS_Vector getNearestSelectedRef(const RS_Vector& coord,
|
||||
double* dist = nullptr) const override;
|
||||
|
||||
double getDistanceToPoint(const RS_Vector& coord,
|
||||
RS_Entity** entity,
|
||||
RS2::ResolveLevel level=RS2::ResolveNone,
|
||||
double solidDist = RS_MAXDOUBLE) const override;
|
||||
|
||||
virtual bool optimizeContours();
|
||||
|
||||
bool hasEndpointsWithinWindow(const RS_Vector& v1, const RS_Vector& v2) override;
|
||||
|
||||
void move(const RS_Vector& offset) override;
|
||||
void rotate(const RS_Vector& center, const double& angle) override;
|
||||
void rotate(const RS_Vector& center, const RS_Vector& angleVector) override;
|
||||
void scale(const RS_Vector& center, const RS_Vector& factor) override;
|
||||
void mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2a) override;
|
||||
|
||||
void stretch(const RS_Vector& firstCorner,
|
||||
const RS_Vector& secondCorner,
|
||||
const RS_Vector& offset) override;
|
||||
void moveRef(const RS_Vector& ref, const RS_Vector& offset) override;
|
||||
void moveSelectedRef(const RS_Vector& ref, const RS_Vector& offset) override;
|
||||
void revertDirection() override;
|
||||
|
||||
|
||||
void draw(RS_Painter* painter, RS_GraphicView* view, double& patternOffset) override;
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os, RS_EntityContainer& ec);
|
||||
|
||||
bool isOwner() const {return autoDelete;}
|
||||
void setOwner(bool owner) {autoDelete=owner;}
|
||||
/**
|
||||
* @brief areaLineIntegral, line integral for contour area calculation by Green's Theorem
|
||||
* Contour Area =\oint x dy
|
||||
* @return line integral \oint x dy along the entity
|
||||
* returns absolute value
|
||||
*/
|
||||
virtual double areaLineIntegral() const override;
|
||||
/**
|
||||
* @brief ignoreForModification ignore this entity for entity catch for certain actions
|
||||
* like catching circles to create tangent circles
|
||||
* @return, true, indicate this entity container should be ignored
|
||||
*/
|
||||
bool ignoredOnModification() const;
|
||||
|
||||
/**
|
||||
* @brief begin/end to support range based loop
|
||||
* @return iterator
|
||||
*/
|
||||
QList<RS_Entity *>::const_iterator begin() const;
|
||||
QList<RS_Entity *>::const_iterator end() const;
|
||||
QList<RS_Entity *>::iterator begin() ;
|
||||
QList<RS_Entity *>::iterator end() ;
|
||||
//! \{
|
||||
//! first and last without resolving into children, assume the container is
|
||||
//! not empty
|
||||
RS_Entity* last() const;
|
||||
RS_Entity* first() const;
|
||||
//! \}
|
||||
|
||||
const QList<RS_Entity*>& getEntityList();
|
||||
|
||||
protected:
|
||||
|
||||
/** entities in the container */
|
||||
QList<RS_Entity *> entities;
|
||||
|
||||
/** sub container used only temporarily for iteration. */
|
||||
RS_EntityContainer* subContainer;
|
||||
|
||||
/**
|
||||
* Automatically update the borders of the container when entities
|
||||
* are added or removed.
|
||||
*/
|
||||
static bool autoUpdateBorders;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief ignoredSnap whether snapping is ignored
|
||||
* @return true when entity of this container won't be considered for snapping points
|
||||
*/
|
||||
bool ignoredSnap() const;
|
||||
int entIdx;
|
||||
bool autoDelete;
|
||||
};
|
||||
|
||||
#endif
|
||||
64
lib/engine/rs_flags.cpp
Normal file
64
lib/engine/rs_flags.cpp
Normal file
@@ -0,0 +1,64 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2015 Dongxu Li (dongxuli2011@gmail.com)
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
#include "rs_flags.h"
|
||||
|
||||
/** Constructor with initialisation to the given flags. */
|
||||
RS_Flags::RS_Flags(unsigned f):
|
||||
flags(f)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
unsigned RS_Flags::getFlags() const {
|
||||
return flags;
|
||||
}
|
||||
|
||||
void RS_Flags::resetFlags() {
|
||||
flags=0;
|
||||
}
|
||||
|
||||
void RS_Flags::setFlags(unsigned f) {
|
||||
flags=f;
|
||||
}
|
||||
|
||||
void RS_Flags::setFlag(unsigned f) {
|
||||
flags |= f;
|
||||
}
|
||||
|
||||
void RS_Flags::delFlag(unsigned f) {
|
||||
flags &= ~f;
|
||||
}
|
||||
|
||||
void RS_Flags::toggleFlag(unsigned f) {
|
||||
flags ^= f;
|
||||
}
|
||||
|
||||
bool RS_Flags::getFlag(unsigned f) const {
|
||||
return flags&f;
|
||||
}
|
||||
|
||||
60
lib/engine/rs_flags.h
Normal file
60
lib/engine/rs_flags.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
#ifndef RS_FLAGS_H
|
||||
#define RS_FLAGS_H
|
||||
|
||||
/**
|
||||
* Base class for objects which have flags.
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
struct RS_Flags {
|
||||
//! \{Constructor with initialisation to the given flags.
|
||||
//! Default sets all flags to 0
|
||||
RS_Flags(unsigned f = 0);
|
||||
//! \}
|
||||
|
||||
virtual ~RS_Flags() = default;
|
||||
|
||||
unsigned getFlags() const;
|
||||
|
||||
void resetFlags();
|
||||
|
||||
void setFlags(unsigned f);
|
||||
|
||||
void setFlag(unsigned f);
|
||||
|
||||
void delFlag(unsigned f);
|
||||
|
||||
void toggleFlag(unsigned f);
|
||||
|
||||
bool getFlag(unsigned f) const;
|
||||
|
||||
private:
|
||||
unsigned flags = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
463
lib/engine/rs_font.cpp
Normal file
463
lib/engine/rs_font.cpp
Normal file
@@ -0,0 +1,463 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <QTextStream>
|
||||
#include <QTextCodec>
|
||||
|
||||
#include "rs_font.h"
|
||||
#include "rs_arc.h"
|
||||
#include "rs_line.h"
|
||||
#include "rs_polyline.h"
|
||||
#include "rs_fontchar.h"
|
||||
#include "rs_system.h"
|
||||
#include "rs_math.h"
|
||||
#include "rs_debug.h"
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param owner true if the font owns the letters (blocks). Otherwise
|
||||
* the letters will be deleted when the font is deleted.
|
||||
*/
|
||||
RS_Font::RS_Font(const QString& fileName, bool owner)
|
||||
: letterList(owner), fileName(fileName), fileLicense("unknown") {
|
||||
loaded = false;
|
||||
letterSpacing = 3.0;
|
||||
wordSpacing = 6.75;
|
||||
lineSpacingFactor = 1.0;
|
||||
rawLffFontList.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Loads the font into memory.
|
||||
*
|
||||
* @retval true font was already loaded or is loaded now.
|
||||
* @retval false font could not be loaded.
|
||||
*/
|
||||
bool RS_Font::loadFont() {
|
||||
RS_DEBUG->print("RS_Font::loadFont");
|
||||
|
||||
if (loaded) {
|
||||
return true;
|
||||
}
|
||||
|
||||
QString path;
|
||||
|
||||
// Search for the appropriate font if we have only the name of the font:
|
||||
if (!fileName.toLower().contains(".cxf") &&
|
||||
!fileName.toLower().contains(".lff")) {
|
||||
QStringList fonts = RS_SYSTEM->getNewFontList();
|
||||
fonts.append(RS_SYSTEM->getFontList());
|
||||
|
||||
QFileInfo file;
|
||||
for (QStringList::Iterator it = fonts.begin();
|
||||
it!=fonts.end();
|
||||
it++) {
|
||||
|
||||
if (QFileInfo(*it).baseName().toLower()==fileName.toLower()) {
|
||||
path = *it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We have the full path of the font:
|
||||
else {
|
||||
path = fileName;
|
||||
}
|
||||
|
||||
// No font paths found:
|
||||
if (path.isEmpty()) {
|
||||
RS_DEBUG->print(RS_Debug::D_WARNING,
|
||||
"RS_Font::loadFont: No fonts available.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Open cxf file:
|
||||
QFile f(path);
|
||||
if (!f.open(QIODevice::ReadOnly)) {
|
||||
RS_DEBUG->print(RS_Debug::D_WARNING,
|
||||
"RS_Font::loadFont: Cannot open font file: %s",
|
||||
path.toLatin1().data());
|
||||
return false;
|
||||
} else {
|
||||
RS_DEBUG->print("RS_Font::loadFont: "
|
||||
"Successfully opened font file: %s",
|
||||
path.toLatin1().data());
|
||||
}
|
||||
f.close();
|
||||
|
||||
if (path.contains(".cxf"))
|
||||
readCXF(path);
|
||||
if (path.contains(".lff"))
|
||||
readLFF(path);
|
||||
|
||||
RS_Block* bk = letterList.find(QChar(0xfffd));
|
||||
if (!bk) {
|
||||
// create new letter:
|
||||
RS_FontChar* letter = new RS_FontChar(nullptr, QChar(0xfffd), RS_Vector(0.0, 0.0));
|
||||
RS_Polyline* pline = new RS_Polyline(letter, RS_PolylineData());
|
||||
pline->setPen(RS_Pen(RS2::FlagInvalid));
|
||||
pline->setLayer(nullptr);
|
||||
pline->addVertex(RS_Vector(1, 0), 0);
|
||||
pline->addVertex(RS_Vector(0, 2), 0);
|
||||
pline->addVertex(RS_Vector(1, 4), 0);
|
||||
pline->addVertex(RS_Vector(2, 2), 0);
|
||||
pline->addVertex(RS_Vector(1, 0), 0);
|
||||
letter->addEntity(pline);
|
||||
letter->calculateBorders();
|
||||
letterList.add(letter);
|
||||
}
|
||||
|
||||
loaded = true;
|
||||
|
||||
RS_DEBUG->print("RS_Font::loadFont OK");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void RS_Font::readCXF(QString path) {
|
||||
QString line;
|
||||
QFile f(path);
|
||||
f.open(QIODevice::ReadOnly);
|
||||
QTextStream ts(&f);
|
||||
|
||||
// Read line by line until we find a new letter:
|
||||
while (!ts.atEnd()) {
|
||||
line = ts.readLine();
|
||||
|
||||
if (line.isEmpty())
|
||||
continue;
|
||||
|
||||
// Read font settings:
|
||||
if (line.at(0)=='#') {
|
||||
QStringList lst =
|
||||
( line.right(line.length()-1) ).split(':', QString::SkipEmptyParts);
|
||||
QStringList::Iterator it3 = lst.begin();
|
||||
|
||||
// RVT_PORT sometimes it happens that the size is < 2
|
||||
if (lst.size()<2)
|
||||
continue;
|
||||
|
||||
QString identifier = (*it3).trimmed();
|
||||
it3++;
|
||||
QString value = (*it3).trimmed();
|
||||
|
||||
if (identifier.toLower()=="letterspacing") {
|
||||
letterSpacing = value.toDouble();
|
||||
} else if (identifier.toLower()=="wordspacing") {
|
||||
wordSpacing = value.toDouble();
|
||||
} else if (identifier.toLower()=="linespacingfactor") {
|
||||
lineSpacingFactor = value.toDouble();
|
||||
} else if (identifier.toLower()=="author") {
|
||||
authors.append(value);
|
||||
} else if (identifier.toLower()=="name") {
|
||||
names.append(value);
|
||||
} else if (identifier.toLower()=="encoding") {
|
||||
ts.setCodec(QTextCodec::codecForName(value.toLatin1()));
|
||||
encoding = value;
|
||||
}
|
||||
}
|
||||
|
||||
// Add another letter to this font:
|
||||
else if (line.at(0)=='[') {
|
||||
|
||||
// uniode character:
|
||||
QChar ch;
|
||||
|
||||
// read unicode:
|
||||
QRegExp regexp("[0-9A-Fa-f]{4,4}");
|
||||
regexp.indexIn(line);
|
||||
QString cap = regexp.cap();
|
||||
if (!cap.isNull()) {
|
||||
int uCode = cap.toInt(nullptr, 16);
|
||||
ch = QChar(uCode);
|
||||
}
|
||||
|
||||
// read UTF8 (LibreCAD 1 compatibility)
|
||||
else if (line.indexOf(']')>=3) {
|
||||
int i = line.indexOf(']');
|
||||
QString mid = line.mid(1, i-1);
|
||||
ch = QString::fromUtf8(mid.toLatin1()).at(0);
|
||||
}
|
||||
|
||||
// read normal ascii character:
|
||||
else {
|
||||
ch = line.at(1);
|
||||
}
|
||||
|
||||
// create new letter:
|
||||
RS_FontChar* letter =
|
||||
new RS_FontChar(nullptr, ch, RS_Vector(0.0, 0.0));
|
||||
|
||||
// Read entities of this letter:
|
||||
QString coordsStr;
|
||||
QStringList coords;
|
||||
QStringList::Iterator it2;
|
||||
do {
|
||||
line = ts.readLine();
|
||||
|
||||
if (line.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
coordsStr = line.right(line.length()-2);
|
||||
// coords = QStringList::split(',', coordsStr);
|
||||
coords = coordsStr.split(',', QString::SkipEmptyParts);
|
||||
it2 = coords.begin();
|
||||
|
||||
// Line:
|
||||
if (line.at(0)=='L') {
|
||||
double x1 = (*it2++).toDouble();
|
||||
double y1 = (*it2++).toDouble();
|
||||
double x2 = (*it2++).toDouble();
|
||||
double y2 = (*it2).toDouble();
|
||||
|
||||
RS_Line* line = new RS_Line{letter, {{x1, y1}, {x2, y2}}};
|
||||
line->setPen(RS_Pen(RS2::FlagInvalid));
|
||||
line->setLayer(nullptr);
|
||||
letter->addEntity(line);
|
||||
}
|
||||
|
||||
// Arc:
|
||||
else if (line.at(0)=='A') {
|
||||
double cx = (*it2++).toDouble();
|
||||
double cy = (*it2++).toDouble();
|
||||
double r = (*it2++).toDouble();
|
||||
double a1 = RS_Math::deg2rad((*it2++).toDouble());
|
||||
double a2 = RS_Math::deg2rad((*it2).toDouble());
|
||||
bool reversed = (line.at(1)=='R');
|
||||
|
||||
RS_ArcData ad(RS_Vector(cx,cy),
|
||||
r, a1, a2, reversed);
|
||||
RS_Arc* arc = new RS_Arc(letter, ad);
|
||||
arc->setPen(RS_Pen(RS2::FlagInvalid));
|
||||
arc->setLayer(nullptr);
|
||||
letter->addEntity(arc);
|
||||
}
|
||||
} while (!line.isEmpty());
|
||||
|
||||
if (letter->isEmpty()) {
|
||||
delete letter;
|
||||
} else {
|
||||
letter->calculateBorders();
|
||||
letterList.add(letter);
|
||||
}
|
||||
}
|
||||
}
|
||||
f.close();
|
||||
}
|
||||
|
||||
void RS_Font::readLFF(QString path) {
|
||||
QString line;
|
||||
QFile f(path);
|
||||
encoding = "UTF-8";
|
||||
f.open(QIODevice::ReadOnly);
|
||||
QTextStream ts(&f);
|
||||
|
||||
// Read line by line until we find a new letter:
|
||||
while (!ts.atEnd()) {
|
||||
line = ts.readLine();
|
||||
|
||||
if (line.isEmpty())
|
||||
continue;
|
||||
|
||||
// Read font settings:
|
||||
if (line.at(0)=='#') {
|
||||
QStringList lst =line.remove(0,1).split(':', QString::SkipEmptyParts);
|
||||
//if size is < 2 is a comentary not parameter
|
||||
if (lst.size()<2)
|
||||
continue;
|
||||
|
||||
QString identifier = lst.at(0).trimmed();
|
||||
QString value = lst.at(1).trimmed();
|
||||
|
||||
if (identifier.toLower()=="letterspacing") {
|
||||
letterSpacing = value.toDouble();
|
||||
} else if (identifier.toLower()=="wordspacing") {
|
||||
wordSpacing = value.toDouble();
|
||||
} else if (identifier.toLower()=="linespacingfactor") {
|
||||
lineSpacingFactor = value.toDouble();
|
||||
} else if (identifier.toLower()=="author") {
|
||||
authors.append(value);
|
||||
} else if (identifier.toLower()=="name") {
|
||||
names.append(value);
|
||||
} else if (identifier.toLower()=="license") {
|
||||
fileLicense = value;
|
||||
} else if (identifier.toLower()=="encoding") {
|
||||
ts.setCodec(QTextCodec::codecForName(value.toLatin1()));
|
||||
encoding = value;
|
||||
} else if (identifier.toLower()=="created") {
|
||||
fileCreate = value;
|
||||
}
|
||||
}
|
||||
|
||||
// Add another letter to this font:
|
||||
else if (line.at(0)=='[') {
|
||||
|
||||
// uniode character:
|
||||
QChar ch;
|
||||
|
||||
// read unicode:
|
||||
QRegExp regexp("[0-9A-Fa-f]{1,5}");
|
||||
regexp.indexIn(line);
|
||||
QString cap = regexp.cap();
|
||||
if (!cap.isNull()) {
|
||||
int uCode = cap.toInt(nullptr, 16);
|
||||
ch = QChar(uCode);
|
||||
}
|
||||
// only unicode allowed
|
||||
else {
|
||||
RS_DEBUG->print(RS_Debug::D_WARNING,"Ignoring code from LFF font file: %s",qPrintable(line));
|
||||
continue;
|
||||
}
|
||||
|
||||
QStringList fontData;
|
||||
do {
|
||||
line = ts.readLine();
|
||||
if(line.isEmpty()) break;
|
||||
fontData.push_back(line);
|
||||
} while(true);
|
||||
if(fontData.size()>0) {
|
||||
rawLffFontList[QString(ch)]=fontData;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
f.close();
|
||||
}
|
||||
|
||||
void RS_Font::generateAllFonts(){
|
||||
QMap<QString, QStringList>::const_iterator i = rawLffFontList.constBegin();
|
||||
while (i != rawLffFontList.constEnd()) {
|
||||
generateLffFont(i.key());
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
RS_Block* RS_Font::generateLffFont(const QString& ch){
|
||||
if(rawLffFontList.contains(ch) == false ){
|
||||
RS_DEBUG->print("RS_Font::generateLffFont(QChar %s ) : can not find the letter in given lff font file",qPrintable(ch));
|
||||
return nullptr;
|
||||
}
|
||||
// create new letter:
|
||||
RS_FontChar* letter =
|
||||
new RS_FontChar(nullptr, ch, RS_Vector(0.0, 0.0));
|
||||
|
||||
// Read entities of this letter:
|
||||
QStringList vertex;
|
||||
QStringList coords;
|
||||
QStringList fontData=rawLffFontList[ch];
|
||||
QString line;
|
||||
|
||||
while(fontData.isEmpty() == false) {
|
||||
line = fontData.takeFirst();
|
||||
|
||||
if (line.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Defined char:
|
||||
if (line.at(0)=='C') {
|
||||
line.remove(0,1);
|
||||
int uCode = line.toInt(nullptr, 16);
|
||||
QChar ch = QChar(uCode);
|
||||
RS_Block* bk = letterList.find(ch);
|
||||
if (!bk && rawLffFontList.contains(ch)) {
|
||||
generateLffFont(ch);
|
||||
bk = letterList.find(ch);
|
||||
}
|
||||
if (bk) {
|
||||
RS_Entity* bk2 = bk->clone();
|
||||
bk2->setPen(RS_Pen(RS2::FlagInvalid));
|
||||
bk2->setLayer(nullptr);
|
||||
letter->addEntity(bk2);
|
||||
}
|
||||
}
|
||||
//sequence:
|
||||
else {
|
||||
vertex = line.split(';', QString::SkipEmptyParts);
|
||||
//at least is required two vertex
|
||||
if (vertex.size()<2)
|
||||
continue;
|
||||
RS_Polyline* pline = new RS_Polyline(letter, RS_PolylineData());
|
||||
pline->setPen(RS_Pen(RS2::FlagInvalid));
|
||||
pline->setLayer(nullptr);
|
||||
for (int i = 0; i < vertex.size(); ++i) {
|
||||
double x1, y1;
|
||||
double bulge = 0;
|
||||
|
||||
coords = vertex.at(i).split(',', QString::SkipEmptyParts);
|
||||
//at least X,Y is required
|
||||
if (coords.size()<2)
|
||||
continue;
|
||||
x1 = coords.at(0).toDouble();
|
||||
y1 = coords.at(1).toDouble();
|
||||
//check presence of bulge
|
||||
if (coords.size() == 3 && coords.at(2).at(0) == QChar('A')){
|
||||
QString bulgeStr = coords.at(2);
|
||||
bulge = bulgeStr.remove(0,1).toDouble();
|
||||
}
|
||||
pline->setNextBulge(bulge);
|
||||
pline->addVertex(RS_Vector(x1, y1), bulge);
|
||||
}
|
||||
letter->addEntity(pline);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (letter->isEmpty()) {
|
||||
delete letter;
|
||||
return nullptr;
|
||||
} else {
|
||||
letter->calculateBorders();
|
||||
letterList.add(letter);
|
||||
return letter;
|
||||
}
|
||||
}
|
||||
|
||||
RS_Block* RS_Font::findLetter(const QString& name) {
|
||||
RS_Block* ret= letterList.find(name);
|
||||
if (ret) return ret;
|
||||
return generateLffFont(name);
|
||||
|
||||
}
|
||||
/**
|
||||
* Dumps the fonts data to stdout.
|
||||
*/
|
||||
std::ostream& operator << (std::ostream& os, const RS_Font& f) {
|
||||
os << " Font file name: " << f.getFileName().toLatin1().data() << "\n";
|
||||
//<< (RS_BlockList&)f << "\n";
|
||||
return os;
|
||||
}
|
||||
|
||||
160
lib/engine/rs_font.h
Normal file
160
lib/engine/rs_font.h
Normal file
@@ -0,0 +1,160 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_FONT_H
|
||||
#define RS_FONT_H
|
||||
|
||||
#include <iosfwd>
|
||||
#include <QStringList>
|
||||
#include <QMap>
|
||||
#include "rs_blocklist.h"
|
||||
|
||||
/**
|
||||
* Class for representing a font. This is implemented as a RS_Graphic
|
||||
* with a name (the font name) and several blocks, one for each letter
|
||||
* in the font.
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_Font {
|
||||
public:
|
||||
RS_Font(const QString& name, bool owner=true);
|
||||
//RS_Font(const char* name);
|
||||
|
||||
/** @return the fileName of this font. */
|
||||
QString getFileName() const {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
/** @return the fileLicense of this font. */
|
||||
QString getFileLicense() const {
|
||||
return fileLicense;
|
||||
}
|
||||
|
||||
/** @return the creation date of this font. */
|
||||
QString getFileCreate() const {
|
||||
return fileCreate;
|
||||
}
|
||||
|
||||
/** @return the encoding of this font. */
|
||||
QString getEncoding() const {
|
||||
return encoding;
|
||||
}
|
||||
|
||||
/** @return the alternative names of this font. */
|
||||
const QStringList& getNames() const {
|
||||
return names;
|
||||
}
|
||||
|
||||
/** @return the author(s) of this font. */
|
||||
const QStringList& getAuthors() const {
|
||||
return authors;
|
||||
}
|
||||
|
||||
/** @return Default letter spacing for this font */
|
||||
double getLetterSpacing() {
|
||||
return letterSpacing;
|
||||
}
|
||||
|
||||
/** @return Default word spacing for this font */
|
||||
double getWordSpacing() {
|
||||
return wordSpacing;
|
||||
}
|
||||
|
||||
/** @return Default line spacing factor for this font */
|
||||
double getLineSpacingFactor() {
|
||||
return lineSpacingFactor;
|
||||
}
|
||||
|
||||
bool loadFont();
|
||||
|
||||
void generateAllFonts();
|
||||
|
||||
// Wrappers for block list (letters) functions
|
||||
RS_BlockList* getLetterList() {
|
||||
return &letterList;
|
||||
}
|
||||
RS_Block* findLetter(const QString& name);
|
||||
// RS_Block* findLetter(const QString& name) {
|
||||
// return letterList.find(name);
|
||||
// }
|
||||
unsigned countLetters() {
|
||||
return letterList.count();
|
||||
}
|
||||
RS_Block* letterAt(unsigned i) {
|
||||
return letterList.at(i);
|
||||
}
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os, const RS_Font& l);
|
||||
|
||||
friend class RS_FontList;
|
||||
|
||||
private:
|
||||
void readCXF(QString path);
|
||||
void readLFF(QString path);
|
||||
RS_Block* generateLffFont(const QString& ch);
|
||||
|
||||
private:
|
||||
//raw lff font file list, not processed into blocks yet
|
||||
QMap<QString, QStringList> rawLffFontList;
|
||||
|
||||
//! block list (letters)
|
||||
RS_BlockList letterList;
|
||||
|
||||
//! Font file name
|
||||
QString fileName;
|
||||
|
||||
//! Font file license
|
||||
QString fileLicense;
|
||||
|
||||
//! Font file license
|
||||
QString fileCreate;
|
||||
|
||||
//! Font encoding (see docu for QTextCodec)
|
||||
QString encoding;
|
||||
|
||||
//! Font names
|
||||
QStringList names;
|
||||
|
||||
//! Authors
|
||||
QStringList authors;
|
||||
|
||||
//! Is this font currently loaded into memory?
|
||||
bool loaded;
|
||||
|
||||
//! Default letter spacing for this font
|
||||
double letterSpacing;
|
||||
|
||||
//! Default word spacing for this font
|
||||
double wordSpacing;
|
||||
|
||||
//! Default line spacing factor for this font
|
||||
double lineSpacingFactor;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
71
lib/engine/rs_fontchar.h
Normal file
71
lib/engine/rs_fontchar.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_FONTCHAR_H
|
||||
#define RS_FONTCHAR_H
|
||||
|
||||
#include "rs_block.h"
|
||||
|
||||
|
||||
/**
|
||||
* A character in a font is represented by this special block class.
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_FontChar : public RS_Block {
|
||||
public:
|
||||
/**
|
||||
* @param parent The font this block belongs to.
|
||||
* @param name The name of the letter (a unicode char) used as
|
||||
* an identifier.
|
||||
* @param basePoint Base point (offset) of the letter (usually 0/0).
|
||||
*/
|
||||
RS_FontChar(RS_EntityContainer* parent,
|
||||
const QString& name,
|
||||
RS_Vector basePoint)
|
||||
: RS_Block(parent, RS_BlockData(name, basePoint, false)) {}
|
||||
|
||||
virtual ~RS_FontChar() {}
|
||||
|
||||
/** @return RS2::EntityFontChar */
|
||||
virtual RS2::EntityType rtti() const {
|
||||
return RS2::EntityFontChar;
|
||||
}
|
||||
|
||||
|
||||
/*friend std::ostream& operator << (std::ostream& os, const RS_FontChar& b) {
|
||||
os << " name: " << b.getName().latin1() << "\n";
|
||||
os << " entities: " << (RS_EntityContainer&)b << "\n";
|
||||
return os;
|
||||
}*/
|
||||
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
142
lib/engine/rs_fontlist.cpp
Normal file
142
lib/engine/rs_fontlist.cpp
Normal file
@@ -0,0 +1,142 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
#include <QHash>
|
||||
#include "rs_fontlist.h"
|
||||
#include "rs_debug.h"
|
||||
#include "rs_font.h"
|
||||
#include "rs_system.h"
|
||||
|
||||
RS_FontList* RS_FontList::uniqueInstance = nullptr;
|
||||
|
||||
RS_FontList* RS_FontList::instance() {
|
||||
if (!uniqueInstance) {
|
||||
uniqueInstance = new RS_FontList();
|
||||
}
|
||||
return uniqueInstance;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the font list by creating empty RS_Font
|
||||
* objects, one for each font that could be found.
|
||||
*/
|
||||
void RS_FontList::init() {
|
||||
RS_DEBUG->print("RS_FontList::initFonts");
|
||||
|
||||
QStringList list = RS_SYSTEM->getNewFontList();
|
||||
list.append(RS_SYSTEM->getFontList());
|
||||
QHash<QString, int> added; //used to remember added fonts (avoid duplication)
|
||||
|
||||
for (int i = 0; i < list.size(); ++i) {
|
||||
RS_DEBUG->print("font: %s:", list.at(i).toLatin1().data());
|
||||
|
||||
QFileInfo fi( list.at(i) );
|
||||
if ( !added.contains(fi.baseName()) ) {
|
||||
fonts.emplace_back(new RS_Font(fi.baseName()));
|
||||
added.insert(fi.baseName(), 1);
|
||||
}
|
||||
|
||||
RS_DEBUG->print("base: %s", fi.baseName().toLatin1().data());
|
||||
}
|
||||
}
|
||||
|
||||
size_t RS_FontList::countFonts() const{
|
||||
return fonts.size();
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<RS_Font> >::const_iterator RS_FontList::begin() const
|
||||
{
|
||||
return fonts.begin();
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<RS_Font> >::const_iterator RS_FontList::end() const
|
||||
{
|
||||
return fonts.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all fonts in the fontlist.
|
||||
*/
|
||||
void RS_FontList::clearFonts() {
|
||||
fonts.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Pointer to the font with the given name or
|
||||
* \p NULL if no such font was found. The font will be loaded into
|
||||
* memory if it's not already.
|
||||
*/
|
||||
RS_Font* RS_FontList::requestFont(const QString& name) {
|
||||
RS_DEBUG->print("RS_FontList::requestFont %s", name.toLatin1().data());
|
||||
|
||||
QString name2 = name.toLower();
|
||||
RS_Font* foundFont = NULL;
|
||||
|
||||
// QCAD 1 compatibility:
|
||||
if (name2.contains('#') && name2.contains('_')) {
|
||||
name2 = name2.left(name2.indexOf('_'));
|
||||
} else if (name2.contains('#')) {
|
||||
name2 = name2.left(name2.indexOf('#'));
|
||||
}
|
||||
|
||||
RS_DEBUG->print("name2: %s", name2.toLatin1().data());
|
||||
|
||||
// Search our list of available fonts:
|
||||
for( auto const& f: fonts){
|
||||
|
||||
if (f->getFileName().toLower() == name2) {
|
||||
// Make sure this font is loaded into memory:
|
||||
f->loadFont();
|
||||
foundFont = f.get();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundFont && name!="standard") {
|
||||
foundFont = requestFont("standard");
|
||||
}
|
||||
|
||||
return foundFont;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps the fonts to stdout.
|
||||
*/
|
||||
std::ostream& operator << (std::ostream& os, RS_FontList& l) {
|
||||
|
||||
os << "Fontlist: \n";
|
||||
for(auto const& f: l.fonts){
|
||||
os << *f << "\n";
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
70
lib/engine/rs_fontlist.h
Normal file
70
lib/engine/rs_fontlist.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
#ifndef RS_FONTLIST_H
|
||||
#define RS_FONTLIST_H
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
class RS_Font;
|
||||
|
||||
#define RS_FONTLIST RS_FontList::instance()
|
||||
|
||||
/**
|
||||
* The global list of fonts. This is implemented as a singleton.
|
||||
* Use RS_FontList::instance() to get a pointer to the object.
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_FontList {
|
||||
|
||||
public:
|
||||
/**
|
||||
* @return Instance to the unique font list.
|
||||
*/
|
||||
static RS_FontList* instance();
|
||||
|
||||
virtual ~RS_FontList() = default;
|
||||
|
||||
void init();
|
||||
|
||||
void clearFonts();
|
||||
size_t countFonts() const;
|
||||
RS_Font* requestFont(const QString& name);
|
||||
std::vector<std::unique_ptr<RS_Font> >::const_iterator begin() const;
|
||||
std::vector<std::unique_ptr<RS_Font> >::const_iterator end() const;
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os, RS_FontList& l);
|
||||
|
||||
private:
|
||||
RS_FontList()=default;
|
||||
RS_FontList(RS_FontList const&)=delete;
|
||||
RS_FontList& operator = (RS_FontList const&)=delete;
|
||||
static RS_FontList* uniqueInstance;
|
||||
//! fonts in the graphic
|
||||
std::vector<std::unique_ptr<RS_Font>> fonts;
|
||||
};
|
||||
|
||||
#endif
|
||||
1047
lib/engine/rs_graphic.cpp
Normal file
1047
lib/engine/rs_graphic.cpp
Normal file
File diff suppressed because it is too large
Load Diff
383
lib/engine/rs_graphic.h
Normal file
383
lib/engine/rs_graphic.h
Normal file
@@ -0,0 +1,383 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2015 A. Stebich (librecad@mail.lordofbikes.de)
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_GRAPHIC_H
|
||||
#define RS_GRAPHIC_H
|
||||
|
||||
#include <QDateTime>
|
||||
#include "rs_blocklist.h"
|
||||
#include "rs_layerlist.h"
|
||||
#include "rs_variabledict.h"
|
||||
#include "rs_document.h"
|
||||
#include "rs_units.h"
|
||||
|
||||
class RS_VariableDict;
|
||||
class QG_LayerWidget;
|
||||
|
||||
/**
|
||||
* A graphic document which can contain entities layers and blocks.
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_Graphic : public RS_Document {
|
||||
public:
|
||||
RS_Graphic(RS_EntityContainer* parent=NULL);
|
||||
virtual ~RS_Graphic();
|
||||
|
||||
//virtual RS_Entity* clone() {
|
||||
// return new RS_Graphic(*this);
|
||||
//}
|
||||
|
||||
/** @return RS2::EntityGraphic */
|
||||
virtual RS2::EntityType rtti() const {
|
||||
return RS2::EntityGraphic;
|
||||
}
|
||||
|
||||
virtual unsigned long int countLayerEntities(RS_Layer* layer);
|
||||
|
||||
virtual RS_LayerList* getLayerList() {
|
||||
return &layerList;
|
||||
}
|
||||
virtual RS_BlockList* getBlockList() {
|
||||
return &blockList;
|
||||
}
|
||||
|
||||
virtual void newDoc();
|
||||
virtual bool save(bool isAutoSave = false);
|
||||
virtual bool saveAs(const QString& filename, RS2::FormatType type, bool force = false);
|
||||
virtual bool open(const QString& filename, RS2::FormatType type);
|
||||
bool loadTemplate(const QString &filename, RS2::FormatType type);
|
||||
|
||||
// Wrappers for Layer functions:
|
||||
void clearLayers() {
|
||||
layerList.clear();
|
||||
}
|
||||
unsigned countLayers() const {
|
||||
return layerList.count();
|
||||
}
|
||||
RS_Layer* layerAt(unsigned i) {
|
||||
return layerList.at(i);
|
||||
}
|
||||
void activateLayer(const QString& name) {
|
||||
layerList.activate(name);
|
||||
}
|
||||
void activateLayer(RS_Layer* layer) {
|
||||
layerList.activate(layer);
|
||||
}
|
||||
RS_Layer* getActiveLayer() {
|
||||
return layerList.getActive();
|
||||
}
|
||||
virtual void addLayer(RS_Layer* layer) {
|
||||
layerList.add(layer);
|
||||
}
|
||||
virtual void addEntity(RS_Entity* entity);
|
||||
virtual void removeLayer(RS_Layer* layer);
|
||||
virtual void editLayer(RS_Layer* layer, const RS_Layer& source) {
|
||||
layerList.edit(layer, source);
|
||||
}
|
||||
RS_Layer* findLayer(const QString& name) {
|
||||
return layerList.find(name);
|
||||
}
|
||||
void toggleLayer(const QString& name) {
|
||||
layerList.toggle(name);
|
||||
}
|
||||
void toggleLayer(RS_Layer* layer) {
|
||||
layerList.toggle(layer);
|
||||
}
|
||||
void toggleLayerLock(RS_Layer* layer) {
|
||||
layerList.toggleLock(layer);
|
||||
}
|
||||
void toggleLayerPrint(RS_Layer* layer) {
|
||||
layerList.togglePrint(layer);
|
||||
}
|
||||
void toggleLayerConstruction(RS_Layer* layer) {
|
||||
layerList.toggleConstruction(layer);
|
||||
}
|
||||
void freezeAllLayers(bool freeze) {
|
||||
layerList.freezeAll(freeze);
|
||||
}
|
||||
void lockAllLayers(bool lock) {
|
||||
layerList.lockAll(lock);
|
||||
}
|
||||
|
||||
void addLayerListListener(RS_LayerListListener* listener) {
|
||||
layerList.addListener(listener);
|
||||
}
|
||||
void removeLayerListListener(RS_LayerListListener* listener) {
|
||||
layerList.removeListener(listener);
|
||||
}
|
||||
|
||||
|
||||
// Wrapper for block functions:
|
||||
void clearBlocks() {
|
||||
blockList.clear();
|
||||
}
|
||||
unsigned countBlocks() {
|
||||
return blockList.count();
|
||||
}
|
||||
RS_Block* blockAt(unsigned i) {
|
||||
return blockList.at(i);
|
||||
}
|
||||
void activateBlock(const QString& name) {
|
||||
blockList.activate(name);
|
||||
}
|
||||
void activateBlock(RS_Block* block) {
|
||||
blockList.activate(block);
|
||||
}
|
||||
RS_Block* getActiveBlock() {
|
||||
return blockList.getActive();
|
||||
}
|
||||
virtual bool addBlock(RS_Block* block, bool notify=true) {
|
||||
return blockList.add(block, notify);
|
||||
}
|
||||
virtual void addBlockNotification() {
|
||||
blockList.addNotification();
|
||||
}
|
||||
virtual void removeBlock(RS_Block* block) {
|
||||
blockList.remove(block);
|
||||
}
|
||||
RS_Block* findBlock(const QString& name) {
|
||||
return blockList.find(name);
|
||||
}
|
||||
QString newBlockName() {
|
||||
return blockList.newName();
|
||||
}
|
||||
void toggleBlock(const QString& name) {
|
||||
blockList.toggle(name);
|
||||
}
|
||||
void toggleBlock(RS_Block* block) {
|
||||
blockList.toggle(block);
|
||||
}
|
||||
void freezeAllBlocks(bool freeze) {
|
||||
blockList.freezeAll(freeze);
|
||||
}
|
||||
void addBlockListListener(RS_BlockListListener* listener) {
|
||||
blockList.addListener(listener);
|
||||
}
|
||||
void removeBlockListListener(RS_BlockListListener* listener) {
|
||||
blockList.removeListener(listener);
|
||||
}
|
||||
|
||||
// Wrappers for variable functions:
|
||||
void clearVariables() {
|
||||
variableDict.clear();
|
||||
}
|
||||
int countVariables() {
|
||||
return variableDict.count();
|
||||
}
|
||||
|
||||
void addVariable(const QString& key, const RS_Vector& value, int code) {
|
||||
variableDict.add(key, value, code);
|
||||
}
|
||||
void addVariable(const QString& key, const QString& value, int code) {
|
||||
variableDict.add(key, value, code);
|
||||
}
|
||||
void addVariable(const QString& key, int value, int code) {
|
||||
variableDict.add(key, value, code);
|
||||
}
|
||||
void addVariable(const QString& key, double value, int code) {
|
||||
variableDict.add(key, value, code);
|
||||
}
|
||||
|
||||
RS_Vector getVariableVector(const QString& key, const RS_Vector& def) {
|
||||
return variableDict.getVector(key, def);
|
||||
}
|
||||
QString getVariableString(const QString& key, const QString& def) {
|
||||
return variableDict.getString(key, def);
|
||||
}
|
||||
int getVariableInt(const QString& key, int def) {
|
||||
return variableDict.getInt(key, def);
|
||||
}
|
||||
double getVariableDouble(const QString& key, double def) {
|
||||
return variableDict.getDouble(key, def);
|
||||
}
|
||||
|
||||
void removeVariable(const QString& key) {
|
||||
variableDict.remove(key);
|
||||
}
|
||||
|
||||
QHash<QString, RS_Variable>& getVariableDict() {
|
||||
return variableDict.getVariableDict();
|
||||
}
|
||||
|
||||
RS2::LinearFormat getLinearFormat();
|
||||
RS2::LinearFormat getLinearFormat(int f);
|
||||
int getLinearPrecision();
|
||||
RS2::AngleFormat getAngleFormat();
|
||||
int getAnglePrecision();
|
||||
|
||||
RS_Vector getPaperSize();
|
||||
void setPaperSize(const RS_Vector& s);
|
||||
RS_Vector getPrintAreaSize(bool total=true);
|
||||
|
||||
RS_Vector getPaperInsertionBase();
|
||||
void setPaperInsertionBase(const RS_Vector& p);
|
||||
|
||||
RS2::PaperFormat getPaperFormat(bool* landscape);
|
||||
void setPaperFormat(RS2::PaperFormat f, bool landscape);
|
||||
|
||||
double getPaperScale();
|
||||
void setPaperScale(double s);
|
||||
|
||||
virtual void setUnit(RS2::Unit u);
|
||||
virtual RS2::Unit getUnit();
|
||||
|
||||
bool isGridOn();
|
||||
void setGridOn(bool on);
|
||||
bool isIsometricGrid();
|
||||
void setIsometricGrid(bool on);
|
||||
void setCrosshairType(RS2::CrosshairType chType);
|
||||
RS2::CrosshairType getCrosshairType();
|
||||
|
||||
bool isDraftOn();
|
||||
void setDraftOn(bool on);
|
||||
|
||||
/** Sets the unit of this graphic's dimensions to 'u' */
|
||||
/*virtual void setDimensionUnit(RS2::Unit u) {
|
||||
addVariable("$INSUNITS", (int)u, 70);
|
||||
dimensionUnit = u;
|
||||
}*/
|
||||
|
||||
/** Gets the unit of this graphic's dimension */
|
||||
/*virtual RS2::Unit getDimensionUnit() {
|
||||
return dimensionUnit;
|
||||
}*/
|
||||
|
||||
void centerToPage();
|
||||
bool fitToPage();
|
||||
|
||||
bool isBiggerThanPaper();
|
||||
|
||||
/**
|
||||
* @retval true The document has been modified since it was last saved.
|
||||
* @retval false The document has not been modified since it was last saved.
|
||||
*/
|
||||
virtual bool isModified() const {
|
||||
return modified || layerList.isModified() || blockList.isModified();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the documents modified status to 'm'.
|
||||
*/
|
||||
virtual void setModified(bool m) {
|
||||
modified = m;
|
||||
layerList.setModified(m);
|
||||
blockList.setModified(m);
|
||||
}
|
||||
virtual QDateTime getModifyTime(void){
|
||||
return modifiedTime;
|
||||
}
|
||||
|
||||
//if set to true, will refuse to modify paper scale
|
||||
void setPaperScaleFixed(bool fixed)
|
||||
{
|
||||
paperScaleFixed=fixed;
|
||||
}
|
||||
bool getPaperScaleFixed()
|
||||
{
|
||||
return paperScaleFixed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Paper margins in millimeters
|
||||
*/
|
||||
void setMargins(double left, double top, double right, double bottom)
|
||||
{
|
||||
if (left >= 0.0) marginLeft = left;
|
||||
if (top >= 0.0) marginTop = top;
|
||||
if (right >= 0.0) marginRight = right;
|
||||
if (bottom >= 0.0) marginBottom = bottom;
|
||||
}
|
||||
double getMarginLeft() const
|
||||
{
|
||||
return marginLeft;
|
||||
}
|
||||
double getMarginTop() const
|
||||
{
|
||||
return marginTop;
|
||||
}
|
||||
double getMarginRight() const
|
||||
{
|
||||
return marginRight;
|
||||
}
|
||||
double getMarginBottom() const
|
||||
{
|
||||
return marginBottom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Paper margins in graphic units
|
||||
*/
|
||||
void setMarginsInUnits(double left, double top, double right, double bottom);
|
||||
double getMarginLeftInUnits();
|
||||
double getMarginTopInUnits();
|
||||
double getMarginRightInUnits();
|
||||
double getMarginBottomInUnits();
|
||||
|
||||
/**
|
||||
* Number of pages drawing occupies
|
||||
*/
|
||||
void setPagesNum(int horiz, int vert);
|
||||
void setPagesNum(const QString &horizXvert);
|
||||
int getPagesNumHoriz() {
|
||||
return pagesNumH;
|
||||
}
|
||||
int getPagesNumVert() {
|
||||
return pagesNumV;
|
||||
}
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os, RS_Graphic& g);
|
||||
|
||||
int clean();
|
||||
|
||||
private:
|
||||
|
||||
bool BackupDrawingFile(const QString &filename);
|
||||
QDateTime modifiedTime;
|
||||
QString currentFileName; //keep a copy of filename for the modifiedTime
|
||||
|
||||
RS_LayerList layerList;
|
||||
RS_BlockList blockList;
|
||||
RS_VariableDict variableDict;
|
||||
RS2::CrosshairType crosshairType; //crosshair type used by isometric grid
|
||||
//if set to true, will refuse to modify paper scale
|
||||
bool paperScaleFixed;
|
||||
|
||||
// Paper margins in millimeters
|
||||
double marginLeft;
|
||||
double marginTop;
|
||||
double marginRight;
|
||||
double marginBottom;
|
||||
|
||||
// Number of pages drawing occupies
|
||||
int pagesNumH;
|
||||
int pagesNumV;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
788
lib/engine/rs_hatch.cpp
Normal file
788
lib/engine/rs_hatch.cpp
Normal file
@@ -0,0 +1,788 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
#include <memory>
|
||||
#include <QPainterPath>
|
||||
#include <QBrush>
|
||||
#include <QString>
|
||||
#include "rs_hatch.h"
|
||||
|
||||
#include "rs_arc.h"
|
||||
#include "rs_circle.h"
|
||||
#include "rs_ellipse.h"
|
||||
#include "rs_line.h"
|
||||
#include "rs_graphicview.h"
|
||||
#include "rs_dialogfactory.h"
|
||||
#include "rs_infoarea.h"
|
||||
|
||||
#include "rs_information.h"
|
||||
#include "rs_painter.h"
|
||||
#include "rs_pattern.h"
|
||||
#include "rs_patternlist.h"
|
||||
#include "rs_math.h"
|
||||
#include "rs_debug.h"
|
||||
|
||||
|
||||
RS_HatchData::RS_HatchData(bool _solid,
|
||||
double _scale,
|
||||
double _angle,
|
||||
const QString& _pattern):
|
||||
solid(_solid)
|
||||
,scale(_scale)
|
||||
,angle(_angle)
|
||||
,pattern(_pattern)
|
||||
{
|
||||
//std::cout << "RS_HatchData: " << pattern.latin1() << "\n";
|
||||
}
|
||||
|
||||
std::ostream& operator << (std::ostream& os, const RS_HatchData& td) {
|
||||
os << "(" << td.pattern.toLatin1().data() << ")";
|
||||
return os;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
RS_Hatch::RS_Hatch(RS_EntityContainer* parent,
|
||||
const RS_HatchData& d)
|
||||
: RS_EntityContainer(parent), data(d)
|
||||
{
|
||||
|
||||
hatch = nullptr;
|
||||
updateRunning = false;
|
||||
needOptimization = true;
|
||||
updateError = HATCH_UNDEFINED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Validates the hatch.
|
||||
*/
|
||||
bool RS_Hatch::validate() {
|
||||
bool ret = true;
|
||||
|
||||
// loops:
|
||||
for(auto l: entities){
|
||||
|
||||
if (l->rtti()==RS2::EntityContainer) {
|
||||
RS_EntityContainer* loop = (RS_EntityContainer*)l;
|
||||
|
||||
ret = loop->optimizeContours() && ret;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
RS_Entity* RS_Hatch::clone() const{
|
||||
RS_DEBUG->print(RS_Debug::D_DEBUGGING, "RS_Hatch::clone()");
|
||||
RS_Hatch* t = new RS_Hatch(*this);
|
||||
t->setOwner(isOwner());
|
||||
t->initId();
|
||||
t->detach();
|
||||
t->update();
|
||||
// t->hatch = nullptr;
|
||||
RS_DEBUG->print(RS_Debug::D_DEBUGGING, "RS_Hatch::clone(): OK");
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Number of loops.
|
||||
*/
|
||||
int RS_Hatch::countLoops() const{
|
||||
if (data.solid) {
|
||||
return count();
|
||||
} else {
|
||||
return count() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool RS_Hatch::isContainer() const {
|
||||
return !isSolid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Recalculates the borders of this hatch.
|
||||
*/
|
||||
void RS_Hatch::calculateBorders() {
|
||||
RS_DEBUG->print("RS_Hatch::calculateBorders");
|
||||
|
||||
activateContour(true);
|
||||
|
||||
RS_EntityContainer::calculateBorders();
|
||||
|
||||
RS_DEBUG->print("RS_Hatch::calculateBorders: size: %f,%f",
|
||||
getSize().x, getSize().y);
|
||||
|
||||
activateContour(false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Updates the Hatch. Called when the
|
||||
* hatch or it's data, position, alignment, .. changes.
|
||||
*
|
||||
* Refill hatch with pattern. Move, scale, rotate, trim, etc.
|
||||
*/
|
||||
void RS_Hatch::update() {
|
||||
|
||||
RS_DEBUG->print(RS_Debug::D_DEBUGGING, "RS_Hatch::update");
|
||||
|
||||
updateError = HATCH_OK;
|
||||
if (updateRunning) {
|
||||
RS_DEBUG->print(RS_Debug::D_NOTICE, "RS_Hatch::update: skip hatch in updating process");
|
||||
return;
|
||||
}
|
||||
|
||||
if (updateEnabled==false) {
|
||||
RS_DEBUG->print(RS_Debug::D_NOTICE, "RS_Hatch::update: skip hatch forbidden to update");
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.solid==true) {
|
||||
RS_DEBUG->print(RS_Debug::D_DEBUGGING, "RS_Hatch::update: processing solid hatch");
|
||||
calculateBorders();
|
||||
return;
|
||||
}
|
||||
|
||||
RS_DEBUG->print(RS_Debug::D_DEBUGGING, "RS_Hatch::update: contour has %d loops", count());
|
||||
updateRunning = true;
|
||||
|
||||
// save attributes for the current hatch
|
||||
RS_Layer* hatch_layer = this->getLayer();
|
||||
RS_Pen hatch_pen = this->getPen();
|
||||
|
||||
// delete old hatch:
|
||||
if (hatch) {
|
||||
removeEntity(hatch);
|
||||
hatch = nullptr;
|
||||
}
|
||||
|
||||
if (isUndone()) {
|
||||
RS_DEBUG->print(RS_Debug::D_NOTICE, "RS_Hatch::update: skip undone hatch");
|
||||
updateRunning = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validate()) {
|
||||
RS_DEBUG->print(RS_Debug::D_ERROR, "RS_Hatch::update: invalid contour in hatch found");
|
||||
updateRunning = false;
|
||||
updateError = HATCH_INVALID_CONTOUR;
|
||||
return;
|
||||
}
|
||||
|
||||
// search for pattern
|
||||
RS_DEBUG->print(RS_Debug::D_DEBUGGING, "RS_Hatch::update: requesting pattern");
|
||||
RS_Pattern* pat = RS_PATTERNLIST->requestPattern(data.pattern);
|
||||
if (!pat) {
|
||||
updateRunning = false;
|
||||
RS_DEBUG->print(RS_Debug::D_ERROR, "RS_Hatch::update: requesting pattern: not found");
|
||||
updateError = HATCH_PATTERN_NOT_FOUND;
|
||||
return;
|
||||
} else {
|
||||
RS_DEBUG->print(RS_Debug::D_DEBUGGING, "RS_Hatch::update: requesting pattern: OK");
|
||||
// make a working copy of hatch pattern
|
||||
RS_DEBUG->print(RS_Debug::D_DEBUGGING, "RS_Hatch::update: cloning pattern");
|
||||
pat = (RS_Pattern*)pat->clone();
|
||||
if (pat) {
|
||||
RS_DEBUG->print(RS_Debug::D_DEBUGGING, "RS_Hatch::update: cloning pattern: OK");
|
||||
} else {
|
||||
RS_DEBUG->print(RS_Debug::D_ERROR, "RS_Hatch::update: error while cloning hatch pattern");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// scale pattern
|
||||
RS_DEBUG->print(RS_Debug::D_DEBUGGING, "RS_Hatch::update: scaling pattern");
|
||||
pat->scale(RS_Vector(0.0,0.0), RS_Vector(data.scale, data.scale));
|
||||
pat->calculateBorders();
|
||||
forcedCalculateBorders();
|
||||
RS_DEBUG->print(RS_Debug::D_DEBUGGING, "RS_Hatch::update: scaling pattern: OK");
|
||||
|
||||
// find out how many pattern-instances we need in x/y:
|
||||
int px1, py1, px2, py2;
|
||||
double f;
|
||||
RS_Hatch* copy = (RS_Hatch*)this->clone();
|
||||
copy->rotate(RS_Vector(0.0,0.0), -data.angle);
|
||||
copy->forcedCalculateBorders();
|
||||
|
||||
// create a pattern over the whole contour.
|
||||
RS_Vector pSize = pat->getSize();
|
||||
RS_Vector rot_center=pat->getMin();
|
||||
// RS_Vector cPos = getMin();
|
||||
RS_Vector cSize = getSize();
|
||||
|
||||
RS_DEBUG->print(RS_Debug::D_DEBUGGING, "RS_Hatch::update: pattern size: %f/%f", pSize.x, pSize.y);
|
||||
RS_DEBUG->print(RS_Debug::D_DEBUGGING, "RS_Hatch::update: contour size: %f/%f", cSize.x, cSize.y);
|
||||
|
||||
// check pattern sizes for sanity
|
||||
if (cSize.x<1.0e-6 || cSize.y<1.0e-6 ||
|
||||
pSize.x<1.0e-6 || pSize.y<1.0e-6 ||
|
||||
cSize.x>RS_MAXDOUBLE-1 || cSize.y>RS_MAXDOUBLE-1 ||
|
||||
pSize.x>RS_MAXDOUBLE-1 || pSize.y>RS_MAXDOUBLE-1) {
|
||||
delete pat;
|
||||
delete copy;
|
||||
updateRunning = false;
|
||||
RS_DEBUG->print(RS_Debug::D_ERROR, "RS_Hatch::update: contour size or pattern size too small");
|
||||
updateError = HATCH_TOO_SMALL;
|
||||
return;
|
||||
}
|
||||
// avoid huge memory consumption:
|
||||
else if ( cSize.x* cSize.y/(pSize.x*pSize.y)>1e4) {
|
||||
RS_DEBUG->print(RS_Debug::D_ERROR, "RS_Hatch::update: contour size too large or pattern size too small");
|
||||
delete pat;
|
||||
delete copy;
|
||||
updateError = HATCH_AREA_TOO_BIG;
|
||||
return;
|
||||
}
|
||||
|
||||
// calculate pattern pieces quantity
|
||||
f = copy->getMin().x/pSize.x;
|
||||
px1 = (int)floor(f);
|
||||
f = copy->getMin().y/pSize.y;
|
||||
py1 = (int)floor(f);
|
||||
f = copy->getMax().x/pSize.x;
|
||||
px2 = (int)ceil(f);
|
||||
f = copy->getMax().y/pSize.y;
|
||||
py2 = (int)ceil(f);
|
||||
RS_Vector dvx=RS_Vector(data.angle)*pSize.x;
|
||||
RS_Vector dvy=RS_Vector(data.angle+M_PI*0.5)*pSize.y;
|
||||
pat->rotate(rot_center, data.angle);
|
||||
pat->move(-rot_center);
|
||||
|
||||
RS_EntityContainer tmp; // container for untrimmed lines
|
||||
|
||||
// adding array of patterns to tmp:
|
||||
RS_DEBUG->print(RS_Debug::D_DEBUGGING, "RS_Hatch::update: creating pattern carpet");
|
||||
for (int px=px1; px<px2; px++) {
|
||||
for (int py=py1; py<py2; py++) {
|
||||
for(auto e: *pat){
|
||||
RS_Entity* te=e->clone();
|
||||
te->move(dvx*px + dvy*py);
|
||||
tmp.addEntity(te);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// clean memory
|
||||
delete pat;
|
||||
pat = nullptr;
|
||||
delete copy;
|
||||
copy = nullptr;
|
||||
RS_DEBUG->print(RS_Debug::D_DEBUGGING, "RS_Hatch::update: creating pattern carpet: OK");
|
||||
|
||||
// cut pattern to contour shape
|
||||
RS_DEBUG->print(RS_Debug::D_DEBUGGING, "RS_Hatch::update: cutting pattern carpet");
|
||||
RS_EntityContainer tmp2; // container for small cut lines
|
||||
RS_Line* line = nullptr;
|
||||
RS_Arc* arc = nullptr;
|
||||
RS_Circle* circle = nullptr;
|
||||
RS_Ellipse* ellipse = nullptr;
|
||||
|
||||
for(auto e: tmp) {
|
||||
|
||||
if (!e) {
|
||||
RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Hatch::update: nullptr entity found");
|
||||
continue;
|
||||
}
|
||||
|
||||
line = nullptr;
|
||||
arc = nullptr;
|
||||
circle = nullptr;
|
||||
ellipse = nullptr;
|
||||
|
||||
RS_Vector startPoint;
|
||||
RS_Vector endPoint;
|
||||
RS_Vector center = RS_Vector(false);
|
||||
bool reversed=false;
|
||||
|
||||
switch(e->rtti()) {
|
||||
case RS2::EntityLine:
|
||||
line=static_cast<RS_Line*>(e);
|
||||
startPoint = line->getStartpoint();
|
||||
endPoint = line->getEndpoint();
|
||||
break;
|
||||
case RS2::EntityArc:
|
||||
arc=static_cast<RS_Arc*>(e);
|
||||
startPoint = arc->getStartpoint();
|
||||
endPoint = arc->getEndpoint();
|
||||
center = arc->getCenter();
|
||||
reversed = arc->isReversed();
|
||||
break;
|
||||
case RS2::EntityCircle:
|
||||
circle=static_cast<RS_Circle*>(e);
|
||||
startPoint = circle->getCenter()
|
||||
+ RS_Vector(circle->getRadius(), 0.0);
|
||||
endPoint = startPoint;
|
||||
center = circle->getCenter();
|
||||
break;
|
||||
case RS2::EntityEllipse:
|
||||
ellipse = static_cast<RS_Ellipse*>(e);
|
||||
startPoint = ellipse->getStartpoint();
|
||||
endPoint = ellipse->getEndpoint();
|
||||
center = ellipse->getCenter();
|
||||
reversed = ellipse->isReversed();
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
// getting all intersections of this pattern line with the contour:
|
||||
QList<RS_Vector> is;
|
||||
|
||||
for(auto loop: entities){
|
||||
|
||||
if (loop->isContainer()) {
|
||||
for(auto p: * static_cast<RS_EntityContainer*>(loop)){
|
||||
|
||||
RS_VectorSolutions sol =
|
||||
RS_Information::getIntersection(e, p, true);
|
||||
|
||||
for (const RS_Vector& vp: sol) {
|
||||
if (vp.valid) {
|
||||
is.append(vp);
|
||||
RS_DEBUG->print(RS_Debug::D_DEBUGGING, " pattern line intersection: %f/%f", vp.x, vp.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QList<RS_Vector> is2; //to be filled with sorted intersections
|
||||
is2.append(startPoint);
|
||||
|
||||
// sort the intersection points into is2 (only if there are intersections):
|
||||
if(is.size() == 1) { //only one intersection
|
||||
is2.append(is.first());
|
||||
}
|
||||
else if(is.size() > 1) {
|
||||
RS_Vector sp = startPoint;
|
||||
double sa = center.angleTo(sp);
|
||||
if(ellipse ) sa=ellipse->getEllipseAngle(sp);
|
||||
bool done;
|
||||
double minDist;
|
||||
double dist = 0.0;
|
||||
RS_Vector av;
|
||||
RS_Vector v;
|
||||
RS_Vector last{};
|
||||
do { // very long while(!done) loop
|
||||
done = true;
|
||||
minDist = RS_MAXDOUBLE;
|
||||
av.valid = false;
|
||||
for (int i = 0; i < is.size(); ++i) {
|
||||
v = is.at(i);
|
||||
double a;
|
||||
switch(e->rtti()){
|
||||
case RS2::EntityLine:
|
||||
dist = sp.distanceTo(v);
|
||||
break;
|
||||
case RS2::EntityArc:
|
||||
case RS2::EntityCircle:
|
||||
a = center.angleTo(v);
|
||||
dist = reversed?
|
||||
fmod(sa - a + 2.*M_PI,2.*M_PI):
|
||||
fmod(a - sa + 2.*M_PI,2.*M_PI);
|
||||
break;
|
||||
case RS2::EntityEllipse:
|
||||
a = ellipse->getEllipseAngle(v);
|
||||
dist = reversed?
|
||||
fmod(sa - a + 2.*M_PI,2.*M_PI):
|
||||
fmod(a - sa + 2.*M_PI,2.*M_PI);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (dist<minDist) {
|
||||
minDist = dist;
|
||||
done = false;
|
||||
av = v;
|
||||
}
|
||||
}
|
||||
|
||||
// copy to sorted list, removing double points
|
||||
if (!done && av) {
|
||||
if (last.valid==false || last.distanceTo(av)>RS_TOLERANCE) {
|
||||
is2.append(av);
|
||||
last = av;
|
||||
}
|
||||
is.removeOne(av);
|
||||
|
||||
av.valid = false;
|
||||
}
|
||||
} while(!done);
|
||||
}
|
||||
|
||||
is2.append(endPoint);
|
||||
|
||||
// add small cut lines / arcs to tmp2:
|
||||
for (int i = 1; i < is2.size(); ++i) {
|
||||
auto v1 = is2.at(i-1);
|
||||
auto v2 = is2.at(i);
|
||||
|
||||
|
||||
if (line) {
|
||||
|
||||
tmp2.addEntity(new RS_Line{&tmp2, v1, v2});
|
||||
} else if (arc || circle) {
|
||||
if(fabs(center.angleTo(v2)-center.angleTo(v1)) > RS_TOLERANCE_ANGLE)
|
||||
{//don't create an arc with a too small angle
|
||||
tmp2.addEntity(new RS_Arc(&tmp2,
|
||||
RS_ArcData(center,
|
||||
center.distanceTo(v1),
|
||||
center.angleTo(v1),
|
||||
center.angleTo(v2),
|
||||
reversed)));
|
||||
}
|
||||
}
|
||||
}
|
||||
} // end for very very long for(auto e: tmp) loop
|
||||
|
||||
// updating hatch / adding entities that are inside
|
||||
RS_DEBUG->print(RS_Debug::D_DEBUGGING, "RS_Hatch::update: cutting pattern carpet: OK");
|
||||
|
||||
//RS_EntityContainer* rubbish = new RS_EntityContainer(getGraphic());
|
||||
|
||||
// add the hatch pattern entities
|
||||
hatch = new RS_EntityContainer(this);
|
||||
hatch->setPen(hatch_pen);
|
||||
hatch->setLayer(hatch_layer);
|
||||
hatch->setFlag(RS2::FlagTemp);
|
||||
|
||||
//calculateBorders();
|
||||
for(auto e: tmp2){
|
||||
|
||||
RS_Vector middlePoint;
|
||||
RS_Vector middlePoint2;
|
||||
if (e->rtti()==RS2::EntityLine) {
|
||||
RS_Line* line = static_cast<RS_Line*>(e);
|
||||
middlePoint = line->getMiddlePoint();
|
||||
middlePoint2 = line->getNearestDist(line->getLength()/2.1,
|
||||
line->getStartpoint());
|
||||
} else if (e->rtti()==RS2::EntityArc) {
|
||||
RS_Arc* arc = static_cast<RS_Arc*>(e);
|
||||
middlePoint = arc->getMiddlePoint();
|
||||
middlePoint2 = arc->getNearestDist(arc->getLength()/2.1,
|
||||
arc->getStartpoint());
|
||||
} else {
|
||||
middlePoint = RS_Vector{false};
|
||||
middlePoint2 = RS_Vector{false};
|
||||
}
|
||||
|
||||
if (middlePoint.valid) {
|
||||
bool onContour=false;
|
||||
|
||||
if (RS_Information::isPointInsideContour(
|
||||
middlePoint,
|
||||
this, &onContour) ||
|
||||
RS_Information::isPointInsideContour(middlePoint2, this)) {
|
||||
|
||||
RS_Entity* te = e->clone();
|
||||
te->setPen(hatch_pen);
|
||||
te->setLayer(hatch_layer);
|
||||
te->reparent(hatch);
|
||||
hatch->addEntity(te);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addEntity(hatch);
|
||||
//getGraphic()->addEntity(rubbish);
|
||||
|
||||
forcedCalculateBorders();
|
||||
|
||||
// deactivate contour:
|
||||
activateContour(false);
|
||||
|
||||
updateRunning = false;
|
||||
|
||||
RS_DEBUG->print(RS_Debug::D_DEBUGGING, "RS_Hatch::update: OK");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Activates of deactivates the hatch boundary.
|
||||
*/
|
||||
void RS_Hatch::activateContour(bool on) {
|
||||
RS_DEBUG->print("RS_Hatch::activateContour: %d", (int)on);
|
||||
for(auto e: entities){
|
||||
if (!e->isUndone()) {
|
||||
if (!e->getFlag(RS2::FlagTemp)) {
|
||||
RS_DEBUG->print("RS_Hatch::activateContour: set visible");
|
||||
e->setVisible(on);
|
||||
}
|
||||
else {
|
||||
RS_DEBUG->print("RS_Hatch::activateContour: entity temp");
|
||||
}
|
||||
}
|
||||
else {
|
||||
RS_DEBUG->print("RS_Hatch::activateContour: entity undone");
|
||||
}
|
||||
}
|
||||
RS_DEBUG->print("RS_Hatch::activateContour: OK");
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides drawing of subentities. This is only ever called for solid fills.
|
||||
*/
|
||||
void RS_Hatch::draw(RS_Painter* painter, RS_GraphicView* view, double& /*patternOffset*/) {
|
||||
|
||||
if (!data.solid) {
|
||||
foreach (auto se, entities){
|
||||
|
||||
view->drawEntity(painter,se);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//area of solid fill. Use polygon approximation, except trivial cases
|
||||
QPainterPath path;
|
||||
QList<QPolygon> paClosed;
|
||||
QPolygon pa;
|
||||
|
||||
if (needOptimization==true) {
|
||||
foreach (auto l, entities){
|
||||
|
||||
if (l->rtti()==RS2::EntityContainer) {
|
||||
RS_EntityContainer* loop = (RS_EntityContainer*)l;
|
||||
|
||||
loop->optimizeContours();
|
||||
}
|
||||
}
|
||||
needOptimization = false;
|
||||
}
|
||||
|
||||
foreach (auto l, entities){
|
||||
l->setLayer(getLayer());
|
||||
|
||||
if (l->rtti()==RS2::EntityContainer) {
|
||||
RS_EntityContainer* loop = (RS_EntityContainer*)l;
|
||||
|
||||
// edges:
|
||||
for(auto e: *loop){
|
||||
|
||||
e->setLayer(getLayer());
|
||||
switch (e->rtti()) {
|
||||
case RS2::EntityLine: {
|
||||
QPoint pt1(RS_Math::round(view->toGuiX(e->getStartpoint().x)),
|
||||
RS_Math::round(view->toGuiY(e->getStartpoint().y)));
|
||||
QPoint pt2(RS_Math::round(view->toGuiX(e->getEndpoint().x)),
|
||||
RS_Math::round(view->toGuiY(e->getEndpoint().y)));
|
||||
|
||||
if(!pa.size() || (pa.last() - pt1).manhattanLength() >= 1) {
|
||||
pa << pt1;
|
||||
}
|
||||
pa << pt2;
|
||||
}
|
||||
break;
|
||||
|
||||
case RS2::EntityArc: {
|
||||
QPolygon pa2;
|
||||
RS_Arc* arc=static_cast<RS_Arc*>(e);
|
||||
|
||||
painter->createArc(pa2, view->toGui(arc->getCenter()),
|
||||
view->toGuiDX(arc->getRadius())
|
||||
,arc->getAngle1(),arc->getAngle2(),arc->isReversed());
|
||||
if(pa.size() &&pa2.size()&&(pa.last()-pa2.first()).manhattanLength()<1)
|
||||
pa2.remove(0,1);
|
||||
pa<<pa2;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case RS2::EntityCircle: {
|
||||
RS_Circle* circle = static_cast<RS_Circle*>(e);
|
||||
RS_Vector c=view->toGui(circle->getCenter());
|
||||
double r=view->toGuiDX(circle->getRadius());
|
||||
path.addEllipse(QPoint(c.x,c.y),r,r);
|
||||
}
|
||||
break;
|
||||
case RS2::EntityEllipse:
|
||||
if(static_cast<RS_Ellipse*>(e)->isArc()) {
|
||||
QPolygon pa2;
|
||||
auto ellipse=static_cast<RS_Ellipse*>(e);
|
||||
|
||||
painter->createEllipse(pa2,
|
||||
view->toGui(ellipse->getCenter()),
|
||||
view->toGuiDX(ellipse->getMajorRadius()),
|
||||
view->toGuiDX(ellipse->getMinorRadius()),
|
||||
ellipse->getAngle()
|
||||
,ellipse->getAngle1(),ellipse->getAngle2(),ellipse->isReversed()
|
||||
);
|
||||
|
||||
if(pa.size() && pa2.size()&&(pa.last()-pa2.first()).manhattanLength()<1)
|
||||
pa2.remove(0,1);
|
||||
pa<<pa2;
|
||||
}else{
|
||||
QPolygon pa2;
|
||||
auto ellipse=static_cast<RS_Ellipse*>(e);
|
||||
painter->createEllipse(pa2,
|
||||
view->toGui(ellipse->getCenter()),
|
||||
view->toGuiDX(ellipse->getMajorRadius()),
|
||||
view->toGuiDX(ellipse->getMinorRadius()),
|
||||
ellipse->getAngle(),
|
||||
ellipse->getAngle1(), ellipse->getAngle2(),
|
||||
ellipse->isReversed()
|
||||
);
|
||||
path.addPolygon(pa2);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if( pa.size()>2 && pa.first() == pa.last()) {
|
||||
paClosed<<pa;
|
||||
pa.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if(pa.size()>2){
|
||||
pa<<pa.first();
|
||||
paClosed<<pa;
|
||||
}
|
||||
|
||||
for(auto& p:paClosed){
|
||||
path.addPolygon(p);
|
||||
}
|
||||
|
||||
//bug#474, restore brush after solid fill
|
||||
const QBrush brush(painter->brush());
|
||||
const RS_Pen pen=painter->getPen();
|
||||
painter->setBrush(pen.getColor());
|
||||
painter->disablePen();
|
||||
painter->drawPath(path);
|
||||
painter->setBrush(brush);
|
||||
painter->setPen(pen);
|
||||
}
|
||||
|
||||
//must be called after update()
|
||||
double RS_Hatch::getTotalArea() {
|
||||
|
||||
double totalArea=0.;
|
||||
|
||||
// loops:
|
||||
for(auto l: entities){
|
||||
|
||||
if (l!=hatch && l->rtti()==RS2::EntityContainer) {
|
||||
totalArea += l->areaLineIntegral();
|
||||
}
|
||||
}
|
||||
return totalArea;
|
||||
}
|
||||
|
||||
double RS_Hatch::getDistanceToPoint(
|
||||
const RS_Vector& coord,
|
||||
RS_Entity** entity,
|
||||
RS2::ResolveLevel level,
|
||||
double solidDist) const {
|
||||
|
||||
if (data.solid==true) {
|
||||
if (entity) {
|
||||
*entity = const_cast<RS_Hatch*>(this);
|
||||
}
|
||||
|
||||
bool onContour;
|
||||
if (RS_Information::isPointInsideContour(
|
||||
coord,
|
||||
const_cast<RS_Hatch*>(this), &onContour)) {
|
||||
|
||||
// distance is the snap range:
|
||||
return solidDist;
|
||||
}
|
||||
|
||||
return RS_MAXDOUBLE;
|
||||
} else {
|
||||
return RS_EntityContainer::getDistanceToPoint(coord, entity,
|
||||
level, solidDist);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_Hatch::move(const RS_Vector& offset) {
|
||||
RS_EntityContainer::move(offset);
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_Hatch::rotate(const RS_Vector& center, const double& angle) {
|
||||
RS_EntityContainer::rotate(center, angle);
|
||||
data.angle = RS_Math::correctAngle(data.angle+angle);
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
void RS_Hatch::rotate(const RS_Vector& center, const RS_Vector& angleVector) {
|
||||
RS_EntityContainer::rotate(center, angleVector);
|
||||
data.angle = RS_Math::correctAngle(data.angle+angleVector.angle());
|
||||
update();
|
||||
}
|
||||
|
||||
void RS_Hatch::scale(const RS_Vector& center, const RS_Vector& factor) {
|
||||
RS_EntityContainer::scale(center, factor);
|
||||
data.scale *= factor.x;
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_Hatch::mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) {
|
||||
RS_EntityContainer::mirror(axisPoint1, axisPoint2);
|
||||
double ang = axisPoint1.angleTo(axisPoint2);
|
||||
data.angle = RS_Math::correctAngle(data.angle + ang*2.0);
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
void RS_Hatch::stretch(const RS_Vector& firstCorner,
|
||||
const RS_Vector& secondCorner,
|
||||
const RS_Vector& offset) {
|
||||
|
||||
RS_EntityContainer::stretch(firstCorner, secondCorner, offset);
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Dumps the point's data to stdout.
|
||||
*/
|
||||
std::ostream& operator << (std::ostream& os, const RS_Hatch& p) {
|
||||
os << " Hatch: " << p.getData() << "\n";
|
||||
return os;
|
||||
}
|
||||
175
lib/engine/rs_hatch.h
Normal file
175
lib/engine/rs_hatch.h
Normal file
@@ -0,0 +1,175 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_HATCH_H
|
||||
#define RS_HATCH_H
|
||||
|
||||
#include "rs_entity.h"
|
||||
#include "rs_entitycontainer.h"
|
||||
|
||||
/**
|
||||
* Holds the data that defines a hatch entity.
|
||||
*/
|
||||
struct RS_HatchData {
|
||||
/**
|
||||
* Default constructor. Leaves the data object uninitialized.
|
||||
*/
|
||||
RS_HatchData() = default;
|
||||
~RS_HatchData() = default;
|
||||
|
||||
/**
|
||||
* @param solid true: solid fill, false: pattern.
|
||||
* @param scale Pattern scale or spacing.
|
||||
* @param pattern Pattern name.
|
||||
*/
|
||||
RS_HatchData(bool solid,
|
||||
double scale,
|
||||
double angle,
|
||||
const QString& pattern);
|
||||
|
||||
|
||||
bool solid;
|
||||
double scale;
|
||||
double angle;
|
||||
QString pattern;
|
||||
};
|
||||
|
||||
std::ostream& operator << (std::ostream& os, const RS_HatchData& td);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Class for a hatch entity.
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_Hatch : public RS_EntityContainer {
|
||||
public:
|
||||
enum RS_HatchError { HATCH_UNDEFINED = -1,
|
||||
HATCH_OK,
|
||||
HATCH_INVALID_CONTOUR,
|
||||
HATCH_PATTERN_NOT_FOUND,
|
||||
HATCH_TOO_SMALL,
|
||||
HATCH_AREA_TOO_BIG };
|
||||
|
||||
RS_Hatch() = default;
|
||||
|
||||
RS_Hatch(RS_EntityContainer* parent,
|
||||
const RS_HatchData& d);
|
||||
|
||||
RS_Entity* clone() const override;
|
||||
|
||||
/** @return RS2::EntityHatch */
|
||||
RS2::EntityType rtti() const override{
|
||||
return RS2::EntityHatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true: if this is a hatch with lines (hatch pattern),
|
||||
* false: if this is filled with a solid color.
|
||||
*/
|
||||
bool isContainer() const override;
|
||||
|
||||
/** @return Copy of data that defines the hatch. */
|
||||
RS_HatchData getData() const {
|
||||
return data;
|
||||
}
|
||||
|
||||
bool validate();
|
||||
|
||||
int countLoops() const;
|
||||
|
||||
/** @return true if this is a solid fill. false if it is a pattern hatch. */
|
||||
bool isSolid() const {
|
||||
return data.solid;
|
||||
}
|
||||
void setSolid(bool solid) {
|
||||
data.solid = solid;
|
||||
}
|
||||
|
||||
QString getPattern() {
|
||||
return data.pattern;
|
||||
}
|
||||
void setPattern(const QString& pattern) {
|
||||
data.pattern = pattern;
|
||||
}
|
||||
|
||||
double getScale() {
|
||||
return data.scale;
|
||||
}
|
||||
void setScale(double scale) {
|
||||
data.scale = scale;
|
||||
}
|
||||
|
||||
double getAngle() {
|
||||
return data.angle;
|
||||
}
|
||||
void setAngle(double angle) {
|
||||
data.angle = angle;
|
||||
}
|
||||
double getTotalArea();
|
||||
|
||||
void calculateBorders() override;
|
||||
void update() override;
|
||||
int getUpdateError() {
|
||||
return updateError;
|
||||
}
|
||||
void activateContour(bool on);
|
||||
|
||||
void draw(RS_Painter* painter, RS_GraphicView* view,
|
||||
double& patternOffset) override;
|
||||
|
||||
// double getLength() {
|
||||
// return -1.0;
|
||||
// }
|
||||
|
||||
double getDistanceToPoint(const RS_Vector& coord,
|
||||
RS_Entity** entity = NULL,
|
||||
RS2::ResolveLevel level = RS2::ResolveNone,
|
||||
double solidDist = RS_MAXDOUBLE) const override;
|
||||
|
||||
|
||||
void move(const RS_Vector& offset) override;
|
||||
void rotate(const RS_Vector& center, const double& angle) override;
|
||||
void rotate(const RS_Vector& center, const RS_Vector& angleVector) override;
|
||||
void scale(const RS_Vector& center, const RS_Vector& factor) override;
|
||||
void mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) override;
|
||||
void stretch(const RS_Vector& firstCorner,
|
||||
const RS_Vector& secondCorner,
|
||||
const RS_Vector& offset) override;
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os, const RS_Hatch& p);
|
||||
|
||||
protected:
|
||||
RS_HatchData data;
|
||||
RS_EntityContainer* hatch;
|
||||
bool updateRunning;
|
||||
bool needOptimization;
|
||||
int updateError;
|
||||
};
|
||||
|
||||
#endif
|
||||
418
lib/engine/rs_image.cpp
Normal file
418
lib/engine/rs_image.cpp
Normal file
@@ -0,0 +1,418 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
#include<iostream>
|
||||
#include <QImage>
|
||||
#include "rs_image.h"
|
||||
#include "rs_line.h"
|
||||
#include "rs_settings.h"
|
||||
|
||||
#include "rs_constructionline.h"
|
||||
#include "rs_debug.h"
|
||||
#include "rs_graphicview.h"
|
||||
#include "rs_painterqt.h"
|
||||
#include "rs_math.h"
|
||||
|
||||
RS_ImageData::RS_ImageData(int _handle,
|
||||
const RS_Vector& _insertionPoint,
|
||||
const RS_Vector& _uVector,
|
||||
const RS_Vector& _vVector,
|
||||
const RS_Vector& _size,
|
||||
const QString& _file,
|
||||
int _brightness,
|
||||
int _contrast,
|
||||
int _fade):
|
||||
handle(_handle)
|
||||
, insertionPoint(_insertionPoint)
|
||||
, uVector(_uVector)
|
||||
, vVector(_vVector)
|
||||
, size(_size)
|
||||
, file(_file)
|
||||
, brightness(_brightness)
|
||||
, contrast(_contrast)
|
||||
, fade(_fade)
|
||||
{
|
||||
}
|
||||
|
||||
std::ostream& operator << (std::ostream& os, const RS_ImageData& ld) {
|
||||
os << "(" << ld.insertionPoint << ")";
|
||||
return os;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
RS_Image::RS_Image(RS_EntityContainer* parent,
|
||||
const RS_ImageData& d)
|
||||
:RS_AtomicEntity(parent), data(d) {
|
||||
|
||||
update();
|
||||
calculateBorders();
|
||||
}
|
||||
|
||||
RS_Image::RS_Image(const RS_Image& _image):
|
||||
RS_AtomicEntity(_image.getParent())
|
||||
,data(_image.data)
|
||||
,img(_image.img.get()?new QImage(*_image.img):nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
RS_Image& RS_Image::operator = (const RS_Image& _image)
|
||||
{
|
||||
data=_image.data;
|
||||
if(_image.img.get()){
|
||||
img.reset(new QImage(*_image.img));
|
||||
}else{
|
||||
img.reset();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
RS_Image::RS_Image(RS_Image&& _image):
|
||||
RS_AtomicEntity(_image.getParent())
|
||||
,data(std::move(_image.data))
|
||||
,img(std::move(_image.img))
|
||||
{
|
||||
}
|
||||
|
||||
RS_Image& RS_Image::operator = (RS_Image&& _image)
|
||||
{
|
||||
data=_image.data;
|
||||
img = std::move(_image.img);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
RS_Entity* RS_Image::clone() const {
|
||||
RS_Image* i = new RS_Image(*this);
|
||||
i->setHandle(getHandle());
|
||||
i->initId();
|
||||
i->update();
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
void RS_Image::updateData(RS_Vector size, RS_Vector Uv, RS_Vector Vv) {
|
||||
data.size = size;
|
||||
data.uVector = Uv;
|
||||
data.vVector = Vv;
|
||||
update();
|
||||
calculateBorders();
|
||||
}
|
||||
|
||||
|
||||
void RS_Image::update() {
|
||||
|
||||
RS_DEBUG->print("RS_Image::update");
|
||||
|
||||
// the whole image:
|
||||
//QImage image = QImage(data.file);
|
||||
img.reset(new QImage(data.file));
|
||||
if (!img->isNull()) {
|
||||
data.size = RS_Vector(img->width(), img->height());
|
||||
calculateBorders(); // image update need this.
|
||||
}
|
||||
|
||||
RS_DEBUG->print("RS_Image::update: OK");
|
||||
|
||||
/*
|
||||
// number of small images:
|
||||
nx = image.width()/100;
|
||||
ny = image.height()/100;
|
||||
|
||||
// create small images:
|
||||
img = new QImage*[nx];
|
||||
QPixmap pm;
|
||||
int w,h;
|
||||
for (int x = 0; x<nx; ++x) {
|
||||
img[x] = new QImage[ny];
|
||||
for (int y = 0; y<ny; ++y) {
|
||||
if (x<nx-1) {
|
||||
w = 100;
|
||||
}
|
||||
else {
|
||||
w = image.width()%100;
|
||||
}
|
||||
|
||||
if (y<ny-1) {
|
||||
h = 100;
|
||||
}
|
||||
else {
|
||||
h = image.height()%100;
|
||||
}
|
||||
|
||||
pm = QPixmap(w, h);
|
||||
RS_PainterQt painter(&pm);
|
||||
painter.drawImage(-x*100, -y*100, image);
|
||||
img[x][y] = pm.convertToImage();
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_Image::calculateBorders() {
|
||||
|
||||
RS_VectorSolutions sol = getCorners();
|
||||
minV = RS_Vector::minimum(
|
||||
RS_Vector::minimum(sol.get(0), sol.get(1)),
|
||||
RS_Vector::minimum(sol.get(2), sol.get(3))
|
||||
);
|
||||
maxV = RS_Vector::maximum(
|
||||
RS_Vector::maximum(sol.get(0), sol.get(1)),
|
||||
RS_Vector::maximum(sol.get(2), sol.get(3))
|
||||
);
|
||||
}
|
||||
|
||||
RS_VectorSolutions RS_Image::getCorners() const {
|
||||
RS_VectorSolutions sol(4);
|
||||
|
||||
sol.set(0, data.insertionPoint);
|
||||
sol.set(1,
|
||||
data.insertionPoint + data.uVector*RS_Math::round(data.size.x));
|
||||
sol.set(3,
|
||||
data.insertionPoint + data.vVector*RS_Math::round(data.size.y));
|
||||
sol.set(2, sol.get(3) + data.uVector*RS_Math::round(data.size.x));
|
||||
|
||||
return sol;
|
||||
}
|
||||
|
||||
/**
|
||||
* whether a given point is within image region
|
||||
*@ coord, a point
|
||||
*@ returns true, if the point is within borders of image
|
||||
*/
|
||||
bool RS_Image::containsPoint(const RS_Vector& coord) const{
|
||||
QPolygonF paf;
|
||||
RS_VectorSolutions corners =getCorners();
|
||||
for(const RS_Vector& vp: corners){
|
||||
paf.push_back(QPointF(vp.x, vp.y));
|
||||
}
|
||||
paf.push_back(paf.at(0));
|
||||
return paf.containsPoint(QPointF(coord.x,coord.y),Qt::OddEvenFill);
|
||||
}
|
||||
|
||||
RS_Vector RS_Image::getNearestEndpoint(const RS_Vector& coord,
|
||||
double* dist) const {
|
||||
RS_VectorSolutions corners =getCorners();
|
||||
return corners.getClosest(coord, dist);
|
||||
}
|
||||
|
||||
|
||||
|
||||
RS_Vector RS_Image::getNearestPointOnEntity(const RS_Vector& coord,
|
||||
bool onEntity, double* dist, RS_Entity** entity) const{
|
||||
|
||||
if (entity) {
|
||||
*entity = const_cast<RS_Image*>(this);
|
||||
}
|
||||
|
||||
RS_VectorSolutions const& corners =getCorners();
|
||||
//allow selecting image by clicking within images, bug#3464626
|
||||
if(containsPoint(coord)){
|
||||
//if coord is within image
|
||||
if(dist) *dist=0.;
|
||||
return coord;
|
||||
}
|
||||
RS_VectorSolutions points;
|
||||
for (size_t i=0; i < corners.size(); ++i){
|
||||
size_t const j = (i+1)%corners.size();
|
||||
RS_Line const l{corners.at(i), corners.at(j)};
|
||||
RS_Vector const vp = l.getNearestPointOnEntity(coord, onEntity);
|
||||
points.push_back(vp);
|
||||
}
|
||||
|
||||
return points.getClosest(coord, dist);
|
||||
}
|
||||
|
||||
|
||||
|
||||
RS_Vector RS_Image::getNearestCenter(const RS_Vector& coord,
|
||||
double* dist) const{
|
||||
|
||||
RS_VectorSolutions const& corners{getCorners()};
|
||||
//bug#485, there's no clear reason to ignore snapping to center within an image
|
||||
// if(containsPoint(coord)){
|
||||
// //if coord is within image
|
||||
// if(dist) *dist=0.;
|
||||
// return coord;
|
||||
// }
|
||||
|
||||
RS_VectorSolutions points;
|
||||
for (size_t i=0; i < corners.size(); ++i) {
|
||||
size_t const j = (i+1)%corners.size();
|
||||
points.push_back((corners.get(i) + corners.get(j))*0.5);
|
||||
}
|
||||
points.push_back((corners.get(0) + corners.get(2))*0.5);
|
||||
|
||||
return points.getClosest(coord, dist);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ToDo, implement middlePoints
|
||||
*/
|
||||
RS_Vector RS_Image::getNearestMiddle(const RS_Vector& coord,
|
||||
double* dist,
|
||||
const int /*middlePoints*/) const{
|
||||
return getNearestCenter(coord, dist);
|
||||
}
|
||||
|
||||
|
||||
|
||||
RS_Vector RS_Image::getNearestDist(double distance,
|
||||
const RS_Vector& coord,
|
||||
double* dist) const{
|
||||
|
||||
RS_VectorSolutions const& corners = getCorners();
|
||||
RS_VectorSolutions points;
|
||||
|
||||
for (size_t i = 0; i < corners.size(); ++i){
|
||||
size_t const j = (i+1)%corners.size();
|
||||
RS_Line const l{corners.get(i), corners.get(j)};
|
||||
RS_Vector const& vp = l.getNearestDist(distance, coord, dist);
|
||||
points.push_back(vp);
|
||||
}
|
||||
|
||||
return points.getClosest(coord, dist);
|
||||
}
|
||||
|
||||
|
||||
|
||||
double RS_Image::getDistanceToPoint(const RS_Vector& coord,
|
||||
RS_Entity** entity,
|
||||
RS2::ResolveLevel /*level*/,
|
||||
double /*solidDist*/) const{
|
||||
if (entity) {
|
||||
*entity = const_cast<RS_Image*>(this);
|
||||
}
|
||||
|
||||
RS_VectorSolutions corners = getCorners();
|
||||
|
||||
//allow selecting image by clicking within images, bug#3464626
|
||||
if(containsPoint(coord)){
|
||||
//if coord is on image
|
||||
|
||||
RS_SETTINGS->beginGroup("/Appearance");
|
||||
bool draftMode = (bool)RS_SETTINGS->readNumEntry("/DraftMode", 0);
|
||||
RS_SETTINGS->endGroup();
|
||||
if(!draftMode) return double(0.);
|
||||
}
|
||||
//continue to allow selecting by image edges
|
||||
double minDist = RS_MAXDOUBLE;
|
||||
|
||||
for (size_t i = 0; i < corners.size(); ++i){
|
||||
size_t const j = (i+1)%corners.size();
|
||||
RS_Line const l{corners.get(i), corners.get(j)};
|
||||
double const dist = l.getDistanceToPoint(coord, nullptr);
|
||||
minDist = std::min(minDist, dist);
|
||||
}
|
||||
|
||||
return minDist;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_Image::move(const RS_Vector& offset) {
|
||||
data.insertionPoint.move(offset);
|
||||
moveBorders(offset);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_Image::rotate(const RS_Vector& center, const double& angle) {
|
||||
RS_Vector angleVector(angle);
|
||||
data.insertionPoint.rotate(center, angleVector);
|
||||
data.uVector.rotate(angleVector);
|
||||
data.vVector.rotate(angleVector);
|
||||
calculateBorders();
|
||||
}
|
||||
|
||||
void RS_Image::rotate(const RS_Vector& center, const RS_Vector& angleVector) {
|
||||
data.insertionPoint.rotate(center, angleVector);
|
||||
data.uVector.rotate(angleVector);
|
||||
data.vVector.rotate(angleVector);
|
||||
calculateBorders();
|
||||
}
|
||||
|
||||
|
||||
void RS_Image::scale(const RS_Vector& center, const RS_Vector& factor) {
|
||||
data.insertionPoint.scale(center, factor);
|
||||
data.uVector.scale(factor);
|
||||
data.vVector.scale(factor);
|
||||
scaleBorders(center,factor);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_Image::mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) {
|
||||
data.insertionPoint.mirror(axisPoint1, axisPoint2);
|
||||
RS_Vector vp0(0.,0.);
|
||||
RS_Vector vp1( axisPoint2-axisPoint1 );
|
||||
data.uVector.mirror(vp0,vp1);
|
||||
data.vVector.mirror(vp0,vp1);
|
||||
calculateBorders();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_Image::draw(RS_Painter* painter, RS_GraphicView* view, double& /*patternOffset*/) {
|
||||
if (!(painter && view) || !img.get() || img->isNull())
|
||||
return;
|
||||
|
||||
// erase image:
|
||||
//if (painter->getPen().getColor()==view->getBackground()) {
|
||||
// RS_VectorSolutions sol = getCorners();
|
||||
//
|
||||
//}
|
||||
|
||||
RS_Vector scale{view->toGuiDX(data.uVector.magnitude()),
|
||||
view->toGuiDY(data.vVector.magnitude())};
|
||||
double angle = data.uVector.angle();
|
||||
|
||||
painter->drawImg(*img,
|
||||
view->toGui(data.insertionPoint),
|
||||
angle, scale);
|
||||
|
||||
if (isSelected() && !(view->isPrinting() || view->isPrintPreview())) {
|
||||
RS_VectorSolutions sol = getCorners();
|
||||
for (size_t i = 0; i < sol.size(); ++i){
|
||||
size_t const j = (i+1)%sol.size();
|
||||
painter->drawLine(view->toGui(sol.get(i)), view->toGui(sol.get(j)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Dumps the point's data to stdout.
|
||||
*/
|
||||
std::ostream& operator << (std::ostream& os, const RS_Image& i) {
|
||||
os << " Image: " << i.getData() << "\n";
|
||||
return os;
|
||||
}
|
||||
|
||||
229
lib/engine/rs_image.h
Normal file
229
lib/engine/rs_image.h
Normal file
@@ -0,0 +1,229 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
#ifndef RS_IMAGE_H
|
||||
#define RS_IMAGE_H
|
||||
|
||||
#include <memory>
|
||||
#include "rs_atomicentity.h"
|
||||
|
||||
class QImage;
|
||||
|
||||
/**
|
||||
* Holds the data that defines a line.
|
||||
*/
|
||||
struct RS_ImageData {
|
||||
/**
|
||||
* Default constructor. Leaves the data object uninitialized.
|
||||
*/
|
||||
RS_ImageData() = default;
|
||||
|
||||
RS_ImageData(int handle,
|
||||
const RS_Vector& insertionPoint,
|
||||
const RS_Vector& uVector,
|
||||
const RS_Vector& vVector,
|
||||
const RS_Vector& size,
|
||||
const QString& file,
|
||||
int brightness,
|
||||
int contrast,
|
||||
int fade);
|
||||
|
||||
/** Handle of image definition. */
|
||||
int handle;
|
||||
/** Insertion point. */
|
||||
RS_Vector insertionPoint;
|
||||
/** u vector. Points along visual bottom of image. */
|
||||
RS_Vector uVector;
|
||||
/** v vector. Points along visual left of image. */
|
||||
RS_Vector vVector;
|
||||
/** Image size in pixel. */
|
||||
RS_Vector size;
|
||||
/** Path to image file. */
|
||||
QString file;
|
||||
/** Brightness (0..100, default: 50). */
|
||||
int brightness;
|
||||
/** Contrast (0..100, default: 50). */
|
||||
int contrast;
|
||||
/** Fade (0..100, default: 0). */
|
||||
int fade;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Class for a line entity.
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_Image : public RS_AtomicEntity {
|
||||
public:
|
||||
RS_Image(RS_EntityContainer* parent,
|
||||
const RS_ImageData& d);
|
||||
RS_Image(const RS_Image& _image);
|
||||
RS_Image(RS_Image&& _image);
|
||||
RS_Image& operator = (const RS_Image& _image);
|
||||
RS_Image& operator = (RS_Image&& _image);
|
||||
|
||||
RS_Entity* clone() const override;
|
||||
|
||||
/** @return RS2::EntityImage */
|
||||
RS2::EntityType rtti() const override{
|
||||
return RS2::EntityImage;
|
||||
}
|
||||
|
||||
void update() override;
|
||||
|
||||
/** @return Copy of data that defines the image. */
|
||||
RS_ImageData getData() const {
|
||||
return data;
|
||||
}
|
||||
|
||||
/** @return Insertion point of the entity */
|
||||
RS_Vector getInsertionPoint() const {
|
||||
return data.insertionPoint;
|
||||
}
|
||||
/** Sets the insertion point for the image. */
|
||||
void setInsertionPoint(RS_Vector ip) {
|
||||
data.insertionPoint = ip;
|
||||
calculateBorders();
|
||||
}
|
||||
|
||||
/** Update image data ONLY for plugins. */
|
||||
void updateData(RS_Vector size, RS_Vector Uv, RS_Vector Vv);
|
||||
|
||||
/** @return File name of the image. */
|
||||
QString getFile() const {
|
||||
return data.file;
|
||||
}
|
||||
|
||||
/** Sets the file name of the image. */
|
||||
void setFile(const QString& file) {
|
||||
data.file = file;
|
||||
}
|
||||
|
||||
/** @return u Vector. Points along bottom, 1 pixel long. */
|
||||
RS_Vector getUVector() const {
|
||||
return data.uVector;
|
||||
}
|
||||
/** @return v Vector. Points along left, 1 pixel long. */
|
||||
RS_Vector getVVector() const {
|
||||
return data.vVector;
|
||||
}
|
||||
/** @return Width of image in pixels. */
|
||||
int getWidth() const {
|
||||
return (int)data.size.x;
|
||||
}
|
||||
/** @return Height of image in pixels. */
|
||||
int getHeight() const {
|
||||
return (int)data.size.y;
|
||||
}
|
||||
/** @return Brightness. */
|
||||
int getBrightness() const {
|
||||
return data.brightness;
|
||||
}
|
||||
/** @return Contrast. */
|
||||
int getContrast() const {
|
||||
return data.contrast;
|
||||
}
|
||||
/** @return Fade. */
|
||||
int getFade() const {
|
||||
return data.fade;
|
||||
}
|
||||
/** @return Image definition handle. */
|
||||
int getHandle() const {
|
||||
return data.handle;
|
||||
}
|
||||
/** Sets the image definition handle. */
|
||||
void setHandle(int h) {
|
||||
data.handle = h;
|
||||
}
|
||||
|
||||
|
||||
/** @return The four corners. **/
|
||||
RS_VectorSolutions getCorners() const;
|
||||
|
||||
/**
|
||||
* @return image with in graphic units.
|
||||
*/
|
||||
double getImageWidth() {
|
||||
return data.size.x * data.uVector.magnitude();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return image height in graphic units.
|
||||
*/
|
||||
double getImageHeight() {
|
||||
return data.size.y * data.vVector.magnitude();
|
||||
}
|
||||
|
||||
|
||||
RS_Vector getNearestEndpoint(const RS_Vector& coord,
|
||||
double* dist = NULL)const override;
|
||||
RS_Vector getNearestPointOnEntity(const RS_Vector& coord,
|
||||
bool onEntity=true, double* dist = NULL, RS_Entity** entity=NULL)const override;
|
||||
RS_Vector getNearestCenter(const RS_Vector& coord,
|
||||
double* dist = NULL)const override;
|
||||
RS_Vector getNearestMiddle(const RS_Vector& coord,
|
||||
double* dist = NULL,
|
||||
int middlePoints=1)const override;
|
||||
RS_Vector getNearestDist(double distance,
|
||||
const RS_Vector& coord,
|
||||
double* dist = NULL)const override;
|
||||
double getDistanceToPoint(const RS_Vector& coord,
|
||||
RS_Entity** entity=NULL,
|
||||
RS2::ResolveLevel level=RS2::ResolveNone,
|
||||
double solidDist = RS_MAXDOUBLE) const override;
|
||||
|
||||
// double getLength() const {
|
||||
// return -1.0;
|
||||
// }
|
||||
|
||||
void move(const RS_Vector& offset) override;
|
||||
void rotate(const RS_Vector& center, const double& angle) override;
|
||||
void rotate(const RS_Vector& center, const RS_Vector& angleVector) override;
|
||||
void scale(const RS_Vector& center, const RS_Vector& factor) override;
|
||||
void mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) override;
|
||||
/*void stretch(RS_Vector firstCorner,
|
||||
RS_Vector secondCorner,
|
||||
RS_Vector offset);*/
|
||||
|
||||
void draw(RS_Painter* painter, RS_GraphicView* view, double& patternOffset) override;
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os, const RS_Image& l);
|
||||
|
||||
void calculateBorders() override;
|
||||
|
||||
|
||||
protected:
|
||||
// whether the point is within image
|
||||
bool containsPoint(const RS_Vector& coord) const;
|
||||
RS_ImageData data;
|
||||
std::unique_ptr<QImage> img;
|
||||
//QImage** img;
|
||||
//int nx;
|
||||
//int ny;
|
||||
};
|
||||
|
||||
#endif
|
||||
397
lib/engine/rs_insert.cpp
Normal file
397
lib/engine/rs_insert.cpp
Normal file
@@ -0,0 +1,397 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
#include<iostream>
|
||||
#include<cmath>
|
||||
#include "rs_insert.h"
|
||||
|
||||
#include "rs_arc.h"
|
||||
#include "rs_circle.h"
|
||||
#include "rs_ellipse.h"
|
||||
#include "rs_block.h"
|
||||
#include "rs_graphic.h"
|
||||
#include "rs_layer.h"
|
||||
#include "rs_math.h"
|
||||
#include "rs_debug.h"
|
||||
|
||||
RS_InsertData::RS_InsertData(const QString& _name,
|
||||
RS_Vector _insertionPoint,
|
||||
RS_Vector _scaleFactor,
|
||||
double _angle,
|
||||
int _cols, int _rows, RS_Vector _spacing,
|
||||
RS_BlockList* _blockSource ,
|
||||
RS2::UpdateMode _updateMode ):
|
||||
name(_name)
|
||||
,insertionPoint(_insertionPoint)
|
||||
,scaleFactor(_scaleFactor)
|
||||
,angle(_angle)
|
||||
,cols(_cols)
|
||||
,rows(_rows)
|
||||
,spacing(_spacing)
|
||||
,blockSource(_blockSource)
|
||||
,updateMode(_updateMode)
|
||||
{
|
||||
}
|
||||
|
||||
std::ostream& operator << (std::ostream& os,
|
||||
const RS_InsertData& d) {
|
||||
os << "(" << d.name.toLatin1().data() << ")";
|
||||
return os;
|
||||
}
|
||||
/**
|
||||
* @param parent The graphic this block belongs to.
|
||||
*/
|
||||
RS_Insert::RS_Insert(RS_EntityContainer* parent,
|
||||
const RS_InsertData& d)
|
||||
: RS_EntityContainer(parent), data(d) {
|
||||
|
||||
block = nullptr;
|
||||
|
||||
if (data.updateMode!=RS2::NoUpdate) {
|
||||
update();
|
||||
//calculateBorders();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RS_Entity* RS_Insert::clone() const{
|
||||
RS_Insert* i = new RS_Insert(*this);
|
||||
i->setOwner(isOwner());
|
||||
i->initId();
|
||||
i->detach();
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Updates the entity buffer of this insert entity. This method
|
||||
* needs to be called whenever the block this insert is based on changes.
|
||||
*/
|
||||
void RS_Insert::update() {
|
||||
|
||||
RS_DEBUG->print("RS_Insert::update");
|
||||
RS_DEBUG->print("RS_Insert::update: name: %s", data.name.toLatin1().data());
|
||||
// RS_DEBUG->print("RS_Insert::update: insertionPoint: %f/%f",
|
||||
// data.insertionPoint.x, data.insertionPoint.y);
|
||||
|
||||
if (updateEnabled==false) {
|
||||
return;
|
||||
}
|
||||
|
||||
clear();
|
||||
|
||||
RS_Block* blk = getBlockForInsert();
|
||||
if (!blk) {
|
||||
//return nullptr;
|
||||
RS_DEBUG->print("RS_Insert::update: Block is nullptr");
|
||||
return;
|
||||
}
|
||||
|
||||
if (isUndone()) {
|
||||
RS_DEBUG->print("RS_Insert::update: Insert is in undo list");
|
||||
return;
|
||||
}
|
||||
|
||||
if (fabs(data.scaleFactor.x)<1.0e-6 || fabs(data.scaleFactor.y)<1.0e-6) {
|
||||
RS_DEBUG->print("RS_Insert::update: scale factor is 0");
|
||||
return;
|
||||
}
|
||||
|
||||
RS_Pen tmpPen;
|
||||
|
||||
/*QListIterator<RS_Entity> it = createIterator();
|
||||
RS_Entity* e;
|
||||
while ( (e = it.current()) ) {
|
||||
++it;*/
|
||||
|
||||
RS_DEBUG->print("RS_Insert::update: cols: %d, rows: %d",
|
||||
data.cols, data.rows);
|
||||
RS_DEBUG->print("RS_Insert::update: block has %d entities",
|
||||
blk->count());
|
||||
//int i_en_counts=0;
|
||||
for(auto e: *blk){
|
||||
for (int c=0; c<data.cols; ++c) {
|
||||
// RS_DEBUG->print("RS_Insert::update: col %d", c);
|
||||
for (int r=0; r<data.rows; ++r) {
|
||||
// i_en_counts++;
|
||||
// RS_DEBUG->print("RS_Insert::update: row %d", r);
|
||||
|
||||
if (e->rtti()==RS2::EntityInsert &&
|
||||
data.updateMode!=RS2::PreviewUpdate) {
|
||||
|
||||
// RS_DEBUG->print("RS_Insert::update: updating sub-insert");
|
||||
static_cast<RS_Insert*>(e)->update();
|
||||
}
|
||||
|
||||
// RS_DEBUG->print("RS_Insert::update: cloning entity");
|
||||
|
||||
RS_Entity* ne;
|
||||
if ( (data.scaleFactor.x - data.scaleFactor.y)>1.0e-6) {
|
||||
if (e->rtti()== RS2::EntityArc) {
|
||||
RS_Arc* a= static_cast<RS_Arc*>(e);
|
||||
ne = new RS_Ellipse{this,
|
||||
{a->getCenter(), {a->getRadius(), 0.},
|
||||
1, a->getAngle1(), a->getAngle2(),
|
||||
a->isReversed()}
|
||||
};
|
||||
ne->setLayer(e->getLayer());
|
||||
ne->setPen(e->getPen(false));
|
||||
} else if (e->rtti()== RS2::EntityCircle) {
|
||||
RS_Circle* a= static_cast<RS_Circle*>(e);
|
||||
ne = new RS_Ellipse{this,
|
||||
{ a->getCenter(), {a->getRadius(), 0.}, 1, 0., 2.*M_PI, false}
|
||||
};
|
||||
ne->setLayer(e->getLayer());
|
||||
ne->setPen(e->getPen(false));
|
||||
} else
|
||||
ne = e->clone();
|
||||
} else
|
||||
ne = e->clone();
|
||||
ne->initId();
|
||||
ne->setUpdateEnabled(false);
|
||||
// if entity layer are 0 set to insert layer to allow "1 layer control" bug ID #3602152
|
||||
RS_Layer *l= ne->getLayer();//special fontchar block don't have
|
||||
if (l && ne->getLayer()->getName() == "0")
|
||||
ne->setLayer(this->getLayer());
|
||||
ne->setParent(this);
|
||||
ne->setVisible(getFlag(RS2::FlagVisible));
|
||||
|
||||
// RS_DEBUG->print("RS_Insert::update: transforming entity");
|
||||
|
||||
// Move:
|
||||
// RS_DEBUG->print("RS_Insert::update: move 1");
|
||||
if (fabs(data.scaleFactor.x)>1.0e-6 &&
|
||||
fabs(data.scaleFactor.y)>1.0e-6) {
|
||||
ne->move(data.insertionPoint +
|
||||
RS_Vector(data.spacing.x/data.scaleFactor.x*c,
|
||||
data.spacing.y/data.scaleFactor.y*r));
|
||||
}
|
||||
else {
|
||||
ne->move(data.insertionPoint);
|
||||
}
|
||||
// Move because of block base point:
|
||||
// RS_DEBUG->print("RS_Insert::update: move 2");
|
||||
ne->move(blk->getBasePoint()*-1);
|
||||
// Scale:
|
||||
// RS_DEBUG->print("RS_Insert::update: scale");
|
||||
ne->scale(data.insertionPoint, data.scaleFactor);
|
||||
// Rotate:
|
||||
// RS_DEBUG->print("RS_Insert::update: rotate");
|
||||
ne->rotate(data.insertionPoint, data.angle);
|
||||
// Select:
|
||||
ne->setSelected(isSelected());
|
||||
|
||||
// individual entities can be on indiv. layers
|
||||
tmpPen = ne->getPen(false);
|
||||
|
||||
// color from block (free floating):
|
||||
if (tmpPen.getColor()==RS_Color(RS2::FlagByBlock)) {
|
||||
tmpPen.setColor(getPen().getColor());
|
||||
}
|
||||
|
||||
// line width from block (free floating):
|
||||
if (tmpPen.getWidth()==RS2::WidthByBlock) {
|
||||
tmpPen.setWidth(getPen().getWidth());
|
||||
}
|
||||
|
||||
// line type from block (free floating):
|
||||
if (tmpPen.getLineType()==RS2::LineByBlock) {
|
||||
tmpPen.setLineType(getPen().getLineType());
|
||||
}
|
||||
|
||||
// now that we've evaluated all flags, let's strip them:
|
||||
// TODO: strip all flags (width, line type)
|
||||
//tmpPen.setColor(tmpPen.getColor().stripFlags());
|
||||
|
||||
ne->setPen(tmpPen);
|
||||
|
||||
ne->setUpdateEnabled(true);
|
||||
|
||||
// insert must be updated even in preview mode
|
||||
if (data.updateMode != RS2::PreviewUpdate
|
||||
|| ne->rtti() == RS2::EntityInsert) {
|
||||
//RS_DEBUG->print("RS_Insert::update: updating new entity");
|
||||
ne->update();
|
||||
}
|
||||
|
||||
// RS_DEBUG->print("RS_Insert::update: adding new entity");
|
||||
appendEntity(ne);
|
||||
// std::cout<<"done # of entity: "<<i_en_counts<<std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
calculateBorders();
|
||||
|
||||
RS_DEBUG->print("RS_Insert::update: OK");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return Pointer to the block associated with this Insert or
|
||||
* nullptr if the block couldn't be found. Blocks are requested
|
||||
* from the blockSource if one was supplied and otherwise from
|
||||
* the closest parent graphic.
|
||||
*/
|
||||
RS_Block* RS_Insert::getBlockForInsert() const{
|
||||
RS_Block* blk = nullptr;
|
||||
if (block) {
|
||||
blk=block;
|
||||
return blk;
|
||||
}
|
||||
|
||||
RS_BlockList* blkList;
|
||||
|
||||
if (!data.blockSource) {
|
||||
if (getGraphic()) {
|
||||
blkList = getGraphic()->getBlockList();
|
||||
} else {
|
||||
blkList = nullptr;
|
||||
}
|
||||
} else {
|
||||
blkList = data.blockSource;
|
||||
}
|
||||
|
||||
if (blkList) {
|
||||
blk = blkList->find(data.name);
|
||||
}
|
||||
|
||||
if (blk) {
|
||||
}
|
||||
|
||||
block = blk;
|
||||
|
||||
return blk;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Is this insert visible? (re-implementation from RS_Entity)
|
||||
*
|
||||
* @return true Only if the entity and the block and the layer it is on
|
||||
* are visible.
|
||||
* The Layer might also be nullptr. In that case the layer visibility
|
||||
* is ignored.
|
||||
* The Block might also be nullptr. In that case the block visibility
|
||||
* is ignored.
|
||||
*/
|
||||
bool RS_Insert::isVisible() const
|
||||
{
|
||||
RS_Block* blk = getBlockForInsert();
|
||||
if (blk) {
|
||||
if (blk->isFrozen()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return RS_Entity::isVisible();
|
||||
}
|
||||
|
||||
|
||||
RS_VectorSolutions RS_Insert::getRefPoints() const
|
||||
{
|
||||
return RS_VectorSolutions{data.insertionPoint};
|
||||
}
|
||||
|
||||
|
||||
|
||||
RS_Vector RS_Insert::getNearestRef(const RS_Vector& coord,
|
||||
double* dist) const{
|
||||
|
||||
return getRefPoints().getClosest(coord, dist);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_Insert::move(const RS_Vector& offset) {
|
||||
RS_DEBUG->print("RS_Insert::move: offset: %f/%f",
|
||||
offset.x, offset.y);
|
||||
RS_DEBUG->print("RS_Insert::move1: insertionPoint: %f/%f",
|
||||
data.insertionPoint.x, data.insertionPoint.y);
|
||||
data.insertionPoint.move(offset);
|
||||
RS_DEBUG->print("RS_Insert::move2: insertionPoint: %f/%f",
|
||||
data.insertionPoint.x, data.insertionPoint.y);
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_Insert::rotate(const RS_Vector& center, const double& angle) {
|
||||
RS_DEBUG->print("RS_Insert::rotate1: insertionPoint: %f/%f "
|
||||
"/ center: %f/%f",
|
||||
data.insertionPoint.x, data.insertionPoint.y,
|
||||
center.x, center.y);
|
||||
data.insertionPoint.rotate(center, angle);
|
||||
data.angle = RS_Math::correctAngle(data.angle+angle);
|
||||
RS_DEBUG->print("RS_Insert::rotate2: insertionPoint: %f/%f",
|
||||
data.insertionPoint.x, data.insertionPoint.y);
|
||||
update();
|
||||
}
|
||||
void RS_Insert::rotate(const RS_Vector& center, const RS_Vector& angleVector) {
|
||||
RS_DEBUG->print("RS_Insert::rotate1: insertionPoint: %f/%f "
|
||||
"/ center: %f/%f",
|
||||
data.insertionPoint.x, data.insertionPoint.y,
|
||||
center.x, center.y);
|
||||
data.insertionPoint.rotate(center, angleVector);
|
||||
data.angle = RS_Math::correctAngle(data.angle+angleVector.angle());
|
||||
RS_DEBUG->print("RS_Insert::rotate2: insertionPoint: %f/%f",
|
||||
data.insertionPoint.x, data.insertionPoint.y);
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_Insert::scale(const RS_Vector& center, const RS_Vector& factor) {
|
||||
RS_DEBUG->print("RS_Insert::scale1: insertionPoint: %f/%f",
|
||||
data.insertionPoint.x, data.insertionPoint.y);
|
||||
data.insertionPoint.scale(center, factor);
|
||||
data.scaleFactor.scale(RS_Vector(0.0, 0.0), factor);
|
||||
data.spacing.scale(RS_Vector(0.0, 0.0), factor);
|
||||
RS_DEBUG->print("RS_Insert::scale2: insertionPoint: %f/%f",
|
||||
data.insertionPoint.x, data.insertionPoint.y);
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_Insert::mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) {
|
||||
data.insertionPoint.mirror(axisPoint1, axisPoint2);
|
||||
|
||||
RS_Vector vec = RS_Vector::polar(1.0, data.angle);
|
||||
vec.mirror(RS_Vector(0.0,0.0), axisPoint2-axisPoint1);
|
||||
data.angle = RS_Math::correctAngle(vec.angle()-M_PI);
|
||||
|
||||
data.scaleFactor.x*=-1;
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
std::ostream& operator << (std::ostream& os, const RS_Insert& i) {
|
||||
os << " Insert: " << i.getData() << std::endl;
|
||||
return os;
|
||||
}
|
||||
|
||||
197
lib/engine/rs_insert.h
Normal file
197
lib/engine/rs_insert.h
Normal file
@@ -0,0 +1,197 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_INSERT_H
|
||||
#define RS_INSERT_H
|
||||
|
||||
#include "rs_entitycontainer.h"
|
||||
|
||||
class RS_BlockList;
|
||||
|
||||
/**
|
||||
* Holds the data that defines an insert.
|
||||
*/
|
||||
struct RS_InsertData {
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
RS_InsertData() = default;
|
||||
~RS_InsertData() = default;
|
||||
|
||||
/**
|
||||
* @param name The name of the block used as an identifier.
|
||||
* @param insertionPoint Insertion point of the block.
|
||||
* @param scaleFactor Scale factor in x / y.
|
||||
* @param angle Rotation angle.
|
||||
* @param cols Number of cols if we insert a whole array.
|
||||
* @param rows Number of rows if we insert a whole array.
|
||||
* @param spacing Spacing between rows and cols.
|
||||
* @param blockSource Source for the block to insert if other than parent.
|
||||
* Normally blocks are requested from the entity's parent but the
|
||||
* block can also come from another resource. RS_Text uses that
|
||||
* to share the blocks (letters) from a font.
|
||||
* @param updateMode RS2::Update will update the insert entity instantly
|
||||
* RS2::NoUpdate will not update the insert. You can update
|
||||
* it later manually using the update() method. This is
|
||||
* often the case since you might want to adjust attributes
|
||||
* after creating an insert entity.
|
||||
*/
|
||||
RS_InsertData(const QString& name,
|
||||
RS_Vector insertionPoint,
|
||||
RS_Vector scaleFactor,
|
||||
double angle,
|
||||
int cols, int rows, RS_Vector spacing,
|
||||
RS_BlockList* blockSource = NULL,
|
||||
RS2::UpdateMode updateMode = RS2::Update);
|
||||
|
||||
QString name;
|
||||
RS_Vector insertionPoint;
|
||||
RS_Vector scaleFactor;
|
||||
double angle;
|
||||
int cols, rows;
|
||||
RS_Vector spacing;
|
||||
RS_BlockList* blockSource;
|
||||
RS2::UpdateMode updateMode;
|
||||
};
|
||||
|
||||
std::ostream& operator << (std::ostream& os, const RS_InsertData& d);
|
||||
|
||||
/**
|
||||
* An insert inserts a block into the drawing at a certain location
|
||||
* with certain attributes (angle, scale, ...).
|
||||
* Inserts don't really contain other entities internally. They just
|
||||
* refer to a block. However, to the outside world they act exactly
|
||||
* like EntityContainer.
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_Insert : public RS_EntityContainer {
|
||||
public:
|
||||
RS_Insert(RS_EntityContainer* parent,
|
||||
const RS_InsertData& d);
|
||||
virtual ~RS_Insert() = default;
|
||||
|
||||
virtual RS_Entity* clone() const;
|
||||
|
||||
/** @return RS2::EntityInsert */
|
||||
virtual RS2::EntityType rtti() const {
|
||||
return RS2::EntityInsert;
|
||||
}
|
||||
|
||||
/** @return Copy of data that defines the insert. **/
|
||||
RS_InsertData getData() const {
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reimplementation of reparent. Invalidates block cache pointer.
|
||||
*/
|
||||
virtual void reparent(RS_EntityContainer* parent) {
|
||||
RS_Entity::reparent(parent);
|
||||
block = NULL;
|
||||
}
|
||||
|
||||
RS_Block* getBlockForInsert() const;
|
||||
|
||||
virtual void update();
|
||||
|
||||
QString getName() const {
|
||||
return data.name;
|
||||
}
|
||||
|
||||
void setName(const QString& newName) {
|
||||
data.name = newName;
|
||||
update();
|
||||
}
|
||||
|
||||
RS_Vector getInsertionPoint() const {
|
||||
return data.insertionPoint;
|
||||
}
|
||||
void setInsertionPoint(const RS_Vector& i) {
|
||||
data.insertionPoint = i;
|
||||
}
|
||||
|
||||
RS_Vector getScale() const {
|
||||
return data.scaleFactor;
|
||||
}
|
||||
|
||||
void setScale(const RS_Vector& s) {
|
||||
data.scaleFactor = s;
|
||||
}
|
||||
|
||||
double getAngle() const {
|
||||
return data.angle;
|
||||
}
|
||||
void setAngle(double a) {
|
||||
data.angle = a;
|
||||
}
|
||||
|
||||
int getCols() const {
|
||||
return data.cols;
|
||||
}
|
||||
void setCols(int c) {
|
||||
data.cols = c;
|
||||
}
|
||||
|
||||
int getRows() const {
|
||||
return data.rows;
|
||||
}
|
||||
void setRows(int r) {
|
||||
data.rows = r;
|
||||
}
|
||||
|
||||
RS_Vector getSpacing() const {
|
||||
return data.spacing;
|
||||
}
|
||||
void setSpacing(const RS_Vector& s) {
|
||||
data.spacing = s;
|
||||
}
|
||||
|
||||
virtual bool isVisible() const;
|
||||
|
||||
virtual RS_VectorSolutions getRefPoints() const;
|
||||
virtual RS_Vector getMiddlePoint(void) const{
|
||||
return RS_Vector(false);
|
||||
}
|
||||
virtual RS_Vector getNearestRef(const RS_Vector& coord,
|
||||
double* dist = nullptr) const;
|
||||
|
||||
virtual void move(const RS_Vector& offset);
|
||||
virtual void rotate(const RS_Vector& center, const double& angle);
|
||||
virtual void rotate(const RS_Vector& center, const RS_Vector& angleVector);
|
||||
virtual void scale(const RS_Vector& center, const RS_Vector& factor);
|
||||
virtual void mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2);
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os, const RS_Insert& i);
|
||||
|
||||
protected:
|
||||
RS_InsertData data;
|
||||
mutable RS_Block* block;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
233
lib/engine/rs_layer.cpp
Normal file
233
lib/engine/rs_layer.cpp
Normal file
@@ -0,0 +1,233 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2015 A. Stebich (librecad@mail.lordofbikes.de)
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
#include <QString>
|
||||
#include "rs_layer.h"
|
||||
|
||||
RS_LayerData::RS_LayerData(const QString& name,
|
||||
const RS_Pen& pen,
|
||||
bool frozen,
|
||||
bool locked):
|
||||
name(name)
|
||||
,pen(pen)
|
||||
,frozen(frozen)
|
||||
,locked(locked)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
RS_Layer::RS_Layer(const QString& name):
|
||||
data(name, RS_Pen(Qt::black, RS2::Width00,RS2::SolidLine), false, false)
|
||||
{
|
||||
}
|
||||
|
||||
RS_Layer* RS_Layer::clone() const{
|
||||
return new RS_Layer(*this);
|
||||
}
|
||||
|
||||
/** sets a new name for this layer. */
|
||||
void RS_Layer::setName(const QString& name) {
|
||||
data.name = name;
|
||||
}
|
||||
|
||||
/** @return the name of this layer. */
|
||||
QString RS_Layer::getName() const {
|
||||
return data.name;
|
||||
}
|
||||
|
||||
/** sets the default pen for this layer. */
|
||||
void RS_Layer::setPen(const RS_Pen& pen) {
|
||||
data.pen = pen;
|
||||
}
|
||||
|
||||
/** @return default pen for this layer. */
|
||||
RS_Pen RS_Layer::getPen() const {
|
||||
return data.pen;
|
||||
}
|
||||
|
||||
/**
|
||||
* @retval true if this layer is frozen (invisible)
|
||||
* @retval false if this layer isn't frozen (visible)
|
||||
*/
|
||||
bool RS_Layer::isFrozen() const {
|
||||
return data.frozen;
|
||||
//getFlag(RS2::FlagFrozen);
|
||||
}
|
||||
|
||||
/**
|
||||
* @retval true the layer has been converted already
|
||||
* @retval false the layer still needs to be converted
|
||||
*/
|
||||
bool RS_Layer::isConverted() const {
|
||||
return data.converted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the converted flag
|
||||
*/
|
||||
void RS_Layer::setConverted(bool c) {
|
||||
data.converted = c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the visibility of this layer.
|
||||
* Freezes the layer if it's not frozen, thaws the layer otherwise
|
||||
*/
|
||||
void RS_Layer::toggle() {
|
||||
//toggleFlag(RS2::FlagFrozen);
|
||||
data.frozen = !data.frozen;
|
||||
}
|
||||
|
||||
/**
|
||||
* (De-)freezes this layer.
|
||||
*
|
||||
* @param freeze true: freeze, false: defreeze
|
||||
*/
|
||||
void RS_Layer::freeze(bool freeze) {
|
||||
data.frozen = freeze;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the lock of this layer.
|
||||
*/
|
||||
void RS_Layer::toggleLock() {
|
||||
//toggleFlag(RS2::FlagFrozen);
|
||||
data.locked = !data.locked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles printing of this layer on / off.
|
||||
*/
|
||||
void RS_Layer::togglePrint() {
|
||||
data.print = !data.print;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles construction attribute of this layer on / off.
|
||||
*/
|
||||
void RS_Layer::toggleConstruction() {
|
||||
data.construction = !data.construction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locks/Unlocks this layer.
|
||||
*
|
||||
* @param l true: lock, false: unlock
|
||||
*/
|
||||
void RS_Layer::lock(bool l) {
|
||||
data.locked = l;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the LOCK state of the Layer
|
||||
*/
|
||||
bool RS_Layer::isLocked() const{
|
||||
return data.locked;
|
||||
}
|
||||
|
||||
/**
|
||||
* set visibility of layer in layer list
|
||||
*
|
||||
* @param l true: visible, false: invisible
|
||||
*/
|
||||
void RS_Layer::visibleInLayerList(bool l) {
|
||||
data.visibleInLayerList = l;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the visibility of the Layer in layer list
|
||||
*/
|
||||
bool RS_Layer::isVisibleInLayerList() const{
|
||||
return data.visibleInLayerList;
|
||||
}
|
||||
|
||||
/**
|
||||
* set selection state of the layer in layer list
|
||||
*
|
||||
* @param val true: selected, false: deselected
|
||||
*/
|
||||
void RS_Layer::selectedInLayerList(bool val) {
|
||||
data.selectedInLayerList = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* return selection state of the layer in layer list
|
||||
*/
|
||||
bool RS_Layer::isSelectedInLayerList() const {
|
||||
return data.selectedInLayerList;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the PRINT state of the Layer
|
||||
*
|
||||
* @param print true: print layer, false: don't print layer
|
||||
*/
|
||||
bool RS_Layer::setPrint( const bool print) {
|
||||
return data.print = print;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the PRINT state of the Layer
|
||||
*/
|
||||
bool RS_Layer::isPrint() const{
|
||||
return data.print;
|
||||
}
|
||||
|
||||
/**
|
||||
* whether the layer is a construction layer
|
||||
* The construction layer property is stored
|
||||
* in extended data in the DXF layer table
|
||||
*/
|
||||
bool RS_Layer::isConstruction() const{
|
||||
return data.construction;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the construction attribute for the layer
|
||||
*
|
||||
* @param construction true: infinite lines, false: normal layer
|
||||
*/
|
||||
bool RS_Layer::setConstruction( const bool construction){
|
||||
data.construction = construction;
|
||||
return construction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps the layers data to stdout.
|
||||
*/
|
||||
std::ostream& operator << (std::ostream& os, const RS_Layer& l) {
|
||||
os << " name: " << l.getName().toLatin1().data()
|
||||
<< " pen: " << l.getPen()
|
||||
<< " frozen: " << (int)l.isFrozen()
|
||||
<< " address: " << &l
|
||||
<< std::endl;
|
||||
return os;
|
||||
}
|
||||
|
||||
206
lib/engine/rs_layer.h
Normal file
206
lib/engine/rs_layer.h
Normal file
@@ -0,0 +1,206 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2015 A. Stebich (librecad@mail.lordofbikes.de)
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_LAYER_H
|
||||
#define RS_LAYER_H
|
||||
|
||||
#ifdef __hpux
|
||||
#include <sys/_size_t.h>
|
||||
#endif
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
#include "rs_pen.h"
|
||||
|
||||
class QString;
|
||||
|
||||
/**
|
||||
* Holds the data that defines a layer.
|
||||
*/
|
||||
struct RS_LayerData {
|
||||
RS_LayerData() = default;
|
||||
|
||||
RS_LayerData(const QString& name,
|
||||
const RS_Pen& pen,
|
||||
bool frozen,
|
||||
bool locked);
|
||||
|
||||
QString name; //!< Layer name
|
||||
RS_Pen pen; //!< default pen for this layer
|
||||
bool frozen {false}; //!< Frozen flag
|
||||
bool locked {false}; //!< Locked flag
|
||||
bool print {true}; //!< Print flag
|
||||
bool converted {false}; //!< Converted flag (CAM)
|
||||
bool construction {false}; //!< a construction layer has entities of infinite length
|
||||
//!< and will never be printed out
|
||||
bool visibleInLayerList {true}; //!< visible in layer list
|
||||
bool selectedInLayerList {false}; //!< selected in layer list
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Class for representing a layer
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_Layer {
|
||||
public:
|
||||
explicit RS_Layer(const QString& name);
|
||||
//RS_Layer(const char* name);
|
||||
|
||||
RS_Layer* clone() const;
|
||||
|
||||
/** sets a new name for this layer. */
|
||||
void setName(const QString& name);
|
||||
|
||||
/** @return the name of this layer. */
|
||||
QString getName() const;
|
||||
|
||||
/** sets the default pen for this layer. */
|
||||
void setPen(const RS_Pen& pen);
|
||||
|
||||
/** @return default pen for this layer. */
|
||||
RS_Pen getPen() const;
|
||||
|
||||
/**
|
||||
* @retval true if this layer is frozen (invisible)
|
||||
* @retval false if this layer isn't frozen (visible)
|
||||
*/
|
||||
bool isFrozen() const;
|
||||
|
||||
/**
|
||||
* @retval true the layer has been converted already
|
||||
* @retval false the layer still needs to be converted
|
||||
*/
|
||||
bool isConverted() const;
|
||||
|
||||
/**
|
||||
* Sets the converted flag
|
||||
*/
|
||||
void setConverted(bool c);
|
||||
|
||||
/**
|
||||
* Toggles the visibility of this layer.
|
||||
* Freezes the layer if it's not frozen, thaws the layer otherwise
|
||||
*/
|
||||
void toggle();
|
||||
|
||||
/**
|
||||
* (De-)freezes this layer.
|
||||
*
|
||||
* @param freeze true: freeze, false: defreeze
|
||||
*/
|
||||
void freeze(bool freeze);
|
||||
|
||||
/**
|
||||
* Toggles the lock of this layer.
|
||||
*/
|
||||
void toggleLock();
|
||||
|
||||
/**
|
||||
* Toggles printing of this layer on / off.
|
||||
*/
|
||||
void togglePrint();
|
||||
|
||||
/**
|
||||
* Toggles construction attribute of this layer on / off.
|
||||
*/
|
||||
void toggleConstruction();
|
||||
|
||||
/**
|
||||
* Locks/Unlocks this layer.
|
||||
*
|
||||
* @param l true: lock, false: unlock
|
||||
*/
|
||||
void lock(bool l);
|
||||
|
||||
/**
|
||||
* return the LOCK state of the Layer
|
||||
*/
|
||||
bool isLocked() const;
|
||||
|
||||
/**
|
||||
* set visibility of layer in layer list
|
||||
*
|
||||
* @param l true: visible, false: invisible
|
||||
*/
|
||||
void visibleInLayerList(bool l);
|
||||
|
||||
/**
|
||||
* return the visibility of the Layer in layer list
|
||||
*/
|
||||
bool isVisibleInLayerList() const;
|
||||
|
||||
/**
|
||||
* set selection state of the layer in layer list
|
||||
*
|
||||
* @param val true: selected, false: deselected
|
||||
*/
|
||||
void selectedInLayerList(bool val);
|
||||
|
||||
/**
|
||||
* return selection state of the layer in layer list
|
||||
*/
|
||||
bool isSelectedInLayerList() const;
|
||||
|
||||
/**
|
||||
* set the PRINT state of the Layer
|
||||
*
|
||||
* @param print true: print layer, false: don't print layer
|
||||
*/
|
||||
bool setPrint( const bool print);
|
||||
|
||||
/**
|
||||
* return the PRINT state of the Layer
|
||||
*/
|
||||
bool isPrint() const;
|
||||
|
||||
/**
|
||||
* whether the layer is a construction layer
|
||||
* The construction layer property is stored
|
||||
* in extended data in the DXF layer table
|
||||
*/
|
||||
bool isConstruction() const;
|
||||
|
||||
/**
|
||||
* set the construction attribute for the layer
|
||||
*
|
||||
* @param construction true: infinite lines, false: normal layer
|
||||
*/
|
||||
bool setConstruction( const bool construction);
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os, const RS_Layer& l);
|
||||
|
||||
private:
|
||||
//! Layer data
|
||||
RS_LayerData data;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
496
lib/engine/rs_layerlist.cpp
Normal file
496
lib/engine/rs_layerlist.cpp
Normal file
@@ -0,0 +1,496 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2015 A. Stebich (librecad@mail.lordofbikes.de)
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
#include<iostream>
|
||||
#include "rs_debug.h"
|
||||
#include "rs_layerlist.h"
|
||||
#include "rs_layer.h"
|
||||
#include "rs_layerlistlistener.h"
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
RS_LayerList::RS_LayerList() {
|
||||
activeLayer = NULL;
|
||||
setModified(false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Removes all layers in the layerlist.
|
||||
*/
|
||||
void RS_LayerList::clear() {
|
||||
layers.clear();
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
|
||||
QList<RS_Layer*>::iterator RS_LayerList::begin()
|
||||
{
|
||||
return layers.begin();
|
||||
}
|
||||
|
||||
QList<RS_Layer*>::iterator RS_LayerList::end()
|
||||
{
|
||||
return layers.end();
|
||||
}
|
||||
|
||||
QList<RS_Layer*>::const_iterator RS_LayerList::begin()const
|
||||
{
|
||||
return layers.begin();
|
||||
}
|
||||
|
||||
QList<RS_Layer*>::const_iterator RS_LayerList::end()const
|
||||
{
|
||||
return layers.end();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Activates the given layer.
|
||||
*
|
||||
* @param notify Notify listeners.
|
||||
*/
|
||||
void RS_LayerList::activate(const QString& name, bool notify) {
|
||||
RS_DEBUG->print("RS_LayerList::activate: %s, notify: %d begin",
|
||||
name.toLatin1().data(), notify);
|
||||
|
||||
activate(find(name), notify);
|
||||
/*
|
||||
if (activeLayer==NULL) {
|
||||
RS_DEBUG->print("activeLayer is NULL");
|
||||
} else {
|
||||
RS_DEBUG->print("activeLayer is %s", activeLayer->getName().latin1());
|
||||
}
|
||||
*/
|
||||
|
||||
RS_DEBUG->print("RS_LayerList::activate: %s end", name.toLatin1().data());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Activates the given layer.
|
||||
*
|
||||
* @param notify Notify listeners.
|
||||
*/
|
||||
void RS_LayerList::activate(RS_Layer* layer, bool notify) {
|
||||
RS_DEBUG->print("RS_LayerList::activate notify: %d begin", notify);
|
||||
|
||||
/*if (layer) {
|
||||
RS_DEBUG->print("RS_LayerList::activate: %s",
|
||||
layer->getName().latin1());
|
||||
} else {
|
||||
RS_DEBUG->print("RS_LayerList::activate: NULL");
|
||||
}*/
|
||||
|
||||
activeLayer = layer;
|
||||
|
||||
if (notify) {
|
||||
for (int i=0; i<layerListListeners.size(); ++i) {
|
||||
RS_LayerListListener* l = layerListListeners.at(i);
|
||||
|
||||
l->layerActivated(activeLayer);
|
||||
RS_DEBUG->print("RS_LayerList::activate listener notified");
|
||||
}
|
||||
}
|
||||
|
||||
RS_DEBUG->print("RS_LayerList::activate end");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief sort by layer names
|
||||
*/
|
||||
void RS_LayerList::sort()
|
||||
{
|
||||
std::stable_sort(layers.begin(), layers.end(), [](const RS_Layer* l0, const RS_Layer* l1 )->bool{
|
||||
return l0->getName() < l1->getName();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a layer to the layer list.
|
||||
* If there is already a layer with the same name, no layer is
|
||||
* added. In that case the layer passed to the method will be deleted!
|
||||
* If no layer was active so far, the new layer becomes the active one.
|
||||
*
|
||||
* Listeners are notified.
|
||||
*/
|
||||
void RS_LayerList::add(RS_Layer* layer) {
|
||||
RS_DEBUG->print("RS_LayerList::addLayer()");
|
||||
|
||||
if (layer==NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check if layer already exists:
|
||||
RS_Layer* l = find(layer->getName());
|
||||
if (l==NULL) {
|
||||
layers.append(layer);
|
||||
this->sort();
|
||||
// notify listeners
|
||||
for (int i=0; i<layerListListeners.size(); ++i) {
|
||||
RS_LayerListListener* l = layerListListeners.at(i);
|
||||
l->layerAdded(layer);
|
||||
}
|
||||
setModified(true);
|
||||
|
||||
// if there was no active layer so far, activate this one.
|
||||
if (activeLayer==NULL) {
|
||||
activate(layer);
|
||||
}
|
||||
} else {
|
||||
// if there was no active layer so far, activate this one.
|
||||
if (activeLayer==NULL) {
|
||||
activate(l);
|
||||
}
|
||||
|
||||
l->freeze( layer->isFrozen());
|
||||
l->lock( layer->isLocked());
|
||||
l->setPrint( layer->isPrint());
|
||||
l->setConverted( layer->isConverted());
|
||||
l->setConstruction( layer->isConstruction());
|
||||
l->visibleInLayerList( layer->isVisibleInLayerList());
|
||||
l->setPen(layer->getPen());
|
||||
|
||||
delete layer;
|
||||
layer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Removes a layer from the list.
|
||||
* Listeners are notified after the layer was removed from
|
||||
* the list but before it gets deleted.
|
||||
*/
|
||||
void RS_LayerList::remove(RS_Layer* layer) {
|
||||
RS_DEBUG->print("RS_LayerList::removeLayer()");
|
||||
if (layer==NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// here the layer is removed from the list but not deleted
|
||||
layers.removeOne(layer);
|
||||
|
||||
for (int i=0; i<layerListListeners.size(); ++i) {
|
||||
RS_LayerListListener* l = layerListListeners.at(i);
|
||||
l->layerRemoved(layer);
|
||||
}
|
||||
|
||||
setModified(true);
|
||||
|
||||
// activate an other layer if necessary:
|
||||
if (activeLayer==layer) {
|
||||
activate(layers.first());
|
||||
}
|
||||
|
||||
// now it's save to delete the layer
|
||||
delete layer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Changes a layer's attributes. The attributes of layer 'layer'
|
||||
* are copied from layer 'source'.
|
||||
* Listeners are notified.
|
||||
*/
|
||||
void RS_LayerList::edit(RS_Layer* layer, const RS_Layer& source) {
|
||||
if (layer==NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
*layer = source;
|
||||
|
||||
for (int i=0; i<layerListListeners.size(); ++i) {
|
||||
RS_LayerListListener* l = layerListListeners.at(i);
|
||||
|
||||
l->layerEdited(layer);
|
||||
}
|
||||
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return Pointer to the layer with the given name or
|
||||
* \p NULL if no such layer was found.
|
||||
*/
|
||||
RS_Layer* RS_LayerList::find(const QString& name) {
|
||||
//RS_DEBUG->print("RS_LayerList::find begin");
|
||||
|
||||
RS_Layer* ret = NULL;
|
||||
|
||||
for (int i=0; i<layers.size(); ++i) {
|
||||
RS_Layer* l = layers.at(i);
|
||||
if (l->getName()==name) {
|
||||
ret = l;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//RS_DEBUG->print("RS_LayerList::find end");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return Index of the given layer in the layer list or -1 if the layer
|
||||
* was not found.
|
||||
*/
|
||||
int RS_LayerList::getIndex(const QString& name) {
|
||||
//RS_DEBUG->print("RS_LayerList::find begin");
|
||||
|
||||
int ret = -1;
|
||||
|
||||
for (int i=0; i<layers.size(); i++) {
|
||||
RS_Layer* l = layers.at(i);
|
||||
|
||||
if (l->getName()==name) {
|
||||
ret = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//RS_DEBUG->print("RS_LayerList::find end");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Index of the given layer in the layer list or -1 if the layer
|
||||
* was not found.
|
||||
*/
|
||||
int RS_LayerList::getIndex(RS_Layer* layer) {
|
||||
//RS_DEBUG->print("RS_LayerList::find begin");
|
||||
return layers.indexOf(layer);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Switches on / off the given layer.
|
||||
* Listeners are notified.
|
||||
*/
|
||||
void RS_LayerList::toggle(const QString& name) {
|
||||
toggle(find(name));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Switches on / off the given layer.
|
||||
* Listeners are notified.
|
||||
*/
|
||||
void RS_LayerList::toggle(RS_Layer* layer) {
|
||||
|
||||
if (!layer) {
|
||||
RS_DEBUG->print(RS_Debug::D_ERROR, "RS_LayerList::toggle: nullptr layer");
|
||||
return;
|
||||
}
|
||||
|
||||
// set flags
|
||||
layer->toggle();
|
||||
setModified(true);
|
||||
|
||||
// Notify listeners:
|
||||
for (auto *i : layerListListeners) {
|
||||
|
||||
if (!i) {
|
||||
RS_DEBUG->print(RS_Debug::D_WARNING, "RS_LayerList::toggle: nullptr layer listener");
|
||||
continue;
|
||||
}
|
||||
|
||||
RS_LayerListListener *l = (RS_LayerListListener *)i;
|
||||
l->layerToggled(layer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Locks or unlocks the given layer.
|
||||
* Listeners are notified.
|
||||
*/
|
||||
void RS_LayerList::toggleLock(RS_Layer* layer) {
|
||||
if (layer==NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
layer->toggleLock();
|
||||
setModified(true);
|
||||
|
||||
// Notify listeners:
|
||||
for (int i=0; i<layerListListeners.size(); ++i) {
|
||||
RS_LayerListListener* l = layerListListeners.at(i);
|
||||
l->layerToggledLock(layer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Switch printing for the given layer on / off.
|
||||
* Listeners are notified.
|
||||
*/
|
||||
void RS_LayerList::togglePrint(RS_Layer* layer) {
|
||||
if (layer==NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
layer->togglePrint();
|
||||
setModified(true);
|
||||
|
||||
// Notify listeners:
|
||||
for (int i=0; i<layerListListeners.size(); ++i) {
|
||||
RS_LayerListListener* l = layerListListeners.at(i);
|
||||
l->layerToggledPrint(layer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Switch construction attribute for the given layer on / off.
|
||||
* Listeners are notified.
|
||||
*/
|
||||
void RS_LayerList::toggleConstruction(RS_Layer* layer) {
|
||||
if (layer==NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
layer->toggleConstruction();
|
||||
setModified(true);
|
||||
|
||||
// Notify listeners:
|
||||
for (int i=0; i<layerListListeners.size(); ++i) {
|
||||
RS_LayerListListener* l = layerListListeners.at(i);
|
||||
l->layerToggledConstruction(layer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Freezes or defreezes all layers.
|
||||
*
|
||||
* @param freeze true: freeze, false: defreeze
|
||||
*/
|
||||
void RS_LayerList::freezeAll(bool freeze) {
|
||||
|
||||
for (unsigned l=0; l<count(); l++) {
|
||||
if (at(l)->isVisibleInLayerList()) {
|
||||
at(l)->freeze(freeze);
|
||||
}
|
||||
}
|
||||
setModified(true);
|
||||
|
||||
for (int i=0; i<layerListListeners.size(); ++i) {
|
||||
RS_LayerListListener* l = layerListListeners.at(i);
|
||||
l->layerToggled(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Locks or unlocks all layers.
|
||||
*
|
||||
* @param lock true: lock, false: unlock
|
||||
*/
|
||||
void RS_LayerList::lockAll(bool lock) {
|
||||
|
||||
for (unsigned l=0; l<count(); l++) {
|
||||
if (at(l)->isVisibleInLayerList()) {
|
||||
at(l)->lock(lock);
|
||||
}
|
||||
}
|
||||
setModified(true);
|
||||
|
||||
for (int i=0; i<layerListListeners.size(); ++i) {
|
||||
RS_LayerListListener* l = layerListListeners.at(i);
|
||||
l->layerToggled(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* adds a LayerListListener to the list of listeners. Listeners
|
||||
* are notified when the layer list changes.
|
||||
*
|
||||
* Typical listeners are: layer list widgets, pen toolbar, graphic view
|
||||
*/
|
||||
void RS_LayerList::addListener(RS_LayerListListener* listener) {
|
||||
layerListListeners.append(listener);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* removes a LayerListListener from the list of listeners.
|
||||
*/
|
||||
void RS_LayerList::removeListener(RS_LayerListListener* listener) {
|
||||
layerListListeners.removeOne(listener);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Dumps the layers to stdout.
|
||||
*/
|
||||
std::ostream& operator << (std::ostream& os, RS_LayerList& l) {
|
||||
|
||||
os << "Layerlist: \n";
|
||||
for (unsigned i=0; i<l.count(); i++) {
|
||||
os << *(l.at(i)) << "\n";
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the layer lists modified status to 'm'.
|
||||
* Listeners are notified.
|
||||
*/
|
||||
void RS_LayerList::setModified(bool m) {
|
||||
modified = m;
|
||||
|
||||
// Notify listeners
|
||||
for (auto l: layerListListeners) {
|
||||
l->layerListModified(m);
|
||||
}
|
||||
}
|
||||
|
||||
141
lib/engine/rs_layerlist.h
Normal file
141
lib/engine/rs_layerlist.h
Normal file
@@ -0,0 +1,141 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2015 A. Stebich (librecad@mail.lordofbikes.de)
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_LAYERLIST_H
|
||||
#define RS_LAYERLIST_H
|
||||
|
||||
#include <QList>
|
||||
#include "rs_layer.h"
|
||||
|
||||
class RS_LayerListListener;
|
||||
class QG_LayerWidget;
|
||||
|
||||
/**
|
||||
* A list of layers.
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_LayerList {
|
||||
public:
|
||||
RS_LayerList();
|
||||
virtual ~RS_LayerList() = default;
|
||||
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* @return Number of layers in the list.
|
||||
*/
|
||||
unsigned int count() const {
|
||||
return layers.count();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Layer at given position or NULL if i is out of range.
|
||||
*/
|
||||
RS_Layer* at(unsigned int i) {
|
||||
return layers.at(i);
|
||||
}
|
||||
QList<RS_Layer*>::iterator begin();
|
||||
QList<RS_Layer*>::iterator end();
|
||||
QList<RS_Layer*>::const_iterator begin()const;
|
||||
QList<RS_Layer*>::const_iterator end()const;
|
||||
|
||||
void activate(const QString& name, bool notify = false);
|
||||
void activate(RS_Layer* layer, bool notify = false);
|
||||
//! @return The active layer of NULL if no layer is activated.
|
||||
RS_Layer* getActive() {
|
||||
return activeLayer;
|
||||
}
|
||||
virtual void add(RS_Layer* layer);
|
||||
virtual void remove(RS_Layer* layer);
|
||||
virtual void edit(RS_Layer* layer, const RS_Layer& source);
|
||||
RS_Layer* find(const QString& name);
|
||||
int getIndex(const QString& name);
|
||||
int getIndex(RS_Layer* layer);
|
||||
void toggle(const QString& name);
|
||||
void toggle(RS_Layer* layer);
|
||||
void toggleLock(RS_Layer* layer);
|
||||
void togglePrint(RS_Layer* layer);
|
||||
void toggleConstruction(RS_Layer* layer);
|
||||
void freezeAll(bool freeze);
|
||||
void lockAll(bool lock);
|
||||
|
||||
//! sets the layerWidget pointer in RS_LayerListClass
|
||||
void setLayerWitget(QG_LayerWidget * lw) {
|
||||
layerWidget=lw;
|
||||
}
|
||||
//! @return the layerWidget pointer inside the RS_LayerListClass
|
||||
QG_LayerWidget* getLayerWitget() {
|
||||
return layerWidget;
|
||||
}
|
||||
//! @return First layer of the list.
|
||||
//RS_Layer* firstLayer() {
|
||||
// return layers.first();
|
||||
//}
|
||||
/** @return Next layer from the list after
|
||||
* calling firstLayer() or nextLayer().
|
||||
*/
|
||||
//RS_Layer* nextLayer() {
|
||||
// return layers.next();
|
||||
//}
|
||||
|
||||
void addListener(RS_LayerListListener* listener);
|
||||
void removeListener(RS_LayerListListener* listener);
|
||||
|
||||
/**
|
||||
* Sets the layer lists modified status to 'm'.
|
||||
*/
|
||||
void setModified(bool m);
|
||||
|
||||
/**
|
||||
* @retval true The layer list has been modified.
|
||||
* @retval false The layer list has not been modified.
|
||||
*/
|
||||
virtual bool isModified() const {
|
||||
return modified;
|
||||
}
|
||||
/**
|
||||
* @brief sort by layer names
|
||||
*/
|
||||
void sort();
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os, RS_LayerList& l);
|
||||
|
||||
private:
|
||||
//! layers in the graphic
|
||||
QList<RS_Layer*> layers;
|
||||
//! List of registered LayerListListeners
|
||||
QList<RS_LayerListListener*> layerListListeners;
|
||||
QG_LayerWidget* layerWidget;
|
||||
//! Currently active layer
|
||||
RS_Layer* activeLayer;
|
||||
/** Flag set if the layer list was modified and not yet saved. */
|
||||
bool modified;
|
||||
};
|
||||
|
||||
#endif
|
||||
90
lib/engine/rs_layerlistlistener.h
Normal file
90
lib/engine/rs_layerlistlistener.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2015 A. Stebich (librecad@mail.lordofbikes.de)
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_LAYERLISTLISTENER_H
|
||||
#define RS_LAYERLISTLISTENER_H
|
||||
|
||||
#include "rs_layer.h"
|
||||
|
||||
/**
|
||||
* This class is an interface for classes that are interested in
|
||||
* knowing about changes in the layer list.
|
||||
*/
|
||||
class RS_LayerListListener {
|
||||
public:
|
||||
RS_LayerListListener() {}
|
||||
virtual ~RS_LayerListListener() {}
|
||||
|
||||
/**
|
||||
* Called when the active layer changes.
|
||||
*/
|
||||
virtual void layerActivated(RS_Layer*) {}
|
||||
|
||||
/**
|
||||
* Called when a new layer is added to the list.
|
||||
*/
|
||||
virtual void layerAdded(RS_Layer*) {}
|
||||
|
||||
/**
|
||||
* Called when a layer is removed from the list.
|
||||
*/
|
||||
virtual void layerRemoved(RS_Layer*) {}
|
||||
|
||||
/**
|
||||
* Called when a layer's attributes are modified.
|
||||
*/
|
||||
virtual void layerEdited(RS_Layer*) {}
|
||||
|
||||
/**
|
||||
* Called when a layer's visibility is toggled.
|
||||
*/
|
||||
virtual void layerToggled(RS_Layer*) {}
|
||||
|
||||
/**
|
||||
* Called when a layer's lock attribute is toggled.
|
||||
*/
|
||||
virtual void layerToggledLock(RS_Layer*) {}
|
||||
|
||||
/**
|
||||
* Called when a layer's printing attribute is toggled.
|
||||
*/
|
||||
virtual void layerToggledPrint(RS_Layer*) {}
|
||||
|
||||
/**
|
||||
* Called when a layer's construction attribute is toggled.
|
||||
*/
|
||||
virtual void layerToggledConstruction(RS_Layer*) {}
|
||||
|
||||
/**
|
||||
* Called when layer list is modified.
|
||||
*/
|
||||
virtual void layerListModified(bool) {}
|
||||
}
|
||||
;
|
||||
|
||||
#endif
|
||||
214
lib/engine/rs_leader.cpp
Normal file
214
lib/engine/rs_leader.cpp
Normal file
@@ -0,0 +1,214 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
#include<iostream>
|
||||
#include "rs_leader.h"
|
||||
|
||||
#include "rs_debug.h"
|
||||
#include "rs_line.h"
|
||||
#include "rs_solid.h"
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
RS_Leader::RS_Leader(RS_EntityContainer* parent)
|
||||
:RS_EntityContainer(parent)
|
||||
,empty(true)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param d Leader data
|
||||
*/
|
||||
RS_Leader::RS_Leader(RS_EntityContainer* parent,
|
||||
const RS_LeaderData& d)
|
||||
:RS_EntityContainer(parent), data(d) {
|
||||
empty = true;
|
||||
}
|
||||
|
||||
RS_Entity* RS_Leader::clone() const{
|
||||
RS_Leader* p = new RS_Leader(*this);
|
||||
p->setOwner(isOwner());
|
||||
p->initId();
|
||||
p->detach();
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of update. Updates the arrow.
|
||||
*/
|
||||
void RS_Leader::update() {
|
||||
|
||||
// find and delete arrow:
|
||||
for(auto e: entities){
|
||||
if (e->rtti()==RS2::EntitySolid) {
|
||||
removeEntity(e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isUndone()) {
|
||||
return;
|
||||
}
|
||||
|
||||
RS_Entity* fe = firstEntity();
|
||||
if (fe && fe->isAtomic()) {
|
||||
RS_Vector p1 = ((RS_AtomicEntity*)fe)->getStartpoint();
|
||||
RS_Vector p2 = ((RS_AtomicEntity*)fe)->getEndpoint();
|
||||
|
||||
// first entity must be the line which gets the arrow:
|
||||
if (hasArrowHead()) {
|
||||
RS_Solid* s = new RS_Solid(this, RS_SolidData());
|
||||
s->shapeArrow(p1,
|
||||
p2.angleTo(p1),
|
||||
getGraphicVariableDouble("$DIMASZ", 2.5)* getGraphicVariableDouble("$DIMSCALE", 1.0));
|
||||
s->setPen(RS_Pen(RS2::FlagInvalid));
|
||||
s->setLayer(nullptr);
|
||||
RS_EntityContainer::addEntity(s);
|
||||
}
|
||||
}
|
||||
calculateBorders();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Adds a vertex from the endpoint of the last element or
|
||||
* sets the startpoint to the point 'v'.
|
||||
*
|
||||
* The very first vertex added is the starting point.
|
||||
*
|
||||
* @param v vertex coordinate
|
||||
*
|
||||
* @return Pointer to the entity that was added or nullptr if this
|
||||
* was the first vertex added.
|
||||
*/
|
||||
RS_Entity* RS_Leader::addVertex(const RS_Vector& v) {
|
||||
|
||||
RS_Entity* entity{nullptr};
|
||||
static RS_Vector last = RS_Vector{false};
|
||||
|
||||
if (empty) {
|
||||
last = v;
|
||||
empty = false;
|
||||
} else {
|
||||
// add line to the leader:
|
||||
entity = new RS_Line{this, {last, v}};
|
||||
entity->setPen(RS_Pen(RS2::FlagInvalid));
|
||||
entity->setLayer(nullptr);
|
||||
RS_EntityContainer::addEntity(entity);
|
||||
|
||||
if (count()==1 && hasArrowHead()) {
|
||||
update();
|
||||
}
|
||||
|
||||
last = v;
|
||||
}
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Reimplementation of the addEntity method for a normal container.
|
||||
* This reimplementation deletes the given entity!
|
||||
*
|
||||
* To add entities use addVertex() instead.
|
||||
*/
|
||||
void RS_Leader::addEntity(RS_Entity* entity) {
|
||||
RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Leader::addEntity:"
|
||||
" should never be called");
|
||||
|
||||
if (!entity) return;
|
||||
|
||||
delete entity;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_Leader::move(const RS_Vector& offset) {
|
||||
RS_EntityContainer::move(offset);
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_Leader::rotate(const RS_Vector& center, const double& angle) {
|
||||
RS_EntityContainer::rotate(center, angle);
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
void RS_Leader::rotate(const RS_Vector& center, const RS_Vector& angleVector) {
|
||||
RS_EntityContainer::rotate(center, angleVector);
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
void RS_Leader::scale(const RS_Vector& center, const RS_Vector& factor) {
|
||||
RS_EntityContainer::scale(center, factor);
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_Leader::mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) {
|
||||
RS_EntityContainer::mirror(axisPoint1, axisPoint2);
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
void RS_Leader::stretch(const RS_Vector& firstCorner,
|
||||
const RS_Vector& secondCorner,
|
||||
const RS_Vector& offset) {
|
||||
|
||||
RS_EntityContainer::stretch(firstCorner, secondCorner, offset);
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps the leader's data to stdout.
|
||||
*/
|
||||
std::ostream& operator << (std::ostream& os, const RS_Leader& l) {
|
||||
os << " Leader: " << l.getData() << " {\n";
|
||||
|
||||
os << (RS_EntityContainer&)l;
|
||||
|
||||
os << "\n}\n";
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream& operator << (std::ostream& os,
|
||||
const RS_LeaderData& /*ld*/) {
|
||||
os << "(Leader)";
|
||||
return os;
|
||||
}
|
||||
|
||||
109
lib/engine/rs_leader.h
Normal file
109
lib/engine/rs_leader.h
Normal file
@@ -0,0 +1,109 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_LEADER_H
|
||||
#define RS_LEADER_H
|
||||
|
||||
#include "rs_entity.h"
|
||||
#include "rs_entitycontainer.h"
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Holds the data that defines a leader.
|
||||
*/
|
||||
class RS_LeaderData {
|
||||
public:
|
||||
RS_LeaderData() = default;
|
||||
RS_LeaderData(bool arrowHeadFlag) {
|
||||
arrowHead = arrowHeadFlag;
|
||||
}
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os,
|
||||
const RS_LeaderData& /*ld*/);
|
||||
|
||||
/** true: leader has an arrow head. false: no arrow. */
|
||||
bool arrowHead;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Class for a leader entity (kind of a polyline arrow).
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_Leader : public RS_EntityContainer {
|
||||
public:
|
||||
RS_Leader(RS_EntityContainer* parent=NULL);
|
||||
RS_Leader(RS_EntityContainer* parent,
|
||||
const RS_LeaderData& d);
|
||||
|
||||
RS_Entity* clone() const override;
|
||||
|
||||
/** @return RS2::EntityDimLeader */
|
||||
RS2::EntityType rtti() const override{
|
||||
return RS2::EntityDimLeader;
|
||||
}
|
||||
|
||||
void update() override;
|
||||
|
||||
/** @return Copy of data that defines the leader. */
|
||||
RS_LeaderData getData() const {
|
||||
return data;
|
||||
}
|
||||
|
||||
/** @return true: if this leader has an arrow at the beginning. */
|
||||
bool hasArrowHead() {
|
||||
return data.arrowHead;
|
||||
}
|
||||
|
||||
RS_Entity* addVertex(const RS_Vector& v);
|
||||
void addEntity(RS_Entity* entity) override;
|
||||
|
||||
// double getLength() const {
|
||||
// return -1.0;
|
||||
// }
|
||||
|
||||
|
||||
void move(const RS_Vector& offset) override;
|
||||
void rotate(const RS_Vector& center, const double& angle) override;
|
||||
void rotate(const RS_Vector& center, const RS_Vector& angleVector) override;
|
||||
void scale(const RS_Vector& center, const RS_Vector& factor) override;
|
||||
void mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) override;
|
||||
void stretch(const RS_Vector& firstCorner,
|
||||
const RS_Vector& secondCorner,
|
||||
const RS_Vector& offset) override;
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os, const RS_Leader& l);
|
||||
|
||||
protected:
|
||||
RS_LeaderData data;
|
||||
bool empty;
|
||||
};
|
||||
|
||||
#endif
|
||||
789
lib/engine/rs_line.cpp
Normal file
789
lib/engine/rs_line.cpp
Normal file
@@ -0,0 +1,789 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2015-2018 A. Stebich (librecad@mail.lordofbikes.de)
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#include "rs_line.h"
|
||||
|
||||
#include "rs_debug.h"
|
||||
#include "rs_graphicview.h"
|
||||
#include "rs_painter.h"
|
||||
#include "rs_graphic.h"
|
||||
#include "rs_linetypepattern.h"
|
||||
#include "rs_information.h"
|
||||
#include "lc_quadratic.h"
|
||||
#include "rs_painterqt.h"
|
||||
#include "rs_circle.h"
|
||||
#include "lc_rect.h"
|
||||
|
||||
#ifdef EMU_C99
|
||||
#include "emu_c99.h"
|
||||
#endif
|
||||
|
||||
std::ostream& operator << (std::ostream& os, const RS_LineData& ld) {
|
||||
os << "RS_LINE: ((" << ld.startpoint <<
|
||||
")(" << ld.endpoint <<
|
||||
"))";
|
||||
return os;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
RS_Line::RS_Line(RS_EntityContainer* parent,
|
||||
const RS_LineData& d)
|
||||
:RS_AtomicEntity(parent), data(d) {
|
||||
calculateBorders();
|
||||
}
|
||||
|
||||
////construct a line from two endpoints
|
||||
RS_Line::RS_Line(RS_EntityContainer* parent, const RS_Vector& pStart, const RS_Vector& pEnd)
|
||||
:RS_AtomicEntity(parent), data({pStart,pEnd}) {
|
||||
calculateBorders();
|
||||
}
|
||||
|
||||
////construct a line from two endpoints, to be used for construction
|
||||
RS_Line::RS_Line(const RS_Vector& pStart, const RS_Vector& pEnd)
|
||||
:RS_AtomicEntity(nullptr), data({pStart,pEnd}) {
|
||||
calculateBorders();
|
||||
}
|
||||
|
||||
|
||||
RS_Entity* RS_Line::clone() const {
|
||||
RS_Line* l = new RS_Line(*this);
|
||||
l->initId();
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_Line::calculateBorders() {
|
||||
minV = RS_Vector::minimum(data.startpoint, data.endpoint);
|
||||
maxV = RS_Vector::maximum(data.startpoint, data.endpoint);
|
||||
}
|
||||
|
||||
|
||||
|
||||
RS_VectorSolutions RS_Line::getRefPoints() const
|
||||
{
|
||||
return RS_VectorSolutions({data.startpoint, data.endpoint});
|
||||
}
|
||||
|
||||
|
||||
RS_Vector RS_Line::getNearestEndpoint(const RS_Vector& coord,
|
||||
double* dist)const {
|
||||
double dist1((data.startpoint-coord).squared());
|
||||
double dist2((data.endpoint-coord).squared());
|
||||
|
||||
if (dist2<dist1) {
|
||||
if (dist) {
|
||||
*dist = sqrt(dist2);
|
||||
}
|
||||
return data.endpoint;
|
||||
} else {
|
||||
if (dist) {
|
||||
*dist = sqrt(dist1);
|
||||
}
|
||||
return data.startpoint;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This is similar to getNearestPointOnEntity, but only returns the value of
|
||||
* the position of the projection. The value may be negative, or greater than
|
||||
* the length of the line since there are no bounds checking. The absolute
|
||||
* value of the return value represents a physical distance from the
|
||||
* startpoint.
|
||||
*
|
||||
* @param coord The point which will be projected onto the line.
|
||||
*/
|
||||
double RS_Line::getProjectionValueAlongLine(const RS_Vector& coord) const
|
||||
{
|
||||
RS_Vector direction {data.endpoint - data.startpoint};
|
||||
RS_Vector vpc {coord - data.startpoint};
|
||||
double direction_magnitude {direction.magnitude()};
|
||||
double v = 0.0;
|
||||
|
||||
if(direction_magnitude > RS_TOLERANCE2) {
|
||||
//find projection on line
|
||||
v = RS_Vector::dotP(vpc, direction) / direction_magnitude;
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
RS_Vector RS_Line::getNearestPointOnEntity(const RS_Vector& coord,
|
||||
bool onEntity,
|
||||
double* dist,
|
||||
RS_Entity** entity) const
|
||||
{
|
||||
if (entity) {
|
||||
*entity = const_cast<RS_Line*>(this);
|
||||
}
|
||||
|
||||
RS_Vector direction {data.endpoint - data.startpoint};
|
||||
RS_Vector vpc {coord - data.startpoint};
|
||||
double a {direction.squared()};
|
||||
|
||||
if( a < RS_TOLERANCE2) {
|
||||
//line too short
|
||||
vpc = getMiddlePoint();
|
||||
}
|
||||
else {
|
||||
//find projection on line
|
||||
const double t {RS_Vector::dotP( vpc, direction) / a};
|
||||
if( !isConstruction()
|
||||
&& onEntity
|
||||
&& ( t <= -RS_TOLERANCE
|
||||
|| t >= 1. + RS_TOLERANCE ) ) {
|
||||
//projection point not within range, find the nearest endpoint
|
||||
return getNearestEndpoint( coord, dist);
|
||||
}
|
||||
|
||||
vpc = data.startpoint + direction * t;
|
||||
}
|
||||
|
||||
if (dist) {
|
||||
*dist = vpc.distanceTo( coord);
|
||||
}
|
||||
|
||||
return vpc;
|
||||
}
|
||||
|
||||
/*
|
||||
RS_Vector RS_Line::getPointOnEntityAlongLine(const RS_Vector& coord,const double angle,
|
||||
bool onEntity,
|
||||
double* dist,
|
||||
RS_Entity** entity) const
|
||||
{
|
||||
if (entity)
|
||||
{
|
||||
*entity = const_cast<RS_Line*>(this);
|
||||
}
|
||||
|
||||
|
||||
RS_Vector direction {data.endpoint - data.startpoint};
|
||||
RS_Vector vpc {coord - data.startpoint};
|
||||
double a {direction.squared()};
|
||||
|
||||
if( a < RS_TOLERANCE2)
|
||||
{
|
||||
//line too short
|
||||
vpc = getMiddlePoint();
|
||||
}
|
||||
else
|
||||
{
|
||||
//find projection on line
|
||||
const double t {RS_Vector::dotP( vpc, direction) / a};
|
||||
if( !isConstruction() && onEntity && ( t <= -RS_TOLERANCE || t >= 1. + RS_TOLERANCE ) )
|
||||
{
|
||||
//projection point not within range, find the nearest endpoint
|
||||
return getNearestEndpoint( coord, dist);
|
||||
}
|
||||
|
||||
vpc = data.startpoint + direction * t;
|
||||
}
|
||||
|
||||
if (dist)
|
||||
{
|
||||
*dist = vpc.distanceTo( coord);
|
||||
}
|
||||
|
||||
return vpc;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
RS_Vector RS_Line::getMiddlePoint()const
|
||||
{
|
||||
return (getStartpoint() + getEndpoint())*0.5;
|
||||
}
|
||||
/** @return the nearest of equidistant middle points of the line. */
|
||||
RS_Vector RS_Line::getNearestMiddle(const RS_Vector& coord,
|
||||
double* dist,
|
||||
int middlePoints
|
||||
)const {
|
||||
// RS_DEBUG->print("RS_Line::getNearestMiddle(): begin\n");
|
||||
RS_Vector dvp(getEndpoint() - getStartpoint());
|
||||
double l=dvp.magnitude();
|
||||
if( l<= RS_TOLERANCE) {
|
||||
//line too short
|
||||
return const_cast<RS_Line*>(this)->getNearestCenter(coord, dist);
|
||||
}
|
||||
RS_Vector vp0(getNearestPointOnEntity(coord,true,dist));
|
||||
int counts=middlePoints+1;
|
||||
int i( static_cast<int>(vp0.distanceTo(getStartpoint())/l*counts+0.5));
|
||||
if(!i) i++; // remove end points
|
||||
if(i==counts) i--;
|
||||
vp0=getStartpoint() + dvp*(double(i)/double(counts));
|
||||
|
||||
if (dist) {
|
||||
*dist=vp0.distanceTo(coord);
|
||||
}
|
||||
// RS_DEBUG->print("RS_Line::getNearestMiddle(): end\n");
|
||||
return vp0;
|
||||
}
|
||||
|
||||
|
||||
//RS_Vector RS_Line::getNearestCenter(const RS_Vector& coord,
|
||||
// double* dist) {
|
||||
|
||||
// RS_Vector p = (data.startpoint + data.endpoint)*0.5;
|
||||
|
||||
// if (dist) {
|
||||
// *dist = p.distanceTo(coord);
|
||||
// }
|
||||
|
||||
// return p;
|
||||
//}
|
||||
|
||||
|
||||
RS_Vector RS_Line::getNearestDist(double distance,
|
||||
const RS_Vector& coord,
|
||||
double* dist) const{
|
||||
|
||||
RS_Vector dv = RS_Vector::polar(distance, getAngle1());
|
||||
|
||||
RS_Vector ret;
|
||||
//if(coord.distanceTo(getStartpoint()) < coord.distanceTo(getEndpoint())) {
|
||||
if( (coord-getStartpoint()).squared()< (coord-getEndpoint()).squared() ) {
|
||||
ret = getStartpoint() + dv;
|
||||
}else{
|
||||
ret = getEndpoint() - dv;
|
||||
}
|
||||
if (dist)
|
||||
*dist=coord.distanceTo(ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
RS_Vector RS_Line::getNearestDist(double distance,
|
||||
bool startp) const{
|
||||
|
||||
double a1 = getAngle1();
|
||||
|
||||
RS_Vector dv = RS_Vector::polar(distance, a1);
|
||||
RS_Vector ret;
|
||||
|
||||
if (startp) {
|
||||
ret = data.startpoint + dv;
|
||||
}
|
||||
else {
|
||||
ret = data.endpoint - dv;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*RS_Vector RS_Line::getNearestRef(const RS_Vector& coord,
|
||||
double* dist) {
|
||||
double d1, d2, d;
|
||||
RS_Vector p;
|
||||
RS_Vector p1 = getNearestEndpoint(coord, &d1);
|
||||
RS_Vector p2 = getNearestMiddle(coord, &d2);
|
||||
|
||||
if (d1<d2) {
|
||||
d = d1;
|
||||
p = p1;
|
||||
} else {
|
||||
d = d2;
|
||||
p = p2;
|
||||
}
|
||||
|
||||
if (dist) {
|
||||
*dist = d;
|
||||
}
|
||||
|
||||
return p;
|
||||
}*/
|
||||
|
||||
|
||||
|
||||
/** return the equation of the entity
|
||||
for quadratic,
|
||||
|
||||
return a vector contains:
|
||||
m0 x^2 + m1 xy + m2 y^2 + m3 x + m4 y + m5 =0
|
||||
|
||||
for linear:
|
||||
m0 x + m1 y + m2 =0
|
||||
**/
|
||||
LC_Quadratic RS_Line::getQuadratic() const
|
||||
{
|
||||
std::vector<double> ce(3,0.);
|
||||
auto dvp=data.endpoint - data.startpoint;
|
||||
RS_Vector normal(-dvp.y,dvp.x);
|
||||
ce[0]=normal.x;
|
||||
ce[1]=normal.y;
|
||||
ce[2]= -normal.dotP(data.endpoint);
|
||||
return LC_Quadratic(ce);
|
||||
}
|
||||
|
||||
double RS_Line::areaLineIntegral() const
|
||||
{
|
||||
return 0.5*(data.endpoint.y - data.startpoint.y)*(data.startpoint.x + data.endpoint.x);
|
||||
}
|
||||
|
||||
|
||||
RS_Vector RS_Line::getTangentDirection(const RS_Vector& /*point*/)const{
|
||||
return getEndpoint() - getStartpoint();
|
||||
}
|
||||
|
||||
void RS_Line::moveStartpoint(const RS_Vector& pos) {
|
||||
data.startpoint = pos;
|
||||
calculateBorders();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_Line::moveEndpoint(const RS_Vector& pos) {
|
||||
data.endpoint = pos;
|
||||
calculateBorders();
|
||||
}
|
||||
|
||||
|
||||
|
||||
RS_Vector RS_Line::prepareTrim(const RS_Vector& trimCoord,
|
||||
const RS_VectorSolutions& trimSol) {
|
||||
//prepare trimming for multiple intersections
|
||||
if ( ! trimSol.hasValid()) return(RS_Vector(false));
|
||||
if ( trimSol.getNumber() == 1 ) return(trimSol.get(0));
|
||||
auto vp0=trimSol.getClosest(trimCoord, nullptr, 0);
|
||||
|
||||
double dr2=trimCoord.squaredTo(vp0);
|
||||
//the trim point found is closer to mouse location (trimCoord) than both end points, return this trim point
|
||||
if(dr2 < trimCoord.squaredTo(getStartpoint()) && dr2 < trimCoord.squaredTo(getEndpoint())) return vp0;
|
||||
//the closer endpoint to trimCoord
|
||||
RS_Vector vp1=(trimCoord.squaredTo(getStartpoint()) <= trimCoord.squaredTo(getEndpoint()))?getStartpoint():getEndpoint();
|
||||
|
||||
//searching for intersection in the direction of the closer end point
|
||||
auto dvp1=vp1 - trimCoord;
|
||||
RS_VectorSolutions sol1;
|
||||
for(size_t i=0; i<trimSol.size(); i++){
|
||||
auto dvp2=trimSol.at(i) - trimCoord;
|
||||
if( RS_Vector::dotP(dvp1, dvp2) > RS_TOLERANCE)
|
||||
sol1.push_back(trimSol.at(i));
|
||||
}
|
||||
//if found intersection in direction, return the closest to trimCoord from it
|
||||
if(sol1.size())
|
||||
return sol1.getClosest(trimCoord, nullptr, 0);
|
||||
|
||||
//no intersection by direction, return previously found closest intersection
|
||||
return vp0;
|
||||
}
|
||||
|
||||
RS2::Ending RS_Line::getTrimPoint(const RS_Vector& trimCoord,
|
||||
const RS_Vector& trimPoint) {
|
||||
RS_Vector vp1=getStartpoint() - trimCoord;
|
||||
RS_Vector vp2=trimPoint - trimCoord;
|
||||
if ( RS_Vector::dotP(vp1,vp2) < 0 ) {
|
||||
return RS2::EndingEnd;
|
||||
} else {
|
||||
return RS2::EndingStart;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RS_Line::reverse() {
|
||||
std::swap(data.startpoint, data.endpoint);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool RS_Line::hasEndpointsWithinWindow(const RS_Vector& firstCorner, const RS_Vector& secondCorner) {
|
||||
RS_Vector vLow( std::min(firstCorner.x, secondCorner.x), std::min(firstCorner.y, secondCorner.y));
|
||||
RS_Vector vHigh( std::max(firstCorner.x, secondCorner.x), std::max(firstCorner.y, secondCorner.y));
|
||||
|
||||
return data.startpoint.isInWindowOrdered(vLow, vHigh)
|
||||
|| data.endpoint.isInWindowOrdered(vLow, vHigh);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* this function creates offset
|
||||
*@coord, position indicates the direction of offset
|
||||
*@distance, distance of offset
|
||||
* return true, if success, otherwise, false
|
||||
*
|
||||
*Author: Dongxu Li
|
||||
*/
|
||||
bool RS_Line::offset(const RS_Vector& coord, const double& distance) {
|
||||
RS_Vector direction{getEndpoint()-getStartpoint()};
|
||||
double ds(direction.magnitude());
|
||||
if(ds< RS_TOLERANCE) return false;
|
||||
direction /= ds;
|
||||
RS_Vector vp(coord-getStartpoint());
|
||||
// RS_Vector vp1(getStartpoint() + direction*(RS_Vector::dotP(direction,vp))); //projection
|
||||
direction.set(-direction.y,direction.x); //rotate pi/2
|
||||
if(RS_Vector::dotP(direction,vp)<0.) {
|
||||
direction *= -1.;
|
||||
}
|
||||
direction*=distance;
|
||||
move(direction);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RS_Line::isTangent(const RS_CircleData& circleData) const{
|
||||
double d;
|
||||
getNearestPointOnEntity(circleData.center,false,&d);
|
||||
if(fabs(d-circleData.radius)<20.*RS_TOLERANCE) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
RS_Vector RS_Line::getNormalVector() const
|
||||
{
|
||||
RS_Vector vp=data.endpoint - data.startpoint; //direction vector
|
||||
double r=vp.magnitude();
|
||||
if (r< RS_TOLERANCE) return RS_Vector{false};
|
||||
return RS_Vector{-vp.y,vp.x}/r;
|
||||
}
|
||||
|
||||
std::vector<RS_Entity* > RS_Line::offsetTwoSides(const double& distance) const
|
||||
{
|
||||
std::vector<RS_Entity*> ret(0);
|
||||
RS_Vector const& vp=getNormalVector()*distance;
|
||||
ret.push_back(new RS_Line{data.startpoint+vp,data.endpoint+vp});
|
||||
ret.push_back(new RS_Line{data.startpoint-vp,data.endpoint-vp});
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* revert the direction of line
|
||||
*/
|
||||
void RS_Line::revertDirection(){
|
||||
std::swap(data.startpoint,data.endpoint);
|
||||
}
|
||||
|
||||
void RS_Line::move(const RS_Vector& offset) {
|
||||
// RS_DEBUG->print("RS_Line::move1: sp: %f/%f, ep: %f/%f",
|
||||
// data.startpoint.x, data.startpoint.y,
|
||||
// data.endpoint.x, data.endpoint.y);
|
||||
|
||||
// RS_DEBUG->print("RS_Line::move1: offset: %f/%f", offset.x, offset.y);
|
||||
|
||||
data.startpoint.move(offset);
|
||||
data.endpoint.move(offset);
|
||||
moveBorders(offset);
|
||||
// RS_DEBUG->print("RS_Line::move2: sp: %f/%f, ep: %f/%f",
|
||||
// data.startpoint.x, data.startpoint.y,
|
||||
// data.endpoint.x, data.endpoint.y);
|
||||
}
|
||||
|
||||
void RS_Line::rotate(const double& angle) {
|
||||
// RS_DEBUG->print("RS_Line::rotate");
|
||||
// RS_DEBUG->print("RS_Line::rotate1: sp: %f/%f, ep: %f/%f",
|
||||
// data.startpoint.x, data.startpoint.y,
|
||||
// data.endpoint.x, data.endpoint.y);
|
||||
RS_Vector rvp(angle);
|
||||
data.startpoint.rotate(rvp);
|
||||
data.endpoint.rotate(rvp);
|
||||
// RS_DEBUG->print("RS_Line::rotate2: sp: %f/%f, ep: %f/%f",
|
||||
// data.startpoint.x, data.startpoint.y,
|
||||
// data.endpoint.x, data.endpoint.y);
|
||||
calculateBorders();
|
||||
// RS_DEBUG->print("RS_Line::rotate: OK");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_Line::rotate(const RS_Vector& center, const double& angle) {
|
||||
// RS_DEBUG->print("RS_Line::rotate");
|
||||
// RS_DEBUG->print("RS_Line::rotate1: sp: %f/%f, ep: %f/%f",
|
||||
// data.startpoint.x, data.startpoint.y,
|
||||
// data.endpoint.x, data.endpoint.y);
|
||||
RS_Vector rvp(angle);
|
||||
data.startpoint.rotate(center, rvp);
|
||||
data.endpoint.rotate(center, rvp);
|
||||
// RS_DEBUG->print("RS_Line::rotate2: sp: %f/%f, ep: %f/%f",
|
||||
// data.startpoint.x, data.startpoint.y,
|
||||
// data.endpoint.x, data.endpoint.y);
|
||||
calculateBorders();
|
||||
// RS_DEBUG->print("RS_Line::rotate: OK");
|
||||
}
|
||||
|
||||
void RS_Line::rotate(const RS_Vector& center, const RS_Vector& angleVector) {
|
||||
data.startpoint.rotate(center, angleVector);
|
||||
data.endpoint.rotate(center, angleVector);
|
||||
calculateBorders();
|
||||
}
|
||||
|
||||
/*scale the line around origin (0,0)
|
||||
*
|
||||
*/
|
||||
void RS_Line::scale(const RS_Vector& factor) {
|
||||
// RS_DEBUG->print("RS_Line::scale1: sp: %f/%f, ep: %f/%f",
|
||||
// data.startpoint.x, data.startpoint.y,
|
||||
// data.endpoint.x, data.endpoint.y);
|
||||
data.startpoint.scale(factor);
|
||||
data.endpoint.scale(factor);
|
||||
// RS_DEBUG->print("RS_Line::scale2: sp: %f/%f, ep: %f/%f",
|
||||
// data.startpoint.x, data.startpoint.y,
|
||||
// data.endpoint.x, data.endpoint.y);
|
||||
calculateBorders();
|
||||
}
|
||||
|
||||
|
||||
void RS_Line::scale(const RS_Vector& center, const RS_Vector& factor) {
|
||||
// RS_DEBUG->print("RS_Line::scale1: sp: %f/%f, ep: %f/%f",
|
||||
// data.startpoint.x, data.startpoint.y,
|
||||
// data.endpoint.x, data.endpoint.y);
|
||||
data.startpoint.scale(center, factor);
|
||||
data.endpoint.scale(center, factor);
|
||||
// RS_DEBUG->print("RS_Line::scale2: sp: %f/%f, ep: %f/%f",
|
||||
// data.startpoint.x, data.startpoint.y,
|
||||
// data.endpoint.x, data.endpoint.y);
|
||||
calculateBorders();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_Line::mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) {
|
||||
data.startpoint.mirror(axisPoint1, axisPoint2);
|
||||
data.endpoint.mirror(axisPoint1, axisPoint2);
|
||||
calculateBorders();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stretches the given range of the entity by the given offset.
|
||||
*/
|
||||
void RS_Line::stretch(const RS_Vector& firstCorner,
|
||||
const RS_Vector& secondCorner,
|
||||
const RS_Vector& offset) {
|
||||
|
||||
RS_Vector const vLow{std::min(firstCorner.x, secondCorner.x),
|
||||
std::min(firstCorner.y, secondCorner.y)
|
||||
};
|
||||
RS_Vector const vHigh{std::max(firstCorner.x, secondCorner.x),
|
||||
std::max(firstCorner.y, secondCorner.y)
|
||||
};
|
||||
|
||||
if (getStartpoint().isInWindowOrdered(vLow, vHigh)) {
|
||||
moveStartpoint(getStartpoint() + offset);
|
||||
}
|
||||
if (getEndpoint().isInWindowOrdered(vLow, vHigh)) {
|
||||
moveEndpoint(getEndpoint() + offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_Line::moveRef(const RS_Vector& ref, const RS_Vector& offset) {
|
||||
if( fabs(data.startpoint.x -ref.x)<1.0e-4 &&
|
||||
fabs(data.startpoint.y -ref.y)<1.0e-4 ) {
|
||||
moveStartpoint(data.startpoint+offset);
|
||||
}
|
||||
if( fabs(data.endpoint.x -ref.x)<1.0e-4 &&
|
||||
fabs(data.endpoint.y -ref.y)<1.0e-4 ) {
|
||||
moveEndpoint(data.endpoint+offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RS_Line::draw(RS_Painter* painter, RS_GraphicView* view, double& patternOffset) {
|
||||
if (! (painter && view)) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto viewportRect = view->getViewRect();
|
||||
RS_VectorSolutions endPoints(0);
|
||||
endPoints.push_back(getStartpoint());
|
||||
endPoints.push_back(getEndpoint());
|
||||
|
||||
RS_EntityContainer ec(nullptr);
|
||||
ec.addRectangle(viewportRect.minP(), viewportRect.maxP());
|
||||
|
||||
// if (viewportRect.inArea(getStartpoint(), RS_TOLERANCE))
|
||||
// endPoints.push_back(getStartpoint());
|
||||
// if (viewportRect.inArea(getEndpoint(), RS_TOLERANCE))
|
||||
// endPoints.push_back(getEndpoint());
|
||||
|
||||
// if (endPoints.size() < 2){
|
||||
// RS_VectorSolutions vpIts;
|
||||
// for(auto p: ec) {
|
||||
// auto const sol=RS_Information::getIntersection(this, p, true);
|
||||
// for (auto const& vp: sol) {
|
||||
// if (vpIts.getClosestDistance(vp) <= RS_TOLERANCE * 10.)
|
||||
// continue;
|
||||
// vpIts.push_back(vp);
|
||||
// }
|
||||
// }
|
||||
// for (auto const& vp: vpIts) {
|
||||
// if (endPoints.getClosestDistance(vp) <= RS_TOLERANCE * 10.)
|
||||
// continue;
|
||||
// endPoints.push_back(vp);
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (endPoints.size()<2) return;
|
||||
|
||||
if ((endPoints[0] - getStartpoint()).squared() >
|
||||
(endPoints[1] - getStartpoint()).squared() )
|
||||
{
|
||||
std::swap(endPoints[0],endPoints[1]);
|
||||
}
|
||||
|
||||
RS_Vector pStart{view->toGui(endPoints.at(0))};
|
||||
RS_Vector pEnd{view->toGui(endPoints.at(1))};
|
||||
// std::cout<<"draw line: "<<pStart<<" to "<<pEnd<<std::endl;
|
||||
RS_Vector direction = pEnd-pStart;
|
||||
|
||||
if (isConstruction(true) && direction.squared() > RS_TOLERANCE){
|
||||
//extend line on a construction layer to fill the whole view
|
||||
RS_VectorSolutions vpIts;
|
||||
for(auto p: ec) {
|
||||
auto const sol=RS_Information::getIntersection(this, p, true);
|
||||
for (auto const& vp: sol) {
|
||||
if (vpIts.getClosestDistance(vp) <= RS_TOLERANCE * 10.)
|
||||
continue;
|
||||
vpIts.push_back(vp);
|
||||
}
|
||||
}
|
||||
|
||||
//draw construction lines up to viewport border
|
||||
switch (vpIts.size()) {
|
||||
case 2:
|
||||
// no need to sort intersections
|
||||
break;
|
||||
case 3:
|
||||
case 4: {
|
||||
// will use the inner two points
|
||||
size_t i{0};
|
||||
for (size_t j = 0; j < vpIts.size(); ++j)
|
||||
if (viewportRect.inArea(vpIts.at(j), RS_TOLERANCE * 10.))
|
||||
std::swap(vpIts[j], vpIts[i++]);
|
||||
|
||||
}
|
||||
break;
|
||||
default:
|
||||
//should not happen
|
||||
return;
|
||||
}
|
||||
pStart=view->toGui(vpIts.get(0));
|
||||
pEnd=view->toGui(vpIts.get(1));
|
||||
direction=pEnd-pStart;
|
||||
}
|
||||
|
||||
bool drawAsSelected = isSelected() && !(view->isPrinting() || view->isPrintPreview());
|
||||
|
||||
double length=direction.magnitude();
|
||||
patternOffset -= length;
|
||||
if (( !drawAsSelected && (
|
||||
getPen().getLineType()==RS2::SolidLine ||
|
||||
view->getDrawingMode()==RS2::ModePreview)) ) {
|
||||
//if length is too small, attempt to draw the line, could be a potential bug
|
||||
painter->drawLine(pStart,pEnd);
|
||||
return;
|
||||
}
|
||||
// double styleFactor = getStyleFactor(view);
|
||||
|
||||
|
||||
// Pattern:
|
||||
const RS_LineTypePattern* pat;
|
||||
if (drawAsSelected) {
|
||||
// styleFactor=1.;
|
||||
pat = &RS_LineTypePattern::patternSelected;
|
||||
|
||||
} else {
|
||||
pat = view->getPattern(getPen().getLineType());
|
||||
}
|
||||
if (!pat) {
|
||||
// patternOffset -= length;
|
||||
RS_DEBUG->print(RS_Debug::D_WARNING,
|
||||
"RS_Line::draw: Invalid line pattern");
|
||||
painter->drawLine(pStart,pEnd);
|
||||
return;
|
||||
}
|
||||
// patternOffset = remainder(patternOffset - length-0.5*pat->totalLength,pat->totalLength)+0.5*pat->totalLength;
|
||||
if(length<=RS_TOLERANCE){
|
||||
painter->drawLine(pStart,pEnd);
|
||||
return; //avoid division by zero
|
||||
}
|
||||
direction/=length; //cos(angle), sin(angle)
|
||||
// Pen to draw pattern is always solid:
|
||||
RS_Pen pen = painter->getPen();
|
||||
|
||||
pen.setLineType(RS2::SolidLine);
|
||||
painter->setPen(pen);
|
||||
|
||||
if (pat->num <= 0) {
|
||||
RS_DEBUG->print(RS_Debug::D_WARNING,"invalid line pattern for line, draw solid line instead");
|
||||
painter->drawLine(view->toGui(getStartpoint()),
|
||||
view->toGui(getEndpoint()));
|
||||
return;
|
||||
}
|
||||
|
||||
// pattern segment length:
|
||||
double patternSegmentLength = pat->totalLength;
|
||||
|
||||
// create pattern:
|
||||
std::vector<RS_Vector> dp(pat->num);
|
||||
std::vector<double> ds(pat->num);
|
||||
double dpmm=static_cast<RS_PainterQt*>(painter)->getDpmm();
|
||||
for (size_t i=0; i < pat->num; ++i) {
|
||||
// ds[j]=pat->pattern[i] * styleFactor;
|
||||
//fixme, styleFactor support needed
|
||||
|
||||
ds[i]=dpmm*pat->pattern[i];
|
||||
if (fabs(ds[i]) < 1. ) ds[i] = copysign(1., ds[i]);
|
||||
dp[i] = direction*fabs(ds[i]);
|
||||
}
|
||||
double total= remainder(patternOffset-0.5*patternSegmentLength,patternSegmentLength) -0.5*patternSegmentLength;
|
||||
// double total= patternOffset-patternSegmentLength;
|
||||
|
||||
RS_Vector curP{pStart+direction*total};
|
||||
for (int j=0; total<length; j=(j+1)%pat->num) {
|
||||
|
||||
// line segment (otherwise space segment)
|
||||
double const t2=total+fabs(ds[j]);
|
||||
RS_Vector const& p3=curP+dp[j];
|
||||
if (ds[j]>0.0 && t2 > 0.0) {
|
||||
// drop the whole pattern segment line, for ds[i]<0:
|
||||
// trim end points of pattern segment line to line
|
||||
RS_Vector const& p1 =(total > -0.5)?curP:pStart;
|
||||
RS_Vector const& p2 =(t2 < length+0.5)?p3:pEnd;
|
||||
painter->drawLine(p1,p2);
|
||||
}
|
||||
total=t2;
|
||||
curP=p3;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps the point's data to stdout.
|
||||
*/
|
||||
std::ostream& operator << (std::ostream& os, const RS_Line& l) {
|
||||
os << " Line: " << l.getData() << "\n";
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
234
lib/engine/rs_line.h
Normal file
234
lib/engine/rs_line.h
Normal file
@@ -0,0 +1,234 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_LINE_H
|
||||
#define RS_LINE_H
|
||||
|
||||
#include "rs_atomicentity.h"
|
||||
|
||||
class LC_Quadratic;
|
||||
|
||||
/**
|
||||
* Holds the data that defines a line.
|
||||
*/
|
||||
struct RS_LineData {
|
||||
RS_LineData() :
|
||||
startpoint( false),
|
||||
endpoint( false)
|
||||
{}
|
||||
|
||||
RS_LineData(const RS_Vector& point1,
|
||||
const RS_Vector& point2) :
|
||||
startpoint( point1),
|
||||
endpoint( point2)
|
||||
{}
|
||||
|
||||
RS_Vector startpoint;
|
||||
RS_Vector endpoint;
|
||||
};
|
||||
|
||||
std::ostream& operator << (std::ostream& os, const RS_LineData& ld);
|
||||
|
||||
/**
|
||||
* Class for a line entity.
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_Line : public RS_AtomicEntity {
|
||||
public:
|
||||
RS_Line() = default;
|
||||
RS_Line(RS_EntityContainer* parent,
|
||||
const RS_LineData& d);
|
||||
RS_Line(RS_EntityContainer* parent, const RS_Vector& pStart, const RS_Vector& pEnd);
|
||||
RS_Line(const RS_Vector& pStart, const RS_Vector& pEnd);
|
||||
|
||||
RS_Entity* clone() const override;
|
||||
|
||||
/** @return RS2::EntityLine */
|
||||
RS2::EntityType rtti() const override{
|
||||
return RS2::EntityLine;
|
||||
}
|
||||
/** @return true */
|
||||
bool isEdge() const override{
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @return Copy of data that defines the line. */
|
||||
RS_LineData getData() const{
|
||||
return data;
|
||||
}
|
||||
|
||||
RS_VectorSolutions getRefPoints() const override;
|
||||
|
||||
/** @return Start point of the entity */
|
||||
RS_Vector getStartpoint() const override{
|
||||
return data.startpoint;
|
||||
}
|
||||
/** @return End point of the entity */
|
||||
RS_Vector getEndpoint() const override{
|
||||
return data.endpoint;
|
||||
}
|
||||
/** Sets the startpoint */
|
||||
void setStartpoint(RS_Vector s) {
|
||||
data.startpoint = s;
|
||||
calculateBorders();
|
||||
}
|
||||
/** Sets the endpoint */
|
||||
void setEndpoint(RS_Vector e) {
|
||||
data.endpoint = e;
|
||||
calculateBorders();
|
||||
}
|
||||
/**
|
||||
* @return Direction 1. The angle at which the line starts at
|
||||
* the startpoint.
|
||||
*/
|
||||
double getDirection1() const override{
|
||||
return getAngle1();
|
||||
}
|
||||
/**
|
||||
* @return Direction 2. The angle at which the line starts at
|
||||
* the endpoint.
|
||||
*/
|
||||
double getDirection2() const override{
|
||||
return getAngle2();
|
||||
}
|
||||
RS_Vector getTangentDirection(const RS_Vector& point)const override;
|
||||
|
||||
void moveStartpoint(const RS_Vector& pos) override;
|
||||
void moveEndpoint(const RS_Vector& pos) override;
|
||||
RS2::Ending getTrimPoint(const RS_Vector& trimCoord,
|
||||
const RS_Vector& trimPoint) override;
|
||||
RS_Vector prepareTrim(const RS_Vector& trimCoord,
|
||||
const RS_VectorSolutions& trimSol) override;
|
||||
void reverse() override;
|
||||
/** Sets the y coordinate of the startpoint */
|
||||
void setStartpointY(double val) {
|
||||
data.startpoint.y = val;
|
||||
calculateBorders();
|
||||
}
|
||||
/** Sets the y coordinate of the endpoint */
|
||||
void setEndpointY(double val) {
|
||||
data.endpoint.y = val;
|
||||
calculateBorders();
|
||||
}
|
||||
bool hasEndpointsWithinWindow(const RS_Vector& v1, const RS_Vector& v2) override;
|
||||
|
||||
/**
|
||||
* @return The length of the line.
|
||||
*/
|
||||
double getLength() const override{
|
||||
return data.startpoint.distanceTo(data.endpoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The angle of the line (from start to endpoint).
|
||||
*/
|
||||
double getAngle1() const{
|
||||
return data.startpoint.angleTo(data.endpoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The angle of the line (from end to startpoint).
|
||||
*/
|
||||
double getAngle2() const{
|
||||
return data.endpoint.angleTo(data.startpoint);
|
||||
}
|
||||
bool isTangent(const RS_CircleData& circleData) const override;
|
||||
|
||||
/**
|
||||
* @return a perpendicular vector
|
||||
*/
|
||||
RS_Vector getNormalVector() const;
|
||||
double getProjectionValueAlongLine(const RS_Vector& coord) const;
|
||||
RS_Vector getMiddlePoint() const override;
|
||||
RS_Vector getNearestEndpoint(const RS_Vector& coord,
|
||||
double* dist = nullptr) const override;
|
||||
RS_Vector getNearestPointOnEntity(const RS_Vector& coord,
|
||||
bool onEntity = true,
|
||||
double* dist = nullptr,
|
||||
RS_Entity** entity=nullptr) const override;
|
||||
//RS_Vector getPointOnEntityAlongLine(const RS_Vector& coord,const double angle,bool onEntity,double* dist,RS_Entity** entity) const;
|
||||
RS_Vector getNearestMiddle(const RS_Vector& coord,
|
||||
double* dist = nullptr,
|
||||
int middlePoints = 1) const override;
|
||||
RS_Vector getNearestDist(double distance,
|
||||
const RS_Vector& coord,
|
||||
double* dist = nullptr) const override;
|
||||
RS_Vector getNearestDist(double distance,
|
||||
bool startp) const override;
|
||||
|
||||
/**
|
||||
* implementations must revert the direction of an atomic entity
|
||||
*/
|
||||
void revertDirection() override;
|
||||
std::vector<RS_Entity* > offsetTwoSides(const double& distance) const override;
|
||||
/**
|
||||
* the modify offset action
|
||||
*/
|
||||
bool offset(const RS_Vector& coord, const double& distance) override;
|
||||
void move(const RS_Vector& offset) override;
|
||||
void rotate(const double& angle);
|
||||
void rotate(const RS_Vector& center, const double& angle) override;
|
||||
void rotate(const RS_Vector& center, const RS_Vector& angleVector) override;
|
||||
void scale(const RS_Vector& factor) override;
|
||||
void scale(const RS_Vector& center, const RS_Vector& factor) override;
|
||||
void mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) override;
|
||||
void stretch(const RS_Vector& firstCorner,
|
||||
const RS_Vector& secondCorner,
|
||||
const RS_Vector& offset) override;
|
||||
void moveRef(const RS_Vector& ref, const RS_Vector& offset) override;
|
||||
|
||||
/** whether the entity's bounding box intersects with visible portion of graphic view */
|
||||
void draw(RS_Painter* painter, RS_GraphicView* view, double& patternOffset) override;
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os, const RS_Line& l);
|
||||
|
||||
void calculateBorders() override;
|
||||
/**
|
||||
* @brief getQuadratic() returns the equation of the entity
|
||||
* for quadratic,
|
||||
*
|
||||
* return a vector contains:
|
||||
* m0 x^2 + m1 xy + m2 y^2 + m3 x + m4 y + m5 =0
|
||||
*
|
||||
* for linear:
|
||||
* m0 x + m1 y + m2 =0
|
||||
*/
|
||||
LC_Quadratic getQuadratic() const override;
|
||||
/**
|
||||
* @brief areaLineIntegral line integral for contour area calculation by Green's Theorem
|
||||
* Contour Area =\oint x dy
|
||||
* @return line integral \oint x dy along the entity
|
||||
* \oint x dy = 0.5*(x0+x1)*(y1-y0)
|
||||
*/
|
||||
double areaLineIntegral() const override;
|
||||
|
||||
protected:
|
||||
RS_LineData data;
|
||||
};
|
||||
|
||||
#endif
|
||||
692
lib/engine/rs_mtext.cpp
Normal file
692
lib/engine/rs_mtext.cpp
Normal file
@@ -0,0 +1,692 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
#include<iostream>
|
||||
#include<cmath>
|
||||
#include "rs_font.h"
|
||||
#include "rs_mtext.h"
|
||||
|
||||
#include "rs_fontlist.h"
|
||||
#include "rs_insert.h"
|
||||
#include "rs_math.h"
|
||||
#include "rs_debug.h"
|
||||
#include "rs_graphicview.h"
|
||||
#include "rs_painter.h"
|
||||
|
||||
RS_MTextData::RS_MTextData(const RS_Vector& _insertionPoint,
|
||||
double _height,
|
||||
double _width,
|
||||
VAlign _valign,
|
||||
HAlign _halign,
|
||||
MTextDrawingDirection _drawingDirection,
|
||||
MTextLineSpacingStyle _lineSpacingStyle,
|
||||
double _lineSpacingFactor,
|
||||
const QString& _text,
|
||||
const QString& _style,
|
||||
double _angle,
|
||||
RS2::UpdateMode _updateMode):
|
||||
insertionPoint(_insertionPoint)
|
||||
,height(_height)
|
||||
,width(_width)
|
||||
,valign(_valign)
|
||||
,halign(_halign)
|
||||
,drawingDirection(_drawingDirection)
|
||||
,lineSpacingStyle(_lineSpacingStyle)
|
||||
,lineSpacingFactor(_lineSpacingFactor)
|
||||
,text(_text)
|
||||
,style(_style)
|
||||
,angle(_angle)
|
||||
,updateMode(_updateMode)
|
||||
{
|
||||
}
|
||||
|
||||
std::ostream& operator << (std::ostream& os, const RS_MTextData& td) {
|
||||
os << "("
|
||||
<<td.insertionPoint<<','
|
||||
<<td.height<<','
|
||||
<<td.width<<','
|
||||
<<td.valign<<','
|
||||
<<td.halign<<','
|
||||
<<td.drawingDirection<<','
|
||||
<<td.lineSpacingStyle<<','
|
||||
<<td.lineSpacingFactor<<','
|
||||
<<td.text.toLatin1().data() <<','
|
||||
<<td.style.toLatin1().data()<<','
|
||||
<<td.angle<<','
|
||||
<<td.updateMode<<','
|
||||
<<")";
|
||||
return os;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
RS_MText::RS_MText(RS_EntityContainer* parent,
|
||||
const RS_MTextData& d)
|
||||
: RS_EntityContainer(parent), data(d) {
|
||||
|
||||
usedTextHeight = 0.0;
|
||||
usedTextWidth = 0.0;
|
||||
setText(data.text);
|
||||
}
|
||||
|
||||
RS_Entity* RS_MText::clone() const{
|
||||
RS_MText* t = new RS_MText(*this);
|
||||
t->setOwner(isOwner());
|
||||
t->initId();
|
||||
t->detach();
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a new text. The entities representing the
|
||||
* text are updated.
|
||||
*/
|
||||
void RS_MText::setText(const QString& t) {
|
||||
data.text = t;
|
||||
|
||||
// handle some special flags embedded in the text:
|
||||
if (data.text.left(4)=="\\A0;") {
|
||||
data.text = data.text.mid(4);
|
||||
data.valign = RS_MTextData::VABottom;
|
||||
} else if (data.text.left(4)=="\\A1;") {
|
||||
data.text = data.text.mid(4);
|
||||
data.valign = RS_MTextData::VAMiddle;
|
||||
} else if (data.text.left(4)=="\\A2;") {
|
||||
data.text = data.text.mid(4);
|
||||
data.valign = RS_MTextData::VATop;
|
||||
}
|
||||
|
||||
if (data.updateMode==RS2::Update) {
|
||||
update();
|
||||
//calculateBorders();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets the alignment as an int.
|
||||
*
|
||||
* @return 1: top left ... 9: bottom right
|
||||
*/
|
||||
int RS_MText::getAlignment() {
|
||||
if (data.valign==RS_MTextData::VATop) {
|
||||
if (data.halign==RS_MTextData::HALeft) {
|
||||
return 1;
|
||||
} else if (data.halign==RS_MTextData::HACenter) {
|
||||
return 2;
|
||||
} else if (data.halign==RS_MTextData::HARight) {
|
||||
return 3;
|
||||
}
|
||||
} else if (data.valign==RS_MTextData::VAMiddle) {
|
||||
if (data.halign==RS_MTextData::HALeft) {
|
||||
return 4;
|
||||
} else if (data.halign==RS_MTextData::HACenter) {
|
||||
return 5;
|
||||
} else if (data.halign==RS_MTextData::HARight) {
|
||||
return 6;
|
||||
}
|
||||
} else if (data.valign==RS_MTextData::VABottom) {
|
||||
if (data.halign==RS_MTextData::HALeft) {
|
||||
return 7;
|
||||
} else if (data.halign==RS_MTextData::HACenter) {
|
||||
return 8;
|
||||
} else if (data.halign==RS_MTextData::HARight) {
|
||||
return 9;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Sets the alignment from an int.
|
||||
*
|
||||
* @param a 1: top left ... 9: bottom right
|
||||
*/
|
||||
void RS_MText::setAlignment(int a) {
|
||||
switch (a%3) {
|
||||
default:
|
||||
case 1:
|
||||
data.halign = RS_MTextData::HALeft;
|
||||
break;
|
||||
case 2:
|
||||
data.halign = RS_MTextData::HACenter;
|
||||
break;
|
||||
case 0:
|
||||
data.halign = RS_MTextData::HARight;
|
||||
break;
|
||||
}
|
||||
|
||||
switch ((int)ceil(a/3.0)) {
|
||||
default:
|
||||
case 1:
|
||||
data.valign = RS_MTextData::VATop;
|
||||
break;
|
||||
case 2:
|
||||
data.valign = RS_MTextData::VAMiddle;
|
||||
break;
|
||||
case 3:
|
||||
data.valign = RS_MTextData::VABottom;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return Number of lines in this text entity.
|
||||
*/
|
||||
int RS_MText::getNumberOfLines() {
|
||||
int c=1;
|
||||
|
||||
for (int i=0; i<(int)data.text.length(); ++i) {
|
||||
if (data.text.at(i).unicode()==0x0A) {
|
||||
c++;
|
||||
}
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Updates the Inserts (letters) of this text. Called when the
|
||||
* text or it's data, position, alignment, .. changes.
|
||||
* This method also updates the usedTextWidth / usedTextHeight property.
|
||||
*/
|
||||
void RS_MText::update()
|
||||
{
|
||||
RS_DEBUG->print("RS_MText::update");
|
||||
|
||||
clear();
|
||||
if (isUndone()) {
|
||||
return;
|
||||
}
|
||||
|
||||
usedTextWidth = 0.0;
|
||||
usedTextHeight = 0.0;
|
||||
|
||||
RS_Font* font {RS_FONTLIST->requestFont( data.style)};
|
||||
if (nullptr == font) {
|
||||
return;
|
||||
}
|
||||
|
||||
RS_Vector letterPos {RS_Vector( 0.0, -9.0)};
|
||||
RS_Vector letterSpace {RS_Vector( font->getLetterSpacing(), 0.0)};
|
||||
RS_Vector space {RS_Vector( font->getWordSpacing(), 0.0)};
|
||||
int lineCounter {0};
|
||||
|
||||
// Every single text line gets stored in this entity container
|
||||
// so we can move the whole line around easily:
|
||||
RS_EntityContainer* oneLine {new RS_EntityContainer(this)};
|
||||
|
||||
// First every text line is created with
|
||||
// alignment: top left
|
||||
// angle: 0
|
||||
// height: 9.0
|
||||
// Rotation, scaling and centering is done later
|
||||
|
||||
// For every letter:
|
||||
for (int i = 0; i < static_cast<int>(data.text.length()); ++i) {
|
||||
bool handled {false};
|
||||
|
||||
switch (data.text.at(i).unicode()) {
|
||||
case 0x0A:
|
||||
// line feed:
|
||||
updateAddLine( oneLine, lineCounter++);
|
||||
oneLine = new RS_EntityContainer(this);
|
||||
letterPos = RS_Vector( 0.0, -9.0);
|
||||
break;
|
||||
|
||||
case 0x20:
|
||||
// Space:
|
||||
letterPos += space;
|
||||
break;
|
||||
|
||||
case 0x5C: {
|
||||
// code (e.g. \S, \P, ..)
|
||||
++i;
|
||||
if (static_cast<int>(data.text.length()) <= i) {
|
||||
continue;
|
||||
}
|
||||
int ch {data.text.at(i).unicode()};
|
||||
switch (ch) {
|
||||
case 'P':
|
||||
updateAddLine( oneLine, lineCounter++);
|
||||
oneLine = new RS_EntityContainer(this);
|
||||
letterPos = RS_Vector( 0.0, -9.0);
|
||||
handled = true;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
case 'F': {
|
||||
//font change
|
||||
// \f{symbol} changes font to symbol
|
||||
// \f{} sets font to standard
|
||||
++i;
|
||||
if ('{' != data.text.at(i).unicode()) {
|
||||
--i;
|
||||
continue;
|
||||
}
|
||||
|
||||
int j {data.text.indexOf( '}', i)};
|
||||
if (j > i) {
|
||||
QString fontName;
|
||||
if (i + 1 == j) {
|
||||
fontName = "standard";
|
||||
}
|
||||
else {
|
||||
fontName = data.text.mid( i + 1, j - i - 1);
|
||||
}
|
||||
|
||||
RS_Font* fontNew {RS_FONTLIST->requestFont( fontName)};
|
||||
if (nullptr != fontNew) {
|
||||
font = fontNew;
|
||||
}
|
||||
if (nullptr == font) {
|
||||
font = RS_FONTLIST->requestFont( "standard");
|
||||
}
|
||||
i = j;
|
||||
}
|
||||
continue;
|
||||
} // inner case 'f','F'
|
||||
|
||||
case 'S': {
|
||||
QString upperText;
|
||||
QString lowerText;
|
||||
|
||||
// get upper string:
|
||||
++i;
|
||||
while (static_cast<int>(data.text.length()) > i
|
||||
&& data.text.at(i).unicode()!='^'
|
||||
&& data.text.at(i).unicode()!='\\') {
|
||||
upperText += data.text.at(i);
|
||||
++i;
|
||||
}
|
||||
|
||||
++i;
|
||||
if (static_cast<int>(data.text.length()) > i
|
||||
&& '^' == data.text.at(i - 1).unicode()
|
||||
&& ' ' == data.text.at(i).unicode() ) {
|
||||
++i;
|
||||
}
|
||||
|
||||
// get lower string:
|
||||
while (static_cast<int>(data.text.length()) > i
|
||||
&& ';' != data.text.at(i).unicode()) {
|
||||
lowerText += data.text.at(i);
|
||||
++i;
|
||||
}
|
||||
|
||||
// add texts:
|
||||
double upperWidth {0.0};
|
||||
if (! upperText.isEmpty()) {
|
||||
RS_MText* upper { new RS_MText( oneLine,
|
||||
RS_MTextData( letterPos + RS_Vector( 0.0, 9.0),
|
||||
4.0,
|
||||
100.0,
|
||||
RS_MTextData::VATop,
|
||||
RS_MTextData::HALeft,
|
||||
RS_MTextData::LeftToRight,
|
||||
RS_MTextData::Exact,
|
||||
1.0,
|
||||
upperText,
|
||||
data.style,
|
||||
0.0,
|
||||
RS2::Update)) };
|
||||
upper->setLayer( nullptr);
|
||||
upper->setPen( RS_Pen( RS2::FlagInvalid));
|
||||
upper->calculateBorders();
|
||||
oneLine->addEntity(upper);
|
||||
upperWidth = upper->getSize().x;
|
||||
}
|
||||
|
||||
double lowerWidth {0.0};
|
||||
if (! lowerText.isEmpty()) {
|
||||
RS_MText* lower { new RS_MText( oneLine,
|
||||
RS_MTextData( letterPos + RS_Vector( 0.0, 4.0),
|
||||
4.0,
|
||||
100.0,
|
||||
RS_MTextData::VATop,
|
||||
RS_MTextData::HALeft,
|
||||
RS_MTextData::LeftToRight,
|
||||
RS_MTextData::Exact,
|
||||
1.0,
|
||||
lowerText,
|
||||
data.style,
|
||||
0.0,
|
||||
RS2::Update)) };
|
||||
lower->setLayer( nullptr);
|
||||
lower->setPen( RS_Pen( RS2::FlagInvalid));
|
||||
lower->calculateBorders();
|
||||
oneLine->addEntity(lower);
|
||||
lowerWidth = lower->getSize().x;
|
||||
}
|
||||
|
||||
if (upperWidth > lowerWidth) {
|
||||
letterPos += RS_Vector( upperWidth, 0.0);
|
||||
}
|
||||
else {
|
||||
letterPos += RS_Vector( lowerWidth, 0.0);
|
||||
}
|
||||
letterPos += letterSpace;
|
||||
handled = true;
|
||||
|
||||
break;
|
||||
} // inner case 'S'
|
||||
|
||||
default:
|
||||
--i;
|
||||
break;
|
||||
} // inner switch (ch)
|
||||
|
||||
if (handled) {
|
||||
break;
|
||||
}
|
||||
} // outer case 0x5C
|
||||
|
||||
// if char is not handled
|
||||
// fall-through
|
||||
default: {
|
||||
// One Letter:
|
||||
QString letterText {QString(data.text.at(i))};
|
||||
if (nullptr == font->findLetter( letterText)) {
|
||||
RS_DEBUG->print("RS_MText::update: missing font for letter( %s ), replaced it with QChar(0xfffd)",
|
||||
qPrintable( letterText));
|
||||
letterText = QChar( 0xfffd);
|
||||
}
|
||||
|
||||
RS_DEBUG->print("RS_MText::update: insert a letter at pos: %f/%f", letterPos.x, letterPos.y);
|
||||
|
||||
RS_InsertData d( letterText,
|
||||
letterPos,
|
||||
RS_Vector( 1.0, 1.0),
|
||||
0.0,
|
||||
1,
|
||||
1,
|
||||
RS_Vector( 0.0, 0.0),
|
||||
font->getLetterList(),
|
||||
RS2::NoUpdate);
|
||||
|
||||
RS_Insert* letter {new RS_Insert(this, d)};
|
||||
RS_Vector letterWidth;
|
||||
letter->setPen( RS_Pen( RS2::FlagInvalid));
|
||||
letter->setLayer( nullptr);
|
||||
letter->update();
|
||||
letter->forcedCalculateBorders();
|
||||
|
||||
letterWidth = RS_Vector( letter->getMax().x - letterPos.x, 0.0);
|
||||
if (0 > letterWidth.x) {
|
||||
letterWidth.x = -letterSpace.x;
|
||||
}
|
||||
|
||||
oneLine->addEntity( letter);
|
||||
|
||||
// next letter position:
|
||||
letterPos += letterWidth;
|
||||
letterPos += letterSpace;
|
||||
|
||||
break;
|
||||
} // outer default
|
||||
} // outer switch (data.text.at(i).unicode())
|
||||
} // for (i) loop
|
||||
|
||||
double tt {updateAddLine( oneLine, lineCounter)};
|
||||
if (RS_MTextData::VABottom == data.valign) {
|
||||
RS_Vector ot {RS_Vector( 0.0, -tt).rotate( data.angle)};
|
||||
RS_EntityContainer::move( ot);
|
||||
}
|
||||
|
||||
usedTextHeight -= data.height * data.lineSpacingFactor * 5.0 / 3.0 - data.height;
|
||||
forcedCalculateBorders();
|
||||
|
||||
RS_DEBUG->print("RS_MText::update: OK");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Used internally by update() to add a text line created with
|
||||
* default values and alignment to this text container.
|
||||
*
|
||||
* @param textLine The text line.
|
||||
* @param lineCounter Line number.
|
||||
*
|
||||
* @return distance over the text base-line
|
||||
*/
|
||||
double RS_MText::updateAddLine(RS_EntityContainer* textLine, int lineCounter) {
|
||||
double ls =5.0/3.0;
|
||||
|
||||
RS_DEBUG->print("RS_MText::updateAddLine: width: %f", textLine->getSize().x);
|
||||
|
||||
//textLine->forcedCalculateBorders();
|
||||
//RS_DEBUG->print("RS_MText::updateAddLine: width 2: %f", textLine->getSize().x);
|
||||
|
||||
// Move to correct line position:
|
||||
textLine->move(RS_Vector(0.0, -9.0 * lineCounter
|
||||
* data.lineSpacingFactor * ls));
|
||||
|
||||
if( ! RS_EntityContainer::autoUpdateBorders) {
|
||||
//only update borders when needed
|
||||
textLine->forcedCalculateBorders();
|
||||
}
|
||||
RS_Vector textSize = textLine->getSize();
|
||||
|
||||
RS_DEBUG->print("RS_MText::updateAddLine: width 2: %f", textSize.x);
|
||||
|
||||
// Horizontal Align:
|
||||
switch (data.halign) {
|
||||
case RS_MTextData::HACenter:
|
||||
RS_DEBUG->print("RS_MText::updateAddLine: move by: %f", -textSize.x/2.0);
|
||||
textLine->move(RS_Vector(-textSize.x/2.0, 0.0));
|
||||
break;
|
||||
|
||||
case RS_MTextData::HARight:
|
||||
textLine->move(RS_Vector(-textSize.x, 0.0));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Vertical Align:
|
||||
double vSize = getNumberOfLines()*9.0*data.lineSpacingFactor*ls
|
||||
- (9.0*data.lineSpacingFactor*ls - 9.0);
|
||||
|
||||
switch (data.valign) {
|
||||
case RS_MTextData::VAMiddle:
|
||||
textLine->move(RS_Vector(0.0, vSize/2.0));
|
||||
break;
|
||||
|
||||
case RS_MTextData::VABottom:
|
||||
textLine->move(RS_Vector(0.0, vSize));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Scale:
|
||||
textLine->scale(RS_Vector(0.0,0.0),
|
||||
RS_Vector(data.height/9.0, data.height/9.0));
|
||||
|
||||
textLine->forcedCalculateBorders();
|
||||
|
||||
// Update actual text size (before rotating, after scaling!):
|
||||
if (textLine->getSize().x>usedTextWidth) {
|
||||
usedTextWidth = textLine->getSize().x;
|
||||
}
|
||||
|
||||
usedTextHeight += data.height*data.lineSpacingFactor*ls;
|
||||
|
||||
// Gets the distance over text base-line (before rotating, after scaling!):
|
||||
double textTail = textLine->getMin().y;
|
||||
|
||||
// Rotate:
|
||||
textLine->rotate(RS_Vector(0.0,0.0), data.angle);
|
||||
|
||||
// Move:
|
||||
textLine->move(data.insertionPoint);
|
||||
textLine->setPen(RS_Pen(RS2::FlagInvalid));
|
||||
textLine->setLayer(NULL);
|
||||
textLine->forcedCalculateBorders();
|
||||
|
||||
addEntity(textLine);
|
||||
return textTail;
|
||||
}
|
||||
|
||||
|
||||
RS_Vector RS_MText::getNearestEndpoint(const RS_Vector& coord, double* dist)const {
|
||||
if (dist) {
|
||||
*dist = data.insertionPoint.distanceTo(coord);
|
||||
}
|
||||
return data.insertionPoint;
|
||||
}
|
||||
|
||||
|
||||
RS_VectorSolutions RS_MText::getRefPoints() const{
|
||||
return RS_VectorSolutions({data.insertionPoint});
|
||||
}
|
||||
|
||||
void RS_MText::move(const RS_Vector& offset) {
|
||||
RS_EntityContainer::move(offset);
|
||||
data.insertionPoint.move(offset);
|
||||
// update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_MText::rotate(const RS_Vector& center, const double& angle) {
|
||||
RS_Vector angleVector(angle);
|
||||
RS_EntityContainer::rotate(center, angleVector);
|
||||
data.insertionPoint.rotate(center, angleVector);
|
||||
data.angle = RS_Math::correctAngle(data.angle+angle);
|
||||
// update();
|
||||
}
|
||||
void RS_MText::rotate(const RS_Vector& center, const RS_Vector& angleVector) {
|
||||
RS_EntityContainer::rotate(center, angleVector);
|
||||
data.insertionPoint.rotate(center, angleVector);
|
||||
data.angle = RS_Math::correctAngle(data.angle+angleVector.angle());
|
||||
// update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_MText::scale(const RS_Vector& center, const RS_Vector& factor) {
|
||||
data.insertionPoint.scale(center, factor);
|
||||
data.width*=factor.x;
|
||||
data.height*=factor.x;
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RS_MText::mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) {
|
||||
data.insertionPoint.mirror(axisPoint1, axisPoint2);
|
||||
//double ang = axisPoint1.angleTo(axisPoint2);
|
||||
bool readable = RS_Math::isAngleReadable(data.angle);
|
||||
|
||||
RS_Vector vec = RS_Vector::polar(1.0, data.angle);
|
||||
vec.mirror(RS_Vector(0.0,0.0), axisPoint2-axisPoint1);
|
||||
data.angle = vec.angle();
|
||||
|
||||
bool corr;
|
||||
data.angle = RS_Math::makeAngleReadable(data.angle, readable, &corr);
|
||||
|
||||
if (corr) {
|
||||
if (data.halign==RS_MTextData::HALeft) {
|
||||
data.halign=RS_MTextData::HARight;
|
||||
} else if (data.halign==RS_MTextData::HARight) {
|
||||
data.halign=RS_MTextData::HALeft;
|
||||
}
|
||||
} else {
|
||||
if (data.valign==RS_MTextData::VATop) {
|
||||
data.valign=RS_MTextData::VABottom;
|
||||
} else if (data.valign==RS_MTextData::VABottom) {
|
||||
data.valign=RS_MTextData::VATop;
|
||||
}
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool RS_MText::hasEndpointsWithinWindow(const RS_Vector& /*v1*/, const RS_Vector& /*v2*/) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Implementations must stretch the given range of the entity
|
||||
* by the given offset.
|
||||
*/
|
||||
void RS_MText::stretch(const RS_Vector& firstCorner, const RS_Vector& secondCorner, const RS_Vector& offset) {
|
||||
|
||||
if (getMin().isInWindow(firstCorner, secondCorner) &&
|
||||
getMax().isInWindow(firstCorner, secondCorner)) {
|
||||
|
||||
move(offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Dumps the point's data to stdout.
|
||||
*/
|
||||
std::ostream& operator << (std::ostream& os, const RS_MText& p) {
|
||||
os << " Text: " << p.getData() << "\n";
|
||||
return os;
|
||||
}
|
||||
|
||||
void RS_MText::draw(RS_Painter* painter, RS_GraphicView* view, double& /*patternOffset*/)
|
||||
{
|
||||
if (!(painter && view)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!view->isPrintPreview() && !view->isPrinting())
|
||||
{
|
||||
if (view->isPanning() || view->toGuiDY(getHeight()) < 4)
|
||||
{
|
||||
painter->drawRect(view->toGui(getMin()), view->toGui(getMax()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (auto e, entities)
|
||||
{
|
||||
view->drawEntity(painter, e);
|
||||
}
|
||||
}
|
||||
276
lib/engine/rs_mtext.h
Normal file
276
lib/engine/rs_mtext.h
Normal file
@@ -0,0 +1,276 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_MTEXT_H
|
||||
#define RS_MTEXT_H
|
||||
|
||||
#include "rs_entitycontainer.h"
|
||||
|
||||
/**
|
||||
* Holds the data that defines a text entity.
|
||||
*/
|
||||
struct RS_MTextData {
|
||||
/**
|
||||
* Vertical alignments.
|
||||
*/
|
||||
enum VAlign {
|
||||
VATop, /**< Top. */
|
||||
VAMiddle, /**< Middle */
|
||||
VABottom /**< Bottom */
|
||||
};
|
||||
|
||||
/**
|
||||
* Horizontal alignments.
|
||||
*/
|
||||
enum HAlign {
|
||||
HALeft, /**< Left */
|
||||
HACenter, /**< Centered */
|
||||
HARight /**< Right */
|
||||
};
|
||||
|
||||
/**
|
||||
* MText drawing direction.
|
||||
*/
|
||||
enum MTextDrawingDirection {
|
||||
LeftToRight, /**< Left to right */
|
||||
TopToBottom, /**< Top to bottom */
|
||||
ByStyle /**< Inherited from associated text style */
|
||||
};
|
||||
|
||||
/**
|
||||
* Line spacing style for MTexts.
|
||||
*/
|
||||
enum MTextLineSpacingStyle {
|
||||
AtLeast, /**< Taller characters will override */
|
||||
Exact /**< Taller characters will not override */
|
||||
};
|
||||
|
||||
/**
|
||||
* Default constructor. Leaves the data object uninitialized.
|
||||
*/
|
||||
RS_MTextData() = default;
|
||||
|
||||
/**
|
||||
* Constructor with initialisation.
|
||||
*
|
||||
* @param insertionPoint Insertion point
|
||||
* @param height Nominal (initial) text height
|
||||
* @param width Reference rectangle width
|
||||
* @param valign Vertical alignment
|
||||
* @param halign Horizontal alignment
|
||||
* @param drawingDirection Drawing direction
|
||||
* @param lineSpacingStyle Line spacing style
|
||||
* @param lineSpacingFactor Line spacing factor
|
||||
* @param text Text string
|
||||
* @param style Text style name
|
||||
* @param angle Rotation angle
|
||||
* @param updateMode RS2::Update will update the text entity instantly
|
||||
* RS2::NoUpdate will not update the entity. You can update
|
||||
* it later manually using the update() method. This is
|
||||
* often the case since you might want to adjust attributes
|
||||
* after creating a text entity.
|
||||
*/
|
||||
RS_MTextData(const RS_Vector& insertionPoint,
|
||||
double height,
|
||||
double width,
|
||||
VAlign valign,
|
||||
HAlign halign,
|
||||
MTextDrawingDirection drawingDirection,
|
||||
MTextLineSpacingStyle lineSpacingStyle,
|
||||
double lineSpacingFactor,
|
||||
const QString& text,
|
||||
const QString& style,
|
||||
double angle,
|
||||
RS2::UpdateMode updateMode = RS2::Update);
|
||||
|
||||
/** Insertion point */
|
||||
RS_Vector insertionPoint;
|
||||
/** Nominal (initial) text height */
|
||||
double height;
|
||||
/** Reference rectangle width */
|
||||
double width;
|
||||
/** Vertical alignment */
|
||||
VAlign valign;
|
||||
/** Horizontal alignment */
|
||||
HAlign halign;
|
||||
/** Drawing direction */
|
||||
MTextDrawingDirection drawingDirection;
|
||||
/** Line spacing style */
|
||||
MTextLineSpacingStyle lineSpacingStyle;
|
||||
/** Line spacing factor */
|
||||
double lineSpacingFactor;
|
||||
/** Text string */
|
||||
QString text;
|
||||
/** Text style name */
|
||||
QString style;
|
||||
/** Rotation angle */
|
||||
double angle;
|
||||
/** Update mode */
|
||||
RS2::UpdateMode updateMode;
|
||||
};
|
||||
|
||||
std::ostream& operator << (std::ostream& os, const RS_MTextData& td);
|
||||
|
||||
|
||||
/**
|
||||
* Class for a text entity.
|
||||
* Please note that text strings can contain special
|
||||
* characters such as %%c for a diameter sign as well as unicode
|
||||
* characters. Line feeds are stored as real line feeds in the string.
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_MText : public RS_EntityContainer {
|
||||
public:
|
||||
RS_MText(RS_EntityContainer* parent,
|
||||
const RS_MTextData& d);
|
||||
virtual ~RS_MText() = default;
|
||||
|
||||
virtual RS_Entity* clone() const override;
|
||||
|
||||
/** @return RS2::EntityText */
|
||||
virtual RS2::EntityType rtti() const override{
|
||||
return RS2::EntityMText;
|
||||
}
|
||||
|
||||
/** @return Copy of data that defines the text. */
|
||||
RS_MTextData getData() const {
|
||||
return data;
|
||||
}
|
||||
|
||||
void update() override;
|
||||
|
||||
int getNumberOfLines();
|
||||
|
||||
|
||||
RS_Vector getInsertionPoint() {
|
||||
return data.insertionPoint;
|
||||
}
|
||||
double getHeight() {
|
||||
return data.height;
|
||||
}
|
||||
void setHeight(double h) {
|
||||
data.height = h;
|
||||
}
|
||||
double getWidth() {
|
||||
return data.width;
|
||||
}
|
||||
void setAlignment(int a);
|
||||
int getAlignment();
|
||||
RS_MTextData::VAlign getVAlign() {
|
||||
return data.valign;
|
||||
}
|
||||
void setVAlign(RS_MTextData::VAlign va) {
|
||||
data.valign = va;
|
||||
}
|
||||
RS_MTextData::HAlign getHAlign() {
|
||||
return data.halign;
|
||||
}
|
||||
void setHAlign(RS_MTextData::HAlign ha) {
|
||||
data.halign = ha;
|
||||
}
|
||||
RS_MTextData::MTextDrawingDirection getDrawingDirection() {
|
||||
return data.drawingDirection;
|
||||
}
|
||||
RS_MTextData::MTextLineSpacingStyle getLineSpacingStyle() {
|
||||
return data.lineSpacingStyle;
|
||||
}
|
||||
void setLineSpacingFactor(double f) {
|
||||
data.lineSpacingFactor = f;
|
||||
}
|
||||
double getLineSpacingFactor() {
|
||||
return data.lineSpacingFactor;
|
||||
}
|
||||
void setText(const QString& t);
|
||||
QString getText() {
|
||||
return data.text;
|
||||
}
|
||||
void setStyle(const QString& s) {
|
||||
data.style = s;
|
||||
}
|
||||
QString getStyle() {
|
||||
return data.style;
|
||||
}
|
||||
void setAngle(double a) {
|
||||
data.angle = a;
|
||||
}
|
||||
double getAngle() {
|
||||
return data.angle;
|
||||
}
|
||||
double getUsedTextWidth() {
|
||||
return usedTextWidth;
|
||||
}
|
||||
double getUsedTextHeight() {
|
||||
return usedTextHeight;
|
||||
}
|
||||
|
||||
// virtual double getLength() const {
|
||||
// return -1.0;
|
||||
// }
|
||||
|
||||
/**
|
||||
* @return The insertion point as endpoint.
|
||||
*/
|
||||
virtual RS_Vector getNearestEndpoint(const RS_Vector& coord,
|
||||
double* dist = NULL)const override;
|
||||
virtual RS_VectorSolutions getRefPoints() const override;
|
||||
|
||||
virtual void move(const RS_Vector& offset) override;
|
||||
virtual void rotate(const RS_Vector& center, const double& angle) override;
|
||||
virtual void rotate(const RS_Vector& center, const RS_Vector& angleVector) override;
|
||||
virtual void scale(const RS_Vector& center, const RS_Vector& factor) override;
|
||||
virtual void mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) override;
|
||||
virtual bool hasEndpointsWithinWindow(const RS_Vector& v1, const RS_Vector& v2) override;
|
||||
virtual void stretch(const RS_Vector& firstCorner,
|
||||
const RS_Vector& secondCorner,
|
||||
const RS_Vector& offset) override;
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os, const RS_Text& p);
|
||||
|
||||
void draw(RS_Painter* painter, RS_GraphicView* view, double& patternOffset) override;
|
||||
|
||||
private:
|
||||
double updateAddLine(RS_EntityContainer* textLine, int lineCounter);
|
||||
|
||||
protected:
|
||||
RS_MTextData data;
|
||||
|
||||
/**
|
||||
* Text width used by the current contents of this text entity.
|
||||
* This property is updated by the update method.
|
||||
* @see update
|
||||
*/
|
||||
double usedTextWidth;
|
||||
/**
|
||||
* Text height used by the current contents of this text entity.
|
||||
* This property is updated by the update method.
|
||||
* @see update
|
||||
*/
|
||||
double usedTextHeight;
|
||||
};
|
||||
|
||||
#endif
|
||||
93
lib/engine/rs_overlaybox.cpp
Normal file
93
lib/engine/rs_overlaybox.cpp
Normal file
@@ -0,0 +1,93 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
#include<iostream>
|
||||
#include "rs_overlaybox.h"
|
||||
|
||||
#include "rs_debug.h"
|
||||
#include "rs_graphicview.h"
|
||||
#include "rs_painter.h"
|
||||
#include "rs_graphic.h"
|
||||
#include <QBrush>
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
RS_OverlayBox::RS_OverlayBox(RS_EntityContainer* parent,
|
||||
const RS_OverlayBoxData& d)
|
||||
:RS_AtomicEntity(parent), data(d) {
|
||||
}
|
||||
|
||||
RS_Entity* RS_OverlayBox::clone() const{
|
||||
RS_OverlayBox* l = new RS_OverlayBox(*this);
|
||||
l->initId();
|
||||
return l;
|
||||
}
|
||||
|
||||
void RS_OverlayBox::draw(RS_Painter* painter, RS_GraphicView* view, double& /*patternOffset*/) {
|
||||
if (painter==NULL || view==NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
RS_Vector v1=view->toGui(getCorner1());
|
||||
RS_Vector v2=view->toGui(getCorner2());
|
||||
|
||||
QRectF selectRect(
|
||||
v1.x,
|
||||
v1.y,
|
||||
v2.x - v1.x,
|
||||
v2.y - v1.y);
|
||||
|
||||
if (v1.x > v2.x) {
|
||||
RS_Pen p(RS_Color(50,255,50),RS2::Width00,RS2::DashLine);
|
||||
painter->setPen(p);
|
||||
// painter->setPen(QColor(50, 255, 50));
|
||||
painter->fillRect(selectRect, RS_Color(9, 255, 9, 90));
|
||||
}
|
||||
else {
|
||||
painter->setPen(QColor(50, 50, 255));
|
||||
painter->fillRect(selectRect, RS_Color(9, 9, 255, 90));
|
||||
}
|
||||
|
||||
painter->drawRect(v1, v2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps the point's data to stdout.
|
||||
*/
|
||||
std::ostream& operator << (std::ostream& os, const RS_OverlayBox& l) {
|
||||
os << " Line: " << l.getData() << "\n";
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream& operator << (std::ostream& os, const RS_OverlayBoxData& ld) {
|
||||
os << "(" << ld.corner1 <<
|
||||
"/" << ld.corner2 <<
|
||||
")";
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
104
lib/engine/rs_overlaybox.h
Normal file
104
lib/engine/rs_overlaybox.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_OVERLAYBOX_H
|
||||
#define RS_OVERLAYBOX_H
|
||||
|
||||
#include "rs_atomicentity.h"
|
||||
|
||||
/**
|
||||
* Holds the data that defines a line.
|
||||
*/
|
||||
class RS_OverlayBoxData {
|
||||
public:
|
||||
/**
|
||||
* Default constructor. Leaves the data object uninitialized.
|
||||
*/
|
||||
RS_OverlayBoxData() = default;
|
||||
|
||||
RS_OverlayBoxData(const RS_Vector& corner1, const RS_Vector& corner2)
|
||||
: corner1(corner1), corner2(corner2) {}
|
||||
|
||||
friend class RS_OverlayBox;
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os, const RS_OverlayBoxData& ld);
|
||||
|
||||
public:
|
||||
RS_Vector corner1;
|
||||
RS_Vector corner2;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Class for a line entity.
|
||||
*
|
||||
* @author R. van Twisk
|
||||
*/
|
||||
class RS_OverlayBox : public RS_AtomicEntity {
|
||||
public:
|
||||
RS_OverlayBox(RS_EntityContainer* parent, const RS_OverlayBoxData& d);
|
||||
RS_Entity* clone() const override;
|
||||
|
||||
/** @return RS2::EntityLine */
|
||||
RS2::EntityType rtti() const override{
|
||||
return RS2::EntityOverlayBox;
|
||||
}
|
||||
void draw(RS_Painter* painter, RS_GraphicView* view, double& patternOffset) override;
|
||||
|
||||
/** @return Start point of the entity */
|
||||
RS_Vector getCorner1() const {
|
||||
return data.corner1;
|
||||
}
|
||||
/** @return End point of the entity */
|
||||
RS_Vector getCorner2() const {
|
||||
return data.corner2;
|
||||
}
|
||||
/** @return Copy of data that defines the line. */
|
||||
RS_OverlayBoxData getData() const {
|
||||
return data;
|
||||
}
|
||||
|
||||
/** We should make a separate drawing mechanism for overlays and not use entities */
|
||||
void move(const RS_Vector& /*offset*/)override{}
|
||||
void rotate(const RS_Vector& /*center*/, const double& /*angle*/)override{}
|
||||
void rotate(const RS_Vector& /*center*/, const RS_Vector& /*angleVector*/)override{}
|
||||
void scale(const RS_Vector& /*center*/, const RS_Vector& /*factor*/)override{}
|
||||
void mirror(const RS_Vector& /*axisPoint1*/, const RS_Vector& /*axisPoint2*/)override{}
|
||||
void calculateBorders() override{}
|
||||
RS_Vector getNearestEndpoint(const RS_Vector&, double*)const override{return {};}
|
||||
RS_Vector getNearestPointOnEntity(const RS_Vector&, bool, double*, RS_Entity**)const override{return {};}
|
||||
RS_Vector getNearestCenter(const RS_Vector&, double*)const override{return {};}
|
||||
RS_Vector getNearestMiddle(const RS_Vector&, double*,int)const override{return {};}
|
||||
RS_Vector getNearestDist(double, const RS_Vector&, double*)const override{return {};}
|
||||
double getDistanceToPoint(const RS_Vector&, RS_Entity**, RS2::ResolveLevel, double)const override{return -1;}//is -1 right here
|
||||
|
||||
protected:
|
||||
RS_OverlayBoxData data;
|
||||
}
|
||||
;
|
||||
|
||||
#endif
|
||||
48
lib/engine/rs_overlayline.cpp
Normal file
48
lib/engine/rs_overlayline.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#include "rs_overlayline.h"
|
||||
#include "rs_painter.h"
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
RS_OverlayLine::RS_OverlayLine(RS_EntityContainer* parent,
|
||||
const RS_LineData& d)
|
||||
:RS_Line(parent, d) {
|
||||
}
|
||||
|
||||
|
||||
void RS_OverlayLine::draw(RS_Painter* painter, RS_GraphicView* view, double& /*patternOffset*/) {
|
||||
if (painter==NULL || view==NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
painter->drawLine(getStartpoint(),
|
||||
getEndpoint());
|
||||
|
||||
}
|
||||
53
lib/engine/rs_overlayline.h
Normal file
53
lib/engine/rs_overlayline.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_OVERLAYLINE_H
|
||||
#define RS_OVERLAYLINE_H
|
||||
|
||||
#include "rs_line.h"
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Class for a overlay line entity. It's used to draw lines on the overlay paint event
|
||||
* The main difference is that the coordinates are actual screen coordinates and not real world coordinates
|
||||
*
|
||||
* @author R. van Twisk
|
||||
*/
|
||||
class RS_OverlayLine : public RS_Line {
|
||||
public:
|
||||
RS_OverlayLine(RS_EntityContainer* parent, const RS_LineData& d);
|
||||
|
||||
virtual void draw(RS_Painter* painter, RS_GraphicView* view, double& patternOffset) override;
|
||||
|
||||
RS2::EntityType rtti() const override{
|
||||
return RS2::EntityOverlayLine;
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
#endif
|
||||
119
lib/engine/rs_pattern.cpp
Normal file
119
lib/engine/rs_pattern.cpp
Normal file
@@ -0,0 +1,119 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#include "rs_pattern.h"
|
||||
|
||||
#include "rs_system.h"
|
||||
#include "rs_fileio.h"
|
||||
#include "rs_layer.h"
|
||||
#include "rs_debug.h"
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param fileName File name of a DXF file defining the pattern
|
||||
*/
|
||||
RS_Pattern::RS_Pattern(const QString& fileName)
|
||||
: RS_EntityContainer(NULL)
|
||||
,fileName(fileName)
|
||||
,loaded(false)
|
||||
{
|
||||
RS_DEBUG->print("RS_Pattern::RS_Pattern() ");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Loads the given pattern file into this pattern.
|
||||
* Entities other than lines are ignored.
|
||||
*
|
||||
* @param filename File name of the pattern file (without path and
|
||||
* extension or full path.
|
||||
*/
|
||||
bool RS_Pattern::loadPattern() {
|
||||
if (loaded) {
|
||||
return true;
|
||||
}
|
||||
|
||||
RS_DEBUG->print("RS_Pattern::loadPattern");
|
||||
|
||||
QString path;
|
||||
|
||||
// Search for the appropriate pattern if we have only the name of the pattern:
|
||||
if (!fileName.toLower().contains(".dxf")) {
|
||||
QStringList patterns = RS_SYSTEM->getPatternList();
|
||||
QFileInfo file;
|
||||
for (QStringList::Iterator it = patterns.begin();
|
||||
it!=patterns.end();
|
||||
it++) {
|
||||
|
||||
if (QFileInfo(*it).baseName().toLower()==fileName.toLower()) {
|
||||
path = *it;
|
||||
RS_DEBUG->print("Pattern found: %s", path.toLatin1().data());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We have the full path of the pattern:
|
||||
else {
|
||||
path = fileName;
|
||||
}
|
||||
|
||||
// No pattern paths found:
|
||||
if (path.isEmpty()) {
|
||||
RS_DEBUG->print("No pattern \"%s\"available.", fileName.toLatin1().data());
|
||||
return false;
|
||||
}
|
||||
|
||||
RS_Graphic gr;
|
||||
RS_FileIO::instance()->fileImport(gr, path);
|
||||
for(auto e: gr){
|
||||
if (e->rtti()==RS2::EntityLine ||
|
||||
e->rtti()==RS2::EntityArc||
|
||||
e->rtti()==RS2::EntityEllipse
|
||||
) {
|
||||
RS_Layer* l = e->getLayer();
|
||||
RS_Entity* cl = e->clone();
|
||||
cl->reparent(this);
|
||||
if (l) {
|
||||
cl->setLayer(l->getName());
|
||||
}
|
||||
addEntity(cl);
|
||||
}
|
||||
}
|
||||
|
||||
loaded = true;
|
||||
RS_DEBUG->print("RS_Pattern::loadPattern: OK");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QString RS_Pattern::getFileName() const {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
65
lib/engine/rs_pattern.h
Normal file
65
lib/engine/rs_pattern.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_PATTERN_H
|
||||
#define RS_PATTERN_H
|
||||
|
||||
#include "rs_entitycontainer.h"
|
||||
|
||||
class RS_PatternList;
|
||||
|
||||
/**
|
||||
* Patterns are used for hatches. They are stored in a RS_PatternList.
|
||||
* Use RS_PatternList to access a pattern.
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_Pattern : public RS_EntityContainer {
|
||||
public:
|
||||
RS_Pattern(const QString& fileName);
|
||||
virtual ~RS_Pattern()=default;
|
||||
RS2::EntityType rtti() const{
|
||||
return RS2::EntityPattern;
|
||||
}
|
||||
|
||||
virtual bool loadPattern();
|
||||
|
||||
/** @return the fileName of this pattern. */
|
||||
QString getFileName() const;
|
||||
|
||||
protected:
|
||||
//! Pattern file name
|
||||
QString fileName;
|
||||
|
||||
//! Is this pattern currently loaded into memory?
|
||||
bool loaded;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
112
lib/engine/rs_patternlist.cpp
Normal file
112
lib/engine/rs_patternlist.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
#include<iostream>
|
||||
#include<QString>
|
||||
#include "rs_patternlist.h"
|
||||
|
||||
#include "rs_system.h"
|
||||
#include "rs_pattern.h"
|
||||
#include "rs_debug.h"
|
||||
|
||||
RS_PatternList* RS_PatternList::instance() {
|
||||
static RS_PatternList instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
|
||||
RS_PatternList::~RS_PatternList() = default;
|
||||
|
||||
/**
|
||||
* Initializes the pattern list by creating empty RS_Pattern
|
||||
* objects, one for each pattern that could be found.
|
||||
*/
|
||||
void RS_PatternList::init() {
|
||||
RS_DEBUG->print("RS_PatternList::initPatterns");
|
||||
|
||||
QStringList list = RS_SYSTEM->getPatternList();
|
||||
|
||||
patterns.clear();
|
||||
|
||||
for (auto const& s: list) {
|
||||
RS_DEBUG->print("pattern: %s:", s.toLatin1().data());
|
||||
|
||||
QFileInfo fi(s);
|
||||
QString const name = fi.baseName().toLower();
|
||||
patterns[name] = std::unique_ptr<RS_Pattern>{};
|
||||
|
||||
RS_DEBUG->print("base: %s", name.toLatin1().data());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Pointer to the pattern with the given name or
|
||||
* \p NULL if no such pattern was found. The pattern will be loaded into
|
||||
* memory if it's not already.
|
||||
*/
|
||||
RS_Pattern* RS_PatternList::requestPattern(const QString& name) {
|
||||
RS_DEBUG->print("RS_PatternList::requestPattern %s", name.toLatin1().data());
|
||||
|
||||
QString name2 = name.toLower();
|
||||
|
||||
RS_DEBUG->print("name2: %s", name2.toLatin1().data());
|
||||
if (patterns.count(name2)) {
|
||||
if (!patterns[name2]) {
|
||||
RS_Pattern* p = new RS_Pattern(name2);
|
||||
p->loadPattern();
|
||||
patterns[name2].reset(p);
|
||||
}
|
||||
RS_DEBUG->print("name2: %s, size= %d", name2.toLatin1().data(),
|
||||
patterns[name2]->countDeep());
|
||||
return patterns[name2].get();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool RS_PatternList::contains(const QString& name) const {
|
||||
|
||||
return patterns.count(name.toLower());
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Dumps the patterns to stdout.
|
||||
*/
|
||||
std::ostream& operator << (std::ostream& os, RS_PatternList& l) {
|
||||
|
||||
os << "Patternlist: \n";
|
||||
for (auto const& pa: l.patterns)
|
||||
if (pa.second)
|
||||
os<< *pa.second << '\n';
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
94
lib/engine/rs_patternlist.h
Normal file
94
lib/engine/rs_patternlist.h
Normal file
@@ -0,0 +1,94 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of the LibreCAD project, a 2D CAD program
|
||||
**
|
||||
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
|
||||
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
|
||||
**
|
||||
**
|
||||
** This file may be distributed and/or modified under the terms of the
|
||||
** GNU General Public License version 2 as published by the Free Software
|
||||
** Foundation and appearing in the file gpl-2.0.txt included in the
|
||||
** packaging of this file.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
**
|
||||
** This copyright notice MUST APPEAR in all copies of the script!
|
||||
**
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef RS_PATTERNLIST_H
|
||||
#define RS_PATTERNLIST_H
|
||||
|
||||
#include<map>
|
||||
#include<memory>
|
||||
|
||||
class RS_Pattern;
|
||||
class QString;
|
||||
|
||||
#define RS_PATTERNLIST RS_PatternList::instance()
|
||||
|
||||
/**
|
||||
* The global list of patterns. This is implemented as a singleton.
|
||||
* Use RS_PatternList::instance() to get a pointer to the object.
|
||||
*
|
||||
* @author Andrew Mustun
|
||||
*/
|
||||
class RS_PatternList {
|
||||
using PTN_MAP = std::map<QString, std::unique_ptr<RS_Pattern>>;
|
||||
RS_PatternList() = default;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @return Instance to the unique pattern list.
|
||||
*/
|
||||
static RS_PatternList* instance();
|
||||
|
||||
~RS_PatternList();
|
||||
RS_PatternList(RS_PatternList const&) = delete;
|
||||
RS_PatternList& operator = (RS_PatternList const&) = delete;
|
||||
RS_PatternList(RS_PatternList &&) = delete;
|
||||
RS_PatternList& operator = (RS_PatternList &&) = delete;
|
||||
|
||||
void init();
|
||||
|
||||
int countPatterns() const {
|
||||
return patterns.size();
|
||||
}
|
||||
|
||||
//! \{ range based loop support
|
||||
PTN_MAP::iterator begin() {
|
||||
return patterns.begin();
|
||||
}
|
||||
PTN_MAP::const_iterator begin() const{
|
||||
return patterns.begin();
|
||||
}
|
||||
PTN_MAP::iterator end() {
|
||||
return patterns.end();
|
||||
}
|
||||
PTN_MAP::const_iterator end() const{
|
||||
return patterns.end();
|
||||
}
|
||||
//! \}
|
||||
|
||||
RS_Pattern* requestPattern(const QString& name);
|
||||
|
||||
bool contains(const QString& name) const;
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os, RS_PatternList& l);
|
||||
|
||||
|
||||
private:
|
||||
//! patterns in the graphic
|
||||
PTN_MAP patterns;
|
||||
};
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user