/**************************************************************************** ** ** 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 #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(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(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; }