2023-08-16 00:20:26 +10:00
|
|
|
/* SPDX-FileCopyrightText: 2008-2023 Blender Authors
|
2023-06-14 23:30:43 +10:00
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
2013-01-02 01:55:30 +00:00
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
|
* \ingroup freestyle
|
|
|
|
|
* \brief Class to build view edges and the underlying chains of feature edges...
|
2013-01-02 01:55:30 +00:00
|
|
|
*/
|
2008-04-30 15:41:54 +00:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
#include <list>
|
|
|
|
|
|
|
|
|
|
#include "SilhouetteGeomEngine.h"
|
2008-04-30 15:41:54 +00:00
|
|
|
#include "ViewEdgeXBuilder.h"
|
2013-01-02 01:55:30 +00:00
|
|
|
#include "ViewMap.h"
|
|
|
|
|
|
2008-04-30 15:41:54 +00:00
|
|
|
#include "../winged_edge/WXEdge.h"
|
|
|
|
|
|
2022-10-26 18:58:04 +02:00
|
|
|
#include "BLI_sys_types.h"
|
|
|
|
|
|
2008-04-30 15:41:54 +00:00
|
|
|
using namespace std;
|
|
|
|
|
|
2013-04-09 00:46:49 +00:00
|
|
|
namespace Freestyle {
|
|
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
void ViewEdgeXBuilder::Init(ViewShape *oVShape)
|
|
|
|
|
{
|
2020-11-06 17:49:09 +01:00
|
|
|
if (nullptr == oVShape) {
|
2013-01-02 01:55:30 +00:00
|
|
|
return;
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2013-01-02 01:55:30 +00:00
|
|
|
|
2019-07-31 14:25:09 +02:00
|
|
|
// for design convenience, we store the current SShape.
|
2013-01-02 01:55:30 +00:00
|
|
|
_pCurrentSShape = oVShape->sshape();
|
2020-11-06 17:49:09 +01:00
|
|
|
if (nullptr == _pCurrentSShape) {
|
2013-01-02 01:55:30 +00:00
|
|
|
return;
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2013-01-02 01:55:30 +00:00
|
|
|
|
|
|
|
|
_pCurrentVShape = oVShape;
|
|
|
|
|
|
|
|
|
|
// Reset previous data
|
|
|
|
|
//--------------------
|
2019-05-31 22:51:19 +10:00
|
|
|
if (!_SVertexMap.empty()) {
|
2013-01-02 01:55:30 +00:00
|
|
|
_SVertexMap.clear();
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2008-04-30 15:41:54 +00:00
|
|
|
}
|
|
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
void ViewEdgeXBuilder::BuildViewEdges(WXShape *iWShape,
|
|
|
|
|
ViewShape *oVShape,
|
|
|
|
|
vector<ViewEdge *> &ioVEdges,
|
|
|
|
|
vector<ViewVertex *> &ioVVertices,
|
|
|
|
|
vector<FEdge *> &ioFEdges,
|
|
|
|
|
vector<SVertex *> &ioSVertices)
|
|
|
|
|
{
|
|
|
|
|
// Reinit structures
|
|
|
|
|
Init(oVShape);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-09-25 16:56:17 +10:00
|
|
|
// ViewEdge *vedge; /* UNUSED. */
|
|
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
// Let us build the smooth stuff
|
|
|
|
|
//----------------------------------------
|
|
|
|
|
// We parse all faces to find the ones that contain smooth edges
|
|
|
|
|
vector<WFace *> &wfaces = iWShape->GetFaceList();
|
|
|
|
|
vector<WFace *>::iterator wf, wfend;
|
|
|
|
|
WXFace *wxf;
|
|
|
|
|
for (wf = wfaces.begin(), wfend = wfaces.end(); wf != wfend; wf++) {
|
|
|
|
|
wxf = dynamic_cast<WXFace *>(*wf);
|
2022-09-25 15:14:13 +10:00
|
|
|
if (false == (wxf)->hasSmoothEdges()) { // does it contain at least one smooth edge ?
|
2013-01-02 01:55:30 +00:00
|
|
|
continue;
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2013-01-02 01:55:30 +00:00
|
|
|
// parse all smooth layers:
|
|
|
|
|
vector<WXFaceLayer *> &smoothLayers = wxf->getSmoothLayers();
|
|
|
|
|
for (vector<WXFaceLayer *>::iterator sl = smoothLayers.begin(), slend = smoothLayers.end();
|
|
|
|
|
sl != slend;
|
|
|
|
|
++sl)
|
|
|
|
|
{
|
2019-05-31 22:51:19 +10:00
|
|
|
if (!(*sl)->hasSmoothEdge()) {
|
2013-01-02 01:55:30 +00:00
|
|
|
continue;
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2022-09-25 15:14:13 +10:00
|
|
|
if (stopSmoothViewEdge(*sl)) { // has it been parsed already ?
|
2013-01-02 01:55:30 +00:00
|
|
|
continue;
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2019-04-30 17:50:57 +10:00
|
|
|
// here we know that we're dealing with a face layer that has not been processed yet and that
|
|
|
|
|
// contains a smooth edge.
|
2025-04-29 09:02:49 +10:00
|
|
|
/* `vedge =` */ /* UNUSED */ BuildSmoothViewEdge(OWXFaceLayer(*sl, true));
|
2013-01-02 01:55:30 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
// Now let's build sharp view edges:
|
|
|
|
|
//----------------------------------
|
|
|
|
|
// Reset all userdata for WXEdge structure
|
|
|
|
|
//----------------------------------------
|
2019-04-30 17:50:57 +10:00
|
|
|
// iWShape->ResetUserData();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
WXEdge *wxe;
|
|
|
|
|
vector<WEdge *> &wedges = iWShape->getEdgeList();
|
|
|
|
|
//------------------------------
|
|
|
|
|
for (vector<WEdge *>::iterator we = wedges.begin(), weend = wedges.end(); we != weend; we++) {
|
|
|
|
|
wxe = dynamic_cast<WXEdge *>(*we);
|
2019-05-31 22:51:19 +10:00
|
|
|
if (Nature::NO_FEATURE == wxe->nature()) {
|
2013-01-02 01:55:30 +00:00
|
|
|
continue;
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
if (!stopSharpViewEdge(wxe)) {
|
|
|
|
|
bool b = true;
|
2019-05-31 22:51:19 +10:00
|
|
|
if (wxe->order() == -1) {
|
2013-01-02 01:55:30 +00:00
|
|
|
b = false;
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2013-01-02 01:55:30 +00:00
|
|
|
BuildSharpViewEdge(OWXEdge(wxe, b));
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
// Reset all userdata for WXEdge structure
|
|
|
|
|
//----------------------------------------
|
|
|
|
|
iWShape->ResetUserData();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
// Add all these new edges to the scene's feature edges list:
|
|
|
|
|
//-----------------------------------------------------------
|
|
|
|
|
vector<FEdge *> &newedges = _pCurrentSShape->getEdgeList();
|
|
|
|
|
vector<SVertex *> &newVertices = _pCurrentSShape->getVertexList();
|
|
|
|
|
vector<ViewVertex *> &newVVertices = _pCurrentVShape->vertices();
|
|
|
|
|
vector<ViewEdge *> &newVEdges = _pCurrentVShape->edges();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
// inserts in ioFEdges, at its end, all the edges of newedges
|
|
|
|
|
ioFEdges.insert(ioFEdges.end(), newedges.begin(), newedges.end());
|
|
|
|
|
ioSVertices.insert(ioSVertices.end(), newVertices.begin(), newVertices.end());
|
|
|
|
|
ioVVertices.insert(ioVVertices.end(), newVVertices.begin(), newVVertices.end());
|
|
|
|
|
ioVEdges.insert(ioVEdges.end(), newVEdges.begin(), newVEdges.end());
|
2008-04-30 15:41:54 +00:00
|
|
|
}
|
|
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
ViewEdge *ViewEdgeXBuilder::BuildSmoothViewEdge(const OWXFaceLayer &iFaceLayer)
|
|
|
|
|
{
|
|
|
|
|
// Find first edge:
|
|
|
|
|
OWXFaceLayer first = iFaceLayer;
|
|
|
|
|
OWXFaceLayer currentFace = first;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
// bidirectional chaining.
|
|
|
|
|
// first direction
|
|
|
|
|
list<OWXFaceLayer> facesChain;
|
2022-09-26 10:04:44 +10:00
|
|
|
uint size = 0;
|
2013-01-02 01:55:30 +00:00
|
|
|
while (!stopSmoothViewEdge(currentFace.fl)) {
|
|
|
|
|
facesChain.push_back(currentFace);
|
|
|
|
|
++size;
|
|
|
|
|
currentFace.fl->userdata = (void *)1; // processed
|
|
|
|
|
// Find the next edge!
|
|
|
|
|
currentFace = FindNextFaceLayer(currentFace);
|
|
|
|
|
}
|
|
|
|
|
OWXFaceLayer end = facesChain.back();
|
|
|
|
|
// second direction
|
|
|
|
|
currentFace = FindPreviousFaceLayer(first);
|
|
|
|
|
while (!stopSmoothViewEdge(currentFace.fl)) {
|
|
|
|
|
facesChain.push_front(currentFace);
|
|
|
|
|
++size;
|
|
|
|
|
currentFace.fl->userdata = (void *)1; // processed
|
|
|
|
|
// Find the previous edge!
|
|
|
|
|
currentFace = FindPreviousFaceLayer(currentFace);
|
|
|
|
|
}
|
|
|
|
|
first = facesChain.front();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
if (iFaceLayer.fl->nature() & Nature::RIDGE) {
|
|
|
|
|
if (size < 4) {
|
2020-11-06 17:49:09 +01:00
|
|
|
return nullptr;
|
2013-01-02 01:55:30 +00:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
// Start a new chain edges
|
|
|
|
|
ViewEdge *newVEdge = new ViewEdge;
|
|
|
|
|
newVEdge->setId(_currentViewId);
|
|
|
|
|
++_currentViewId;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
_pCurrentVShape->AddEdge(newVEdge);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
// build FEdges
|
2020-11-06 17:49:09 +01:00
|
|
|
FEdge *feprevious = nullptr;
|
|
|
|
|
FEdge *fefirst = nullptr;
|
|
|
|
|
FEdge *fe = nullptr;
|
2013-01-02 01:55:30 +00:00
|
|
|
for (list<OWXFaceLayer>::iterator fl = facesChain.begin(), flend = facesChain.end(); fl != flend;
|
|
|
|
|
++fl)
|
|
|
|
|
{
|
|
|
|
|
fe = BuildSmoothFEdge(feprevious, (*fl));
|
2019-05-31 22:51:19 +10:00
|
|
|
if (feprevious && fe == feprevious) {
|
2013-01-02 01:55:30 +00:00
|
|
|
continue;
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2013-01-02 01:55:30 +00:00
|
|
|
fe->setViewEdge(newVEdge);
|
2019-05-31 22:51:19 +10:00
|
|
|
if (!fefirst) {
|
2013-01-02 01:55:30 +00:00
|
|
|
fefirst = fe;
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2013-01-02 01:55:30 +00:00
|
|
|
feprevious = fe;
|
|
|
|
|
}
|
|
|
|
|
// Store the chain starting edge:
|
|
|
|
|
_pCurrentSShape->AddChain(fefirst);
|
|
|
|
|
newVEdge->setNature(iFaceLayer.fl->nature());
|
|
|
|
|
newVEdge->setFEdgeA(fefirst);
|
|
|
|
|
newVEdge->setFEdgeB(fe);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
// is it a closed loop ?
|
|
|
|
|
if ((first == end) && (size != 1)) {
|
|
|
|
|
fefirst->setPreviousEdge(fe);
|
|
|
|
|
fe->setNextEdge(fefirst);
|
2020-11-06 17:49:09 +01:00
|
|
|
newVEdge->setA(nullptr);
|
|
|
|
|
newVEdge->setB(nullptr);
|
2013-01-02 01:55:30 +00:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
ViewVertex *vva = MakeViewVertex(fefirst->vertexA());
|
|
|
|
|
ViewVertex *vvb = MakeViewVertex(fe->vertexB());
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-03-11 06:56:51 +00:00
|
|
|
((NonTVertex *)vva)->AddOutgoingViewEdge(newVEdge);
|
|
|
|
|
((NonTVertex *)vvb)->AddIncomingViewEdge(newVEdge);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
newVEdge->setA(vva);
|
|
|
|
|
newVEdge->setB(vvb);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
return newVEdge;
|
2008-04-30 15:41:54 +00:00
|
|
|
}
|
|
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
ViewEdge *ViewEdgeXBuilder::BuildSharpViewEdge(const OWXEdge &iWEdge)
|
|
|
|
|
{
|
|
|
|
|
// Start a new sharp chain edges
|
|
|
|
|
ViewEdge *newVEdge = new ViewEdge;
|
|
|
|
|
newVEdge->setId(_currentViewId);
|
|
|
|
|
++_currentViewId;
|
2022-09-26 10:04:44 +10:00
|
|
|
uint size = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
_pCurrentVShape->AddEdge(newVEdge);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
// Find first edge:
|
|
|
|
|
OWXEdge firstWEdge = iWEdge;
|
2023-09-25 16:56:17 +10:00
|
|
|
// OWXEdge previousWEdge = firstWEdge; /* UNUSED */
|
2013-01-02 01:55:30 +00:00
|
|
|
OWXEdge currentWEdge = firstWEdge;
|
|
|
|
|
list<OWXEdge> edgesChain;
|
Experimental fix for incorrect view edge visibility.
The problem is that the visibility of view edges in the view map may be incorrect.
The main cause of this issue is that view edges are constructed from a series of FEdges
without testing the visibility of the FEdges being concatenated. Later view edges
are split into pieces if two view edges intersect in the 2D image coordinate system.
After that the visibility of the view edges is computed by taking account of occluding
faces in the 3D scene. In many cases this procedure results in correct line visibility,
but not always (that is the problem).
A simple solution experimentally implemented here is not to chain FEdges at all.
Instead view edges are constructed from at most one FEdge now. This solution is only
applied to sharp FEdges (roughly corresponding to edges in the input mesh data; specifically,
silhouette, crease, border, edge mark, contour, external contour, and material boundary).
A better solution is to reorder the three steps of view edges construction mentioned above,
i.e., first splitting FEdges at 2D intersection, computing the visibility of the FEdges,
then concatenating them to build view edges. This solution is left for future work for now.
2012-09-03 01:01:50 +00:00
|
|
|
#if 0 /* TK 02-Sep-2012 Experimental fix for incorrect view edge visibility. */
|
2013-01-02 01:55:30 +00:00
|
|
|
// bidirectional chaining
|
|
|
|
|
// first direction:
|
|
|
|
|
while (!stopSharpViewEdge(currentWEdge.e)) {
|
|
|
|
|
edgesChain.push_back(currentWEdge);
|
|
|
|
|
++size;
|
2019-04-17 08:24:14 +02:00
|
|
|
currentWEdge.e->userdata = (void *)1; // processed
|
2013-01-02 01:55:30 +00:00
|
|
|
// Find the next edge!
|
|
|
|
|
currentWEdge = FindNextWEdge(currentWEdge);
|
|
|
|
|
}
|
|
|
|
|
OWXEdge endWEdge = edgesChain.back();
|
|
|
|
|
// second direction
|
|
|
|
|
currentWEdge = FindPreviousWEdge(firstWEdge);
|
|
|
|
|
while (!stopSharpViewEdge(currentWEdge.e)) {
|
|
|
|
|
edgesChain.push_front(currentWEdge);
|
|
|
|
|
++size;
|
2019-04-17 08:24:14 +02:00
|
|
|
currentWEdge.e->userdata = (void *)1; // processed
|
2013-01-02 01:55:30 +00:00
|
|
|
// Find the previous edge!
|
|
|
|
|
currentWEdge = FindPreviousWEdge(currentWEdge);
|
|
|
|
|
}
|
Experimental fix for incorrect view edge visibility.
The problem is that the visibility of view edges in the view map may be incorrect.
The main cause of this issue is that view edges are constructed from a series of FEdges
without testing the visibility of the FEdges being concatenated. Later view edges
are split into pieces if two view edges intersect in the 2D image coordinate system.
After that the visibility of the view edges is computed by taking account of occluding
faces in the 3D scene. In many cases this procedure results in correct line visibility,
but not always (that is the problem).
A simple solution experimentally implemented here is not to chain FEdges at all.
Instead view edges are constructed from at most one FEdge now. This solution is only
applied to sharp FEdges (roughly corresponding to edges in the input mesh data; specifically,
silhouette, crease, border, edge mark, contour, external contour, and material boundary).
A better solution is to reorder the three steps of view edges construction mentioned above,
i.e., first splitting FEdges at 2D intersection, computing the visibility of the FEdges,
then concatenating them to build view edges. This solution is left for future work for now.
2012-09-03 01:01:50 +00:00
|
|
|
#else
|
2013-01-02 01:55:30 +00:00
|
|
|
edgesChain.push_back(currentWEdge);
|
|
|
|
|
++size;
|
|
|
|
|
currentWEdge.e->userdata = (void *)1; // processed
|
|
|
|
|
OWXEdge endWEdge = edgesChain.back();
|
Experimental fix for incorrect view edge visibility.
The problem is that the visibility of view edges in the view map may be incorrect.
The main cause of this issue is that view edges are constructed from a series of FEdges
without testing the visibility of the FEdges being concatenated. Later view edges
are split into pieces if two view edges intersect in the 2D image coordinate system.
After that the visibility of the view edges is computed by taking account of occluding
faces in the 3D scene. In many cases this procedure results in correct line visibility,
but not always (that is the problem).
A simple solution experimentally implemented here is not to chain FEdges at all.
Instead view edges are constructed from at most one FEdge now. This solution is only
applied to sharp FEdges (roughly corresponding to edges in the input mesh data; specifically,
silhouette, crease, border, edge mark, contour, external contour, and material boundary).
A better solution is to reorder the three steps of view edges construction mentioned above,
i.e., first splitting FEdges at 2D intersection, computing the visibility of the FEdges,
then concatenating them to build view edges. This solution is left for future work for now.
2012-09-03 01:01:50 +00:00
|
|
|
#endif
|
2013-01-02 01:55:30 +00:00
|
|
|
firstWEdge = edgesChain.front();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
// build FEdges
|
2020-11-06 17:49:09 +01:00
|
|
|
FEdge *feprevious = nullptr;
|
|
|
|
|
FEdge *fefirst = nullptr;
|
|
|
|
|
FEdge *fe = nullptr;
|
2013-01-02 01:55:30 +00:00
|
|
|
for (list<OWXEdge>::iterator we = edgesChain.begin(), weend = edgesChain.end(); we != weend;
|
2024-01-02 18:12:54 +01:00
|
|
|
++we)
|
|
|
|
|
{
|
2013-01-02 01:55:30 +00:00
|
|
|
fe = BuildSharpFEdge(feprevious, (*we));
|
|
|
|
|
fe->setViewEdge(newVEdge);
|
2019-05-31 22:51:19 +10:00
|
|
|
if (!fefirst) {
|
2013-01-02 01:55:30 +00:00
|
|
|
fefirst = fe;
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2013-01-02 01:55:30 +00:00
|
|
|
feprevious = fe;
|
|
|
|
|
}
|
|
|
|
|
// Store the chain starting edge:
|
|
|
|
|
_pCurrentSShape->AddChain(fefirst);
|
|
|
|
|
newVEdge->setNature(iWEdge.e->nature());
|
|
|
|
|
newVEdge->setFEdgeA(fefirst);
|
|
|
|
|
newVEdge->setFEdgeB(fe);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
// is it a closed loop ?
|
|
|
|
|
if ((firstWEdge == endWEdge) && (size != 1)) {
|
|
|
|
|
fefirst->setPreviousEdge(fe);
|
|
|
|
|
fe->setNextEdge(fefirst);
|
2020-11-06 17:49:09 +01:00
|
|
|
newVEdge->setA(nullptr);
|
|
|
|
|
newVEdge->setB(nullptr);
|
2013-01-02 01:55:30 +00:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
ViewVertex *vva = MakeViewVertex(fefirst->vertexA());
|
|
|
|
|
ViewVertex *vvb = MakeViewVertex(fe->vertexB());
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-03-11 06:56:51 +00:00
|
|
|
((NonTVertex *)vva)->AddOutgoingViewEdge(newVEdge);
|
|
|
|
|
((NonTVertex *)vvb)->AddIncomingViewEdge(newVEdge);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
newVEdge->setA(vva);
|
|
|
|
|
newVEdge->setB(vvb);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
return newVEdge;
|
2008-04-30 15:41:54 +00:00
|
|
|
}
|
|
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
OWXFaceLayer ViewEdgeXBuilder::FindNextFaceLayer(const OWXFaceLayer &iFaceLayer)
|
|
|
|
|
{
|
2020-11-06 17:49:09 +01:00
|
|
|
WXFace *nextFace = nullptr;
|
2013-01-02 01:55:30 +00:00
|
|
|
WOEdge *woeend;
|
|
|
|
|
real tend;
|
|
|
|
|
if (iFaceLayer.order) {
|
|
|
|
|
woeend = iFaceLayer.fl->getSmoothEdge()->woeb();
|
|
|
|
|
tend = iFaceLayer.fl->getSmoothEdge()->tb();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
woeend = iFaceLayer.fl->getSmoothEdge()->woea();
|
|
|
|
|
tend = iFaceLayer.fl->getSmoothEdge()->ta();
|
|
|
|
|
}
|
|
|
|
|
// special case of EDGE_VERTEX config:
|
2020-11-06 12:30:59 +11:00
|
|
|
if (ELEM(tend, 0.0, 1.0)) {
|
2013-01-02 01:55:30 +00:00
|
|
|
WVertex *nextVertex;
|
2019-05-31 22:51:19 +10:00
|
|
|
if (tend == 0.0) {
|
2013-01-02 01:55:30 +00:00
|
|
|
nextVertex = woeend->GetaVertex();
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2013-01-02 01:55:30 +00:00
|
|
|
nextVertex = woeend->GetbVertex();
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
|
|
|
|
if (nextVertex->isBoundary()) { // if it's a non-manifold vertex -> ignore
|
2020-11-06 17:49:09 +01:00
|
|
|
return OWXFaceLayer(nullptr, true);
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2013-01-02 01:55:30 +00:00
|
|
|
bool found = false;
|
|
|
|
|
WVertex::face_iterator f = nextVertex->faces_begin();
|
|
|
|
|
WVertex::face_iterator fend = nextVertex->faces_end();
|
|
|
|
|
while ((!found) && (f != fend)) {
|
|
|
|
|
nextFace = dynamic_cast<WXFace *>(*f);
|
2020-11-06 17:49:09 +01:00
|
|
|
if ((nullptr != nextFace) && (nextFace != iFaceLayer.fl->getFace())) {
|
2013-01-02 01:55:30 +00:00
|
|
|
vector<WXFaceLayer *> sameNatureLayers;
|
|
|
|
|
nextFace->retrieveSmoothEdgesLayers(iFaceLayer.fl->nature(), sameNatureLayers);
|
|
|
|
|
// don't know... Maybe should test whether this face has also a vertex_edge configuration.
|
|
|
|
|
if (sameNatureLayers.size() == 1) {
|
|
|
|
|
WXFaceLayer *winner = sameNatureLayers[0];
|
|
|
|
|
// check face mark continuity
|
2019-05-31 22:51:19 +10:00
|
|
|
if (winner->getFace()->GetMark() != iFaceLayer.fl->getFace()->GetMark()) {
|
2020-11-06 17:49:09 +01:00
|
|
|
return OWXFaceLayer(nullptr, true);
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
|
|
|
|
if (woeend == winner->getSmoothEdge()->woea()->twin()) {
|
2013-01-02 01:55:30 +00:00
|
|
|
return OWXFaceLayer(winner, true);
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2020-08-07 12:39:05 +02:00
|
|
|
|
|
|
|
|
return OWXFaceLayer(winner, false);
|
2013-01-02 01:55:30 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
++f;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
nextFace = dynamic_cast<WXFace *>(iFaceLayer.fl->getFace()->GetBordingFace(woeend));
|
2019-05-31 22:51:19 +10:00
|
|
|
if (!nextFace) {
|
2020-11-06 17:49:09 +01:00
|
|
|
return OWXFaceLayer(nullptr, true);
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2019-04-30 17:50:57 +10:00
|
|
|
// if the next face layer has either no smooth edge or no smooth edge of same nature, no next
|
|
|
|
|
// face
|
2019-05-31 22:51:19 +10:00
|
|
|
if (!nextFace->hasSmoothEdges()) {
|
2020-11-06 17:49:09 +01:00
|
|
|
return OWXFaceLayer(nullptr, true);
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2013-01-02 01:55:30 +00:00
|
|
|
vector<WXFaceLayer *> sameNatureLayers;
|
|
|
|
|
nextFace->retrieveSmoothEdgesLayers(iFaceLayer.fl->nature(), sameNatureLayers);
|
|
|
|
|
// don't know how to deal with several edges of same nature on a single face
|
2022-10-07 22:52:53 +11:00
|
|
|
if (sameNatureLayers.empty() || (sameNatureLayers.size() != 1)) {
|
2020-11-06 17:49:09 +01:00
|
|
|
return OWXFaceLayer(nullptr, true);
|
2013-01-02 01:55:30 +00:00
|
|
|
}
|
2020-08-07 12:39:05 +02:00
|
|
|
|
|
|
|
|
WXFaceLayer *winner = sameNatureLayers[0];
|
|
|
|
|
// check face mark continuity
|
|
|
|
|
if (winner->getFace()->GetMark() != iFaceLayer.fl->getFace()->GetMark()) {
|
2020-11-06 17:49:09 +01:00
|
|
|
return OWXFaceLayer(nullptr, true);
|
2020-08-07 12:39:05 +02:00
|
|
|
}
|
|
|
|
|
if (woeend == winner->getSmoothEdge()->woea()->twin()) {
|
|
|
|
|
return OWXFaceLayer(winner, true);
|
2013-01-02 01:55:30 +00:00
|
|
|
}
|
2020-08-07 12:39:05 +02:00
|
|
|
|
|
|
|
|
return OWXFaceLayer(winner, false);
|
2013-01-02 01:55:30 +00:00
|
|
|
}
|
2020-11-06 17:49:09 +01:00
|
|
|
return OWXFaceLayer(nullptr, true);
|
2008-04-30 15:41:54 +00:00
|
|
|
}
|
|
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
OWXFaceLayer ViewEdgeXBuilder::FindPreviousFaceLayer(const OWXFaceLayer &iFaceLayer)
|
|
|
|
|
{
|
2020-11-06 17:49:09 +01:00
|
|
|
WXFace *previousFace = nullptr;
|
2013-01-02 01:55:30 +00:00
|
|
|
WOEdge *woebegin;
|
|
|
|
|
real tend;
|
|
|
|
|
if (iFaceLayer.order) {
|
|
|
|
|
woebegin = iFaceLayer.fl->getSmoothEdge()->woea();
|
|
|
|
|
tend = iFaceLayer.fl->getSmoothEdge()->ta();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
woebegin = iFaceLayer.fl->getSmoothEdge()->woeb();
|
|
|
|
|
tend = iFaceLayer.fl->getSmoothEdge()->tb();
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
// special case of EDGE_VERTEX config:
|
2020-11-06 12:30:59 +11:00
|
|
|
if (ELEM(tend, 0.0, 1.0)) {
|
2013-01-02 01:55:30 +00:00
|
|
|
WVertex *previousVertex;
|
2019-05-31 22:51:19 +10:00
|
|
|
if (tend == 0.0) {
|
2013-01-02 01:55:30 +00:00
|
|
|
previousVertex = woebegin->GetaVertex();
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2013-01-02 01:55:30 +00:00
|
|
|
previousVertex = woebegin->GetbVertex();
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
|
|
|
|
if (previousVertex->isBoundary()) { // if it's a non-manifold vertex -> ignore
|
2020-11-06 17:49:09 +01:00
|
|
|
return OWXFaceLayer(nullptr, true);
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2013-01-02 01:55:30 +00:00
|
|
|
bool found = false;
|
|
|
|
|
WVertex::face_iterator f = previousVertex->faces_begin();
|
|
|
|
|
WVertex::face_iterator fend = previousVertex->faces_end();
|
|
|
|
|
for (; (!found) && (f != fend); ++f) {
|
|
|
|
|
previousFace = dynamic_cast<WXFace *>(*f);
|
2020-11-06 17:49:09 +01:00
|
|
|
if ((nullptr != previousFace) && (previousFace != iFaceLayer.fl->getFace())) {
|
2013-01-02 01:55:30 +00:00
|
|
|
vector<WXFaceLayer *> sameNatureLayers;
|
|
|
|
|
previousFace->retrieveSmoothEdgesLayers(iFaceLayer.fl->nature(), sameNatureLayers);
|
|
|
|
|
// don't know... Maybe should test whether this face has also a vertex_edge configuration
|
|
|
|
|
if (sameNatureLayers.size() == 1) {
|
|
|
|
|
WXFaceLayer *winner = sameNatureLayers[0];
|
|
|
|
|
// check face mark continuity
|
2019-05-31 22:51:19 +10:00
|
|
|
if (winner->getFace()->GetMark() != iFaceLayer.fl->getFace()->GetMark()) {
|
2020-11-06 17:49:09 +01:00
|
|
|
return OWXFaceLayer(nullptr, true);
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
|
|
|
|
if (woebegin == winner->getSmoothEdge()->woeb()->twin()) {
|
2013-01-02 01:55:30 +00:00
|
|
|
return OWXFaceLayer(winner, true);
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2020-08-07 12:39:05 +02:00
|
|
|
|
|
|
|
|
return OWXFaceLayer(winner, false);
|
2013-01-02 01:55:30 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
previousFace = dynamic_cast<WXFace *>(iFaceLayer.fl->getFace()->GetBordingFace(woebegin));
|
2020-11-06 17:49:09 +01:00
|
|
|
if (nullptr == previousFace) {
|
|
|
|
|
return OWXFaceLayer(nullptr, true);
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2019-04-30 17:50:57 +10:00
|
|
|
// if the next face layer has either no smooth edge or no smooth edge of same nature, no next
|
|
|
|
|
// face
|
2019-05-31 22:51:19 +10:00
|
|
|
if (!previousFace->hasSmoothEdges()) {
|
2020-11-06 17:49:09 +01:00
|
|
|
return OWXFaceLayer(nullptr, true);
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2013-01-02 01:55:30 +00:00
|
|
|
vector<WXFaceLayer *> sameNatureLayers;
|
|
|
|
|
previousFace->retrieveSmoothEdgesLayers(iFaceLayer.fl->nature(), sameNatureLayers);
|
|
|
|
|
// don't know how to deal with several edges of same nature on a single face
|
2022-10-07 22:52:53 +11:00
|
|
|
if (sameNatureLayers.empty() || (sameNatureLayers.size() != 1)) {
|
2020-11-06 17:49:09 +01:00
|
|
|
return OWXFaceLayer(nullptr, true);
|
2013-01-02 01:55:30 +00:00
|
|
|
}
|
2020-08-07 12:39:05 +02:00
|
|
|
|
|
|
|
|
WXFaceLayer *winner = sameNatureLayers[0];
|
|
|
|
|
// check face mark continuity
|
|
|
|
|
if (winner->getFace()->GetMark() != iFaceLayer.fl->getFace()->GetMark()) {
|
2020-11-06 17:49:09 +01:00
|
|
|
return OWXFaceLayer(nullptr, true);
|
2020-08-07 12:39:05 +02:00
|
|
|
}
|
|
|
|
|
if (woebegin == winner->getSmoothEdge()->woeb()->twin()) {
|
|
|
|
|
return OWXFaceLayer(winner, true);
|
2013-01-02 01:55:30 +00:00
|
|
|
}
|
2020-08-07 12:39:05 +02:00
|
|
|
|
|
|
|
|
return OWXFaceLayer(winner, false);
|
2013-01-02 01:55:30 +00:00
|
|
|
}
|
2020-11-06 17:49:09 +01:00
|
|
|
return OWXFaceLayer(nullptr, true);
|
2008-04-30 15:41:54 +00:00
|
|
|
}
|
|
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
FEdge *ViewEdgeXBuilder::BuildSmoothFEdge(FEdge *feprevious, const OWXFaceLayer &ifl)
|
|
|
|
|
{
|
|
|
|
|
WOEdge *woea, *woeb;
|
|
|
|
|
real ta, tb;
|
|
|
|
|
SVertex *va, *vb;
|
|
|
|
|
FEdgeSmooth *fe;
|
|
|
|
|
// retrieve exact silhouette data
|
|
|
|
|
WXSmoothEdge *se = ifl.fl->getSmoothEdge();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
if (ifl.order) {
|
|
|
|
|
woea = se->woea();
|
|
|
|
|
woeb = se->woeb();
|
|
|
|
|
ta = se->ta();
|
|
|
|
|
tb = se->tb();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
woea = se->woeb();
|
|
|
|
|
woeb = se->woea();
|
|
|
|
|
ta = se->tb();
|
|
|
|
|
tb = se->ta();
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
Vec3r normal;
|
|
|
|
|
// Make the 2 Svertices
|
2023-05-02 09:32:44 +10:00
|
|
|
|
|
|
|
|
/* That means that we don't have any vertex already built for that face. */
|
|
|
|
|
if (feprevious == nullptr) {
|
2013-01-02 01:55:30 +00:00
|
|
|
Vec3r A1(woea->GetaVertex()->GetVertex());
|
|
|
|
|
Vec3r A2(woea->GetbVertex()->GetVertex());
|
|
|
|
|
Vec3r A(A1 + ta * (A2 - A1));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
va = MakeSVertex(A, false);
|
|
|
|
|
// Set normal:
|
|
|
|
|
Vec3r NA1(ifl.fl->getFace()->GetVertexNormal(woea->GetaVertex()));
|
|
|
|
|
Vec3r NA2(ifl.fl->getFace()->GetVertexNormal(woea->GetbVertex()));
|
|
|
|
|
Vec3r na((1 - ta) * NA1 + ta * NA2);
|
|
|
|
|
na.normalize();
|
|
|
|
|
va->AddNormal(na);
|
|
|
|
|
normal = na;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
// Set CurvatureInfo
|
|
|
|
|
CurvatureInfo *curvature_info_a = new CurvatureInfo(
|
|
|
|
|
*(dynamic_cast<WXVertex *>(woea->GetaVertex())->curvatures()),
|
|
|
|
|
*(dynamic_cast<WXVertex *>(woea->GetbVertex())->curvatures()),
|
|
|
|
|
ta);
|
|
|
|
|
va->setCurvatureInfo(curvature_info_a);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
va = feprevious->vertexB();
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
Vec3r B1(woeb->GetaVertex()->GetVertex());
|
|
|
|
|
Vec3r B2(woeb->GetbVertex()->GetVertex());
|
|
|
|
|
Vec3r B(B1 + tb * (B2 - B1));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-31 22:51:19 +10:00
|
|
|
if (feprevious && (B - va->point3D()).norm() < 1.0e-6) {
|
2013-01-02 01:55:30 +00:00
|
|
|
return feprevious;
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
vb = MakeSVertex(B, false);
|
|
|
|
|
// Set normal:
|
|
|
|
|
Vec3r NB1(ifl.fl->getFace()->GetVertexNormal(woeb->GetaVertex()));
|
|
|
|
|
Vec3r NB2(ifl.fl->getFace()->GetVertexNormal(woeb->GetbVertex()));
|
|
|
|
|
Vec3r nb((1 - tb) * NB1 + tb * NB2);
|
|
|
|
|
nb.normalize();
|
|
|
|
|
normal += nb;
|
|
|
|
|
vb->AddNormal(nb);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
// Set CurvatureInfo
|
|
|
|
|
CurvatureInfo *curvature_info_b = new CurvatureInfo(
|
|
|
|
|
*(dynamic_cast<WXVertex *>(woeb->GetaVertex())->curvatures()),
|
|
|
|
|
*(dynamic_cast<WXVertex *>(woeb->GetbVertex())->curvatures()),
|
|
|
|
|
tb);
|
|
|
|
|
vb->setCurvatureInfo(curvature_info_b);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
// Creates the corresponding feature edge
|
|
|
|
|
fe = new FEdgeSmooth(va, vb);
|
|
|
|
|
fe->setNature(ifl.fl->nature());
|
|
|
|
|
fe->setId(_currentFId);
|
|
|
|
|
fe->setFrsMaterialIndex(ifl.fl->getFace()->frs_materialIndex());
|
|
|
|
|
fe->setFace(ifl.fl->getFace());
|
|
|
|
|
fe->setFaceMark(ifl.fl->getFace()->GetMark());
|
2020-11-06 17:49:09 +01:00
|
|
|
if (feprevious == nullptr) {
|
2013-01-02 01:55:30 +00:00
|
|
|
normal.normalize();
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2013-01-02 01:55:30 +00:00
|
|
|
fe->setNormal(normal);
|
|
|
|
|
fe->setPreviousEdge(feprevious);
|
2019-05-31 22:51:19 +10:00
|
|
|
if (feprevious) {
|
2013-01-02 01:55:30 +00:00
|
|
|
feprevious->setNextEdge(fe);
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2013-01-02 01:55:30 +00:00
|
|
|
_pCurrentSShape->AddEdge(fe);
|
|
|
|
|
va->AddFEdge(fe);
|
|
|
|
|
vb->AddFEdge(fe);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
++_currentFId;
|
|
|
|
|
ifl.fl->userdata = fe;
|
|
|
|
|
return fe;
|
2008-04-30 15:41:54 +00:00
|
|
|
}
|
|
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
bool ViewEdgeXBuilder::stopSmoothViewEdge(WXFaceLayer *iFaceLayer)
|
|
|
|
|
{
|
2020-11-06 17:49:09 +01:00
|
|
|
if (nullptr == iFaceLayer) {
|
2013-01-02 01:55:30 +00:00
|
|
|
return true;
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2020-11-06 17:49:09 +01:00
|
|
|
if (iFaceLayer->userdata == nullptr) {
|
2013-01-02 01:55:30 +00:00
|
|
|
return false;
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2013-01-02 01:55:30 +00:00
|
|
|
return true;
|
2008-04-30 15:41:54 +00:00
|
|
|
}
|
|
|
|
|
|
2011-11-12 19:08:16 +00:00
|
|
|
int ViewEdgeXBuilder::retrieveFaceMarks(WXEdge *iEdge)
|
|
|
|
|
{
|
2013-01-02 01:55:30 +00:00
|
|
|
WFace *aFace = iEdge->GetaFace();
|
|
|
|
|
WFace *bFace = iEdge->GetbFace();
|
|
|
|
|
int result = 0;
|
2019-05-31 22:51:19 +10:00
|
|
|
if (aFace && aFace->GetMark()) {
|
2013-01-02 01:55:30 +00:00
|
|
|
result += 1;
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
|
|
|
|
if (bFace && bFace->GetMark()) {
|
2013-01-02 01:55:30 +00:00
|
|
|
result += 2;
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2013-01-02 01:55:30 +00:00
|
|
|
return result;
|
2011-11-12 19:08:16 +00:00
|
|
|
}
|
|
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
OWXEdge ViewEdgeXBuilder::FindNextWEdge(const OWXEdge &iEdge)
|
|
|
|
|
{
|
2019-05-31 22:51:19 +10:00
|
|
|
if (Nature::NO_FEATURE == iEdge.e->nature()) {
|
2020-11-06 17:49:09 +01:00
|
|
|
return OWXEdge(nullptr, true);
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
WVertex *v;
|
2019-05-31 22:51:19 +10:00
|
|
|
if (true == iEdge.order) {
|
2013-01-02 01:55:30 +00:00
|
|
|
v = iEdge.e->GetbVertex();
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2013-01-02 01:55:30 +00:00
|
|
|
v = iEdge.e->GetaVertex();
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-31 22:51:19 +10:00
|
|
|
if (((WXVertex *)v)->isFeature()) {
|
2023-08-01 21:15:52 +10:00
|
|
|
return nullptr; /* XXX eeek? nullptr? OWXEdge(nullptr, true/false)? */
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
int faceMarks = retrieveFaceMarks(iEdge.e);
|
|
|
|
|
vector<WEdge *> &vEdges = (v)->GetEdges();
|
|
|
|
|
for (vector<WEdge *>::iterator ve = vEdges.begin(), veend = vEdges.end(); ve != veend; ve++) {
|
|
|
|
|
WXEdge *wxe = dynamic_cast<WXEdge *>(*ve);
|
2019-05-31 22:51:19 +10:00
|
|
|
if (wxe == iEdge.e) {
|
2013-01-02 01:55:30 +00:00
|
|
|
continue; // same edge as the one processed
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-31 22:51:19 +10:00
|
|
|
if (wxe->nature() != iEdge.e->nature()) {
|
2013-01-02 01:55:30 +00:00
|
|
|
continue;
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
// check face mark continuity
|
2019-05-31 22:51:19 +10:00
|
|
|
if (retrieveFaceMarks(wxe) != faceMarks) {
|
2013-01-02 01:55:30 +00:00
|
|
|
continue;
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
if (wxe->GetaVertex() == v) {
|
2019-07-31 14:25:09 +02:00
|
|
|
// That means that the face necessarily lies on the edge left.
|
2013-01-02 01:55:30 +00:00
|
|
|
// So the vertex order is OK.
|
|
|
|
|
return OWXEdge(wxe, true);
|
|
|
|
|
}
|
2020-08-07 12:39:05 +02:00
|
|
|
|
|
|
|
|
// That means that the face necessarily lies on the edge left.
|
|
|
|
|
// So the vertex order is OK.
|
|
|
|
|
return OWXEdge(wxe, false);
|
2013-01-02 01:55:30 +00:00
|
|
|
}
|
|
|
|
|
// we did not find:
|
2020-11-06 17:49:09 +01:00
|
|
|
return OWXEdge(nullptr, true);
|
2008-04-30 15:41:54 +00:00
|
|
|
}
|
|
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
OWXEdge ViewEdgeXBuilder::FindPreviousWEdge(const OWXEdge &iEdge)
|
|
|
|
|
{
|
2019-05-31 22:51:19 +10:00
|
|
|
if (Nature::NO_FEATURE == iEdge.e->nature()) {
|
2020-11-06 17:49:09 +01:00
|
|
|
return OWXEdge(nullptr, true);
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
WVertex *v;
|
2019-05-31 22:51:19 +10:00
|
|
|
if (true == iEdge.order) {
|
2013-01-02 01:55:30 +00:00
|
|
|
v = iEdge.e->GetaVertex();
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2013-01-02 01:55:30 +00:00
|
|
|
v = iEdge.e->GetbVertex();
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-31 22:51:19 +10:00
|
|
|
if (((WXVertex *)v)->isFeature()) {
|
2020-11-06 17:49:09 +01:00
|
|
|
return nullptr;
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
int faceMarks = retrieveFaceMarks(iEdge.e);
|
2013-03-11 06:56:51 +00:00
|
|
|
vector<WEdge *> &vEdges = (v)->GetEdges();
|
|
|
|
|
for (vector<WEdge *>::iterator ve = vEdges.begin(), veend = vEdges.end(); ve != veend; ve++) {
|
|
|
|
|
WXEdge *wxe = dynamic_cast<WXEdge *>(*ve);
|
2019-05-31 22:51:19 +10:00
|
|
|
if (wxe == iEdge.e) {
|
2013-01-02 01:55:30 +00:00
|
|
|
continue; // same edge as the one processed
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-31 22:51:19 +10:00
|
|
|
if (wxe->nature() != iEdge.e->nature()) {
|
2013-01-02 01:55:30 +00:00
|
|
|
continue;
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
// check face mark continuity
|
2019-05-31 22:51:19 +10:00
|
|
|
if (retrieveFaceMarks(wxe) != faceMarks) {
|
2013-01-02 01:55:30 +00:00
|
|
|
continue;
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
if (wxe->GetbVertex() == v) {
|
|
|
|
|
return OWXEdge(wxe, true);
|
|
|
|
|
}
|
2020-08-07 12:39:05 +02:00
|
|
|
|
|
|
|
|
return OWXEdge(wxe, false);
|
2013-01-02 01:55:30 +00:00
|
|
|
}
|
|
|
|
|
// we did not find:
|
2020-11-06 17:49:09 +01:00
|
|
|
return OWXEdge(nullptr, true);
|
2008-04-30 15:41:54 +00:00
|
|
|
}
|
|
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
FEdge *ViewEdgeXBuilder::BuildSharpFEdge(FEdge *feprevious, const OWXEdge &iwe)
|
|
|
|
|
{
|
|
|
|
|
SVertex *va, *vb;
|
|
|
|
|
FEdgeSharp *fe;
|
2015-06-27 22:07:51 +09:00
|
|
|
Vec3r vA, vB;
|
2013-01-02 01:55:30 +00:00
|
|
|
if (iwe.order) {
|
2015-06-27 22:07:51 +09:00
|
|
|
vA = iwe.e->GetaVertex()->GetVertex();
|
|
|
|
|
vB = iwe.e->GetbVertex()->GetVertex();
|
2013-01-02 01:55:30 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2015-06-27 22:07:51 +09:00
|
|
|
vA = iwe.e->GetbVertex()->GetVertex();
|
|
|
|
|
vB = iwe.e->GetaVertex()->GetVertex();
|
2013-01-02 01:55:30 +00:00
|
|
|
}
|
|
|
|
|
// Make the 2 SVertex
|
2015-06-27 22:07:51 +09:00
|
|
|
va = MakeSVertex(vA, true);
|
|
|
|
|
vb = MakeSVertex(vB, true);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
// get the faces normals and the material indices
|
|
|
|
|
Vec3r normalA, normalB;
|
2022-09-26 10:04:44 +10:00
|
|
|
uint matA(0), matB(0);
|
2013-01-02 01:55:30 +00:00
|
|
|
bool faceMarkA = false, faceMarkB = false;
|
|
|
|
|
if (iwe.order) {
|
2022-10-07 22:52:53 +11:00
|
|
|
normalB = iwe.e->GetbFace()->GetNormal();
|
|
|
|
|
matB = iwe.e->GetbFace()->frs_materialIndex();
|
|
|
|
|
faceMarkB = iwe.e->GetbFace()->GetMark();
|
2013-01-02 01:55:30 +00:00
|
|
|
if (!(iwe.e->nature() & Nature::BORDER)) {
|
2022-10-07 22:52:53 +11:00
|
|
|
normalA = iwe.e->GetaFace()->GetNormal();
|
|
|
|
|
matA = iwe.e->GetaFace()->frs_materialIndex();
|
|
|
|
|
faceMarkA = iwe.e->GetaFace()->GetMark();
|
2013-01-02 01:55:30 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2022-10-07 22:52:53 +11:00
|
|
|
normalA = iwe.e->GetbFace()->GetNormal();
|
|
|
|
|
matA = iwe.e->GetbFace()->frs_materialIndex();
|
|
|
|
|
faceMarkA = iwe.e->GetbFace()->GetMark();
|
2013-01-02 01:55:30 +00:00
|
|
|
if (!(iwe.e->nature() & Nature::BORDER)) {
|
2022-10-07 22:52:53 +11:00
|
|
|
normalB = iwe.e->GetaFace()->GetNormal();
|
|
|
|
|
matB = iwe.e->GetaFace()->frs_materialIndex();
|
|
|
|
|
faceMarkB = iwe.e->GetaFace()->GetMark();
|
2013-01-02 01:55:30 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Creates the corresponding feature edge
|
|
|
|
|
fe = new FEdgeSharp(va, vb);
|
|
|
|
|
fe->setNature(iwe.e->nature());
|
|
|
|
|
fe->setId(_currentFId);
|
|
|
|
|
fe->setaFrsMaterialIndex(matA);
|
|
|
|
|
fe->setbFrsMaterialIndex(matB);
|
|
|
|
|
fe->setaFaceMark(faceMarkA);
|
|
|
|
|
fe->setbFaceMark(faceMarkB);
|
|
|
|
|
fe->setNormalA(normalA);
|
|
|
|
|
fe->setNormalB(normalB);
|
|
|
|
|
fe->setPreviousEdge(feprevious);
|
2019-05-31 22:51:19 +10:00
|
|
|
if (feprevious) {
|
2013-01-02 01:55:30 +00:00
|
|
|
feprevious->setNextEdge(fe);
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2013-01-02 01:55:30 +00:00
|
|
|
_pCurrentSShape->AddEdge(fe);
|
|
|
|
|
va->AddFEdge(fe);
|
|
|
|
|
vb->AddFEdge(fe);
|
2019-04-30 17:50:57 +10:00
|
|
|
// Add normals:
|
2013-01-02 01:55:30 +00:00
|
|
|
va->AddNormal(normalA);
|
|
|
|
|
va->AddNormal(normalB);
|
|
|
|
|
vb->AddNormal(normalA);
|
|
|
|
|
vb->AddNormal(normalB);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
++_currentFId;
|
|
|
|
|
iwe.e->userdata = fe;
|
|
|
|
|
return fe;
|
2008-04-30 15:41:54 +00:00
|
|
|
}
|
|
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
bool ViewEdgeXBuilder::stopSharpViewEdge(WXEdge *iEdge)
|
|
|
|
|
{
|
2020-11-06 17:49:09 +01:00
|
|
|
if (nullptr == iEdge) {
|
2013-01-02 01:55:30 +00:00
|
|
|
return true;
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2020-11-06 17:49:09 +01:00
|
|
|
if (iEdge->userdata == nullptr) {
|
2013-01-02 01:55:30 +00:00
|
|
|
return false;
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2013-01-02 01:55:30 +00:00
|
|
|
return true;
|
2008-04-30 15:41:54 +00:00
|
|
|
}
|
|
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
SVertex *ViewEdgeXBuilder::MakeSVertex(Vec3r &iPoint)
|
|
|
|
|
{
|
|
|
|
|
SVertex *va = new SVertex(iPoint, _currentSVertexId);
|
|
|
|
|
SilhouetteGeomEngine::ProjectSilhouette(va);
|
|
|
|
|
++_currentSVertexId;
|
|
|
|
|
// Add the svertex to the SShape svertex list:
|
|
|
|
|
_pCurrentSShape->AddNewVertex(va);
|
|
|
|
|
return va;
|
Stability improvements for the Face Smoothness option.
The instability considered here is due to a persistent failure of the
getFEdge() method in the Interface0D class and its subclasses in the
presence of smooth FEdges. When the Face Smoothness option is
enabled, the view map is populated with not only sharp FEdges (i.e.,
edges in the original meshes) but also smooth FEdges (i.e., newly
built edges lying on triangular surfaces). The failure of getFEdge()
caused many related issues because the method is widely used in other
predicates and functions that rely on it. The most prominent example
of related user-visible problems is a constant failure of the built-in
MaterialF0D.
The main issue and related problems were addressed as follows:
* A bug in the construction of smooth FEdges was fixed. Individual
smooth FEdges, even when they were detected as a series of smooth
FEdges that constitute one smooth ViewEdge, may have some irregular
geometry in the form of non-uniform OWXFaceLayer::order values. The
OWXFaceLayer::order values were used in an inappropriate way, so that
resulting smooth ViewEdges may have an FEdge between two subsequent
SVertices that were indeed the same SVertex object. This was an
unexpected situation that getFEdge() could not handle.
* Another issue in the construction of smooth FEdges was resolved.
When sharp FEdges are constructed, two SVertices at both ends of an
FEdge are generated only when no SVertex exists in a given 3D position
(this way, the original mesh topology is reconstructed from a bunch of
independent triangles that the BlenderFileLoader class passes to the
view map creation process). This sharing of SVertices was used also
for the generation of SVertices at the two ends of each smooth FEdge,
causing the getFEdge() failure in the presence of smooth FEdges. The
workaround implemented here is to simply suppress the sharing of
generated SVertices when smooth FEdges are created.
* In the Parameter Editor mode, the built-in MaterialF0D was replaced
with a better implementation that works well with Curves and Strokes.
MaterialF0D does not work with these 1D data types.
2011-10-10 19:57:06 +00:00
|
|
|
}
|
|
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
SVertex *ViewEdgeXBuilder::MakeSVertex(Vec3r &iPoint, bool shared)
|
|
|
|
|
{
|
|
|
|
|
SVertex *va;
|
|
|
|
|
if (!shared) {
|
|
|
|
|
va = MakeSVertex(iPoint);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// Check whether the iPoint is already in the table
|
|
|
|
|
SVertexMap::const_iterator found = _SVertexMap.find(iPoint);
|
|
|
|
|
if (shared && found != _SVertexMap.end()) {
|
|
|
|
|
va = (*found).second;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
va = MakeSVertex(iPoint);
|
|
|
|
|
// Add the svertex into the table using iPoint as the key
|
|
|
|
|
_SVertexMap[iPoint] = va;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return va;
|
2008-04-30 15:41:54 +00:00
|
|
|
}
|
|
|
|
|
|
2013-01-02 01:55:30 +00:00
|
|
|
ViewVertex *ViewEdgeXBuilder::MakeViewVertex(SVertex *iSVertex)
|
|
|
|
|
{
|
|
|
|
|
ViewVertex *vva = iSVertex->viewvertex();
|
2019-05-31 22:51:19 +10:00
|
|
|
if (vva) {
|
2013-01-02 01:55:30 +00:00
|
|
|
return vva;
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2013-01-02 01:55:30 +00:00
|
|
|
vva = new NonTVertex(iSVertex);
|
|
|
|
|
// Add the view vertex to the ViewShape svertex list:
|
|
|
|
|
_pCurrentVShape->AddVertex(vva);
|
|
|
|
|
return vva;
|
2008-04-30 15:41:54 +00:00
|
|
|
}
|
2013-04-09 00:46:49 +00:00
|
|
|
|
|
|
|
|
} /* namespace Freestyle */
|