This commit is generated using regex based find and replace: ``` s/[\w:]+_cast\s*<([^>]+)\*>\s*\(\s*getObject\(\s*\)\)/getObject<$1>/ s/[\w:]+_cast\s*<([^>]+)\*>\s*\(\s*([^)]*)\s*->\s*getObject\(\s*\)\)/$2->getObject<$1>()/ ``` To regenerate if needed.
345 lines
11 KiB
C++
345 lines
11 KiB
C++
/***************************************************************************
|
|
* Copyright (c) 2011 Jürgen Riegel (juergen.riegel@web.de) *
|
|
* *
|
|
* This file is part of the FreeCAD CAx development system. *
|
|
* *
|
|
* This library is free software; you can redistribute it and/or *
|
|
* modify it under the terms of the GNU Library General Public *
|
|
* License as published by the Free Software Foundation; either *
|
|
* version 2 of the License, or (at your option) any later version. *
|
|
* *
|
|
* This library 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 Library General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU Library General Public *
|
|
* License along with this library; see the file COPYING.LIB. If not, *
|
|
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
|
* Suite 330, Boston, MA 02111-1307, USA *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#include "PreCompiled.h"
|
|
#ifndef _PreComp_
|
|
# include <sstream>
|
|
# include <QAction>
|
|
# include <QFileInfo>
|
|
# include <QImage>
|
|
# include <QMenu>
|
|
# include <QString>
|
|
# include <QSvgRenderer>
|
|
# include <Inventor/nodes/SoCoordinate3.h>
|
|
# include <Inventor/nodes/SoFaceSet.h>
|
|
# include <Inventor/nodes/SoLightModel.h>
|
|
# include <Inventor/nodes/SoMaterial.h>
|
|
# include <Inventor/nodes/SoSeparator.h>
|
|
# include <Inventor/nodes/SoShapeHints.h>
|
|
# include <Inventor/nodes/SoTexture2.h>
|
|
# include <Inventor/nodes/SoTextureCoordinate2.h>
|
|
#endif
|
|
|
|
#include <App/Document.h>
|
|
#include <Gui/ActionFunction.h>
|
|
#include <Gui/BitmapFactory.h>
|
|
#include <Gui/Control.h>
|
|
#include <Gui/TaskView/TaskImage.h>
|
|
#include <App/ImagePlane.h>
|
|
|
|
#include "ViewProviderImagePlane.h"
|
|
|
|
|
|
using namespace Gui;
|
|
|
|
|
|
PROPERTY_SOURCE(Gui::ViewProviderImagePlane, Gui::ViewProviderGeometryObject)
|
|
const char* ViewProviderImagePlane::LightingEnums[]= {"One side", "Two side", nullptr};
|
|
|
|
ViewProviderImagePlane::ViewProviderImagePlane()
|
|
{
|
|
ADD_PROPERTY_TYPE(Lighting,(1L), "Object Style", App::Prop_None, "Set object lighting.");
|
|
Lighting.setEnums(LightingEnums);
|
|
|
|
texture = new SoTexture2;
|
|
texture->ref();
|
|
|
|
pcCoords = new SoCoordinate3();
|
|
pcCoords->ref();
|
|
|
|
shapeHints = new SoShapeHints;
|
|
shapeHints->shapeType = SoShapeHints::UNKNOWN_SHAPE_TYPE;
|
|
shapeHints->vertexOrdering = SoShapeHints::COUNTERCLOCKWISE;
|
|
shapeHints->ref();
|
|
|
|
sPixmap = "image-plane";
|
|
|
|
ShapeAppearance.setDiffuseColor(1.0F, 1.0F, 1.0F);
|
|
}
|
|
|
|
ViewProviderImagePlane::~ViewProviderImagePlane()
|
|
{
|
|
pcCoords->unref();
|
|
texture->unref();
|
|
shapeHints->unref();
|
|
}
|
|
|
|
void ViewProviderImagePlane::attach(App::DocumentObject *pcObj)
|
|
{
|
|
ViewProviderGeometryObject::attach(pcObj);
|
|
|
|
// NOTE: SoFCSelection node has beem removed because it led to
|
|
// problems using the image as a construction plane with the
|
|
// draft commands
|
|
SoSeparator* shading = new SoSeparator;
|
|
shading->addChild(pcCoords);
|
|
|
|
SoTextureCoordinate2 *textCoord = new SoTextureCoordinate2;
|
|
textCoord->point.set1Value(0,0,0);
|
|
textCoord->point.set1Value(1,1,0);
|
|
textCoord->point.set1Value(2,1,1);
|
|
textCoord->point.set1Value(3,0,1);
|
|
shading->addChild(textCoord);
|
|
|
|
// texture
|
|
texture->model = SoTexture2::MODULATE;
|
|
shading->addChild(texture);
|
|
|
|
shading->addChild(shapeHints);
|
|
shading->addChild(pcShapeMaterial);
|
|
|
|
// plane
|
|
pcCoords->point.set1Value(0,0,0,0);
|
|
pcCoords->point.set1Value(1,1,0,0);
|
|
pcCoords->point.set1Value(2,1,1,0);
|
|
pcCoords->point.set1Value(3,0,1,0);
|
|
SoFaceSet *faceset = new SoFaceSet;
|
|
faceset->numVertices.set1Value(0,4);
|
|
shading->addChild(faceset);
|
|
|
|
addDisplayMaskMode(shading, "Shading");
|
|
|
|
SoLightModel* lightmodel = new SoLightModel;
|
|
lightmodel->model = SoLightModel::BASE_COLOR;
|
|
|
|
SoSeparator* noshading = new SoSeparator;
|
|
noshading->addChild(pcCoords);
|
|
noshading->addChild(textCoord);
|
|
noshading->addChild(texture);
|
|
noshading->addChild(shapeHints);
|
|
noshading->addChild(pcShapeMaterial);
|
|
noshading->addChild(lightmodel);
|
|
noshading->addChild(faceset);
|
|
|
|
addDisplayMaskMode(noshading, "No shading");
|
|
}
|
|
|
|
void ViewProviderImagePlane::setDisplayMode(const char* ModeName)
|
|
{
|
|
if (strcmp("Shading", ModeName) == 0) {
|
|
setDisplayMaskMode("Shading");
|
|
}
|
|
else if (strcmp("No shading", ModeName) == 0) {
|
|
setDisplayMaskMode("No shading");
|
|
}
|
|
ViewProviderGeometryObject::setDisplayMode(ModeName);
|
|
}
|
|
|
|
std::vector<std::string> ViewProviderImagePlane::getDisplayModes() const
|
|
{
|
|
std::vector<std::string> StrList;
|
|
StrList.emplace_back("Shading");
|
|
StrList.emplace_back("No shading");
|
|
return StrList;
|
|
}
|
|
|
|
void ViewProviderImagePlane::onChanged(const App::Property* prop)
|
|
{
|
|
if (prop == &Lighting) {
|
|
if (Lighting.getValue() == 0)
|
|
shapeHints->vertexOrdering = SoShapeHints::UNKNOWN_ORDERING;
|
|
else
|
|
shapeHints->vertexOrdering = SoShapeHints::COUNTERCLOCKWISE;
|
|
}
|
|
ViewProviderGeometryObject::onChanged(prop);
|
|
}
|
|
|
|
void ViewProviderImagePlane::setupContextMenu(QMenu* menu, QObject* receiver, const char* member)
|
|
{
|
|
Gui::ActionFunction* func = new Gui::ActionFunction(menu);
|
|
QAction* action = menu->addAction(QObject::tr("Change image..."));
|
|
action->setIcon(QIcon(QLatin1String("images:image-scaling.svg")));
|
|
func->trigger(action, [this](){
|
|
this->manipulateImage();
|
|
});
|
|
|
|
ViewProviderGeometryObject::setupContextMenu(menu, receiver, member);
|
|
}
|
|
|
|
bool ViewProviderImagePlane::doubleClicked()
|
|
{
|
|
manipulateImage();
|
|
return true;
|
|
}
|
|
|
|
void ViewProviderImagePlane::manipulateImage()
|
|
{
|
|
auto dialog = new TaskImageDialog(getObject<Image::ImagePlane>());
|
|
|
|
Gui::Control().showDialog(dialog);
|
|
}
|
|
|
|
void ViewProviderImagePlane::resizePlane(float xsize, float ysize)
|
|
{
|
|
pcCoords->point.set1Value(0,-(xsize/2),-(ysize/2),0.0);
|
|
pcCoords->point.set1Value(1,+(xsize/2),-(ysize/2),0.0);
|
|
pcCoords->point.set1Value(2,+(xsize/2),+(ysize/2),0.0);
|
|
pcCoords->point.set1Value(3,-(xsize/2),+(ysize/2),0.0);
|
|
}
|
|
|
|
void ViewProviderImagePlane::loadImage()
|
|
{
|
|
Image::ImagePlane* imagePlane = static_cast<Image::ImagePlane*>(pcObject);
|
|
std::string fileName = imagePlane->ImageFile.getValue();
|
|
|
|
if (!fileName.empty()) {
|
|
QImage impQ;
|
|
if (isSvgFile(fileName.c_str())) {
|
|
impQ = loadSvg(fileName.c_str());
|
|
}
|
|
else {
|
|
impQ = loadRaster(fileName.c_str());
|
|
}
|
|
|
|
QSizeF size = getSizeInMM(impQ);
|
|
setPlaneSize(size, impQ);
|
|
convertToSFImage(impQ);
|
|
}
|
|
}
|
|
|
|
void ViewProviderImagePlane::setPlaneSize(const QSizeF& size, const QImage& img)
|
|
{
|
|
if (!img.isNull()) {
|
|
Image::ImagePlane* imagePlane = static_cast<Image::ImagePlane*>(pcObject);
|
|
// When restoring the document or importing a ImagePlane by eg. pasting it
|
|
// preserve the X and Y size.
|
|
if (!isRestoring() && !pcObject->testStatus(App::ObjectStatus::ObjImporting)) {
|
|
imagePlane->XSize.setValue(size.width());
|
|
imagePlane->YSize.setValue(size.height());
|
|
}
|
|
|
|
imagePlane->XPixelsPerMeter = img.dotsPerMeterX();
|
|
imagePlane->YPixelsPerMeter = img.dotsPerMeterY();
|
|
}
|
|
}
|
|
|
|
QImage ViewProviderImagePlane::loadRaster(const char* fileName) const
|
|
{
|
|
QImage img;
|
|
img.load(QString::fromUtf8(fileName));
|
|
return img;
|
|
}
|
|
|
|
void ViewProviderImagePlane::reloadIfSvg()
|
|
{
|
|
Image::ImagePlane* imagePlane = static_cast<Image::ImagePlane*>(pcObject);
|
|
std::string fileName = imagePlane->ImageFile.getValue();
|
|
|
|
if (isSvgFile(fileName.c_str())) {
|
|
double xsize = imagePlane->XSize.getValue();
|
|
double ysize = imagePlane->YSize.getValue();
|
|
|
|
QImage impQ = loadSvgOfSize(fileName.c_str(), QSizeF(xsize, ysize));
|
|
convertToSFImage(impQ);
|
|
}
|
|
}
|
|
|
|
QImage ViewProviderImagePlane::loadSvg(const char* filename) const
|
|
{
|
|
QSizeF defaultSize = defaultSizeOfSvg(filename);
|
|
QPixmap px = BitmapFactory().pixmapFromSvg(filename, defaultSize);
|
|
return px.toImage();
|
|
}
|
|
|
|
QImage ViewProviderImagePlane::loadSvgOfSize(const char* filename, const QSizeF& size) const
|
|
{
|
|
QSizeF psize = pixelSize(filename, size);
|
|
QPixmap px = BitmapFactory().pixmapFromSvg(filename, psize);
|
|
return px.toImage();
|
|
}
|
|
|
|
bool ViewProviderImagePlane::isSvgFile(const char* filename) const
|
|
{
|
|
QFileInfo fi(QString::fromUtf8(filename));
|
|
return (fi.suffix().toLower() == QLatin1String("svg"));
|
|
}
|
|
|
|
QSizeF ViewProviderImagePlane::defaultSizeOfSvg(const char* filename) const
|
|
{
|
|
QSvgRenderer svg;
|
|
svg.load(QString::fromUtf8(filename));
|
|
return svg.defaultSize();
|
|
}
|
|
|
|
QSizeF ViewProviderImagePlane::getSizeInMM(const QImage& img) const
|
|
{
|
|
double xPixelsPerM = img.dotsPerMeterX();
|
|
double width = img.width();
|
|
width = width * 1000 / xPixelsPerM;
|
|
|
|
double yPixelsPerM = img.dotsPerMeterY();
|
|
double height = img.height();
|
|
height = height * 1000 / yPixelsPerM;
|
|
|
|
QSizeF sizef;
|
|
sizef.setWidth(width);
|
|
sizef.setHeight(height);
|
|
return sizef;
|
|
}
|
|
|
|
QSizeF ViewProviderImagePlane::pixelSize(const char* filename, const QSizeF& size) const
|
|
{
|
|
QImage tmp;
|
|
if (tmp.load(QString::fromUtf8(filename))) {
|
|
double xPixelsPerM = tmp.dotsPerMeterX();
|
|
double yPixelsPerM = tmp.dotsPerMeterY();
|
|
|
|
double width = size.width();
|
|
double height = size.height();
|
|
|
|
width = width * xPixelsPerM / 1000;
|
|
height = height * yPixelsPerM / 1000;
|
|
|
|
return {width, height};
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
void ViewProviderImagePlane::convertToSFImage(const QImage& img)
|
|
{
|
|
if (!img.isNull()) {
|
|
SoSFImage sfimg;
|
|
// convert to Coin bitmap
|
|
BitmapFactory().convert(img, sfimg);
|
|
texture->image = sfimg;
|
|
}
|
|
}
|
|
|
|
void ViewProviderImagePlane::updateData(const App::Property* prop)
|
|
{
|
|
Image::ImagePlane* pcPlaneObj = static_cast<Image::ImagePlane*>(pcObject);
|
|
if (prop == &pcPlaneObj->XSize || prop == &pcPlaneObj->YSize) {
|
|
float xsize = pcPlaneObj->XSize.getValue();
|
|
float ysize = pcPlaneObj->YSize.getValue();
|
|
|
|
resizePlane(xsize, ysize);
|
|
reloadIfSvg();
|
|
}
|
|
else if (prop == &pcPlaneObj->ImageFile) {
|
|
loadImage();
|
|
}
|
|
else {
|
|
Gui::ViewProviderGeometryObject::updateData(prop);
|
|
}
|
|
}
|