Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
CGoGN
CGoGN
Commits
7f4059ea
Commit
7f4059ea
authored
Nov 08, 2011
by
Thomas
Browse files
qq modif gcarte et ajout exemple 3carte
parent
73b5f3f3
Changes
10
Hide whitespace changes
Inline
Side-by-side
Apps/Examples/Debug/CMakeLists.txt
View file @
7f4059ea
...
...
@@ -54,6 +54,11 @@ add_executable( texturesExampleD ../texturesExample.cpp ${texturesExample_moc} )
target_link_libraries
(
texturesExampleD
${
CGoGN_LIBS_D
}
${
COMMON_LIBS
}
${
QT_LIBRARIES
}
)
QT4_WRAP_CPP
(
simpleMap3_moc ../simpleMap3.h
)
add_executable
(
simpleMap3D ../simpleMap3.cpp
${
simpleMap3_moc
}
)
target_link_libraries
(
simpleMap3D
${
CGoGN_LIBS_D
}
${
COMMON_LIBS
}
${
QT_LIBRARIES
}
)
QT4_WRAP_CPP
(
simpleGMap2_moc ../simpleGMap2.h
)
add_executable
(
simpleGMap2D ../simpleGMap2.cpp
${
simpleGMap2_moc
}
)
target_link_libraries
(
simpleGMap2D
...
...
Apps/Examples/simpleGMap3.cpp
View file @
7f4059ea
...
...
@@ -34,11 +34,21 @@ SimpleGMap3::SimpleGMap3()
position
=
myMap
.
addAttribute
<
PFP
::
VEC3
>
(
VERTEX
,
"position"
);
Algo
::
Modelisation
::
Primitive3D
<
PFP
>
primCat
(
myMap
,
position
);
Dart
d
=
primCat
.
hexaGrid_topo
(
2
,
2
,
2
);
Dart
d
=
primCat
.
hexaGrid_topo
(
2
,
1
,
1
);
primCat
.
embedHexaGrid
(
1
,
1
,
1
);
myMap
.
check
();
// DartMarker markOrient(myMap);
// std::vector<Dart> orient;
// FunctorStore fs(orient);
// myMap.foreach_dart_of_oriented_volume(d,fs);
//
// for(std::vector<Dart>::iterator it = orient.begin() ; it != orient.end() ; ++it)
// markOrient.mark(*it);
//
// SelectorMarked sm(markOrient);
Algo
::
Modelisation
::
catmullClarkVol
<
PFP
,
PFP
::
TVEC3
,
PFP
::
VEC3
>
(
myMap
,
position
);
for
(
unsigned
int
i
=
position
.
begin
()
;
i
!=
position
.
end
()
;
position
.
next
(
i
))
...
...
@@ -67,14 +77,14 @@ SimpleGMap3::SimpleGMap3()
myMap
.
check
();
//
Algo::Modelisation::Primitive3D<PFP> prim2(myMap,position);
//
d = prim2.hexaGrid_topo(2,1,1);
//
prim2.embedHexaGrid(1,1,1);
//
//
d = myMap.phi2(myMap.phi1(myMap.phi1(myMap.phi2(d))));
//
myMap.unsewVolumes(d);
//
//
myMap.check();
Algo
::
Modelisation
::
Primitive3D
<
PFP
>
prim2
(
myMap
,
position
);
d
=
prim2
.
hexaGrid_topo
(
2
,
1
,
1
);
prim2
.
embedHexaGrid
(
1
,
1
,
1
);
d
=
myMap
.
phi2
(
myMap
.
phi1
(
myMap
.
phi1
(
myMap
.
phi2
(
d
))));
myMap
.
unsewVolumes
(
d
);
myMap
.
check
();
}
void
SimpleGMap3
::
initGUI
()
...
...
Apps/Examples/simpleMap3.cpp
0 → 100644
View file @
7f4059ea
/*******************************************************************************
* CGoGN: Combinatorial and Geometric modeling with Generic N-dimensional Maps *
* version 0.1 *
* Copyright (C) 2009, IGG Team, LSIIT, University of Strasbourg *
* *
* This library is free software; you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, or (at your *
* option) any later version. *
* *
* This library is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
* for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this library; if not, write to the Free Software Foundation, *
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
* *
* Web site: https://iggservis.u-strasbg.fr/CGoGN/ *
* Contact information: cgogn@unistra.fr *
* *
*******************************************************************************/
#include
"simpleMap3.h"
#include
"Utils/GLSLShader.h"
#include
"Algo/Geometry/boundingbox.h"
#include
"Algo/Modelisation/primitives3d.h"
#include
"Algo/Modelisation/subdivision3map.h"
SimpleMap3
::
SimpleMap3
()
{
position
=
myMap
.
addAttribute
<
PFP
::
VEC3
>
(
VERTEX
,
"position"
);
Algo
::
Modelisation
::
Primitive3D
<
PFP
>
primCat
(
myMap
,
position
);
Dart
d
=
primCat
.
hexaGrid_topo
(
2
,
1
,
1
);
primCat
.
embedHexaGrid
(
1
,
1
,
1
);
unsigned
int
nb
=
0
;
for
(
unsigned
int
i
=
position
.
begin
();
i
!=
position
.
end
();
position
.
next
(
i
))
nb
++
;
std
::
cout
<<
"Nb vertices (equals 12) : "
<<
nb
<<
std
::
endl
;
assert
(
nb
==
12
);
d
=
myMap
.
phi2
(
myMap
.
phi1
(
myMap
.
phi1
(
myMap
.
phi2
(
d
))));
Dart
dd
=
myMap
.
phi3
(
d
);
myMap
.
unsewVolumes
(
d
);
myMap
.
check
();
nb
=
0
;
for
(
unsigned
int
i
=
position
.
begin
();
i
!=
position
.
end
();
position
.
next
(
i
))
nb
++
;
std
::
cout
<<
"Nb vertices after unsew (equals 16) : "
<<
nb
<<
std
::
endl
;
assert
(
nb
==
16
);
myMap
.
sewVolumes
(
d
,
dd
);
myMap
.
check
();
nb
=
0
;
for
(
unsigned
int
i
=
position
.
begin
();
i
!=
position
.
end
();
position
.
next
(
i
))
nb
++
;
std
::
cout
<<
"Nb vertices after resew (equals 12) : "
<<
nb
<<
std
::
endl
;
assert
(
nb
==
12
);
}
void
SimpleMap3
::
initGUI
()
{
}
void
SimpleMap3
::
cb_initGL
()
{
Utils
::
GLSLShader
::
setCurrentOGLVersion
(
1
)
;
Geom
::
BoundingBox
<
PFP
::
VEC3
>
bb
=
Algo
::
Geometry
::
computeBoundingBox
<
PFP
>
(
myMap
,
position
)
;
VEC3
gPosObj
=
bb
.
center
()
;
float
tailleX
=
bb
.
size
(
0
)
;
float
tailleY
=
bb
.
size
(
1
)
;
float
tailleZ
=
bb
.
size
(
2
)
;
float
gWidthObj
=
std
::
max
<
float
>
(
std
::
max
<
float
>
(
tailleX
,
tailleY
),
tailleZ
)
;
setParamObject
(
gWidthObj
,
gPosObj
.
data
());
}
void
SimpleMap3
::
cb_redraw
()
{
glDisable
(
GL_LIGHTING
);
glLineWidth
(
1.0
f
);
Algo
::
Render
::
GL1
::
renderTopoMD3
<
PFP
>
(
myMap
,
position
,
true
,
true
,
true
,
0.9
f
,
0.9
f
,
0.9
f
);
}
/**********************************************************************************************
* MAIN FUNCTION *
**********************************************************************************************/
int
main
(
int
argc
,
char
**
argv
)
{
QApplication
app
(
argc
,
argv
)
;
SimpleMap3
sqt
;
sqt
.
setGeometry
(
0
,
0
,
1000
,
800
)
;
sqt
.
show
()
;
sqt
.
initGUI
()
;
return
app
.
exec
()
;
}
Apps/Examples/simpleMap3.h
0 → 100644
View file @
7f4059ea
/*******************************************************************************
* CGoGN: Combinatorial and Geometric modeling with Generic N-dimensional Maps *
* version 0.1 *
* Copyright (C) 2009, IGG Team, LSIIT, University of Strasbourg *
* *
* This library is free software; you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, or (at your *
* option) any later version. *
* *
* This library is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
* for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this library; if not, write to the Free Software Foundation, *
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
* *
* Web site: https://iggservis.u-strasbg.fr/CGoGN/ *
* Contact information: cgogn@unistra.fr *
* *
*******************************************************************************/
#include
<iostream>
#include
"Utils/qtSimple.h"
#include
"Topology/generic/parameters.h"
#include
"Topology/map/embeddedMap3.h"
#include
"Geometry/vector_gen.h"
#include
"Algo/Render/GL1/topo_render.h"
using
namespace
CGoGN
;
struct
PFP
:
public
PFP_STANDARD
{
// definition of the map
typedef
EmbeddedMap3
MAP
;
};
typedef
PFP
::
MAP
MAP
;
typedef
PFP
::
VEC3
VEC3
;
class
SimpleMap3
:
public
Utils
::
QT
::
SimpleQT
{
Q_OBJECT
public:
MAP
myMap
;
SelectorTrue
allDarts
;
PFP
::
TVEC3
position
;
SimpleMap3
()
;
void
initGUI
()
;
void
cb_initGL
()
;
void
cb_redraw
()
;
};
Apps/Tuto/tuto5.cpp
View file @
7f4059ea
...
...
@@ -313,8 +313,6 @@ int main(int argc, char **argv)
CGoGNout
<<
"CGoGNOut dans la console"
<<
Geom
::
Vec3f
(
2.5
f
,
2.2
f
,
4.3
f
)
<<
CGoGNendl
;
CGoGNout
.
toStatusBar
(
NULL
);
CGoGNout
<<
"tirelipinpon .."
<<
CGoGNendl
;
CGoGNout
<<
"ah aha ah"
<<
CGoGNendl
;
// bounding box
Geom
::
BoundingBox
<
PFP
::
VEC3
>
bb
=
Algo
::
Geometry
::
computeBoundingBox
<
PFP
>
(
myMap
,
position
);
...
...
include/Algo/Modelisation/subdivision3map.hpp
View file @
7f4059ea
...
...
@@ -125,6 +125,7 @@ void catmullClarkVol(typename PFP::MAP& map, EMBV& attributs, const FunctorSelec
//memorize each vertices per volumes
if
(
selected
(
d
)
&&
!
mv
.
isMarked
(
d
))
{
std
::
cout
<<
" d "
<<
d
<<
std
::
endl
;
l_vertices
.
push_back
(
d
);
mv
.
markOrbitInParent
<
typename
PFP
::
MAP
>
(
VERTEX
,
d
);
}
...
...
@@ -156,6 +157,12 @@ void catmullClarkVol(typename PFP::MAP& map, EMBV& attributs, const FunctorSelec
}
}
unsigned
int
nb_
=
0
;
for
(
unsigned
int
nb
=
attributs
.
begin
()
;
nb
!=
attributs
.
end
()
;
attributs
.
next
(
nb
))
nb_
++
;
std
::
cout
<<
"first "
<<
nb_
<<
std
::
endl
;
// second pass: quandrangule faces
std
::
map
<
Dart
,
Dart
>
toSew
;
for
(
Dart
d
=
map
.
begin
();
d
!=
map
.
end
();
map
.
next
(
d
))
...
...
@@ -217,33 +224,39 @@ void catmullClarkVol(typename PFP::MAP& map, EMBV& attributs, const FunctorSelec
d
=
dN
;
}
while
(
*
it
!=
d
);
//close the generated hole and create the central vertex
unsigned
int
degree
=
map
.
closeHole
(
map
.
phi1
(
d
));
Dart
dd
=
map
.
phi1
(
map
.
phi2
(
map
.
phi1
(
d
)));
map
.
splitFace
(
map
.
phi_1
(
dd
),
map
.
phi1
(
dd
));
Dart
dS
=
map
.
phi1
(
dd
);
map
.
cutEdge
(
dS
);
attributs
[
map
.
phi1
(
dS
)]
=
attBary
[
d
];
//TODO : test with vertices with degree higher than 3
for
(
unsigned
int
i
=
0
;
i
<
(
degree
/
2
)
-
2
;
++
i
)
{
map
.
splitFace
(
map
.
phi2
(
dS
),
map
.
template
phi
<
111
>(
map
.
phi2
(
dS
)));
dS
=
map
.
template
phi
<
111
>(
map
.
phi2
(
dS
));
}
//
//close the generated hole and create the central vertex
//
unsigned int degree = map.closeHole(map.phi1(d));
//
//
Dart dd = map.phi1(map.phi2(map.phi1(d)));
//
map.splitFace(map.phi_1(dd),map.phi1(dd));
//
Dart dS = map.phi1(dd);
//
map.cutEdge(dS);
//
//
attributs[map.phi1(dS)] = attBary[d];
//
//
//TODO : test with vertices with degree higher than 3
//
for(unsigned int i=0; i < (degree/2)-2; ++i)
//
{
//
map.splitFace(map.phi2(dS),map.template phi<111>(map.phi2(dS)));
//
dS = map.template phi<111>(map.phi2(dS));
//
}
}
//sew all faces leading to the central vertex
for
(
std
::
map
<
Dart
,
Dart
>::
iterator
it
=
toSew
.
begin
();
it
!=
toSew
.
end
();
++
it
)
{
Dart
dT
=
map
.
phi2
(
it
->
first
);
if
(
dT
==
map
.
phi3
(
dT
))
{
map
.
sewVolumes
(
dT
,
map
.
phi2
(
it
->
second
));
}
}
nb_
=
0
;
for
(
unsigned
int
nb
=
attributs
.
begin
()
;
nb
!=
attributs
.
end
()
;
attributs
.
next
(
nb
))
nb_
++
;
std
::
cout
<<
"then "
<<
nb_
<<
std
::
endl
;
// //sew all faces leading to the central vertex
// for (std::map<Dart,Dart>::iterator it = toSew.begin(); it != toSew.end(); ++it)
// {
// Dart dT = map.phi2(it->first);
// if(dT==map.phi3(dT))
// {
// map.sewVolumes(dT,map.phi2(it->second));
// }
// }
}
}
//namespace Modelisation
...
...
include/Topology/gmap/gmap3.h
View file @
7f4059ea
...
...
@@ -215,6 +215,11 @@ public:
virtual
bool
check
();
/**
*
*/
virtual
bool
isBoundaryVertex
(
Dart
d
);
/*! @name Cell Functors
* Apply functors to all darts of a cell
*************************************************************************/
...
...
src/Topology/gmap/embeddedGMap2.cpp
View file @
7f4059ea
...
...
@@ -323,44 +323,31 @@ void EmbeddedGMap2::sewFaces(Dart d, Dart e)
void
EmbeddedGMap2
::
unsewFaces
(
Dart
d
)
{
bool
boundaryD
=
false
;
bool
boundaryE
=
false
;
if
(
isOrbitEmbedded
(
VERTEX
))
{
if
(
isBoundaryVertex
(
d
))
boundaryD
=
true
;
if
(
isBoundaryVertex
(
phi1
(
d
)))
boundaryE
=
true
;
}
Dart
e
=
phi2
(
d
)
;
GMap2
::
unsewFaces
(
d
)
;
Dart
e
=
beta2
(
d
);
GMap2
::
unsewFaces
(
d
);
if
(
isOrbitEmbedded
(
VERTEX
))
{
if
(
boundaryD
)
if
(
!
sameVertex
(
d
,
e
)
)
{
if
(
e
!=
d
)
{
Dart
ee
=
phi1
(
e
)
;
embedNewCell
(
VERTEX
,
ee
)
;
copyCell
(
VERTEX
,
ee
,
d
)
;
}
embedNewCell
(
VERTEX
,
e
);
copyCell
(
VERTEX
,
e
,
d
);
}
if
(
boundaryE
)
d
=
beta0
(
d
);
e
=
beta0
(
e
);
if
(
!
sameVertex
(
d
,
e
))
{
if
(
e
!=
d
)
{
embedNewCell
(
VERTEX
,
e
)
;
copyCell
(
VERTEX
,
e
,
phi1
(
d
))
;
}
embedNewCell
(
VERTEX
,
e
);
copyCell
(
VERTEX
,
e
,
d
);
}
}
if
(
isOrbitEmbedded
(
EDGE
))
{
embedNewCell
(
EDGE
,
e
)
;
copyCell
(
EDGE
,
e
,
d
)
;
embedNewCell
(
EDGE
,
e
);
copyCell
(
EDGE
,
e
,
d
);
}
}
...
...
src/Topology/gmap/embeddedGMap3.cpp
View file @
7f4059ea
...
...
@@ -96,7 +96,7 @@ void EmbeddedGMap3::unsewVolumes(Dart d)
if
(
!
sameEdge
(
ddd
,
dd
))
{
embedNewCell
(
EDGE
,
dd
);
copyCell
(
VERTEX
,
dd
,
ddd
);
copyCell
(
EDGE
,
dd
,
ddd
);
}
}
...
...
@@ -224,9 +224,9 @@ void EmbeddedGMap3::cutEdge(Dart d)
{
Dart
nd
=
phi1
(
f
);
copyDartEmbedding
(
VOLUME
,
nd
,
f
);
copyDartEmbedding
(
VOLUME
,
beta
0
(
nd
),
f
);
copyDartEmbedding
(
VOLUME
,
beta
1
(
nd
),
f
);
copyDartEmbedding
(
VOLUME
,
beta2
(
nd
),
f
);
copyDartEmbedding
(
VOLUME
,
beta
3
(
nd
),
f
);
copyDartEmbedding
(
VOLUME
,
beta
1
(
beta2
(
nd
)
)
,
f
);
// Dart nd2 = beta2(nd);
// if(f!=nd2)
...
...
@@ -322,19 +322,19 @@ bool EmbeddedGMap3::check()
{
if
(
getEmbedding
(
VERTEX
,
d
)
!=
getEmbedding
(
VERTEX
,
beta1
(
d
)))
{
CGoGNout
<<
"Check: different embeddings on vertex"
<<
CGoGNendl
;
CGoGNout
<<
"Check: different embeddings on vertex
(1)
"
<<
CGoGNendl
;
return
false
;
}
if
(
getEmbedding
(
VERTEX
,
d
)
!=
getEmbedding
(
VERTEX
,
beta2
(
d
)))
{
CGoGNout
<<
"Check: different embeddings on vertex"
<<
CGoGNendl
;
CGoGNout
<<
"Check: different embeddings on vertex
(2)
"
<<
CGoGNendl
;
return
false
;
}
if
(
getEmbedding
(
VERTEX
,
d
)
!=
getEmbedding
(
VERTEX
,
beta3
(
d
)))
{
CGoGNout
<<
"Check: different embeddings on vertex"
<<
CGoGNendl
;
CGoGNout
<<
"Check: different embeddings on vertex
(3)
"
<<
CGoGNendl
;
return
false
;
}
}
...
...
@@ -343,19 +343,19 @@ bool EmbeddedGMap3::check()
{
if
(
getEmbedding
(
EDGE
,
d
)
!=
getEmbedding
(
EDGE
,
beta0
(
d
)))
{
CGoGNout
<<
"Check: different embeddings on edge"
<<
CGoGNendl
;
CGoGNout
<<
"Check: different embeddings on edge
(0)
"
<<
CGoGNendl
;
return
false
;
}
if
(
getEmbedding
(
EDGE
,
d
)
!=
getEmbedding
(
EDGE
,
beta2
(
d
)))
{
CGoGNout
<<
"Check: different embeddings on edge"
<<
CGoGNendl
;
CGoGNout
<<
"Check: different embeddings on edge
(1)
"
<<
CGoGNendl
;
return
false
;
}
if
(
getEmbedding
(
EDGE
,
d
)
!=
getEmbedding
(
EDGE
,
beta3
(
d
)))
{
CGoGNout
<<
"Check: different embeddings on edge"
<<
CGoGNendl
;
CGoGNout
<<
"Check: different embeddings on edge
(2)
"
<<
CGoGNendl
;
return
false
;
}
}
...
...
@@ -364,13 +364,13 @@ bool EmbeddedGMap3::check()
{
if
(
getEmbedding
(
FACE
,
d
)
!=
getEmbedding
(
FACE
,
beta0
(
d
)))
{
CGoGNout
<<
"Check: different embeddings on face"
<<
CGoGNendl
;
CGoGNout
<<
"Check: different embeddings on face
(0)
"
<<
CGoGNendl
;
return
false
;
}
if
(
getEmbedding
(
FACE
,
d
)
!=
getEmbedding
(
FACE
,
beta1
(
d
)))
{
CGoGNout
<<
"Check: different embeddings on face"
<<
CGoGNendl
;
CGoGNout
<<
"Check: different embeddings on face
(1)
"
<<
CGoGNendl
;
return
false
;
}
}
...
...
@@ -379,19 +379,19 @@ bool EmbeddedGMap3::check()
{
if
(
getEmbedding
(
VOLUME
,
d
)
!=
getEmbedding
(
VOLUME
,
beta0
(
d
)))
{
CGoGNout
<<
"Check: different embeddings in volume"
<<
CGoGNendl
;
CGoGNout
<<
"Check: different embeddings in volume
(0)
"
<<
CGoGNendl
;
return
false
;
}
if
(
getEmbedding
(
VOLUME
,
d
)
!=
getEmbedding
(
VOLUME
,
beta1
(
d
)))
{
CGoGNout
<<
"Check: different embeddings in volume"
<<
CGoGNendl
;
CGoGNout
<<
"Check: different embeddings in volume
(1)
"
<<
CGoGNendl
;
return
false
;
}
if
(
getEmbedding
(
VOLUME
,
d
)
!=
getEmbedding
(
VOLUME
,
beta2
(
d
)))
{
CGoGNout
<<
"Check: different embeddings in volume"
<<
CGoGNendl
;
CGoGNout
<<
"Check: different embeddings in volume
(2)
"
<<
CGoGNendl
;
return
false
;
}
}
...
...
src/Topology/gmap/gmap3.cpp
View file @
7f4059ea
...
...
@@ -587,6 +587,44 @@ bool GMap3::check()
return
true
;
}
bool
GMap3
::
isBoundaryVertex
(
Dart
d
)
{
DartMarkerStore
mv
(
*
this
);
// Lock a marker
bool
found
=
false
;
// Last functor return value
std
::
list
<
Dart
>
darts_list
;
//Darts that are traversed
darts_list
.
push_back
(
d
);
//Start with the dart d
std
::
list
<
Dart
>::
iterator
darts
;
mv
.
mark
(
d
);
for
(
darts
=
darts_list
.
begin
();
!
found
&&
darts
!=
darts_list
.
end
()
;
++
darts
)
{
Dart
dc
=
*
darts
;
//add phi21 and phi23 successor if they are not marked yet
Dart
d2
=
phi2
(
dc
);
Dart
d21
=
phi1
(
d2
);
// turn in volume
Dart
d23
=
phi3
(
d2
);
// change volume
if
(
!
mv
.
isMarked
(
d21
))
{
darts_list
.
push_back
(
d21
);
mv
.
mark
(
d21
);
}
if
((
d23
!=
d2
)
&&
!
mv
.
isMarked
(
d23
))
{
darts_list
.
push_back
(
d23
);
mv
.
mark
(
d23
);
}
found
=
phi3
(
dc
)
==
dc
;
}
return
found
;
}
/*! @name Cell Functors
* Apply functors to all darts of a cell
*************************************************************************/
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment