/**************************************************************************** ** ** 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 #include "lc_quadratic.h" #include "lc_splinepoints.h" #include "lc_undosection.h" #include "rs_arc.h" #include "rs_block.h" #include "rs_circle.h" #include "rs_creation.h" #include "rs_constructionline.h" #include "rs_debug.h" #include "rs_ellipse.h" #include "rs_entitycontainer.h" #include "rs_graphic.h" #include "rs_image.h" #include "rs_information.h" #include "rs_insert.h" #include "rs_line.h" #include "rs_math.h" #include "rs_modification.h" #include "rs_units.h" // fixme - sand - refactor - review this class completely namespace { /** * @brief isArc whether the entity supports tangent * @param entity * @return true if the entity can have tangent (RS_Line is not considered as an arc here). */ bool isArc(const RS_Entity& entity) { if (entity.isArc()) { return true; } switch (entity.rtti()) { case RS2::EntityCircle: case RS2::EntityEllipse: case RS2::EntityHyperbola: case RS2::EntityParabola: return true; default: return false; } } /** * @brief fromLineCoordinate create a line from line coordinates (x, y, 1) * @param line the line coordinates, (x, y, 1), the last coordinate is always one, and the z-component of the input * vector is not used * @return the same line in RS_LineData */ RS_LineData fromLineCoordinate(const RS_Vector& line) { RS_Vector start = RS_Vector{line}.rotate(-M_PI / 4.); RS_Vector stop = RS_Vector{line}.rotate(M_PI / 4.); return {start / (-start.dotP(line)), stop / (-stop.dotP(line))}; } } /** * Default constructor. * * @param container The container to which we will add * entities. Usually that's an RS_Graphic entity but * it can also be a polyline, text, ... */ RS_Creation::RS_Creation(RS_EntityContainer* container, LC_GraphicViewport* viewport, bool handleUndo): m_container{container} ,m_graphic{container?container->getGraphic():nullptr} ,m_document{container?container->getDocument():nullptr} ,m_viewport{viewport} ,handleUndo(handleUndo){ // assert(viewport != nullptr); } /** * Creates an entity parallel to the given entity e through the given * 'coord'. * * @param coord Coordinate to define the distance / side (typically a * mouse coordinate). * @param number Number of parallels. * @param e Original entity. * * @return Pointer to the first created parallel or nullptr if no * parallel has been created. */ RS_Entity* RS_Creation::createParallelThrough(const RS_Vector& coord, int number, RS_Entity* e, bool symmetric) { if (e == nullptr) { return nullptr; } double dist = 0.; if (e->rtti()==RS2::EntityLine) { auto* l = (RS_Line*)e; RS_ConstructionLine cl(nullptr,RS_ConstructionLineData(l->getStartpoint(),l->getEndpoint())); dist = cl.getDistanceToPoint(coord); } else { dist = e->getDistanceToPoint(coord); } if (distrtti()) { case RS2::EntityLine: return createParallelLine(coord, distance, number, static_cast(e), symmetric); case RS2::EntityArc: return createParallelArc(coord, distance, number, static_cast(e)); case RS2::EntityCircle: return createParallelCircle(coord, distance, number, static_cast(e)); case RS2::EntityParabola: case RS2::EntitySplinePoints: return createParallelSplinePoints(coord, distance, number, static_cast(e)); default: break; } return nullptr; } /** * Creates a line parallel to the given line e. * Out of the 2 possible parallels, the one closest to * the given coordinate is returned. * * @param coord Coordinate to define which parallel we want (typically a * mouse coordinate). * @param distance Distance of the parallel. * @param number Number of parallels. * @param e Original entity. * * @return Pointer to the first created parallel or nullptr if no * parallel has been created. */ RS_Line* RS_Creation::createParallelLine(const RS_Vector& coord, double distance, int number, RS_Line* e, bool symmetric) { if (e == nullptr) { return nullptr; } double ang = e->getAngle1() + M_PI_2; RS_LineData parallelData; RS_Line* ret = nullptr; LC_UndoSection undo( m_document,m_viewport, handleUndo); for (int num = 1; num <= number; ++num) { // calculate 1st parallel: RS_Vector p1 = RS_Vector::polar(distance*num, ang); p1 += e->getStartpoint(); RS_Vector p2 = RS_Vector::polar(distance*num, ang); p2 += e->getEndpoint(); RS_Line parallel1{p1, p2}; // calculate 2nd parallel: p1.setPolar(distance*num, ang+M_PI); p1 += e->getStartpoint(); p2.setPolar(distance*num, ang+M_PI); p2 += e->getEndpoint(); RS_Line parallel2{p1, p2}; double dist1 = parallel1.getDistanceToPoint(coord); double dist2 = parallel2.getDistanceToPoint(coord); double minDist = std::min(dist1, dist2); if (minDistgetCenter().distanceTo(coord) < e->getRadius()); if (inside) { distance *= -1; } for (int num = 1; num <= number; ++num) { // calculate parallel: bool ok = true; RS_Arc parallel1(nullptr, e->getData()); parallel1.setRadius(e->getRadius() + distance*num); if (parallel1.getRadius()<0.0) { parallel1.setRadius(RS_MAXDOUBLE); ok = false; } // calculate 2nd parallel: //RS_Arc parallel2(nullptr, e->getData()); //parallel2.setRadius(e->getRadius()+distance*num); //double dist1 = parallel1.getDistanceToPoint(coord); //double dist2 = parallel2.getDistanceToPoint(coord); //double minDist = min(dist1, dist2); //if (minDistgetCenter().distanceTo(coord) < e->getRadius()); if (inside) { distance *= -1; } for (int num = 1; num <= number; ++num) { // calculate parallel: bool ok = true; RS_Circle parallel1(nullptr, e->getData()); parallel1.setRadius(e->getRadius() + distance*num); if (parallel1.getRadius()<0.0) { parallel1.setRadius(RS_MAXDOUBLE); ok = false; } // calculate 2nd parallel: //RS_Circle parallel2(nullptr, e->getData()); //parallel2.setRadius(e->getRadius()+distance*num); //double dist1 = parallel1.getDistanceToPoint(coord); //double dist2 = parallel2.getDistanceToPoint(coord); //double minDist = min(dist1, dist2); //if (minDistclone(); psp->offset(coord, i*distance); psp->setParent(m_container); if(!ret) ret = psp; setupAndAddEntity(psp); } return ret; } /** * Creates a bisecting line of the angle between the entities * e1 and e2. Out of the 4 possible bisectors, the one closest to * the given coordinate is returned. * * @param coord Coordinate to define which bisector we want (typically a * mouse coordinate). * @param length Length of the bisecting line. * @param num Number of bisectors * @param l1 First line. * @param l2 Second line. * * @return Pointer to the first bisector created or nullptr if no bisectors * were created. */ RS_Line* RS_Creation::createBisector(const RS_Vector& coord1, const RS_Vector& coord2, double length, int num, RS_Line* l1, RS_Line* l2) { // check given entities: if (!(l1 != nullptr && l2 != nullptr)) { return nullptr; } if (!(l1->rtti()==RS2::EntityLine && l2->rtti()==RS2::EntityLine)) { return nullptr; } // intersection between entities: RS_VectorSolutions const& sol = RS_Information::getIntersection(l1, l2, false); RS_Vector inters = sol.get(0); if (!inters.valid) { return nullptr; } double angle1 = inters.angleTo(l1->getNearestPointOnEntity(coord1)); double angle2 = inters.angleTo(l2->getNearestPointOnEntity(coord2)); double angleDiff = RS_Math::getAngleDifference(angle1, angle2); if (angleDiff > M_PI) { angleDiff = angleDiff - 2.*M_PI; } RS_Line* ret = nullptr; LC_UndoSection undo( m_document, m_viewport, handleUndo); for (int n = 1; n <= num; ++n) { double angle = angle1 + (angleDiff / (num + 1) * n); RS_Vector const& v = RS_Vector::polar(length, angle); auto* newLine = new RS_Line{m_container, inters, inters + v}; if (ret == nullptr) { ret = newLine; } setupAndAddEntity(newLine); } return ret; } /** * create a tangent line which is orthogonal to the given RS_Line(normal) * @coord, the tangent line closest to this point * @normal, the line orthogonal to the tangent line * @circle, arc/circle/ellipse for tangent line * * Author: Dongxu Li */ std::unique_ptr RS_Creation::createLineOrthTan(const RS_Vector& coord, RS_Line* normal, RS_Entity* circle, RS_Vector& alternativeTangent){ // check given entities: if (!(circle != nullptr && normal != nullptr)) { return {}; } // Allow construction of a tangent normal to a given line using getTangentDirection() RS_Vector const& tangent = circle->getNearestOrthTan(coord,*normal,false); if (tangent.valid) { double tangentDirection = circle->getTangentDirection(tangent).angle(); double normalDirection = normal->getDirection1(); if (RS_Math::equal(RS_Math::correctAngle0ToPi(tangentDirection - normalDirection), M_PI/2, RS_TOLERANCE_ANGLE)) { RS_Vector linePoint = normal->getNearestPointOnEntity(tangent, false); return std::make_unique(m_container, RS_LineData{linePoint, tangent}); } } RS2::EntityType rtti = circle->rtti(); if (!(circle->isArc())) { return {}; } RS_Vector tangentPoint0; RS_Vector t1; switch (rtti){ case RS2::EntityCircle: { auto *cir = dynamic_cast(circle); const RS_Vector ¢er = cir->getCenter(); double radius = cir->getRadius(); RS_Vector vp0(coord - center); RS_Vector vp1(normal->getAngle1()); double d = RS_Vector::dotP(vp0, vp1); const RS_Vector &ortVector = vp1 * radius; if (d >= 0.){ tangentPoint0 = center + ortVector; t1 = center - ortVector; } else { tangentPoint0 = center - ortVector; t1 = center + ortVector; } break; } case RS2::EntityArc: { auto *cir = dynamic_cast(circle); double angle=normal->getAngle1(); double radius = cir->getRadius(); RS_Vector vp = RS_Vector::polar(radius, angle); std::vector sol; bool onEntity = false; for (int i = 0; i <= 1; i++) { if(!onEntity || RS_Math::isAngleBetween(angle,cir->getAngle1(),cir->getAngle2(),cir->isReversed())) { if (i) { sol.push_back(- vp); } else { sol.push_back(vp); } } angle=RS_Math::correctAngle(angle+M_PI); } const RS_Vector ¢er = cir->getCenter(); switch(sol.size()) { case 0: tangentPoint0 = RS_Vector(false); [[fallthrough]]; case 2: if (RS_Vector::dotP(sol[1], coord - center) > 0.){ tangentPoint0 = center + sol[1]; t1 = center + sol[0]; break; } [[fallthrough]]; default: tangentPoint0 = center + sol[0]; t1 = center + sol[1]; break; } break; } case RS2::EntityEllipse: { auto *cir = dynamic_cast(circle); //scale to ellipse angle RS_Vector aV(-cir->getAngle()); RS_Vector direction = normal->getEndpoint() - normal->getStartpoint(); direction.rotate(aV); double ratio = cir->getRatio(); double angle = direction.scale(RS_Vector(1., ratio)).angle(); double ra(cir->getMajorRadius()); direction.set(ra * cos(angle), ratio * ra * sin(angle));//relative to center std::vector sol; bool onEntity = false; for (int i = 0; i < 2; i++) { if (!onEntity || RS_Math::isAngleBetween(angle, cir->getAngle1(), cir->getAngle2(), cir->isReversed())){ if (i){ sol.push_back(-direction); } else { sol.push_back(direction); } } angle = RS_Math::correctAngle(angle + M_PI); } if (sol.size() < 1) { tangentPoint0 = RS_Vector(false); } else { aV.y *= -1.; for (auto &v: sol) { v.rotate(aV); } const RS_Vector ¢er = cir->getCenter(); switch (sol.size()) { case 0: tangentPoint0 = RS_Vector(false); [[fallthrough]]; case 2: if (RS_Vector::dotP(sol[1], coord - center) > 0.){ tangentPoint0 = center + sol[1]; t1 = center + sol[0]; break; } [[fallthrough]]; default: tangentPoint0 = center + sol[0]; t1 = center + sol[1]; break; } } break; } default: break; } alternativeTangent = t1; if(!tangentPoint0.valid) { return {}; } RS_Vector const& vp=normal->getNearestPointOnEntity(tangentPoint0, false); return std::make_unique(m_container, vp, tangentPoint0); // fixme - sand - files - merge - UNDO??? Previously it was in undo cycle. Why this is changed - yet that's ok, // the action should handle /*if(!t0.valid) return ret; RS_Vector const& vp=normal->getNearestPointOnEntity(t0, false); LC_UndoSection undo( m_document,m_viewport, handleUndo); ret = new RS_Line{m_container, vp, t0}; ret->setLayerToActive(); ret->setPenToActive(); return ret;*/ } /** * Creates a tangent between a given point and a circle or arc. * Out of the 2 possible tangents, the one closest to * the given coordinate is returned. * * @param coord Coordinate to define which tangent we want (typically a * mouse coordinate). * @param point Point. * @param circle Circle, arc or ellipse entity. */ RS_Line* RS_Creation::createTangent1(const RS_Vector& coord, const RS_Vector& point, RS_Entity* circle, RS_Vector& tangentPoint, RS_Vector& altTangentPoint) { RS_Line* ret = nullptr; // check given entities: if (!(circle != nullptr && point.valid && circle->isAtomic())) { return nullptr; } if (isArc(*circle)) { // Find tangent lines through dual curves // the dual line of the given point LC_Quadratic dualLine{{point.x, point.y, 1.}}; LC_Quadratic dualCircle = circle->getQuadratic().getDualCurve(); // tangent lines by intersection of dual curves RS_VectorSolutions dualSol = LC_Quadratic::getIntersection(dualLine, dualCircle); if (dualSol.empty()) return nullptr; // distance to coord auto distCoord = [&coord](const RS_Vector& uv) { return std::abs(uv.dotP(coord) + 1.); }; if (dualSol.getNumber() == 2 && distCoord(dualSol[1]) < distCoord(dualSol[0])) std::swap(dualSol[0], dualSol[1]); if (dualSol.getNumber() == 2) { altTangentPoint = circle->dualLineTangentPoint(dualSol[1]); } tangentPoint = circle->dualLineTangentPoint(dualSol[0]); // in case the point is on circle if (tangentPoint == point) { tangentPoint.move(dualSol[0].rotate(M_PI/2.) * circle->getLength()); } LC_UndoSection undo(m_document, m_viewport, handleUndo); ret = new RS_Line{m_container, {point, tangentPoint}}; setupAndAddEntity(ret); return ret; } // the two tangent points: RS_VectorSolutions sol = circle->getTangentPoint(point); // second port of if condition means that there is no solution - yet some entities (like circle) put coordinate... if (sol.isEmpty() || (sol.getNumber() == 1 && sol[0] == point)){ return nullptr; } RS_Vector const vp2{sol.getClosest(coord)}; RS_LineData d{}; if ((vp2 - point).squared() > RS_TOLERANCE2) { d = {vp2, point}; } else { //the given point is a tangential point d = {point + circle->getTangentDirection(point), point}; } tangentPoint = d.startpoint; if (sol.getNumber() == 1) { // spline by points support... altTangentPoint = sol[0]; } else { altTangentPoint = (sol[0] == vp2) ? sol[1] : sol[0]; } // create the closest tangent: LC_UndoSection undo(m_document, m_viewport, handleUndo); ret = new RS_Line{m_container, d}; setupAndAddEntity(ret); return ret; } /** * Creates a tangent between two circles or arcs. * Out of the 4 possible tangents, the one closest to * the given coordinate is returned. * * @param coord Coordinate to define which tangent we want (typically a * mouse coordinate). * @param circle1 1st circle or arc entity. * @param circle2 2nd circle or arc entity. */ std::vector> RS_Creation::createTangent2( RS_Entity* circle1, RS_Entity* circle2) { // check given entities: if(! (circle1 != nullptr && circle2 != nullptr)) { return {}; } if( !(isArc(*circle1) && isArc(*circle2))) { return {}; } // Find common tangent lines in line coordinates, i.e. using dual curves // A common tangent line is an intersection of the dual curves auto sol = LC_Quadratic::getIntersection(circle1->getQuadratic().getDualCurve(), circle2->getQuadratic().getDualCurve()); if (sol.empty()) return {}; RS_VectorSolutions sol1; for (const auto& vp: sol) { if (!vp.valid) { continue; } if (sol1.empty()) { sol1.push_back(vp); } else if (sol1.getClosestDistance(vp) > RS_TOLERANCE_ANGLE) { sol1.push_back(vp); } } // verify the tangent lines std::vector> tangents; std::transform(sol1.begin(), sol1.end(), std::back_inserter(tangents), [circle1, circle2](const RS_Vector& line) -> std::unique_ptr { auto rsLine = std::make_unique(nullptr, fromLineCoordinate(line)); rsLine->setStartpoint(circle1->dualLineTangentPoint(line)); rsLine->setEndpoint(circle2->dualLineTangentPoint(line)); if (!(rsLine->getStartpoint().isValid() && rsLine->getEndpoint().isValid())) return nullptr; return std::unique_ptr(std::move(rsLine)); }); // cleanup invalid lines tangents.erase(remove_if(tangents.begin(), tangents.end(), [](const std::unique_ptr& line) { return line == nullptr; }), tangents.end()); if (tangents.empty()) { return {}; } return tangents; } /** * Creates a line with a relative angle to the given entity. * * @param coord Coordinate to define the point where the line should end. * (typically a mouse coordinate). * @param entity Pointer to basis entity. The angle is relative to the * angle of this entity. * @param angle Angle of the line relative to the angle of the basis entity. * @param length Length of the line we're creating. */ std::unique_ptr RS_Creation::createLineRelAngle(const RS_Vector& coord, RS_Entity* entity, double angle, double length) { // check given entity / coord: if (!(entity && coord)) { return {}; } switch (entity->rtti()) { default: return {}; case RS2::EntityArc: case RS2::EntityCircle: case RS2::EntityLine: case RS2::EntityEllipse: break; } const RS_Vector vp = entity->getNearestPointOnEntity(coord, false); double const a1 = angle + entity->getTangentDirection(vp).angle(); RS_Vector const v1 = RS_Vector::polar(length, a1); auto ret = std::make_unique(m_container, coord, coord+v1); bool addedToUndo = setupAndAddEntity(ret.get()); if (addedToUndo) { ret.release(); return {}; } return ret; } /** * Creates a polygon with 'number' edges. * * @param center Center of the polygon. * @param corner The first corner of the polygon * @param number Number of edges / corners. */ RS_Line* RS_Creation::createPolygon(const RS_Vector& center, const RS_Vector& corner, int number) { // check given coords / number: if (!center.valid || !corner.valid || number<3) { return nullptr; } RS_Line* ret = nullptr; double const r = center.distanceTo(corner); double const angle0 = center.angleTo(corner); double const da = 2.*M_PI/number; LC_UndoSection undo( m_document,m_viewport, handleUndo); for (int i=0; i < number; ++i) { auto c0 = center + RS_Vector::polar(r, angle0 + i*da); auto c1 = center + RS_Vector::polar(r, angle0 + ((i+1)%number)*da); auto* line = new RS_Line{m_container, c0, c1}; line->setLayerToActive(); line->setPenToActive(); if (!ret) { ret = line; } if (m_container) { m_container->addEntity(line); } undo.addUndoable(line); } return ret; } /** * Creates a polygon with 'number' edges. * * @param corner1 The first corner of the polygon. * @param corner2 The second corner of the polygon. * @param number Number of edges / corners. */ RS_Line* RS_Creation::createPolygon2(const RS_Vector& corner1, const RS_Vector& corner2, int number) { // check given coords / number: if (!corner1.valid || !corner2.valid || number<3) { return nullptr; } RS_Line* ret = nullptr; LC_UndoSection undo( m_document,m_viewport, handleUndo); double const len = corner1.distanceTo(corner2); double const da = 2.*M_PI/number; double const r = 0.5*len/std::sin(0.5*da); double const angle1 = corner1.angleTo(corner2); RS_Vector center = (corner1 + corner2)*0.5; //TODO, the center or the polygon could be at left or right side //left is chosen here center += RS_Vector::polar(0.5*len/tan(0.5*da), angle1 + M_PI_2); double const angle0 = center.angleTo(corner1); for (int i=0; isetLayerToActive(); line->setPenToActive(); if (!ret) { ret = line; } if (m_container) { m_container->addEntity(line); } undo.addUndoable(line); } return ret; } /** * Creates a polygon with 'number' edges. * * @param center Center of the polygon. * @param tangent The first tangent of the polygon with a circle * @param number Number of edges / corners. */ RS_Line* RS_Creation::createPolygon3(const RS_Vector& center, //added by txmy const RS_Vector& tangent, int number) { // check given coords / number: if (!center.valid || !tangent.valid || number<3) { return nullptr; } RS_Line* ret = nullptr; LC_UndoSection undo( m_document, m_viewport,handleUndo); RS_Vector corner(0, 0); double angle = 2.*M_PI/number/2.0; corner.x = tangent.x + (center.y - tangent.y) * tan(angle); corner.y = tangent.y + (tangent.x - center.x) * tan(angle); double const r = center.distanceTo(corner); double const angle0 = center.angleTo(corner); double const da = 2.*M_PI/number; for (int i=0; i < number; ++i) { auto c0 = center + RS_Vector::polar(r, angle0 + i*da); auto c1 = center + RS_Vector::polar(r, angle0 + ((i+1)%number)*da); auto* line = new RS_Line{m_container, c0, c1}; line->setLayerToActive(); line->setPenToActive(); if (!ret) { ret = line; } if (m_container) { m_container->addEntity(line); } undo.addUndoable(line); } return ret; } /** * Creates an insert with the given data. * * @param data Insert data (position, block name, ..) */ RS_Insert* RS_Creation::createInsert(const RS_InsertData* pdata) { RS_DEBUG->print("RS_Creation::createInsert"); LC_UndoSection undo( m_document, m_viewport,handleUndo); auto ins = new RS_Insert(m_container, *pdata); // inserts are also on layers setupAndAddEntity(ins); RS_DEBUG->print("RS_Creation::createInsert: OK"); return ins; } /** * Creates an image with the given data. */ RS_Image* RS_Creation::createImage(const RS_ImageData* data) { LC_UndoSection undo( m_document, m_viewport,handleUndo); auto* img = new RS_Image(m_container, *data); img->update(); setupAndAddEntity(img); return img; } /** * Creates a new block from the currently selected entitiies. * * @param referencePoint Reference point for the block. * @param name Block name * @param remove true: remove existing entities, false: don't touch entities */ RS_Block* RS_Creation::createBlock(const RS_BlockData* data, const RS_Vector& referencePoint, const bool remove) { // start undo cycle for the container if we're deleting the existing entities LC_UndoSection undo(m_document, m_viewport,remove); RS_Block* block; // Block cannot contain blocks. if (m_container->rtti() == RS2::EntityBlock) { block = new RS_Block(m_container->getParent(), RS_BlockData(*data)); } else { block = new RS_Block(m_container, RS_BlockData(*data)); } // copy entities into a block for(auto e: *m_container){ // fixme - iterating all entities for selection if (e != nullptr && e->isSelected()) { // delete / redraw entity in graphic view: if (remove) { // fixme - what's this? same logic there? e->setSelected(false); } else { e->setSelected(false); } // add entity to block: RS_Entity* c = e->clone(); c->move(-referencePoint); block->addEntity(c); if (remove) { //container->removeEntity(e); //i=0; e->changeUndoState(); undo.addUndoable(e); } } } if (m_graphic != nullptr) { m_graphic->addBlock(block); } return block; } /** * Inserts a library item from the given path into the drawing. */ RS_Insert* RS_Creation::createLibraryInsert(RS_LibraryInsertData& data) { RS_DEBUG->print("RS_Creation::createLibraryInsert"); RS_Graphic* insertGraphic = data.graphic; if (insertGraphic == nullptr) { return nullptr; } // unit conversion: if (m_graphic != nullptr) { double uf = RS_Units::convert(1.0, insertGraphic->getUnit(),m_graphic->getUnit()); insertGraphic->scale(RS_Vector(0.0, 0.0), RS_Vector(uf, uf)); } QString insertFileName = QFileInfo(data.file).completeBaseName(); RS_Modification m(*m_container, m_viewport); m.paste( RS_PasteData(data.insertionPoint,data.factor, data.angle, true,insertFileName),insertGraphic); RS_DEBUG->print("RS_Creation::createLibraryInsert: OK"); return nullptr; } bool RS_Creation::setupAndAddEntity(RS_Entity* en) const{ // this check is overkill - plus, if null is there - it's severe error of the developer. // // Returning false may lead to indefinite behavior. // // It's better to have a crash during the development with clear indication that something is wrong, // than try to find some subtle effects based on the user-provided report // if something may crash - it should fail as fast as possible. // // and MOREOVER! // this is just a private method of this class. // HOW IT MIGHT BE THAT CREATED ENTITY IS NULL???? assert(en != nullptr); /*if (en == nullptr) return false;*/ en->setLayerToActive(); en->setPenToActive(); if (m_container) { m_container->addEntity(en); } // why in general it could be null there? it's better to check in constructor once and // prohibit passing null during creation of RS_Creation. if (m_viewport != nullptr) { // fixme - sand - P.S. again, having undo semantic mixed with creation logic is just a mess... LC_UndoSection undo(m_document, m_viewport, handleUndo); undo.addUndoable(en); return true;// fixme - sand - what if handle undo is false? in this sense, true is not correct... } return false; }