Files
newspark110/lib/actions/rs_snapper.cpp
Chenwenxuan edac2715f0 init
2024-03-06 14:54:30 +08:00

1017 lines
30 KiB
C++

/****************************************************************************
**
** 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<cmath>
#include<QMouseEvent>
#include "rs_snapper.h"
#include "rs_point.h"
#include "rs_circle.h"
#include "rs_line.h"
#include "rs_dialogfactory.h"
#include "rs_graphicview.h"
#include "rs_grid.h"
#include "rs_settings.h"
#include "rs_overlayline.h"
#include "rs_coordinateevent.h"
#include "rs_entitycontainer.h"
#include "rs_pen.h"
#include "rs_debug.h"
/**
* Disable all snapping.
*
* This effectively puts the object into free snap mode.
*
* @returns A reference to itself.
*/
RS_SnapMode const & RS_SnapMode::clear()
{
snapIntersection = false;
snapOnEntity = false;
snapCenter = false;
snapDistance = false;
snapMiddle = false;
snapEndpoint = false;
snapGrid = false;
snapFree = false;
snapAngle = false;
restriction = RS2::RestrictNothing;
return *this;
}
bool RS_SnapMode::operator ==(RS_SnapMode const& rhs) const
{
return snapIntersection == rhs.snapIntersection
&& snapOnEntity == rhs.snapOnEntity
&& snapCenter == rhs.snapCenter
&& snapDistance == rhs.snapDistance
&& snapMiddle == rhs.snapMiddle
&& snapEndpoint == rhs.snapEndpoint
&& snapGrid == rhs.snapGrid
&& snapFree == rhs.snapFree
&& restriction == rhs.restriction
&& snapAngle == rhs.snapAngle;
}
/**
* snap mode to a flag integer
*/
uint RS_SnapMode::toInt(const RS_SnapMode& s)
{
uint ret {0};
if (s.snapIntersection) ret |= RS_SnapMode::SnapIntersection;
if (s.snapOnEntity) ret |= RS_SnapMode::SnapOnEntity;
if (s.snapCenter) ret |= RS_SnapMode::SnapCenter;
if (s.snapDistance) ret |= RS_SnapMode::SnapDistance;
if (s.snapMiddle) ret |= RS_SnapMode::SnapMiddle;
if (s.snapEndpoint) ret |= RS_SnapMode::SnapEndpoint;
if (s.snapGrid) ret |= RS_SnapMode::SnapGrid;
if (s.snapFree) ret |= RS_SnapMode::SnapFree;
if (s.snapAngle) ret |= RS_SnapMode::SnapAngle;
switch (s.restriction) {
case RS2::RestrictHorizontal:
ret |= RS_SnapMode::RestrictHorizontal;
break;
case RS2::RestrictVertical:
ret |= RS_SnapMode::RestrictVertical;
break;
case RS2::RestrictOrthogonal:
ret |= RS_SnapMode::RestrictOrthogonal;
break;
default:
break;
}
return ret;
}
/**
* integer flag to snapMode
*/
RS_SnapMode RS_SnapMode::fromInt(unsigned int ret)
{
RS_SnapMode s;
if (RS_SnapMode::SnapIntersection & ret) s.snapIntersection = true;
if (RS_SnapMode::SnapOnEntity & ret) s.snapOnEntity = true;
if (RS_SnapMode::SnapCenter & ret) s.snapCenter = true;
if (RS_SnapMode::SnapDistance & ret) s.snapDistance = true;
if (RS_SnapMode::SnapMiddle & ret) s.snapMiddle = true;
if (RS_SnapMode::SnapEndpoint & ret) s.snapEndpoint = true;
if (RS_SnapMode::SnapGrid & ret) s.snapGrid = true;
if (RS_SnapMode::SnapFree & ret) s.snapFree = true;
if (RS_SnapMode::SnapAngle & ret) s.snapAngle = true;
switch (RS_SnapMode::RestrictOrthogonal & ret) {
case RS_SnapMode::RestrictHorizontal:
s.restriction = RS2::RestrictHorizontal;
break;
case RS_SnapMode::RestrictVertical:
s.restriction = RS2::RestrictVertical;
break;
case RS_SnapMode::RestrictOrthogonal:
s.restriction = RS2::RestrictOrthogonal;
break;
default:
s.restriction = RS2::RestrictNothing;
break;
}
return s;
}
/**
* Methods and structs for class RS_Snapper
*/
struct RS_Snapper::Indicator
{
bool lines_state;
QString lines_type;
RS_Pen lines_pen;
bool shape_state;
QString shape_type;
RS_Pen shape_pen;
};
struct RS_Snapper::ImpData {
RS_Vector snapCoord;
RS_Vector snapSpot;
};
/**
* Constructor.
*/
RS_Snapper::RS_Snapper(RS_EntityContainer& container, RS_GraphicView& graphicView)
:container(&container)
,graphicView(&graphicView)
,pImpData(new ImpData{})
,snap_indicator(new Indicator{})
{}
RS_Snapper::~RS_Snapper()
{
delete snap_indicator;
}
/**
* Initialize (called by all constructors)
*/
void RS_Snapper::init()
{
snapMode = graphicView->getDefaultSnapMode();
keyEntity = nullptr;
pImpData->snapSpot = RS_Vector{false};
pImpData->snapCoord = RS_Vector{false};
m_SnapDistance = 1.0;
RS_SETTINGS->beginGroup("/Appearance");
snap_indicator->lines_state = RS_SETTINGS->readNumEntry("/indicator_lines_state", 1);
snap_indicator->lines_type = RS_SETTINGS->readEntry("/indicator_lines_type", "Crosshair");
snap_indicator->shape_state = RS_SETTINGS->readNumEntry("/indicator_shape_state", 1);
snap_indicator->shape_type = RS_SETTINGS->readEntry("/indicator_shape_type", "Circle");
RS_SETTINGS->endGroup();
RS_SETTINGS->beginGroup("Colors");
QString snap_color = RS_SETTINGS->readEntry("/snap_indicator", Colors::snap_indicator);
RS_SETTINGS->endGroup();
snap_indicator->lines_pen = RS_Pen(RS_Color(snap_color), RS2::Width00, RS2::DashLine2);
snap_indicator->shape_pen = RS_Pen(RS_Color(snap_color), RS2::Width00, RS2::SolidLine);
snap_indicator->shape_pen.setScreenWidth(1);
snapRange=getSnapRange();
}
void RS_Snapper::finish() {
finished = true;
deleteSnapper();
}
void RS_Snapper::setSnapMode(const RS_SnapMode& snapMode) {
this->snapMode = snapMode;
RS_DIALOGFACTORY->requestSnapDistOptions(m_SnapDistance, snapMode.snapDistance);
RS_DIALOGFACTORY->requestSnapMiddleOptions(middlePoints, snapMode.snapMiddle);
//std::cout<<"RS_Snapper::setSnapMode(): middlePoints="<<middlePoints<<std::endl;
}
RS_SnapMode const* RS_Snapper::getSnapMode() const{
return &(this->snapMode);
}
RS_SnapMode* RS_Snapper::getSnapMode() {
return &(this->snapMode);
}
//get current mouse coordinates
RS_Vector RS_Snapper::snapFree(QMouseEvent* e) {
if (!e) {
RS_DEBUG->print(RS_Debug::D_WARNING,
"RS_Snapper::snapFree: event is nullptr");
return RS_Vector(false);
}
pImpData->snapSpot=graphicView->toGraph(e->x(), e->y());
pImpData->snapCoord=pImpData->snapSpot;
snap_indicator->lines_state=true;
return pImpData->snapCoord;
}
/**
* Snap to a coordinate in the drawing using the current snap mode.
*
* @param e A mouse event.
* @return The coordinates of the point or an invalid vector.
*/
RS_Vector RS_Snapper::snapPoint(QMouseEvent* e)
{
pImpData->snapSpot = RS_Vector(false);
RS_Vector t(false);
if (!e) {
RS_DEBUG->print(RS_Debug::D_WARNING,
"RS_Snapper::snapPoint: event is nullptr");
return pImpData->snapSpot;
}
RS_Vector mouseCoord = graphicView->toGraph(e->x(), e->y());
double ds2Min=RS_MAXDOUBLE*RS_MAXDOUBLE;
if (snapMode.snapEndpoint) {
t = snapEndpoint(mouseCoord);
double ds2=mouseCoord.squaredTo(t);
if (ds2 < ds2Min){
ds2Min=ds2;
pImpData->snapSpot = t;
}
}
if (snapMode.snapCenter) {
t = snapCenter(mouseCoord);
double ds2=mouseCoord.squaredTo(t);
if (ds2 < ds2Min){
ds2Min=ds2;
pImpData->snapSpot = t;
}
}
if (snapMode.snapMiddle) {
//this is still brutal force
//todo: accept value from widget QG_SnapMiddleOptions
RS_DIALOGFACTORY->requestSnapMiddleOptions(middlePoints, snapMode.snapMiddle);
t = snapMiddle(mouseCoord);
double ds2=mouseCoord.squaredTo(t);
if (ds2 < ds2Min){
ds2Min=ds2;
pImpData->snapSpot = t;
}
}
if (snapMode.snapDistance) {
//this is still brutal force
//todo: accept value from widget QG_SnapDistOptions
RS_DIALOGFACTORY->requestSnapDistOptions(m_SnapDistance, snapMode.snapDistance);
t = snapDist(mouseCoord);
double ds2=mouseCoord.squaredTo(t);
if (ds2 < ds2Min){
ds2Min=ds2;
pImpData->snapSpot = t;
}
}
if (snapMode.snapIntersection) {
t = snapIntersection(mouseCoord);
double ds2=mouseCoord.squaredTo(t);
if (ds2 < ds2Min){
ds2Min=ds2;
pImpData->snapSpot = t;
}
}
if (snapMode.snapOnEntity &&
pImpData->snapSpot.distanceTo(mouseCoord) > snapMode.distance) {
t = snapOnEntity(mouseCoord);
double ds2=mouseCoord.squaredTo(t);
if (ds2 < ds2Min){
ds2Min=ds2;
pImpData->snapSpot = t;
}
}
if (snapMode.snapGrid) {
t = snapGrid(mouseCoord);
double ds2=mouseCoord.squaredTo(t);
if (ds2 < ds2Min){
// ds2Min=ds2;
pImpData->snapSpot = t;
}
}
if( !pImpData->snapSpot.valid ) {
pImpData->snapSpot=mouseCoord; //default to snapFree
} else {
// std::cout<<"mouseCoord.distanceTo(snapSpot)="<<mouseCoord.distanceTo(snapSpot)<<std::endl;
// std::cout<<"snapRange="<<snapRange<<std::endl;
//retreat to snapFree when distance is more than half grid
if(snapMode.snapFree){
RS_Vector const& ds=mouseCoord - pImpData->snapSpot;
RS_Vector const& grid=graphicView->getGrid()->getCellVector()*0.5;
if( fabs(ds.x) > fabs(grid.x) || fabs(ds.y) > fabs(grid.y) ) pImpData->snapSpot = mouseCoord;
}
//another choice is to keep snapRange in GUI coordinates instead of graph coordinates
// if (mouseCoord.distanceTo(snapSpot) > snapRange ) snapSpot = mouseCoord;
}
//if (snapSpot.distanceTo(mouseCoord) > snapMode.distance) {
// handle snap restrictions that can be activated in addition
// to the ones above:
//apply restriction
RS_Vector rz = graphicView->getRelativeZero();
RS_Vector vpv(rz.x, pImpData->snapSpot.y);
RS_Vector vph(pImpData->snapSpot.x,rz.y);
switch (snapMode.restriction) {
case RS2::RestrictOrthogonal:
pImpData->snapCoord= ( mouseCoord.distanceTo(vpv)< mouseCoord.distanceTo(vph))?
vpv:vph;
break;
case RS2::RestrictHorizontal:
pImpData->snapCoord = vph;
break;
case RS2::RestrictVertical:
pImpData->snapCoord = vpv;
break;
//case RS2::RestrictNothing:
default:
pImpData->snapCoord = pImpData->snapSpot;
break;
}
//}
//else snapCoord = snapSpot;
snapPoint(pImpData->snapSpot, false);
return pImpData->snapCoord;
}
/**manually set snapPoint*/
RS_Vector RS_Snapper::snapPoint(const RS_Vector& coord, bool setSpot)
{
if(coord.valid){
pImpData->snapSpot=coord;
if(setSpot) pImpData->snapCoord = coord;
drawSnapper();
RS_DIALOGFACTORY->updateCoordinateWidget(
pImpData->snapCoord,
pImpData->snapCoord - graphicView->getRelativeZero());
}
return coord;
}
double RS_Snapper::getSnapRange() const
{
if (graphicView) {
return (graphicView->getGrid()->getCellVector() * 0.5).magnitude();
}
return 20.;
}
/**
* Snaps to a free coordinate.
*
* @param coord The mouse coordinate.
* @return The coordinates of the point or an invalid vector.
*/
RS_Vector RS_Snapper::snapFree(const RS_Vector& coord) {
keyEntity = nullptr;
return coord;
}
/**
* Snaps to the closest endpoint.
*
* @param coord The mouse coordinate.
* @return The coordinates of the point or an invalid vector.
*/
RS_Vector RS_Snapper::snapEndpoint(const RS_Vector& coord) {
RS_Vector vec(false);
vec = container->getNearestEndpoint(coord,
nullptr/*, &keyEntity*/);
return vec;
}
/**
* Snaps to a grid point.
*
* @param coord The mouse coordinate.
* @return The coordinates of the point or an invalid vector.
*/
RS_Vector RS_Snapper::snapGrid(const RS_Vector& coord) {
// RS_DEBUG->print("RS_Snapper::snapGrid begin");
// std::cout<<__FILE__<<" : "<<__func__<<" : line "<<__LINE__<<std::endl;
// std::cout<<" mouse: = "<<coord<<std::endl;
// std::cout<<" snapGrid: = "<<graphicView->getGrid()->snapGrid(coord)<<std::endl;
return graphicView->getGrid()->snapGrid(coord);
}
/**
* Snaps to a point on an entity.
*
* @param coord The mouse coordinate.
* @return The coordinates of the point or an invalid vector.
*/
RS_Vector RS_Snapper::snapOnEntity(const RS_Vector& coord) {
RS_Vector vec{};
vec = container->getNearestPointOnEntity(coord, true, nullptr, &keyEntity);
return vec;
}
/**
* Snaps to the closest center.
*
* @param coord The mouse coordinate.
* @return The coordinates of the point or an invalid vector.
*/
RS_Vector RS_Snapper::snapCenter(const RS_Vector& coord) {
RS_Vector vec{};
vec = container->getNearestCenter(coord, nullptr);
return vec;
}
/**
* Snaps to the closest middle.
*
* @param coord The mouse coordinate.
* @return The coordinates of the point or an invalid vector.
*/
RS_Vector RS_Snapper::snapMiddle(const RS_Vector& coord) {
//std::cout<<"RS_Snapper::snapMiddle(): middlePoints="<<middlePoints<<std::endl;
return container->getNearestMiddle(coord,static_cast<double *>(nullptr),middlePoints);
}
/**
* Snaps to the closest point with a given distance to the endpoint.
*
* @param coord The mouse coordinate.
* @return The coordinates of the point or an invalid vector.
*/
RS_Vector RS_Snapper::snapDist(const RS_Vector& coord) {
RS_Vector vec;
//std::cout<<" RS_Snapper::snapDist(RS_Vector coord): distance="<<distance<<std::endl;
vec = container->getNearestDist(m_SnapDistance,
coord,
nullptr);
return vec;
}
/**
* Snaps to the closest intersection point.
*
* @param coord The mouse coordinate.
* @return The coordinates of the point or an invalid vector.
*/
RS_Vector RS_Snapper::snapIntersection(const RS_Vector& coord) {
RS_Vector vec{};
vec = container->getNearestIntersection(coord,
nullptr);
return vec;
}
/**
* 'Corrects' the given coordinates to 0, 90, 180, 270 degrees relative to
* the current relative zero point.
*
* @param coord The uncorrected coordinates.
* @return The corrected coordinates.
*/
RS_Vector RS_Snapper::restrictOrthogonal(const RS_Vector& coord) {
RS_Vector rz = graphicView->getRelativeZero();
RS_Vector ret(coord);
RS_Vector retx = RS_Vector(rz.x, ret.y);
RS_Vector rety = RS_Vector(ret.x, rz.y);
if (retx.distanceTo(ret) > rety.distanceTo(ret)) {
ret = rety;
} else {
ret = retx;
}
return ret;
}
/**
* 'Corrects' the given coordinates to 0, 180 degrees relative to
* the current relative zero point.
*
* @param coord The uncorrected coordinates.
* @return The corrected coordinates.
*/
RS_Vector RS_Snapper::restrictHorizontal(const RS_Vector& coord) {
RS_Vector rz = graphicView->getRelativeZero();
RS_Vector ret = RS_Vector(coord.x, rz.y);
return ret;
}
/**
* 'Corrects' the given coordinates to 90, 270 degrees relative to
* the current relative zero point.
*
* @param coord The uncorrected coordinates.
* @return The corrected coordinates.
*/
RS_Vector RS_Snapper::restrictVertical(const RS_Vector& coord) {
RS_Vector rz = graphicView->getRelativeZero();
RS_Vector ret = RS_Vector(rz.x, coord.y);
return ret;
}
/**
* Catches an entity which is close to the given position 'pos'.
*
* @param pos A graphic coordinate.
* @param level The level of resolving for iterating through the entity
* container
* @return Pointer to the entity or nullptr.
*/
RS_Entity* RS_Snapper::catchEntity(const RS_Vector& pos,
RS2::ResolveLevel level) {
RS_DEBUG->print("RS_Snapper::catchEntity");
// set default distance for points inside solids
double dist (0.);
// std::cout<<"getSnapRange()="<<getSnapRange()<<"\tsnap distance = "<<dist<<std::endl;
RS_Entity* entity = container->getNearestEntity(pos, &dist, level);
int idx = -1;
if (entity && entity->getParent()) {
idx = entity->getParent()->findEntity(entity);
}
if (entity && dist<=getSnapRange()) {
// highlight:
RS_DEBUG->print("RS_Snapper::catchEntity: found: %d", idx);
return entity;
} else {
RS_DEBUG->print("RS_Snapper::catchEntity: not found");
return nullptr;
}
RS_DEBUG->print("RS_Snapper::catchEntity: OK");
}
/**
* Catches an entity which is close to the given position 'pos'.
*
* @param pos A graphic coordinate.
* @param level The level of resolving for iterating through the entity
* container
* @enType, only search for a particular entity type
* @return Pointer to the entity or nullptr.
*/
RS_Entity* RS_Snapper::catchEntity(const RS_Vector& pos, RS2::EntityType enType,
RS2::ResolveLevel level) {
RS_DEBUG->print("RS_Snapper::catchEntity");
// std::cout<<"RS_Snapper::catchEntity(): enType= "<<enType<<std::endl;
// set default distance for points inside solids
RS_EntityContainer ec(nullptr,false);
//isContainer
bool isContainer{false};
switch(enType){
case RS2::EntityPolyline:
case RS2::EntityContainer:
case RS2::EntitySpline:
isContainer=true;
break;
default:
break;
}
for(RS_Entity* en= container->firstEntity(level);en;en=container->nextEntity(level)){
if(en->isVisible()==false) continue;
if(en->rtti() != enType && isContainer){
//whether this entity is a member of member of the type enType
RS_Entity* parent(en->getParent());
bool matchFound{false};
while(parent ) {
// std::cout<<"RS_Snapper::catchEntity(): parent->rtti()="<<parent->rtti()<<" enType= "<<enType<<std::endl;
if(parent->rtti() == enType) {
matchFound=true;
ec.addEntity(en);
break;
}
parent=parent->getParent();
}
if(!matchFound) continue;
}
if (en->rtti() == enType){
ec.addEntity(en);
}
}
if (ec.count() == 0 ) return nullptr;
double dist(0.);
RS_Entity* entity = ec.getNearestEntity(pos, &dist, RS2::ResolveNone);
int idx = -1;
if (entity && entity->getParent()) {
idx = entity->getParent()->findEntity(entity);
}
if (entity && dist<=getSnapRange()) {
// highlight:
RS_DEBUG->print("RS_Snapper::catchEntity: found: %d", idx);
return entity;
} else {
RS_DEBUG->print("RS_Snapper::catchEntity: not found");
return nullptr;
}
}
/**
* Catches an entity which is close to the mouse cursor.
*
* @param e A mouse event.
* @param level The level of resolving for iterating through the entity
* container
* @return Pointer to the entity or nullptr.
*/
RS_Entity* RS_Snapper::catchEntity(QMouseEvent* e,
RS2::ResolveLevel level) {
return catchEntity(
RS_Vector(graphicView->toGraphX(e->x()),
graphicView->toGraphY(e->y())),
level);
}
/**
* Catches an entity which is close to the mouse cursor.
*
* @param e A mouse event.
* @param level The level of resolving for iterating through the entity
* container
* @enType, only search for a particular entity type
* @return Pointer to the entity or nullptr.
*/
RS_Entity* RS_Snapper::catchEntity(QMouseEvent* e, RS2::EntityType enType,
RS2::ResolveLevel level) {
return catchEntity(
{graphicView->toGraphX(e->x()), graphicView->toGraphY(e->y())},
enType,
level);
}
RS_Entity* RS_Snapper::catchEntity(QMouseEvent* e, const EntityTypeList& enTypeList,
RS2::ResolveLevel level) {
RS_Entity* pten = nullptr;
RS_Vector coord{graphicView->toGraphX(e->x()), graphicView->toGraphY(e->y())};
switch(enTypeList.size()) {
case 0:
return catchEntity(coord, level);
default:
{
RS_EntityContainer ec(nullptr,false);
for( auto t0: enTypeList){
RS_Entity* en=catchEntity(coord, t0, level);
if(en) ec.addEntity(en);
// if(en) {
// std::cout<<__FILE__<<" : "<<__func__<<" : lines "<<__LINE__<<std::endl;
// std::cout<<"caught id= "<<en->getId()<<std::endl;
// }
}
if(ec.count()>0){
ec.getDistanceToPoint(coord, &pten, RS2::ResolveNone);
return pten;
}
}
}
return nullptr;
}
void RS_Snapper::suspend() {
// RVT Don't delete the snapper here!
// RVT_PORT (can be deleted)();
pImpData->snapSpot = pImpData->snapCoord = RS_Vector{false};
}
/**
* Hides the snapper options. Default implementation does nothing.
*/
void RS_Snapper::hideOptions() {
//not used any more, will be removed
}
/**
* Shows the snapper options. Default implementation does nothing.
*/
void RS_Snapper::showOptions() {
//not used any more, will be removed
}
/**
* Deletes the snapper from the screen.
*/
void RS_Snapper::deleteSnapper()
{
graphicView->getOverlayContainer(RS2::Snapper)->clear();
graphicView->redraw(RS2::RedrawOverlay); // redraw will happen in the mouse movement event
}
/**
* creates the snap indicator
*/
void RS_Snapper::drawSnapper()
{
// We could properly speed this up by calling the draw function of this snapper within the paint event
// this will avoid creating/deletion of the lines
graphicView->getOverlayContainer(RS2::Snapper)->clear();
if (!finished && pImpData->snapSpot.valid)
{
RS_EntityContainer *container=graphicView->getOverlayContainer(RS2::Snapper);
if (snap_indicator->lines_state)
{
QString type = snap_indicator->lines_type;
if (type == "Crosshair")
{
RS_OverlayLine *line = new RS_OverlayLine(nullptr,
{{0., graphicView->toGuiY(pImpData->snapCoord.y)},
{double(graphicView->getWidth()),
graphicView->toGuiY(pImpData->snapCoord.y)}});
line->setPen(snap_indicator->lines_pen);
container->addEntity(line);
line = new RS_OverlayLine(nullptr,
{{graphicView->toGuiX(pImpData->snapCoord.x),0.},
{graphicView->toGuiX(pImpData->snapCoord.x),
double(graphicView->getHeight())}});
line->setPen(snap_indicator->lines_pen);
container->addEntity(line);
}
else if (type == "Crosshair2")
{
double xenoRadius=16;
double snapX=graphicView->toGuiX(pImpData->snapCoord.x);
double snapY=graphicView->toGuiY(pImpData->snapCoord.y);
double viewWidth=double(graphicView->getWidth());
double viewHeight=double(graphicView->getHeight());
RS_OverlayLine *line;
// ----O (Left)
line=new RS_OverlayLine(nullptr, {
{0., snapY},
{snapX-xenoRadius, snapY}
});
{
line->setPen(snap_indicator->lines_pen);
container->addEntity(line);
}
// O---- (Right)
line=new RS_OverlayLine(nullptr, {
{snapX+xenoRadius, snapY},
{viewWidth, snapY}
});
{
line->setPen(snap_indicator->lines_pen);
container->addEntity(line);
}
// (Top)
line=new RS_OverlayLine(nullptr, {
{snapX, 0.},
{snapX, snapY-xenoRadius}
});
{
line->setPen(snap_indicator->lines_pen);
container->addEntity(line);
}
// (Bottom)
line=new RS_OverlayLine(nullptr, {
{snapX, snapY+xenoRadius},
{snapX, viewHeight}
});
{
line->setPen(snap_indicator->lines_pen);
container->addEntity(line);
}
}
else if (type == "Isometric")
{
//isometric crosshair
RS2::CrosshairType chType=graphicView->getCrosshairType();
RS_Vector direction1;
RS_Vector direction2(0.,1.);
double l=graphicView->getWidth()+graphicView->getHeight();
switch(chType){
case RS2::RightCrosshair:
direction1=RS_Vector(M_PI*5./6.)*l;
direction2*=l;
break;
case RS2::LeftCrosshair:
direction1=RS_Vector(M_PI*1./6.)*l;
direction2*=l;
break;
default:
direction1=RS_Vector(M_PI*1./6.)*l;
direction2=RS_Vector(M_PI*5./6.)*l;
}
RS_Vector center(graphicView->toGui(pImpData->snapCoord));
RS_OverlayLine *line=new RS_OverlayLine(container,
{center-direction1,center+direction1});
line->setPen(snap_indicator->lines_pen);
container->addEntity(line);
line=new RS_OverlayLine(nullptr,
{center-direction2,center+direction2});
line->setPen(snap_indicator->lines_pen);
container->addEntity(line);
}
else if (type == "Spiderweb")
{
RS_OverlayLine* line;
RS_Vector point1;
RS_Vector point2;
point1 = RS_Vector{0, 0};
point2 = RS_Vector{graphicView->toGuiX(pImpData->snapCoord.x),
graphicView->toGuiY(pImpData->snapCoord.y)};
line=new RS_OverlayLine{nullptr, {point1, point2}};
line->setPen(snap_indicator->lines_pen);
container->addEntity(line);
point1 = RS_Vector(0, graphicView->getHeight());
line = new RS_OverlayLine{nullptr, {point1, point2}};
line->setPen(snap_indicator->lines_pen);
container->addEntity(line);
point1 = RS_Vector(graphicView->getWidth(), 0);
line = new RS_OverlayLine(nullptr, {point1, point2});
line->setPen(snap_indicator->lines_pen);
container->addEntity(line);
point1 = RS_Vector(graphicView->getWidth(), graphicView->getHeight());
line = new RS_OverlayLine(nullptr, {point1, point2});
line->setPen(snap_indicator->lines_pen);
container->addEntity(line);
}
}
if (snap_indicator->shape_state)
{
QString type = snap_indicator->shape_type;
if (type == "Circle")
{
RS_Circle *circle=new RS_Circle(container,
{pImpData->snapCoord, 4./graphicView->getFactor().x});
circle->setPen(snap_indicator->shape_pen);
container->addEntity(circle);
}
else if (type == "Point")
{
RS_Point *point=new RS_Point(container, pImpData->snapCoord);
point->setPen(snap_indicator->shape_pen);
container->addEntity(point);
}
else if (type == "Square")
{
RS_Vector snap_point{graphicView->toGuiX(pImpData->snapCoord.x),
graphicView->toGuiY(pImpData->snapCoord.y)};
double a = 6.0;
RS_Vector p1 = snap_point + RS_Vector(-a, a);
RS_Vector p2 = snap_point + RS_Vector(a, a);
RS_Vector p3 = snap_point + RS_Vector(a, -a);
RS_Vector p4 = snap_point + RS_Vector(-a, -a);
RS_OverlayLine* line;
line=new RS_OverlayLine{nullptr, {p1, p2}};
line->setPen(snap_indicator->shape_pen);
container->addEntity(line);
line = new RS_OverlayLine{nullptr, {p2, p3}};
line->setPen(snap_indicator->shape_pen);
container->addEntity(line);
line = new RS_OverlayLine(nullptr, {p3, p4});
line->setPen(snap_indicator->shape_pen);
container->addEntity(line);
line = new RS_OverlayLine(nullptr, {p4, p1});
line->setPen(snap_indicator->shape_pen);
container->addEntity(line);
}
}
graphicView->redraw(RS2::RedrawOverlay); // redraw will happen in the mouse movement event
}
}
RS_Vector RS_Snapper::snapToAngle(const RS_Vector &currentCoord, const RS_Vector &referenceCoord, const double angularResolution)
{
if(snapMode.restriction != RS2::RestrictNothing || snapMode.snapGrid)
{
return currentCoord;
}
double angle = referenceCoord.angleTo(currentCoord)*180.0/M_PI;
angle -= remainder(angle,angularResolution);
angle *= M_PI/180.;
RS_Vector res = RS_Vector::polar(referenceCoord.distanceTo(currentCoord),angle);
res += referenceCoord;
if (snapMode.snapOnEntity)
{
RS_Vector t(false);
//RS_Vector mouseCoord = graphicView->toGraph(currentCoord.x(), currentCoord.y());
t = container->getNearestVirtualIntersection(res,angle,nullptr);
pImpData->snapSpot = t;
snapPoint(pImpData->snapSpot, true);
return t;
}
else
{
snapPoint(res, true);
return res;
}
}