diff --git a/CMakeLists.txt b/CMakeLists.txt index 9e16b5c..7876bf2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -140,90 +140,46 @@ set_target_properties( Licensing PROPERTIES PREFIX "" ) # -# ACIS Python Module - Topology (ENTITY, BODY, FACE, etc.) +# ACIS Python Module - Entity (ENTITY, BODY, FACE, etc.) # # Set source files -set( ACIS_SOURCES_Topology - src/acis_topology.h - src/acis_topology.cpp - ${PROJECT_BINARY_DIR}/acis_topology_export.h +set( ACIS_SOURCES_Entity + src/acis_entity.h + src/acis_entity.cpp + ${PROJECT_BINARY_DIR}/acis_entity_export.h ) # Generate Python module -add_library( Topology SHARED ${ACIS_SOURCES_Topology} ) +add_library( Entity SHARED ${ACIS_SOURCES_Entity} ) # Generate export header file -generate_export_header( Topology - BASE_NAME acis_topology +generate_export_header( Entity + BASE_NAME acis_entity ) # Set link targets -target_link_libraries( Topology ${ACIS_LINK_LIBRARIES} ${PYTHON_LIBRARIES} ) +target_link_libraries( Entity ${ACIS_LINK_LIBRARIES} ${PYTHON_LIBRARIES} ) # Add the build location to the include directories -target_include_directories( Topology PUBLIC ${PROJECT_SOURCE_DIR} ${PROJECT_BINARY_DIR} ) +target_include_directories( Entity PUBLIC ${PROJECT_SOURCE_DIR} ${PROJECT_BINARY_DIR} ) # Set required C++ standard -set_property( TARGET Topology PROPERTY CXX_STANDARD 11 ) -set_property( TARGET Topology PROPERTY CXX_STANDARD_REQUIRED ON ) +set_property( TARGET Entity PROPERTY CXX_STANDARD 11 ) +set_property( TARGET Entity PROPERTY CXX_STANDARD_REQUIRED ON ) # Add suffix to debug builds if( WIN32 ) - set_target_properties( Topology PROPERTIES DEBUG_POSTFIX "_d" ) + set_target_properties( Entity PROPERTIES DEBUG_POSTFIX "_d" ) endif() # On Windows, Python modules have .pyd filename extension if( WIN32 AND NOT CYGWIN ) - set_target_properties( Topology PROPERTIES SUFFIX ".pyd" ) + set_target_properties( Entity PROPERTIES SUFFIX ".pyd" ) endif() # This is only needed for the python case where a modulename.so is generated -set_target_properties( Topology PROPERTIES PREFIX "" ) - - -# -# ACIS Python Module - Geometry (SURFACE and its subclasses & surface and its subclasses) -# - -# Set source files -set( ACIS_SOURCES_Geometry - src/acis_geometry.h - src/acis_geometry.cpp - ${PROJECT_BINARY_DIR}/acis_geometry_export.h - ) - -# Generate Python module -add_library( Geometry SHARED ${ACIS_SOURCES_Geometry} ) - -# Generate export header file -generate_export_header( - Geometry - BASE_NAME acis_geometry - ) - -# Set link targets -target_link_libraries( Geometry ${ACIS_LINK_LIBRARIES} ${PYTHON_LIBRARIES} Topology ) - -# Add the build location to the include directories -target_include_directories( Geometry PUBLIC ${PROJECT_SOURCE_DIR} ${PROJECT_BINARY_DIR} ) - -# Set required C++ standard -set_property( TARGET Geometry PROPERTY CXX_STANDARD 11 ) -set_property( TARGET Geometry PROPERTY CXX_STANDARD_REQUIRED ON ) - -# Add suffix to debug builds -if( WIN32 ) - set_target_properties( Geometry PROPERTIES DEBUG_POSTFIX "_d" ) -endif() - -# On Windows, Python modules have .pyd filename extension -if( WIN32 AND NOT CYGWIN ) - set_target_properties( Geometry PROPERTIES SUFFIX ".pyd" ) -endif() - -# This is only needed for the python case where a modulename.so is generated -set_target_properties( Geometry PROPERTIES PREFIX "" ) +set_target_properties( Entity PROPERTIES PREFIX "" ) # @@ -269,49 +225,6 @@ endif() set_target_properties( GeometricAtoms PROPERTIES PREFIX "" ) -# -# ACIS Python Module - Geometric Operators (translate_transf, parallel, antiparallel, etc.) -# - -# Set source files -set( ACIS_SOURCES_GeometricOperators - src/acis_geometric_operators.h - src/acis_geometric_operators.cpp - ${PROJECT_BINARY_DIR}/acis_geometric_operators_export.h - ) - -# Generate Python module -add_library( GeometricOperators SHARED ${ACIS_SOURCES_GeometricOperators} ) - -# Generate export header file -generate_export_header( GeometricOperators - BASE_NAME acis_geometric_operators - ) - -# Set link targets -target_link_libraries( GeometricOperators ${ACIS_LINK_LIBRARIES} ${PYTHON_LIBRARIES} GeometricAtoms ) - -# Add the build location to the include directories -target_include_directories( GeometricOperators PUBLIC ${PROJECT_SOURCE_DIR} ${PROJECT_BINARY_DIR} ) - -# Set required C++ standard -set_property( TARGET GeometricOperators PROPERTY CXX_STANDARD 11 ) -set_property( TARGET GeometricOperators PROPERTY CXX_STANDARD_REQUIRED ON ) - -# Add suffix to debug builds -if( WIN32 ) - set_target_properties( GeometricOperators PROPERTIES DEBUG_POSTFIX "_d" ) -endif() - -# On Windows, Python modules have .pyd filename extension -if( WIN32 AND NOT CYGWIN ) - set_target_properties( GeometricOperators PROPERTIES SUFFIX ".pyd" ) -endif() - -# This is only needed for the python case where a modulename.so is generated -set_target_properties( GeometricOperators PROPERTIES PREFIX "" ) - - # # ACIS Python Module - Save & Restore (FileInfo, etc.) # @@ -377,7 +290,7 @@ generate_export_header( Lists ) # Set link targets -target_link_libraries( Lists ${ACIS_LINK_LIBRARIES} ${PYTHON_LIBRARIES} Topology ) +target_link_libraries( Lists ${ACIS_LINK_LIBRARIES} ${PYTHON_LIBRARIES} Entity ) # Add the build location to the include directories target_include_directories( Lists PUBLIC ${PROJECT_SOURCE_DIR} ${PROJECT_BINARY_DIR} ) @@ -422,7 +335,7 @@ generate_export_header( Sweeping ) # Set link targets. Note that Modeler has dependencies towards most helper modules. -target_link_libraries( Sweeping ${ACIS_LINK_LIBRARIES} ${PYTHON_LIBRARIES} Topology GeometricAtoms ) +target_link_libraries( Sweeping ${ACIS_LINK_LIBRARIES} ${PYTHON_LIBRARIES} Entity GeometricAtoms ) # Add the build location to the include directories target_include_directories( Sweeping PUBLIC ${PROJECT_SOURCE_DIR} ${PROJECT_BINARY_DIR} ) @@ -467,7 +380,7 @@ generate_export_header( Query ) # Set link targets. Note that Modeler has dependencies towards most helper modules. -target_link_libraries( Query ${ACIS_LINK_LIBRARIES} ${PYTHON_LIBRARIES} Topology GeometricAtoms Lists ) +target_link_libraries( Query ${ACIS_LINK_LIBRARIES} ${PYTHON_LIBRARIES} Entity GeometricAtoms Lists ) # Add the build location to the include directories target_include_directories( Query PUBLIC ${PROJECT_SOURCE_DIR} ${PROJECT_BINARY_DIR} ) @@ -506,7 +419,7 @@ set( ACIS_SOURCES_Modeler add_library( Modeler SHARED ${ACIS_SOURCES_Modeler} ) # Set link targets. Note that Modeler has dependencies towards most helper modules. -target_link_libraries( Modeler ${ACIS_LINK_LIBRARIES} ${PYTHON_LIBRARIES} Topology Lists SaveRestore GeometricAtoms ) +target_link_libraries( Modeler ${ACIS_LINK_LIBRARIES} ${PYTHON_LIBRARIES} Entity Lists SaveRestore GeometricAtoms ) # Add the build location to the include directories target_include_directories( Modeler PUBLIC ${PROJECT_SOURCE_DIR} ${PROJECT_BINARY_DIR} ) @@ -535,7 +448,7 @@ set_target_properties( Modeler PROPERTIES PREFIX "" ) # Install Python modules to APP_INSTALL_DIR install( - TARGETS Modeler Licensing Topology Lists SaveRestore GeometricAtoms GeometricOperators Sweeping Geometry Query + TARGETS Modeler Licensing Entity Lists SaveRestore GeometricAtoms Sweeping Query DESTINATION ${APP_INSTALL_DIR}/${APP_MODULE_NAME} ) diff --git a/FUNCTION_REFERENCE.md b/FUNCTION_REFERENCE.md index ebdabe8..5a75bff 100644 --- a/FUNCTION_REFERENCE.md +++ b/FUNCTION_REFERENCE.md @@ -61,7 +61,26 @@ ### Functions +* coordinate_transf +* make_transf +* reflect_transf +* rotate_transf +* scale_transf +* shear_transf * translate_transf +* angle_between +* antiparallel +* are_parallel +* are_perpendicular +* biparallel +* degrees_to_radians +* radians_to_degrees +* get_resabs +* get_resfit +* get_resmch +* get_resnor +* distance_to_point +* distance_to_point_squared ## Lists diff --git a/src/acis_geometric_atoms.cpp b/src/acis_geometric_atoms.cpp index e7fd67a..038476a 100644 --- a/src/acis_geometric_atoms.cpp +++ b/src/acis_geometric_atoms.cpp @@ -1557,6 +1557,278 @@ static PyTypeObject * Python module definitions */ +static PyObject * +ACIS_GeometricAtoms_method_coordinate_transf(PyObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *input_origin = NULL, *input_x_axis = NULL, *input_y_axis = NULL; + + // List of keyword arguments that this function can take + static char *kwlist[] = + { + (char *) "new_origin", + (char *) "new_x_axis", + (char *) "new_y_axis", + NULL + }; + + // Try to parse input arguments and/or keywords + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOO", kwlist, &input_origin, &input_x_axis, &input_y_axis)) + return NULL; + + // Check inputs + if (!_ACIS_check_SPAposition(input_origin)) + { + PyErr_SetString(PyExc_TypeError, "First parameter (new_origin) must be a SPAposition object"); + return NULL; + } + + if (!_ACIS_check_SPAunit_vector(input_x_axis)) + { + PyErr_SetString(PyExc_TypeError, "Second parameter (new_x_axis) must be a SPAunit_vector object"); + return NULL; + } + + if (!_ACIS_check_SPAunit_vector(input_y_axis)) + { + PyErr_SetString(PyExc_TypeError, "Third parameter (new_y_axis) must be a SPAunit_vector object"); + return NULL; + } + + // Get the ACIS object from the user input + SPAposition *&_new_origin = ((ACIS_GeometricAtoms_SPAposition *) input_origin)->_acis_obj; + SPAunit_vector *&_new_x_axis = ((ACIS_GeometricAtoms_SPAunit_vector *) input_x_axis)->_acis_obj; + SPAunit_vector *&_new_y_axis = ((ACIS_GeometricAtoms_SPAunit_vector *) input_y_axis)->_acis_obj; + + // Execute ACIS function + SPAtransf retval = coordinate_transf(*_new_origin, *_new_x_axis, *_new_y_axis); + + // Generate a new SPAtransf python object and set its ACIS object value + PyObject *retobj = _ACIS_new_SPAtransf(); + *((ACIS_GeometricAtoms_SPAtransf *) retobj)->_acis_obj = retval; + + // Return SPAtransf python object + return retobj; +} + +static PyObject * +ACIS_GeometricAtoms_method_make_transf(PyObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *input_affine = NULL, *input_translation = NULL; + + // List of keyword arguments that this function can take + static char *kwlist[] = + { + (char *) "affine", + (char *) "translation", + NULL + }; + + // Try to parse input arguments and/or keywords + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO", kwlist, &input_affine, &input_translation)) + return NULL; + + // Check inputs + if (!_ACIS_check_SPAmatrix(input_affine)) + { + PyErr_SetString(PyExc_TypeError, "First parameter (affine) must be a SPAmatrix object"); + return NULL; + } + + if (!_ACIS_check_SPAvector(input_translation)) + { + PyErr_SetString(PyExc_TypeError, "Second parameter (translate) must be a SPAvector object"); + return NULL; + } + + // Get the ACIS object from the user input + SPAmatrix *&_affine = ((ACIS_GeometricAtoms_SPAmatrix *) input_affine)->_acis_obj; + SPAvector *&_translation = ((ACIS_GeometricAtoms_SPAvector *) input_translation)->_acis_obj; + + // Execute ACIS function + SPAtransf retval = make_transf(*_affine, *_translation); + + // Generate a new SPAtransf python object and set its ACIS object value + PyObject *retobj = _ACIS_new_SPAtransf(); + *((ACIS_GeometricAtoms_SPAtransf *) retobj)->_acis_obj = retval; + + // Return SPAtransf python object + return retobj; +} + +static PyObject * +ACIS_GeometricAtoms_method_reflect_transf(PyObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *input_axis = NULL; + + // List of keyword arguments that this function can take + static char *kwlist[] = + { + (char *) "axis", + NULL + }; + + // Try to parse input arguments and/or keywords + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwlist, &input_axis)) + return NULL; + + // Check inputs + if (!_ACIS_check_SPAvector(input_axis)) + { + PyErr_SetString(PyExc_TypeError, "Expecting a SPAvector object"); + return NULL; + } + + // Get the ACIS object from the user input + SPAvector *&_axis = ((ACIS_GeometricAtoms_SPAvector *) input_axis)->_acis_obj; + + // Execute ACIS function + SPAtransf retval = reflect_transf(*_axis); + + // Generate a new SPAtransf python object and set its ACIS object value + PyObject *retobj = _ACIS_new_SPAtransf(); + *((ACIS_GeometricAtoms_SPAtransf *) retobj)->_acis_obj = retval; + + // Return SPAtransf python object + return retobj; +} + +static PyObject * +ACIS_GeometricAtoms_method_rotate_transf(PyObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *input_axis = NULL; + double input_angle; + + // List of keyword arguments that this function can take + static char *kwlist[] = + { + (char *) "angle", + (char *) "axis", + NULL + }; + + // Try to parse input arguments and/or keywords + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "dO", kwlist, &input_angle, &input_axis)) + return NULL; + + // Check inputs + if (!_ACIS_check_SPAvector(input_axis)) + { + PyErr_SetString(PyExc_TypeError, "Expecting a SPAvector object"); + return NULL; + } + + // Get the ACIS object from the user input + SPAvector *&_axis = ((ACIS_GeometricAtoms_SPAvector *) input_axis)->_acis_obj; + + // Execute ACIS function + SPAtransf retval = rotate_transf(input_angle, *_axis); + + // Generate a new SPAtransf python object and set its ACIS object value + PyObject *retobj = _ACIS_new_SPAtransf(); + *((ACIS_GeometricAtoms_SPAtransf *) retobj)->_acis_obj = retval; + + // Return SPAtransf python object + return retobj; +} + +static PyObject * +ACIS_GeometricAtoms_method_scale_transf(PyObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *input_arg1 = NULL, *input_arg2 = NULL, *input_arg3 = NULL, *input_arg4 = NULL, *input_arg5 = NULL, *input_arg6 = NULL; + + // List of keyword arguments that this function can take + static char *kwlist[] = + { + (char *) "scale", + NULL + }; + + // Try to parse input arguments and/or keywords + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OOOOO", kwlist, &input_arg1, &input_arg2, &input_arg3, &input_arg4, &input_arg5, &input_arg6)) + return NULL; + + SPAtransf retval; + + if (!PyFloat_Check(input_arg1)) + { + PyErr_SetString(PyExc_TypeError, "Expecting a floating-point number"); + return NULL; + } + + double _arg1 = PyFloat_AsDouble(input_arg1); + + if (input_arg2 != NULL || input_arg3 != NULL) + { + if (!PyFloat_Check(input_arg2) && !PyFloat_Check(input_arg3)) + { + PyErr_SetString(PyExc_TypeError, "Expecting a floating-point number"); + return NULL; + } + + double _arg2 = PyFloat_AsDouble(input_arg2); + double _arg3 = PyFloat_AsDouble(input_arg3); + + if (input_arg4 != NULL || input_arg5 != NULL || input_arg6 != NULL) + { + if (!PyFloat_Check(input_arg4) && !PyFloat_Check(input_arg5) && !PyFloat_Check(input_arg5)) + { + PyErr_SetString(PyExc_TypeError, "Expecting a floating-point number"); + return NULL; + } + + double _arg4 = PyFloat_AsDouble(input_arg4); + double _arg5 = PyFloat_AsDouble(input_arg5); + double _arg6 = PyFloat_AsDouble(input_arg5); + + retval = scale_transf(_arg1, _arg2, _arg3, _arg4, _arg5, _arg6); + } + else + { + retval = scale_transf(_arg1, _arg2, _arg3); + } + } + else + { + retval = scale_transf(_arg1); + } + + // Generate a new SPAtransf python object and set its ACIS object value + PyObject *retobj = _ACIS_new_SPAtransf(); + *((ACIS_GeometricAtoms_SPAtransf *) retobj)->_acis_obj = retval; + + // Return SPAtransf python object + return retobj; +} + +static PyObject * +ACIS_GeometricAtoms_method_shear_transf(PyObject *self, PyObject *args, PyObject *kwargs) +{ + double _shear_xy, _shear_xz, _shear_yz; + + // List of keyword arguments that this function can take + static char *kwlist[] = + { + (char *) "shearxy", + (char *) "shearxz", + (char *) "shearyz", + NULL + }; + + // Try to parse input arguments and/or keywords + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ddd", kwlist, &_shear_xy, &_shear_xz, &_shear_yz)) + return NULL; + + // Execute ACIS function + SPAtransf retval = shear_transf(_shear_xy, _shear_xz, _shear_yz); + + // Generate a new SPAtransf python object and set its ACIS object value + PyObject *retobj = _ACIS_new_SPAtransf(); + *((ACIS_GeometricAtoms_SPAtransf *) retobj)->_acis_obj = retval; + + // Return SPAtransf python object + return retobj; +} + static PyObject * ACIS_GeometricAtoms_method_translate_transf(PyObject *self, PyObject *args, PyObject *kwargs) { @@ -1594,10 +1866,520 @@ ACIS_GeometricAtoms_method_translate_transf(PyObject *self, PyObject *args, PyOb return retobj; } +static PyObject * +ACIS_GeometricAtoms_method_angle_between(PyObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *input_v1 = NULL, *input_v2 = NULL, *input_z = NULL; + + // List of keyword arguments that this function can take + static char *kwlist[] = + { + (char *) "v1", + (char *) "v2", + (char *) "z", + NULL + }; + + // Try to parse input arguments and/or keywords + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|O", kwlist, &input_v1, &input_v2, &input_z)) + return NULL; + + // Set return value + double _retval; + + // SPAvector scenario + if (_ACIS_check_SPAvector(input_v1)) + { + if (!_ACIS_check_SPAvector(input_v2)) + { + PyErr_SetString(PyExc_TypeError, "Second parameter (v2) should be a SPAvector object"); + return NULL; + } + + SPAvector *&_v1 = ((ACIS_GeometricAtoms_SPAvector *) input_v1)->_acis_obj; + SPAvector *&_v2 = ((ACIS_GeometricAtoms_SPAvector *) input_v2)->_acis_obj; + + if (input_z != NULL) + { + if (!_ACIS_check_SPAvector(input_z)) + { + PyErr_SetString(PyExc_TypeError, "Third parameter (z) should be a SPAunit_vector object"); + return NULL; + } + + SPAunit_vector *&_z = ((ACIS_GeometricAtoms_SPAunit_vector *) input_z)->_acis_obj; + + _retval = angle_between(*_v1, *_v2, *_z); + } + else + { + _retval = angle_between(*_v1, *_v2); + } + } + else if (_ACIS_check_SPAunit_vector(input_v1)) + { + // SPAunit_vector scenario + if (!_ACIS_check_SPAunit_vector(input_v2)) + { + PyErr_SetString(PyExc_TypeError, "Second parameter (v2) should be a SPAunit_vector object"); + return NULL; + } + + SPAunit_vector *&_v1 = ((ACIS_GeometricAtoms_SPAunit_vector *) input_v1)->_acis_obj; + SPAunit_vector *&_v2 = ((ACIS_GeometricAtoms_SPAunit_vector *) input_v2)->_acis_obj; + + if (input_z != NULL) + { + if (!_ACIS_check_SPAunit_vector(input_z)) + { + PyErr_SetString(PyExc_TypeError, "Third parameter (z) should be a SPAunit_vector object"); + return NULL; + } + + SPAunit_vector *&_z = ((ACIS_GeometricAtoms_SPAunit_vector *) input_z)->_acis_obj; + + _retval = angle_between(*_v1, *_v2, *_z); + } + else + { + _retval = angle_between(*_v1, *_v2); + } + } + else + { + PyErr_SetString(PyExc_TypeError, "First parameter (v1) should be a SPAvector or SPAunit_vector object"); + return NULL; + } + + // Return PyFloat object + return PyFloat_FromDouble(_retval); +} + +static PyObject * +ACIS_GeometricAtoms_method_antiparallel(PyObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *input_v1 = NULL, *input_v2 = NULL; + double input_res = -1.0; + + // List of keyword arguments that this function can take + static char *kwlist[] = + { + (char *) "v1", + (char *) "v2", + (char *) "res", + NULL + }; + + // Try to parse input arguments and/or keywords + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|d", kwlist, &input_v1, &input_v2, &input_res)) + return NULL; + + // Set return value + logical _retval; + + // SPAvector scenario + if (_ACIS_check_SPAvector(input_v1)) + { + if (!_ACIS_check_SPAvector(input_v2) || !_ACIS_check_SPAunit_vector(input_v2)) + { + PyErr_SetString(PyExc_TypeError, "Second parameter (v2) should be a SPAvector or SPAunit_vector object"); + return NULL; + } + + SPAvector *&_v1 = ((ACIS_GeometricAtoms_SPAvector *) input_v1)->_acis_obj; + SPAvector *&_v2 = ((ACIS_GeometricAtoms_SPAvector *) input_v2)->_acis_obj; + + if (input_res >= 0.0) + { + _retval = antiparallel(*_v1, *_v2, input_res); + } + else + { + _retval = antiparallel(*_v1, *_v2); + } + } + else if (_ACIS_check_SPAunit_vector(input_v1)) + { + // SPAunit_vector scenario + if (!_ACIS_check_SPAunit_vector(input_v2) || !_ACIS_check_SPAvector(input_v2)) + { + PyErr_SetString(PyExc_TypeError, "Second parameter (v2) should be a SPAunit_vector or SPAvector object"); + return NULL; + } + + SPAunit_vector *&_v1 = ((ACIS_GeometricAtoms_SPAunit_vector *) input_v1)->_acis_obj; + SPAunit_vector *&_v2 = ((ACIS_GeometricAtoms_SPAunit_vector *) input_v2)->_acis_obj; + + if (input_res >= 0.0) + { + _retval = antiparallel(*_v1, *_v2, input_res); + } + else + { + _retval = antiparallel(*_v1, *_v2); + } + } + else + { + PyErr_SetString(PyExc_TypeError, "First parameter (v1) should be a SPAvector or SPAunit_vector object"); + return NULL; + } + + // Return logical + if (_retval == 1) + Py_RETURN_TRUE; + Py_RETURN_FALSE; +} + +static PyObject * +ACIS_GeometricAtoms_method_are_parallel(PyObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *input_v1 = NULL, *input_v2 = NULL; + int input_same_dir = 0; + + // List of keyword arguments that this function can take + static char *kwlist[] = + { + (char *) "v1", + (char *) "v2", + (char *) "same_dir", + NULL + }; + + // Try to parse input arguments and/or keywords + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|i", kwlist, &input_v1, &input_v2, &input_same_dir)) + return NULL; + + // Set return value + logical _retval; + + // SPAvector scenario + if (_ACIS_check_SPAvector(input_v1)) + { + if (!_ACIS_check_SPAvector(input_v2)) + { + PyErr_SetString(PyExc_TypeError, "Second parameter (v2) should be a SPAvector object"); + return NULL; + } + + SPAvector *&_v1 = ((ACIS_GeometricAtoms_SPAvector *) input_v1)->_acis_obj; + SPAvector *&_v2 = ((ACIS_GeometricAtoms_SPAvector *) input_v2)->_acis_obj; + + _retval = are_parallel(*_v1, *_v2, input_same_dir); + } + else if (_ACIS_check_SPAunit_vector(input_v1)) + { + // SPAunit_vector scenario + if (!_ACIS_check_SPAunit_vector(input_v2)) + { + PyErr_SetString(PyExc_TypeError, "Second parameter (v2) should be a SPAunit_vector object"); + return NULL; + } + + SPAunit_vector *&_v1 = ((ACIS_GeometricAtoms_SPAunit_vector *) input_v1)->_acis_obj; + SPAunit_vector *&_v2 = ((ACIS_GeometricAtoms_SPAunit_vector *) input_v2)->_acis_obj; + + _retval = are_parallel(*_v1, *_v2, input_same_dir); + } + else + { + PyErr_SetString(PyExc_TypeError, "First parameter (v1) should be a SPAvector or SPAunit_vector object"); + return NULL; + } + + // Return logical + if (_retval == 1) + Py_RETURN_TRUE; + Py_RETURN_FALSE; +} + +static PyObject * +ACIS_GeometricAtoms_method_are_perpendicular(PyObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *input_v1 = NULL, *input_v2 = NULL; + + // List of keyword arguments that this function can take + static char *kwlist[] = + { + (char *) "v1", + (char *) "v2", + NULL + }; + + // Try to parse input arguments and/or keywords + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO", kwlist, &input_v1, &input_v2)) + return NULL; + + // Set return value + logical _retval; + + // SPAvector scenario + if (_ACIS_check_SPAvector(input_v1)) + { + if (!_ACIS_check_SPAvector(input_v2)) + { + PyErr_SetString(PyExc_TypeError, "Second parameter (v2) should be a SPAvector object"); + return NULL; + } + + SPAvector *&_v1 = ((ACIS_GeometricAtoms_SPAvector *) input_v1)->_acis_obj; + SPAvector *&_v2 = ((ACIS_GeometricAtoms_SPAvector *) input_v2)->_acis_obj; + + _retval = are_perpendicular(*_v1, *_v2); + } + else if (_ACIS_check_SPAunit_vector(input_v1)) + { + // SPAunit_vector scenario + if (!_ACIS_check_SPAunit_vector(input_v2)) + { + PyErr_SetString(PyExc_TypeError, "Second parameter (v2) should be a SPAunit_vector object"); + return NULL; + } + + SPAunit_vector *&_v1 = ((ACIS_GeometricAtoms_SPAunit_vector *) input_v1)->_acis_obj; + SPAunit_vector *&_v2 = ((ACIS_GeometricAtoms_SPAunit_vector *) input_v2)->_acis_obj; + + _retval = are_perpendicular(*_v1, *_v2); + } + else + { + PyErr_SetString(PyExc_TypeError, "First parameter (v1) should be a SPAvector or SPAunit_vector object"); + return NULL; + } + + // Return logical + if (_retval == 1) + Py_RETURN_TRUE; + Py_RETURN_FALSE; +} + +static PyObject * +ACIS_GeometricAtoms_method_biparallel(PyObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *input_v1 = NULL, *input_v2 = NULL; + double input_res = -1.0; + + // List of keyword arguments that this function can take + static char *kwlist[] = + { + (char *) "v1", + (char *) "v2", + (char *) "res", + NULL + }; + + // Try to parse input arguments and/or keywords + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|d", kwlist, &input_v1, &input_v2, &input_res)) + return NULL; + + // Set return value + logical _retval; + + // SPAvector scenario + if (_ACIS_check_SPAvector(input_v1)) + { + if (!_ACIS_check_SPAvector(input_v2)) + { + PyErr_SetString(PyExc_TypeError, "Second parameter (v2) should be a SPAvector object"); + return NULL; + } + + SPAvector *&_v1 = ((ACIS_GeometricAtoms_SPAvector *) input_v1)->_acis_obj; + SPAvector *&_v2 = ((ACIS_GeometricAtoms_SPAvector *) input_v2)->_acis_obj; + + if (input_res >= 0.0) + { + _retval = biparallel(*_v1, *_v2, input_res); + } + else + { + _retval = biparallel(*_v1, *_v2); + } + } + else if (_ACIS_check_SPAunit_vector(input_v1)) + { + // SPAunit_vector scenario + if (!_ACIS_check_SPAunit_vector(input_v2)) + { + PyErr_SetString(PyExc_TypeError, "Second parameter (v2) should be a SPAunit_vector object"); + return NULL; + } + + SPAunit_vector *&_v1 = ((ACIS_GeometricAtoms_SPAunit_vector *) input_v1)->_acis_obj; + SPAunit_vector *&_v2 = ((ACIS_GeometricAtoms_SPAunit_vector *) input_v2)->_acis_obj; + + if (input_res >= 0.0) + { + _retval = biparallel(*_v1, *_v2, input_res); + } + else + { + _retval = biparallel(*_v1, *_v2); + } + } + else + { + PyErr_SetString(PyExc_TypeError, "First parameter (v1) should be a SPAvector or SPAunit_vector object"); + return NULL; + } + + // Return logical + if (_retval == 1) + Py_RETURN_TRUE; + Py_RETURN_FALSE; +} + +static PyObject * +ACIS_GeometricAtoms_method_degrees_to_radians(PyObject *self, PyObject *args, PyObject *kwargs) +{ + double input_ang; + + // List of keyword arguments that this function can take + static char *kwlist[] = + { + (char *) "ang", + NULL + }; + + // Try to parse input arguments and/or keywords + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "d", kwlist, &input_ang)) + return NULL; + + double _retval = degrees_to_radians(input_ang); + + // Return double + return PyFloat_FromDouble(_retval); +} + +static PyObject * +ACIS_GeometricAtoms_method_radians_to_degrees(PyObject *self, PyObject *args, PyObject *kwargs) +{ + double input_ang; + + // List of keyword arguments that this function can take + static char *kwlist[] = + { + (char *) "ang", + NULL + }; + + // Try to parse input arguments and/or keywords + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "d", kwlist, &input_ang)) + return NULL; + + double _retval = radians_to_degrees(input_ang); + + // Return double + return PyFloat_FromDouble(_retval); +} + +static PyObject * +ACIS_GeometricAtoms_method_get_resabs(PyObject *self) +{ + return PyFloat_FromDouble(get_resabs()); +} + +static PyObject * +ACIS_GeometricAtoms_method_get_resfit(PyObject *self) +{ + return PyFloat_FromDouble(get_resfit()); +} + +static PyObject * +ACIS_GeometricAtoms_method_get_resmch(PyObject *self) +{ + return PyFloat_FromDouble(get_resmch()); +} + +static PyObject * +ACIS_GeometricAtoms_method_get_resnor(PyObject *self) +{ + return PyFloat_FromDouble(get_resnor()); +} + +static PyObject * +ACIS_GeometricAtoms_method_distance_to_point(PyObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *input_pt1 = NULL, *input_pt2 = NULL; + + // List of keyword arguments that this function can take + static char *kwlist[] = + { + (char *) "pt1", + (char *) "pt2", + NULL + }; + + // Try to parse input arguments and/or keywords + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO", kwlist, &input_pt1, &input_pt2)) + return NULL; + + if (!_ACIS_check_SPAposition(input_pt1) || !_ACIS_check_SPAposition(input_pt2)) + { + PyErr_SetString(PyExc_TypeError, "Input values should be SPAposition objects"); + return NULL; + } + + SPAposition *&_pt1 = ((ACIS_GeometricAtoms_SPAposition *) input_pt1)->_acis_obj; + SPAposition *&_pt2 = ((ACIS_GeometricAtoms_SPAposition *) input_pt2)->_acis_obj; + + // Return double + return PyFloat_FromDouble(distance_to_point(*_pt1, *_pt2)); +} + +static PyObject * +ACIS_GeometricAtoms_method_distance_to_point_squared(PyObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *input_pt1 = NULL, *input_pt2 = NULL; + + // List of keyword arguments that this function can take + static char *kwlist[] = + { + (char *) "pt1", + (char *) "pt2", + NULL + }; + + // Try to parse input arguments and/or keywords + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO", kwlist, &input_pt1, &input_pt2)) + return NULL; + + if (!_ACIS_check_SPAposition(input_pt1) || !_ACIS_check_SPAposition(input_pt2)) + { + PyErr_SetString(PyExc_TypeError, "Input values should be SPAposition objects"); + return NULL; + } + + SPAposition *&_pt1 = ((ACIS_GeometricAtoms_SPAposition *) input_pt1)->_acis_obj; + SPAposition *&_pt2 = ((ACIS_GeometricAtoms_SPAposition *) input_pt2)->_acis_obj; + + // Return double + return PyFloat_FromDouble(distance_to_point_squared(*_pt1, *_pt2)); +} + static PyMethodDef module_methods[] = { + { "coordinate_transf", (PyCFunction) ACIS_GeometricAtoms_method_coordinate_transf, METH_VARARGS | METH_KEYWORDS, "Constructs a coordinate transformation" }, + { "make_transf", (PyCFunction) ACIS_GeometricAtoms_method_make_transf, METH_VARARGS | METH_KEYWORDS, "Constructs a transformation retrieving the needed information from the provided transformation matrix and the scaling vector" }, + { "reflect_transf", (PyCFunction) ACIS_GeometricAtoms_method_reflect_transf, METH_VARARGS | METH_KEYWORDS, "Constructs a transformation corresponding to a reflection through a plane, specified by its normal" }, + { "rotate_transf", (PyCFunction) ACIS_GeometricAtoms_method_rotate_transf, METH_VARARGS | METH_KEYWORDS, "Constructs a transformation corresponding to a simple rotation by an angle about a given axis" }, + { "scale_transf", (PyCFunction) ACIS_GeometricAtoms_method_scale_transf, METH_VARARGS | METH_KEYWORDS, "Constructs a scale transformation (uniform, non-uniform and shear)" }, + { "shear_transf", (PyCFunction) ACIS_GeometricAtoms_method_shear_transf, METH_VARARGS | METH_KEYWORDS, "Constructs a shear transformation" }, { "translate_transf", (PyCFunction) ACIS_GeometricAtoms_method_translate_transf, METH_VARARGS | METH_KEYWORDS, "Constructs a transformation corresponding to a translation by a given vector" }, + { "angle_between", (PyCFunction) ACIS_GeometricAtoms_method_angle_between, METH_VARARGS | METH_KEYWORDS, "Calculates the angle between two vectors or unit vectors" }, + { "antiparallel", (PyCFunction) ACIS_GeometricAtoms_method_antiparallel, METH_VARARGS | METH_KEYWORDS, "Determines if two vectors or unit vectors are anti-parallel" }, + { "are_parallel", (PyCFunction) ACIS_GeometricAtoms_method_are_parallel, METH_VARARGS | METH_KEYWORDS, "Determines if two vectors or unit vectors are parallel" }, + { "are_perpendicular", (PyCFunction) ACIS_GeometricAtoms_method_are_perpendicular, METH_VARARGS | METH_KEYWORDS, " Determines if two vectors or unit vectors are perpendicular" }, + { "biparallel", (PyCFunction) ACIS_GeometricAtoms_method_biparallel, METH_VARARGS | METH_KEYWORDS, "Determines if two vectors or unit vectors are bi-parallel" }, + { "degrees_to_radians", (PyCFunction) ACIS_GeometricAtoms_method_degrees_to_radians, METH_VARARGS | METH_KEYWORDS, "Converts an angle from degrees to radians" }, + { "radians_to_degrees", (PyCFunction) ACIS_GeometricAtoms_method_radians_to_degrees, METH_VARARGS | METH_KEYWORDS, "Converts an angle from radians to degrees" }, + { "get_resabs", (PyCFunction) ACIS_GeometricAtoms_method_get_resabs, METH_NOARGS, "Gets the SPAresabs resolution" }, + { "get_resfit", (PyCFunction) ACIS_GeometricAtoms_method_get_resfit, METH_NOARGS, "Gets the SPAresfit resolution" }, + { "get_resmch", (PyCFunction) ACIS_GeometricAtoms_method_get_resmch, METH_NOARGS, "Gets the resmch resolution" }, + { "get_resnor", (PyCFunction) ACIS_GeometricAtoms_method_get_resnor, METH_NOARGS, "Gets the SPAresnor resolution" }, + { "distance_to_point", (PyCFunction) ACIS_GeometricAtoms_method_distance_to_point, METH_VARARGS | METH_KEYWORDS, "Determines the distance between two points" }, + { "distance_to_point_squared", (PyCFunction) ACIS_GeometricAtoms_method_distance_to_point_squared, METH_VARARGS | METH_KEYWORDS, "\tComputes the squared distance between two positions" }, { NULL, NULL, 0, NULL } }; diff --git a/src/acis_geometric_atoms.h b/src/acis_geometric_atoms.h index 08338c7..f437846 100644 --- a/src/acis_geometric_atoms.h +++ b/src/acis_geometric_atoms.h @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include "acis_geometric_atoms_export.h" diff --git a/src/acis_lists.cpp b/src/acis_lists.cpp index ae16b51..31c1e0c 100644 --- a/src/acis_lists.cpp +++ b/src/acis_lists.cpp @@ -205,7 +205,17 @@ ACIS_Lists_method_ENTITY_LIST_next(ACIS_Lists_ENTITY_LIST *self) { PyObject *retobj = _ACIS_new_ENTITY(); ENTITY *_elem = self->_acis_obj->next(); - ((ACIS_Entity_ENTITY *) retobj)->_acis_obj = _elem; + if (_elem) + { + ((ACIS_Entity_ENTITY *) retobj)->_acis_obj = _elem; + } + else + { + // This is a requirement for iterator/generator to stop. Otherwise, you will observe an infinite loop. + PyErr_SetNone(PyExc_StopIteration); + return NULL; + } + return retobj; } @@ -220,17 +230,60 @@ ACIS_Lists_method_ENTITY_LIST_next_from(ACIS_Lists_ENTITY_LIST *self, PyObject * Py_INCREF(arg); int _from_index = (int) PyLong_AsLong(arg); + Py_DECREF(arg); PyObject *retobj = _ACIS_new_ENTITY(); ENTITY *_elem = self->_acis_obj->next_from(_from_index); - ((ACIS_Entity_ENTITY *) retobj)->_acis_obj = _elem; - Py_DECREF(arg); + if (_elem) + { + ((ACIS_Entity_ENTITY *) retobj)->_acis_obj = _elem; + } + else + { + // This is a requirement for iterator/generator to stop. Otherwise, you will observe an infinite loop. + PyErr_SetNone(PyExc_StopIteration); + return NULL; + } return retobj; } -/* TO-DO: Implement ENTITY_LIST::array as a Python iterator */ +static PyObject * +ACIS_Lists_method_ENTITY_LIST_array(ACIS_Lists_ENTITY_LIST *self) +{ + /* This function will create a Python generator/iterator */ + + // Reference increment is necessary, otherwise this ENTITY_LIST will be garbage collected + Py_INCREF(self); + + // Iterator/Generator creation functions always return self! + return (PyObject *) self; +} + +static PyObject * +ACIS_Lists_iter_ENTITY_LIST(PyObject *self) +{ + /* Must have the same signature as PyObject_GetIter() */ + + // Move the ENTITY_LIST pointer to the beginning + ACIS_Lists_method_ENTITY_LIST_init((ACIS_Lists_ENTITY_LIST *) self); + + Py_INCREF(self); + return self; +} + +static PyObject * +ACIS_Lists_iter_next_ENTITY_LIST(PyObject *self) +{ + /* Must have the same signature as PyIter_Next() */ + + // Convert the input argument to a ENTITY_LIST object + ACIS_Lists_ENTITY_LIST *_ent_list = (ACIS_Lists_ENTITY_LIST *) self; + + // Return the next element + return ACIS_Lists_method_ENTITY_LIST_next(_ent_list); +} static PyGetSetDef ACIS_Lists_getseters_ENTITY_LIST[] = @@ -258,7 +311,7 @@ static PyMethodDef { "first", (PyCFunction) ACIS_Lists_method_ENTITY_LIST_first, METH_NOARGS, "Initializes the iterator, which is used by the next method, to the beginning of the list" }, { "next", (PyCFunction) ACIS_Lists_method_ENTITY_LIST_next, METH_NOARGS, "Returns the next undeleted (live) entry" }, { "next_from", (PyCFunction) ACIS_Lists_method_ENTITY_LIST_next_from, METH_O, "Returns the next non deleted entry after the index given without affecting the member variables used by init and next" }, - //{ "array", (PyCFunction)ACIS_Lists_method_ENTITY_LIST_array, METH_VARARGS | METH_KEYWORDS, "Gets an array of the entities in the list" }, + { "array", (PyCFunction) ACIS_Lists_method_ENTITY_LIST_array, METH_NOARGS, "Gets an array of the entities in the list (creates a Python generator)" }, { NULL } /* Sentinel */ }; @@ -290,8 +343,8 @@ static PyTypeObject 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ + (getiterfunc) ACIS_Lists_iter_ENTITY_LIST, /* tp_iter */ + (iternextfunc) ACIS_Lists_iter_next_ENTITY_LIST, /* tp_iternext */ ACIS_Lists_methods_ENTITY_LIST, /* tp_methods */ ACIS_Lists_members_ENTITY_LIST, /* tp_members */ ACIS_Lists_getseters_ENTITY_LIST, /* tp_getset */