Closed luogyong closed 2 years ago
Hi @luogyong, sorry for not seeing your post before now! The problem you're having is that your in
object is not constructed when you call %initialize
. To allocate an object wrapped by SWIG-Fortran, you must construct it:
type(tetgenio):: in
in = tetgenio()
Since your constructor calls initialize
as a side effect, you do not need to call in%initialize
after that.
To use nested classes natively, you can use the flatnested
feature of SWIG:
%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Class::NestedClass;
%feature("flatnested") Class::NestedClass;
%rename(MyNestedClass) Class::NestedClass;
Hi @luogyong, sorry for not seeing your post before now! The problem you're having is that your
in
object is not constructed when you call%initialize
. To allocate an object wrapped by SWIG-Fortran, you must construct it:type(tetgenio):: in in = tetgenio()
Since your constructor calls
initialize
as a side effect, you do not need to callin%initialize
after that.To use nested classes natively, you can use the
flatnested
feature of SWIG:%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Class::NestedClass; %feature("flatnested") Class::NestedClass; %rename(MyNestedClass) Class::NestedClass;
It works. Thank you very much. @sethrj
Hi, @sethrj , I run into another problem. I don't know how to prepare data passed to C++ from Fortran. The Swig-Fortran seems hide many variables in swigdata class. For example, a class tetgenio,
class tetgenio {
public:
typedef struct {
int *vertexlist;
int numberofvertices;
} polygon;
typedef struct {
polygon *polygonlist;
int numberofpolygons;
REAL *holelist;
int numberofholes;
} facet;
int numberoffacets;
facet *facetlist;
}; // class tetgenio
was translate into a fortran class as something like this,
//......
type, bind(C) :: SwigClassWrapper
type(C_PTR), public :: cptr = C_NULL_PTR
integer(C_INT), public :: cmemflags = 0
end type
type, public :: SWIGTYPE_p_tetgenio__facet
type(SwigClassWrapper), public :: swigdata
end type
public :: SWIGTYPE_f_p_void_int_int__double
public :: SWIGTYPE_f_p_void_int_double_p_double__void
public :: SWIGTYPE_f_p_void_int_int_p_double__void
public :: SWIGTYPE_f_p_void_int_double_int_p_double__void
public :: SWIGTYPE_f_p_void_int_p_double_p_double__void
public :: SWIGTYPE_f_p_double_p_double_p_double_p_double_p_double_doE5JNE
type, bind(C) :: SwigArrayWrapper
type(C_PTR), public :: data = C_NULL_PTR
integer(C_SIZE_T), public :: size = 0
end type
type, public :: SWIGTYPE_p_tetgenio__polygon
type(SwigClassWrapper), public :: swigdata
end type
type, public :: tetgenio
type(SwigClassWrapper), public :: swigdata
contains
procedure :: set_facetlist => swigf_tetgenio_facetlist_set
procedure :: get_facetlist => swigf_tetgenio_facetlist_get
//......
end type tetgenio
subroutine swigf_tetgenio_facetlist_set(self, facetlist)
use, intrinsic :: ISO_C_BINDING
class(tetgenio), intent(in) :: self
class(SWIGTYPE_p_tetgenio__facet), intent(in) :: facetlist
type(SwigClassWrapper) :: farg1
type(SwigClassWrapper) :: farg2
farg1 = self%swigdata
farg2 = facetlist%swigdata
call swigc_tetgenio_facetlist_set(farg1, farg2)
end subroutine
function swigf_tetgenio_facetlist_get(self) &
result(swig_result)
use, intrinsic :: ISO_C_BINDING
type(SWIGTYPE_p_tetgenio__facet) :: swig_result
class(tetgenio), intent(in) :: self
type(SwigClassWrapper) :: fresult
type(SwigClassWrapper) :: farg1
farg1 = self%swigdata
fresult = swigc_tetgenio_facetlist_get(farg1)
swig_result%swigdata = fresult
end function
//...
My problem is I don't how to prepare a facelist array data passed to subroutine swigc_tetgenio_facetlist_set. That is, I don't know how to tranlate the following C++ code into SWIGTYPE_p_tetgenio__facet type ffacelist.
//......
tetgenio in, out;
tetgenio::facet *f;
tetgenio::polygon *p;
in.numberoffacets = 6;
in.facetlist = new tetgenio::facet[in.numberoffacets];
in.facetmarkerlist = new int[in.numberoffacets];
// Facet 1. The leftmost facet.
f = &in.facetlist[0];
f->numberofpolygons = 1;
f->polygonlist = new tetgenio::polygon[f->numberofpolygons];
f->numberofholes = 0;
f->holelist = NULL;
p = &f->polygonlist[0];
p->numberofvertices = 4;
p->vertexlist = new int[p->numberofvertices];
p->vertexlist[0] = 1;
p->vertexlist[1] = 2;
p->vertexlist[2] = 3;
p->vertexlist[3] = 4;
//...
So that, I can call the set subroutine
`call in.swigf_tetgenio_facetlist_set(ffacelist)`
Can you give me an example how to do it?
Thank you.
Yes, C arrays can be a little awkward with SWIG. You should be able to use the carrays feature to do this. SWIG-Fortran is targeted for two main use cases: low-level C-compatible types, and high-level object-oriented C++ types. The nested classes with manual memory management and pointer assignment in your class interface don't exactly match either category so will be a little harder to get working.
fortran_tetgen.zip
Hi, I tried to call tetgen from fortran but I failed. I passed the compilation and got the exe file. When I run the exe, I got the error message as follows:
*terminate called after throwing an instance of 'std::logic_error' what(): In tetgenio::initialize(): Cannot pass null tetgenio (class tetgenio) as a reference
Program received signal SIGABRT: Process abort signal.**
The file used was attached below. And the directives used are swig -c++ -fortran tetgen.i gcc -c tetgen.cxx -o tetgencxx.o -D "TETLIBRARY" gcc -c tetgen_wrap.cxx predicates.cxx gfortran -c tetgen.f90 ar cr tet.a
lorder tetgen.o tetgencxx.o tetgen_wrap.o predicates.o | tsort
gfortran -g main_tetgen.f90 tet.a -lstdc++ -o ftetgen.exeIn addition, since SWIG does not seem to support nesting of classes, in the interface file, I copy the nested class to the outside so that it can be compiled successfully. I don't know if this is the source of my problem.
Can any one help me out? Thank you.