Merge branch 'devel' into devel-PFasano99

# Conflicts:
#	.github/workflows/BuildMeshLab.yml
#	src/vcglib
This commit is contained in:
alemuntoni 2023-10-16 14:58:57 +02:00
commit 8724db38b3
23 changed files with 858 additions and 177 deletions

23
.github/actions/0_setup/action.yml vendored Normal file
View File

@ -0,0 +1,23 @@
name: 'Setup Environment'
description: 'Setup Environment'
inputs:
qt-version:
description: 'Qt Version'
required: false
default: '5.15.2'
runs:
using: "composite"
steps:
- name: Setup MSVC
uses: ilammy/msvc-dev-cmd@v1
- name: Install Qt
uses: jurplel/install-qt-action@v3
with:
cache: true
version: ${{ inputs.qt-version }}
- name: Install dependencies
shell: bash
run: |
bash scripts/${{ runner.os }}/0_setup_env.sh --dont_install_qt

56
.github/actions/1_build/action.yml vendored Normal file
View File

@ -0,0 +1,56 @@
name: 'Build'
description: 'Build'
inputs:
cache-path:
description: 'Directory to cache after build'
required: false
default: ''
cache-key:
description: 'Cache key'
required: false
default: ''
build-option:
description: 'Build option'
required: false
default: ''
nightly:
description: 'Nightly build'
required: false
type: boolean
default: false
runs:
using: "composite"
steps:
- name: Setup env variables
id: envs
shell: bash
run: |
if [ "${{ inputs.build-option }}" != "" ]; then
echo "build_option=--${{ inputs.build-option }}" >> $GITHUB_OUTPUT
echo "artifact_suffix=_${{ inputs.build-option }}" >> $GITHUB_OUTPUT
else
echo "build_option=" >> $GITHUB_OUTPUT
echo "artifact_suffix=" >> $GITHUB_OUTPUT
fi
if [ "${{ inputs.nightly }}" = "true" ]; then
echo "nightly=--nightly" >> $GITHUB_OUTPUT
else
echo "nightly=" >> $GITHUB_OUTPUT
fi
- name: Cache external libraries sources
id: cache-ext-libs
if: ${{ inputs.cache-path != '' }}
uses: actions/cache@v3
with:
path: ${{ inputs.cache-path }}
key: ${{ runner.os }}-${{ inputs.cache-key }}
- name: Ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ${{ runner.os }}-${{ github.ref }}-${{ inputs.build-option }}
- name: Configure and Build
shell: bash
run: |
bash scripts/${{ runner.os }}/1_build.sh ${{ steps.envs.outputs.build_option }} ${{ steps.envs.outputs.nightly }} --ccache

65
.github/actions/2_deploy/action.yml vendored Normal file
View File

@ -0,0 +1,65 @@
name: 'Deploy'
description: 'Deploy'
inputs:
mac-certificate:
description: 'MacOS Certificate'
required: false
default: ''
mac-certificate-id:
description: 'MacOS Certificate ID'
required: false
default: ''
mac-certificate-pssw:
description: 'MacOS Certificate Password'
required: false
mac-notarization-user:
description: 'MacOS Notarization User'
required: false
default: ''
mac-notarization-team:
description: 'MacOS Notarization Team'
required: false
default: ''
mac-notarization-pssw:
description: 'MacOS Notarization Password'
required: false
default: ''
win-certificate:
description: 'Windows Certificate'
required: false
default: ''
win-certificate-pssw:
description: 'Windows Certificate Password'
required: false
default: ''
runs:
using: "composite"
steps:
- name: Set Notarization settings
id: notarization
shell: bash
run: |
if [ "${{ inputs.mac-notarization-user }}" != "" ]; then
echo "not_setting=--notarization_user='${{ inputs.mac-notarization-user }}' --notarization_team='${{ inputs.mac-notarization-team }}' --notarization_pssw='${{ inputs.mac-notarization-pssw }}'" >> $GITHUB_OUTPUT
else
echo "not_setting=" >> $GITHUB_OUTPUT
fi
- name: Set CodeSign Certificate macOS
if: ${{ runner.os == 'macOS' && inputs.mac-certificate != ''}}
uses: apple-actions/import-codesign-certs@v2
with:
p12-file-base64: ${{ inputs.mac-certificate }}
p12-password: ${{ inputs.mac-certificate-pssw }}
- name: Set CodeSign Certificate Windows
shell: powershell
if: ${{ runner.os == 'Windows' && inputs.win-certificate != '' }}
run: |
New-Item -ItemType directory -Path certificate
Set-Content -Path certificate\certificate.txt -Value '${{ inputs.win-certificate }}'
certutil -decode certificate\certificate.txt certificate\certificate.pfx
- name: Deploy
shell: bash
run: |
bash scripts/${{ runner.os }}/2_deploy.sh --cert_pssw='${{ inputs.win-certificate-pssw }}' --cert_id='${{ inputs.mac-certificate-id }}' ${{ steps.notarization.outputs.not_setting }}

2
.github/stale.yml vendored
View File

@ -51,7 +51,7 @@ markComment: >
limitPerRun: 10
# Limit to only `issues` or `pulls`
# only: issues
only: issues
# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
# pulls:

View File

@ -6,6 +6,7 @@ on:
env:
QT_VERSION: 5.15.2
MAC_CERT: ${{secrets.MACOS_CERT_ID}}
MAC_CERT_PSSW: ${{secrets.MACOS_CERTIFICATE_PSSW}}
WIN_CERT: ${{secrets.WIN_CERTIFICATE}}
jobs:
@ -21,29 +22,8 @@ jobs:
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Setup MSVC
uses: ilammy/msvc-dev-cmd@v1
- name: Set CodeSign Certificate macOS
if: runner.os == 'macOS' && env.MAC_CERT != null
uses: apple-actions/import-codesign-certs@v2
with:
p12-file-base64: ${{ secrets.MACOS_CERTIFICATE }}
p12-password: ${{ secrets.MACOS_CERTIFICATE_PSSW }}
- name: Set CodeSign Certificate Windows
if: runner.os == 'Windows' && env.WIN_CERT != null
run: |
New-Item -ItemType directory -Path certificate
Set-Content -Path certificate\certificate.txt -Value '${{ secrets.WIN_CERTIFICATE }}'
certutil -decode certificate\certificate.txt certificate\certificate.pfx
- name: Install Qt
uses: jurplel/install-qt-action@v3
with:
cache: true
version: ${{ env.QT_VERSION }}
- name: Install dependencies
shell: bash
run: |
bash scripts/${{ runner.os }}/0_setup_env.sh --dont_install_qt
- name: Setup Environment
uses: ./.github/actions/0_setup
- name: Setup env variables
id: envs
shell: bash
@ -53,24 +33,20 @@ jobs:
else
echo "artifact_suffix=" >> $GITHUB_OUTPUT
fi
- name: Cache external libraries sources
id: cache-ext-libs
uses: actions/cache@v3
with:
path: src/external/downloads/*
key: ${{ runner.os }}-external-libraries
- name: Ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ${{ runner.os }}-${{ github.ref }}-${{ matrix.precision }}
- name: Configure and Build
shell: bash
run: |
bash scripts/${{ runner.os }}/1_build.sh --${{ matrix.precision }} --nightly --ccache --use_brew_llvm
- name: Build
uses: ./.github/actions/1_build
cache-path: src/external/downloads/*
cache-key: external-libraries
build-option: ${{matrix.precision}}
nightly: true
- name: Deploy
shell: bash
run: |
bash scripts/${{ runner.os }}/2_deploy.sh --cert_pssw='${{ secrets.WIN_CERTIFICATE_PSSW }}' --cert_id=${{ secrets.MACOS_CERT_ID }}
uses: ./.github/actions/2_deploy
with:
mac-certificate: ${{ secrets.MACOS_CERTIFICATE }}
mac-certificate-id: ${{ secrets.MACOS_CERT_ID }}
mac-certificate-pssw: ${{ secrets.MACOS_CERTIFICATE_PSSW }}
win-certificate: ${{ secrets.WIN_CERTIFICATE }}
win-certificate-pssw: ${{ secrets.WIN_CERTIFICATE_PSSW }}
- name: Upload MeshLab Portable
uses: actions/upload-artifact@v3
with:

View File

@ -41,29 +41,8 @@ jobs:
with:
submodules: recursive
ref: main
- name: Setup MSVC
uses: ilammy/msvc-dev-cmd@v1
- name: Set CodeSign Certificate macOS
if: runner.os == 'macOS'
uses: apple-actions/import-codesign-certs@v2
with:
p12-file-base64: ${{ secrets.MACOS_CERTIFICATE }}
p12-password: ${{ secrets.MACOS_CERTIFICATE_PSSW }}
- name: Set CodeSign Certificate Windows
if: runner.os == 'Windows'
run: |
New-Item -ItemType directory -Path certificate
Set-Content -Path certificate\certificate.txt -Value '${{ secrets.WIN_CERTIFICATE }}'
certutil -decode certificate\certificate.txt certificate\certificate.pfx
- name: Install Qt
uses: jurplel/install-qt-action@v3
with:
cache: true
version: ${{ env.QT_VERSION }}
- name: Install dependencies
shell: bash
run: |
bash scripts/${{ runner.os }}/0_setup_env.sh --dont_install_qt
- name: Setup Environment
uses: ./.github/actions/0_setup
- name: Setup env variables
id: envs
shell: bash
@ -73,44 +52,23 @@ jobs:
else
echo "artifact_suffix=" >> $GITHUB_OUTPUT
fi
- name: Cache external libraries sources
id: cache-ext-libs
uses: actions/cache@v3
- name: Build
uses: ./.github/actions/1_build
with:
path: src/external/downloads/*
key: ${{ runner.os }}-external-libraries
- name: Ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ${{ runner.os }}-${{ github.ref }}-${{ matrix.precision }}
- name: Configure and Build
shell: bash
run: |
bash scripts/${{ runner.os }}/1_build.sh --${{ matrix.precision }} --ccache
cache-path: src/external/downloads/*
cache-key: external-libraries
build-option: ${{matrix.precision}}
- name: Deploy
shell: bash
run: |
bash scripts/${{ runner.os }}/2_deploy.sh --cert_pssw='${{ secrets.WIN_CERTIFICATE_PSSW }}' --cert_id=${{ secrets.MACOS_CERT_ID }}
- name: Get AppBundle Name
if: runner.os == 'macOS'
id: abn
shell: bash
run: |
cd install
NAME=$(ls -d MeshLab*)
echo "app_bundle_name=$NAME" >> $GITHUB_OUTPUT
- name: Notarize macOS
if: runner.os == 'macOS'
uses: devbotsxyz/xcode-notarize@v1
uses: ./.github/actions/2_deploy
with:
product-path: "install/${{steps.abn.outputs.app_bundle_name}}"
appstore-connect-username: ${{ secrets.MACOS_NOTARIZATION_USER }}
appstore-connect-password: ${{ secrets.MACOS_NOTARIZATION_PSSW }}
- name: Staple Release macOS
if: runner.os == 'macOS'
uses: devbotsxyz/xcode-staple@v1
with:
product-path: "install/${{steps.abn.outputs.app_bundle_name}}"
mac-certificate: ${{ secrets.MACOS_CERTIFICATE }}
mac-certificate-id: ${{ secrets.MACOS_CERT_ID }}
mac-certificate-pssw: ${{ secrets.MACOS_CERTIFICATE_PSSW }}
mac-notarization-user: ${{ secrets.MACOS_NOTARIZATION_USER }}
mac-notarization-team: ${{ secrets.MACOS_NOTARIZATION_TEAM_ID }}
mac-notarization-pssw: ${{ secrets.MACOS_NOTARIZATION_PSSW }}
win-certificate: ${{ secrets.WIN_CERTIFICATE }}
win-certificate-pssw: ${{ secrets.WIN_CERTIFICATE_PSSW }}
- name: Upload MeshLab Portable
uses: actions/upload-artifact@v3
with:
@ -242,7 +200,7 @@ jobs:
cd ..
#Create release and upload
- uses: "marvinpinto/action-automatic-releases@latest"
- uses: "marvinpinto/action-automatic-releases@6273874b61ebc8c71f1a61b2d98e234cf389b303"
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
automatic_release_tag: "MeshLab-${{steps.envs.outputs.ml_version}}"

View File

@ -30,9 +30,9 @@ case $i in
shift # past argument=value
;;
-cp=*|--cert_pssw=*)
if [ -z "${i#*=}" ]; then
CERT_PSSW="${i#*=}"
if [ -n "$CERT_PSSW" ]; then
SIGN=true
CERT_PSSW="${i#*=}"
fi
shift # past argument=value
;;
@ -60,4 +60,4 @@ if [ "$SIGN" = true ] ; then
bash $SCRIPTS_PATH/internal/2b_sign_dlls.sh -i=$PACKAGES_PATH $CERT_FILE_OPTION -cp=$CERT_PSSW
echo "======= Installer Signed ======="
fi
fi

View File

@ -6,7 +6,11 @@ INSTALL_PATH=$SCRIPTS_PATH/../../install
QT_DIR_OPTION=""
PACKAGES_PATH=$SCRIPTS_PATH/../../packages
SIGN=false
NOTARIZE=false
CERT_ID=""
NOTAR_USER=""
NOTAR_TEAM_ID=""
NOTAR_PASSWORD=""
#checking for parameters
for i in "$@"
@ -25,12 +29,27 @@ case $i in
shift # past argument=value
;;
-ci=*|--cert_id=*)
if [ -z "${i#*=}" ]; then
SIGN=true
CERT_ID="${i#*=}"
CERT_ID="${i#*=}"
if [ -n "$CERT_ID" ]; then
SIGN=true
fi
shift # past argument=value
;;
-nu=*|--notarization_user=*)
NOTAR_USER="${i#*=}"
if [ -n "$NOTAR_USER" ]; then
NOTARIZE=true
fi
shift # past argument=value
;;
-np=*|--notarization_pssw=*)
NOTAR_PASSWORD="${i#*=}"
shift # past argument=value
;;
-nt=*|--notarization_team=*)
NOTAR_TEAM_ID="${i#*=}"
shift # past argument=value
;;
*)
# unknown option
;;
@ -47,6 +66,12 @@ if [ "$SIGN" = true ] ; then
echo "======= AppBundle Signed ======="
fi
bash $SCRIPTS_PATH/internal/2c_dmg.sh -i=$INSTALL_PATH -p=$PACKAGES_PATH
if [ "$NOTARIZE" = true ] ; then
bash $SCRIPTS_PATH/internal/2c_notarize_appbundle.sh -i=$INSTALL_PATH -nu=$NOTAR_USER -nt=$NOTAR_TEAM_ID -np=$NOTAR_PASSWORD
echo "======= AppBundle Notarized ======="
fi
bash $SCRIPTS_PATH/internal/2d_dmg.sh -i=$INSTALL_PATH -p=$PACKAGES_PATH
echo "======= DMG Created ======="

View File

@ -23,4 +23,6 @@ case $i in
esac
done
codesign --options "runtime" --timestamp --force --deep --sign $CERT_ID $INSTALL_PATH/meshlab.app
codesign --options "runtime" --timestamp --force --deep --sign $CERT_ID $INSTALL_PATH/meshlab.app
spctl -a -vvv $INSTALL_PATH/meshlab.app

View File

@ -0,0 +1,44 @@
#!/bin/bash
SCRIPTS_PATH="$(dirname "$(realpath "$0")")"/..
INSTALL_PATH=$SCRIPTS_PATH/../../install
NOTAR_USER=""
NOTAR_PASSWORD=""
NOTAR_TEAM_ID=""
#checking for parameters
for i in "$@"
do
case $i in
-i=*|--install_path=*)
INSTALL_PATH="${i#*=}"
shift # past argument=value
;;
-nu=*|--notarization_user=*)
NOTAR_USER="${i#*=}"
shift # past argument=value
;;
-nt=*|--notarization_team=*)
NOTAR_TEAM_ID="${i#*=}"
shift # past argument=value
;;
-np=*|--notarization_pssw=*)
NOTAR_PASSWORD="${i#*=}"
shift # past argument=value
;;
*)
# unknown option
;;
esac
done
xcrun notarytool store-credentials "notarytool-profile" --apple-id $NOTAR_USER --team-id $NOTAR_TEAM_ID --password $NOTAR_PASSWORD
ditto -c -k --keepParent "$INSTALL_PATH/meshlab.app" "$INSTALL_PATH/notarization.zip"
xcrun notarytool submit "install/notarization.zip" --keychain-profile "notarytool-profile" --wait
xcrun stapler staple "$INSTALL_PATH/meshlab.app"
rm -rf $INSTALL_PATH/notarization.zip

View File

@ -153,7 +153,7 @@ if(NOT DEFINED MESHLAB_PLUGINS) # it may be already defined in parent directory
meshlabplugins/filter_dirt
meshlabplugins/filter_embree
meshlabplugins/filter_fractal
meshlabplugins/filter_func
meshlabplugins/filter_func
meshlabplugins/filter_img_patch_param
meshlabplugins/filter_icp
meshlabplugins/filter_io_nxs

View File

@ -18,7 +18,7 @@ set(CMAKE_C_STANDARD 99)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.11" CACHE STRING "Minimum OS X deployment version" FORCE)
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.13" CACHE STRING "Minimum OS X deployment version" FORCE)
### Settings needed for both "external" and internal code
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

View File

@ -82,18 +82,31 @@ LayerDialog::LayerDialog(QWidget *parent )
// The following connection is used to associate the click with the switch between raster and mesh view.
connect(ui->rasterTreeWidget, SIGNAL(itemClicked(QTreeWidgetItem * , int )) , this, SLOT(rasterItemClicked(QTreeWidgetItem * , int ) ) );
// state buttons
// state and animation buttons
isRecording = false;
viewState[0] = viewState[1] = viewState[2] = viewState[3] = "";
connect(ui->bW1, SIGNAL(clicked()), this, SLOT(clickW1()));
connect(ui->bW2, SIGNAL(clicked()), this, SLOT(clickW2()));
connect(ui->bW3, SIGNAL(clicked()), this, SLOT(clickW3()));
connect(ui->bW4, SIGNAL(clicked()), this, SLOT(clickW4()));
connect(ui->animSlower, SIGNAL(clicked()), this, SLOT(clickAnimSlower()));
connect(ui->animStepBackward, SIGNAL(clicked()), this, SLOT(clickAnimStepBackward()));
connect(ui->animPlay, SIGNAL(clicked()), this, SLOT(clickAnimPlay()));
connect(ui->animStepForward, SIGNAL(clicked()), this, SLOT(clickAnimStepForward()));
connect(ui->animFaster, SIGNAL(clicked()), this, SLOT(clickAnimFaster()));
connect(ui->bV1, SIGNAL(clicked()), this, SLOT(clickV1()));
connect(ui->bV2, SIGNAL(clicked()), this, SLOT(clickV2()));
connect(ui->bV3, SIGNAL(clicked()), this, SLOT(clickV3()));
connect(ui->bV4, SIGNAL(clicked()), this, SLOT(clickV4()));
animIndex = -1;
animMsecDelay = 500;
animTimer = new QTimer(this);
resetAnim();
connect(animTimer, SIGNAL(timeout()), this, SLOT(updateAnim()));
// Make wide enough to accommodate alternate text ("||") from clickAnimPlay()
ui->animPlay->setMinimumSize(ui->animPlay->size().width() + 6, ui->animPlay->size().height());
this->setContextMenuPolicy(Qt::CustomContextMenu);
ui->meshTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
ui->rasterTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
@ -219,6 +232,61 @@ void LayerDialog::clickW4()
mw->meshDoc()->Log.log(0, "No View to Restore");
}
void LayerDialog::clickAnimSlower()
{
if (animMsecDelay < 3000)
{
animMsecDelay = int(animMsecDelay * 1.2);
}
}
void LayerDialog::clickAnimStepBackward()
{
pauseAnim();
stepAnim(-1);
}
void LayerDialog::clickAnimPlay()
{
if (!animTimer->isActive() && startAnim())
{
ui->animPlay->setText(tr("||"));
ui->animPlay->setToolTip(tr("Pause animation"));
stepAnim(1);
animTimer->start(animMsecDelay);
}
else
{
pauseAnim();
}
}
void LayerDialog::clickAnimStepForward()
{
pauseAnim();
stepAnim(1);
}
void LayerDialog::clickAnimFaster()
{
if (animMsecDelay > 10)
{
animMsecDelay = int(animMsecDelay / 1.2f);
}
}
void LayerDialog::updateAnim()
{
if (stepAnim(1) > 1)
{
animTimer->start(animMsecDelay); // Restart in case animMsecDelay changed
}
else
{
pauseAnim();
}
}
void LayerDialog::clickV1()
{
MeshDocument *md = mw->meshDoc();
@ -406,6 +474,13 @@ void LayerDialog::meshItemClicked (QTreeWidgetItem * item , int col)
mw->GLA()->meshSetVisibility(*md->getMesh(clickedId), !md->getMesh(clickedId)->isVisible());
}
updatePerMeshItemVisibility();
// If not animating, or a mesh in the animation set was clicked, reset the animation
if (!ui->animPlay->isChecked() ||
std::find(animMeshIDs.begin(), animMeshIDs.end(), clickedId) != animMeshIDs.end())
{
resetAnim();
}
} break;
case 1 :
@ -676,6 +751,28 @@ void LayerDialog::updateTable(const MLSceneGLSharedDataContext::PerMeshRendering
}
_docitem->addChildren(itms);
// Delete any animation IDs no longer in the layer dialog
for (auto animIter = animMeshIDs.begin(); animIter != animMeshIDs.end(); )
{
bool foundInMeshList = false;
for(MeshModel& m : md->meshIterator())
{
if (m.id() == *animIter)
{
foundInMeshList = true;
break;
}
}
if (foundInMeshList)
{
++animIter;
}
else
{
animIter = animMeshIDs.erase(animIter);
}
}
updateTreeWidgetSizes(ui->meshTreeWidget);
updatePerMeshItemVisibility();
updatePerMeshItemSelectionStatus();
@ -861,6 +958,114 @@ void LayerDialog::actionActivated(MLRenderingAction* ract)
_tabw->switchTab(ract->meshId(),ract->text());
}
bool LayerDialog::startAnim()
{
if (animMeshIDs.size() > 1)
{
return true;
}
MeshDocument *md = mw->meshDoc();
bool canAnimate = md->meshNumber() > 1;
if (canAnimate)
{
int visibleCount = 0;
for(MeshModel& m : md->meshIterator())
{
if (m.isVisible())
{
++visibleCount;
}
}
// If fewer than two meshes were visible select all meshes, else select only the visible ones
animIndex = -1;
animMeshIDs.clear();
for(MeshModel& m : md->meshIterator())
{
if (m.isVisible() && animIndex < 0)
{
animIndex = animMeshIDs.size(); // Remember first visible mesh
}
if (m.isVisible() || visibleCount < 2)
{
animMeshIDs.push_back(m.id());
}
}
if (animIndex >= 0)
{
--animIndex;
}
ui->animStepBackward->setEnabled(true);
ui->animStepForward->setEnabled(true);
}
return canAnimate;
}
// Advance the animation by the specified offset (1 = forward, -1 = backward)
int LayerDialog::stepAnim(int offset)
{
bool foundVisible = false;
int animatingCount = 0;
MeshDocument *md = mw->meshDoc();
if (md->meshNumber() > 1)
{
MeshModel* lastMP = nullptr;
while (!foundVisible && animMeshIDs.size() > 1)
{
animIndex = (animMeshIDs.size() + animIndex + offset) % animMeshIDs.size();
animatingCount = 0;
for (const auto& id : animMeshIDs)
{
for(MeshModel& m : md->meshIterator())
{
if (m.id() == id)
{
bool makeVisible = m.id() == animMeshIDs[animIndex];
mw->GLA()->meshSetVisibility(m, makeVisible);
foundVisible |= makeVisible;
++animatingCount;
lastMP = &m;
}
}
}
if (!foundVisible)
{
// The mesh being animated to was deleted; remove it from the list and try again
animMeshIDs.erase(animMeshIDs.begin() + animIndex);
animIndex -= offset;
}
}
if (animMeshIDs.size() == 1 && lastMP != nullptr)
{
mw->GLA()->meshSetVisibility(*lastMP, true);
}
updatePerMeshItemVisibility();
updatePerMeshItemSelectionStatus();
mw->GLA()->update();
}
return animatingCount;
}
void LayerDialog::pauseAnim()
{
animTimer->stop();
ui->animPlay->setChecked(false);
ui->animPlay->setText(tr(">"));
ui->animPlay->setToolTip(tr("Resume animation"));
}
void LayerDialog::resetAnim()
{
pauseAnim();
animMeshIDs.clear();
ui->animStepBackward->setEnabled(false);
ui->animStepForward->setEnabled(false);
ui->animPlay->setToolTip(tr("Animate visible meshes, or all if < 2 are visible"));
}
LayerDialog::~LayerDialog()
{
delete ui;

View File

@ -30,6 +30,7 @@
#include <QTabWidget>
#include <QGroupBox>
#include <QCheckBox>
#include <QTimer>
#include <common/parameters/rich_parameter_list.h>
#include <common/ml_shared_data_context/ml_shared_data_context.h>
#include "ml_render_gui.h"
@ -140,6 +141,12 @@ public slots:
void clickW2();
void clickW3();
void clickW4();
void clickAnimSlower();
void clickAnimStepBackward();
void clickAnimPlay();
void clickAnimStepForward();
void clickAnimFaster();
void updateAnim();
void clickV1();
void clickV2();
void clickV3();
@ -177,6 +184,16 @@ private:
QString viewState[4];
QMap<int, bool> visibilityState[4];
int animIndex;
std::vector<int> animMeshIDs;
int animMsecDelay;
QTimer* animTimer;
bool startAnim();
int stepAnim(int offset);
void pauseAnim();
void resetAnim();
QTreeWidgetItem* _docitem;
int _previd;
QGroupBox* _renderingtabcontainer;

View File

@ -139,7 +139,105 @@
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<width>1</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="animSlower">
<property name="font">
<font>
<pointsize>9</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="toolTip">
<string>Decrease animation speed</string>
</property>
<property name="text">
<string>-</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="animStepBackward">
<property name="font">
<font>
<pointsize>9</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="toolTip">
<string>Animate one step backward</string>
</property>
<property name="text">
<string>-1</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="animPlay">
<property name="font">
<font>
<pointsize>9</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>&gt;</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="animStepForward">
<property name="font">
<font>
<pointsize>9</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="toolTip">
<string>Animate one step forward</string>
</property>
<property name="text">
<string>+1</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="animFaster">
<property name="font">
<font>
<pointsize>9</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="toolTip">
<string>Increase animation speed</string>
</property>
<property name="text">
<string>+</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>1</width>
<height>20</height>
</size>
</property>

View File

@ -22,17 +22,33 @@
****************************************************************************/
#include "filter_func.h"
#include <random>
#include <vcg/complex/algorithms/create/platonic.h>
#include <vcg/complex/algorithms/create/marching_cubes.h>
#include <vcg/complex/algorithms/create/mc_trivial_walker.h>
#include "muParser.h"
#include "string_conversion.h"
#include <random>
using namespace mu;
using namespace vcg;
std::random_device randomDev;
std::default_random_engine rndEngine(randomDev());
//Function to generate a random double number in [0..1) interval
double ML_Rnd() { return std::generate_canonical<double, 24>(rndEngine); }
//Function to generate a random integer number in [0..a) interval
double ML_RandInt(const double a) { return std::floor(a*ML_Rnd()); }
//Add rnd() and randint() custom functions to a mu::Parser
void setCustomFunctions(mu::Parser& p)
{
p.DefineFun("rnd", ML_Rnd);
p.DefineFun("randInt", ML_RandInt);
}
// Constructor
FilterFunctionPlugin::FilterFunctionPlugin()
{
@ -123,32 +139,47 @@ QString FilterFunctionPlugin::pythonFilterName(ActionIDType f) const
}
const QString PossibleOperators(
"<br>It's possible to use parenthesis <b>()</b>, and predefined operators:<br>"
"<br>It's possible to use any of the predefined muparser built-in "
"<a href='https://beltoforion.de/en/muparser/features.php#idDef2'>operators</a> and "
"<a href='https://beltoforion.de/en/muparser/features.php#idDef1'>functions</a>, like: "
"<b>&&</b> (logic and), <b>||</b> (logic or), <b>&lt;</b>, <b>&lt;=</b>, <b>></b>, <b>>=</b>, "
"<b>!=</b> (not equal), <b>==</b> (equal), <b>_?_:_</b> (c/c++ ternary operator)<br><br>");
"<b>!=</b> (not equal), <b>==</b> (equal), <b>_?_:_</b> (c/c++ ternary operator), and "
"<b>rnd()</b> (random value in [0..1]), and these values:" );
const QString PerVertexAttributeString(
"It's possible to use the following per-vertex variables in the expression:<br>"
"<ul><li>Per-vertex variables:<br>"
"<b>x,y,z</b> (position), <b>nx,ny,nz</b> (normal), <b>r,g,b,a</b> (color), <b>q</b> "
"(quality), <b>vi</b> (vertex index), <b>vtu,vtv,ti</b> (texture coords and texture "
"index), <b>vsel</b> (is the vertex selected? 1 yes, 0 no) "
"and all custom <i>vertex attributes</i> already defined by user."
"Point3 attribute are available as three variables with _x, _y, _z appended to the attribute name.<br>");
"index), <b>vsel</b> ( 1 if selected, 0 if not selected)."
"</li><li>Bounding Box variables:<br>"
"<b>xmin,ymin,zmin</b> (min coordinates), <b>xmax,ymax,zmax</b> (max coordinates), "
"<b>xmid,ymid,zmid</b> (midpoint coordinates), <b>xdim,ydim,zdim</b> (dimensions), "
"<b>bbdiag</b> (diagonal length)"
"</li><li>User-defined attributes:<br>"
"All user defined custom <i>vertex attributes</i> are available. "
"Point3 attribute are available as 3 variables with _x, _y, _z appended to the attribute name."
"</li></ul>");
const QString PerFaceAttributeString(
"It's possible to use the following per-face variables, or variables associated to the three "
"vertex of every face:<br>"
"<b>x0,y0,z0</b> for the first vertex position, <b>x1,y1,z1</b> for the second vertex "
"position, <b>x2,y2,z2</b> for the third vertex position, "
"<b>nx0,ny0,nz0 nx1,ny1,nz1 nx2,ny2,nz2</b> for vertex normals, <b>r0,g0,b0,a0 r1,g1,b1,a1 "
"r2,g2,b2,a2</b> for vertex colors, <b>vi0, vi1, vi2</b> for vertex indices, "
"<b>q0,q1,q2</b> for vertex quality, <b>wtu0,wtv0 wtu1,wtv1 wtu2,wtv2</b> for per-wedge "
"texture coords, <b>ti</b> for face texture index, <b>vsel0,vsel1,vsel2</b> for vertex "
"selection (1 yes, 0 no) "
"<b>fi</b> for face index, <b>fr,fg,fb,fa</b> for face color, <b>fq</b> for face quality, "
"<b>fnx,fny,fnz</b> for face normal, <b>fsel</b> face selection (1 yes, 0 no)."
"All user defined <i>face scalar attributes</i> are available."
"Point3 attribute are available as three variables with _x, _y, _z appended to the attribute name.<br><br>");
"<ul><li>Per-face variables:<br>"
"<b>fi</b> (face index), <b>fr,fg,fb,fa</b> (face color), <b>fq</b> (face quality), "
"<b>fnx,fny,fnz</b> (face normal), <b>fsel</b> ( 1 if face is selected, 0 if not selected)."
"</li><li>Per-vertex variables:<br>"
"<b>x0,y0,z0</b> (first vertex position), <b>x1,y1,z1</b> (second vertex position),"
"<b>x2,y2,z2</b> (third vertex position), "
"<b>nx0,ny0,nz0 nx1,ny1,nz1 nx2,ny2,nz2</b> (vertex normals), <b>r0,g0,b0,a0 r1,g1,b1,a1 "
"r2,g2,b2,a2</b> (vertex colors), <b>vi0, vi1, vi2</b> (vertex indices), "
"<b>q0,q1,q2</b> (vertex quality), <b>wtu0,wtv0 wtu1,wtv1 wtu2,wtv2</b> (per-wedge texture coords), "
"<b>ti</b> (face texture index), <b>vsel0,vsel1,vsel2</b> (1 if vertex is selected, 0 if not)."
"</li><li>Bounding Box variables:<br>"
"<b>xmin,ymin,zmin</b> (min coordinates), <b>xmax,ymax,zmax</b> (max coordinates), "
"<b>xmid,ymid,zmid</b> (midpoint coordinates), <b>xdim,ydim,zdim</b> (dimensions), "
"<b>bbdiag</b> (diagonal length)."
"</li><li>User-defined attributes:<br>"
"All user defined custom <i>face scalar attributes</i> are available. "
"Point3 attribute are available as 3 variables with _x, _y, _z appended to the attribute name."
"</li></ul>");
// long string describing each filtering action
QString FilterFunctionPlugin::filterInfo(ActionIDType filterId) const
@ -694,6 +725,24 @@ std::map<std::string, QVariant> FilterFunctionPlugin::applyFilter(
md.addNewMesh("", this->filterName(ID(filter)));
MeshModel& m = *(md.mm());
Q_UNUSED(cb);
//Set values to parser variables related to BBox
const auto &bbox = m.cm.bbox;
xmin = bbox.min.X();
ymin = bbox.min.Y();
zmin = bbox.min.Z();
xmax = bbox.max.X();
ymax = bbox.max.Y();
zmax = bbox.max.Z();
xdim = bbox.DimX();
ydim = bbox.DimY();
zdim = bbox.DimZ();
bbdiag = bbox.Diag();
auto bbCenter = bbox.Center();
xmid = bbCenter.X();
ymid = bbCenter.Y();
zmid = bbCenter.Z();
switch (ID(filter)) {
case FF_VERT_SELECTION: {
std::string expr = par.getString("condSelect").toStdString();
@ -701,7 +750,9 @@ std::map<std::string, QVariant> FilterFunctionPlugin::applyFilter(
// muparser initialization and explicitly define parser variables
Parser p;
setPerVertexVariables(p, m.cm);
setCustomFunctions(p);
// set expression inserted by user as string (required by muparser)
p.SetExpr(wexpr);
@ -747,7 +798,8 @@ std::map<std::string, QVariant> FilterFunctionPlugin::applyFilter(
// muparser initialization and explicitly define parser variables
Parser p;
setPerFaceVariables(p, m.cm);
setCustomFunctions(p);
// set expression inserted by user as string (required by muparser)
p.SetExpr(conversion::fromStringToWString(select.toStdString()));
@ -815,12 +867,16 @@ std::map<std::string, QVariant> FilterFunctionPlugin::applyFilter(
// muparser initialization and explicitly define parser variables
// function for x,y and z must use different parser and variables
Parser p1, p2, p3, p4;
setPerVertexVariables(p1, m.cm);
setPerVertexVariables(p2, m.cm);
setPerVertexVariables(p3, m.cm);
setPerVertexVariables(p4, m.cm);
setCustomFunctions(p1);
setCustomFunctions(p2);
setCustomFunctions(p3);
setCustomFunctions(p4);
p1.SetExpr(conversion::fromStringToWString(func_x));
p2.SetExpr(conversion::fromStringToWString(func_y));
p3.SetExpr(conversion::fromStringToWString(func_z));
@ -916,6 +972,9 @@ std::map<std::string, QVariant> FilterFunctionPlugin::applyFilter(
Parser p;
setPerVertexVariables(p, m.cm);
//Add rnd() and randInt() internal functions
setCustomFunctions(p);
// set expression to calc with parser
p.SetExpr(conversion::fromStringToWString(func_q));
@ -975,6 +1034,8 @@ std::map<std::string, QVariant> FilterFunctionPlugin::applyFilter(
Parser pu, pv;
setPerVertexVariables(pu, m.cm);
setPerVertexVariables(pv, m.cm);
setCustomFunctions(pu);
setCustomFunctions(pv);
// set expression to calc with parser
#ifdef _UNICODE
@ -1033,6 +1094,12 @@ std::map<std::string, QVariant> FilterFunctionPlugin::applyFilter(
setPerFaceVariables(pv1, m.cm);
setPerFaceVariables(pu2, m.cm);
setPerFaceVariables(pv2, m.cm);
setCustomFunctions(pu0);
setCustomFunctions(pv0);
setCustomFunctions(pu1);
setCustomFunctions(pv1);
setCustomFunctions(pu2);
setCustomFunctions(pv2);
// set expression to calc with parser
pu0.SetExpr(conversion::fromStringToWString(func_u0));
@ -1082,6 +1149,10 @@ std::map<std::string, QVariant> FilterFunctionPlugin::applyFilter(
setPerFaceVariables(p_nx, m.cm);
setPerFaceVariables(p_ny, m.cm);
setPerFaceVariables(p_nz, m.cm);
setCustomFunctions(p_nx);
setCustomFunctions(p_ny);
setCustomFunctions(p_nz);
p_nx.SetExpr(conversion::fromStringToWString(func_nx));
p_ny.SetExpr(conversion::fromStringToWString(func_ny));
p_nz.SetExpr(conversion::fromStringToWString(func_nz));
@ -1154,6 +1225,10 @@ std::map<std::string, QVariant> FilterFunctionPlugin::applyFilter(
setPerFaceVariables(p2, m.cm);
setPerFaceVariables(p3, m.cm);
setPerFaceVariables(p4, m.cm);
setCustomFunctions(p1);
setCustomFunctions(p2);
setCustomFunctions(p3);
setCustomFunctions(p4);
p1.SetExpr(conversion::fromStringToWString(func_r));
p2.SetExpr(conversion::fromStringToWString(func_g));
@ -1227,6 +1302,7 @@ std::map<std::string, QVariant> FilterFunctionPlugin::applyFilter(
// muparser initialization and define custom variables
Parser pf;
setPerFaceVariables(pf, m.cm);
setCustomFunctions(pf);
// set expression to calc with parser
pf.SetExpr(conversion::fromStringToWString(func_q));
@ -1286,6 +1362,7 @@ std::map<std::string, QVariant> FilterFunctionPlugin::applyFilter(
Parser p;
setPerVertexVariables(p, m.cm);
setCustomFunctions(p);
p.SetExpr(conversion::fromStringToWString(expr));
@ -1338,6 +1415,7 @@ std::map<std::string, QVariant> FilterFunctionPlugin::applyFilter(
h = tri::Allocator<CMeshO>::AddPerFaceAttribute<Scalarm>(m.cm, name);
Parser p;
setPerFaceVariables(p, m.cm);
setCustomFunctions(p);
p.SetExpr(conversion::fromStringToWString(expr));
time_t start = clock();
@ -1384,6 +1462,10 @@ std::map<std::string, QVariant> FilterFunctionPlugin::applyFilter(
setPerVertexVariables(p_x, m.cm);
setPerVertexVariables(p_y, m.cm);
setPerVertexVariables(p_z, m.cm);
setCustomFunctions(p_x);
setCustomFunctions(p_y);
setCustomFunctions(p_z);
p_x.SetExpr(conversion::fromStringToWString(x_expr));
p_y.SetExpr(conversion::fromStringToWString(y_expr));
p_z.SetExpr(conversion::fromStringToWString(z_expr));
@ -1443,6 +1525,9 @@ std::map<std::string, QVariant> FilterFunctionPlugin::applyFilter(
setPerFaceVariables(p_x, m.cm);
setPerFaceVariables(p_y, m.cm);
setPerFaceVariables(p_z, m.cm);
setCustomFunctions(p_x);
setCustomFunctions(p_y);
setCustomFunctions(p_z);
p_x.SetExpr(conversion::fromStringToWString(x_expr));
p_y.SetExpr(conversion::fromStringToWString(y_expr));
p_z.SetExpr(conversion::fromStringToWString(z_expr));
@ -1524,6 +1609,8 @@ std::map<std::string, QVariant> FilterFunctionPlugin::applyFilter(
Parser p;
double x, y, z;
setCustomFunctions(p);
p.DefineVar(conversion::fromStringToWString("x"), &x);
p.DefineVar(conversion::fromStringToWString("y"), &y);
p.DefineVar(conversion::fromStringToWString("z"), &z);
@ -1760,6 +1847,15 @@ void FilterFunctionPlugin::setAttributes(CMeshO::FaceIterator& fi, CMeshO& m)
}
// Generate a random double in [0.0, 1.0] interval
double FilterFunctionPlugin::random()
{
std::random_device rd; // Seed for the random number engine
std::mt19937 gen(rd()); // Mersenne Twister engine
std::uniform_real_distribution<double> dis(0.0, 1.0);
return dis(gen); // Generate a random double in [0.0, 1.0]
}
// Function explicitly define parser variables to perform per-vertex filter action
// x, y, z for vertex coord, nx, ny, nz for normal coord, r, g ,b for color
// and q for quality
@ -1782,6 +1878,24 @@ void FilterFunctionPlugin::setPerVertexVariables(Parser& p, CMeshO& m)
p.DefineVar(conversion::fromStringToWString("ti"), &ti);
p.DefineVar(conversion::fromStringToWString("vsel"), &vsel);
//Add tokens related to mesh bounding box
p.DefineVar(conversion::fromStringToWString("xmin"), &xmin);
p.DefineVar(conversion::fromStringToWString("ymin"), &ymin);
p.DefineVar(conversion::fromStringToWString("zmin"), &zmin);
p.DefineVar(conversion::fromStringToWString("xmax"), &xmax);
p.DefineVar(conversion::fromStringToWString("ymax"), &ymax);
p.DefineVar(conversion::fromStringToWString("zmax"), &zmax);
p.DefineVar(conversion::fromStringToWString("bbdiag"), &bbdiag);
p.DefineVar(conversion::fromStringToWString("xdim"), &xdim);
p.DefineVar(conversion::fromStringToWString("ydim"), &ydim);
p.DefineVar(conversion::fromStringToWString("zdim"), &zdim);
p.DefineVar(conversion::fromStringToWString("xmid"), &xmid);
p.DefineVar(conversion::fromStringToWString("ymid"), &ymid);
p.DefineVar(conversion::fromStringToWString("zmid"), &zmid);
//Add function rnd()
p.DefineFun("rnd", random);
// define var for user-defined attributes (if any exists)
// if vector is empty, code won't be executed
v_handlers.clear();
@ -1910,6 +2024,24 @@ void FilterFunctionPlugin::setPerFaceVariables(Parser& p, CMeshO& m)
p.DefineVar(conversion::fromStringToWString("vsel2"), &vsel2);
p.DefineVar(conversion::fromStringToWString("fsel"), &fsel);
//Add tokens related to mesh bounding box
p.DefineVar(conversion::fromStringToWString("xmin"), &xmin);
p.DefineVar(conversion::fromStringToWString("ymin"), &ymin);
p.DefineVar(conversion::fromStringToWString("zmin"), &zmin);
p.DefineVar(conversion::fromStringToWString("xmax"), &xmax);
p.DefineVar(conversion::fromStringToWString("ymax"), &ymax);
p.DefineVar(conversion::fromStringToWString("zmax"), &zmax);
p.DefineVar(conversion::fromStringToWString("bbdiag"), &bbdiag);
p.DefineVar(conversion::fromStringToWString("xdim"), &xdim);
p.DefineVar(conversion::fromStringToWString("ydim"), &ydim);
p.DefineVar(conversion::fromStringToWString("zdim"), &zdim);
p.DefineVar(conversion::fromStringToWString("xmid"), &xmid);
p.DefineVar(conversion::fromStringToWString("ymid"), &ymid);
p.DefineVar(conversion::fromStringToWString("zmid"), &zmid);
//Add function rnd()
p.DefineFun("rnd", random);
// define var for user-defined attributes (if any exists)
// if vector is empty, code won't be executed
f_handlers.clear();

View File

@ -44,6 +44,10 @@ protected:
vsel0, vsel1, vsel2;
double fr, fg, fb, fa, fnx, fny, fnz, fq, fsel;
double v, f, v0i, v1i, v2i, ti;
//Bounding Box of the mesh
double xmin, ymin, zmin, xmax, ymax, zmax, xdim, ydim, zdim, bbdiag, xmid, ymid, zmid;
std::vector<std::string> v_attrNames; // names of the <float> per vertex attributes
std::vector<double> v_attrValue; // values of the <Scalarm> per vertex attributes
std::vector<std::string> v3_attrNames; // names of the <Point3f> per vertex attributes There are
@ -62,6 +66,9 @@ protected:
QString errorMsg;
// Generate a random double in [0.0, 1.0] interval
static double random();
public:
enum {
FF_VERT_SELECTION,

View File

@ -44,7 +44,8 @@ FilterGeodesic::FilterGeodesic()
typeList = {
FP_QUALITY_BORDER_GEODESIC,
FP_QUALITY_POINT_GEODESIC,
FP_QUALITY_SELECTED_GEODESIC
FP_QUALITY_SELECTED_GEODESIC,
FP_QUALITY_SELECTED_GEODESIC_HEAT
};
for(ActionIDType tt : types())
@ -67,6 +68,8 @@ QString FilterGeodesic::filterName(ActionIDType filter) const
return QString("Colorize by geodesic distance from a given point");
case FP_QUALITY_SELECTED_GEODESIC:
return QString("Colorize by geodesic distance from the selected points");
case FP_QUALITY_SELECTED_GEODESIC_HEAT:
return QString("Colorize by approximated geodesic distance from the selected points");
default: assert(0); return QString();
}
}
@ -79,6 +82,8 @@ QString FilterGeodesic::pythonFilterName(ActionIDType f) const
return QString("compute_scalar_by_geodesic_distance_from_given_point_per_vertex");
case FP_QUALITY_SELECTED_GEODESIC:
return QString("compute_scalar_by_geodesic_distance_from_selection_per_vertex");
case FP_QUALITY_SELECTED_GEODESIC_HEAT:
return QString("compute_scalar_by_heat_geodesic_distance_from_selection_per_vertex");
default: assert(0); return QString();
}
}
@ -87,9 +92,10 @@ QString FilterGeodesic::filterInfo(ActionIDType filterId) const
{
switch(filterId)
{
case FP_QUALITY_BORDER_GEODESIC : return tr("Store in the quality field the geodesic distance from borders and color the mesh accordingly.");
case FP_QUALITY_POINT_GEODESIC : return tr("Store in the quality field the geodesic distance from a given point on the mesh surface and color the mesh accordingly.");
case FP_QUALITY_SELECTED_GEODESIC : return tr("Store in the quality field the geodesic distance from the selected points on the mesh surface and color the mesh accordingly.");
case FP_QUALITY_BORDER_GEODESIC : return tr("Store in the quality field the geodesic distance from borders and color the mesh accordingly.");
case FP_QUALITY_POINT_GEODESIC : return tr("Store in the quality field the geodesic distance from a given point on the mesh surface and color the mesh accordingly.");
case FP_QUALITY_SELECTED_GEODESIC : return tr("Store in the quality field the geodesic distance from the selected points on the mesh surface and color the mesh accordingly.");
case FP_QUALITY_SELECTED_GEODESIC_HEAT : return tr("Store in the quality field the approximated geodesic distance, computed via heat method (Crane et al.), from the selected points on the mesh surface and color the mesh accordingly. As this implementation does not use intrinsic triangulation it is very sensitive to trinagulation. First run takes longer as factorization has to be build. ");
default : assert(0);
}
return QString("error!");
@ -99,9 +105,10 @@ FilterGeodesic::FilterClass FilterGeodesic::getClass(const QAction *a) const
{
switch(ID(a))
{
case FP_QUALITY_BORDER_GEODESIC :
case FP_QUALITY_SELECTED_GEODESIC :
case FP_QUALITY_POINT_GEODESIC : return FilterGeodesic::FilterClass(FilterPlugin::VertexColoring + FilterPlugin::Quality);
case FP_QUALITY_BORDER_GEODESIC :
case FP_QUALITY_SELECTED_GEODESIC :
case FP_QUALITY_POINT_GEODESIC :
case FP_QUALITY_SELECTED_GEODESIC_HEAT : return FilterGeodesic::FilterClass(FilterPlugin::VertexColoring + FilterPlugin::Quality);
default : assert(0);
}
return FilterPlugin::Generic;
@ -111,15 +118,16 @@ int FilterGeodesic::getRequirements(const QAction *action)
{
switch(ID(action))
{
case FP_QUALITY_BORDER_GEODESIC :
case FP_QUALITY_SELECTED_GEODESIC:
case FP_QUALITY_POINT_GEODESIC : return MeshModel::MM_VERTFACETOPO;
case FP_QUALITY_BORDER_GEODESIC :
case FP_QUALITY_SELECTED_GEODESIC :
case FP_QUALITY_POINT_GEODESIC : return MeshModel::MM_VERTFACETOPO;
case FP_QUALITY_SELECTED_GEODESIC_HEAT : return MeshModel::MM_VERTFACETOPO + MeshModel::MM_FACEFACETOPO;
default: assert(0);
}
return 0;
}
std::map<std::string, QVariant> FilterGeodesic::applyFilter(const QAction *filter, const RichParameterList & par, MeshDocument &md, unsigned int& /*postConditionMask*/, vcg::CallBackPos * /*cb*/)
std::map<std::string, QVariant> FilterGeodesic::applyFilter(const QAction *filter, const RichParameterList & par, MeshDocument &md, unsigned int& /*postConditionMask*/, vcg::CallBackPos *cb)
{
MeshModel &m=*(md.mm());
CMeshO::VertexIterator vi;
@ -236,7 +244,60 @@ std::map<std::string, QVariant> FilterGeodesic::applyFilter(const QAction *filte
else
log("Warning: no vertices are selected! aborting geodesic computation.");
}
break;
break;
case FP_QUALITY_SELECTED_GEODESIC_HEAT:
{
m.updateDataMask(MeshModel::MM_FACEFACETOPO);
m.updateDataMask(MeshModel::MM_VERTFACETOPO);
m.updateDataMask(MeshModel::MM_FACEQUALITY);
m.updateDataMask(MeshModel::MM_FACENORMAL);
m.updateDataMask(MeshModel::MM_VERTQUALITY);
m.updateDataMask(MeshModel::MM_VERTCOLOR);
std::vector<CMeshO::VertexPointer> seedVec;
ForEachVertex(m.cm, [&seedVec] (CMeshO::VertexType & v) {
if (v.IsS()) seedVec.push_back(&v);
});
float param_m = par.getFloat("m");
if (seedVec.size() > 0){
// cache factorizations to reduce runtime on successive computations
std::pair<float, tri::GeodesicHeat<CMeshO>::GeodesicHeatCache> cache;
if (!vcg::tri::HasPerMeshAttribute(m.cm, "GeodesicHeatCache")){
cb(20, "Building Cache: Computing Factorizations...");
cache = std::make_pair(param_m, tri::GeodesicHeat<CMeshO>::BuildCache(m.cm, param_m));
// save cache for next compute
auto GeodesicHeatCacheHandle = tri::Allocator<CMeshO>::GetPerMeshAttribute<std::pair<float, tri::GeodesicHeat<CMeshO>::GeodesicHeatCache>>(m.cm, std::string("GeodesicHeatCache"));
GeodesicHeatCacheHandle() = cache;
}
else {
cb(10, "Recovering Cache...");
// recover cache
auto GeodesicHeatCacheHandle = vcg::tri::Allocator<CMeshO>::GetPerMeshAttribute<std::pair<float, tri::GeodesicHeat<CMeshO>::GeodesicHeatCache>>(m.cm, std::string("GeodesicHeatCache"));
// if m has changed rebuild everything
if (std::get<0>(GeodesicHeatCacheHandle()) != param_m){
cb(20, "Parameter Changed: Rebuilding Factorizations...");
GeodesicHeatCacheHandle() = std::make_pair(param_m, tri::GeodesicHeat<CMeshO>::BuildCache(m.cm, param_m));
}
cache = GeodesicHeatCacheHandle();
}
cb(80, "Computing Geodesic Distance...");
if (tri::GeodesicHeat<CMeshO>::ComputeFromCache(m.cm, seedVec, std::get<1>(cache))){
tri::UpdateColor<CMeshO>::PerVertexQualityRamp(m.cm);
}
else{
log("Warning: heat method has failed. The mesh is most likely badly conditioned (e.g. angles ~ 0deg) or has disconnected components");
// delete cache as its most likely useless after failure
auto GeodesicHeatCacheHandle = vcg::tri::Allocator<CMeshO>::GetPerMeshAttribute<std::pair<float, tri::GeodesicHeat<CMeshO>::GeodesicHeatCache>>(m.cm, std::string("GeodesicHeatCache"));
tri::Allocator<CMeshO>::DeletePerMeshAttribute<std::pair<float, tri::GeodesicHeat<CMeshO>::GeodesicHeatCache>>(m.cm, GeodesicHeatCacheHandle);
}
}
else
log("Warning: no vertices are selected! aborting geodesic computation.");
}
break;
default:
wrongActionCalled(filter);
break;
@ -255,7 +316,10 @@ RichParameterList FilterGeodesic::initParameterList(const QAction *action, const
break;
case FP_QUALITY_SELECTED_GEODESIC :
parlst.addParam(RichPercentage("maxDistance",m.cm.bbox.Diag(),0,m.cm.bbox.Diag()*2,"Max Distance","If not zero it indicates a cut off value to be used during geodesic distance computation."));
break;
break;
case FP_QUALITY_SELECTED_GEODESIC_HEAT :
parlst.addParam(RichFloat("m", 1.0, tr("Euler Step"), tr("Multiplier used in backward Euler timestep. Changing this value will reset the cache.")));
break;
default: break; // do not add any parameter for the other filters
}
return parlst;
@ -265,10 +329,11 @@ int FilterGeodesic::postCondition(const QAction * filter) const
{
switch (ID(filter))
{
case FP_QUALITY_BORDER_GEODESIC :
case FP_QUALITY_SELECTED_GEODESIC :
case FP_QUALITY_POINT_GEODESIC : return MeshModel::MM_VERTCOLOR + MeshModel::MM_VERTQUALITY;
default : return MeshModel::MM_ALL;
case FP_QUALITY_BORDER_GEODESIC :
case FP_QUALITY_SELECTED_GEODESIC :
case FP_QUALITY_POINT_GEODESIC : return MeshModel::MM_VERTCOLOR + MeshModel::MM_VERTQUALITY;
case FP_QUALITY_SELECTED_GEODESIC_HEAT : return MeshModel::MM_VERTCOLOR + MeshModel::MM_VERTQUALITY + MeshModel::MM_FACEQUALITY;
default : return MeshModel::MM_ALL;
}
}
MESHLAB_PLUGIN_NAME_EXPORTER(FilterGeodesic)

View File

@ -26,6 +26,7 @@
#include <QObject>
#include <common/plugins/interfaces/filter_plugin.h>
#include <vcg/complex/algorithms/geodesic.h>
#include <vcg/complex/algorithms/geodesic_heat.h>
class FilterGeodesic : public QObject, public FilterPlugin
@ -42,7 +43,8 @@ class FilterGeodesic : public QObject, public FilterPlugin
enum {
FP_QUALITY_BORDER_GEODESIC,
FP_QUALITY_POINT_GEODESIC,
FP_QUALITY_SELECTED_GEODESIC
FP_QUALITY_SELECTED_GEODESIC,
FP_QUALITY_SELECTED_GEODESIC_HEAT
} ;

View File

@ -26,6 +26,7 @@
#include <vcg/complex/algorithms/smooth.h>
#include <vcg/complex/algorithms/create/plymc/plymc.h>
#include <vcg/complex/algorithms/create/plymc/simplemeshprovider.h>
#include <QTemporaryDir>
#include <QTemporaryFile>
using namespace vcg;
@ -142,13 +143,21 @@ std::map<std::string, QVariant> PlyMCPlugin::applyFilter(
case FP_PLYMC:
{
srand(time(NULL));
//check if folder is writable
QTemporaryFile file("./_tmp_XXXXXX.tmp");
if (!file.open())
{
log("ERROR - current folder is not writable. VCG Merging needs to save intermediate files in the current working folder. Project and meshes must be in a write-enabled folder. Please save your data in a suitable folder before applying.");
throw MLException("current folder is not writable.<br> VCG Merging needs to save intermediate files in the current working folder.<br> Project and meshes must be in a write-enabled folder.<br> Please save your data in a suitable folder before applying.");
QDir currDir = QDir::current();
//Using tmp dir
QTemporaryDir tmpdir;
QTemporaryFile file(tmpdir.path());
if (!file.open()) {
log("ERROR - tmp folder is not writable. VCG Merging needs to save intermediate files "
"in the tmp folder.");
throw MLException(
"tmp folder is not writable.<br> VCG Merging needs to save intermediate files in "
"the tmp folder.");
}
else {
QDir::setCurrent(tmpdir.path());
}
tri::PlyMC<SMesh,SimpleMeshProvider<SMesh> > pmc;
@ -170,10 +179,8 @@ std::map<std::string, QVariant> PlyMCPlugin::applyFilter(
p.FullyPreprocessedFlag=true;
p.MergeColor=p.VertSplatFlag=par.getBool("mergeColor");
p.SimplificationFlag = par.getBool("simplification");
for(MeshModel& mm: md.meshIterator())
{
if(mm.isVisible())
{
for(MeshModel& mm: md.meshIterator()) {
if(mm.isVisible()) {
SMesh sm;
mm.updateDataMask(MeshModel::MM_FACEQUALITY);
tri::Append<SMesh,CMeshO>::Mesh(sm, mm.cm/*,false,p.VertSplatFlag*/); // note the last parameter of the append to prevent removal of unreferenced vertices...
@ -189,8 +196,7 @@ std::map<std::string, QVariant> PlyMCPlugin::applyFilter(
QString mshTmpPath=QString("__TMP")+QString(mm.shortName())+QString(".vmi");
qDebug("Saving tmp file %s",qUtf8Printable(mshTmpPath));
int retVal = tri::io::ExporterVMI<SMesh>::Save(sm,qUtf8Printable(mshTmpPath) );
if(retVal!=0)
{
if(retVal!=0) {
qDebug("Failed to write vmi temp file %s",qUtf8Printable(mshTmpPath));
log("ERROR - Failed to write vmi temp file %s", qUtf8Printable(mshTmpPath));
@ -201,14 +207,12 @@ std::map<std::string, QVariant> PlyMCPlugin::applyFilter(
}
}
if(pmc.Process(cb)==false)
{
if(pmc.Process(cb)==false) {
throw MLException(pmc.errorMessage.c_str());
}
if(par.getBool("openResult"))
{
if(par.getBool("openResult")) {
for(size_t i=0;i<p.OutNameVec.size();++i)
{std::string name;
if(!p.SimplificationFlag) name = p.OutNameVec[i].c_str();
@ -225,6 +229,8 @@ std::map<std::string, QVariant> PlyMCPlugin::applyFilter(
for(int i=0;i<pmc.MP.size();++i)
QFile::remove(pmc.MP.MeshName(i).c_str());
QDir::setCurrent(currDir.path());
} break;
case FP_MC_SIMPLIFY:
{

View File

@ -296,19 +296,19 @@ void U3DIOPlugin::saveLatex(const QString& file,const vcg::tri::io::u3dparameter
std::string u3d_final =
vcg::tri::io::QtUtilityFunctions::fileNameFromTrimmedPath(file_trim).toStdString();
latex.write(0,"\\documentclass[a4paper]{article}");
latex.write(0,"\\usepackage[3D]{movie15}");
latex.write(0,"\\usepackage[3Dmenu]{media9}");
latex.write(0,"\\usepackage{hyperref}");
latex.write(0,"\\usepackage[UKenglish]{babel}");
latex.write(0,"\\begin{document}");
latex.write(0,"\\includemovie[");
latex.write(1,"poster,");
latex.write(1,"toolbar, %same as `controls\'");
latex.write(0,"\\includemedia[");
latex.write(1,"width=\\linewidth,height=\\linewidth,");
latex.write(1,"3Dmenu,'");
QString u3d_text = QString::fromStdString(u3d_final);
substituteChar(u3d_text,QChar('_'),QString(""));
latex.write(1,"label=" + u3d_text.toStdString() + ",");
latex.write(1,"text=(" + u3d_text.toStdString() + "),");
latex.write(1,"activate=pageopen,");
std::string cam_string;
typename vcg::tri::io::u3dparametersclasses::Movie15Parameters<CMeshO>::CameraParameters* cam = mov_par._campar;
if (cam != NULL) {
@ -319,8 +319,8 @@ void U3DIOPlugin::saveLatex(const QString& file,const vcg::tri::io::u3dparameter
", 3Dcoo=" + TextUtility::nmbToStr(-cam->_obj_pos.X()) + " " + TextUtility::nmbToStr(cam->_obj_pos.Z()) + " " + TextUtility::nmbToStr(cam->_obj_pos.Y()) + ",";
latex.write(1,cam_string);
}
latex.write(1,"3Dlights=CAD,");
latex.write(0,"]{\\linewidth}{\\linewidth}{" + u3d_final + "}");
latex.write(1,"3Dlights=CAD");
latex.write(0,"]{}{" + u3d_final + "}");
latex.write(0,"\\end{document}");
}

@ -1 +1 @@
Subproject commit d3822ec0cd1161de2223ddc4f126c413d398dad1
Subproject commit 97adf94662ed4e54752c456d6ebfa97d7bf92ebd