Skip to content

Commit

Permalink
Merge branch 'main' into issue-152-2
Browse files Browse the repository at this point in the history
  • Loading branch information
CharlesPignerol authored Dec 10, 2024
2 parents a3277de + 249dc7a commit fe12849
Show file tree
Hide file tree
Showing 19 changed files with 159 additions and 236 deletions.
5 changes: 5 additions & 0 deletions Docs/pages/preferences.rst
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,11 @@ Section **panels** : ressources des panneaux de l’IHM
- **commandNotificationDelay** : Durée d'exécution de commande en
secondes à partir de laquelle une notification système est
envoyée.

- **commandNotificationDuration** : Durée d'affichage en
millisecondes des notifications système (0 pour désactiver leur
affichage). Repose sur l'application notify-send.


- Section **selection** :

Expand Down
4 changes: 2 additions & 2 deletions cmake/version.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#

set (MAGIX3D_MAJOR_VERSION "2")
set (MAGIX3D_MINOR_VERSION "3")
set (MAGIX3D_RELEASE_VERSION "5")
set (MAGIX3D_MINOR_VERSION "4")
set (MAGIX3D_RELEASE_VERSION "0")
set (MAGIX3D_VERSION ${MAGIX3D_MAJOR_VERSION}.${MAGIX3D_MINOR_VERSION}.${MAGIX3D_RELEASE_VERSION})

51 changes: 15 additions & 36 deletions src/Core/Geom/OCCGeomRepresentation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1782,6 +1782,7 @@ void OCCGeomRepresentation::project(const Utils::Math::Point& P1, Utils::Math::P
/*----------------------------------------------------------------------------*/
void OCCGeomRepresentation::projectPointOn( Utils::Math::Point& P)
{

if(!m_shape.IsNull() && m_shape.ShapeType()==TopAbs_VERTEX)
{
gp_Pnt pnt = BRep_Tool::Pnt(TopoDS::Vertex(m_shape));
Expand All @@ -1790,42 +1791,20 @@ void OCCGeomRepresentation::projectPointOn( Utils::Math::Point& P)
else
{
gp_Pnt pnt(P.getX(),P.getY(),P.getZ());

// issue#86 : dans le cas des surfaces, si la surface est toute petite,
// il faut projeter avec GeomAPI_ProjectPointOnSurf au lieu de
// BRepExtrema_DistShapeShape pour éviter les imprécisions numériques.
bool is_done = false;
if (m_shape.ShapeType()==TopAbs_FACE && computeSurfaceArea()<getPrecision()) {
// Initialisation du projecteur
TopoDS_Face face = TopoDS::Face(m_shape);
Handle(Geom_Surface) surface = BRep_Tool::Surface(face);
GeomAPI_ProjectPointOnSurf projector;
projector.Init(pnt, surface);

// Si la projection est réussie
if (projector.NbPoints() > 0) {
gp_Pnt pnt2 = projector.NearestPoint(); // Point projeté le plus proche
P.setXYZ(pnt2.X(), pnt2.Y(), pnt2.Z());
is_done = true;
}
}

if (!is_done) {
TopoDS_Vertex V = BRepBuilderAPI_MakeVertex(pnt);
BRepExtrema_DistShapeShape extrema(V, m_shape);
bool isDone = extrema.IsDone();
if(!isDone) {
isDone = extrema.Perform();
}

if(!isDone){
std::cerr<<"OCCGeomRepresentation::projectPointOn("<<P<<")\n";
throw TkUtil::Exception("Echec d'une projection d'un point sur une courbe ou surface!!");

}
gp_Pnt pnt2 = extrema.PointOnShape2(1);
P.setXYZ(pnt2.X(), pnt2.Y(), pnt2.Z());
}
TopoDS_Vertex V = BRepBuilderAPI_MakeVertex(pnt);
BRepExtrema_DistShapeShape extrema(V, m_shape);
bool isDone = extrema.IsDone();
if(!isDone) {
isDone = extrema.Perform();
}

if(!isDone){
std::cerr<<"OCCGeomRepresentation::projectPointOn("<<P<<")\n";
throw TkUtil::Exception("Echec d'une projection d'un point sur une courbe ou surface!!");

}
gp_Pnt pnt2 = extrema.PointOnShape2(1);
P.setXYZ(pnt2.X(), pnt2.Y(), pnt2.Z());
// std::cout<<"OCCGeomRepresentation::projectPointOn("<<pnt.X()<<", "<<pnt.Y()<<", "<<pnt.Z()
// <<") => "<<pnt2.X()<<", "<<pnt2.Y()<<", "<<pnt2.Z()<<" distance : "<<pnt.Distance(pnt2)<<std::endl;
}
Expand Down
2 changes: 2 additions & 0 deletions src/Core/Internal/Resources.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ _autoUpdateUsesSelection ("autoUpdateUsesSelection", true, UTF8String ("Les pann
_showDialogOnCommandError ("showDialogOnCommandError", true, UTF8String ("Faut-il afficher une boite de dialogue d'erreur lorsqu'une commande échoue ? Oui si true, non si false.", Charset::UTF_8)),
_showAmodalDialogOnCommandError ("showAmodalDialogOnCommandError", false, UTF8String ("Faut-il afficher une boite de dialogue d'erreur non modale lorsqu'une commande échoue ? Non si true (risque de désorganiser le bureau courant), oui si false.", Charset::UTF_8)),
_commandNotificationDelay ("commandNotificationDelay", 30, UTF8String ("Durée d'exécution de commande en secondes à partir de laquelle une notification système est envoyée.", Charset::UTF_8)),
_commandNotificationDuration ("commandNotificationDuration", 30000, UTF8String ("Durée d'affichage des notifications système (en millisecondes) ou 0 pour les désactiver.", Charset::UTF_8)),
_maxIndividualProperties ("maxIndividualProperties", 50, UTF8String ("Nombre maximum d'entités sélectionnées dont on détaille les propriétés individuelles.", Charset::UTF_8)),
_maxCommonProperties ("maxCommonProperties", 50, UTF8String ("Nombre maximum d'entités sélectionnées dont on détaille les propriétés communes.", Charset::UTF_8)),
_logInformations ("informations", true),
Expand Down Expand Up @@ -161,6 +162,7 @@ _autoUpdateUsesSelection ("autoUpdateUsesSelection", "true", "Les panneaux d'op
_showDialogOnCommandError ("showDialogOnCommandError", "true", "Faut-il afficher une boite de dialogue d'erreur lorsqu'une commande échoue ? Oui si true, non si false."),
_showAmodalDialogOnCommandError ("showAmodalDialogOnCommandError", false, "Faut-il afficher une boite de dialogue d'erreur non modale lorsqu'une commande échoue ? Oui si true (risque de désorganiser le bureau courant), non si false."),
_commandNotificationDelay ("commandNotificationDelay", 20, "Durée d'exécution de commande en secondes à partir de laquelle une notification système est envoyée."),
_commandNotificationDuration ("commandNotificationDuration", 30000, UTF8String ("Durée d'affichage des notifications système (en millisecondes) ou 0 pour les désactiver.", Charset::UTF_8)),
_maxIndividualProperties ("maxIndividualProperties", 50, "Nombre maximum d'entités sélectionnées dont on détaille les propriétés individuelles."),
_maxCommonProperties ("maxCommonProperties", 50, "Nombre maximum d'entités sélectionnées dont on détaille les propriétés communes."),
_logInformations ("informations", true),
Expand Down
18 changes: 17 additions & 1 deletion src/Core/Mesh/CommandNewBlocksMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,23 @@ internalExecute()
TkUtil::Timer timer(false);
#endif


// delete the premesh of the edges to accommodate for possible smooth/pert modifications
// applied to adjacent surfaces
{
std::set<Topo::CoEdge *> set_coedges;
for (auto b: m_blocks) {
std::vector<Topo::CoEdge *> coedges;
b->getCoEdges(coedges);

for (auto ce: coedges) {
set_coedges.insert(ce);
}
}
for (auto ce: set_coedges) {
ce->clearPoints();
ce->getMeshingData()->setPreMeshed(false);
}
}

// maille et modifie le maillage pour les modifications 2D, s'il y en a
// cette étape est à effectuer avant le maillage de toutes les arêtes car le lissage
Expand Down
18 changes: 18 additions & 0 deletions src/Core/Mesh/CommandNewFacesMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,24 @@ internalExecute()
iter != m_faces.end(); ++iter)
(*iter)->check();

// delete the premesh of the edges to accommodate for possible smooth/pert modifications
// applied to adjacent surfaces
{
std::set<Topo::CoEdge *> set_coedges;
for (auto cf: list_cofaces) {
std::vector<Topo::CoEdge *> coedges;
cf->getCoEdges(coedges);

for (auto ce: coedges) {
set_coedges.insert(ce);
}
}
for (auto ce: set_coedges) {
ce->clearPoints();
ce->getMeshingData()->setPreMeshed(false);
}
}

// maille et modifie le maillage pour les modifications 2D, s'il y en a
setStepProgression (1.);
setStep (++step, "Lissage et perturbation des surfaces", 0.);
Expand Down
143 changes: 19 additions & 124 deletions src/Core/Topo/CommandSplitBlocksWithOgrid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,25 @@ CommandSplitBlocksWithOgrid(Internal::Context& c,
, m_create_internal_vertices(create_internal_vertices)
, m_propagate_neighbor_block(propagate_neighbor_block)
{
// la validité de la sélection se fera dans le preExecute
m_blocs.insert(m_blocs.end(), blocs.begin(), blocs.end());
if (ratio_ogrid<=0.0 || ratio_ogrid>=1.0)
throw TkUtil::Exception (TkUtil::UTF8String ("Le ratio doit être dans l'interval ]0 1[", TkUtil::Charset::UTF_8));

if (nb_bras<=0)
throw TkUtil::Exception (TkUtil::UTF8String ("Le nombre de bras doit être d'au moins 1", TkUtil::Charset::UTF_8));

// on ne conserve que les blocs structurés et non dégénérés
for (std::vector<Topo::Block* >::iterator iter = blocs.begin();
iter != blocs.end(); ++iter){
Topo::Block* hb = *iter;
if (hb->isStructured() && hb->getNbVertices() == 8)
m_blocs.push_back(hb);
else{
TkUtil::UTF8String message (TkUtil::Charset::UTF_8);
message <<"Il n'est pas prévu de faire un découpage en o-grid dans un bloc non structuré ou dégénéré\n";
message << "("<<hb->getName()<<" n'est pas structuré)";
throw TkUtil::Exception(message);
}
}

// la validité de la sélection se fera lors de la création des filtres
m_cofaces.insert(m_cofaces.end(), cofaces.begin(), cofaces.end());
Expand All @@ -66,125 +83,6 @@ CommandSplitBlocksWithOgrid::
{
}
/*----------------------------------------------------------------------------*/
/* Les traitements de la méthode preExecute étaient auparavant faits dans le */
/* constructeur. Or, lever une exception dans le constructeur ne permet pas */
/* de récupérer le message d'erreur si la commande a été déclenchée en Python */
/* (fonctionne depuis l'IHM). */
void CommandSplitBlocksWithOgrid::
preExecute()
{
if (m_ratio_ogrid<=0.0 || m_ratio_ogrid>=1.0)
throw TkUtil::Exception (TkUtil::UTF8String ("Le ratio doit être dans l'interval ]0 1[", TkUtil::Charset::UTF_8));

if (m_nb_meshing_edges<=0)
throw TkUtil::Exception (TkUtil::UTF8String ("Le nombre de bras doit être d'au moins 1", TkUtil::Charset::UTF_8));

// on vérifie que les blocs sont structurés et non dégénérés
for (std::vector<Topo::Block* >::iterator iter = m_blocs.begin();
iter != m_blocs.end(); ++iter){
Topo::Block* hb = *iter;
if (!(hb->isStructured() && hb->getNbVertices() == 8)){
TkUtil::UTF8String message (TkUtil::Charset::UTF_8);
message <<"Il n'est pas prévu de faire un découpage en o-grid dans un bloc non structuré ou dégénéré\n";
message << "("<<hb->getName()<<" n'est pas structuré)";
throw TkUtil::Exception(message);
}
}

// Vérification de la contrainte d'Euler sur les blocs
// https://fr.wikipedia.org/wiki/Caract%C3%A9ristique_d%27Euler
// Pour tout sommet s d'un bloc, on considère tous les blocs adjacents à s
// comme un unique polyhèdre sur lequel on vérifie la contrainte d'Euler
// cad : S - A + F = 2

// Recherche de tous les sommets des blocs à découper (en enlevant les doublons)
std::set<Topo::Vertex*> all_vertices;
for (auto bi = m_blocs.begin(); bi != m_blocs.end(); ++bi){
Topo::Block* b = *bi;
std::vector<Topo::Vertex* > vertices;
b->getVertices(vertices);
for (auto vi = vertices.begin(); vi != vertices.end(); ++vi)
all_vertices.insert(*vi);
}

// Parcours des blocs adjacents à chacun des sommets (parmi les blocs sélectionnés).
// Ils sont considérés comme un unique polyhèdre
// pour le calcul de la contrainte d'Euler.
for (auto vi = all_vertices.begin(); vi != all_vertices.end(); ++vi){
Topo::Vertex* v = *vi;
// recherche de tous les blocs adjacents à v
std::vector<Topo::Block* > adjacent_blocks;
v->getBlocks(adjacent_blocks);
// filtrage pour ne laisser que les blocs de la liste des blocs sélectionnés (m_blocs)
adjacent_blocks.erase(std::remove_if(adjacent_blocks.begin(), adjacent_blocks.end(), [&](Topo::Block* b){
return std::find(m_blocs.begin(), m_blocs.end(), b) == m_blocs.end();
}), adjacent_blocks.end());

// Recherche des faces externes des blocs adjacents (= du polyhèdre)
// Pour cela, effacement des faces communes
std::set<Topo::CoFace*> external_faces;
for (auto bi = adjacent_blocks.begin(); bi != adjacent_blocks.end(); ++bi){
Topo::Block* hb = *bi;

std::vector<Topo::CoFace* > faces;
hb->getCoFaces(faces);
for (auto fi = faces.begin(); fi != faces.end(); ++fi){
Topo::CoFace* f = *fi;
if (external_faces.find(f) == external_faces.end())
// not found
external_faces.insert(f);
else
// found => common internal face
external_faces.erase(f);
}
}

// Recherche des aretes et sommets des faces externes.
// On utilise un set pour éviter les doublons.
std::set<Topo::CoEdge*> external_edges;
std::set<Topo::Vertex*> external_vertices;
for (auto fi = external_faces.begin(); fi != external_faces.end(); ++fi){
Topo::CoFace* f = *fi;

std::vector<Topo::CoEdge* > edges;
f->getCoEdges(edges);
for (auto ei = edges.begin(); ei != edges.end() ; ++ei)
external_edges.insert(*ei);

std::vector<Topo::Vertex* > vertices;
f->getVertices(vertices);
for (auto vi = vertices.begin(); vi != vertices.end(); ++vi)
external_vertices.insert(*vi);
}

// Calcul de khi = S - A + F
const int S = external_vertices.size();
const int A = external_edges.size();
const int F = external_faces.size();
const int khi = S - A + F;

#ifdef _DEBUG_SPLIT_OGRID
std::cout << "Pour " << v->getName() << std::endl;
std::cout << " Faces externes des blocs adjacents :";
for (auto fi = external_faces.begin(); fi != external_faces.end(); ++fi)
std::cout << " " << (*fi)->getName();
std::cout << std::endl;
std::cout << " S=" << S << ", A=" << A << ", F=" << F << " => Khi=" << khi << std::endl;
#endif

if (khi != 2) {
TkUtil::UTF8String message (TkUtil::Charset::UTF_8);
message << "La caractéristique d'Euler (S-A+F) n'est pas respectée pour les blocs adjacents à ";
message << v->getName();
message <<" c'est à dire le polyhèdre représenté par [";
for (auto bi = adjacent_blocks.begin(); bi != adjacent_blocks.end(); ++bi)
message << " " << (*bi)->getName();
message << " ]. Par conséquent, réaliser un O-grid global n'est pas possible.";
throw TkUtil::Exception(message);
}
}
}
/*----------------------------------------------------------------------------*/
void CommandSplitBlocksWithOgrid::
internalExecute()
{
Expand All @@ -196,9 +94,6 @@ internalExecute()
std::cout<<"CommandSplitBlocksWithOgrid::internalExecute"<<std::endl;
#endif

// vérifications avant exécution
preExecute();

// Filtres: à 1 pour ce qui est sur le bord et à 2 ce qui est à l'intérieur
std::map<Vertex*, uint> filtre_vertex;
std::map<CoEdge*, uint> filtre_coedge;
Expand Down
7 changes: 6 additions & 1 deletion src/Core/protected/Internal/Resources.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,12 @@ class Resources
/**
* Durée d'exécution de commande à partir de laquelle une notification système est envoyée.
*/
Preferences::UnsignedLongNamedValue _commandNotificationDelay;
Preferences::UnsignedLongNamedValue _commandNotificationDelay;

/**
* Durée d'affichage des notifications système (en millisecondes) ou 0 pour les désactiver.
*/
Preferences::UnsignedLongNamedValue _commandNotificationDuration;

/**
* A partir de quel nombre d'entités sélectionnées ne faut il plus afficher les propriétés individuelles de la sélection ? */
Expand Down
7 changes: 0 additions & 7 deletions src/Core/protected/Topo/CommandSplitBlocksWithOgrid.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,6 @@ class CommandSplitBlocksWithOgrid: public Topo::CommandEditTopo {
virtual void getPreviewRepresentation(Utils::DisplayRepresentation& dr);

private:
/** Les traitements de la méthode preExecute étaient auparavant faits dans le
* constructeur. Or, lever une exception dans le constructeur ne permet pas
* de récupérer le message d'erreur si la commande a été déclenchée en Python
* (fonctionne depuis l'IHM).
*/
void preExecute();

/** Remplissage des filtres pour les sommets, arêtes communes,
* faces communes et les blocs
* On met à 1 ce qui est sur le bord et
Expand Down
2 changes: 2 additions & 0 deletions src/QtComponents/QtMgx3DApplication.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -758,6 +758,7 @@ void QtMgx3DApplication::applyConfiguration (const Section& mainSection)
PreferencesHelper::getBoolean (operationSection, Resources::instance ( )._showDialogOnCommandError);
PreferencesHelper::getBoolean (operationSection, Resources::instance ( )._showAmodalDialogOnCommandError);
PreferencesHelper::getUnsignedLong (operationSection, Resources::instance ( )._commandNotificationDelay);
PreferencesHelper::getUnsignedLong (operationSection, Resources::instance ( )._commandNotificationDuration);
EntitySeizureManager::interactiveModeBackground.setRedF (Resources::instance ( )._IDSeizureBackgroundColor.getRed ( ));
EntitySeizureManager::interactiveModeBackground.setGreenF (Resources::instance ( )._IDSeizureBackgroundColor.getGreen ( ));
EntitySeizureManager::interactiveModeBackground.setBlueF (Resources::instance ( )._IDSeizureBackgroundColor.getBlue ( ));
Expand Down Expand Up @@ -1052,6 +1053,7 @@ void QtMgx3DApplication::saveConfiguration (Section& mainSection)
PreferencesHelper::updateBoolean (operationSection, Resources::instance ( )._showDialogOnCommandError);
PreferencesHelper::updateBoolean (operationSection, Resources::instance ( )._showAmodalDialogOnCommandError);
PreferencesHelper::updateUnsignedLong (operationSection, Resources::instance ( )._commandNotificationDelay);
PreferencesHelper::updateUnsignedLong (operationSection, Resources::instance ( )._commandNotificationDuration);
PreferencesHelper::updateUnsignedLong (selectionSection, Resources::instance ( )._maxIndividualProperties);
PreferencesHelper::updateUnsignedLong (selectionSection, Resources::instance ( )._maxCommonProperties);
PreferencesHelper::updateBoolean (groupsSection, Resources::instance ( )._automaticSort);
Expand Down
4 changes: 2 additions & 2 deletions src/QtComponents/QtMgx3DMainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4442,7 +4442,7 @@ const SelectionManagerIfc& QtMgx3DMainWindow::getSelectionManager ( ) const
const string warn = commandInternal->getWarningToPopup();
if (false == warn.empty())
{
QtMessageBox::systemNotification ("Magix3D", QtMgx3DApplication::getAppIcon ( ), "Commandes terminées avec avertissement.", QtMessageBox::URGENCY_CRITICAL);
QtMessageBox::systemNotification ("Magix3D", QtMgx3DApplication::getAppIcon ( ), "Commandes terminées avec avertissement.", QtMessageBox::URGENCY_NORMAL, Resources::instance ( )._commandNotificationDuration);
if (false == Resources::instance ( )._showAmodalDialogOnCommandError.getValue ( ))
QtMessageBox::displayWarningMessage (this, getAppTitle().c_str ( ), warn); // Défaut
else
Expand All @@ -4460,7 +4460,7 @@ const SelectionManagerIfc& QtMgx3DMainWindow::getSelectionManager ( ) const
if ((true == Resources::instance()._showDialogOnCommandError.getValue()) && (false == command.isUserNotified()))
{
command.setUserNotified (true);
QtMessageBox::systemNotification ("Magix3D", QtMgx3DApplication::getAppIcon ( ), "Commandes terminées en erreur.", QtMessageBox::URGENCY_CRITICAL);
QtMessageBox::systemNotification ("Magix3D", QtMgx3DApplication::getAppIcon ( ), "Commandes terminées en erreur.", QtMessageBox::URGENCY_NORMAL, Resources::instance ( )._commandNotificationDuration);
if (false == Resources::instance ( )._showAmodalDialogOnCommandError.getValue ( ))
QtMessageBox::displayErrorMessage (this, getAppTitle ( ), command.getErrorMessage ( )); // défaut
else
Expand Down
Loading

0 comments on commit fe12849

Please sign in to comment.