Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
214 changes: 211 additions & 3 deletions src/geometry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,27 @@
conversion::{CoordSeq, CoordType, ToSFCGALGeom},
errors::get_last_error,
utils::{
_c_string_with_size, _string, check_computed_value, check_nan_value,
_string, c_string_with_size, check_computed_value, check_nan_value,
check_null_prepared_geom, check_predicate, get_raw_bytes,
},
Result, ToSFCGAL,
};

// For review
use sfcgal_sys::{
sfcgal_geometry_alpha_wrapping_3d, sfcgal_geometry_as_stl, sfcgal_geometry_as_stl_file,

Check failure on line 82 in src/geometry.rs

View workflow job for this annotation

GitHub Actions / test (stable)

unresolved imports `sfcgal_sys::sfcgal_geometry_as_stl`, `sfcgal_sys::sfcgal_geometry_as_stl_file`, `sfcgal_sys::sfcgal_geometry_get_geometry_n`, `sfcgal_sys::sfcgal_geometry_get_geometry_n`, `sfcgal_sys::sfcgal_geometry_set_geometry_n`
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CI is running against the latest stable sfcgal release (2.1.0) which doesn't seem to contain the following functions (sfcgal_sys::sfcgal_geometry_as_stl, sfcgal_sys::sfcgal_geometry_as_stl_file, sfcgal_sys::sfcgal_geometry_get_geometry_n, sfcgal_sys::sfcgal_geometry_get_geometry_n, sfcgal_sys::sfcgal_geometry_set_geometry_n).
I tested locally (and checked in the source distribution of sfcgal 2.1.0) and I can't find them either (although they are in the documentation https://sfcgal.gitlab.io/SFCGAL/API/group__capi/, which is probably based on the current source tree of sfcgal).

sfcgal_geometry_boundary, sfcgal_geometry_centroid, sfcgal_geometry_centroid,

Check warning on line 83 in src/geometry.rs

View workflow job for this annotation

GitHub Actions / test (stable)

unused import: `sfcgal_geometry_centroid`

Check failure on line 83 in src/geometry.rs

View workflow job for this annotation

GitHub Actions / test (stable)

the name `sfcgal_geometry_centroid` is defined multiple times
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicated sfcgal_geometry_centroid should be removed.

sfcgal_geometry_centroid_3d, sfcgal_geometry_collection_set_geometry_n,
sfcgal_geometry_dimension, sfcgal_geometry_drop_m, sfcgal_geometry_drop_z,
sfcgal_geometry_envelope, sfcgal_geometry_force_m, sfcgal_geometry_force_z,
sfcgal_geometry_get_geometry_n, sfcgal_geometry_get_geometry_n,
sfcgal_geometry_is_almost_equals, sfcgal_geometry_is_equals, sfcgal_geometry_is_simple,
sfcgal_geometry_length, sfcgal_geometry_length_3d, sfcgal_geometry_num_geometries,
sfcgal_geometry_set_geometry_n, sfcgal_geometry_simplify, sfcgal_geometry_swap_xy,
sfcgal_geometry_type, sfcgal_polyhedral_surface_set_patch_n,
sfcgal_triangulated_surface_set_patch_n,
};

/// Represent the buffer types usable with the `buffer3d` method.
#[repr(C)]
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Primitive)]
Expand Down Expand Up @@ -282,7 +297,7 @@
unsafe {
sfcgal_geometry_as_text(self.c_geom.as_ref(), ptr.as_mut_ptr(), &mut length);

Ok(_c_string_with_size(ptr.assume_init(), length))
Ok(c_string_with_size(ptr.assume_init(), length))
}
}

Expand All @@ -302,7 +317,7 @@
&mut length,
);

Ok(_c_string_with_size(ptr.assume_init(), length))
Ok(c_string_with_size(ptr.assume_init(), length))
}
}

Expand Down Expand Up @@ -1491,7 +1506,7 @@
pub fn triangulated_surface_triangle_n(&self, index: usize) -> Result<SFCGeometry> {
precondition_match_type!(self, GeomType::Triangulatedsurface);

precondition_index_in_result_value!(index, self.triangulated_surface_num_triangles());

Check warning on line 1509 in src/geometry.rs

View workflow job for this annotation

GitHub Actions / test (stable)

use of deprecated method `geometry::SFCGeometry::triangulated_surface_num_triangles`: Use geometry_num_geometries instead.

unsafe {
let result = sfcgal_triangulated_surface_triangle_n(self.c_geom.as_ptr(), index);
Expand All @@ -1515,6 +1530,7 @@
Ok(())
}

#[deprecated = "Use geometry_num_geometries instead."]
/// Returns the number of triangles of a given TriangulatedSurface
pub fn triangulated_surface_num_triangles(&self) -> Result<usize> {
precondition_match_type!(self, GeomType::Triangulatedsurface);
Expand Down Expand Up @@ -1620,6 +1636,7 @@
unsafe { SFCGeometry::new_from_raw(result, true) }
}

#[deprecated = "Use geometry_num_geometries instead."]
/// Returns the number of polygons of a given PolyhedralSurface
pub fn polyhedral_surface_num_polygons(&self) -> Result<usize> {
precondition_match_type!(self, GeomType::Polyhedralsurface);
Expand All @@ -1640,11 +1657,12 @@
Ok(())
}

#[deprecated = "Use geometry_get_geometry_n instead.c"]
/// Returns the ith polygon of a given PolyhedralSurface
pub fn polyhedral_surface_polygon_n(&self, index: usize) -> Result<SFCGeometry> {
precondition_match_type!(self, GeomType::Polyhedralsurface);

precondition_index_in_result_value!(index, self.polyhedral_surface_num_polygons());

Check warning on line 1665 in src/geometry.rs

View workflow job for this annotation

GitHub Actions / test (stable)

use of deprecated method `geometry::SFCGeometry::polyhedral_surface_num_polygons`: Use geometry_num_geometries instead.

let result = unsafe { sfcgal_polyhedral_surface_polygon_n(self.c_geom.as_ptr(), index) };

Expand Down Expand Up @@ -1849,6 +1867,196 @@

SFCGeometry::new_from_raw(converted, true)
}

// For review
Copy link
Owner

@mthh mthh Jul 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The newly added function looks good to me. It is just lacking documentation for now but I guess you were planning to add documentation to them? Otherwise I could accept it as it and do it myself :)

Concerning the functions that depend on the new sfcgal function there weren't included in 2.1.0 (namely sfcgal_sys::sfcgal_geometry_as_stl, sfcgal_sys::sfcgal_geometry_as_stl_file, sfcgal_sys::sfcgal_geometry_get_geometry_n, sfcgal_sys::sfcgal_geometry_get_geometry_n, sfcgal_sys::sfcgal_geometry_set_geometry_n), you can just comment the code and the imports and we will add them when 2.2.0 will be released ? (or you can remove them totally from this PR, and create a new draft PR for them, but it's a bit of extra work that's not necessarily necessary).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes you are right, I probably pulled the trigger too fast, many functions are planned for 2.2.0 (that will be less work for the future)! I will double check that, comment the offenders and resubmit! :)

pub fn geometry_envelope(&self) -> Result<SFCGeometry> {
let result = unsafe { sfcgal_geometry_envelope(self.c_geom.as_ptr()) };

unsafe { SFCGeometry::new_from_raw(result, true) }
}

pub fn geometry_is_simple(&self) -> Result<bool> {
let result = unsafe { sfcgal_geometry_is_simple(self.c_geom.as_ptr()) };

check_predicate(result)
}

pub fn geometry_alpha_wrapping_3d(
&self,
relative_alpha: usize,
relative_offset: usize,
) -> Result<SFCGeometry> {
let result = unsafe {
sfcgal_geometry_alpha_wrapping_3d(self.c_geom.as_ptr(), relative_alpha, relative_offset)
};

unsafe { SFCGeometry::new_from_raw(result, true) }
}

pub fn geometry_length(&self) -> Result<f64> {
let result = unsafe { sfcgal_geometry_length(self.c_geom.as_ptr()) };

check_nan_value(result)
}
pub fn geometry_length_3d(&self) -> Result<f64> {
let result = unsafe { sfcgal_geometry_length_3d(self.c_geom.as_ptr()) };

check_nan_value(result)
}

pub fn geometry_centroid(&self) -> Result<SFCGeometry> {
let result = unsafe { sfcgal_geometry_centroid(self.c_geom.as_ptr()) };

unsafe { SFCGeometry::new_from_raw(result, true) }
}

pub fn geometry_centroid_3d(&self) -> Result<SFCGeometry> {
let result = unsafe { sfcgal_geometry_centroid_3d(self.c_geom.as_ptr()) };

unsafe { SFCGeometry::new_from_raw(result, true) }
}

pub fn geometry_is_equals(&self, other: &SFCGeometry) -> Result<bool> {
let result =
unsafe { sfcgal_geometry_is_equals(self.c_geom.as_ptr(), other.c_geom.as_ptr()) };

check_predicate(result)
}
pub fn geometry_is_almost_equals(&self, other: &SFCGeometry, tolerance: f64) -> Result<bool> {
let result = unsafe {
sfcgal_geometry_is_almost_equals(self.c_geom.as_ptr(), other.c_geom.as_ptr(), tolerance)
};

check_predicate(result)
}

pub fn geometry_get_geometry_n(&self, index: usize) -> Result<SFCGeometry> {
let result = unsafe { sfcgal_geometry_get_geometry_n(self.c_geom.as_ptr(), index) };

unsafe { SFCGeometry::new_from_raw(result, true) }
}
pub fn geometry_num_geometries(&self) -> usize {
unsafe { sfcgal_geometry_num_geometries(self.c_geom.as_ptr()) }
}
pub fn geometry_set_geometry_n(&self, other: &SFCGeometry, index: usize) -> usize {
unsafe {
sfcgal_geometry_set_geometry_n(self.c_geom.as_ptr(), other.c_geom.as_ptr(), index)
}
}

pub fn geometry_drop_z(&self) -> Result<bool> {
let result = unsafe { sfcgal_geometry_drop_z(self.c_geom.as_ptr()) };

check_predicate(result)
}

pub fn geometry_drop_m(&self) -> Result<bool> {
let result = unsafe { sfcgal_geometry_drop_m(self.c_geom.as_ptr()) };

check_predicate(result)
}

pub fn geometry_dimension(&self) -> i32 {
unsafe { sfcgal_geometry_dimension(self.c_geom.as_ptr()) }
}

pub fn geometry_type(&self) -> Result<String> {
let mut ptr = MaybeUninit::<*mut c_char>::uninit();

let mut length: usize = 0;

unsafe {
sfcgal_geometry_type(self.c_geom.as_ref(), ptr.as_mut_ptr(), &mut length);

Ok(c_string_with_size(ptr.assume_init(), length))
}
}

pub fn geometry_boundary(&self) -> Result<SFCGeometry> {
let result = unsafe { sfcgal_geometry_boundary(self.c_geom.as_ptr()) };

unsafe { SFCGeometry::new_from_raw(result, true) }
}

pub fn geometry_swap_xy(&self) {
unsafe { sfcgal_geometry_swap_xy(self.c_geom.as_ptr()) };
}
pub fn geometry_force_z(&self, z: f64) -> Result<bool> {
let result = unsafe { sfcgal_geometry_force_z(self.c_geom.as_ptr(), z) };

check_predicate(result)
}

pub fn geometry_force_m(&self, m: f64) -> Result<bool> {
let result = unsafe { sfcgal_geometry_force_m(self.c_geom.as_ptr(), m) };

check_predicate(result)
}

pub fn geometry_simplify(
&self,
threshold: f64,
preserve_topology: bool,
) -> Result<SFCGeometry> {
let result =
unsafe { sfcgal_geometry_simplify(self.c_geom.as_ptr(), threshold, preserve_topology) };

unsafe { SFCGeometry::new_from_raw(result, true) }
}

pub fn polyhedral_surface_set_patch_n(&self, other: &SFCGeometry, index: usize) {
unsafe {
sfcgal_polyhedral_surface_set_patch_n(
self.c_geom.as_ptr(),
other.c_geom.as_ptr(),
index,
)
};
}
pub fn triangulated_surface_set_patch_n(&self, other: &SFCGeometry, index: usize) {
unsafe {
sfcgal_triangulated_surface_set_patch_n(
self.c_geom.as_ptr(),
other.c_geom.as_ptr(),
index,
)
};
}

pub fn geometry_collection_set_geometry_n(&self, other: &SFCGeometry, index: usize) {
unsafe {
sfcgal_geometry_collection_set_geometry_n(
self.c_geom.as_ptr(),
other.c_geom.as_ptr(),
index,
)
};
}

pub fn to_stl_file(&self, filename: &str) -> Result<()> {
unsafe {
let c_string = CString::new(filename)?;

let raw: *mut c_char = c_string.into_raw();

sfcgal_geometry_as_stl_file(self.c_geom.as_ptr(), raw);
};

Ok(())
}

/// Creates a STL string of the given geometry. In memory version.
pub fn to_stl_in_memory(&self) -> Result<Vec<u8>> {
let mut ptr = MaybeUninit::<*mut c_char>::uninit();

let mut length: usize = 0;

unsafe {
sfcgal_geometry_as_stl(self.c_geom.as_ref(), ptr.as_mut_ptr(), &mut length);

Ok(get_raw_bytes(ptr.assume_init(), length))
}
}
}
fn is_all_same<T>(arr: &[T]) -> bool
where
Expand Down
2 changes: 1 addition & 1 deletion src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ pub(crate) fn check_nan_value(val: f64) -> Result<f64> {
// (as it seems to not always end with a null byte)
// from the pointer to uninitialized memory with give
// to it earlier.
pub(crate) fn _c_string_with_size(raw_ptr: *const c_char, size: usize) -> String {
pub(crate) fn c_string_with_size(raw_ptr: *const c_char, size: usize) -> String {
let slice: &[u8] = unsafe { std::slice::from_raw_parts(raw_ptr as *const u8, size) };

let res = std::str::from_utf8(slice).unwrap().to_string();
Expand Down
Loading