use std::ffi::{CStr, CString};
use std::os::raw::{c_char, c_int};
use std::ptr;
use crate::bindings as ffi;
#[derive(Debug, Clone)]
pub struct GmshError {
message: String,
}
impl GmshError {
fn new(msg: String) -> Self {
Self { message: msg }
}
}
impl std::fmt::Display for GmshError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Gmsh error: {}", self.message)
}
}
impl std::error::Error for GmshError {}
#[macro_export]
macro_rules! check_err {
($call:expr) => {{
let mut ierr = 0;
let res = $call(&mut ierr);
if ierr == 0 {
Ok(res)
} else {
let msg = unsafe {
let mut err_ptr = std::ptr::null_mut();
ffi::gmshLoggerGetLastError(&mut err_ptr, std::ptr::null_mut());
if err_ptr.is_null() {
"unknown error".to_string()
} else {
std::ffi::CStr::from_ptr(err_ptr)
.to_string_lossy()
.into_owned()
}
};
Err(GmshError::new(msg))
}
}};
}
unsafe fn cstr_to_string_and_free(ptr: *mut c_char) -> String {
if ptr.is_null() {
return String::new();
}
let s = unsafe { CStr::from_ptr(ptr) }.to_string_lossy().into_owned();
unsafe { ffi::gmshFree(ptr as *mut _) };
s
}
unsafe fn cstr_array_to_vec_and_free(ptr: *mut *mut c_char, len: usize) -> Vec<String> {
let mut vec = Vec::with_capacity(len);
for i in 0..len {
let s_ptr = unsafe { *ptr.add(i) };
if !s_ptr.is_null() {
vec.push(unsafe { cstr_to_string_and_free(s_ptr) });
}
}
unsafe { ffi::gmshFree(ptr as *mut _) };
vec
}
fn to_cstring(s: &str) -> CString {
CString::new(s).expect("CString conversion failed")
}
fn dimtags_to_cvec(dimtags: &[(i32, i32)]) -> Vec<i32> {
let mut v = Vec::with_capacity(dimtags.len() * 2);
for &(dim, tag) in dimtags {
v.push(dim);
v.push(tag);
}
v
}
pub struct Gmsh;
impl Gmsh {
pub fn new(args: Vec<String>, read_config_files: bool, run: bool) -> Result<Self, GmshError> {
let mut c_args: Vec<CString> = args.into_iter().map(|s| to_cstring(&s)).collect();
let mut c_argv: Vec<*mut c_char> = c_args.iter_mut().map(|c| c.as_ptr() as *mut _).collect();
let argc = c_argv.len() as c_int;
let argv_ptr = if c_argv.is_empty() {
ptr::null_mut()
} else {
c_argv.as_mut_ptr()
};
unsafe {
check_err!(|ierr| {
ffi::gmshInitialize(
argc,
argv_ptr,
if read_config_files { 1 } else { 0 },
if run { 1 } else { 0 },
ierr,
)
})?;
}
Ok(Gmsh)
}
pub fn new_default() -> Result<Self, GmshError> {
Self::new(std::env::args().collect(), true, false)
}
pub fn finalize(self) -> Result<(), GmshError> {
unsafe {
check_err!(|ierr| ffi::gmshFinalize(ierr))?;
}
std::mem::forget(self);
Ok(())
}
pub fn add_model(&self, name: &str) -> Result<Model, GmshError> {
let c_name = to_cstring(name);
unsafe {
check_err!(|ierr| ffi::gmshModelAdd(c_name.as_ptr(), ierr))?;
}
Ok(Model { name: name.to_string() })
}
pub fn current_model(&self) -> Result<Model, GmshError> {
let mut name_ptr = ptr::null_mut();
unsafe {
check_err!(|ierr| ffi::gmshModelGetCurrent(&mut name_ptr, ierr))?;
let name = unsafe { cstr_to_string_and_free(name_ptr) };
Ok(Model { name })
}
}
pub fn set_current_model(&self, name: &str) -> Result<(), GmshError> {
let c_name = to_cstring(name);
unsafe {
check_err!(|ierr| ffi::gmshModelSetCurrent(c_name.as_ptr(), ierr))
}
}
pub fn list_models(&self) -> Result<Vec<String>, GmshError> {
let mut names_ptr = ptr::null_mut();
let mut names_n = 0;
unsafe {
check_err!(|ierr| ffi::gmshModelList(&mut names_ptr, &mut names_n, ierr))?;
Ok(unsafe { cstr_array_to_vec_and_free(names_ptr, names_n) })
}
}
pub fn remove_current_model(&self) -> Result<(), GmshError> {
unsafe { check_err!(|ierr| ffi::gmshModelRemove(ierr)) }
}
pub fn model_file_name(&self) -> Result<String, GmshError> {
let mut name_ptr = ptr::null_mut();
unsafe {
check_err!(|ierr| ffi::gmshModelGetFileName(&mut name_ptr, ierr))?;
Ok(unsafe { cstr_to_string_and_free(name_ptr) })
}
}
pub fn set_model_file_name(&self, name: &str) -> Result<(), GmshError> {
let c_name = to_cstring(name);
unsafe {
check_err!(|ierr| ffi::gmshModelSetFileName(c_name.as_ptr(), ierr))
}
}
}
impl Drop for Gmsh {
fn drop(&mut self) {
let _ = unsafe { ffi::gmshFinalize(ptr::null_mut()) };
}
}
pub struct Model {
name: String,
}
impl Model {
pub fn name(&self) -> &str {
&self.name
}
pub fn generate_mesh(&self, dim: i32) -> Result<(), GmshError> {
unsafe { check_err!(|ierr| ffi::gmshModelMeshGenerate(dim, ierr)) }
}
pub fn get_entities(&self, dim: i32) -> Result<Vec<(i32, i32)>, GmshError> {
let mut dimtags_ptr = ptr::null_mut();
let mut dimtags_n = 0;
unsafe {
check_err!(|ierr| {
ffi::gmshModelGetEntities(&mut dimtags_ptr, &mut dimtags_n, dim, ierr)
})?;
let mut entities = Vec::with_capacity(dimtags_n / 2);
for i in 0..(dimtags_n / 2) {
let d = *dimtags_ptr.add(i * 2);
let t = *dimtags_ptr.add(i * 2 + 1);
entities.push((d, t));
}
ffi::gmshFree(dimtags_ptr as *mut _);
Ok(entities)
}
}
pub fn get_entity_tags(&self, dim: i32) -> Result<Vec<i32>, GmshError> {
let entities = self.get_entities(dim)?;
Ok(entities.into_iter().map(|(_, tag)| tag).collect())
}
pub fn set_entity_name(&self, dim: i32, tag: i32, name: &str) -> Result<(), GmshError> {
let c_name = to_cstring(name);
unsafe {
check_err!(|ierr| ffi::gmshModelSetEntityName(dim, tag, c_name.as_ptr(), ierr))
}
}
pub fn get_entity_name(&self, dim: i32, tag: i32) -> Result<String, GmshError> {
let mut name_ptr = ptr::null_mut();
unsafe {
check_err!(|ierr| ffi::gmshModelGetEntityName(dim, tag, &mut name_ptr, ierr))?;
Ok(unsafe { cstr_to_string_and_free(name_ptr) })
}
}
pub fn add_physical_group(
&self,
dim: i32,
tags: &[i32],
tag: i32,
name: Option<&str>,
) -> Result<i32, GmshError> {
let c_name = name.map(to_cstring).unwrap_or_else(|| CString::new("").unwrap());
unsafe {
check_err!(|ierr| {
ffi::gmshModelAddPhysicalGroup(dim, tags.as_ptr(), tags.len(), tag, c_name.as_ptr(), ierr)
})
}
}
pub fn get_physical_groups(&self, dim: i32) -> Result<Vec<(i32, i32)>, GmshError> {
let mut dimtags_ptr = ptr::null_mut();
let mut dimtags_n = 0;
unsafe {
check_err!(|ierr| {
ffi::gmshModelGetPhysicalGroups(&mut dimtags_ptr, &mut dimtags_n, dim, ierr)
})?;
let mut groups = Vec::with_capacity(dimtags_n / 2);
for i in 0..(dimtags_n / 2) {
let d = *dimtags_ptr.add(i * 2);
let t = *dimtags_ptr.add(i * 2 + 1);
groups.push((d, t));
}
ffi::gmshFree(dimtags_ptr as *mut _);
Ok(groups)
}
}
pub fn get_entities_for_physical_group(&self, dim: i32, tag: i32) -> Result<Vec<i32>, GmshError> {
let mut tags_ptr = ptr::null_mut();
let mut tags_n = 0;
unsafe {
check_err!(|ierr| {
ffi::gmshModelGetEntitiesForPhysicalGroup(dim, tag, &mut tags_ptr, &mut tags_n, ierr)
})?;
let tags = std::slice::from_raw_parts(tags_ptr, tags_n).to_vec();
ffi::gmshFree(tags_ptr as *mut _);
Ok(tags)
}
}
pub fn set_physical_name(&self, dim: i32, tag: i32, name: &str) -> Result<(), GmshError> {
let c_name = to_cstring(name);
unsafe {
check_err!(|ierr| ffi::gmshModelSetPhysicalName(dim, tag, c_name.as_ptr(), ierr))
}
}
pub fn get_physical_name(&self, dim: i32, tag: i32) -> Result<String, GmshError> {
let mut name_ptr = ptr::null_mut();
unsafe {
check_err!(|ierr| ffi::gmshModelGetPhysicalName(dim, tag, &mut name_ptr, ierr))?;
Ok(unsafe { cstr_to_string_and_free(name_ptr) })
}
}
pub fn get_boundary(
&self,
entities: &[(i32, i32)],
combined: bool,
oriented: bool,
recursive: bool,
) -> Result<Vec<(i32, i32)>, GmshError> {
let dimtags = dimtags_to_cvec(entities);
let mut out_ptr = ptr::null_mut();
let mut out_n = 0;
unsafe {
check_err!(|ierr| {
ffi::gmshModelGetBoundary(
dimtags.as_ptr(),
dimtags.len(),
&mut out_ptr,
&mut out_n,
if combined { 1 } else { 0 },
if oriented { 1 } else { 0 },
if recursive { 1 } else { 0 },
ierr,
)
})?;
let mut boundary = Vec::with_capacity(out_n / 2);
for i in 0..(out_n / 2) {
let d = *out_ptr.add(i * 2);
let t = *out_ptr.add(i * 2 + 1);
boundary.push((d, t));
}
ffi::gmshFree(out_ptr as *mut _);
Ok(boundary)
}
}
pub fn get_bounding_box(&self, dim: i32, tag: i32) -> Result<[f64; 6], GmshError> {
let mut xmin = 0.0;
let mut ymin = 0.0;
let mut zmin = 0.0;
let mut xmax = 0.0;
let mut ymax = 0.0;
let mut zmax = 0.0;
unsafe {
check_err!(|ierr| {
ffi::gmshModelGetBoundingBox(dim, tag, &mut xmin, &mut ymin, &mut zmin, &mut xmax, &mut ymax, &mut zmax, ierr)
})?;
Ok([xmin, ymin, zmin, xmax, ymax, zmax])
}
}
pub fn get_dimension(&self) -> Result<i32, GmshError> {
unsafe { check_err!(|ierr| ffi::gmshModelGetDimension(ierr)) }
}
pub fn mesh(&self) -> Mesh {
Mesh { model_name: self.name.clone() }
}
pub fn geo(&self) -> Geo {
Geo { _model_name: self.name.clone() }
}
pub fn occ(&self) -> Occ {
Occ { _model_name: self.name.clone() }
}
pub fn write(&self, filename: &str) -> Result<(), GmshError> {
let c_filename = to_cstring(filename);
unsafe { check_err!(|ierr| ffi::gmshWrite(c_filename.as_ptr(), ierr)) }
}
}
pub struct Mesh {
model_name: String,
}
impl Mesh {
pub fn get_nodes(
&self,
dim: i32,
tag: i32,
include_boundary: bool,
return_parametric: bool,
) -> Result<(Vec<usize>, Vec<f64>, Vec<f64>), GmshError> {
let mut node_tags_ptr = ptr::null_mut();
let mut node_tags_n = 0;
let mut coord_ptr = ptr::null_mut();
let mut coord_n = 0;
let mut param_ptr = ptr::null_mut();
let mut param_n = 0;
unsafe {
check_err!(|ierr| {
ffi::gmshModelMeshGetNodes(
&mut node_tags_ptr,
&mut node_tags_n,
&mut coord_ptr,
&mut coord_n,
&mut param_ptr,
&mut param_n,
dim,
tag,
if include_boundary { 1 } else { 0 },
if return_parametric { 1 } else { 0 },
ierr,
)
})?;
let node_tags = if node_tags_ptr.is_null() {
Vec::new()
} else {
std::slice::from_raw_parts(node_tags_ptr, node_tags_n).to_vec()
};
let coords = if coord_ptr.is_null() {
Vec::new()
} else {
std::slice::from_raw_parts(coord_ptr, coord_n).to_vec()
};
let param_coords = if param_ptr.is_null() {
Vec::new()
} else {
std::slice::from_raw_parts(param_ptr, param_n).to_vec()
};
ffi::gmshFree(node_tags_ptr as *mut _);
ffi::gmshFree(coord_ptr as *mut _);
ffi::gmshFree(param_ptr as *mut _);
Ok((node_tags, coords, param_coords))
}
}
pub fn get_elements(
&self,
dim: i32,
tag: i32,
) -> Result<(Vec<i32>, Vec<Vec<usize>>, Vec<Vec<usize>>), GmshError> {
let mut element_types_ptr = ptr::null_mut();
let mut element_types_n = 0;
let mut element_tags_ptr = ptr::null_mut();
let mut element_tags_n_ptr = ptr::null_mut();
let mut element_tags_nn = 0;
let mut node_tags_ptr = ptr::null_mut();
let mut node_tags_n_ptr = ptr::null_mut();
let mut node_tags_nn = 0;
unsafe {
check_err!(|ierr| {
ffi::gmshModelMeshGetElements(
&mut element_types_ptr,
&mut element_types_n,
&mut element_tags_ptr,
&mut element_tags_n_ptr,
&mut element_tags_nn,
&mut node_tags_ptr,
&mut node_tags_n_ptr,
&mut node_tags_nn,
dim,
tag,
ierr,
)
})?;
let element_types = if element_types_ptr.is_null() {
Vec::new()
} else {
std::slice::from_raw_parts(element_types_ptr, element_types_n).to_vec()
};
let element_tags_n_slice = if element_tags_n_ptr.is_null() {
&[]
} else {
std::slice::from_raw_parts(element_tags_n_ptr, element_types_n)
};
let element_tags_flat = if element_tags_ptr.is_null() {
&[]
} else {
std::slice::from_raw_parts(element_tags_ptr, element_tags_nn)
};
let mut element_tags = Vec::with_capacity(element_types_n);
let mut start = 0;
for &n in element_tags_n_slice {
let end = start + n;
let slice = element_tags_flat[start..end]
.iter()
.map(|&ptr| ptr as usize)
.collect();
element_tags.push(slice);
start = end;
}
let node_tags_n_slice = if node_tags_n_ptr.is_null() {
&[]
} else {
std::slice::from_raw_parts(node_tags_n_ptr, element_types_n)
};
let node_tags_flat = if node_tags_ptr.is_null() {
&[]
} else {
std::slice::from_raw_parts(node_tags_ptr, node_tags_nn)
};
let mut node_tags = Vec::with_capacity(element_types_n);
let mut start = 0;
for &n in node_tags_n_slice {
let end = start + n;
let slice = node_tags_flat[start..end]
.iter()
.map(|&ptr| ptr as usize)
.collect();
node_tags.push(slice);
start = end;
}
ffi::gmshFree(element_types_ptr as *mut _);
ffi::gmshFree(element_tags_ptr as *mut _);
ffi::gmshFree(element_tags_n_ptr as *mut _);
ffi::gmshFree(node_tags_ptr as *mut _);
ffi::gmshFree(node_tags_n_ptr as *mut _);
Ok((element_types, element_tags, node_tags))
}
}
pub fn get_element_by_coordinates(
&self,
x: f64,
y: f64,
z: f64,
dim: i32,
strict: bool,
) -> Result<(usize, i32, Vec<usize>, (f64, f64, f64)), GmshError> {
let mut element_tag = 0;
let mut element_type = 0;
let mut node_tags_ptr = ptr::null_mut();
let mut node_tags_n = 0;
let mut u = 0.0;
let mut v = 0.0;
let mut w = 0.0;
unsafe {
check_err!(|ierr| {
ffi::gmshModelMeshGetElementByCoordinates(
x, y, z,
&mut element_tag,
&mut element_type,
&mut node_tags_ptr,
&mut node_tags_n,
&mut u,
&mut v,
&mut w,
dim,
if strict { 1 } else { 0 },
ierr,
)
})?;
let node_tags = if node_tags_ptr.is_null() {
Vec::new()
} else {
std::slice::from_raw_parts(node_tags_ptr, node_tags_n)
.iter()
.map(|&ptr| ptr as usize)
.collect()
};
ffi::gmshFree(node_tags_ptr as *mut _);
Ok((element_tag as usize, element_type, node_tags, (u, v, w)))
}
}
pub fn set_size(&self, entities: &[(i32, i32)], size: f64) -> Result<(), GmshError> {
let dimtags = dimtags_to_cvec(entities);
unsafe {
check_err!(|ierr| ffi::gmshModelMeshSetSize(dimtags.as_ptr(), dimtags.len(), size, ierr))
}
}
pub fn set_transfinite_curve(&self, tag: i32, num_nodes: i32, mesh_type: &str, coef: f64) -> Result<(), GmshError> {
let c_type = to_cstring(mesh_type);
unsafe {
check_err!(|ierr| ffi::gmshModelMeshSetTransfiniteCurve(tag, num_nodes, c_type.as_ptr(), coef, ierr))
}
}
pub fn set_transfinite_surface(&self, tag: i32, arrangement: &str, corner_tags: &[i32]) -> Result<(), GmshError> {
let c_arr = to_cstring(arrangement);
unsafe {
check_err!(|ierr| {
ffi::gmshModelMeshSetTransfiniteSurface(
tag,
c_arr.as_ptr(),
corner_tags.as_ptr(),
corner_tags.len(),
ierr,
)
})
}
}
pub fn set_transfinite_volume(&self, tag: i32, corner_tags: &[i32]) -> Result<(), GmshError> {
unsafe {
check_err!(|ierr| {
ffi::gmshModelMeshSetTransfiniteVolume(tag, corner_tags.as_ptr(), corner_tags.len(), ierr)
})
}
}
pub fn set_recombine(&self, dim: i32, tag: i32, angle: f64) -> Result<(), GmshError> {
unsafe {
check_err!(|ierr| ffi::gmshModelMeshSetRecombine(dim, tag, angle, ierr))
}
}
pub fn set_smoothing(&self, dim: i32, tag: i32, value: i32) -> Result<(), GmshError> {
unsafe {
check_err!(|ierr| ffi::gmshModelMeshSetSmoothing(dim, tag, value, ierr))
}
}
pub fn set_algorithm(&self, dim: i32, tag: i32, value: i32) -> Result<(), GmshError> {
unsafe {
check_err!(|ierr| ffi::gmshModelMeshSetAlgorithm(dim, tag, value, ierr))
}
}
pub fn clear(&self, entities: &[(i32, i32)]) -> Result<(), GmshError> {
let dimtags = dimtags_to_cvec(entities);
unsafe {
check_err!(|ierr| ffi::gmshModelMeshClear(dimtags.as_ptr(), dimtags.len(), ierr))
}
}
}
pub struct Geo {
_model_name: String,
}
impl Geo {
pub fn add_point(&self, x: f64, y: f64, z: f64, mesh_size: f64, tag: i32) -> Result<i32, GmshError> {
unsafe {
check_err!(|ierr| ffi::gmshModelGeoAddPoint(x, y, z, mesh_size, tag, ierr))
}
}
pub fn add_line(&self, start_tag: i32, end_tag: i32, tag: i32) -> Result<i32, GmshError> {
unsafe {
check_err!(|ierr| ffi::gmshModelGeoAddLine(start_tag, end_tag, tag, ierr))
}
}
pub fn add_circle_arc(&self, start_tag: i32, center_tag: i32, end_tag: i32, tag: i32, nx: f64, ny: f64, nz: f64) -> Result<i32, GmshError> {
unsafe {
check_err!(|ierr| ffi::gmshModelGeoAddCircleArc(start_tag, center_tag, end_tag, tag, nx, ny, nz, ierr))
}
}
pub fn add_spline(&self, point_tags: &[i32], tag: i32) -> Result<i32, GmshError> {
unsafe {
check_err!(|ierr| ffi::gmshModelGeoAddSpline(point_tags.as_ptr(), point_tags.len(), tag, ierr))
}
}
pub fn add_curve_loop(&self, curve_tags: &[i32], tag: i32, reorient: bool) -> Result<i32, GmshError> {
unsafe {
check_err!(|ierr| {
ffi::gmshModelGeoAddCurveLoop(
curve_tags.as_ptr(),
curve_tags.len(),
tag,
if reorient { 1 } else { 0 },
ierr,
)
})
}
}
pub fn add_plane_surface(&self, wire_tags: &[i32], tag: i32) -> Result<i32, GmshError> {
unsafe {
check_err!(|ierr| ffi::gmshModelGeoAddPlaneSurface(wire_tags.as_ptr(), wire_tags.len(), tag, ierr))
}
}
pub fn add_surface_loop(&self, surface_tags: &[i32], tag: i32) -> Result<i32, GmshError> {
unsafe {
check_err!(|ierr| ffi::gmshModelGeoAddSurfaceLoop(surface_tags.as_ptr(), surface_tags.len(), tag, ierr))
}
}
pub fn add_volume(&self, shell_tags: &[i32], tag: i32) -> Result<i32, GmshError> {
unsafe {
check_err!(|ierr| ffi::gmshModelGeoAddVolume(shell_tags.as_ptr(), shell_tags.len(), tag, ierr))
}
}
pub fn extrude(
&self,
entities: &[(i32, i32)],
dx: f64,
dy: f64,
dz: f64,
num_elements: &[i32],
heights: &[f64],
recombine: bool,
) -> Result<Vec<(i32, i32)>, GmshError> {
let dimtags = dimtags_to_cvec(entities);
let mut out_ptr = ptr::null_mut();
let mut out_n = 0;
unsafe {
check_err!(|ierr| {
ffi::gmshModelGeoExtrude(
dimtags.as_ptr(),
dimtags.len(),
dx,
dy,
dz,
&mut out_ptr,
&mut out_n,
num_elements.as_ptr(),
num_elements.len(),
heights.as_ptr(),
heights.len(),
if recombine { 1 } else { 0 },
ierr,
)
})?;
let mut new_entities = Vec::with_capacity(out_n / 2);
for i in 0..(out_n / 2) {
let d = *out_ptr.add(i * 2);
let t = *out_ptr.add(i * 2 + 1);
new_entities.push((d, t));
}
ffi::gmshFree(out_ptr as *mut _);
Ok(new_entities)
}
}
pub fn synchronize(&self) -> Result<(), GmshError> {
unsafe { check_err!(|ierr| ffi::gmshModelGeoSynchronize(ierr)) }
}
}
pub struct Occ {
_model_name: String,
}
impl Occ {
pub fn add_point(&self, x: f64, y: f64, z: f64, mesh_size: f64, tag: i32) -> Result<i32, GmshError> {
unsafe {
check_err!(|ierr| ffi::gmshModelOccAddPoint(x, y, z, mesh_size, tag, ierr))
}
}
pub fn add_line(&self, start_tag: i32, end_tag: i32, tag: i32) -> Result<i32, GmshError> {
unsafe {
check_err!(|ierr| ffi::gmshModelOccAddLine(start_tag, end_tag, tag, ierr))
}
}
pub fn add_circle_arc(&self, start_tag: i32, middle_tag: i32, end_tag: i32, tag: i32, center: i32) -> Result<i32, GmshError> {
unsafe {
check_err!(|ierr| ffi::gmshModelOccAddCircleArc(start_tag, middle_tag, end_tag, tag, center, ierr))
}
}
pub fn add_circle(&self, x: f64, y: f64, z: f64, r: f64, tag: i32, angle1: f64, angle2: f64) -> Result<i32, GmshError> {
unsafe {
check_err!(|ierr| ffi::gmshModelOccAddCircle(x, y, z, r, tag, angle1, angle2, ptr::null(), 0, ptr::null(), 0, ierr))
}
}
pub fn add_rectangle(&self, x: f64, y: f64, z: f64, dx: f64, dy: f64, tag: i32, rounded_radius: f64) -> Result<i32, GmshError> {
unsafe {
check_err!(|ierr| ffi::gmshModelOccAddRectangle(x, y, z, dx, dy, tag, rounded_radius, ierr))
}
}
pub fn add_cylinder(&self, x: f64, y: f64, z: f64, dx: f64, dy: f64, dz: f64, r: f64, tag: i32, angle: f64) -> Result<i32, GmshError> {
unsafe {
check_err!(|ierr| ffi::gmshModelOccAddCylinder(x, y, z, dx, dy, dz, r, tag, angle, ierr))
}
}
pub fn add_box(&self, x: f64, y: f64, z: f64, dx: f64, dy: f64, dz: f64, tag: i32) -> Result<i32, GmshError> {
unsafe {
check_err!(|ierr| ffi::gmshModelOccAddBox(x, y, z, dx, dy, dz, tag, ierr))
}
}
pub fn add_sphere(&self, xc: f64, yc: f64, zc: f64, radius: f64, tag: i32, angle1: f64, angle2: f64, angle3: f64) -> Result<i32, GmshError> {
unsafe {
check_err!(|ierr| ffi::gmshModelOccAddSphere(xc, yc, zc, radius, tag, angle1, angle2, angle3, ierr))
}
}
pub fn fuse(
&self,
object: &[(i32, i32)],
tool: &[(i32, i32)],
tag: i32,
remove_object: bool,
remove_tool: bool,
) -> Result<Vec<(i32, i32)>, GmshError> {
let obj_dimtags = dimtags_to_cvec(object);
let tool_dimtags = dimtags_to_cvec(tool);
let mut out_ptr = ptr::null_mut();
let mut out_n = 0;
let mut map_ptr = ptr::null_mut();
let mut map_n_ptr = ptr::null_mut();
let mut map_nn = 0;
unsafe {
check_err!(|ierr| {
ffi::gmshModelOccFuse(
obj_dimtags.as_ptr(),
obj_dimtags.len(),
tool_dimtags.as_ptr(),
tool_dimtags.len(),
&mut out_ptr,
&mut out_n,
&mut map_ptr,
&mut map_n_ptr,
&mut map_nn,
tag,
if remove_object { 1 } else { 0 },
if remove_tool { 1 } else { 0 },
ierr,
)
})?;
let mut result = Vec::with_capacity(out_n / 2);
for i in 0..(out_n / 2) {
let d = *out_ptr.add(i * 2);
let t = *out_ptr.add(i * 2 + 1);
result.push((d, t));
}
ffi::gmshFree(out_ptr as *mut _);
if !map_ptr.is_null() {
ffi::gmshFree(map_ptr as *mut _);
}
if !map_n_ptr.is_null() {
ffi::gmshFree(map_n_ptr as *mut _);
}
Ok(result)
}
}
pub fn synchronize(&self) -> Result<(), GmshError> {
unsafe { check_err!(|ierr| ffi::gmshModelOccSynchronize(ierr)) }
}
}
pub struct View;
impl View {
pub fn add(name: &str, tag: i32) -> Result<i32, GmshError> {
let c_name = to_cstring(name);
unsafe { check_err!(|ierr| ffi::gmshViewAdd(c_name.as_ptr(), tag, ierr)) }
}
pub fn remove(tag: i32) -> Result<(), GmshError> {
unsafe { check_err!(|ierr| ffi::gmshViewRemove(tag, ierr)) }
}
pub fn get_tags() -> Result<Vec<i32>, GmshError> {
let mut tags_ptr = ptr::null_mut();
let mut tags_n = 0;
unsafe {
check_err!(|ierr| ffi::gmshViewGetTags(&mut tags_ptr, &mut tags_n, ierr))?;
let tags = std::slice::from_raw_parts(tags_ptr, tags_n).to_vec();
ffi::gmshFree(tags_ptr as *mut _);
Ok(tags)
}
}
pub fn add_model_data(
tag: i32,
step: i32,
model_name: &str,
data_type: &str,
tags: &[usize],
data: &[&[f64]],
time: f64,
num_components: i32,
partition: i32,
) -> Result<(), GmshError> {
let c_model = to_cstring(model_name);
let c_type = to_cstring(data_type);
let mut data_ptrs: Vec<*const f64> = data.iter().map(|d| d.as_ptr()).collect();
let data_ns: Vec<usize> = data.iter().map(|d| d.len()).collect();
unsafe {
check_err!(|ierr| {
ffi::gmshViewAddModelData(
tag,
step,
c_model.as_ptr(),
c_type.as_ptr(),
tags.as_ptr(),
tags.len(),
data_ptrs.as_ptr(),
data_ns.as_ptr(),
data_ns.iter().sum(),
time,
num_components,
partition,
ierr,
)
})
}
}
pub fn add_homogeneous_model_data(
tag: i32,
step: i32,
model_name: &str,
data_type: &str,
tags: &[usize],
data: &[f64],
time: f64,
num_components: i32,
partition: i32,
) -> Result<(), GmshError> {
let c_model = to_cstring(model_name);
let c_type = to_cstring(data_type);
unsafe {
check_err!(|ierr| {
ffi::gmshViewAddHomogeneousModelData(
tag,
step,
c_model.as_ptr(),
c_type.as_ptr(),
tags.as_ptr(),
tags.len(),
data.as_ptr(),
data.len(),
time,
num_components,
partition,
ierr,
)
})
}
}
pub fn write(tag: i32, file_name: &str, append: bool) -> Result<(), GmshError> {
let c_name = to_cstring(file_name);
unsafe {
check_err!(|ierr| ffi::gmshViewWrite(tag, c_name.as_ptr(), if append { 1 } else { 0 }, ierr))
}
}
}
pub struct GmshOption;
impl GmshOption {
pub fn set_number(name: &str, value: f64) -> Result<(), GmshError> {
let c_name = to_cstring(name);
unsafe { check_err!(|ierr| ffi::gmshOptionSetNumber(c_name.as_ptr(), value, ierr)) }
}
pub fn get_number(name: &str) -> Result<f64, GmshError> {
let c_name = to_cstring(name);
let mut value = 0.0;
unsafe {
check_err!(|ierr| ffi::gmshOptionGetNumber(c_name.as_ptr(), &mut value, ierr))?;
Ok(value)
}
}
pub fn set_string(name: &str, value: &str) -> Result<(), GmshError> {
let c_name = to_cstring(name);
let c_value = to_cstring(value);
unsafe {
check_err!(|ierr| ffi::gmshOptionSetString(c_name.as_ptr(), c_value.as_ptr(), ierr))
}
}
pub fn get_string(name: &str) -> Result<String, GmshError> {
let c_name = to_cstring(name);
let mut value_ptr = ptr::null_mut();
unsafe {
check_err!(|ierr| ffi::gmshOptionGetString(c_name.as_ptr(), &mut value_ptr, ierr))?;
Ok(unsafe { cstr_to_string_and_free(value_ptr) })
}
}
pub fn set_color(name: &str, r: i32, g: i32, b: i32, a: i32) -> Result<(), GmshError> {
let c_name = to_cstring(name);
unsafe {
check_err!(|ierr| ffi::gmshOptionSetColor(c_name.as_ptr(), r, g, b, a, ierr))
}
}
pub fn get_color(name: &str) -> Result<(i32, i32, i32, i32), GmshError> {
let c_name = to_cstring(name);
let mut r = 0;
let mut g = 0;
let mut b = 0;
let mut a = 0;
unsafe {
check_err!(|ierr| ffi::gmshOptionGetColor(c_name.as_ptr(), &mut r, &mut g, &mut b, &mut a, ierr))?;
Ok((r, g, b, a))
}
}
pub fn restore_defaults() -> Result<(), GmshError> {
unsafe { check_err!(|ierr| ffi::gmshOptionRestoreDefaults(ierr)) }
}
}
pub struct Logger;
impl Logger {
pub fn write(message: &str, level: &str) -> Result<(), GmshError> {
let c_msg = to_cstring(message);
let c_level = to_cstring(level);
unsafe {
check_err!(|ierr| ffi::gmshLoggerWrite(c_msg.as_ptr(), c_level.as_ptr(), ierr))
}
}
pub fn start() -> Result<(), GmshError> {
unsafe { check_err!(|ierr| ffi::gmshLoggerStart(ierr)) }
}
pub fn get() -> Result<Vec<String>, GmshError> {
let mut log_ptr = ptr::null_mut();
let mut log_n = 0;
unsafe {
check_err!(|ierr| ffi::gmshLoggerGet(&mut log_ptr, &mut log_n, ierr))?;
Ok(unsafe { cstr_array_to_vec_and_free(log_ptr, log_n) })
}
}
pub fn stop() -> Result<(), GmshError> {
unsafe { check_err!(|ierr| ffi::gmshLoggerStop(ierr)) }
}
pub fn wall_time() -> Result<f64, GmshError> {
unsafe {
let mut ierr = 0;
let value = ffi::gmshLoggerGetWallTime(&mut ierr);
if ierr == 0 {
Ok(value)
} else {
let mut err_ptr = ptr::null_mut();
ffi::gmshLoggerGetLastError(&mut err_ptr, ptr::null_mut());
let msg = if err_ptr.is_null() {
"unknown error".to_string()
} else {
CStr::from_ptr(err_ptr).to_string_lossy().into_owned()
};
Err(GmshError::new(msg))
}
}
}
pub fn cpu_time() -> Result<f64, GmshError> {
unsafe {
let mut ierr = 0;
let value = ffi::gmshLoggerGetCpuTime(&mut ierr);
if ierr == 0 {
Ok(value)
} else {
let mut err_ptr = ptr::null_mut();
ffi::gmshLoggerGetLastError(&mut err_ptr, ptr::null_mut());
let msg = if err_ptr.is_null() {
"unknown error".to_string()
} else {
CStr::from_ptr(err_ptr).to_string_lossy().into_owned()
};
Err(GmshError::new(msg))
}
}
}
pub fn memory() -> Result<f64, GmshError> {
unsafe {
let mut ierr = 0;
let value = ffi::gmshLoggerGetMemory(&mut ierr);
if ierr == 0 {
Ok(value)
} else {
let mut err_ptr = ptr::null_mut();
ffi::gmshLoggerGetLastError(&mut err_ptr, ptr::null_mut());
let msg = if err_ptr.is_null() {
"unknown error".to_string()
} else {
CStr::from_ptr(err_ptr).to_string_lossy().into_owned()
};
Err(GmshError::new(msg))
}
}
}
pub fn total_memory() -> Result<f64, GmshError> {
unsafe {
let mut ierr = 0;
let value = ffi::gmshLoggerGetTotalMemory(&mut ierr);
if ierr == 0 {
Ok(value)
} else {
let mut err_ptr = ptr::null_mut();
ffi::gmshLoggerGetLastError(&mut err_ptr, ptr::null_mut());
let msg = if err_ptr.is_null() {
"unknown error".to_string()
} else {
CStr::from_ptr(err_ptr).to_string_lossy().into_owned()
};
Err(GmshError::new(msg))
}
}
}
}
pub struct Plugin;
impl Plugin {
pub fn set_number(name: &str, option: &str, value: f64) -> Result<(), GmshError> {
let c_name = to_cstring(name);
let c_opt = to_cstring(option);
unsafe {
check_err!(|ierr| ffi::gmshPluginSetNumber(c_name.as_ptr(), c_opt.as_ptr(), value, ierr))
}
}
pub fn set_string(name: &str, option: &str, value: &str) -> Result<(), GmshError> {
let c_name = to_cstring(name);
let c_opt = to_cstring(option);
let c_val = to_cstring(value);
unsafe {
check_err!(|ierr| ffi::gmshPluginSetString(c_name.as_ptr(), c_opt.as_ptr(), c_val.as_ptr(), ierr))
}
}
pub fn run(name: &str) -> Result<i32, GmshError> {
let c_name = to_cstring(name);
unsafe { check_err!(|ierr| ffi::gmshPluginRun(c_name.as_ptr(), ierr)) }
}
}
pub struct Onelab;
impl Onelab {
pub fn set_number(name: &str, value: &[f64]) -> Result<(), GmshError> {
let c_name = to_cstring(name);
unsafe {
check_err!(|ierr| ffi::gmshOnelabSetNumber(c_name.as_ptr(), value.as_ptr(), value.len(), ierr))
}
}
pub fn get_number(name: &str) -> Result<Vec<f64>, GmshError> {
let c_name = to_cstring(name);
let mut value_ptr = ptr::null_mut();
let mut value_n = 0;
unsafe {
check_err!(|ierr| ffi::gmshOnelabGetNumber(c_name.as_ptr(), &mut value_ptr, &mut value_n, ierr))?;
let values = std::slice::from_raw_parts(value_ptr, value_n).to_vec();
ffi::gmshFree(value_ptr as *mut _);
Ok(values)
}
}
pub fn set_string(name: &str, value: &[&str]) -> Result<(), GmshError> {
let c_name = to_cstring(name);
let mut c_values: Vec<CString> = value.iter().map(|s| to_cstring(s)).collect();
let mut c_ptrs: Vec<*const c_char> = c_values.iter().map(|c| c.as_ptr()).collect();
unsafe {
check_err!(|ierr| {
ffi::gmshOnelabSetString(
c_name.as_ptr(),
c_ptrs.as_ptr(),
c_ptrs.len(),
ierr,
)
})
}
}
pub fn get_string(name: &str) -> Result<Vec<String>, GmshError> {
let c_name = to_cstring(name);
let mut value_ptr = ptr::null_mut();
let mut value_n = 0;
unsafe {
check_err!(|ierr| ffi::gmshOnelabGetString(c_name.as_ptr(), &mut value_ptr, &mut value_n, ierr))?;
Ok(unsafe { cstr_array_to_vec_and_free(value_ptr, value_n) })
}
}
pub fn get_changed(name: &str) -> Result<bool, GmshError> {
let c_name = to_cstring(name);
unsafe {
let changed = check_err!(|ierr| ffi::gmshOnelabGetChanged(c_name.as_ptr(), ierr))?;
Ok(changed != 0)
}
}
pub fn clear(name: &str) -> Result<(), GmshError> {
let c_name = to_cstring(name);
unsafe {
check_err!(|ierr| ffi::gmshOnelabClear(c_name.as_ptr(), ierr))
}
}
}
pub struct Fltk;
impl Fltk {
pub fn initialize() -> Result<(), GmshError> {
unsafe { check_err!(|ierr| ffi::gmshFltkInitialize(ierr)) }
}
pub fn finalize() -> Result<(), GmshError> {
unsafe { check_err!(|ierr| ffi::gmshFltkFinalize(ierr)) }
}
pub fn run(option_file_name: Option<&str>) -> Result<(), GmshError> {
let c_file = option_file_name.map(to_cstring).unwrap_or_else(|| CString::new("").unwrap());
unsafe { check_err!(|ierr| ffi::gmshFltkRun(c_file.as_ptr(), ierr)) }
}
pub fn wait(time: f64) -> Result<(), GmshError> {
unsafe { check_err!(|ierr| ffi::gmshFltkWait(time, ierr)) }
}
pub fn update() -> Result<(), GmshError> {
unsafe { check_err!(|ierr| ffi::gmshFltkUpdate(ierr)) }
}
pub fn awake(action: &str) -> Result<(), GmshError> {
let c_action = to_cstring(action);
unsafe { check_err!(|ierr| ffi::gmshFltkAwake(c_action.as_ptr(), ierr)) }
}
pub fn lock() -> Result<(), GmshError> {
unsafe { check_err!(|ierr| ffi::gmshFltkLock(ierr)) }
}
pub fn unlock() -> Result<(), GmshError> {
unsafe { check_err!(|ierr| ffi::gmshFltkUnlock(ierr)) }
}
pub fn is_available() -> Result<bool, GmshError> {
unsafe {
let mut ierr = 0;
let val = ffi::gmshFltkIsAvailable(&mut ierr);
if ierr == 0 {
Ok(val != 0)
} else {
let mut err_ptr = ptr::null_mut();
ffi::gmshLoggerGetLastError(&mut err_ptr, ptr::null_mut());
let msg = if err_ptr.is_null() {
"unknown error".to_string()
} else {
CStr::from_ptr(err_ptr).to_string_lossy().into_owned()
};
Err(GmshError::new(msg))
}
}
}
pub fn select_entities(dim: i32) -> Result<Vec<(i32, i32)>, GmshError> {
let mut dimtags_ptr = ptr::null_mut();
let mut dimtags_n = 0;
unsafe {
let selected = check_err!(|ierr| ffi::gmshFltkSelectEntities(&mut dimtags_ptr, &mut dimtags_n, dim, ierr))?;
if selected == 0 {
return Ok(Vec::new());
}
let mut entities = Vec::with_capacity(dimtags_n / 2);
for i in 0..(dimtags_n / 2) {
let d = *dimtags_ptr.add(i * 2);
let t = *dimtags_ptr.add(i * 2 + 1);
entities.push((d, t));
}
ffi::gmshFree(dimtags_ptr as *mut _);
Ok(entities)
}
}
pub fn select_elements() -> Result<Vec<usize>, GmshError> {
let mut tags_ptr = ptr::null_mut();
let mut tags_n = 0;
unsafe {
let selected = check_err!(|ierr| ffi::gmshFltkSelectElements(&mut tags_ptr, &mut tags_n, ierr))?;
if selected == 0 {
return Ok(Vec::new());
}
let tags = std::slice::from_raw_parts(tags_ptr, tags_n).to_vec();
ffi::gmshFree(tags_ptr as *mut _);
Ok(tags)
}
}
pub fn select_views() -> Result<Vec<i32>, GmshError> {
let mut tags_ptr = ptr::null_mut();
let mut tags_n = 0;
unsafe {
let selected = check_err!(|ierr| ffi::gmshFltkSelectViews(&mut tags_ptr, &mut tags_n, ierr))?;
if selected == 0 {
return Ok(Vec::new());
}
let tags = std::slice::from_raw_parts(tags_ptr, tags_n).to_vec();
ffi::gmshFree(tags_ptr as *mut _);
Ok(tags)
}
}
pub fn split_current_window(how: &str, ratio: f64) -> Result<(), GmshError> {
let c_how = to_cstring(how);
unsafe { check_err!(|ierr| ffi::gmshFltkSplitCurrentWindow(c_how.as_ptr(), ratio, ierr)) }
}
pub fn set_current_window(window_index: i32) -> Result<(), GmshError> {
unsafe { check_err!(|ierr| ffi::gmshFltkSetCurrentWindow(window_index, ierr)) }
}
pub fn set_status_message(message: &str, graphics: bool) -> Result<(), GmshError> {
let c_msg = to_cstring(message);
unsafe {
check_err!(|ierr| ffi::gmshFltkSetStatusMessage(c_msg.as_ptr(), if graphics { 1 } else { 0 }, ierr))
}
}
pub fn show_context_window(dim: i32, tag: i32) -> Result<(), GmshError> {
unsafe { check_err!(|ierr| ffi::gmshFltkShowContextWindow(dim, tag, ierr)) }
}
pub fn open_tree_item(name: &str) -> Result<(), GmshError> {
let c_name = to_cstring(name);
unsafe { check_err!(|ierr| ffi::gmshFltkOpenTreeItem(c_name.as_ptr(), ierr)) }
}
pub fn close_tree_item(name: &str) -> Result<(), GmshError> {
let c_name = to_cstring(name);
unsafe { check_err!(|ierr| ffi::gmshFltkCloseTreeItem(c_name.as_ptr(), ierr)) }
}
}