AbdulElahGwaith's picture
Upload folder using huggingface_hub
a5ffdcd verified
/****************************************************************************
**
** 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 "rs_dimangular.h"
#include "rs_arc.h"
#include "rs_constructionline.h"
#include "rs_debug.h"
#include "rs_information.h"
#include "rs_line.h"
#include "rs_math.h"
#include "rs_pen.h"
#include "rs_solid.h"
#include "rs_units.h"
class RS_Arc;
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,
const double _tickSize) :
dimscale( _dimscale),
dimexo( _dimexo * _dimscale),
dimexe( _dimexe * _dimscale),
dimtxt( _dimtxt * _dimscale),
dimgap( _dimgap * _dimscale),
arrowSize( _arrowSize * _dimscale),
m_tickSize( _tickSize * _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),
m_dimAngularData( ed){
calcDimension();
}
RS_DimAngular::RS_DimAngular(const RS_DimAngular& other)
:RS_Dimension(other), m_dimAngularData{other.m_dimAngularData} {
}
RS_Entity* RS_DimAngular::clone() const{
auto *d = new RS_DimAngular(*this);
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 (',' == getDimDecimalFormatSeparatorChar()) {
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){
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) {
addDimExtensionLine(dimLine.getStartpoint(),dimPoint - dirStart * av.exe(), true);
}
else if( 1.0 < diffLine && 0.0 < diffCenter) {
addDimExtensionLine(dimLine.getEndpoint(),dimPoint - dirEnd * av.exe(), true);
}
else if( 0.0 > diffLine && 1.0 < diffCenter) {
addDimExtensionLine(dimCenter - dirStart * av.exo(),dimPoint + dirEnd * av.exe(), true);
}
}
/**
* @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 double scaledTickSize = av.tickSize();
if (scaledTickSize < 0.01) {
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());
addDimComponentEntity(arrow, getPenExtensionLine(true));
}
else {
RS_Vector tickVector = RS_Vector::polar(scaledTickSize,
(dimAngleL1 + dimAngleL2) / 2.0);
addDimComponentLine(point - tickVector, point + tickVector, getPenExtensionLine(true));
}
}
/**
* 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::doUpdateDim(){
RS_DEBUG->print("RS_DimAngular::update");
if (!dimCenter.valid) {
return;
}
double dimscale = getGeneralScale();
double dimgap = getDimensionLineGap() * dimscale;
bool drawFrameAroundText = std::signbit(dimgap);
if (drawFrameAroundText) {
dimgap = -dimgap;
}
LC_DimAngularVars av( dimscale,
getExtensionLineOffset(),
getExtensionLineExtension(),
getTextHeight(),
dimgap,
getArrowSize(),
getTickSize());
// create new lines with offsets for extension lines
RS_ConstructionLine line1(dimLine1.getStartpoint() - dimDir1s * av.exo(),
dimLine1.getEndpoint() - dimDir1e * av.exo());
RS_ConstructionLine line2(dimLine2.getStartpoint() - dimDir2s * av.exo(),
dimLine2.getEndpoint() - dimDir2e * av.exo());
RS_Vector p1 {dimCenter + dimDir1e * dimRadius};
RS_Vector p2 {dimCenter + dimDir2e * dimRadius};
extensionLine( line1, p1, dimDir1s, dimDir1e, av);
extensionLine( line2, p2, dimDir2s, dimDir2e, av);
RS_ArcData arcData( dimCenter, dimRadius, dimAngleL1, dimAngleL2, false);
// Create dimension line (arc)
RS_Arc* arc = addDimArc(arcData);
// 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);
arrow( p2, dimAngleL2, -1.0, outsideArrows, av);
// text label
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;
auto text = createDimText(textPos, av.txt(), textAngle);
if (drawFrameAroundText) {
addBoundsAroundText(dimgap, text);
}
}
void RS_DimAngular::update(){
calcDimension();
RS_Dimension::update();
}
void RS_DimAngular::move(const RS_Vector& offset){
RS_Dimension::move( offset);
m_dimAngularData.definitionPoint1.move( offset);
m_dimAngularData.definitionPoint2.move( offset);
m_dimAngularData.definitionPoint3.move( offset);
m_dimAngularData.definitionPoint4.move( offset);
update();
}
void RS_DimAngular::rotate(const RS_Vector& center, double angle){
rotate( center, RS_Vector( angle));
}
void RS_DimAngular::rotate(const RS_Vector& center, const RS_Vector& angleVector){
RS_Dimension::rotate( center, angleVector);
m_dimAngularData.definitionPoint1.rotate( center, angleVector);
m_dimAngularData.definitionPoint2.rotate( center, angleVector);
m_dimAngularData.definitionPoint3.rotate( center, angleVector);
m_dimAngularData.definitionPoint4.rotate( center, angleVector);
update();
}
void RS_DimAngular::scale(const RS_Vector& center, const RS_Vector& factor){
RS_Dimension::scale( center, factor);
m_dimAngularData.definitionPoint1.scale( center, factor);
m_dimAngularData.definitionPoint2.scale( center, factor);
m_dimAngularData.definitionPoint3.scale( center, factor);
m_dimAngularData.definitionPoint4.scale( center, factor);
update();
}
void RS_DimAngular::mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2){
RS_Dimension::mirror( axisPoint1, axisPoint2);
m_dimAngularData.definitionPoint1.mirror( axisPoint1, axisPoint2);
m_dimAngularData.definitionPoint2.mirror( axisPoint1, axisPoint2);
m_dimAngularData.definitionPoint3.mirror( axisPoint1, axisPoint2);
m_dimAngularData.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( m_dimAngularData.definitionPoint2.angleTo( m_dimAngularData.definitionPoint1)));
dimDir1e = RS_Vector::polar( 1.0, RS_Math::correctAngle( m_dimAngularData.definitionPoint1.angleTo( m_dimAngularData.definitionPoint2)));
dimDir2s = RS_Vector::polar( 1.0, RS_Math::correctAngle( m_dimGenericData.definitionPoint.angleTo( m_dimAngularData.definitionPoint3)));
dimDir2e = RS_Vector::polar( 1.0, RS_Math::correctAngle( m_dimAngularData.definitionPoint3.angleTo( m_dimGenericData.definitionPoint)));
// create the two dimension definition lines
dimLine1 = RS_ConstructionLine( nullptr,
RS_ConstructionLineData( m_dimAngularData.definitionPoint2,
m_dimAngularData.definitionPoint1));
dimLine2 = RS_ConstructionLine( nullptr,
RS_ConstructionLineData( m_dimGenericData.definitionPoint,
m_dimAngularData.definitionPoint3));
RS_VectorSolutions vs {RS_Information::getIntersection( &dimLine1, &dimLine2, false)};
dimCenter = vs.get(0);
dimRadius = dimCenter.distanceTo( m_dimAngularData.definitionPoint4);
dimDirRad = RS_Vector::polar( 1.0, RS_Math::correctAngle( dimCenter.angleTo( m_dimAngularData.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 {m_dimGenericData.definitionPoint.distanceTo( dimCenter)};
double distance1 {m_dimAngularData.definitionPoint1.distanceTo( dimCenter)};
double distance2 {m_dimAngularData.definitionPoint2.distanceTo( dimCenter)};
double distance3 {m_dimAngularData.definitionPoint3.distanceTo( dimCenter)};
double angle0 {0.0};
double angle1 {0.0};
double angle2 {0.0};
double angle3 {0.0};
if( RS_TOLERANCE >= distance0) {
angle3 = (m_dimAngularData.definitionPoint3 - dimCenter).angle();
angle0 = angle3;
}
else if( RS_TOLERANCE >= distance3) {
angle0 = (m_dimGenericData.definitionPoint - dimCenter).angle();
angle3 = angle0;
}
else {
angle0 = (m_dimGenericData.definitionPoint - dimCenter).angle();
angle3 = (m_dimAngularData.definitionPoint3 - dimCenter).angle();
}
if( RS_TOLERANCE >= distance1) {
angle2 = (m_dimAngularData.definitionPoint2- dimCenter).angle();
angle1 = angle2;
}
else if( RS_TOLERANCE >= distance2) {
angle1 = (m_dimAngularData.definitionPoint1 - dimCenter).angle();
angle2 = angle1;
}
else {
angle1 = (m_dimAngularData.definitionPoint1 - dimCenter).angle();
angle2 = (m_dimAngularData.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;
}