FreeCAD / src /Gui /PreferencePages /DlgSettingsLightSources.cpp
AbdulElahGwaith's picture
Upload folder using huggingface_hub
985c397 verified
// SPDX-License-Identifier: LGPL-2.1-or-later
/***************************************************************************
* Copyright (c) 2023 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of FreeCAD. *
* *
* FreeCAD is free software: you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 2.1 of the *
* License, or (at your option) any later version. *
* *
* FreeCAD 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 *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with FreeCAD. If not, see *
* <https://www.gnu.org/licenses/>. *
* *
**************************************************************************/
#include <Inventor/events/SoEvent.h>
#include <Inventor/nodes/SoDirectionalLight.h>
#include <Inventor/nodes/SoEventCallback.h>
#include <Inventor/nodes/SoOrthographicCamera.h>
#include <Inventor/nodes/SoComplexity.h>
#include <Inventor/nodes/SoSeparator.h>
#include <Inventor/nodes/SoMaterial.h>
#include <Inventor/nodes/SoSphere.h>
#include "DlgSettingsLightSources.h"
#include "ui_DlgSettingsLightSources.h"
#include <Utilities.h>
#include <Base/Builder3D.h>
#include <Base/Tools.h>
#include <Gui/View3DInventorViewer.h>
#include <Gui/View3DSettings.h>
using namespace Gui::Dialog;
/* TRANSLATOR Gui::Dialog::DlgSettingsLightSources */
DlgSettingsLightSources::DlgSettingsLightSources(QWidget* parent)
: PreferencePage(parent)
, ui(new Ui_DlgSettingsLightSources)
{
ui->setupUi(this);
view = ui->viewer;
configureViewer();
const auto connectLightEvents = [this](
QuantitySpinBox* horizontalAngleSpinBox,
QuantitySpinBox* verticalAngleSpinBox,
QSpinBox* intensitySpinBox,
ColorButton* colorButton,
QCheckBox* enabledCheckbox,
auto updateLightFunction
) {
connect(
horizontalAngleSpinBox,
qOverload<double>(&QuantitySpinBox::valueChanged),
this,
updateLightFunction
);
connect(
verticalAngleSpinBox,
qOverload<double>(&QuantitySpinBox::valueChanged),
this,
updateLightFunction
);
connect(intensitySpinBox, qOverload<int>(&QSpinBox::valueChanged), this, updateLightFunction);
connect(colorButton, &ColorButton::changed, this, updateLightFunction);
#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0)
connect(enabledCheckbox, &QCheckBox::checkStateChanged, this, updateLightFunction);
#else
connect(enabledCheckbox, &QCheckBox::stateChanged, this, updateLightFunction);
#endif
};
const auto updateLight = [this](
SoDirectionalLight* light,
QuantitySpinBox* horizontalAngleSpinBox,
QuantitySpinBox* verticalAngleSpinBox,
QSpinBox* intensitySpinBox,
ColorButton* colorButton,
QCheckBox* enabledCheckbox,
std::function<void(bool)> setLightEnabled
) {
light->color = Base::convertTo<SbColor>(colorButton->color());
light->intensity = Base::fromPercent(intensitySpinBox->value());
light->direction = Base::convertTo<SbVec3f>(azimuthElevationToDirection(
horizontalAngleSpinBox->rawValue(),
verticalAngleSpinBox->rawValue()
));
setLightEnabled(enabledCheckbox->isChecked());
};
const auto updateHeadLight = [this, updateLight] {
updateLight(
view->getHeadlight(),
ui->mainLightHorizontalAngle,
ui->mainLightVerticalAngle,
ui->mainLightIntensitySpinBox,
ui->mainLightColor,
ui->mainLightEnable,
[this](bool enabled) { view->setHeadlightEnabled(enabled); }
);
};
const auto updateFillLight = [this, updateLight] {
updateLight(
view->getFillLight(),
ui->fillLightHorizontalAngle,
ui->fillLightVerticalAngle,
ui->fillLightIntensitySpinBox,
ui->fillLightColor,
ui->fillLightEnable,
[this](bool enabled) { view->setFillLightEnabled(enabled); }
);
};
const auto updateBackLight = [this, updateLight] {
updateLight(
view->getBacklight(),
ui->backLightHorizontalAngle,
ui->backLightVerticalAngle,
ui->backLightIntensitySpinBox,
ui->backLightColor,
ui->backLightEnable,
[this](bool enabled) { view->setBacklightEnabled(enabled); }
);
};
connectLightEvents(
ui->mainLightHorizontalAngle,
ui->mainLightVerticalAngle,
ui->mainLightIntensitySpinBox,
ui->mainLightColor,
ui->mainLightEnable,
updateHeadLight
);
connectLightEvents(
ui->backLightHorizontalAngle,
ui->backLightVerticalAngle,
ui->backLightIntensitySpinBox,
ui->backLightColor,
ui->backLightEnable,
updateBackLight
);
connectLightEvents(
ui->fillLightHorizontalAngle,
ui->fillLightVerticalAngle,
ui->fillLightIntensitySpinBox,
ui->fillLightColor,
ui->fillLightEnable,
updateFillLight
);
const auto updateAmbientLight = [this] {
view->getEnvironment()->ambientColor = Base::convertTo<SbColor>(ui->ambientLightColor->color());
view->getEnvironment()->ambientIntensity = Base::fromPercent(
ui->ambientLightIntensitySpinBox->value()
);
};
connect(
ui->ambientLightIntensitySpinBox,
qOverload<int>(&QSpinBox::valueChanged),
this,
updateAmbientLight
);
connect(ui->ambientLightColor, &ColorButton::changed, this, updateAmbientLight);
connect(ui->zoomInButton, &QToolButton::clicked, this, &DlgSettingsLightSources::zoomIn);
connect(ui->zoomOutButton, &QToolButton::clicked, this, &DlgSettingsLightSources::zoomOut);
DlgSettingsLightSources::loadSettings();
}
static inline SoMaterial* createMaterial(void)
{
const QColor ambientColor {0xff333333}, diffuseColor {0xffd2d2ff}, emissiveColor {0xff000000},
specularColor {0xffcccccc};
auto material = new SoMaterial();
material->ambientColor.setValue(Base::convertTo<SbColor>(ambientColor));
material->diffuseColor.setValue(Base::convertTo<SbColor>(diffuseColor));
material->emissiveColor.setValue(Base::convertTo<SbColor>(emissiveColor));
material->specularColor.setValue(Base::convertTo<SbColor>(specularColor));
material->shininess = 0.9f;
return material;
}
static inline SoSphere* createSphere(void)
{
auto sphere = new SoSphere();
sphere->radius = 3;
return sphere;
}
static inline SoComplexity* createGoodComplexity()
{
auto complexity = new SoComplexity();
complexity->value = 1.0;
return complexity;
}
void DlgSettingsLightSources::configureViewer()
{
const SbVec3f defaultViewDirection {0.0f, 1.0f, 0.3f};
View3DSettings(hGrpView, view).applySettings();
view->setRedirectToSceneGraph(true);
view->setViewing(true);
view->setPopupMenuEnabled(false);
view->setEnabledNaviCube(false);
const auto root = static_cast<SoSeparator*>(view->getSceneGraph());
root->addChild(createGoodComplexity());
root->addChild(createMaterial());
root->addChild(createSphere());
const auto callback = new SoEventCallback();
root->addChild(callback);
callback->addEventCallback(
SoEvent::getClassTypeId(),
[]([[maybe_unused]] void* ud, SoEventCallback* cb) { cb->setHandled(); }
);
view->setCameraType(SoOrthographicCamera::getClassTypeId());
view->setViewDirection(defaultViewDirection);
view->viewAll();
camera = dynamic_cast<SoOrthographicCamera*>(view->getCamera());
const float cameraHeight = camera->height.getValue() * 2.0f;
camera->height = cameraHeight;
zoomStep = cameraHeight / 14.0f;
}
Base::Vector3d DlgSettingsLightSources::azimuthElevationToDirection(double azimuth, double elevation)
{
azimuth = Base::toRadians(azimuth);
elevation = Base::toRadians(elevation);
auto direction = Base::Vector3d {
std::sin(azimuth) * std::cos(elevation),
std::cos(azimuth) * std::cos(elevation),
std::sin(elevation)
};
direction.Normalize();
return direction;
}
std::pair<double, double> DlgSettingsLightSources::directionToAzimuthElevation(Base::Vector3d direction)
{
const auto azimuth = std::atan2(direction[0], direction[1]);
const auto elevation = std::atan2(
direction[2],
std::sqrt(direction[1] * direction[1] + direction[0] * direction[0])
);
return {Base::toDegrees(azimuth), Base::toDegrees(elevation)};
}
void DlgSettingsLightSources::saveSettings()
{
for (const auto& widget : findChildren<QWidget*>()) {
if (const auto pref = dynamic_cast<PrefWidget*>(widget)) {
pref->onSave();
}
}
const auto saveAngles = [this](
QuantitySpinBox* horizontalAngleSpinBox,
QuantitySpinBox* verticalAngleSpinBox,
const char* parameter
) {
try {
const auto direction = azimuthElevationToDirection(
horizontalAngleSpinBox->rawValue(),
verticalAngleSpinBox->rawValue()
);
hGrp->SetASCII(parameter, Base::vectorToString(Base::convertTo<Base::Vector3f>(direction)));
}
catch (...) {
}
};
saveAngles(ui->mainLightHorizontalAngle, ui->mainLightVerticalAngle, "HeadlightDirection");
saveAngles(ui->backLightHorizontalAngle, ui->backLightVerticalAngle, "BacklightDirection");
saveAngles(ui->fillLightHorizontalAngle, ui->fillLightVerticalAngle, "FillLightDirection");
}
void DlgSettingsLightSources::loadSettings()
{
for (const auto& widget : findChildren<QWidget*>()) {
if (const auto pref = dynamic_cast<PrefWidget*>(widget)) {
pref->onRestore();
}
}
const auto loadAngles = [this](
QuantitySpinBox* horizontalAngleSpinBox,
QuantitySpinBox* verticalAngleSpinBox,
const char* parameter
) {
try {
const auto direction = Base::stringToVector(hGrp->GetASCII(parameter));
const auto [azimuth, elevation] = directionToAzimuthElevation(
Base::convertTo<Base::Vector3d>(direction)
);
horizontalAngleSpinBox->setValue(azimuth);
verticalAngleSpinBox->setValue(elevation);
}
catch (...) {
}
};
loadAngles(ui->mainLightHorizontalAngle, ui->mainLightVerticalAngle, "HeadlightDirection");
loadAngles(ui->backLightHorizontalAngle, ui->backLightVerticalAngle, "BacklightDirection");
loadAngles(ui->fillLightHorizontalAngle, ui->fillLightVerticalAngle, "FillLightDirection");
}
void DlgSettingsLightSources::resetSettingsToDefaults()
{
PreferencePage::resetSettingsToDefaults();
hGrp->RemoveASCII("HeadlightDirection");
hGrp->RemoveASCII("BacklightDirection");
hGrp->RemoveASCII("FillLightDirection");
loadSettings();
configureViewer();
}
void DlgSettingsLightSources::zoomIn() const
{
if (camera == nullptr) {
return;
}
camera->height = camera->height.getValue() - zoomStep;
}
void DlgSettingsLightSources::zoomOut() const
{
if (camera == nullptr) {
return;
}
camera->height = camera->height.getValue() + zoomStep;
}
void DlgSettingsLightSources::changeEvent(QEvent* event)
{
if (event->type() == QEvent::LanguageChange) {
ui->retranslateUi(this);
}
PreferencePage::changeEvent(event);
}
#include "moc_DlgSettingsLightSources.cpp"